|
Программирование >> Структура ядра и системные вызовы
cerr client authentication setup failsXn ; perror( authdes seccreate ); clnt perror(clntp,server); clntp->cl auth = authnone create(); #endif } break; default: cerr authentication method (int)choice not yet supportedXn ; clntp->cl auth = authnone create0; /* Вызов RPC-функции */ int call( unsigned procnum, xdrproc t xdr ifunc, caddr t argp, xdrproc t xdr ofunc, caddr t rsltp, unsigned timeout = 20 ) if (!clntp) return -1; struct timeval timv; timv.tv sec = timeout; timv.tv usec =0; if (clnt call(clntp, procnum, xdr ifunc, argp, , xdr ofunc, rsltp, timv)!=RPC SUCCESS) clnt perror(clntp, server); return -2; return RPC SUCCESS; /* Поддержка широковещательного режима */ static int broadcast( unsigned prognum, unsigned versnum, unsigned procnum, resultproc t callbaclt, xdrproc t xdr ifunc, caddr t argp, xdrproc t xdr ofunc, caddr t rsltp, char* nettype = datagram v ) #ifdef SYSV4 return rpc broadcast(prognum, versnum, procnum, xdr ifunc, argp, xdr ofunc, rsltp, callbacjc, nettype); #else return clnt broadcast(prognum, versnum, procnum, xdr ifunc, argp, xdr ofunc, rsltp, callbac)<); #endif ,/* Установить тайм-аут для клиента */ int set timeout( long usee ) if (!clntp) return -1; struct timeval timv; timv.tv sec = 0; timv.tv usec = usee; return clnt control( clntp, CLSET TIMEOUT, (char*)Stimv); /* Получить тайм-аут клиента */ long get timeoutО if (!clntp) return -1; struct timeval timv; if (clnt control( clntp, CLGET TIMEOUT, (char*)Stimv)==-1) perror( clnt control ); return -1; return timv.tv usee; tendif /* RPC H */ Последовательность вызова функций-членов этих классов для типичных клиента и сервера показана на рис. 12.2. Клиент RPC cls::RPC cIs RPC cls::set auth RPC cls::call Сервер RPC svc::RPC svc RPC svc::run func RPC svc::getargs RPC svc::reply Рис. 12.2. Функции клиентского и серверного классов RPC и последовательность их вызова Функция-конструктор RPCsvcr.RPCsvc создает обработчик вызовов RPC-сервера для заданного номера RPC-программы и заданного номера RPC-версии. Кроме того, эта функция регистрирует пользовательскую функцию-Диспетчер, которая активизируется, когда клиент вызывает RPC-функцию, управляемую сервером. Последний аргумент функции RPCsvcr.RPCsvc - значение nettype. Оно задает транспортный протокол для связи между сервером и его клиентами. Функция RPC svc.:RPC svc вызывает API svc create, который создает интерфейс к серверному процессу. Пользователи могут модифицировать функцию RPC svc::RPC svc, чтобы вместо svcjcreate она вызывала svc tp create или svc tli create. Функция RPC svc::run /ипс вызывается для регастрации на сервере RPC-функции и присвоенного ей номера процедуры, а затем блокирует сервер и переводит его в режим ожидания клиентских RPC-вызовов (через API svc run). Если пользователь хочет зарегистрировать на сервере более одной RPC-функции, серверную программу необходимо соответствующим образом изменить: RPC svc svcp = new RPC svc(...); if (Isvcp II svcp->good()) return 1; svcp->add func (<procnuniI>, prog2) ; svcp->add func (<procnuniW-I>, progN-1) ; svcp->run func (<procnuniW>, progN) ; Когда поступает клиентский RPC-запрос, то вызывается зарегистрированная с помощью функции RPC svc::RPC svc функция-диспетчер, которая обслуживает клиентский запрос. Функция-диспетчер проверяет, равен ли затребованный клиентом RPC-у. номер нулю. Если равен, то клиент просто запрашивает сервер, а сервер просто посылает клиенту ответ с NULL-значением. Если клиент указывает какие-то аутентификахдаонные данные, диспетчер проверяет их и при отрицательном результате выставляет флаг ошибки аутентификации. В данной функции аутентификация клиента выполняется по усмотрению сторон. Если речь идет о защите RPC-транзакций, то аутентификация обязательна. Сервер должен всегда требовать, rгoбы клиенты посылали аутентификационные данные в каждом RPC-вызове. Метод RPC-аутентификации рассматривается в одном из следующих разделов. При положительном результате аутентификации диспетчер вызывает RPC-функцию, затребованную клиет-ом. Каждая RPC-функция, вызываемая функцией RPCjsvc::dispatch, должна иметь следующий прототип: int <имя функции> (SVCXPRT*); где аргументом является указатель на обработчик для механизма транспортировки, используемого для связи с конечной точкой транспортировки клиента. В случае успешного выполнения функция возвращает нуль (RPC SUCCESS), а в случае неудачи - ненулевое значение. Помимо этого данная RPC-функция должна обрабатывать глобальный указатель RPCjsvc * (имя его переменной определяется приложением), в котором находится адрес указателя на RPC-сервер. Функция сначала должна вызвать RPC svc::getargs, чтобы извлечь аргументы из клиентского запроса, а затем RPCjsvcr.reply, чтобы передать клиенту возвращенное ею значение. В клиентской профамме обработчик клиента для заданных номеров профаммы и версии создается с помощью функции-конструктора RPC cls::RPC cls. Эта функция получает указатель на клиента путем внутреннего вызова API clnt create. Как и функция-конструктор RPCsvc, функция RPCcbr.RPCcls может бьггь модифицирована пользователями так, чтобы вызывать не clntjcreate, а clnt tp create или clnt tli create. Аутентификационные данные клиента можно установить, вызвав функцию RPC cls::set Класс RPC cls поддерживает режимы AUTH NONE, AUTH SYS и AUTH DES, но пользователи могуг модифицировать функцию RPC cls::set auth, чтобы реализовать собственные методы аутентификации. Методы аутентификации AUTH NONE, AUTH SYS и AUTH DES рассмотрены в одном из следующих разделов. В ONC вместо AUTH SYS используется AUTH UNIX. Клиент вызывает RPC-функцию с помощью функции RPC cls::call. Аргументами функции RPC cls::call являются номер RPC-процедуры, XDR-функция, преобразующая входные аргументы в формат XDR, адрес переменной, в которой содержатся входные аргументы, XDR-функция, преобразующая значение, возвращенное данной RPC-функцией (из формата XDR в формат локальной машины), и адрес переменной, содержащей значение, возвращенное RPC-функцией. При успешном выполнении функция RPC cls::call возвращает RPCSUCCESS, а в случае неудачи - ненулевое значение. Статическая функция RPC cls:broadcast обеспечивает передачу широковещательных RPC-запросов из клиентского процесса по сети всем серверным процессам. Подробно эта функция рассмотрена в разделе 12.8. Приложения, в которых используются классы RPC, в различных коммерческих разновидностях UNIX должны компилироваться со следующими опциями: Разновидность UNIX Опции компиляции СС Solaris 2.x Sun OS 4.1.x HP-UX 9.0.x IBM AIX 3.x и 4.x SCO 3.x -DSYSV4 -Isocket -Insl *-Insl Нет -Irpcsvc -Isocket Эти опции компиляции показывают, какие системные библиотеки RPC нужно связывать с пользовательскими приложениями в разных UNIX-системах. Опция -DSYSV4 в системе Solaris 2.x необходима для того, чтобы вместо API ONC использовались API RPC UNIX System V.4. Чтобы проиллюстрировать использование классов RPC, перепишем профамму удаленной печати сообщений, приведенную в разделе 12.3. Обратите внимание на то, что новые клиентская и серверная профаммы проще предыдущих версий, в которых используется компилятор rpcgen. Клиентская программа msg cls2.C ъышящгг следующим образом: /* Клиентская программа: использование низкоуровневых API RPC tinclude msg2.h ♦include RPC.h int main(int argc, char* argv[]) { if (argc<3) ( cerr usage: argv[0] << host msg <nettype>\n ; . return 1; II? ( /f Создать обработчик клиента для RPC-сервера */ ,1.}} RpC cls с1( argv[l], MSGPROG, MSGVER, argc>=4 ? argv[3]: netpath ); if (Icl.goodO) return 1; /* Вызвать RPC-функцию printmsg. Возвращаемое значение устанавливается в res */ int res; if (cl.calK PRIMTMSG, (xdrproc t)xdr string, (caddr t)sargv[2], (xdrproG t)xdr int, (caddr t)Sres) != RPC SUCCESS) return 3; /* Проверить возвращаемое значение RPC-функции */ if (res!=0) cerr clnt: call printmsg fails\n ; else cout clnt: call printmsg succeeds\n ; return 0; Эта клиентская программа вызывается с двумя или тремя аргументами. Первый аргумент - хост-имя машины, на которой работает RPC-сервер. Это может быть имя локальной машины, если клиент и сервер работают на одном компьютере. Второй аргумент - символьная строка сообщения, передаваемого на RPC-сервер для вывода на печать. Третий аргумент (необязательный) - это транспортный протокол, который должен использоваться клиентом для связи с сервером. Если третий аргумент не указан, по умолчанию принимается значение netpath . Допустимые значения третьего аргумента такие же, как для аргумента nettype в API clnt create (см. раздел 12.3.1). Заголовок msg2.h определяется пользователем и содержит только объявление RPC-номеров программы, версии и процедуры для функции printmsg;. * Please do not edit this file. * It was generated using rpcgen. */ #ifndef MSG2 H RPCGEN ♦define MSG2 H RPCGEN ♦ikclude <rpc/rpc.h> ♦define MSGPROG ((unsigned long)(0x20000001)) ♦deq.ne MSGVER ((unsigned long)(l)) ♦define PRINTMSG ((unsigned long)(1)) ♦endif /* ! MSG H RPCGEN */ Программа RPC-сервера, соответствующая вышеупомянутой клиентской программе, называется msg svc2.C: /* программа-сервер: низкоуровневые API RPC */ /* вызов: msg svc2 <механизм транспортировки> */ ♦include <fstream.h> ♦include <stdlib.h> ♦include msg2.h ♦include RPC.h RPC svc *svcp; int printmsg( SVCXPRT* xtrp ) int res = 0; chr *msg =0; if (svcp->getargs( xtrp, (xdrproc t)xdr string, ( cadd!5 t) smsg) !=>RPC SUCCESS) return -1; ofstream ofs( /dev/console ); if (ofs) ofs server: msg Лп ; else res = -1; if (svcp->reply(xtrp, (xdrproc t)xdr int, (caddr t)Sres)!-RPC SUCCESS) res - -2; return res; int main(int argc, char* argv[]) RPC svc *svcp = new RPC svc( MSGPROG, MSGVER, argc==2 ? argv[l] : netpath ); if (svcp && svcp->run func( PRINTMSG, printmsg )) return 2; return 0; /* сюда программа переходит только в том случае, если создание обработчика сервера завершается неудачно */
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |