Add PCICAP_{ID,NEXTPTR} to avoid using magic number
[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.5 2005/11/13 12:27:04 swildner 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(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp,
115                u_int sendsz, u_int recvsz)
116 {
117         CLIENT *h;
118         struct ct_data *ct = NULL;
119         struct timeval now;
120         struct rpc_msg call_msg;
121         static u_int32_t disrupt;
122
123         if (disrupt == 0)
124                 disrupt = (u_int32_t)(long)raddr;
125
126         h  = (CLIENT *)mem_alloc(sizeof(*h));
127         if (h == NULL) {
128                 fprintf(stderr, "clnttcp_create: out of memory\n");
129                 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
130                 rpc_createerr.cf_error.re_errno = errno;
131                 goto fooy;
132         }
133         ct = (struct ct_data *)mem_alloc(sizeof(*ct));
134         if (ct == NULL) {
135                 fprintf(stderr, "clnttcp_create: out of memory\n");
136                 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
137                 rpc_createerr.cf_error.re_errno = errno;
138                 goto fooy;
139         }
140
141         /*
142          * If no port number given ask the pmap for one
143          */
144         if (raddr->sin_port == 0) {
145                 u_short port;
146                 if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) {
147                         mem_free((caddr_t)ct, sizeof(struct ct_data));
148                         mem_free((caddr_t)h, sizeof(CLIENT));
149                         return ((CLIENT *)NULL);
150                 }
151                 raddr->sin_port = htons(port);
152         }
153
154         /*
155          * If no socket given, open one
156          */
157         if (*sockp < 0) {
158                 *sockp = _socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
159                 bindresvport(*sockp, (struct sockaddr_in *)0);
160                 if ((*sockp < 0)
161                     || (_connect(*sockp, (struct sockaddr *)raddr,
162                     sizeof(*raddr)) < 0)) {
163                         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
164                         rpc_createerr.cf_error.re_errno = errno;
165                         if (*sockp != -1)
166                                 _close(*sockp);
167                         goto fooy;
168                 }
169                 ct->ct_closeit = TRUE;
170         } else {
171                 ct->ct_closeit = FALSE;
172         }
173
174         /*
175          * Set up private data struct
176          */
177         ct->ct_sock = *sockp;
178         ct->ct_wait.tv_usec = 0;
179         ct->ct_waitset = FALSE;
180         ct->ct_addr = *raddr;
181
182         /*
183          * Initialize call message
184          */
185         gettimeofday(&now, (struct timezone *)0);
186         call_msg.rm_xid = (++disrupt) ^ getpid() ^ now.tv_sec ^ now.tv_usec;
187         call_msg.rm_direction = CALL;
188         call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
189         call_msg.rm_call.cb_prog = prog;
190         call_msg.rm_call.cb_vers = vers;
191
192         /*
193          * pre-serialize the static part of the call msg and stash it away
194          */
195         xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
196             XDR_ENCODE);
197         if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
198                 if (ct->ct_closeit) {
199                         _close(*sockp);
200                 }
201                 goto fooy;
202         }
203         ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
204         XDR_DESTROY(&(ct->ct_xdrs));
205
206         /*
207          * Create a client handle which uses xdrrec for serialization
208          * and authnone for authentication.
209          */
210         xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
211             (caddr_t)ct, readtcp, writetcp);
212         h->cl_ops = &tcp_ops;
213         h->cl_private = (caddr_t) ct;
214         h->cl_auth = authnone_create();
215         return (h);
216
217 fooy:
218         /*
219          * Something goofed, free stuff and barf
220          */
221         if (ct)
222                 mem_free((caddr_t)ct, sizeof(struct ct_data));
223         if (h)
224                 mem_free((caddr_t)h, sizeof(CLIENT));
225         return ((CLIENT *)NULL);
226 }
227
228 static enum clnt_stat
229 clnttcp_call(CLIENT *h, u_long proc, xdrproc_t xdr_args, caddr_t args_ptr,
230              xdrproc_t xdr_results, caddr_t results_ptr, struct timeval timeout)
231 {
232         struct ct_data *ct = (struct ct_data *) h->cl_private;
233         XDR *xdrs = &(ct->ct_xdrs);
234         struct rpc_msg reply_msg;
235         u_long x_id;
236         u_int32_t *msg_x_id = (u_int32_t *)(ct->ct_mcall);      /* yuk */
237         bool_t shipnow;
238         int refreshes = 2;
239
240         if (!ct->ct_waitset) {
241                 ct->ct_wait = timeout;
242         }
243
244         shipnow =
245             (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0
246             && timeout.tv_usec == 0) ? FALSE : TRUE;
247
248 call_again:
249         xdrs->x_op = XDR_ENCODE;
250         ct->ct_error.re_status = RPC_SUCCESS;
251         x_id = ntohl(--(*msg_x_id));
252         if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
253             (! XDR_PUTLONG(xdrs, (long *)&proc)) ||
254             (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
255             (! (*xdr_args)(xdrs, args_ptr))) {
256                 if (ct->ct_error.re_status == RPC_SUCCESS)
257                         ct->ct_error.re_status = RPC_CANTENCODEARGS;
258                 xdrrec_endofrecord(xdrs, TRUE);
259                 return (ct->ct_error.re_status);
260         }
261         if (! xdrrec_endofrecord(xdrs, shipnow))
262                 return (ct->ct_error.re_status = RPC_CANTSEND);
263         if (! shipnow)
264                 return (RPC_SUCCESS);
265         /*
266          * Hack to provide rpc-based message passing
267          */
268         if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
269                 return(ct->ct_error.re_status = RPC_TIMEDOUT);
270         }
271
272
273         /*
274          * Keep receiving until we get a valid transaction id
275          */
276         xdrs->x_op = XDR_DECODE;
277         while (TRUE) {
278                 reply_msg.acpted_rply.ar_verf = _null_auth;
279                 reply_msg.acpted_rply.ar_results.where = NULL;
280                 reply_msg.acpted_rply.ar_results.proc = xdr_void;
281                 if (! xdrrec_skiprecord(xdrs))
282                         return (ct->ct_error.re_status);
283                 /* now decode and validate the response header */
284                 if (! xdr_replymsg(xdrs, &reply_msg)) {
285                         if (ct->ct_error.re_status == RPC_SUCCESS)
286                                 continue;
287                         return (ct->ct_error.re_status);
288                 }
289                 if (reply_msg.rm_xid == x_id)
290                         break;
291         }
292
293         /*
294          * process header
295          */
296         _seterr_reply(&reply_msg, &(ct->ct_error));
297         if (ct->ct_error.re_status == RPC_SUCCESS) {
298                 if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
299                         ct->ct_error.re_status = RPC_AUTHERROR;
300                         ct->ct_error.re_why = AUTH_INVALIDRESP;
301                 } else if (! (*xdr_results)(xdrs, results_ptr)) {
302                         if (ct->ct_error.re_status == RPC_SUCCESS)
303                                 ct->ct_error.re_status = RPC_CANTDECODERES;
304                 }
305                 /* free verifier ... */
306                 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
307                         xdrs->x_op = XDR_FREE;
308                         xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
309                 }
310         }  /* end successful completion */
311         else {
312                 /* maybe our credentials need to be refreshed ... */
313                 if (refreshes-- && AUTH_REFRESH(h->cl_auth))
314                         goto call_again;
315         }  /* end of unsuccessful completion */
316         return (ct->ct_error.re_status);
317 }
318
319 static void
320 clnttcp_geterr(CLIENT *h, struct rpc_err *errp)
321 {
322         struct ct_data *ct =
323             (struct ct_data *) h->cl_private;
324
325         *errp = ct->ct_error;
326 }
327
328 static bool_t
329 clnttcp_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr)
330 {
331         struct ct_data *ct = (struct ct_data *)cl->cl_private;
332         XDR *xdrs = &(ct->ct_xdrs);
333
334         xdrs->x_op = XDR_FREE;
335         return ((*xdr_res)(xdrs, res_ptr));
336 }
337
338 static void
339 clnttcp_abort(void)
340 {
341 }
342
343
344 static bool_t
345 clnttcp_control(CLIENT *cl, int request, char *info)
346 {
347         struct ct_data *ct = (struct ct_data *)cl->cl_private;
348         struct timeval *tv;
349         int len;
350
351         switch (request) {
352         case CLSET_FD_CLOSE:
353                 ct->ct_closeit = TRUE;
354                 break;
355         case CLSET_FD_NCLOSE:
356                 ct->ct_closeit = FALSE;
357                 break;
358         case CLSET_TIMEOUT:
359                 if (info == NULL)
360                         return(FALSE);
361                 tv = (struct timeval *)info;
362                 ct->ct_wait.tv_sec = tv->tv_sec;
363                 ct->ct_wait.tv_usec = tv->tv_usec;
364                 ct->ct_waitset = TRUE;
365                 break;
366         case CLGET_TIMEOUT:
367                 if (info == NULL)
368                         return(FALSE);
369                 *(struct timeval *)info = ct->ct_wait;
370                 break;
371         case CLGET_SERVER_ADDR:
372                 if (info == NULL)
373                         return(FALSE);
374                 *(struct sockaddr_in *)info = ct->ct_addr;
375                 break;
376         case CLGET_FD:
377                 if (info == NULL)
378                         return(FALSE);
379                 *(int *)info = ct->ct_sock;
380                 break;
381         case CLGET_XID:
382                 /*
383                  * use the knowledge that xid is the
384                  * first element in the call structure *.
385                  * This will get the xid of the PREVIOUS call
386                  */
387                 if (info == NULL)
388                         return(FALSE);
389                 *(u_long *)info = ntohl(*(u_long *)ct->ct_mcall);
390                 break;
391         case CLSET_XID:
392                 /* This will set the xid of the NEXT call */
393                 if (info == NULL)
394                         return(FALSE);
395                 *(u_long *)ct->ct_mcall =  htonl(*(u_long *)info - 1);
396                 /* decrement by 1 as clnttcp_call() increments once */
397         case CLGET_VERS:
398                 /*
399                  * This RELIES on the information that, in the call body,
400                  * the version number field is the fifth field from the
401                  * begining of the RPC header. MUST be changed if the
402                  * call_struct is changed
403                  */
404                 if (info == NULL)
405                         return(FALSE);
406                 *(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall +
407                                                 4 * BYTES_PER_XDR_UNIT));
408                 break;
409         case CLSET_VERS:
410                 if (info == NULL)
411                         return(FALSE);
412                 *(u_long *)(ct->ct_mcall + 4 * BYTES_PER_XDR_UNIT)
413                                 = htonl(*(u_long *)info);
414                 break;
415         case CLGET_PROG:
416                 /*
417                  * This RELIES on the information that, in the call body,
418                  * the program number field is the  field from the
419                  * begining of the RPC header. MUST be changed if the
420                  * call_struct is changed
421                  */
422                 if (info == NULL)
423                         return(FALSE);
424                 *(u_long *)info = ntohl(*(u_long *)(ct->ct_mcall +
425                                                 3 * BYTES_PER_XDR_UNIT));
426                 break;
427         case CLSET_PROG:
428                 if (info == NULL)
429                         return(FALSE);
430                 *(u_long *)(ct->ct_mcall + 3 * BYTES_PER_XDR_UNIT)
431                                 = htonl(*(u_long *)info);
432                 break;
433         case CLGET_LOCAL_ADDR:
434                 len = sizeof(struct sockaddr);
435                 if (_getsockname(ct->ct_sock, (struct sockaddr *)info, &len) <0)
436                         return(FALSE);
437                 break;
438         case CLGET_RETRY_TIMEOUT:
439         case CLSET_RETRY_TIMEOUT:
440         case CLGET_SVC_ADDR:
441         case CLSET_SVC_ADDR:
442         case CLSET_PUSH_TIMOD:
443         case CLSET_POP_TIMOD:
444         default:
445                 return (FALSE);
446         }
447         return (TRUE);
448 }
449
450
451 static void
452 clnttcp_destroy(CLIENT *h)
453 {
454         struct ct_data *ct =
455             (struct ct_data *) h->cl_private;
456
457         if (ct->ct_closeit) {
458                 _close(ct->ct_sock);
459         }
460         XDR_DESTROY(&(ct->ct_xdrs));
461         mem_free((caddr_t)ct, sizeof(struct ct_data));
462         mem_free((caddr_t)h, sizeof(CLIENT));
463 }
464
465 /*
466  * Interface between xdr serializer and tcp connection.
467  * Behaves like the system calls, read & write, but keeps some error state
468  * around for the rpc level.
469  */
470 static int
471 readtcp(struct ct_data *ct, caddr_t buf, int len)
472 {
473         fd_set *fds, readfds;
474         struct timeval start, after, duration, delta, tmp, tv;
475         int r, save_errno;
476
477         if (len == 0)
478                 return (0);
479
480         if (ct->ct_sock + 1 > FD_SETSIZE) {
481                 int bytes = howmany(ct->ct_sock + 1, NFDBITS) * sizeof(fd_mask);
482                 fds = (fd_set *)malloc(bytes);
483                 if (fds == NULL)
484                         return (-1);
485                 memset(fds, 0, bytes);
486         } else {
487                 fds = &readfds;
488                 FD_ZERO(fds);
489         }
490
491         gettimeofday(&start, NULL);
492         delta = ct->ct_wait;
493         while (TRUE) {
494                 /* XXX we know the other bits are still clear */
495                 FD_SET(ct->ct_sock, fds);
496                 tv = delta;     /* in case select writes back */
497                 r = _select(ct->ct_sock+1, fds, NULL, NULL, &tv);
498                 save_errno = errno;
499
500                 gettimeofday(&after, NULL);
501                 timersub(&start, &after, &duration);
502                 timersub(&ct->ct_wait, &duration, &tmp);
503                 delta = tmp;
504                 if (delta.tv_sec < 0 || !timerisset(&delta))
505                         r = 0;
506
507                 switch (r) {
508                 case 0:
509                         if (fds != &readfds)
510                                 free(fds);
511                         ct->ct_error.re_status = RPC_TIMEDOUT;
512                         return (-1);
513
514                 case -1:
515                         if (errno == EINTR)
516                                 continue;
517                         if (fds != &readfds)
518                                 free(fds);
519                         ct->ct_error.re_status = RPC_CANTRECV;
520                         ct->ct_error.re_errno = save_errno;
521                         return (-1);
522                 }
523                 break;
524         }
525         switch (len = _read(ct->ct_sock, buf, len)) {
526
527         case 0:
528                 /* premature eof */
529                 ct->ct_error.re_errno = ECONNRESET;
530                 ct->ct_error.re_status = RPC_CANTRECV;
531                 len = -1;  /* it's really an error */
532                 break;
533
534         case -1:
535                 ct->ct_error.re_errno = errno;
536                 ct->ct_error.re_status = RPC_CANTRECV;
537                 break;
538         }
539         return (len);
540 }
541
542 static int
543 writetcp(struct ct_data *ct, caddr_t buf, int len)
544 {
545         int i, cnt;
546
547         for (cnt = len; cnt > 0; cnt -= i, buf += i) {
548                 if ((i = _write(ct->ct_sock, buf, cnt)) == -1) {
549                         ct->ct_error.re_errno = errno;
550                         ct->ct_error.re_status = RPC_CANTSEND;
551                         return (-1);
552                 }
553         }
554         return (len);
555 }