1dee98913924580b955f198d856d8a75ce0ceab9
[bluesky.git] / TBBT / trace_play / rpc / sfs_cudp.c
1 #ifndef lint
2 static char sfs_cudp_id[] = "@(#)sfs_cudp.c     2.1     97/10/23";
3 #endif
4
5 /* @(#)clnt_udp.c       2.2 88/08/01 4.0 RPCSRC */
6 /*
7  *   Copyright (c) 1992-1997,2001 by Standard Performance Evaluation Corporation
8  *      All rights reserved.
9  *              Standard Performance Evaluation Corporation (SPEC)
10  *              6585 Merchant Place, Suite 100
11  *              Warrenton, VA 20187
12  *
13  *      This product contains benchmarks acquired from several sources who
14  *      understand and agree with SPEC's goal of creating fair and objective
15  *      benchmarks to measure computer performance.
16  *
17  *      This copyright notice is placed here only to protect SPEC in the
18  *      event the source is misused in any manner that is contrary to the
19  *      spirit, the goals and the intent of SPEC.
20  *
21  *      The source code is provided to the user or company under the license
22  *      agreement for the SPEC Benchmark Suite for this product.
23  */
24 /*
25  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
26  * unrestricted use provided that this legend is included on all tape
27  * media and as a part of the software program in whole or part.  Users
28  * may copy or modify Sun RPC without charge, but are not authorized
29  * to license or distribute it to anyone else except as part of a product or
30  * program developed by the user.
31  * 
32  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
33  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
34  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
35  * 
36  * Sun RPC is provided with no support and without any obligation on the
37  * part of Sun Microsystems, Inc. to assist in its use, correction,
38  * modification or enhancement.
39  * 
40  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
41  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
42  * OR ANY PART THEREOF.
43  * 
44  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
45  * or profits or other special, indirect and consequential damages, even if
46  * Sun has been advised of the possibility of such damages.
47  * 
48  * Sun Microsystems, Inc.
49  * 2550 Garcia Avenue
50  * Mountain View, California  94043
51  */
52
53 /*
54  * clnt_udp.c, Implements a UDP/IP based, client side RPC.
55  *
56  * Copyright (C) 1984, Sun Microsystems, Inc.
57  */
58
59
60 #include <stdio.h>
61 #include <unistd.h>
62 #include <stdlib.h>
63 #ifndef FreeBSD
64 #include <stropts.h>
65 #endif  /* ndef FreeBSD */
66 #include <string.h>
67 #include "rpc/rpc.h"
68 #include "rpc/osdep.h"
69 #include <netdb.h>
70 #include "rpc/pmap_clnt.h"
71 #include <errno.h>
72 #include "rfs_c_def.h"  /* Just for the define of RFS */
73 /*
74  * UDP bases client side rpc operations
75  */
76 static enum clnt_stat sfs_cudp_call(CLIENT *, uint32_t, xdrproc_t,
77                                         void *, xdrproc_t, void *,
78                                         struct timeval);
79 static void             sfs_cudp_abort(CLIENT *h);
80 static void             sfs_cudp_geterr(CLIENT *, struct rpc_err *);
81 static bool_t           sfs_cudp_freeres(CLIENT *, xdrproc_t, void *);
82 static bool_t           sfs_cudp_control(CLIENT *, uint_t, void *);
83 static void             sfs_cudp_destroy(CLIENT *);
84 static bool_t           sfs_cudp_getreply(CLIENT *, xdrproc_t, void *,
85                                 int, uint32_t *, uint32_t *, struct timeval *);
86 static int              sfs_cudp_poll(CLIENT *, uint32_t);
87
88 static struct clnt_ops sfs_cudp_ops = {
89         sfs_cudp_call,
90         sfs_cudp_abort,
91         sfs_cudp_geterr,
92         sfs_cudp_freeres,
93         sfs_cudp_destroy,
94         sfs_cudp_control,
95         sfs_cudp_getreply,
96         sfs_cudp_poll
97 };
98
99 /* 
100  * Private data kept per client handle
101  */
102 struct cu_data {
103         int                cu_sock;
104         bool_t             cu_closeit;
105         struct sockaddr_in cu_raddr;
106         int                cu_rlen;
107         struct rpc_err cu_error;
108         XDR                cu_outxdrs;
109         uint_t             cu_xdrpos;
110         uint_t             cu_sendsz;
111         char               *cu_outbuf;
112         uint_t             cu_recvsz;
113         char               cu_inbuf[1];
114 };
115
116 /*
117  * Create a UDP based client handle.
118  * If *sockp<0, *sockp is set to a newly created UPD socket.
119  * If raddr->sin_port is 0 a binder on the remote machine
120  * is consulted for the correct port number.
121  * NB: It is the clients responsibility to close *sockp.
122  * NB: The rpch->cl_auth is initialized to null authentication.
123  *     Caller may wish to set this something more useful.
124  *
125  * wait is the amount of time used between retransmitting a call if
126  * no response has been heard;  retransmition occurs until the actual
127  * rpc call times out.
128  *
129  * sendsz and recvsz are the maximum allowable packet sizes that can be
130  * sent and received.
131  */
132 /* ARGSUSED */
133 CLIENT *
134 sfs_cudp_bufcreate(
135         struct sockaddr_in *raddr,
136         uint32_t program,
137         uint32_t version,
138         struct timeval wait,
139         int *sockp,
140         uint_t sendsz,
141         uint_t recvsz)
142 {
143         CLIENT *cl;
144         struct cu_data *cu;
145         struct timeval now;
146         struct rpc_msg call_msg;
147         int min_buf_sz;
148         int new_buf_sz;
149         int type;
150         int i;
151         int error;
152 #if defined(UNIXWARE) || defined(AIX)
153         size_t optlen;
154 #else
155         int optlen;
156 #endif
157
158         cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
159         if (cl == NULL) {
160                 (void) fprintf(stderr, "sfs_cudp_create: out of memory\n");
161                 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
162                 rpc_createerr.cf_error.re_errno = errno;
163                 goto fooy;
164         }
165         sendsz = ((sendsz + 3) / 4) * 4;
166         recvsz = ((recvsz + 3) / 4) * 4;
167         cu = (struct cu_data *)mem_alloc(sizeof(struct cu_data) +
168                                                         sendsz + recvsz);
169         if (cu == NULL) {
170                 (void) fprintf(stderr, "sfs_cudp_create: out of memory\n");
171                 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
172                 rpc_createerr.cf_error.re_errno = errno;
173                 goto fooy;
174         }
175         cu->cu_outbuf = &cu->cu_inbuf[recvsz];
176
177         (void)gettimeofday(&now, (struct timezone *)0);
178         if (raddr->sin_port == 0) {
179                 uint16_t port;
180                 if ((port =
181                     pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
182                         goto fooy;
183                 }
184                 raddr->sin_port = htons(port);
185         }
186         cl->cl_ops = &sfs_cudp_ops;
187         cl->cl_private = (void *)cu;
188         cu->cu_raddr = *raddr;
189         cu->cu_rlen = sizeof (cu->cu_raddr);
190         cu->cu_sendsz = sendsz;
191         cu->cu_recvsz = recvsz;
192         call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec;
193         call_msg.rm_direction = CALL;
194         call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
195         call_msg.rm_call.cb_prog = program;
196         call_msg.rm_call.cb_vers = version;
197         xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
198             sendsz, XDR_ENCODE);
199         if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
200                 goto fooy;
201         }
202         cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
203         if (*sockp < 0) {
204 #if defined(O_NONBLOCK)
205                 int flags;
206 #elif defined(FIONBIO)
207                 int dontblock = 1;
208 #endif
209
210                 *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
211                 if (*sockp < 0) {
212                         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
213                         rpc_createerr.cf_error.re_errno = errno;
214                         goto fooy;
215                 }
216                 /* attempt to bind to prov port */
217                 (void)bindresvport(*sockp, (struct sockaddr_in *)0);
218                 /* the sockets rpc controls are non-blocking */
219 #if defined(O_NONBLOCK)
220                 flags = fcntl(*sockp, F_GETFL, 0) | O_NONBLOCK;
221                 (void)fcntl(*sockp, F_SETFL, flags);
222 #elif defined(FIONBIO)
223                 (void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
224 #endif
225                 cu->cu_closeit = TRUE;
226         } else {
227                 cu->cu_closeit = FALSE;
228         }
229         cu->cu_sock = *sockp;
230         /*
231          * Need to try to size the socket buffers based on the number of
232          * outstanding requests desired.  NFS reads and writes can do as
233          * much as 8K per request which can quickly run us out of space
234          * on the socket buffer queue.  Use the maximum number of bio style
235          * requests * NFS_MAXDATA plus a pad as a starting point for desired
236          * socket buffer size and then back off by NFS_MAXDATA until the buffer
237          * sizes are successfully set.  Note, the algorithm never sets the
238          * buffer size to less than the OS default.
239          */  
240         type = SO_SNDBUF;
241         for (i = 0; i < 2; i++) {
242                 optlen = sizeof(min_buf_sz);
243 #if defined(UNIXWARE)
244                 if (getsockopt(cu->cu_sock, SOL_SOCKET, type,
245                                 (void *)&min_buf_sz, &optlen) < 0) {
246                         /* guess the default */
247                         min_buf_sz = 18 * 1024;
248                 }
249 #else
250                 if (getsockopt(cu->cu_sock, SOL_SOCKET, type,
251                                 (char *)&min_buf_sz, &optlen) < 0) {
252                         /* guess the default */
253                         min_buf_sz = 18 * 1024;
254                 }
255 #endif
256
257                 new_buf_sz = 512 * 1024;
258                 if (new_buf_sz > min_buf_sz) {
259                         do {
260                                 error = setsockopt(cu->cu_sock, SOL_SOCKET,
261                                                 type, (char *)&new_buf_sz,
262                                                 sizeof(int));
263                                 new_buf_sz -= (8 * 1024);
264                         } while (error != 0 && new_buf_sz > min_buf_sz);
265                 }
266
267                 type = SO_RCVBUF;
268         }
269
270         cl->cl_auth = authnone_create();
271         return (cl);
272 fooy:
273         if (cu)
274                 mem_free((void *)cu, sizeof(struct cu_data) + sendsz + recvsz);
275         if (cl)
276                 mem_free((void *)cl, sizeof(CLIENT));
277         return ((CLIENT *)NULL);
278 }
279
280 CLIENT *
281 sfs_cudp_create(
282         struct sockaddr_in *raddr,
283         uint32_t program,
284         uint32_t version,
285         struct timeval wait,
286         int *sockp)
287 {
288
289         return(sfs_cudp_bufcreate(raddr, program, version, wait, sockp,
290             UDPMSGSIZE, UDPMSGSIZE));
291 }
292
293 #ifdef RFS
294 enum clnt_stat get_areply_udp (
295                 CLIENT * cl,
296                 uint32_t *xid,
297                 struct timeval *timeout) 
298 {
299         return get_areply (cl, xid, timeout);
300 }
301 #endif
302
303 static enum clnt_stat
304 get_areply(
305         CLIENT *cl,
306         uint32_t *xid,
307         struct timeval *timeout)
308 {
309         struct cu_data *cu = (struct cu_data *)cl->cl_private;
310         int inlen;
311 #if defined(AIX)
312         size_t fromlen;
313 #else
314         int fromlen;
315 #endif
316         struct sockaddr_in from;
317 #ifdef FD_SETSIZE
318         fd_set readfds;
319         fd_set mask;
320 #else
321         int readfds;
322         int mask;
323 #endif /* def FD_SETSIZE */
324
325 #ifdef FD_SETSIZE
326         FD_ZERO(&mask);
327         FD_SET(cu->cu_sock, &mask);
328 #else
329         mask = 1 << cu->cu_sock;
330 #endif /* def FD_SETSIZE */
331
332         for (;;) {
333                 readfds = mask;
334                 switch (select(_rpc_dtablesize(), &readfds, NULL, 
335                                NULL, timeout)) {
336
337                 case 0:
338                         return (cu->cu_error.re_status = RPC_TIMEDOUT);
339
340                 case -1:
341                         if (errno == EINTR)
342                                 continue;       
343                         cu->cu_error.re_errno = errno;
344                         return (cu->cu_error.re_status = RPC_CANTRECV);
345                 }
346                 do {
347                         fromlen = sizeof(struct sockaddr);
348                         inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 
349                                 (int) cu->cu_recvsz, 0,
350                                 (struct sockaddr *)&from, &fromlen);
351                 } while (inlen < 0 && errno == EINTR);
352                 if (inlen < 0) {
353                         if (errno == EWOULDBLOCK)
354                                 continue;       
355                         cu->cu_error.re_errno = errno;
356                         return (cu->cu_error.re_status = RPC_CANTRECV);
357                 }
358
359                 if (inlen < sizeof(uint32_t))
360                         continue;       
361
362                 *xid = ntohl(*((uint32_t *)(cu->cu_inbuf)));
363                 return (RPC_SUCCESS);
364         }
365 }
366
367 enum clnt_stat
368 proc_header(
369         CLIENT *cl,
370         xdrproc_t xdr_results,
371         void *results_ptr)
372 {
373         struct cu_data *cu = (struct cu_data *)cl->cl_private;
374         XDR *xdrs = &(cu->cu_outxdrs);
375         struct rpc_msg reply_msg;
376         XDR reply_xdrs;
377         bool_t ok;
378
379         /*
380          * now decode and validate the response
381          */
382         xdrmem_create(&reply_xdrs, cu->cu_inbuf, cu->cu_recvsz, XDR_DECODE);
383
384         reply_msg.acpted_rply.ar_verf = _null_auth;
385         reply_msg.acpted_rply.ar_results.where = results_ptr;
386         reply_msg.acpted_rply.ar_results.proc = xdr_results;
387
388         ok = xdr_replymsg(&reply_xdrs, &reply_msg);
389         /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
390         if (!ok) {
391                 return (cu->cu_error.re_status = RPC_CANTDECODERES);
392         }
393
394         _seterr_reply(&reply_msg, &(cu->cu_error));
395
396         if (cu->cu_error.re_status == RPC_SUCCESS) {
397                 if (! AUTH_VALIDATE(cl->cl_auth,
398                                 &reply_msg.acpted_rply.ar_verf)) {
399                         cu->cu_error.re_status = RPC_AUTHERROR;
400                         cu->cu_error.re_why = AUTH_INVALIDRESP;
401                 }
402                 if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
403                         xdrs->x_op = XDR_FREE;
404                         (void)xdr_opaque_auth(xdrs,
405                                 &(reply_msg.acpted_rply.ar_verf));
406                 }
407         }
408
409         return (cu->cu_error.re_status);
410 }
411
412 /*
413  * Non-standard changes.  Make a call an at-most-once with a per call
414  * timer.  Ignore the timeout set at creation. Never retransmit.
415  */
416 static enum clnt_stat 
417 sfs_cudp_call(
418         CLIENT          *cl,            /* client handle */
419         uint32_t        proc,           /* procedure number */
420         xdrproc_t       xargs,          /* xdr routine for args */
421         void *          argsp,          /* pointer to args */
422         xdrproc_t       xresults,       /* xdr routine for results */
423         void *          resultsp,       /* pointer to results */
424         struct timeval  timeout)        /* seconds to wait before giving up */
425 {
426         struct cu_data *cu = (struct cu_data *)cl->cl_private;
427         XDR *xdrs = &(cu->cu_outxdrs);
428         int outlen;
429         uint32_t x_id, r_xid;
430
431         xdrs->x_op = XDR_ENCODE;
432         XDR_SETPOS(xdrs, cu->cu_xdrpos);
433
434         /*
435          * the transaction is the first thing in the out buffer
436          */
437         (*(uint32_t *)(cu->cu_outbuf))++;
438         x_id = ntohl(*(uint32_t *)(cu->cu_outbuf));
439
440         if ((! XDR_PUTLONG(xdrs, (int32_t *)&proc)) ||
441             (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
442             (! (*xargs)(xdrs, argsp)))
443                 return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
444
445         outlen = (int)XDR_GETPOS(xdrs);
446
447         if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
448             (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) != outlen) {
449                 cu->cu_error.re_errno = errno;
450                 return (cu->cu_error.re_status = RPC_CANTSEND);
451         }
452
453         /*
454          * Hack to provide rpc-based message passing
455          */
456         if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
457                 /* 
458                  * Double hack, send back xid in results_prt if non-NULL
459                  */ 
460                 if (resultsp != NULL) 
461                         *(uint32_t *)resultsp = x_id; 
462
463                 return (cu->cu_error.re_status = RPC_TIMEDOUT);
464         }
465
466         /* CONSTCOND */
467         while (TRUE) {
468                 enum clnt_stat res;
469
470                 if ((res = get_areply(cl, &r_xid, &timeout)) != RPC_SUCCESS)
471                         return (res);
472
473                 if (r_xid == x_id)
474                         break;
475         }
476
477         /*
478          * process header
479          */
480         return (proc_header(cl, xresults, resultsp));
481 }
482
483 static void
484 sfs_cudp_geterr(CLIENT *cl, struct rpc_err *errp)
485 {
486         struct cu_data *cu = (struct cu_data *)cl->cl_private;
487
488         *errp = cu->cu_error;
489 }
490
491
492 static bool_t
493 sfs_cudp_freeres(
494         CLIENT *cl,
495         xdrproc_t xdr_res,
496         void * res_ptr)
497 {
498         struct cu_data *cu = (struct cu_data *)cl->cl_private;
499         XDR *xdrs = &(cu->cu_outxdrs);
500
501         xdrs->x_op = XDR_FREE;
502         return ((*xdr_res)(xdrs, res_ptr));
503 }
504
505 /* ARGSUSED */
506 static void 
507 sfs_cudp_abort(CLIENT *h)
508 {
509 }
510
511 static bool_t
512 sfs_cudp_control(
513         CLIENT *cl,
514         uint_t request,
515         void *info)
516 {
517         struct cu_data *cu = (struct cu_data *)cl->cl_private;
518
519         switch (request) {
520         case CLGET_SERVER_ADDR:
521                 *(struct sockaddr_in *)info = cu->cu_raddr;
522                 break;
523         default:
524                 return (FALSE);
525         }
526         return (TRUE);
527 }
528         
529 static void
530 sfs_cudp_destroy(CLIENT *cl)
531 {
532         struct cu_data *cu = (struct cu_data *)cl->cl_private;
533
534         if (cu->cu_closeit) {
535                 (void)close(cu->cu_sock);
536         }
537         XDR_DESTROY(&(cu->cu_outxdrs));
538         mem_free((void *)cu, (sizeof(struct cu_data) + cu->cu_sendsz + cu->cu_recvsz));
539         mem_free((void *)cl, sizeof(CLIENT));
540 }
541
542 /* ARGSUSED */
543 static bool_t
544 sfs_cudp_getreply(
545         CLIENT *cl,
546         xdrproc_t xproc,
547         void *xres,
548         int cnt,
549         uint32_t *xids,
550         uint32_t *xid,
551         struct timeval *tv)
552 {
553         struct cu_data *cu = (struct cu_data *)cl->cl_private;
554         bool_t res;
555         int i;
556
557         cu->cu_error.re_status = RPC_SUCCESS;
558
559         if ((res = get_areply(cl, xid, tv)) != RPC_SUCCESS)
560                 return (res);
561
562         /*
563          * Check to make sure xid matchs one that we are interested in
564          */
565         for (i = 0; i < cnt; i++) {
566                 if (xids[i] == *xid)
567                         break;
568         }
569
570         if (i == cnt)
571                 return (RPC_CANTDECODERES);
572
573         /*
574          * process header
575          */
576         return (proc_header(cl, xproc, xres));
577 }
578  
579 static int
580 sfs_cudp_poll(
581         CLIENT *cl,
582         uint32_t usecs)
583 {
584         struct cu_data *cu = (struct cu_data *)cl->cl_private;
585         struct timeval tv;
586 #ifdef FD_SETSIZE
587         fd_set mask;
588         fd_set readfds;
589  
590         FD_ZERO(&mask);
591         FD_SET(cu->cu_sock, &mask);
592 #else
593         int mask = 1 << (cu->cu_sock);
594         int readfds;
595 #endif /* def FD_SETSIZE */
596  
597         tv.tv_sec = 0; 
598         if (usecs > 1000000) 
599                 tv.tv_sec = usecs / 1000000; 
600         tv.tv_usec = usecs % 1000000; 
601  
602         readfds = mask;
603         return (select(_rpc_dtablesize(), &readfds, NULL, NULL, &tv));
604 }