OSDN Git Service

More hiding, including __mempcpy
[uclinux-h8/uClibc.git] / libc / inet / rpc / clnt_tcp.c
1 /* @(#)clnt_tcp.c       2.2 88/08/01 4.0 RPCSRC */
2 /*
3  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4  * unrestricted use provided that this legend is included on all tape
5  * media and as a part of the software program in whole or part.  Users
6  * may copy or modify Sun RPC without charge, but are not authorized
7  * to license or distribute it to anyone else except as part of a product or
8  * program developed by the user.
9  *
10  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13  *
14  * Sun RPC is provided with no support and without any obligation on the
15  * part of Sun Microsystems, Inc. to assist in its use, correction,
16  * modification or enhancement.
17  *
18  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20  * OR ANY PART THEREOF.
21  *
22  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23  * or profits or other special, indirect and consequential damages, even if
24  * Sun has been advised of the possibility of such damages.
25  *
26  * Sun Microsystems, Inc.
27  * 2550 Garcia Avenue
28  * Mountain View, California  94043
29  */
30 #if 0
31 static char sccsid[] = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
32 #endif
33
34 /*
35  * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
36  *
37  * Copyright (C) 1984, Sun Microsystems, Inc.
38  *
39  * TCP based RPC supports 'batched calls'.
40  * A sequence of calls may be batched-up in a send buffer.  The rpc call
41  * return immediately to the client even though the call was not necessarily
42  * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
43  * the rpc timeout value is zero (see clnt.h, rpc).
44  *
45  * Clients should NOT casually batch calls that in fact return results; that is,
46  * the server side should be aware that a call is batched and not produce any
47  * return message.  Batched calls that produce many result messages can
48  * deadlock (netlock) the client and the server....
49  *
50  * Now go hang yourself.
51  */
52
53 #define authnone_create __authnone_create
54 #define xdrrec_create __xdrrec_create
55 #define xdrmem_create __xdrmem_create
56
57 #define __FORCE_GLIBC
58 #include <features.h>
59
60 #include <netdb.h>
61 #include <errno.h>
62 #include <stdio.h>
63 #include <unistd.h>
64 #include <rpc/rpc.h>
65 #include <sys/poll.h>
66 #include <sys/socket.h>
67 #include <rpc/pmap_clnt.h>
68 #ifdef USE_IN_LIBIO
69 # include <wchar.h>
70 #endif
71
72 extern u_long _create_xid (void) attribute_hidden;
73
74 #define MCALL_MSG_SIZE 24
75
76 struct ct_data
77   {
78     int ct_sock;
79     bool_t ct_closeit;
80     struct timeval ct_wait;
81     bool_t ct_waitset;          /* wait set by clnt_control? */
82     struct sockaddr_in ct_addr;
83     struct rpc_err ct_error;
84     char ct_mcall[MCALL_MSG_SIZE];      /* marshalled callmsg */
85     u_int ct_mpos;              /* pos after marshal */
86     XDR ct_xdrs;
87   };
88
89 static int readtcp (char *, char *, int);
90 static int writetcp (char *, char *, int);
91
92 static enum clnt_stat clnttcp_call (CLIENT *, u_long, xdrproc_t, caddr_t,
93                                     xdrproc_t, caddr_t, struct timeval);
94 static void clnttcp_abort (void);
95 static void clnttcp_geterr (CLIENT *, struct rpc_err *);
96 static bool_t clnttcp_freeres (CLIENT *, xdrproc_t, caddr_t);
97 static bool_t clnttcp_control (CLIENT *, int, char *);
98 static void clnttcp_destroy (CLIENT *);
99
100 static struct clnt_ops tcp_ops =
101 {
102   clnttcp_call,
103   clnttcp_abort,
104   clnttcp_geterr,
105   clnttcp_freeres,
106   clnttcp_destroy,
107   clnttcp_control
108 };
109
110 /*
111  * Create a client handle for a tcp/ip connection.
112  * If *sockp<0, *sockp is set to a newly created TCP socket and it is
113  * connected to raddr.  If *sockp non-negative then
114  * raddr is ignored.  The rpc/tcp package does buffering
115  * similar to stdio, so the client must pick send and receive buffer sizes,];
116  * 0 => use the default.
117  * If raddr->sin_port is 0, then a binder on the remote machine is
118  * consulted for the right port number.
119  * NB: *sockp is copied into a private area.
120  * NB: It is the clients responsibility to close *sockp.
121  * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
122  * something more useful.
123  */
124 CLIENT *
125 clnttcp_create (struct sockaddr_in *raddr, u_long prog, u_long vers,
126                 int *sockp, u_int sendsz, u_int recvsz)
127 {
128   CLIENT *h;
129   struct ct_data *ct;
130   struct rpc_msg call_msg;
131
132   h = (CLIENT *) mem_alloc (sizeof (*h));
133   ct = (struct ct_data *) mem_alloc (sizeof (*ct));
134   if (h == NULL || ct == NULL)
135     {
136       struct rpc_createerr *ce = &get_rpc_createerr ();
137 #ifdef USE_IN_LIBIO
138       if (_IO_fwide (stderr, 0) > 0)
139         (void) __fwprintf (stderr, L"%s",
140                            _("clnttcp_create: out of memory\n"));
141       else
142 #endif
143         (void) fputs (_("clnttcp_create: out of memory\n"), stderr);
144       ce->cf_stat = RPC_SYSTEMERROR;
145       ce->cf_error.re_errno = ENOMEM;
146       goto fooy;
147     }
148
149   /*
150    * If no port number given ask the pmap for one
151    */
152   if (raddr->sin_port == 0)
153     {
154       u_short port;
155       if ((port = pmap_getport (raddr, prog, vers, IPPROTO_TCP)) == 0)
156         {
157           mem_free ((caddr_t) ct, sizeof (struct ct_data));
158           mem_free ((caddr_t) h, sizeof (CLIENT));
159           return ((CLIENT *) NULL);
160         }
161       raddr->sin_port = htons (port);
162     }
163
164   /*
165    * If no socket given, open one
166    */
167   if (*sockp < 0)
168     {
169       *sockp = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
170       (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
171       if ((*sockp < 0)
172           || (connect (*sockp, (struct sockaddr *) raddr,
173                          sizeof (*raddr)) < 0))
174         {
175           struct rpc_createerr *ce = &get_rpc_createerr ();
176           ce->cf_stat = RPC_SYSTEMERROR;
177           ce->cf_error.re_errno = errno;
178           if (*sockp >= 0)
179             (void) __close (*sockp);
180           goto fooy;
181         }
182       ct->ct_closeit = TRUE;
183     }
184   else
185     {
186       ct->ct_closeit = FALSE;
187     }
188
189   /*
190    * Set up private data struct
191    */
192   ct->ct_sock = *sockp;
193   ct->ct_wait.tv_usec = 0;
194   ct->ct_waitset = FALSE;
195   ct->ct_addr = *raddr;
196
197   /*
198    * Initialize call message
199    */
200   call_msg.rm_xid = _create_xid ();
201   call_msg.rm_direction = CALL;
202   call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
203   call_msg.rm_call.cb_prog = prog;
204   call_msg.rm_call.cb_vers = vers;
205
206   /*
207    * pre-serialize the static part of the call msg and stash it away
208    */
209   xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
210                  XDR_ENCODE);
211   if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
212     {
213       if (ct->ct_closeit)
214         {
215           (void) __close (*sockp);
216         }
217       goto fooy;
218     }
219   ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
220   XDR_DESTROY (&(ct->ct_xdrs));
221
222   /*
223    * Create a client handle which uses xdrrec for serialization
224    * and authnone for authentication.
225    */
226   xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
227                  (caddr_t) ct, readtcp, writetcp);
228   h->cl_ops = &tcp_ops;
229   h->cl_private = (caddr_t) ct;
230   h->cl_auth = authnone_create ();
231   return h;
232
233 fooy:
234   /*
235    * Something goofed, free stuff and barf
236    */
237   mem_free ((caddr_t) ct, sizeof (struct ct_data));
238   mem_free ((caddr_t) h, sizeof (CLIENT));
239   return ((CLIENT *) NULL);
240 }
241
242 static enum clnt_stat
243 clnttcp_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
244      CLIENT *h;
245      u_long proc;
246      xdrproc_t xdr_args;
247      caddr_t args_ptr;
248      xdrproc_t xdr_results;
249      caddr_t results_ptr;
250      struct timeval timeout;
251 {
252   struct ct_data *ct = (struct ct_data *) h->cl_private;
253   XDR *xdrs = &(ct->ct_xdrs);
254   struct rpc_msg reply_msg;
255   u_long x_id;
256   u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall);   /* yuk */
257   bool_t shipnow;
258   int refreshes = 2;
259
260   if (!ct->ct_waitset)
261     {
262       ct->ct_wait = timeout;
263     }
264
265   shipnow =
266     (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
267      && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
268
269 call_again:
270   xdrs->x_op = XDR_ENCODE;
271   ct->ct_error.re_status = RPC_SUCCESS;
272   x_id = ntohl (--(*msg_x_id));
273   if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
274       (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
275       (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
276       (!(*xdr_args) (xdrs, args_ptr)))
277     {
278       if (ct->ct_error.re_status == RPC_SUCCESS)
279         ct->ct_error.re_status = RPC_CANTENCODEARGS;
280       (void) xdrrec_endofrecord (xdrs, TRUE);
281       return (ct->ct_error.re_status);
282     }
283   if (!xdrrec_endofrecord (xdrs, shipnow))
284     return ct->ct_error.re_status = RPC_CANTSEND;
285   if (!shipnow)
286     return RPC_SUCCESS;
287   /*
288    * Hack to provide rpc-based message passing
289    */
290   if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
291     {
292       return ct->ct_error.re_status = RPC_TIMEDOUT;
293     }
294
295
296   /*
297    * Keep receiving until we get a valid transaction id
298    */
299   xdrs->x_op = XDR_DECODE;
300   while (TRUE)
301     {
302       reply_msg.acpted_rply.ar_verf = _null_auth;
303       reply_msg.acpted_rply.ar_results.where = NULL;
304       reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
305       if (!xdrrec_skiprecord (xdrs))
306         return (ct->ct_error.re_status);
307       /* now decode and validate the response header */
308       if (!xdr_replymsg (xdrs, &reply_msg))
309         {
310           if (ct->ct_error.re_status == RPC_SUCCESS)
311             continue;
312           return ct->ct_error.re_status;
313         }
314       if ((u_int32_t) reply_msg.rm_xid == (u_int32_t) x_id)
315         break;
316     }
317
318   /*
319    * process header
320    */
321   _seterr_reply (&reply_msg, &(ct->ct_error));
322   if (ct->ct_error.re_status == RPC_SUCCESS)
323     {
324       if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
325         {
326           ct->ct_error.re_status = RPC_AUTHERROR;
327           ct->ct_error.re_why = AUTH_INVALIDRESP;
328         }
329       else if (!(*xdr_results) (xdrs, results_ptr))
330         {
331           if (ct->ct_error.re_status == RPC_SUCCESS)
332             ct->ct_error.re_status = RPC_CANTDECODERES;
333         }
334       /* free verifier ... */
335       if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
336         {
337           xdrs->x_op = XDR_FREE;
338           (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
339         }
340     }                           /* end successful completion */
341   else
342     {
343       /* maybe our credentials need to be refreshed ... */
344       if (refreshes-- && AUTH_REFRESH (h->cl_auth))
345         goto call_again;
346     }                           /* end of unsuccessful completion */
347   return ct->ct_error.re_status;
348 }
349
350 static void
351 clnttcp_geterr (h, errp)
352      CLIENT *h;
353      struct rpc_err *errp;
354 {
355   struct ct_data *ct =
356   (struct ct_data *) h->cl_private;
357
358   *errp = ct->ct_error;
359 }
360
361 static bool_t
362 clnttcp_freeres (cl, xdr_res, res_ptr)
363      CLIENT *cl;
364      xdrproc_t xdr_res;
365      caddr_t res_ptr;
366 {
367   struct ct_data *ct = (struct ct_data *) cl->cl_private;
368   XDR *xdrs = &(ct->ct_xdrs);
369
370   xdrs->x_op = XDR_FREE;
371   return (*xdr_res) (xdrs, res_ptr);
372 }
373
374 static void
375 clnttcp_abort ()
376 {
377 }
378
379 static bool_t
380 clnttcp_control (CLIENT *cl, int request, char *info)
381 {
382   struct ct_data *ct = (struct ct_data *) cl->cl_private;
383
384
385   switch (request)
386     {
387     case CLSET_FD_CLOSE:
388       ct->ct_closeit = TRUE;
389       break;
390     case CLSET_FD_NCLOSE:
391       ct->ct_closeit = FALSE;
392       break;
393     case CLSET_TIMEOUT:
394       ct->ct_wait = *(struct timeval *) info;
395       ct->ct_waitset = TRUE;
396       break;
397     case CLGET_TIMEOUT:
398       *(struct timeval *) info = ct->ct_wait;
399       break;
400     case CLGET_SERVER_ADDR:
401       *(struct sockaddr_in *) info = ct->ct_addr;
402       break;
403     case CLGET_FD:
404       *(int *)info = ct->ct_sock;
405       break;
406     case CLGET_XID:
407       /*
408        * use the knowledge that xid is the
409        * first element in the call structure *.
410        * This will get the xid of the PREVIOUS call
411        */
412       *(u_long *)info = ntohl (*(u_long *)ct->ct_mcall);
413       break;
414     case CLSET_XID:
415       /* This will set the xid of the NEXT call */
416       *(u_long *)ct->ct_mcall =  htonl (*(u_long *)info - 1);
417       /* decrement by 1 as clnttcp_call() increments once */
418     case CLGET_VERS:
419       /*
420        * This RELIES on the information that, in the call body,
421        * the version number field is the fifth field from the
422        * begining of the RPC header. MUST be changed if the
423        * call_struct is changed
424        */
425       *(u_long *)info = ntohl (*(u_long *)(ct->ct_mcall +
426                                            4 * BYTES_PER_XDR_UNIT));
427       break;
428     case CLSET_VERS:
429       *(u_long *)(ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
430         = htonl (*(u_long *)info);
431       break;
432     case CLGET_PROG:
433       /*
434        * This RELIES on the information that, in the call body,
435        * the program number field is the  field from the
436        * begining of the RPC header. MUST be changed if the
437        * call_struct is changed
438        */
439       *(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall +
440                                           3 * BYTES_PER_XDR_UNIT));
441       break;
442     case CLSET_PROG:
443       *(u_long *)(ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
444         = htonl(*(u_long *)info);
445       break;
446     /* The following are only possible with TI-RPC */
447     case CLGET_RETRY_TIMEOUT:
448     case CLSET_RETRY_TIMEOUT:
449     case CLGET_SVC_ADDR:
450     case CLSET_SVC_ADDR:
451     case CLSET_PUSH_TIMOD:
452     case CLSET_POP_TIMOD:
453     default:
454       return FALSE;
455     }
456   return TRUE;
457 }
458
459
460 static void
461 clnttcp_destroy (CLIENT *h)
462 {
463   struct ct_data *ct =
464   (struct ct_data *) h->cl_private;
465
466   if (ct->ct_closeit)
467     {
468       (void) __close (ct->ct_sock);
469     }
470   XDR_DESTROY (&(ct->ct_xdrs));
471   mem_free ((caddr_t) ct, sizeof (struct ct_data));
472   mem_free ((caddr_t) h, sizeof (CLIENT));
473 }
474
475 /*
476  * Interface between xdr serializer and tcp connection.
477  * Behaves like the system calls, read & write, but keeps some error state
478  * around for the rpc level.
479  */
480 static int
481 readtcp (char *ctptr, char *buf, int len)
482 {
483   struct ct_data *ct = (struct ct_data *)ctptr;
484   struct pollfd fd;
485   int milliseconds = (ct->ct_wait.tv_sec * 1000) +
486     (ct->ct_wait.tv_usec / 1000);
487
488   if (len == 0)
489     return 0;
490
491   fd.fd = ct->ct_sock;
492   fd.events = POLLIN;
493   while (TRUE)
494     {
495       switch (poll(&fd, 1, milliseconds))
496         {
497         case 0:
498           ct->ct_error.re_status = RPC_TIMEDOUT;
499           return -1;
500
501         case -1:
502           if (errno == EINTR)
503             continue;
504           ct->ct_error.re_status = RPC_CANTRECV;
505           ct->ct_error.re_errno = errno;
506           return -1;
507         }
508       break;
509     }
510   switch (len = __read (ct->ct_sock, buf, len))
511     {
512
513     case 0:
514       /* premature eof */
515       ct->ct_error.re_errno = ECONNRESET;
516       ct->ct_error.re_status = RPC_CANTRECV;
517       len = -1;                 /* it's really an error */
518       break;
519
520     case -1:
521       ct->ct_error.re_errno = errno;
522       ct->ct_error.re_status = RPC_CANTRECV;
523       break;
524     }
525   return len;
526 }
527
528 static int
529 writetcp (char *ctptr, char *buf, int len)
530 {
531   int i, cnt;
532   struct ct_data *ct = (struct ct_data*)ctptr;
533
534   for (cnt = len; cnt > 0; cnt -= i, buf += i)
535     {
536       if ((i = __write (ct->ct_sock, buf, cnt)) == -1)
537         {
538           ct->ct_error.re_errno = errno;
539           ct->ct_error.re_status = RPC_CANTSEND;
540           return -1;
541         }
542     }
543   return len;
544 }