OSDN Git Service

hidden_def/hidden_proto: convert all users (I hope) termios split, add some missing...
[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 __FORCE_GLIBC
54 #include <features.h>
55
56 #include <netdb.h>
57 #include <errno.h>
58 #include <stdio.h>
59 #include <unistd.h>
60 #include <rpc/rpc.h>
61 #include <sys/poll.h>
62 #include <sys/socket.h>
63 #include <rpc/pmap_clnt.h>
64 #ifdef USE_IN_LIBIO
65 # include <wchar.h>
66 #endif
67
68 libc_hidden_proto(socket)
69 libc_hidden_proto(read)
70 libc_hidden_proto(write)
71 libc_hidden_proto(close)
72 libc_hidden_proto(authnone_create)
73 libc_hidden_proto(xdrrec_create)
74 libc_hidden_proto(xdrrec_endofrecord)
75 libc_hidden_proto(xdrrec_skiprecord)
76 libc_hidden_proto(xdr_callhdr)
77 libc_hidden_proto(xdr_replymsg)
78 libc_hidden_proto(xdr_opaque_auth)
79 libc_hidden_proto(xdrmem_create)
80 libc_hidden_proto(pmap_getport)
81 libc_hidden_proto(_seterr_reply)
82 libc_hidden_proto(connect)
83 libc_hidden_proto(bindresvport)
84 libc_hidden_proto(poll)
85 libc_hidden_proto(fputs)
86 #ifdef USE_IN_LIBIO
87 libc_hidden_proto(fwprintf)
88 #endif
89 libc_hidden_proto(__rpc_thread_createerr)
90
91 extern u_long _create_xid (void) attribute_hidden;
92
93 #define MCALL_MSG_SIZE 24
94
95 struct ct_data
96   {
97     int ct_sock;
98     bool_t ct_closeit;
99     struct timeval ct_wait;
100     bool_t ct_waitset;          /* wait set by clnt_control? */
101     struct sockaddr_in ct_addr;
102     struct rpc_err ct_error;
103     char ct_mcall[MCALL_MSG_SIZE];      /* marshalled callmsg */
104     u_int ct_mpos;              /* pos after marshal */
105     XDR ct_xdrs;
106   };
107
108 static int readtcp (char *, char *, int);
109 static int writetcp (char *, char *, int);
110
111 static enum clnt_stat clnttcp_call (CLIENT *, u_long, xdrproc_t, caddr_t,
112                                     xdrproc_t, caddr_t, struct timeval);
113 static void clnttcp_abort (void);
114 static void clnttcp_geterr (CLIENT *, struct rpc_err *);
115 static bool_t clnttcp_freeres (CLIENT *, xdrproc_t, caddr_t);
116 static bool_t clnttcp_control (CLIENT *, int, char *);
117 static void clnttcp_destroy (CLIENT *);
118
119 static struct clnt_ops tcp_ops =
120 {
121   clnttcp_call,
122   clnttcp_abort,
123   clnttcp_geterr,
124   clnttcp_freeres,
125   clnttcp_destroy,
126   clnttcp_control
127 };
128
129 /*
130  * Create a client handle for a tcp/ip connection.
131  * If *sockp<0, *sockp is set to a newly created TCP socket and it is
132  * connected to raddr.  If *sockp non-negative then
133  * raddr is ignored.  The rpc/tcp package does buffering
134  * similar to stdio, so the client must pick send and receive buffer sizes,];
135  * 0 => use the default.
136  * If raddr->sin_port is 0, then a binder on the remote machine is
137  * consulted for the right port number.
138  * NB: *sockp is copied into a private area.
139  * NB: It is the clients responsibility to close *sockp.
140  * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
141  * something more useful.
142  */
143 CLIENT *
144 clnttcp_create (struct sockaddr_in *raddr, u_long prog, u_long vers,
145                 int *sockp, u_int sendsz, u_int recvsz)
146 {
147   CLIENT *h;
148   struct ct_data *ct;
149   struct rpc_msg call_msg;
150
151   h = (CLIENT *) mem_alloc (sizeof (*h));
152   ct = (struct ct_data *) mem_alloc (sizeof (*ct));
153   if (h == NULL || ct == NULL)
154     {
155       struct rpc_createerr *ce = &get_rpc_createerr ();
156 #ifdef USE_IN_LIBIO
157       if (_IO_fwide (stderr, 0) > 0)
158         (void) fwprintf (stderr, L"%s",
159                            _("clnttcp_create: out of memory\n"));
160       else
161 #endif
162         (void) fputs (_("clnttcp_create: out of memory\n"), stderr);
163       ce->cf_stat = RPC_SYSTEMERROR;
164       ce->cf_error.re_errno = ENOMEM;
165       goto fooy;
166     }
167
168   /*
169    * If no port number given ask the pmap for one
170    */
171   if (raddr->sin_port == 0)
172     {
173       u_short port;
174       if ((port = pmap_getport (raddr, prog, vers, IPPROTO_TCP)) == 0)
175         {
176           mem_free ((caddr_t) ct, sizeof (struct ct_data));
177           mem_free ((caddr_t) h, sizeof (CLIENT));
178           return ((CLIENT *) NULL);
179         }
180       raddr->sin_port = htons (port);
181     }
182
183   /*
184    * If no socket given, open one
185    */
186   if (*sockp < 0)
187     {
188       *sockp = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
189       (void) bindresvport (*sockp, (struct sockaddr_in *) 0);
190       if ((*sockp < 0)
191           || (connect (*sockp, (struct sockaddr *) raddr,
192                          sizeof (*raddr)) < 0))
193         {
194           struct rpc_createerr *ce = &get_rpc_createerr ();
195           ce->cf_stat = RPC_SYSTEMERROR;
196           ce->cf_error.re_errno = errno;
197           if (*sockp >= 0)
198             (void) close (*sockp);
199           goto fooy;
200         }
201       ct->ct_closeit = TRUE;
202     }
203   else
204     {
205       ct->ct_closeit = FALSE;
206     }
207
208   /*
209    * Set up private data struct
210    */
211   ct->ct_sock = *sockp;
212   ct->ct_wait.tv_usec = 0;
213   ct->ct_waitset = FALSE;
214   ct->ct_addr = *raddr;
215
216   /*
217    * Initialize call message
218    */
219   call_msg.rm_xid = _create_xid ();
220   call_msg.rm_direction = CALL;
221   call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
222   call_msg.rm_call.cb_prog = prog;
223   call_msg.rm_call.cb_vers = vers;
224
225   /*
226    * pre-serialize the static part of the call msg and stash it away
227    */
228   xdrmem_create (&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
229                  XDR_ENCODE);
230   if (!xdr_callhdr (&(ct->ct_xdrs), &call_msg))
231     {
232       if (ct->ct_closeit)
233         {
234           (void) close (*sockp);
235         }
236       goto fooy;
237     }
238   ct->ct_mpos = XDR_GETPOS (&(ct->ct_xdrs));
239   XDR_DESTROY (&(ct->ct_xdrs));
240
241   /*
242    * Create a client handle which uses xdrrec for serialization
243    * and authnone for authentication.
244    */
245   xdrrec_create (&(ct->ct_xdrs), sendsz, recvsz,
246                  (caddr_t) ct, readtcp, writetcp);
247   h->cl_ops = &tcp_ops;
248   h->cl_private = (caddr_t) ct;
249   h->cl_auth = authnone_create ();
250   return h;
251
252 fooy:
253   /*
254    * Something goofed, free stuff and barf
255    */
256   mem_free ((caddr_t) ct, sizeof (struct ct_data));
257   mem_free ((caddr_t) h, sizeof (CLIENT));
258   return ((CLIENT *) NULL);
259 }
260 libc_hidden_proto(clnttcp_create)
261 libc_hidden_def(clnttcp_create)
262
263 static enum clnt_stat
264 clnttcp_call (h, proc, xdr_args, args_ptr, xdr_results, results_ptr, timeout)
265      CLIENT *h;
266      u_long proc;
267      xdrproc_t xdr_args;
268      caddr_t args_ptr;
269      xdrproc_t xdr_results;
270      caddr_t results_ptr;
271      struct timeval timeout;
272 {
273   struct ct_data *ct = (struct ct_data *) h->cl_private;
274   XDR *xdrs = &(ct->ct_xdrs);
275   struct rpc_msg reply_msg;
276   u_long x_id;
277   u_int32_t *msg_x_id = (u_int32_t *) (ct->ct_mcall);   /* yuk */
278   bool_t shipnow;
279   int refreshes = 2;
280
281   if (!ct->ct_waitset)
282     {
283       ct->ct_wait = timeout;
284     }
285
286   shipnow =
287     (xdr_results == (xdrproc_t) 0 && ct->ct_wait.tv_sec == 0
288      && ct->ct_wait.tv_usec == 0) ? FALSE : TRUE;
289
290 call_again:
291   xdrs->x_op = XDR_ENCODE;
292   ct->ct_error.re_status = RPC_SUCCESS;
293   x_id = ntohl (--(*msg_x_id));
294   if ((!XDR_PUTBYTES (xdrs, ct->ct_mcall, ct->ct_mpos)) ||
295       (!XDR_PUTLONG (xdrs, (long *) &proc)) ||
296       (!AUTH_MARSHALL (h->cl_auth, xdrs)) ||
297       (!(*xdr_args) (xdrs, args_ptr)))
298     {
299       if (ct->ct_error.re_status == RPC_SUCCESS)
300         ct->ct_error.re_status = RPC_CANTENCODEARGS;
301       (void) xdrrec_endofrecord (xdrs, TRUE);
302       return (ct->ct_error.re_status);
303     }
304   if (!xdrrec_endofrecord (xdrs, shipnow))
305     return ct->ct_error.re_status = RPC_CANTSEND;
306   if (!shipnow)
307     return RPC_SUCCESS;
308   /*
309    * Hack to provide rpc-based message passing
310    */
311   if (ct->ct_wait.tv_sec == 0 && ct->ct_wait.tv_usec == 0)
312     {
313       return ct->ct_error.re_status = RPC_TIMEDOUT;
314     }
315
316
317   /*
318    * Keep receiving until we get a valid transaction id
319    */
320   xdrs->x_op = XDR_DECODE;
321   while (TRUE)
322     {
323       reply_msg.acpted_rply.ar_verf = _null_auth;
324       reply_msg.acpted_rply.ar_results.where = NULL;
325       reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
326       if (!xdrrec_skiprecord (xdrs))
327         return (ct->ct_error.re_status);
328       /* now decode and validate the response header */
329       if (!xdr_replymsg (xdrs, &reply_msg))
330         {
331           if (ct->ct_error.re_status == RPC_SUCCESS)
332             continue;
333           return ct->ct_error.re_status;
334         }
335       if ((u_int32_t) reply_msg.rm_xid == (u_int32_t) x_id)
336         break;
337     }
338
339   /*
340    * process header
341    */
342   _seterr_reply (&reply_msg, &(ct->ct_error));
343   if (ct->ct_error.re_status == RPC_SUCCESS)
344     {
345       if (!AUTH_VALIDATE (h->cl_auth, &reply_msg.acpted_rply.ar_verf))
346         {
347           ct->ct_error.re_status = RPC_AUTHERROR;
348           ct->ct_error.re_why = AUTH_INVALIDRESP;
349         }
350       else if (!(*xdr_results) (xdrs, results_ptr))
351         {
352           if (ct->ct_error.re_status == RPC_SUCCESS)
353             ct->ct_error.re_status = RPC_CANTDECODERES;
354         }
355       /* free verifier ... */
356       if (reply_msg.acpted_rply.ar_verf.oa_base != NULL)
357         {
358           xdrs->x_op = XDR_FREE;
359           (void) xdr_opaque_auth (xdrs, &(reply_msg.acpted_rply.ar_verf));
360         }
361     }                           /* end successful completion */
362   else
363     {
364       /* maybe our credentials need to be refreshed ... */
365       if (refreshes-- && AUTH_REFRESH (h->cl_auth))
366         goto call_again;
367     }                           /* end of unsuccessful completion */
368   return ct->ct_error.re_status;
369 }
370
371 static void
372 clnttcp_geterr (h, errp)
373      CLIENT *h;
374      struct rpc_err *errp;
375 {
376   struct ct_data *ct =
377   (struct ct_data *) h->cl_private;
378
379   *errp = ct->ct_error;
380 }
381
382 static bool_t
383 clnttcp_freeres (cl, xdr_res, res_ptr)
384      CLIENT *cl;
385      xdrproc_t xdr_res;
386      caddr_t res_ptr;
387 {
388   struct ct_data *ct = (struct ct_data *) cl->cl_private;
389   XDR *xdrs = &(ct->ct_xdrs);
390
391   xdrs->x_op = XDR_FREE;
392   return (*xdr_res) (xdrs, res_ptr);
393 }
394
395 static void
396 clnttcp_abort ()
397 {
398 }
399
400 static bool_t
401 clnttcp_control (CLIENT *cl, int request, char *info)
402 {
403   struct ct_data *ct = (struct ct_data *) cl->cl_private;
404
405
406   switch (request)
407     {
408     case CLSET_FD_CLOSE:
409       ct->ct_closeit = TRUE;
410       break;
411     case CLSET_FD_NCLOSE:
412       ct->ct_closeit = FALSE;
413       break;
414     case CLSET_TIMEOUT:
415       ct->ct_wait = *(struct timeval *) info;
416       ct->ct_waitset = TRUE;
417       break;
418     case CLGET_TIMEOUT:
419       *(struct timeval *) info = ct->ct_wait;
420       break;
421     case CLGET_SERVER_ADDR:
422       *(struct sockaddr_in *) info = ct->ct_addr;
423       break;
424     case CLGET_FD:
425       *(int *)info = ct->ct_sock;
426       break;
427     case CLGET_XID:
428       /*
429        * use the knowledge that xid is the
430        * first element in the call structure *.
431        * This will get the xid of the PREVIOUS call
432        */
433       *(u_long *)info = ntohl (*(u_long *)ct->ct_mcall);
434       break;
435     case CLSET_XID:
436       /* This will set the xid of the NEXT call */
437       *(u_long *)ct->ct_mcall =  htonl (*(u_long *)info - 1);
438       /* decrement by 1 as clnttcp_call() increments once */
439     case CLGET_VERS:
440       /*
441        * This RELIES on the information that, in the call body,
442        * the version number field is the fifth field from the
443        * begining of the RPC header. MUST be changed if the
444        * call_struct is changed
445        */
446       *(u_long *)info = ntohl (*(u_long *)(ct->ct_mcall +
447                                            4 * BYTES_PER_XDR_UNIT));
448       break;
449     case CLSET_VERS:
450       *(u_long *)(ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
451         = htonl (*(u_long *)info);
452       break;
453     case CLGET_PROG:
454       /*
455        * This RELIES on the information that, in the call body,
456        * the program number field is the  field from the
457        * begining of the RPC header. MUST be changed if the
458        * call_struct is changed
459        */
460       *(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall +
461                                           3 * BYTES_PER_XDR_UNIT));
462       break;
463     case CLSET_PROG:
464       *(u_long *)(ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
465         = htonl(*(u_long *)info);
466       break;
467     /* The following are only possible with TI-RPC */
468     case CLGET_RETRY_TIMEOUT:
469     case CLSET_RETRY_TIMEOUT:
470     case CLGET_SVC_ADDR:
471     case CLSET_SVC_ADDR:
472     case CLSET_PUSH_TIMOD:
473     case CLSET_POP_TIMOD:
474     default:
475       return FALSE;
476     }
477   return TRUE;
478 }
479
480
481 static void
482 clnttcp_destroy (CLIENT *h)
483 {
484   struct ct_data *ct =
485   (struct ct_data *) h->cl_private;
486
487   if (ct->ct_closeit)
488     {
489       (void) close (ct->ct_sock);
490     }
491   XDR_DESTROY (&(ct->ct_xdrs));
492   mem_free ((caddr_t) ct, sizeof (struct ct_data));
493   mem_free ((caddr_t) h, sizeof (CLIENT));
494 }
495
496 /*
497  * Interface between xdr serializer and tcp connection.
498  * Behaves like the system calls, read & write, but keeps some error state
499  * around for the rpc level.
500  */
501 static int
502 readtcp (char *ctptr, char *buf, int len)
503 {
504   struct ct_data *ct = (struct ct_data *)ctptr;
505   struct pollfd fd;
506   int milliseconds = (ct->ct_wait.tv_sec * 1000) +
507     (ct->ct_wait.tv_usec / 1000);
508
509   if (len == 0)
510     return 0;
511
512   fd.fd = ct->ct_sock;
513   fd.events = POLLIN;
514   while (TRUE)
515     {
516       switch (poll(&fd, 1, milliseconds))
517         {
518         case 0:
519           ct->ct_error.re_status = RPC_TIMEDOUT;
520           return -1;
521
522         case -1:
523           if (errno == EINTR)
524             continue;
525           ct->ct_error.re_status = RPC_CANTRECV;
526           ct->ct_error.re_errno = errno;
527           return -1;
528         }
529       break;
530     }
531   switch (len = read (ct->ct_sock, buf, len))
532     {
533
534     case 0:
535       /* premature eof */
536       ct->ct_error.re_errno = ECONNRESET;
537       ct->ct_error.re_status = RPC_CANTRECV;
538       len = -1;                 /* it's really an error */
539       break;
540
541     case -1:
542       ct->ct_error.re_errno = errno;
543       ct->ct_error.re_status = RPC_CANTRECV;
544       break;
545     }
546   return len;
547 }
548
549 static int
550 writetcp (char *ctptr, char *buf, int len)
551 {
552   int i, cnt;
553   struct ct_data *ct = (struct ct_data*)ctptr;
554
555   for (cnt = len; cnt > 0; cnt -= i, buf += i)
556     {
557       if ((i = write (ct->ct_sock, buf, cnt)) == -1)
558         {
559           ct->ct_error.re_errno = errno;
560           ct->ct_error.re_status = RPC_CANTSEND;
561           return -1;
562         }
563     }
564   return len;
565 }