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

VxWorks

开发平台:

C/C++

  1. /* clnt_tcp.c - implements a TCP/IP based, client side RPC */
  2. /* Copyright 1984-2001 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. 01t,05nov01,vvv  fixed compilation warning
  38. 01s,15oct01,rae  merge from truestack ver 01t, base 01r (NULL check)
  39. 01r,01aug96,dbt  close the socket if connection failed in clnttc_create
  40.  (SPR #3803).
  41.  Updated copyright.
  42. 01q,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  43. 01p,17sep92,wmd  changed how assignment of ntohl(--(*msg_x_id)) to x_id is
  44.  written to avoid erroneous side-effect by i960 compiler.
  45. 01o,26may92,rrr  the tree shuffle
  46.   -changed includes to have absolute path from h/
  47. 01n,04oct91,rrr  passed through the ansification filter
  48.   -changed includes to have absolute path from h/
  49.   -changed VOID to void
  50.   -changed copyright notice
  51. 01m,01apr91,elh   removed clnt_tcpInit (this is included via clnt_generic).
  52. 01l,25oct90,dnw   removed include of utime.h.
  53. 01k,24oct90,dnw   changed clnt_tcpInit from void to void.
  54. 01j,10may90,dnw   changed taskModuleList->rpccreateerr to rpccreateerr macro
  55.   changed to use rpcErrnoGet instead of errnoGet
  56. 01i,19apr90,hjb   de-linted.
  57. 01h,27oct89,hjb   upgraded to 4.0
  58. 01g,22jun88,dnw   name tweaks.
  59. 01f,30may88,dnw   changed to v4 names.
  60. 01e,05apr88,gae   updated select() to BSD4.3, i.e. used "fd_set".
  61.   changed fprintf() to printErr().
  62. 01d,22feb88,jcf   made kernel independent.
  63. 01c,12feb88,rdc   added clnt_tcpInit.
  64.   changed tcpread and tcpwrite to clnt_tcpread, clnt_tcpwrite
  65.   to avoid clash with corresponding routines in svc_tcp.c.
  66. 01b,11nov87,jlf   added wrs copyright, title, mod history, etc.
  67. 01a,01nov87,rdc   first VxWorks version
  68. */
  69. #ifndef lint
  70. /* static char sccsid[] = "@(#)clnt_tcp.c 1.1 86/02/03 Copyr 1984 Sun Micro"; */
  71. #endif
  72. /*
  73.  * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
  74.  *
  75.  *
  76.  * TCP based RPC supports 'batched calls'.
  77.  * A sequence of calls may be batched-up in a send buffer.  The rpc call
  78.  * return immediately to the client even though the call was not necessarily
  79.  * sent.  The batching occurs iff the results' xdr routine is NULL (0) AND
  80.  * the rpc timeout value is zero (see clnt.h, rpc).
  81.  *
  82.  * Clients should NOT casually batch calls that in fact return results; that is,
  83.  * the server side should be aware that a call is batched and not produce any
  84.  * return message.  Batched calls that produce many result messages can
  85.  * deadlock (netlock) the client and the server....
  86.  *
  87.  * Now go hang yourself.
  88.  */
  89. #include "rpc/rpctypes.h"
  90. #include "sys/socket.h"
  91. #include "netinet/in.h"
  92. #include "errno.h"
  93. #include "rpc/xdr.h"
  94. #include "rpc/auth.h"
  95. #include "rpc/clnt.h"
  96. #include "rpc/rpc_msg.h"
  97. #include "rpc/pmap_clnt.h"
  98. #include "vxWorks.h"
  99. #include "rpc/rpcGbl.h"
  100. #include "memLib.h"
  101. #include "stdio.h"
  102. #include "unistd.h"
  103. #include "rpcLib.h"
  104. #include "sockLib.h"
  105. #include "tickLib.h"
  106. #define MCALL_MSG_SIZE 24
  107. LOCAL int clnt_readtcp();
  108. LOCAL int clnt_writetcp();
  109. LOCAL enum clnt_stat clnttcp_call(); /* 4.0 */
  110. LOCAL void clnttcp_abort(); /* 4.0 */
  111. LOCAL void clnttcp_geterr(); /* 4.0 */
  112. LOCAL bool_t clnttcp_freeres(); /* 4.0 */
  113. LOCAL bool_t clnttcp_control(); /* 4.0 */
  114. LOCAL void clnttcp_destroy(); /* 4.0 */
  115. static struct clnt_ops tcp_ops = {
  116. clnttcp_call,
  117. clnttcp_abort,
  118. clnttcp_geterr,
  119. clnttcp_freeres,
  120. clnttcp_destroy,
  121. clnttcp_control /* 4.0 */
  122. };
  123. struct ct_data {
  124. int ct_sock;
  125. bool_t ct_closeit; /* 4.0 */
  126. struct timeval ct_wait;
  127. bool_t ct_waitset; /* 4.0 - wait bit set by clnt_control */
  128. struct sockaddr_in ct_addr; /* 4.0 */
  129. struct rpc_err ct_error;
  130. char ct_mcall[MCALL_MSG_SIZE]; /* marshalled callmsg */
  131. u_int ct_mpos; /* pos after marshal */
  132. XDR ct_xdrs;
  133. };
  134. IMPORT bool_t xdr_opaque_auth ();
  135. /*
  136.  * Create a client handle for a tcp/ip connection.
  137.  * If *sockp<0, *sockp is set to a newly created TCP socket and it is
  138.  * connected to raddr.  If *sockp non-negative then
  139.  * raddr is ignored.  The rpc/tcp package does buffering
  140.  * similar to stdio, so the client must pick send and receive buffer sizes,];
  141.  * 0 => use the default.
  142.  * If raddr->sin_port is 0, then a binder on the remote machine is
  143.  * consulted for the right port number.
  144.  * NB: *sockp is copied into a private area.
  145.  * NB: It is the clients responsibility to close *sockp.
  146.  * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
  147.  * something more useful.
  148.  */
  149. CLIENT *
  150. clnttcp_create(raddr, prog, vers, sockp, sendsz, recvsz)
  151. struct sockaddr_in *raddr;
  152. u_long prog;
  153. u_long vers;
  154. register int *sockp;
  155. u_int sendsz;
  156. u_int recvsz;
  157. {
  158. CLIENT *h;
  159. register struct ct_data *ct = NULL;
  160. /*struct timeval now;*/
  161. struct rpc_msg call_msg;
  162. h  = (CLIENT *)mem_alloc(sizeof(*h));
  163. if (h == NULL) {
  164. printErr ("clnttcp_create: out of memoryn");
  165. rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  166.   rpc_createerr.cf_error.re_errno = rpcErrnoGet ();
  167. goto fooy;
  168. }
  169. ct = (struct ct_data *)mem_alloc(sizeof(*ct));
  170. if (ct == NULL) {
  171. printErr ("clnttcp_create: out of memoryn");
  172. rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  173. rpc_createerr.cf_error.re_errno = rpcErrnoGet ();
  174. goto fooy;
  175. }
  176. /*
  177.  * If no port number given ask the pmap for one
  178.  */
  179. if (raddr->sin_port == 0) {
  180. u_short port;
  181. if ((port = pmap_getport(raddr, prog, vers, (u_long)IPPROTO_TCP)) == 0) {
  182. mem_free((caddr_t)ct, sizeof(struct ct_data));
  183. mem_free((caddr_t)h, sizeof(CLIENT));
  184. return ((CLIENT *)NULL);
  185. }
  186. raddr->sin_port = htons(port);
  187. }
  188. /*
  189.  * If no socket given, open one
  190.  */
  191. if (*sockp < 0) {
  192. if (((*sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
  193.     || (connect(*sockp, (struct sockaddr *)raddr,
  194.     sizeof(*raddr)) < 0)) {
  195. if (*sockp >= 0)
  196.     (void) close (*sockp);
  197. rpc_createerr.cf_stat = RPC_SYSTEMERROR;
  198. rpc_createerr.cf_error.re_errno = rpcErrnoGet ();
  199. goto fooy;
  200. }
  201. ct->ct_closeit = TRUE; /* 4.0 */
  202. } else {
  203. ct->ct_closeit = FALSE; /* 4.0 */
  204. }
  205. /*
  206.  * Set up private data struct
  207.  */
  208. ct->ct_sock = *sockp;
  209. ct->ct_wait.tv_usec = 0;
  210. ct->ct_waitset = FALSE; /* 4.0 */
  211. ct->ct_addr = *raddr; /* 4.0 */
  212. /*
  213.  * Initialize call message
  214.  */
  215. /* XXX (void)gettimeofday(&now, (struct timezone *)0); */
  216. /* call_msg.rm_xid = getpid() ^  now.tv_sec ^ now.tv_usec; */
  217. call_msg.rm_xid = taskIdSelf () ^  tickGet ();
  218. call_msg.rm_direction = CALL;
  219. call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
  220. call_msg.rm_call.cb_prog = prog;
  221. call_msg.rm_call.cb_vers = vers;
  222. /*
  223.  * pre-serialize the staic part of the call msg and stash it away
  224.  */
  225. xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
  226.     XDR_ENCODE);
  227. if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
  228. if (ct->ct_closeit)  /* 4.0 */
  229.     {
  230.     (void) close (*sockp);
  231.     }
  232. goto fooy;
  233. }
  234. ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
  235. XDR_DESTROY(&(ct->ct_xdrs));
  236. /*
  237.  * Create a client handle which uses xdrrec for serialization
  238.  * and authnone for authentication.
  239.  */
  240. xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
  241.     (caddr_t)ct, clnt_readtcp, clnt_writetcp);
  242. h->cl_ops = &tcp_ops;
  243. h->cl_private = (caddr_t) ct;
  244. h->cl_auth = authnone_create();
  245. return (h);
  246. fooy:
  247. /*
  248.  * Something goofed, free stuff and barf
  249.  */
  250. if (ct != NULL)
  251.     mem_free((caddr_t)ct, sizeof(struct ct_data));
  252. if (h != NULL)
  253.     mem_free((caddr_t)h, sizeof(CLIENT));
  254. /* XXX (void)close(*sockp);    RPC 4.0 doesn't do this -- it checks ct_closeit
  255. instead */
  256. return ((CLIENT *)NULL);
  257. }
  258. LOCAL enum clnt_stat /* 4.0 */
  259. clnttcp_call(h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
  260. register CLIENT *h;
  261. u_long proc;
  262. xdrproc_t xdr_args;
  263. caddr_t args_ptr;
  264. xdrproc_t xdr_results;
  265. caddr_t results_ptr;
  266. struct timeval timeout;
  267. {
  268. register struct ct_data *ct = (struct ct_data *) h->cl_private;
  269. register XDR *xdrs = &(ct->ct_xdrs);
  270. struct rpc_msg reply_msg;
  271. u_long x_id;
  272. u_long *msg_x_id = (u_long *)(ct->ct_mcall); /* yuk */
  273. register bool_t shipnow;
  274. int refreshes = 2; /* 4.0 */
  275. if (!ct->ct_waitset) /* 4.0 */
  276.     { /* 4.0 */
  277.     ct->ct_wait = timeout;
  278.     } /* 4.0 */
  279. shipnow =
  280.     (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0
  281.     && timeout.tv_usec == 0) ? FALSE : TRUE;
  282. call_again:
  283. xdrs->x_op = XDR_ENCODE;
  284. ct->ct_error.re_status = RPC_SUCCESS;
  285. --(*msg_x_id);
  286. x_id = ntohl(*msg_x_id);
  287. if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
  288.     (! XDR_PUTLONG(xdrs, (long *)&proc)) ||
  289.     (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
  290.     (! (*xdr_args)(xdrs, args_ptr))) {
  291. if (ct->ct_error.re_status == RPC_SUCCESS)
  292. ct->ct_error.re_status = RPC_CANTENCODEARGS;
  293. (void)xdrrec_endofrecord(xdrs, TRUE);
  294. return (ct->ct_error.re_status);
  295. }
  296. if (! xdrrec_endofrecord(xdrs, shipnow))
  297. return (ct->ct_error.re_status = RPC_CANTSEND);
  298. if (! shipnow)
  299. return (RPC_SUCCESS);
  300. /*
  301.  *  Hack to provide rpc-based message passing
  302.  */
  303.  if (timeout.tv_sec == 0 && timeout.tv_usec == 0) /* 4.0 */
  304.      { /* 4.0 */
  305.      return (ct->ct_error.re_status = RPC_TIMEDOUT); /* 4.0 */
  306.      } /* 4.0 */
  307. xdrs->x_op = XDR_DECODE;
  308. /*
  309.  * Keep receiving until we get a valid transaction id
  310.  */
  311. while (TRUE) {
  312. reply_msg.acpted_rply.ar_verf = _null_auth;
  313. reply_msg.acpted_rply.ar_results.where = NULL;
  314. reply_msg.acpted_rply.ar_results.proc = xdr_void;
  315. if (! xdrrec_skiprecord(xdrs))
  316. return (ct->ct_error.re_status);
  317. /* now decode and validate the response header */
  318. if (! xdr_replymsg(xdrs, &reply_msg)) {
  319. if (ct->ct_error.re_status == RPC_SUCCESS)
  320. continue;
  321. return (ct->ct_error.re_status);
  322. }
  323. if (reply_msg.rm_xid == x_id)
  324. break;
  325. }
  326. /*
  327.  * process header
  328.  */
  329. _seterr_reply(&reply_msg, &(ct->ct_error));
  330. if (ct->ct_error.re_status == RPC_SUCCESS) {
  331. if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
  332. ct->ct_error.re_status = RPC_AUTHERROR;
  333. ct->ct_error.re_why = AUTH_INVALIDRESP;
  334. } else if (! (*xdr_results)(xdrs, results_ptr)) {
  335. if (ct->ct_error.re_status == RPC_SUCCESS)
  336. ct->ct_error.re_status = RPC_CANTDECODERES;
  337. }
  338. /* free verifier ... */
  339. if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
  340. xdrs->x_op = XDR_FREE;
  341. (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
  342. }
  343. }  /* end successful completion */
  344. else {
  345. /* maybe our credentials need to be refreshed ... */
  346. if (refreshes-- && AUTH_REFRESH(h->cl_auth))
  347. goto call_again;
  348. }  /* end of unsuccessful completion */
  349. return (ct->ct_error.re_status);
  350. }
  351. LOCAL void /* 4.0 */
  352. clnttcp_geterr(h, errp)
  353. CLIENT *h;
  354. struct rpc_err *errp;
  355. {
  356. register struct ct_data *ct =
  357.     (struct ct_data *) h->cl_private;
  358. *errp = ct->ct_error;
  359. }
  360. LOCAL bool_t /* 4.0 */
  361. clnttcp_freeres(cl, xdr_res, res_ptr)
  362. CLIENT *cl;
  363. xdrproc_t xdr_res;
  364. caddr_t res_ptr;
  365. {
  366. register struct ct_data *ct = (struct ct_data *)cl->cl_private;
  367. register XDR *xdrs = &(ct->ct_xdrs);
  368. xdrs->x_op = XDR_FREE;
  369. return ((*xdr_res)(xdrs, res_ptr));
  370. }
  371. LOCAL void /* 4.0 */
  372. clnttcp_abort()
  373. {
  374. }
  375. LOCAL bool_t /* 4.0 */
  376. clnttcp_control (cl, request, info) /* 4.0 */
  377.     CLIENT *cl; /* 4.0 */
  378.     int request; /* 4.0 */
  379.     char *info; /* 4.0 */
  380.     { /* 4.0 */
  381.     register struct ct_data *ct = (struct ct_data *)cl->cl_private;  /* 4.0 */
  382.     switch (request) /* 4.0 */
  383. { /* 4.0 */
  384. case CLSET_TIMEOUT: /* 4.0 */
  385.     ct->ct_wait = *(struct timeval *) info; /* 4.0 */
  386.     ct->ct_waitset = TRUE; /* 4.0 */
  387.     break; /* 4.0 */
  388. case CLGET_TIMEOUT: /* 4.0 */
  389.     *(struct timeval *) info = ct->ct_wait; /* 4.0 */
  390.     break; /* 4.0 */
  391. case CLGET_SERVER_ADDR: /* 4.0 */
  392.     *(struct sockaddr_in *) info = ct->ct_addr; /* 4.0 */
  393.     break; /* 4.0 */
  394. default: /* 4.0 */
  395.     return (FALSE); /* 4.0 */
  396. } /* 4.0 */
  397.     return (TRUE); /* 4.0 */
  398.     } /* 4.0 */
  399. LOCAL void /* 4.0 */
  400. clnttcp_destroy(h)
  401. CLIENT *h;
  402. {
  403. register struct ct_data *ct =
  404.     (struct ct_data *) h->cl_private;
  405. if (ct->ct_closeit) /* new in 4.0 */
  406.     (void) close (ct->ct_sock);
  407. XDR_DESTROY(&(ct->ct_xdrs));
  408. mem_free((caddr_t)ct, sizeof(struct ct_data));
  409. mem_free((caddr_t)h, sizeof(CLIENT));
  410. }
  411. /*
  412.  * Interface between xdr serializer and tcp connection.
  413.  * Behaves like the system calls, read & write, but keeps some error state
  414.  * around for the rpc level.
  415.  */
  416. LOCAL int /* 4.0 */
  417. clnt_readtcp(ct, buf, len)
  418. register struct ct_data *ct;
  419. caddr_t buf;
  420. register int len;
  421. {
  422. fd_set mask; /* 4.0 */
  423. fd_set readFds;
  424. if (len == 0)
  425.     return (0);
  426. FD_ZERO (&mask); /* 4.0 */
  427. FD_SET (ct->ct_sock, &mask); /* 4.0 */
  428. while (TRUE) {
  429. readFds = mask;     /* 4.0 */
  430. switch (select (FD_SETSIZE, &readFds, (fd_set *)NULL,  /* 4.0 */
  431. (fd_set *)NULL, &(ct->ct_wait))) {     /* 4.0 */
  432. case 0:
  433. ct->ct_error.re_status = RPC_TIMEDOUT;
  434. return (-1);
  435. case -1:
  436. if (rpcErrnoGet () == EINTR)
  437. continue;
  438. ct->ct_error.re_status = RPC_CANTRECV;
  439. ct->ct_error.re_errno = rpcErrnoGet ();
  440. return (-1);
  441. }
  442. /* XXX 4.0 if (FD_ISSET(fd, &readFds))  */
  443. break;
  444. }
  445. switch (len = read(ct->ct_sock, buf, len)) {
  446. case 0:
  447. /* premature eof */
  448. ct->ct_error.re_errno = ECONNRESET;
  449. ct->ct_error.re_status = RPC_CANTRECV;
  450. len = -1;  /* it's really an error */
  451. break;
  452. case -1:
  453. ct->ct_error.re_errno = rpcErrnoGet ();
  454. ct->ct_error.re_status = RPC_CANTRECV;
  455. break;
  456. }
  457. return (len);
  458. }
  459. LOCAL int /* 4.0 */
  460. clnt_writetcp(ct, buf, len)
  461. struct ct_data *ct;
  462. caddr_t buf;
  463. int len;
  464. {
  465. register int i, cnt;
  466. for (cnt = len; cnt > 0; cnt -= i, buf += i) {
  467. if ((i = write(ct->ct_sock, buf, cnt)) == -1) {
  468. ct->ct_error.re_errno = rpcErrnoGet ();
  469. ct->ct_error.re_status = RPC_CANTSEND;
  470. return (-1);
  471. }
  472. }
  473. return (len);
  474. }