source: rtems-libbsd/services/librpc/src/rpc/svc_tcp.c @ bceabc9

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since bceabc9 was cd450d2, checked in by Joel Sherrill <joel.sherrill@…>, on 08/06/12 at 00:10:35

librpc: now compiles

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