Шрифт:
27-45
Вызывается функция recvmsg
. Если возвращаются вспомогательные данные, их формат будет таким, как показано на рис. 14.4. Мы проверяем, верны ли длина, уровень и тип, затем получаем вновь созданный дескриптор и возвращаем его через указатель вызывающего процесса recvfd
. Макрос CMSG_DATA
возвращает указатель на элемент cmsg_data
объекта вспомогательных данных как указатель на элемент типа unsigned char
. Мы преобразуем его к указателю на элемент типа int
и получаем целочисленный дескриптор, на который указывает этот указатель. Если поддерживается более старый элемент
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);