Import TBBT (NFS trace replay).
[bluesky.git] / TBBT / trace_play / rpc / svc_tcp.c
1 #ifndef lint
2 static char sfs_svc_tcp_id[] = "@(#)svc_tcp.c     2.1     97/10/23";
3 #endif
4 /* @(#)svc_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[] = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
53 #endif
54
55 /*
56  * svc_tcp.c, Server side for TCP/IP based RPC. 
57  *
58  * Copyright (C) 1984, Sun Microsystems, Inc.
59  *
60  * Actually implements two flavors of transporter -
61  * a tcp rendezvouser (a listner and connection establisher)
62  * and a record/tcp stream.
63  */
64
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <unistd.h>
68 #include <string.h>
69 #include "rpc/rpc.h"
70 #include "rpc/osdep.h"
71 #include <errno.h>
72
73 /*
74  * Ops vector for TCP/IP based rpc service handle
75  */
76 static bool_t           svctcp_recv(SVCXPRT *, struct rpc_msg *);
77 static enum xprt_stat   svctcp_stat(SVCXPRT *);
78 static bool_t           svctcp_getargs(SVCXPRT *, xdrproc_t, void *);
79 static bool_t           svctcp_reply(SVCXPRT *, struct rpc_msg *);
80 static bool_t           svctcp_freeargs(SVCXPRT *, xdrproc_t, void *);
81 static void             svctcp_destroy(SVCXPRT *);
82 static bool_t           svctcp_abortrop(SVCXPRT *, struct rpc_msg *);
83 static bool_t           svctcp_abortgop(SVCXPRT *, xdrproc_t, void *);
84
85 static struct xp_ops svctcp_op = {
86         svctcp_recv,
87         svctcp_stat,
88         svctcp_getargs,
89         svctcp_reply,
90         svctcp_freeargs,
91         svctcp_destroy
92 };
93
94 /*
95  * Ops vector for TCP/IP rendezvous handler
96  */
97 static bool_t           rendezvous_request(SVCXPRT *xprt, struct rpc_msg *);
98 static enum xprt_stat   rendezvous_stat(SVCXPRT *);
99
100 static struct xp_ops svctcp_rendezvous_op = {
101         rendezvous_request,
102         rendezvous_stat,
103         svctcp_abortgop,
104         svctcp_abortrop,
105         svctcp_abortgop,
106         svctcp_destroy
107 };
108
109 static int readtcp(), writetcp();
110 static int readtcp(SVCXPRT *, char *, int);
111 static int writetcp(SVCXPRT *, char *, int);
112 static SVCXPRT *makefd_xprt(int, uint_t, uint_t);
113
114 struct tcp_rendezvous { /* kept in xprt->xp_p1 */
115         uint_t sendsize;
116         uint_t recvsize;
117 };
118
119 struct tcp_conn {  /* kept in xprt->xp_p1 */
120         enum xprt_stat strm_stat;
121         uint32_t x_id;
122         XDR xdrs;
123         char verf_body[MAX_AUTH_BYTES];
124 };
125
126 /*
127  * Usage:
128  *      xprt = svctcp_create(sock, send_buf_size, recv_buf_size);
129  *
130  * Creates, registers, and returns a (rpc) tcp based transporter.
131  * Once *xprt is initialized, it is registered as a transporter
132  * see (svc.h, xprt_register).  This routine returns
133  * a NULL if a problem occurred.
134  *
135  * If sock<0 then a socket is created, else sock is used.
136  * If the socket, sock is not bound to a port then svctcp_create
137  * binds it to an arbitrary port.  The routine then starts a tcp
138  * listener on the socket's associated port.  In any (successful) case,
139  * xprt->xp_sock is the registered socket number and xprt->xp_port is the
140  * associated port number.
141  *
142  * Since tcp streams do buffered io similar to stdio, the caller can specify
143  * how big the send and receive buffers are via the second and third parms;
144  * 0 => use the system default.
145  */
146 SVCXPRT *
147 svctcp_create(
148         int sock,
149         uint_t sendsize,
150         uint_t recvsize)
151 {
152         bool_t madesock = FALSE;
153         SVCXPRT *xprt;
154         struct tcp_rendezvous *r;
155         struct sockaddr_in addr;
156 #if defined(AIX) 
157         size_t len;
158 #else 
159         int len;
160 #endif /* AIX */ 
161  
162         len = sizeof(struct sockaddr_in);
163
164         if (sock == RPC_ANYSOCK) {
165                 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
166                         perror("svctcp_.c - udp socket creation problem");
167                         return ((SVCXPRT *)NULL);
168                 }
169                 madesock = TRUE;
170         }
171         memset((char *)&addr, '\0', sizeof (addr));
172         addr.sin_family = AF_INET;
173         if (bindresvport(sock, &addr)) {
174                 addr.sin_port = 0;
175                 (void)bind(sock, (struct sockaddr *)&addr, len);
176         }
177         if ((getsockname(sock, (struct sockaddr *)&addr, &len) != 0)  ||
178             (listen(sock, 2) != 0)) {
179                 perror("svctcp_.c - cannot getsockname or listen");
180                 if (madesock)
181                        (void)close(sock);
182                 return ((SVCXPRT *)NULL);
183         }
184         r = (struct tcp_rendezvous *)mem_alloc(sizeof(struct tcp_rendezvous));
185         if (r == NULL) {
186                 (void) fprintf(stderr, "svctcp_create: out of memory\n");
187                 return (NULL);
188         }
189         r->sendsize = sendsize;
190         r->recvsize = recvsize;
191         xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
192         if (xprt == NULL) {
193                 (void) fprintf(stderr, "svctcp_create: out of memory\n");
194                 return (NULL);
195         }
196         xprt->xp_p2 = NULL;
197         xprt->xp_p1 = (void *)r;
198         xprt->xp_verf = _null_auth;
199         xprt->xp_ops = &svctcp_rendezvous_op;
200         xprt->xp_port = ntohs(addr.sin_port);
201         xprt->xp_sock = sock;
202         xprt_register(xprt);
203         return (xprt);
204 }
205
206 /*
207  * Like svtcp_create(), except the routine takes any *open* UNIX file
208  * descriptor as its first input.
209  */
210 SVCXPRT *
211 svcfd_create(
212         int fd,
213         uint_t sendsize,
214         uint_t recvsize)
215 {
216
217         return (makefd_xprt(fd, sendsize, recvsize));
218 }
219
220 static SVCXPRT *
221 makefd_xprt(
222         int fd,
223         uint_t sendsize,
224         uint_t recvsize)
225 {
226         SVCXPRT *xprt;
227         struct tcp_conn *cd;
228  
229         xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
230         if (xprt == (SVCXPRT *)NULL) {
231                 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
232                 goto done;
233         }
234         cd = (struct tcp_conn *)mem_alloc(sizeof(struct tcp_conn));
235         if (cd == (struct tcp_conn *)NULL) {
236                 (void) fprintf(stderr, "svc_tcp: makefd_xprt: out of memory\n");
237                 mem_free((char *) xprt, sizeof(SVCXPRT));
238                 xprt = (SVCXPRT *)NULL;
239                 goto done;
240         }
241         cd->strm_stat = XPRT_IDLE;
242         xdrrec_create(&(cd->xdrs), sendsize, recvsize,
243             (void *)xprt, readtcp, writetcp);
244         xprt->xp_p2 = NULL;
245         xprt->xp_p1 = (void *)cd;
246         xprt->xp_verf.oa_base = cd->verf_body;
247         xprt->xp_addrlen = 0;
248         xprt->xp_ops = &svctcp_op;  /* truely deals with calls */
249         xprt->xp_port = 0;  /* this is a connection, not a rendezvouser */
250         xprt->xp_sock = fd;
251         xprt_register(xprt);
252     done:
253         return (xprt);
254 }
255
256 /* ARGSUSED */
257 static bool_t
258 rendezvous_request(
259         SVCXPRT *xprt,
260         struct rpc_msg *msg)
261 {
262         int sock;
263         struct tcp_rendezvous *r;
264         struct sockaddr_in addr;
265 #if defined(AIX) 
266         size_t len;
267 #else 
268         int len;
269 #endif /* AIX */ 
270  
271         r = (struct tcp_rendezvous *)xprt->xp_p1;
272     again:
273         len = sizeof(struct sockaddr_in);
274         if ((sock = accept(xprt->xp_sock, (struct sockaddr *)&addr,
275             &len)) < 0) {
276                 if (errno == EINTR)
277                         goto again;
278                return (FALSE);
279         }
280         /*
281          * make a new transporter (re-uses xprt)
282          */
283         xprt = makefd_xprt(sock, r->sendsize, r->recvsize);
284         xprt->xp_raddr = addr;
285         xprt->xp_addrlen = len;
286         return (FALSE); /* there is never an rpc msg to be processed */
287 }
288
289 /* ARGSUSED */
290 static enum xprt_stat
291 rendezvous_stat(SVCXPRT *x)
292 {
293
294         return (XPRT_IDLE);
295 }
296
297 static void
298 svctcp_destroy(
299         SVCXPRT *xprt)
300 {
301         struct tcp_conn *cd = (struct tcp_conn *)xprt->xp_p1;
302
303         xprt_unregister(xprt);
304         (void)close(xprt->xp_sock);
305         if (xprt->xp_port != 0) {
306                 /* a rendezvouser socket */
307                 xprt->xp_port = 0;
308         } else {
309                 /* an actual connection socket */
310                 XDR_DESTROY(&(cd->xdrs));
311         }
312         mem_free((void *)cd, sizeof(struct tcp_conn));
313         mem_free((void *)xprt, sizeof(SVCXPRT));
314 }
315
316 /*
317  * All read operations timeout after 35 seconds.
318  * A timeout is fatal for the connection.
319  */
320 static struct timeval wait_per_try = { 35, 0 };
321
322 /*
323  * reads data from the tcp conection.
324  * any error is fatal and the connection is closed.
325  * (And a read of zero bytes is a half closed stream => error.)
326  */
327 static int
328 readtcp(
329         SVCXPRT *xprt,
330         char *buf,
331         int len)
332 {
333         int sock = xprt->xp_sock;
334 #ifdef FD_SETSIZE
335         fd_set mask;
336         fd_set readfds;
337
338         FD_ZERO(&mask);
339         FD_SET(sock, &mask);
340 #else
341         int mask = 1 << sock;
342         int readfds;
343 #endif /* def FD_SETSIZE */
344         do {
345                 readfds = mask;
346                 if (select(_rpc_dtablesize(), &readfds, NULL, NULL, 
347                            &wait_per_try) <= 0) {
348                         if (errno == EINTR) {
349                                 continue;
350                         }
351                         goto fatal_err;
352                 }
353 #ifdef FD_SETSIZE
354         } while (!FD_ISSET(sock, &readfds));
355 #else
356         } while (readfds != mask);
357 #endif /* def FD_SETSIZE */
358         if ((len = read(sock, buf, len)) > 0) {
359                 return (len);
360         }
361 fatal_err:
362         ((struct tcp_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
363         return (-1);
364 }
365
366 /*
367  * writes data to the tcp connection.
368  * Any error is fatal and the connection is closed.
369  */
370 static int
371 writetcp(
372         SVCXPRT *xprt,
373         char *buf,
374         int len)
375 {
376         int i, cnt;
377
378         for (cnt = len; cnt > 0; cnt -= i, buf += i) {
379                 if ((i = write(xprt->xp_sock, buf, cnt)) < 0) {
380                         ((struct tcp_conn *)(xprt->xp_p1))->strm_stat =
381                             XPRT_DIED;
382                         return (-1);
383                 }
384         }
385         return (len);
386 }
387
388 static enum xprt_stat
389 svctcp_stat(
390         SVCXPRT *xprt)
391 {
392         struct tcp_conn *cd =
393             (struct tcp_conn *)(xprt->xp_p1);
394
395         if (cd->strm_stat == XPRT_DIED)
396                 return (XPRT_DIED);
397         if (! xdrrec_eof(&(cd->xdrs)))
398                 return (XPRT_MOREREQS);
399         return (XPRT_IDLE);
400 }
401
402 static bool_t
403 svctcp_recv(
404         SVCXPRT *xprt,
405         struct rpc_msg *msg)
406 {
407         struct tcp_conn *cd =
408             (struct tcp_conn *)(xprt->xp_p1);
409         XDR *xdrs = &(cd->xdrs);
410
411         xdrs->x_op = XDR_DECODE;
412         (void)xdrrec_skiprecord(xdrs);
413         if (xdr_callmsg(xdrs, msg)) {
414                 cd->x_id = msg->rm_xid;
415                 return (TRUE);
416         }
417         return (FALSE);
418 }
419
420 static bool_t
421 svctcp_getargs(
422         SVCXPRT *xprt,
423         xdrproc_t xdr_args,
424         void * args_ptr)
425 {
426
427         return ((*xdr_args)(&(((struct tcp_conn *)(xprt->xp_p1))->xdrs), args_ptr));
428 }
429
430 static bool_t
431 svctcp_freeargs(
432         SVCXPRT *xprt,
433         xdrproc_t xdr_args,
434         void * args_ptr)
435 {
436         XDR *xdrs =
437             &(((struct tcp_conn *)(xprt->xp_p1))->xdrs);
438
439         xdrs->x_op = XDR_FREE;
440         return ((*xdr_args)(xdrs, args_ptr));
441 }
442
443 static bool_t
444 svctcp_reply(
445         SVCXPRT *xprt,
446         struct rpc_msg *msg)
447 {
448         struct tcp_conn *cd =
449             (struct tcp_conn *)(xprt->xp_p1);
450         XDR *xdrs = &(cd->xdrs);
451         bool_t stat;
452
453         xdrs->x_op = XDR_ENCODE;
454         msg->rm_xid = cd->x_id;
455         stat = xdr_replymsg(xdrs, msg);
456         (void)xdrrec_endofrecord(xdrs, TRUE);
457         return (stat);
458 }
459
460 /* ARGSUSED */
461 static bool_t
462 svctcp_abortrop(
463         SVCXPRT *x,
464         struct rpc_msg *msg)
465 {
466         abort();
467         /* NOTREACHED */
468         return (FALSE);
469 }
470
471 /* ARGSUSED */
472 static bool_t
473 svctcp_abortgop(
474         SVCXPRT *x,
475         xdrproc_t argp,
476         void *arg)
477 {
478         abort();
479         /* NOTREACHED */
480         return (FALSE);
481 }