Литмир - Электронная Библиотека
Содержание  
A
A

Если поддерживается более старый элемент

msg_accrights
, то длина должна быть равна размеру целого числа, а вновь созданный дескриптор возвращается через указатель
recvfd
вызывающего процесса.

В листинге 15.10 показана программа

openfile
. Она получает три аргумента командной строки, которые должны быть переданы, и вызывает обычную функцию
open
.

Листинг 15.10. Программа openfile: открытие файла и передача дескриптора обратно

//unixdomain/openfile.c

 1 #include "unp.h"

 2 int

 3 main(int argc, char **argv)

 4 {

 5  int fd;

 6  ssize_t n;

 7  if (argc != 4)

 8   err_quit("openfile <sockfd#> <filename> <mode>");

 9  if ((fd = open(argv[2], atoi(argv[3]))) < 0)

10   exit((errno > 0) ? errno : 255);

11  if ((n = write_fd(atoi(argv[1]), "", 1, fd)) < 0)

12   exit((errno > 0) ? errno : 255);

13  exit(0);

14 }

Аргументы командной строки

6-7
 Поскольку два из трех аргументов командной строки были превращены в символьные строки функцией
my_open
, они преобразуются обратно в целые числа при помощи функции
atoi
.

Открытие файла

9-10
 Файл открывается с помощью функции
open
. Если встречается ошибка, статус завершения этого процесса содержит значение переменной
errno
, соответствующее ошибке функции
open
.

Передача дескриптора обратно

11-12
 Дескриптор передается обратно функцией
write_fd
, которую мы покажем в следующем листинге. Затем этот процесс завершается, но ранее в этой главе мы сказали, что отправляющий процесс может закрыть переданный дескриптор (это происходит, когда мы вызываем функцию
exit
), поскольку ядро знает, что дескриптор находится в состоянии передачи («в полете»), и оставляет его открытым для принимающего процесса.

ПРИМЕЧАНИЕ

Статус выхода должен лежать в пределах от 0 до 255. Максимальное значение переменной errno — около 150. Альтернативный способ, при котором не требуется, чтобы значение переменной errno было меньше 256, заключается в том, чтобы передать обратно указание на ошибку в виде обычных данных при вызове функции sendmsg.

В листинге 15.11 показана последняя функция,

write_fd
, вызывающая функцию
sendmsg
для отправки дескриптора (и, возможно, еще каких-либо данных, которые мы не используем) через доменный сокет Unix.

Листинг 15.11. Функция write_fd: передача дескриптора при помощи вызова функции sendmsg

//lib/write_fd.c

 1 #include "unp.h"

 2 ssize_t

 3 write_fd(int fd, void *ptr, size_t nbytes, int sendfd)

 4 {

 5  struct msghdr msg;

 6  struct iovec iov[1];

 7 #ifdef HAVE_MSGHDR_MSG_CONTROL

 8  union {

 9   struct cmsghdr cm;

10   char control[CMSG_SPACE(sizeof(int))];

11  } control_un;

12  struct cmsghdr *cmptr;

13  msg.msg_control = control_un.control;

14  msg.msg_controllen = sizeof(control_un.control);

15  cmptr = CMSG_FIRSTHDR(&msg);

16  cmptr->cmsg_len = CMSG_LEN(sizeof(int));

17  cmptr->cmsg_level = SOL_SOCKET;

18  cmptr->cmsg_type = SCM_RIGHTS;

19  *((int*)CMSG_DATA(cmptr)) = sendfd;

20 #else

21  msg.msg_accrights = (caddr_t)&sendfd;

22  msg.msg_accrightslen = sizeof(int);

23 #endif

24  msg.msg_name = NULL;

25  msg.msg_namelen = 0;

26  iov[0].iov_base = ptr;

27  iov[0].iov_len = nbytes;

28  msg.msg_iov = iov;

29  msg.msg_iovlen = 1;

30  return (sendmsg(fd, &msg, 0));

31 }

Как и в случае функции

read_fg
, эта функция обрабатывает либо вспомогательные данные, либо права доступа, которые предшествовали вспомогательным данным в более ранних реализациях. В любом случае инициализируется структура
msghdr
и затем вызывается функция
sendmsg
.

В разделе 28.7 мы приводим пример передачи дескриптора, в котором участвуют неродственные (unrelated) процессы, а в разделе 30.9 — пример, где задействованы родственные процессы. В них мы будем использовать функции

read_fd
и
write_fd
, которые только что описали.

15.8. Получение информации об отправителе

На рис. 14.4 мы показали другой тип информации, передаваемой через доменный сокет Unix в виде вспомогательных данных: информацию об отправителе, которая передается с помощью структуры

cmsgcred
, определяемой путем включения заголовочного файла
<sys/socket.h>
. Упаковка и формат данных зависят от операционной системы. Такая возможность появилась только в BSD/OS 2.1. Мы описываем FreeBSD, а прочие варианты Unix во многом подобны ей (проблема обычно состоит в выборе структуры, которую следует использовать для передачи данных). Рассказ об этой возможности мы считаем необходимым, поскольку это важное, хотя и простое дополнение доменных протоколов Unix. Когда клиент и сервер связываются с помощью этих протоколов, серверу часто бывает необходим способ точно узнать, кто является клиентом, чтобы убедиться, что клиент имеет право запрашивать определенный сервис.

174
{"b":"225366","o":1}