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