clnt_udp.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:14k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* clnt_udp.c - implements a UPD/IP based, client side RPC */
  2. /* Copyright 1984-2000 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5.  * Copyright (C) 1984, Sun Microsystems, Inc.
  6.  *
  7.  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  8.  * unrestricted use provided that this legend is included on all tape
  9.  * media and as a part of the software program in whole or part.  Users
  10.  * may copy or modify Sun RPC without charge, but are not authorized
  11.  * to license or distribute it to anyone else except as part of a product or
  12.  * program developed by the user.
  13.  *
  14.  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  15.  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  16.  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  17.  *
  18.  * Sun RPC is provided with no support and without any obligation on the
  19.  * part of Sun Microsystems, Inc. to assist in its use, correction,
  20.  * modification or enhancement.
  21.  *
  22.  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  23.  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  24.  * OR ANY PART THEREOF.
  25.  *
  26.  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  27.  * or profits or other special, indirect and consequential damages, even if
  28.  * Sun has been advised of the possibility of such damages.
  29.  *
  30.  * Sun Microsystems, Inc.
  31.  * 2550 Garcia Avenue
  32.  * Mountain View, California  94043
  33.  */
  34. /*
  35. modification history
  36. --------------------
  37. 01p,18apr00,ham  fixed compilation warnings.
  38. 01o,28jul96,sgv  fix for spr #1477, Increased the send window size and
  39.  receive window size to 8000.
  40. 01n,22apr93,caf  ansification: added cast to ioctl() parameter.
  41. 01m,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  42. 01l,26may92,rrr  the tree shuffle
  43.   -changed includes to have absolute path from h/
  44. 01k,04oct91,rrr  passed through the ansification filter
  45.   -changed includes to have absolute path from h/
  46.   -changed copyright notice
  47. 01j,25oct90,dnw   removed include of utime.h.
  48. 01i,10may90,dnw   changed taskModuleList->rpccreateerr to rpccreateerr macro
  49.   changed to use rpcErrnoGet instead of errnoGet
  50. 01h,18mar90,jcf   fixed header dependency.
  51. 01g,27oct89,hjb   upgraded to 4.0
  52. 01f,22jun88,dnw   name tweaks.
  53. 01e,30may88,dnw   changed to v4 names.
  54. 01d,05apr88,gae   updated select() to BSD4.3, i.e. used "fd_set".
  55.   changed fprintf() to printErr().
  56. 01c,22feb88,jcf   made kernel independent.
  57. 01b,11nov87,jlf   added wrs copyright, title, mod history, etc.
  58. 01a,01nov87,rdc   first VxWorks version
  59. */
  60. #ifndef lint
  61. /* static char sccsid[] = "@(#)clnt_udp.c 1.1 86/02/03 Copyr 1984 Sun Micro"; */
  62. #endif
  63. /*
  64.  * clnt_udp.c, Implements a UPD/IP based, client side RPC.
  65.  *
  66.  */
  67. #include "rpc/rpctypes.h"
  68. #include "sys/socket.h"
  69. #include "sys/ioctl.h"
  70. #include "netinet/in.h"
  71. #include "errno.h"
  72. #include "rpc/xdr.h"
  73. #include "rpc/auth.h"
  74. #include "rpc/clnt.h"
  75. #include "rpc/rpc_msg.h"
  76. #include "rpc/pmap_clnt.h"
  77. #include "vxWorks.h"
  78. #include "rpc/rpcGbl.h"
  79. #include "ioLib.h"
  80. #include "memLib.h"
  81. #include "stdio.h"
  82. #include "rpcLib.h"
  83. #include "tickLib.h"
  84. #include "sockLib.h"
  85. #include "remLib.h"
  86. /*
  87.  * UDP bases client side rpc operations
  88.  */
  89. LOCAL enum clnt_stat clntudp_call(); /* 4.0 */
  90. LOCAL void clntudp_abort(); /* 4.0 */
  91. LOCAL void clntudp_geterr(); /* 4.0 */
  92. LOCAL bool_t clntudp_control(); /* 4.0 */
  93. LOCAL void clntudp_destroy(); /* 4.0 */
  94. /*
  95.  * clntudp_freeres () is used by nfsLib.c so it cannot be declared as LOCAL.
  96.  */
  97. bool_t clntudp_freeres();
  98. static struct clnt_ops udp_ops = {
  99. clntudp_call,
  100. clntudp_abort,
  101. clntudp_geterr,
  102. clntudp_freeres,
  103. clntudp_destroy,
  104. clntudp_control /* 4.0 */
  105. };
  106. /*
  107.  * Private data kept per client handle
  108.  */
  109. struct cu_data {
  110. int    cu_sock;
  111. bool_t    cu_closeit; /* 4.0 */
  112. struct sockaddr_in cu_raddr;
  113. int    cu_rlen;
  114. struct timeval    cu_wait;
  115. struct timeval    cu_total; /* 4.0 */
  116. struct rpc_err    cu_error;
  117. XDR    cu_outxdrs;
  118. u_int    cu_xdrpos;
  119. u_int    cu_sendsz;
  120. char    *cu_outbuf;
  121. u_int    cu_recvsz;
  122. char    cu_inbuf[1];
  123. };
  124. IMPORT bool_t xdr_opaque_auth ();
  125. /*
  126.  * Create a UDP based client handle.
  127.  * If *sockp<0, *sockp is set to a newly created UPD socket.
  128.  * If raddr->sin_port is 0 a binder on the remote machine
  129.  * is consulted for the correct port number.
  130.  * NB: It is the clients responsibility to close *sockp.
  131.  * NB: The rpch->cl_auth is initialized to null authentication.
  132.  *     Caller may wish to set this something more useful.
  133.  *
  134.  * wait is the amount of time used between retransmitting a call if
  135.  * no response has been heard;  retransmition occurs until the actual
  136.  * rpc call times out.
  137.  *
  138.  * sendsz and recvsz are the maximum allowable packet sizes that can be
  139.  * sent and received.
  140.  */
  141. CLIENT *
  142. clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
  143. struct sockaddr_in *raddr;
  144. u_long program;
  145. u_long version;
  146. struct timeval wait;
  147. register int *sockp;
  148. u_int sendsz;
  149. u_int recvsz;
  150. {
  151. CLIENT *cl = NULL;
  152. register struct cu_data *cu = NULL;
  153. /* XXX struct timeval now;*/
  154. struct rpc_msg call_msg;
  155. cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
  156. if (cl == NULL) {
  157. printErr ("clntudp_create: out of memoryn");
  158. rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  159. rpc_createerr.cf_error.re_errno = rpcErrnoGet ();
  160. goto fooy;
  161. }
  162. sendsz = ((sendsz + 3) / 4) * 4;
  163. recvsz = ((recvsz + 3) / 4) * 4;
  164. cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
  165. if (cu == NULL) {
  166. printErr ("clntudp_create: out of memoryn");
  167. rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  168. rpc_createerr.cf_error.re_errno = rpcErrnoGet ();
  169. goto fooy;
  170. }
  171. cu->cu_outbuf = &cu->cu_inbuf[recvsz];
  172. /* XXX (void)gettimeofday(&now, (struct timezone *)0); */
  173. if (raddr->sin_port == 0) {
  174. u_short port;
  175. if ((port =
  176.     pmap_getport(raddr, program, version, (u_long)IPPROTO_UDP)) == 0) {
  177. goto fooy;
  178. }
  179. raddr->sin_port = htons(port);
  180. }
  181. cl->cl_ops = &udp_ops;
  182. cl->cl_private = (caddr_t)cu;
  183. cu->cu_raddr = *raddr;
  184. cu->cu_rlen = sizeof (cu->cu_raddr);
  185. cu->cu_wait = wait;
  186. cu->cu_total.tv_sec = -1;
  187. cu->cu_total.tv_usec = -1;
  188. cu->cu_sendsz = sendsz;
  189. cu->cu_recvsz = recvsz;
  190. /* XXX call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; */
  191. call_msg.rm_xid = taskIdSelf () ^ tickGet ();
  192. call_msg.rm_direction = CALL;
  193. call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  194. call_msg.rm_call.cb_prog = program;
  195. call_msg.rm_call.cb_vers = version;
  196. xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
  197.     sendsz, XDR_ENCODE);
  198. if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
  199. goto fooy;
  200. }
  201. cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
  202. if (*sockp < 0) {
  203. int dontblock = 1;
  204. *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
  205. if (*sockp < 0) {
  206. rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  207. rpc_createerr.cf_error.re_errno = rpcErrnoGet ();
  208. goto fooy;
  209. }
  210. setsockopt (*sockp, SOL_SOCKET, SO_SNDBUF, (char *)&(sendsz),
  211.                             sizeof(long));
  212.      setsockopt (*sockp, SOL_SOCKET, SO_RCVBUF, (char *)&(recvsz),
  213.                             sizeof(long));
  214. /* attemp to bind to private port */
  215. (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
  216. /* the sockets rpc controls are non-blocking */
  217. (void)ioctl(*sockp, FIONBIO, (int) &dontblock);
  218. cu->cu_closeit = TRUE;
  219. } else {
  220. cu->cu_closeit = FALSE;
  221. }
  222. cu->cu_sock = *sockp;
  223. cl->cl_auth = authnone_create();
  224. return (cl);
  225. fooy:
  226. if (cu)
  227. mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
  228. if (cl)
  229. mem_free((caddr_t)cl, sizeof(CLIENT));
  230. return ((CLIENT *)NULL);
  231. }
  232. CLIENT *
  233. clntudp_create(raddr, program, version, wait, sockp)
  234. struct sockaddr_in *raddr;
  235. u_long program;
  236. u_long version;
  237. struct timeval wait;
  238. register int *sockp;
  239. {
  240. return(clntudp_bufcreate(raddr, program, version, wait, sockp,
  241.     UDPMSGSIZE, UDPMSGSIZE));
  242. }
  243. LOCAL enum clnt_stat  /* 4.0 */
  244. clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
  245. register CLIENT *cl; /* client handle */
  246. u_long proc; /* procedure number */
  247. xdrproc_t xargs; /* xdr routine for args */
  248. caddr_t argsp; /* pointer to args */
  249. xdrproc_t xresults; /* xdr routine for results */
  250. caddr_t resultsp; /* pointer to results */
  251. struct timeval utimeout;   /* seconds to wait before giving up - 4.0 */
  252. {
  253. register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  254. register XDR *xdrs;
  255. register int outlen;
  256. register int inlen;
  257. int fromlen;
  258. fd_set readFds;
  259. fd_set mask; /* 4.0 */
  260. struct sockaddr_in from;
  261. struct rpc_msg reply_msg;
  262. XDR reply_xdrs;
  263. struct timeval time_waited;
  264. bool_t ok;
  265. int nrefreshes = 2; /* number of times to refresh cred   4.0 */
  266. struct timeval timeout;
  267. if (cu->cu_total.tv_usec == -1) { /* 4.0 */
  268. timeout = utimeout; /* use supplied timeout -- 4.0 */
  269. } else {
  270. timeout = cu->cu_total; /* use default timeout  -- 4.0 */
  271. }
  272. time_waited.tv_sec = 0;
  273. time_waited.tv_usec = 0;
  274. call_again: /* 4.0 */
  275. xdrs = &(cu->cu_outxdrs);
  276. xdrs->x_op = XDR_ENCODE;
  277. XDR_SETPOS(xdrs, cu->cu_xdrpos);
  278. /*
  279.  * the transaction is the first thing in the out buffer
  280.  */
  281. (*(u_short *)(cu->cu_outbuf))++;
  282. if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
  283.     (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
  284.     (! (*xargs)(xdrs, argsp)))
  285.     {
  286.     return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
  287.     }
  288. outlen = (int)XDR_GETPOS(xdrs);
  289. send_again: /* 4.0 */
  290. if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
  291.     (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen)
  292.     != outlen) {
  293. cu->cu_error.re_errno = rpcErrnoGet ();
  294. return (cu->cu_error.re_status = RPC_CANTSEND);
  295. }
  296. /*
  297.  * Hack to provide rpc-based message passing
  298.  */
  299. if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { /* 4.0 */
  300. return (cu->cu_error.re_status = RPC_TIMEDOUT); /* 4.0 */
  301. } /* 4.0 */
  302. /*
  303.  * sub-optimal code appears inside the loop because we have
  304.  * some clock time to spare while the packets are in flight.
  305.  * (We assume that this is actually only executed once.)
  306.  */
  307. reply_msg.acpted_rply.ar_verf = _null_auth;
  308. reply_msg.acpted_rply.ar_results.where = resultsp;
  309. reply_msg.acpted_rply.ar_results.proc = xresults;
  310. FD_ZERO (&mask); /* 4.0 */
  311. FD_SET (cu->cu_sock, &mask); /* 4.0 */
  312. for (;;) { /* 4.0 */
  313. readFds = mask; /* 4.0 */
  314. switch (select (FD_SETSIZE, &readFds, (fd_set *)NULL,
  315. (fd_set *)NULL, &(cu->cu_wait)))
  316. {
  317. case 0:
  318. time_waited.tv_sec += cu->cu_wait.tv_sec;
  319. time_waited.tv_usec += cu->cu_wait.tv_usec;
  320. while (time_waited.tv_usec >= 1000000) {
  321. time_waited.tv_sec++;
  322. time_waited.tv_usec -= 1000000;
  323. }
  324. if ((time_waited.tv_sec < timeout.tv_sec) ||
  325. ((time_waited.tv_sec == timeout.tv_sec) &&
  326. (time_waited.tv_usec < timeout.tv_usec)))
  327. goto send_again;
  328. return (cu->cu_error.re_status = RPC_TIMEDOUT);
  329. /*
  330.  * buggy in other cases because time_waited is not being
  331.  * updated
  332.  */
  333. case -1:
  334. if (rpcErrnoGet () == EINTR)
  335. continue; /* 4.0 */
  336. cu->cu_error.re_errno = rpcErrnoGet ();
  337. return (cu->cu_error.re_status = RPC_CANTRECV);
  338. }
  339. do {
  340. fromlen = sizeof (struct sockaddr);
  341. inlen = recvfrom (cu->cu_sock, cu->cu_inbuf,
  342.   (int) cu->cu_recvsz, 0,
  343.   (struct sockaddr *) &from, &fromlen);
  344. } while (inlen < 0 && (rpcErrnoGet () == EINTR));
  345. if (inlen < 0) {
  346. if (rpcErrnoGet () == EWOULDBLOCK)
  347. continue; /* 4.0 */
  348. cu->cu_error.re_errno = rpcErrnoGet ();
  349. return (cu->cu_error.re_status = RPC_CANTRECV);
  350. }
  351. if (inlen < sizeof(u_long))
  352. continue;
  353. /* see if reply transaction id matches sent id */
  354. if (*((u_long *)(cu->cu_inbuf)) != *((u_long *)(cu->cu_outbuf)))
  355. continue; /* 4.0 */
  356. /* we now assume we have the proper reply */
  357. break;
  358. }
  359. /*
  360.  * now decode and validate the response
  361.  */
  362. xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
  363. ok = xdr_replymsg(&reply_xdrs, &reply_msg);
  364. /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
  365. if (ok) {
  366. _seterr_reply(&reply_msg, &(cu->cu_error));
  367. if (cu->cu_error.re_status == RPC_SUCCESS) {
  368. if (! AUTH_VALIDATE(cl->cl_auth,
  369. &reply_msg.acpted_rply.ar_verf)) {
  370. cu->cu_error.re_status = RPC_AUTHERROR;
  371. cu->cu_error.re_why = AUTH_INVALIDRESP;
  372. }
  373. if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
  374. xdrs->x_op = XDR_FREE;
  375. (void)xdr_opaque_auth(xdrs,
  376.     &(reply_msg.acpted_rply.ar_verf));
  377. }
  378. }  /* end successful completion */
  379. else {
  380. /* maybe our credentials need to be refreshed ... */
  381. if (nrefreshes > 0 &&  /* 4.0 */
  382.     AUTH_REFRESH(cl->cl_auth))
  383. goto call_again;
  384. }  /* end of unsuccessful completion */
  385. }  /* end of valid reply message */
  386. else {
  387. cu->cu_error.re_status = RPC_CANTDECODERES;
  388. }
  389. return (cu->cu_error.re_status);
  390. }
  391. LOCAL void
  392. clntudp_geterr(cl, errp)
  393. CLIENT *cl;
  394. struct rpc_err *errp;
  395. {
  396. register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  397. *errp = cu->cu_error;
  398. }
  399. bool_t /* 4.0 */
  400. clntudp_freeres(cl, xdr_res, res_ptr)
  401. CLIENT *cl;
  402. xdrproc_t xdr_res;
  403. caddr_t res_ptr;
  404. {
  405. register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  406. register XDR *xdrs = &(cu->cu_outxdrs);
  407. xdrs->x_op = XDR_FREE;
  408. return ((*xdr_res)(xdrs, res_ptr));
  409. }
  410. LOCAL void  /* 4.0 */
  411. clntudp_abort(/*h*/)
  412. /*CLIENT *h;*/
  413. {
  414. }
  415. LOCAL bool_t /* 4.0 */
  416. clntudp_control (cl, request, info)
  417.     CLIENT *cl;
  418.     int request;
  419.     char *info;
  420.     {
  421.     register struct cu_data *cu = (struct cu_data *) cl->cl_private;
  422.     switch (request)
  423. {
  424. case CLSET_TIMEOUT:
  425. cu->cu_total = *(struct timeval *) info;
  426. break;
  427. case CLGET_TIMEOUT:
  428. *(struct timeval *) info = cu->cu_total;
  429. break;
  430. case CLSET_RETRY_TIMEOUT:
  431. cu->cu_wait = *(struct timeval *)info;
  432. break;
  433. case CLGET_RETRY_TIMEOUT:
  434. *(struct timeval *) info = cu->cu_wait;
  435. break;
  436. case CLGET_SERVER_ADDR:
  437. *(struct sockaddr_in *) info = cu->cu_raddr;
  438. break;
  439. default:
  440. return (FALSE);
  441. }
  442.     return (TRUE);
  443.     }
  444. LOCAL void /* 4.0 */
  445. clntudp_destroy(cl)
  446. CLIENT *cl;
  447. {
  448. register struct cu_data *cu = (struct cu_data *)cl->cl_private;
  449. if (cu->cu_closeit) { /* 4.0 */
  450. (void) close (cu->cu_sock); /* 4.0 */
  451. } /* 4.0 */
  452. XDR_DESTROY(&(cu->cu_outxdrs));
  453. mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz));
  454. mem_free((caddr_t)cl, sizeof(CLIENT));
  455. }