9 err_quit("usage: client2 server-pathname integer-value");
10 fd = Open(argv[1], O_RDWR); /* открываем дверь */
11 /* подготовка аргументов и указателя на результат */
12 ival = atol(argv[2]);
13 arg.data_ptr = (char *) ival; /* аргументы-данные */
14 arg.data_size = sizeof(long); /* объем данных */
15 arg.desc_ptr = NULL;
16 arg.desc_num = 0;
17 arg.rbuf = (char *) oval; /* возвращаемые данные */
18 arg.rsize = sizeof(long); /* объем возвращаемых данных */
19 /* вызов процедуры сервера и вывод результата */
20 Door_call(fd, arg);
21 printf("oval = %p, data_ptr = %p, rbuf = %p, rsize = %d\n",
22 oval, arg.data_ptr, arg.rbuf, arg.rsize);
23 printf("result: %ld\n", *((long *) arg.data_ptr));
24 exit(0);
25 }
19-22 В этой версии программы на экран выводится адрес переменной oval, содержимое указателя data_ptr, который должен указывать на возвращаемые функцией door_call данные, и адрес и размер приемного буфера (rbuf и rsize).
Запустим эту программу, не изменяя размер приемного буфера по сравнению с листингом 15.2. Мы ожидаем, что data_ptr и rbuf будут указывать на переменную oval и rsize будет иметь значение 4 (4 байта в буфере). И действительно, вот что мы видим:
solaris % client2 /tmp/server2 22
oval = effff740, data_ptr = effff740, rbuf = effff740, rsize = 4
result: 484
Изменим только одну строку в листинге 15.4, уменьшив размер буфера клиента до одного байта. Новый вариант строки 18 будет иметь вид:
arg.rsize = sizeof(long) – 1; /* размер буфера данных */
Запустим новую программу и увидим, что библиотека автоматически выделила место под новый буфер результатов и data_ptr теперь указывает на новый буфер:
solaris % client3 /tmp/server3 33
oval = effff740, data_ptr = ef620000, rbuf = ef620000, rsize = 4096
result: 1089
Размер выделенного буфера равен 4096 байт, что совпадает с размером страницы в данной системе, который мы узнали в разделе 12.6. Этот пример показывает, что следует всегда обращаться к результатам через указатель data_ptr, а не через переменные, адреса которых были переданы в rbuf. В нашем примере к результату типа «длинное целое» следует обращаться как *(long*)arg.data_ptr, а не oval (что мы делали в листинге 15.2).
Новый буфер выделяется вызовом mmap и может быть возвращен системе с помощью munmap. Клиент может повторно использовать этот буфер при новых вызовах door_call.
Функция door_cred и информация о клиенте
На этот раз мы изменим нашу функцию servproc из листинга 15.3, добавив в нее вызов door_cred для получения информации о пользователе. В листинге 15.5 приведен текст новой процедуры сервера; функции main клиента и сервера не претерпевают изменений по сравнению с листингами 15.2 и 15.3.
//doors/server4.c
1 #include "unpipc.h"
2 void
3 servproc(void *cookie, char *dataptr, size_t datasize,
4 door_desc_t *descptr, size_t ndesc)
5 {
6 long arg, result;
7 door_cred_t info;
8 /* получение и вывод информации о клиенте */
9 Door_cred(info);
10 printf("euid = %ld, ruid = %ld, pid = %ld\n",
11 (long) info.dc_euid, (long) info.dc_ruid, (long) info.dc_pid);
12 arg = *((long *) dataptr);
13 result = arg * arg;
14 Door_return((char *) result, sizeof(result), NULL, 0);
15 }
Сначала мы запустим программу-клиент и увидим, что действующий и реальный идентификаторы клиента совпадают, как мы и предполагали. Затем мы сменим владельца исполняемого файла на привилегированного пользователя, установим бит SUID и запустим программу снова: