Чтение онлайн

ЖАНРЫ

UNIX: взаимодействие процессов

Стивенс Уильям Ричард

Шрифт:

15.3. Функция door_create

Процесс-сервер определяет некоторую функцию как процедуру сервера вызовом door_create:

#include <door.h>

typedef void Door_server_proc(void *cookie, char *dataptr, size_t datasize, door_desc_t *descptr, size_t ndesc);

int door_create(Door_server_proc *proc, void *cookie, u_int attr);

/*
Возвращает неотрицательный дескриптор в случае успешного завершения, –1 –в случае ошибки */

Здесь мы добавили наше собственное определение типа, что упрощает прототип функции. Это определение утверждает, что процедуры сервера (например, servproc в листинге 15.2) вызываются с пятью аргументами и ничего не возвращают.

Когда сервер вызывает door_create, первый аргумент (proc) указывает адрес процедуры сервера, которая будет вызываться через дескриптор двери, возвращаемый этим вызовом. При вызове процедуры сервера ее аргумент cookie содержит значение, передаваемое в качестве второго аргумента door_create. Это дает серверу возможность передавать процедуре какой-либо указатель каждый раз, когда эта процедура вызывается клиентом. Следующих четыре аргумента процедуры сервера — dataptr, datasize, descptr и ndesc — описывают аргументы-данные и аргументы-дескрипторы клиента. Они соответствуют первым четырем полям структуры door_arg_t, описанной в предыдущем разделе.

Последний аргумент door_create(attr) описывает специальные атрибуты процедуры сервера и может быть равен либо 0, либо логической сумме двух констант:

■ DOOR_PRIVATE — библиотека дверей автоматически создает новые потоки в процессе-сервере при поступлении запросов от клиентов. По умолчанию эти потоки помещаются в пул потоков и могут использоваться для обслуживания запросов клиентов по всем дверям данного процесса.

Указание атрибута DOOR_PRIVATE говорит библиотеке, что для данной двери следует создать собственный пул потоков, отдельный от пула потоков процесса.

■ DOOR_UNREF — когда количество дескрипторов, открытых для данной двери, изменяется с двух до одного, процедура сервера вызывается со вторым аргументом, имеющим значение DOOR_UNREF_DATA. При этом аргумент descptr представляет собой нулевой указатель, а аргументы datasize и ndesc равны нулю. Мы приведем пример использования этого атрибута в листинге 15.13.

Возвращаемое сервером значение имеет тип void, поскольку процедура сервера никогда не завершает работу вызовом return. Вместо этого процедура должна вызывать door_return (функция описана в следующем разделе).

В листинге 15.2 мы видели, что после получения дескриптора двери вызовом door_create сервер должен вызвать fattach для связывания этого дескриптора с некоторым файлом. Клиент затем может открыть этот файл для получения дескриптора двери, который впоследствии может быть использован при вызове door_call.

ПРИМЕЧАНИЕ

Функция fattach не включена в стандарт Posix.1, но ее наличие требуется стандартом Unix 98. Кроме того, этот стандарт определяет также функцию fdetach, отключающую связь дескриптора и файла, и программу fdetach, вызывающую эту функцию.

Для дескрипторов дверей, создаваемых door_create, устанавливается бит FD_CLOEXEC. Это означает, что дескриптор закрывается при вызове процессом функций типа exec. Что касается вызова fork, несмотря на то что открытые родительским процессом дескрипторы используются дочерним процессом совместно с ним, только родительский процесс будет принимать вызовы от клиентов. Дочерним процессам вызовы не передаются, хотя дескриптор, возвращаемый door_create, и будет в них открыт.

ПРИМЕЧАНИЕ

Если мы учтем, что дверь идентифицируется с помощью PID и адреса процедуры сервера (что

мы узнаем из структуры door_info_t в разделе 15.6), ограничения на вызовы exec и fork станут понятны. Дочерний процесс не будет принимать вызовов, поскольку его идентификатор процесса отличается от идентификатора, связанного с дверью. Дескриптор должен быть закрыт при вызове exec, потому что хотя идентификатор при этом и не меняется, адрес процедуры сервера уже не будет иметь никакого смысла в той программе, которая будет запущена после вызова exec.

15.4. Функция door_return

После завершения работы процедуры сервера возврат из нее осуществляется вызовом door_return. Это приводит к возврату из door_call соответствующего клиента. 

#include <door.h>

int door_return(char *dataptr, size_t datasize, door_desc_t *descptr, size_t ndesc);

/* Ничего не возвращает вызвавшему процессу в случае успешного завершения. –1 – в случае ошибки */

Возвращаемые данные задаются аргументами dataptr и datasize, а возвращаемые дескрипторы — descptr и ndesc.

15.5. Функция door_cred

Интерфейс дверей предусматривает полезную возможность получения информации о клиенте при каждом вызове. Это осуществляется функцией door_cred:

#include <door.h>

int door_cred(door_cred_t *cred);

/* Возвращает 0 в случае успешного завершения, –1 – в случае ошибки */

Структура, на которую указывает аргумент cred, имеет тип door_cred_t, определяемый как

typedef struct door_cred {

 uid_t dc_euid; /* действующий идентификатор пользователя клиента */

 gid_t dc_egid; /* действующий идентификатор группы клиента */

 uid_t dc_ruid; /* реальный идентификатор пользователя клиента */

 gid_t dc_rgid; /* реальный идентификатор группы клиента */

 pid_t dc_pid; /* идентификатор процесса клиента */

} door_cred_t;

В эту структуру помещается информация о клиенте при возвращении из вызова door_cred. В разделе 4.4 [21] подробно рассказывается о различиях между действующими и реальными идентификаторами пользователя и группы, а пример использования этой функции приведен в листинге. 15.5.

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

15.6. Функция door_info

Только что описанная функция door_cred предоставляет серверу информацию о клиенте. Клиент же может получить информацию о сервере, вызвав doo_info:

#include <door.h>

int door_info(int fd, door_info_t *info);

/* Возвращает 0 в случае успешного завершения, –1 – в случае ошибки */

Дескриптор fd указывает на открытую дверь. Структура типа door_info_t, на которую указывает info, после возвращения из функции содержит информацию о сервере:

Поделиться с друзьями: