OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems/] [c/] [src/] [librpc/] [src/] [rpc/] [clnt_tcp.c] - Blame information for rev 1771

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.