Книга: UNIX: взаимодействие процессов
15.2. Функция door_call
15.2. Функция door_call
Функция door_call вызывается клиентом для обращения к процедуре сервера, выполняемой в адресном пространстве процесса-сервера:
#include <door.h>
int door_call(int fd, door_arg_t *argp);
/* Возвращает 0 в случае успешного завершения. –1 – в случае ошибки */
Дескриптор fd обычно возвращается функцией open (см. листинг 15.1). Полное имя файла, открываемого клиентом, однозначно идентифицирует процедуру сервера, которая вызывается door_call при передаче дескриптора.
Второй аргумент — argp — указывает на структуру, описывающую аргументы и приемный буфер для возвращаемых значений:
typedef struct door_arg {
char *data_ptr; /* при вызове указывает на аргументы, при возврате – на результаты */
size_t data_size; /* при вызове определяет общий размер аргументов в байтах, при возврате – общий размер возвращаемых данных в байтах */
door_desc_t *desc_ptr; /* при вызове указывает на аргументы-дескрипторы, при возврате указывает на возвращаемые дескрипторы */
size_t desc_num; /* при вызове задает количество аргументов-дескрипторов, при возврате задает количество возвращаемых дескрипторов */
char *rbuf; /* указатель на буфер результатов */
size_t rsize; /* размер буфера результатов */
} door_arg_t;
При возврате из удаленного вызова эта структура описывает возвращаемые значения. Все поля структуры могут быть изменены при возврате, мы подробно рассмотрим это ниже.
ПРИМЕЧАНИЕ
Использование типа char* для двух указателей кажется странным и требует использования явного преобразования типов для предотвращения вывода предупреждений компилятора. Естественно было бы использовать указатели типа void*. С указателями char* мы еще столкнемся в функции door_return. Вероятно, в Solaris 2.7 тип данных desc_num изменится на unsigned int и последний аргумент door_return изменится соответствующим образом.
Аргументы и результаты могут быть двух типов: данные и дескрипторы.
? Аргументы-данные представляют собой последовательность данных длиной data_size байт. На эту последовательность должен указывать data_ptr. Клиент и сервер должны заранее знать формат этих данных (и аргументов, и результатов). Нет способа указать серверу тип аргументов. В пpoгрaммax листингов 15.1 и 15.2 клиент и сервер были написаны таким образом, что они оба знали, что аргумент представлял собой одно длинное целое и возвращаемый результат также был одним длинным целым. Для скрытия внутреннего устройства передаваемых данных их можно объединить в структуру, что упростит работу тому, кто будет читать код несколько лет спустя. Итак, все аргументы можно заключить в одну структуру, результаты — в другую и обе их определить в одном заголовочном файле, используемом клиентом и сервером. Пример будет приведен в листингах 15.8 и 15.9. Если аргументов-данных нет, указатель data_ptr должен быть нулевым и размер данных data_size должен иметь значение 0.
ПРИМЕЧАНИЕ
Поскольку клиент и сервер работают с аргументами и результатами, помещаемыми в соответствующие буферы, компилировать их следует одним и тем же компилятором, поскольку разные компиляторы могут по-разному упорядочивать данные в структурах даже в одной и той же системе.
? Аргументы-дескрипторы хранятся в массиве структур door_desc_t, каждая из которых содержит один передаваемый от клиента серверу дескриптор. Количество структур типа door_desc_t задается аргументом desc_num. (Мы описываем эту структуру и смысл «передачи дескриптора» в разделе 15.8.) Если аргументов-дескрипторов нет, следует передать нулевой указатель desc_ptr и присвоить полю desc_num значение 0.
? При возврате из функции data_ptr указывает на результаты-данные, a data_size задает размер возвращаемых данных. Если никакие данные не возвращаются, data_size будет иметь значение 0, а значение указателя data_ptr следует игнорировать.
? Функция может возвращать и дескрипторы, при этом desc_ptr указывает на массив структур типа door_desc_t, каждая из которых содержит один передаваемый сервером клиенту дескриптор. Количество возвращаемых структур типа door_desc_t хранится в поле desc_num. Если дескрипторы не возвращаются, значение desc_num будет равно 0, а указатель desc_ptr следует игнорировать.
Можно спокойно использовать один и тот же буфер для передаваемых аргументов и возвращаемых результатов. При вызове door_call и data_ptr, и desc_ptr могут указывать на буфер, указанный аргументом rbuf.
Перед вызовом door_call клиент устанавливает указатель rbuf на буфер для результатов, a rsize делает равным размеру буфера. После возвращения из функции и data_ptr, и desc_ptr будут указывать на этот буфер. Если он слишком мал для хранения результатов, возвращаемых сервером, библиотека дверей автоматически выделит новый буфер в адресном пространстве клиента с помощью mmap (раздел 12.2) и обновит значения rbuf и rsize соответствующим образом. Поля data_ptr и desc_ptr будут указывать на новый буфер. Клиент отвечает за то, чтобы обнаружить изменение этих указателей и впоследствии освободить занимаемую память вызовом munmap с аргументами rbuf и rsize. Пример будет приведен в листинге 15.4.
- 15.1. Введение
- 15.2. Функция door_call
- 15.3. Функция door_create
- 15.4. Функция door_return
- 15.5. Функция door_cred
- 15.6. Функция door_info
- 15.7. Примеры
- 15.8. Передача дескрипторов
- Пример
- 15.9. Функция door server_create
- 15.10. Функции door_bind, door unbind и door_revoke
- 15.11. Досрочное завершение клиента или сервера
- 15.12. Резюме
- Упражнения
- 15.4. Функция door_return
- 2.1.3. Функция getopt_long()
- Группировка по встроенным функциям и UDF
- 19.1.1. Функция jQuery()
- Функция strcmp( )
- Управление функциями узла
- Функция программного обеспечения
- 3.2. Ключи типа key_t и функция ftok
- 9.10. Функция sctp_recvmsg
- 14.4. backdoor
- Функция document
- Функция generate-id