source: rtems/c/src/exec/librpc/src/rpc/svc_tcp.c @ df49c60

4.104.114.84.95
Last change on this file since df49c60 was df49c60, checked in by Joel Sherrill <joel.sherrill@…>, on Jun 12, 2000 at 3:00:15 PM

Merged from 4.5.0-beta3a

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