source: rtems-libbsd/services/librpc/src/rpc/clnt_tcp.c @ e599318

4.115-freebsd-12freebsd-9.3
Last change on this file since e599318 was e599318, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 9, 2013 at 8:52:54 PM

Update files to match FreeBSD layout

Add compatibility with Newlib header files. Some FreeBSD header files
are mapped by the translation script:

o rtems/bsd/sys/_types.h
o rtems/bsd/sys/errno.h
o rtems/bsd/sys/lock.h
o rtems/bsd/sys/param.h
o rtems/bsd/sys/resource.h
o rtems/bsd/sys/time.h
o rtems/bsd/sys/timespec.h
o rtems/bsd/sys/types.h
o rtems/bsd/sys/unistd.h

It is now possible to include <sys/socket.h> directly for example.

Generate one Makefile which builds everything including tests.

  • Property mode set to 100644
File size: 15.2 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: @(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";*/
32/*static char *sccsid = "from: @(#)clnt_tcp.c   2.2 88/08/01 4.0 RPCSRC";*/
33static char *rcsid = "$FreeBSD: src/lib/libc/rpc/clnt_tcp.c,v 1.14 2000/01/27 23:06:36 jasone Exp $";
34#endif
35
36/*
37 * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
38 *
39 * Copyright (C) 1984, Sun Microsystems, Inc.
40 *
41 * TCP based RPC supports 'batched calls'.
42 * A sequence of calls may be batched-up in a send buffer.  The rpc call
43 * return immediately to the client even though the call was not necessarily
44 * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
45 * the rpc timeout value is zero (see clnt.h, rpc).
46 *
47 * Clients should NOT casually batch calls that in fact return results; that is,
48 * the server side should be aware that a call is batched and not produce any
49 * return message.  Batched calls that produce many result messages can
50 * deadlock (netlock) the client and the server....
51 *
52 * Now go hang yourself.
53 */
54
55#ifdef HAVE_CONFIG_H
56#include "config.h"
57#endif
58
59#include <stdio.h>
60#include <stdlib.h>
61#include <unistd.h>
62#include <string.h>
63#include <rpc/rpc.h>
64#include <sys/socket.h>
65#include <netdb.h>
66#include <errno.h>
67#include <rpc/pmap_clnt.h>
68#include <sys/select.h>
69
70#define MCALL_MSG_SIZE 24
71
72static int      readtcp(char *, char*, int);
73static int      writetcp(char *, char*, int);
74
75static enum clnt_stat   clnttcp_call(CLIENT *, rpcproc_t, xdrproc_t, void*, xdrproc_t, void*, struct timeval);
76static void             clnttcp_abort(void);
77static void             clnttcp_geterr(CLIENT *, struct rpc_err*);
78static bool_t           clnttcp_freeres(CLIENT *, xdrproc_t, void*);
79static bool_t           clnttcp_control(CLIENT *, int, char *);
80static void             clnttcp_destroy(CLIENT *);
81
82static struct clnt_ops tcp_ops = {
83        clnttcp_call,
84        clnttcp_abort,
85        clnttcp_geterr,
86        clnttcp_freeres,
87        clnttcp_destroy,
88        clnttcp_control
89};
90
91struct ct_data {
92        int             ct_sock;
93        bool_t          ct_closeit;     /* close it on destroy */
94        struct timeval  ct_wait;        /* wait interval in milliseconds */
95        bool_t          ct_waitset;       /* wait set by clnt_control? */
96        struct sockaddr_in ct_addr;
97        struct rpc_err  ct_error;
98        union {
99                char    ct_mcallc[MCALL_MSG_SIZE];      /* marshalled callmsg */
100                u_int32_t ct_mcalli;
101        } ct_u;
102        u_int           ct_mpos;                        /* pos after marshal */
103        XDR             ct_xdrs;        /* XDR stream */
104};
105
106/*
107 * Create a client handle for a tcp/ip connection.
108 * If *sockp<0, *sockp is set to a newly created TCP socket and it is
109 * connected to raddr.  If *sockp non-negative then
110 * raddr is ignored.  The rpc/tcp package does buffering
111 * similar to stdio, so the client must pick send and receive buffer sizes,];
112 * 0 => use the default.
113 * If raddr->sin_port is 0, then a binder on the remote machine is
114 * consulted for the right port number.
115 * NB: *sockp is copied into a private area.
116 * NB: It is the clients responsibility to close *sockp.
117 * NB: The rpch->cl_auth is set null authentication.  Caller may wish to set this
118 * something more useful.
119 */
120CLIENT *
121clnttcp_create(
122        struct sockaddr_in *raddr,
123        u_long prog,            /* program number */
124        u_long vers,            /* version number */
125        int *sockp,
126        u_int sendsz,
127        u_int recvsz)
128{
129        CLIENT *h;
130        struct ct_data *ct = NULL;      /* client handle */
131        struct timeval now;
132        struct rpc_msg call_msg;
133        static uintptr_t disrupt;
134
135        if (disrupt == 0)
136                disrupt = (uintptr_t)raddr;
137
138        h  = (CLIENT *)mem_alloc(sizeof(*h));
139        if (h == NULL) {
140                (void)fprintf(stderr, "clnttcp_create: out of memory\n");
141                rpc_createerr.cf_stat = RPC_SYSTEMERROR;
142                rpc_createerr.cf_error.re_errno = errno;
143                goto fooy;
144        }
145        ct = (struct ct_data *)mem_alloc(sizeof (*ct));
146        if (ct == NULL) {
147                (void)fprintf(stderr, "clnttcp_create: out of memory\n");
148                rpc_createerr.cf_stat = RPC_SYSTEMERROR;
149                rpc_createerr.cf_error.re_errno = errno;
150                goto fooy;
151        }
152
153        /*
154         * If no port number given ask the pmap for one
155         */
156        if (raddr->sin_port == 0) {
157                u_short port;
158                if ((port = pmap_getport(raddr, prog, vers, IPPROTO_TCP)) == 0) {
159                        mem_free((caddr_t)ct, sizeof(struct ct_data));
160                        mem_free((caddr_t)h, sizeof(CLIENT));
161                        return ((CLIENT *)NULL);
162                }
163                raddr->sin_port = htons(port);
164        }
165
166        /*
167         * If no socket given, open one
168         */
169        if (*sockp < 0) {
170                *sockp = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
171                (void)bindresvport(*sockp, (struct sockaddr_in *)0);
172                if ((*sockp < 0)
173                    || (connect(*sockp, (struct sockaddr *)raddr,
174                    sizeof(*raddr)) < 0)) {
175                        rpc_createerr.cf_stat = RPC_SYSTEMERROR;
176                        rpc_createerr.cf_error.re_errno = errno;
177                        if (*sockp != -1)
178                                (void)_RPC_close(*sockp);
179                        goto fooy;
180                }
181                ct->ct_closeit = TRUE;
182        } else {
183                ct->ct_closeit = FALSE;
184        }
185
186        /*
187         * Set up private data struct
188         */
189        ct->ct_sock = *sockp;
190        ct->ct_wait.tv_usec = 0;
191        ct->ct_waitset = FALSE;
192        ct->ct_addr = *raddr;
193
194        /*
195         * Initialize call message
196         */
197        (void)gettimeofday(&now, (struct timezone *)0);
198        call_msg.rm_xid = (++disrupt) ^ getpid() ^ now.tv_sec ^ now.tv_usec;
199        call_msg.rm_direction = CALL;
200        call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
201        call_msg.rm_call.cb_prog = prog;
202        call_msg.rm_call.cb_vers = vers;
203
204        /*
205         * pre-serialize the static part of the call msg and stash it away
206         */
207        xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE,
208            XDR_ENCODE);
209        if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
210                if (ct->ct_closeit) {
211                        (void)_RPC_close(*sockp);
212                }
213                goto fooy;
214        }
215        ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
216        XDR_DESTROY(&(ct->ct_xdrs));
217
218        /*
219         * Create a client handle which uses xdrrec for serialization
220         * and authnone for authentication.
221         */
222        xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
223            (caddr_t)ct, readtcp, writetcp);
224        h->cl_ops = &tcp_ops;
225        h->cl_private = (caddr_t) ct;
226        h->cl_auth = authnone_create();
227        return (h);
228
229fooy:
230        /*
231         * Something goofed, free stuff and barf
232         */
233        if (ct)
234                mem_free((caddr_t)ct, sizeof(struct ct_data));
235        if (h)
236                mem_free((caddr_t)h, sizeof(CLIENT));
237        return ((CLIENT *)NULL);
238}
239
240static enum clnt_stat
241clnttcp_call(
242        CLIENT *h,
243        rpcproc_t proc,
244        xdrproc_t xdr_args,
245        void *args_ptr,
246        xdrproc_t xdr_results,
247        void *results_ptr,
248        struct timeval timeout)
249{
250        struct ct_data *ct = (struct ct_data *) h->cl_private;
251        XDR *xdrs = &(ct->ct_xdrs);
252        struct rpc_msg reply_msg;
253        u_int32_t x_id;
254        u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli;      /* yuk */
255        bool_t shipnow;
256        int refreshes = 2;
257
258        if (!ct->ct_waitset) {
259                ct->ct_wait = timeout;
260        }
261
262        shipnow =
263            (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0
264            && timeout.tv_usec == 0) ? FALSE : TRUE;
265
266call_again:
267        xdrs->x_op = XDR_ENCODE;
268        ct->ct_error.re_status = RPC_SUCCESS;
269        x_id = ntohl(--(*msg_x_id));
270        if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
271            (! XDR_PUTLONG(xdrs, (long *)&proc)) ||
272            (! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
273            (! (*xdr_args)(xdrs, args_ptr))) {
274                if (ct->ct_error.re_status == RPC_SUCCESS)
275                        ct->ct_error.re_status = RPC_CANTENCODEARGS;
276                (void)xdrrec_endofrecord(xdrs, TRUE);
277                return (ct->ct_error.re_status);
278        }
279        if (! xdrrec_endofrecord(xdrs, shipnow)) {
280                return (ct->ct_error.re_status = RPC_CANTSEND);
281        }
282        if (! shipnow) {
283                return (RPC_SUCCESS);
284        }
285        /*
286         * Hack to provide rpc-based message passing
287         */
288        if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
289                return(ct->ct_error.re_status = RPC_TIMEDOUT);
290        }
291
292
293        /*
294         * Keep receiving until we get a valid transaction id
295         */
296        xdrs->x_op = XDR_DECODE;
297        while (TRUE) {
298                reply_msg.acpted_rply.ar_verf = _null_auth;
299                reply_msg.acpted_rply.ar_results.where = NULL;
300                reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
301                if (! xdrrec_skiprecord(xdrs))
302                        return (ct->ct_error.re_status);
303                /* now decode and validate the response header */
304                if (! xdr_replymsg(xdrs, &reply_msg)) {
305                        if (ct->ct_error.re_status == RPC_SUCCESS)
306                                continue;
307                        return (ct->ct_error.re_status);
308                }
309                if (reply_msg.rm_xid == x_id)
310                        break;
311        }
312
313        /*
314         * process header
315         */
316        _seterr_reply(&reply_msg, &(ct->ct_error));
317        if (ct->ct_error.re_status == RPC_SUCCESS) {
318                if (! AUTH_VALIDATE(h->cl_auth, &reply_msg.acpted_rply.ar_verf)) {
319                        ct->ct_error.re_status = RPC_AUTHERROR;
320                        ct->ct_error.re_why = AUTH_INVALIDRESP;
321                } else if (! (*xdr_results)(xdrs, results_ptr)) {
322                        if (ct->ct_error.re_status == RPC_SUCCESS)
323                                ct->ct_error.re_status = RPC_CANTDECODERES;
324                }
325                /* free verifier ... */
326                if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
327                        xdrs->x_op = XDR_FREE;
328                        (void)xdr_opaque_auth(xdrs, &(reply_msg.acpted_rply.ar_verf));
329                }
330        }  /* end successful completion */
331        else {
332                /* maybe our credentials need to be refreshed ... */
333                if (refreshes-- && AUTH_REFRESH(h->cl_auth, &reply_msg))
334                        goto call_again;
335        }  /* end of unsuccessful completion */
336        return (ct->ct_error.re_status);
337}
338
339static void
340clnttcp_geterr(
341        CLIENT *h,
342        struct rpc_err *errp)
343{
344        struct ct_data *ct;
345
346        ct = (struct ct_data *) h->cl_private;
347        *errp = ct->ct_error;
348}
349
350static bool_t
351clnttcp_freeres(
352        CLIENT *cl,
353        xdrproc_t xdr_res,
354        void *res_ptr)
355{
356        struct ct_data *ct;
357        XDR *xdrs;
358
359        ct = (struct ct_data *)cl->cl_private;
360        xdrs = &(ct->ct_xdrs);
361       
362        xdrs->x_op = XDR_FREE;
363        return ((*xdr_res)(xdrs, res_ptr));
364}
365
366static void
367clnttcp_abort(void)
368{
369}
370
371
372static bool_t
373clnttcp_control(
374        CLIENT *cl,
375        int request,
376        char *info)
377{
378        struct ct_data *ct;
379        struct timeval *tv;
380        socklen_t len;
381       
382        ct = (struct ct_data *)cl->cl_private;
383
384        switch (request) {
385        case CLSET_FD_CLOSE:
386                ct->ct_closeit = TRUE;
387                break;
388        case CLSET_FD_NCLOSE:
389                ct->ct_closeit = FALSE;
390                break;
391        case CLSET_TIMEOUT:
392                if (info == NULL)
393                        return(FALSE);
394                tv = (struct timeval *)info;
395                ct->ct_wait.tv_sec = tv->tv_sec;
396                ct->ct_wait.tv_usec = tv->tv_usec;
397                ct->ct_waitset = TRUE;
398                break;
399        case CLGET_TIMEOUT:
400                if (info == NULL)
401                        return(FALSE);
402                *(struct timeval *)info = ct->ct_wait;
403                break;
404        case CLGET_SERVER_ADDR:
405                if (info == NULL)
406                        return(FALSE);
407                *(struct sockaddr_in *)info = ct->ct_addr;
408                break;
409        case CLGET_FD:
410                if (info == NULL)
411                        return(FALSE);
412                *(int *)info = ct->ct_sock;
413                break;
414        case CLGET_XID:
415                /*
416                 * use the knowledge that xid is the
417                 * first element in the call structure
418                 * This will get the xid of the PREVIOUS call
419                 */
420                if (info == NULL)
421                        return(FALSE);
422                *(u_int32_t *)info =
423                        ntohl(*(u_int32_t *)&ct->ct_u.ct_mcalli);
424                break;
425        case CLSET_XID:
426                /* This will set the xid of the NEXT call */
427                if (info == NULL)
428                        return(FALSE);
429                *(u_int32_t *)&ct->ct_u.ct_mcalli =
430                        htonl(*((u_int32_t *)info) + 1);
431                /* decrement by 1 as clnttcp_call() increments once */
432        case CLGET_VERS:
433                /*
434                 * This RELIES on the information that, in the call body,
435                 * the version number field is the fifth field from the
436                 * begining of the RPC header. MUST be changed if the
437                 * call_struct is changed
438                 */
439                if (info == NULL)
440                        return(FALSE);
441                *(u_int32_t *)info =
442                        ntohl(*(u_int32_t *)(ct->ct_u.ct_mcallc +
443                                                4 * BYTES_PER_XDR_UNIT));
444                break;
445        case CLSET_VERS:
446                if (info == NULL)
447                        return(FALSE);
448                *(u_int32_t *)(ct->ct_u.ct_mcallc +
449                        4 * BYTES_PER_XDR_UNIT) =
450                        htonl(*(u_int32_t *)info);
451                break;
452
453        case CLGET_PROG:
454                /*
455                 * This RELIES on the information that, in the call body,
456                 * the program number field is the fourth field from the
457                 * begining of the RPC header. MUST be changed if the
458                 * call_struct is changed
459                 */
460                if (info == NULL)
461                        return(FALSE);
462                *(u_int32_t *)info = ntohl(*(u_int32_t *)(ct->ct_u.ct_mcallc +
463                                                3 * BYTES_PER_XDR_UNIT));
464                break;
465
466        case CLSET_PROG:
467                if (info == NULL)
468                        return(FALSE);
469                *(u_int32_t *)(ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT)
470                                = htonl(*(u_int32_t *)info);
471                break;
472
473#ifndef __rtems__
474        /* XXX defined in old.. not new */
475        case CLGET_LOCAL_ADDR:
476                len = sizeof(struct sockaddr);
477                if (getsockname(ct->ct_sock, (struct sockaddr *)info, &len) <0)
478                        return(FALSE);
479                break;
480#endif
481
482        case CLGET_RETRY_TIMEOUT:
483        case CLSET_RETRY_TIMEOUT:
484        case CLGET_SVC_ADDR:
485        case CLSET_SVC_ADDR:
486        case CLSET_PUSH_TIMOD:
487        case CLSET_POP_TIMOD:
488        default:
489                return (FALSE);
490        }
491        return (TRUE);
492}
493
494
495static void
496clnttcp_destroy(
497        CLIENT *h)
498{
499        struct ct_data *ct =
500            (struct ct_data *) h->cl_private;
501
502        if (ct->ct_closeit) {
503                (void)_RPC_close(ct->ct_sock);
504        }
505        XDR_DESTROY(&(ct->ct_xdrs));
506        mem_free(ct, sizeof(struct ct_data));
507        mem_free(h, sizeof(CLIENT));
508}
509
510/*
511 * Interface between xdr serializer and tcp connection.
512 * Behaves like the system calls, read & write, but keeps some error state
513 * around for the rpc level.
514 */
515static int
516readtcp(
517        char *_ct,
518        char *buf,
519        int len)
520{
521        struct ct_data *ct = (struct ct_data*) _ct;
522        fd_set *fds, readfds;
523        struct timeval start, after, duration, delta, tmp, tv;
524        int r, save_errno;
525
526        if (len == 0)
527                return (0);
528
529        if (ct->ct_sock + 1 > FD_SETSIZE) {
530                int bytes = howmany(ct->ct_sock + 1, NFDBITS) * sizeof(fd_mask);
531                fds = (fd_set *)malloc(bytes);
532                if (fds == NULL)
533                        return (-1);
534                memset(fds, 0, bytes);
535        } else {
536                fds = &readfds;
537                FD_ZERO(fds);
538        }
539
540        gettimeofday(&start, NULL);
541        delta = ct->ct_wait;
542        while (TRUE) {
543                /* XXX we know the other bits are still clear */
544                FD_SET(ct->ct_sock, fds);
545                tv = delta;     /* in case select writes back */
546                r = select(ct->ct_sock+1, fds, NULL, NULL, &tv);
547                save_errno = errno;
548
549                gettimeofday(&after, NULL);
550                timersub(&start, &after, &duration);
551                timersub(&ct->ct_wait, &duration, &tmp);
552                delta = tmp;
553                if (delta.tv_sec < 0 || !timerisset(&delta))
554                        r = 0;
555
556                switch (r) {
557                case 0:
558                        if (fds != &readfds)
559                                free(fds);
560                        ct->ct_error.re_status = RPC_TIMEDOUT;
561                        return (-1);
562
563                case -1:
564                        if (errno == EINTR)
565                                continue;
566                        if (fds != &readfds)
567                                free(fds);
568                        ct->ct_error.re_status = RPC_CANTRECV;
569                        ct->ct_error.re_errno = save_errno;
570                        return (-1);
571                }
572                break;
573        }
574        switch (len = _RPC_read(ct->ct_sock, buf, len)) {
575
576        case 0:
577                /* premature eof */
578                ct->ct_error.re_errno = ECONNRESET;
579                ct->ct_error.re_status = RPC_CANTRECV;
580                len = -1;  /* it's really an error */
581                break;
582
583        case -1:
584                ct->ct_error.re_errno = errno;
585                ct->ct_error.re_status = RPC_CANTRECV;
586                break;
587        }
588        return (len);
589}
590
591static int
592writetcp(
593        char *_ct,
594        char *buf,
595        int len)
596{
597        struct ct_data *ct = (struct ct_data *) _ct;
598        int i, cnt;
599
600        for (cnt = len; cnt > 0; cnt -= i, buf += i) {
601                if ((i = _RPC_write(ct->ct_sock, buf, cnt)) == -1) {
602                        ct->ct_error.re_errno = errno;
603                        ct->ct_error.re_status = RPC_CANTSEND;
604                        return (-1);
605                }
606        }
607        return (len);
608}
Note: See TracBrowser for help on using the repository browser.