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

16.9. Форматы пакетов RPC

16.9. Форматы пакетов RPC

На рис. 16.5 приведен формат запроса RPC в пакете TCP.

Поскольку TCP передает поток байтов и не предусматривает границ сообщений, приложение должно предусматривать способ разграничения сообщений. Sun RPC определяет запись как запрос или ответ, и каждая запись состоит из одного или более фрагментов. Каждый фрагмент начинается с 4-байтового значения: старший бит является флагом последнего фрагмента, а следующие 31 бит представляют собой счетчик (длина фрагмента). Если бит последнего фрагмента имеет значение 0, данный фрагмент не является последним в записи.

ПРИМЕЧАНИЕ

Это 4-байтовое значение передается в порядке big-endian, так же как и 4-байтовые целые в XDR, но оно не относится к стандарту XDR, поскольку он не предусматривает передачи битовых полей.

Если вместо TCP используется UDP, первое поле в заголовке UDP будет идентификатором транзакции (XID), как показано на рис. 16.7.

ПРИМЕЧАНИЕ

При использовании TCP на размер запроса и ответа RPC ограничения не накладываются, поскольку может использоваться любое количество фрагментов, а длина каждого из них задается 31-разрядным целым. Но при использовании протокола UDP запрос (и ответ) должен помещаться в дейтаграмму целиком, а максимальное количество данных в ней — 65507 байт (для IPv4). Во многих реализациях, предшествовавших TI-RPC, размер ограничивался значением около 8192 байт, поэтому если требуется передавать более 8000 байт, следует пользоваться протоколом TCP.


Рис. 16.5. Запрос RPC в пакете TCP

Приведем спецификацию XDR для запроса RPC, взятую из RFC 1831. Имена на рис. 16.5 взяты из этой спецификации:

enum autn_flavor {
 AUTH_NONE = 0,
 AUTH_SYS = 1,
 AUTH_SHORT = 2
 /* and more to be defined */
};
struct opaque_auth {
 auth_flavor flavor;
 opaque body<400>;
};
enum msg_type {
 CALL = 0,
 REPLY = 1
};
struct call_body {
 unsigned int rpcvers; /* версия RPC: должна быть 2 */
 unsigned int prog; /* номер программы */
 unsigned int vers; /* номер версии */
 unsigned int proc; /* номер процедуры */
 opaque_auth cred; /* данные вызывающего */
 opaque_auth verf; /* проверочная информация вызывающего */
/* параметры, относящиеся к процедуре */
};
struct rpc_msg {
 unsigned int xid;
 union switch (msg_type mtype) {
 case CALL:
  call_body cbody;
 case REPLY:
  reply_body rbody;
 } body;
};

Содержимое скрытых данных переменной длины, содержащих сведения о пользователе и проверочную информацию, зависит от типа аутентификации. Для нулевой аутентификации, используемой по умолчанию, длина этих данных должна быть установлена в 0. Для аутентификации Unix эти данные содержат следующую структуру:

struct authsys_parms {
 unsigned int stamp;
 string machinename<255>;
 unsigned int uid;
 unsigned int gid;
 unsigned int gids<16>;
};

Если тип аутентификации AUTH_SYS, тип проверки должен быть AUTH_NONE. Формат ответа RPC сложнее, чем формат запроса, поскольку в нем могут передаваться сообщения об ошибках. На рис. 16.6 показаны возможные варианты. На рис. 16.7 показан формат ответа RPC в случае успешного выполнения процедуры. Ответ передается по протоколу UDP. 

Ниже приводится текст спецификации XDR ответа RPC, взятый из RFC 1831.

enum reply_stat {
 MSG_ACCEPTED = 0,
 MSG_DENIED = 1
};
enum accept_stat {
 SUCCESS = 0, /* успешное завершение вызова RPC */
 PROG_UNAVAIL = 1, /* требуемый номер программы недоступен */
 PROG_MISMATCH = 2, /* требуемый номер версии недоступен */
 PROC_UNAVAIL = 3, /* номер процедуры недоступен */
 GARBAGE_ARGS = 4, /* не могу декодировать аргументы */
 SYSTEM_ERR = 5 /* ошибка выделения памяти и т. п. */
};
struct accepted_reply {
 opaque_auth verf;
 union switch (accept_stat stat) {
 case SUCCESS:
  opaque results[0]; /* результаты, возвращаемые процедурой */
 case PROG_MISMATCH:
  struct {
   unsigned int low; /* наименьший поддерживаемый номер программы */
   unsigned int high; /* наибольший поддерживаемый номер программы */
  } mismatch_info;
 default: /* PROG_UNAVAIL, PROC_UNAVAIL, GARBAGE_ARGS, SYSTEM_ERR */
  void;
 } reply_data;
};
union reply_body switch (reply_stat stat) {
case MSG_ACCEPTED:
 accepted_reply areply;
case MSG_DENIED:
 rejected_reply rreply;
} reply;


Рис. 16.6. Возможные варианты ответов RPC

Вызов может быть отклонен сервером, если номер версии RPC не тот или возникает ошибка аутентификации:

enum reject_stat {
 RPC_MISMATCH = 0, /* номер версии RPC отличен от 2 */
 AUTH_ERROR =1 /* ошибка аутентификации */
};
enum auth_stat {
 AUTH_OK = 0, /* успешное завершение */
 /* ошибки на сервере */
 AUTH_BADCRED = 1, /* ошибка в личных данных пользователя (нарушена контрольная сумма) */
 AUTH_REJECTEDCRED = 2, /* клиент должен начать сеанс заново */
 AUTH_BADVERF = 3, /* ошибка в проверочных данных (нарушена контрольная сумма) */
 AUTH_REJECTEDVERF = 4, /* проверочные данные устарели или были повторы */
 AUTH_TOOWEAK = 5, /* запрос отклонен системой безопасности */
 /* ошибки клиента */
 AUTH_INVALIDRESP = 6, /* фальшивые проверочные данные в ответе */
 AUTH_FAILED = 7 /* причина неизвестна */
};
union rejected_reply switch (reject_stat stat) {
case RPC_MISMATCH:
 struct {
  unsigned int low; /* наименьший номер версии RPC */
  unsigned int high; /* наибольший номер версии RPC */
 } mismatch_info;
case AUTH_ERROR:
 auth_stat stat;
};


Рис. 16.7. Ответ на успешно обработанный вызов в дейтаграмме UDP

Оглавление книги


Генерация: 1.758. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз