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