Пример применения socketpair()
показан далее в главе.
17.4.6. Передача файловых дескрипторов
Сокеты домена Unix обладают уникальным свойством: через них могут передаваться файловые дескрипторы. Ни один из прочих механизмов IPC не поддерживает подобную возможность. Она позволяет процессу открыть файл и передать файловый дескриптор в другой (возможно, несвязанный) процесс. Все проверки доступа выполняются при открытии файла, поэтому получающий процесс приобретает те же самые права доступа к файлу, что и исходный процесс.
Файловые дескрипторы передаются как часть более сложного сообщения, которое отправляется с помощью системного вызова sendmsg()
и принимается через recvmsg()
.
#include
int sendmsg(int fd, const struct msghdr * msg, unsigned int flags);
int recvmsg(int fd, struct msghdr * msg, unsigned int flags);
Параметр fd
является файловым дескриптором, через который передается сообщение; второй параметр служит указателем на структуру, описывающую сообщение. Параметр flags
обычно не используется и для большинства приложений должен быть равен нулю. В специализированных книгах по программированию для сетей обсуждаются доступные флаги [33].
Сообщение описывается показанной ниже структурой.
#include
#include
struct msghdr {
void * msg_name; /* дополнительный адрес */
unsigned int msg_namelen; /* размер msg_name */
struct iovec * msg_iov; /* массив для чтения вразброс/сборной записи*/
unsigned int msg_iovlen; /* количество элементов в msg_iov */
void * msg_control; /* вспомогательные данные */
unsigned int msg_controllen;/* длина буфера вспомогательных данных */
int msg_flags; /* флаги на получаемом сообщении */
};
Первые два члена msg_name
и msg_namelen
не используются в потоковых протоколах. Приложения, посылающие сообщения через потоковые сокеты, должны устанавливать для msg_name
значение NULL
, для msg_namelen
— ноль.
msg_iov
и msg_iovlen
описывают набор буферов, которые отправляют или принимают. Чтение вразброс и сборная запись, а также struct iovec
, обсуждаются в конце главы 13. Последний член структуры msg_flags
в настоящее время не используется и должен равняться нулю.
Два элемента, которые мы пропустили, msg_control
и msg_controllen
предоставляют возможность передачи файлового дескриптора. Член msg_control
указывает на массив заголовков управляющих сообщений; msg_controllen
устанавливает количество байт, которые содержит массив. Каждое управляющее сообщение состоит из структуры struct cmsghdr
, которая сопровождается дополнительными данными.
#include
struct cmsghdr {
unsigned int cmsg_len; /* длина управляющего сообщения */
int cmsg_level; /* SOL_SOCKET */
int cmsg_type; /* SCM_RIGHTS */
int cmsg_data[0]; /* здесь должен быть файловый дескриптор */
};
Размер управляющего сообщения, включая заголовок, хранится в переменной cmsg_len
. В текущий момент определен только один тип управляющих сообщений — SCM_RIGHTS
, который передает файловые дескрипторы [125] Это иногда называется передачей прав доступа.
. Для данного типа сообщений параметры cmsg_level
и cmsg
_type должны быть равны соответственно SOL_SOCKET
и SCM_RIGHTS
. Последний член cmsg_data
является массивом нулевого размера. Это расширение gcc, которое позволяет приложению копировать данные в конец структуры (в следующей программе показан пример).
Получение файлового дескриптора происходит аналогично. Необходимо выделить достаточное пространство буфера для управляющего сообщения, и каждая приходящая структура struct cmsghdr
будет сопровождаться новым файловым дескриптором.
Для иллюстрации использования таких вложенных структур мы написали пример программы, которая по нашей прихоти названа просто cat
. Она принимает имя файла в качестве единственного аргумента, открывает указанный файл в дочернем процессе и передает результирующий файловый дескриптор в родительский процесс через сокет домена Unix. Родительский процесс затем копирует файл на стандартный вывод. Имя файла посылается вместе с файловым дескриптором с демонстрационной целью.
1: /* passfd.с */
2:
3: /* Программа ведет себя подобно обычной команде /bin/cat, которая обрабатывает
4: только один аргумент (имя файла). Мы создаем сокеты домена Unix при помощи
5: socketpair(), затем разветвляем через fork(). Дочерний процесс открывает файл,
6: имя которого передается в командной строке, пересылает файловый дескриптор и
Читать дальше