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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [librpc/] [src/] [rpc/] [clnt_udp.c] - Blame information for rev 227

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

Line No. Rev Author Line
1 30 unneback
/*
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_udp.c 1.39 87/08/11 Copyr 1984 Sun Micro";*/
32
/*static char *sccsid = "from: @(#)clnt_udp.c   2.2 88/08/01 4.0 RPCSRC";*/
33
static char *rcsid = "$FreeBSD: src/lib/libc/rpc/clnt_udp.c,v 1.15 2000/01/27 23:06:36 jasone Exp $";
34
#endif
35
 
36
/*
37
 * clnt_udp.c, Implements a UDP/IP based, client side RPC.
38
 *
39
 * Copyright (C) 1984, Sun Microsystems, Inc.
40
 */
41
 
42
#include <stdio.h>
43
#include <stdlib.h>
44
#include <unistd.h>
45
#include <string.h>
46
#include <rpc/rpc.h>
47
#include <sys/socket.h>
48
#include <sys/ioctl.h>
49
#include <netdb.h>
50
#include <errno.h>
51
#include <rpc/pmap_clnt.h>
52
 
53
/*
54
 * UDP bases client side rpc operations
55
 */
56
static enum clnt_stat   clntudp_call();
57
static void             clntudp_abort();
58
static void             clntudp_geterr();
59
static bool_t           clntudp_freeres();
60
static bool_t           clntudp_control();
61
static void             clntudp_destroy();
62
 
63
static struct clnt_ops udp_ops = {
64
        clntudp_call,
65
        clntudp_abort,
66
        clntudp_geterr,
67
        clntudp_freeres,
68
        clntudp_destroy,
69
        clntudp_control
70
};
71
 
72
/*
73
 * Private data kept per client handle
74
 */
75
struct cu_data {
76
        int                cu_sock;
77
        bool_t             cu_closeit;
78
        struct sockaddr_in cu_raddr;
79
        int                cu_rlen;
80
        struct timeval     cu_wait;
81
        struct timeval     cu_total;
82
        struct rpc_err     cu_error;
83
        XDR                cu_outxdrs;
84
        u_int              cu_xdrpos;
85
        u_int              cu_sendsz;
86
        char               *cu_outbuf;
87
        u_int              cu_recvsz;
88
        char               cu_inbuf[1];
89
};
90
 
91
/*
92
 * Create a UDP based client handle.
93
 * If *sockp<0, *sockp is set to a newly created UPD socket.
94
 * If raddr->sin_port is 0 a binder on the remote machine
95
 * is consulted for the correct port number.
96
 * NB: It is the clients responsibility to close *sockp.
97
 * NB: The rpch->cl_auth is initialized to null authentication.
98
 *     Caller may wish to set this something more useful.
99
 *
100
 * wait is the amount of time used between retransmitting a call if
101
 * no response has been heard;  retransmition occurs until the actual
102
 * rpc call times out.
103
 *
104
 * sendsz and recvsz are the maximum allowable packet sizes that can be
105
 * sent and received.
106
 */
107
CLIENT *
108
clntudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz)
109
        struct sockaddr_in *raddr;
110
        u_long program;
111
        u_long version;
112
        struct timeval wait;
113
        register int *sockp;
114
        u_int sendsz;
115
        u_int recvsz;
116
{
117
        CLIENT *cl;
118
        register struct cu_data *cu = NULL;
119
        struct timeval now;
120
        struct rpc_msg call_msg;
121
        static u_int32_t disrupt;
122
 
123
        if (disrupt == 0)
124
                disrupt = (u_int32_t)(long)raddr;
125
 
126
        cl = (CLIENT *)mem_alloc(sizeof(CLIENT));
127
        if (cl == NULL) {
128
                (void) fprintf(stderr, "clntudp_create: out of memory\n");
129
                rpc_createerr.cf_stat = RPC_SYSTEMERROR;
130
                rpc_createerr.cf_error.re_errno = errno;
131
                goto fooy;
132
        }
133
        sendsz = ((sendsz + 3) / 4) * 4;
134
        recvsz = ((recvsz + 3) / 4) * 4;
135
        cu = (struct cu_data *)mem_alloc(sizeof(*cu) + sendsz + recvsz);
136
        if (cu == NULL) {
137
                (void) fprintf(stderr, "clntudp_create: out of memory\n");
138
                rpc_createerr.cf_stat = RPC_SYSTEMERROR;
139
                rpc_createerr.cf_error.re_errno = errno;
140
                goto fooy;
141
        }
142
        cu->cu_outbuf = &cu->cu_inbuf[recvsz];
143
 
144
        (void)gettimeofday(&now, (struct timezone *)0);
145
        if (raddr->sin_port == 0) {
146
                u_short port;
147
                if ((port =
148
                    pmap_getport(raddr, program, version, IPPROTO_UDP)) == 0) {
149
                        goto fooy;
150
                }
151
                raddr->sin_port = htons(port);
152
        }
153
        cl->cl_ops = &udp_ops;
154
        cl->cl_private = (caddr_t)cu;
155
        cu->cu_raddr = *raddr;
156
        cu->cu_rlen = sizeof (cu->cu_raddr);
157
        cu->cu_wait = wait;
158
        cu->cu_total.tv_sec = -1;
159
        cu->cu_total.tv_usec = -1;
160
        cu->cu_sendsz = sendsz;
161
        cu->cu_recvsz = recvsz;
162
        call_msg.rm_xid = (++disrupt) ^ getpid() ^ now.tv_sec ^ now.tv_usec;
163
        call_msg.rm_direction = CALL;
164
        call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
165
        call_msg.rm_call.cb_prog = program;
166
        call_msg.rm_call.cb_vers = version;
167
        xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf,
168
            sendsz, XDR_ENCODE);
169
        if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) {
170
                goto fooy;
171
        }
172
        cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
173
        if (*sockp < 0) {
174
                int dontblock = 1;
175
 
176
                *sockp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
177
                if (*sockp < 0) {
178
                        rpc_createerr.cf_stat = RPC_SYSTEMERROR;
179
                        rpc_createerr.cf_error.re_errno = errno;
180
                        goto fooy;
181
                }
182
                /* attempt to bind to priv port */
183
                (void)bindresvport(*sockp, (struct sockaddr_in *)0);
184
                /* the sockets rpc controls are non-blocking */
185
                (void)ioctl(*sockp, FIONBIO, (char *) &dontblock);
186
                cu->cu_closeit = TRUE;
187
        } else {
188
                cu->cu_closeit = FALSE;
189
        }
190
        cu->cu_sock = *sockp;
191
        cl->cl_auth = authnone_create();
192
        return (cl);
193
fooy:
194
        if (cu)
195
                mem_free((caddr_t)cu, sizeof(*cu) + sendsz + recvsz);
196
        if (cl)
197
                mem_free((caddr_t)cl, sizeof(CLIENT));
198
        return ((CLIENT *)NULL);
199
}
200
 
201
CLIENT *
202
clntudp_create(raddr, program, version, wait, sockp)
203
        struct sockaddr_in *raddr;
204
        u_long program;
205
        u_long version;
206
        struct timeval wait;
207
        register int *sockp;
208
{
209
 
210
        return(clntudp_bufcreate(raddr, program, version, wait, sockp,
211
            UDPMSGSIZE, UDPMSGSIZE));
212
}
213
 
214
static enum clnt_stat
215
clntudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout)
216
        register CLIENT *cl;            /* client handle */
217
        u_long          proc;           /* procedure number */
218
        xdrproc_t       xargs;          /* xdr routine for args */
219
        caddr_t         argsp;          /* pointer to args */
220
        xdrproc_t       xresults;       /* xdr routine for results */
221
        caddr_t         resultsp;       /* pointer to results */
222
        struct timeval  utimeout;       /* seconds to wait before giving up */
223
{
224
        register struct cu_data *cu = (struct cu_data *)cl->cl_private;
225
        register XDR *xdrs;
226
        register int outlen;
227
        register int inlen;
228
        int fromlen;
229
        fd_set *fds, readfds;
230
        struct sockaddr_in from;
231
        struct rpc_msg reply_msg;
232
        XDR reply_xdrs;
233
        struct timeval time_waited, start, after, tmp1, tmp2, tv;
234
        bool_t ok;
235
        int nrefreshes = 2;     /* number of times to refresh cred */
236
        struct timeval timeout;
237
 
238
        if (cu->cu_total.tv_usec == -1)
239
                timeout = utimeout;     /* use supplied timeout */
240
        else
241
                timeout = cu->cu_total; /* use default timeout */
242
 
243
        if (cu->cu_sock + 1 > FD_SETSIZE) {
244
                int bytes = howmany(cu->cu_sock + 1, NFDBITS) * sizeof(fd_mask);
245
                fds = (fd_set *)malloc(bytes);
246
                if (fds == NULL)
247
                        return (cu->cu_error.re_status = RPC_CANTSEND);
248
                memset(fds, 0, bytes);
249
        } else {
250
                fds = &readfds;
251
                FD_ZERO(fds);
252
        }
253
 
254
        timerclear(&time_waited);
255
 
256
call_again:
257
        xdrs = &(cu->cu_outxdrs);
258
        xdrs->x_op = XDR_ENCODE;
259
        XDR_SETPOS(xdrs, cu->cu_xdrpos);
260
        /*
261
         * the transaction is the first thing in the out buffer
262
         */
263
        (*(u_short *)(cu->cu_outbuf))++;
264
        if ((! XDR_PUTLONG(xdrs, (long *)&proc)) ||
265
            (! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
266
            (! (*xargs)(xdrs, argsp))) {
267
                if (fds != &readfds)
268
                        free(fds);
269
                return (cu->cu_error.re_status = RPC_CANTENCODEARGS);
270
        }
271
        outlen = (int)XDR_GETPOS(xdrs);
272
 
273
send_again:
274
        if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0,
275
            (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) != outlen) {
276
                cu->cu_error.re_errno = errno;
277
                if (fds != &readfds)
278
                        free(fds);
279
                return (cu->cu_error.re_status = RPC_CANTSEND);
280
        }
281
 
282
        /*
283
         * Hack to provide rpc-based message passing
284
         */
285
        if (!timerisset(&timeout)) {
286
                if (fds != &readfds)
287
                        free(fds);
288
                return (cu->cu_error.re_status = RPC_TIMEDOUT);
289
        }
290
        /*
291
         * sub-optimal code appears here because we have
292
         * some clock time to spare while the packets are in flight.
293
         * (We assume that this is actually only executed once.)
294
         */
295
        reply_msg.acpted_rply.ar_verf = _null_auth;
296
        reply_msg.acpted_rply.ar_results.where = resultsp;
297
        reply_msg.acpted_rply.ar_results.proc = xresults;
298
 
299
        gettimeofday(&start, NULL);
300
        for (;;) {
301
                /* XXX we know the other bits are still clear */
302
                FD_SET(cu->cu_sock, fds);
303
                tv = cu->cu_wait;
304
                switch (select(cu->cu_sock+1, fds, NULL, NULL, &tv)) {
305
 
306
                case 0:
307
                        timeradd(&time_waited, &cu->cu_wait, &tmp1);
308
                        time_waited = tmp1;
309
                        if (timercmp(&time_waited, &timeout, <))
310
                                goto send_again;
311
                        if (fds != &readfds)
312
                                free(fds);
313
                        return (cu->cu_error.re_status = RPC_TIMEDOUT);
314
 
315
                case -1:
316
                        if (errno == EINTR) {
317
                                gettimeofday(&after, NULL);
318
                                timersub(&after, &start, &tmp1);
319
                                timeradd(&time_waited, &tmp1, &tmp2);
320
                                time_waited = tmp2;
321
                                if (timercmp(&time_waited, &timeout, <))
322
                                        continue;
323
                                if (fds != &readfds)
324
                                        free(fds);
325
                                return (cu->cu_error.re_status = RPC_TIMEDOUT);
326
                        }
327
                        cu->cu_error.re_errno = errno;
328
                        if (fds != &readfds)
329
                                free(fds);
330
                        return (cu->cu_error.re_status = RPC_CANTRECV);
331
                }
332
 
333
                do {
334
                        fromlen = sizeof(struct sockaddr);
335
                        inlen = recvfrom(cu->cu_sock, cu->cu_inbuf,
336
                                (int) cu->cu_recvsz, 0,
337
                                (struct sockaddr *)&from, &fromlen);
338
                } while (inlen < 0 && errno == EINTR);
339
                if (inlen < 0) {
340
                        if (errno == EWOULDBLOCK)
341
                                continue;
342
                        cu->cu_error.re_errno = errno;
343
                        if (fds != &readfds)
344
                                free(fds);
345
                        return (cu->cu_error.re_status = RPC_CANTRECV);
346
                }
347
                if (inlen < sizeof(u_int32_t))
348
                        continue;
349
                /* see if reply transaction id matches sent id */
350
                if (*((u_int32_t *)(cu->cu_inbuf)) != *((u_int32_t *)(cu->cu_outbuf)))
351
                        continue;
352
                /* we now assume we have the proper reply */
353
                break;
354
        }
355
 
356
        /*
357
         * now decode and validate the response
358
         */
359
        xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)inlen, XDR_DECODE);
360
        ok = xdr_replymsg(&reply_xdrs, &reply_msg);
361
        /* XDR_DESTROY(&reply_xdrs);  save a few cycles on noop destroy */
362
        if (ok) {
363
                _seterr_reply(&reply_msg, &(cu->cu_error));
364
                if (cu->cu_error.re_status == RPC_SUCCESS) {
365
                        if (! AUTH_VALIDATE(cl->cl_auth,
366
                                &reply_msg.acpted_rply.ar_verf)) {
367
                                cu->cu_error.re_status = RPC_AUTHERROR;
368
                                cu->cu_error.re_why = AUTH_INVALIDRESP;
369
                        }
370
                        if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
371
                                xdrs->x_op = XDR_FREE;
372
                                (void)xdr_opaque_auth(xdrs,
373
                                    &(reply_msg.acpted_rply.ar_verf));
374
                        }
375
                }  /* end successful completion */
376
                else {
377
                        /* maybe our credentials need to be refreshed ... */
378
                        if (nrefreshes > 0 && AUTH_REFRESH(cl->cl_auth)) {
379
                                nrefreshes--;
380
                                goto call_again;
381
                        }
382
                }  /* end of unsuccessful completion */
383
        }  /* end of valid reply message */
384
        else {
385
                /*
386
                 * It's possible for xdr_replymsg() to fail partway
387
                 * through its attempt to decode the result from the
388
                 * server. If this happens, it will leave the reply
389
                 * structure partially populated with dynamically
390
                 * allocated memory. (This can happen if someone uses
391
                 * clntudp_bufcreate() to create a CLIENT handle and
392
                 * specifies a receive buffer size that is too small.)
393
                 * This memory must be free()ed to avoid a leak.
394
                 */
395
                int op = reply_xdrs.x_op;
396
                reply_xdrs.x_op = XDR_FREE;
397
                xdr_replymsg(&reply_xdrs, &reply_msg);
398
                reply_xdrs.x_op = op;
399
                cu->cu_error.re_status = RPC_CANTDECODERES;
400
        }
401
        if (fds != &readfds)
402
                free(fds);
403
        return (cu->cu_error.re_status);
404
}
405
 
406
static void
407
clntudp_geterr(cl, errp)
408
        CLIENT *cl;
409
        struct rpc_err *errp;
410
{
411
        register struct cu_data *cu = (struct cu_data *)cl->cl_private;
412
 
413
        *errp = cu->cu_error;
414
}
415
 
416
 
417
static bool_t
418
clntudp_freeres(cl, xdr_res, res_ptr)
419
        CLIENT *cl;
420
        xdrproc_t xdr_res;
421
        caddr_t res_ptr;
422
{
423
        register struct cu_data *cu = (struct cu_data *)cl->cl_private;
424
        register XDR *xdrs = &(cu->cu_outxdrs);
425
 
426
        xdrs->x_op = XDR_FREE;
427
        return ((*xdr_res)(xdrs, res_ptr));
428
}
429
 
430
static void
431
clntudp_abort(/*h*/)
432
        /*CLIENT *h;*/
433
{
434
}
435
 
436
 
437
static bool_t
438
clntudp_control(cl, request, info)
439
        CLIENT *cl;
440
        int request;
441
        char *info;
442
{
443
        register struct cu_data *cu = (struct cu_data *)cl->cl_private;
444
        register struct timeval *tv;
445
        int len;
446
 
447
        switch (request) {
448
        case CLSET_FD_CLOSE:
449
                cu->cu_closeit = TRUE;
450
                break;
451
        case CLSET_FD_NCLOSE:
452
                cu->cu_closeit = FALSE;
453
                break;
454
        case CLSET_TIMEOUT:
455
                if (info == NULL)
456
                        return(FALSE);
457
                tv = (struct timeval *)info;
458
                cu->cu_total.tv_sec = tv->tv_sec;
459
                cu->cu_total.tv_usec = tv->tv_usec;
460
                break;
461
        case CLGET_TIMEOUT:
462
                if (info == NULL)
463
                        return(FALSE);
464
                *(struct timeval *)info = cu->cu_total;
465
                break;
466
        case CLSET_RETRY_TIMEOUT:
467
                if (info == NULL)
468
                        return(FALSE);
469
                tv = (struct timeval *)info;
470
                cu->cu_wait.tv_sec = tv->tv_sec;
471
                cu->cu_wait.tv_usec = tv->tv_usec;
472
                break;
473
        case CLGET_RETRY_TIMEOUT:
474
                if (info == NULL)
475
                        return(FALSE);
476
                *(struct timeval *)info = cu->cu_wait;
477
                break;
478
        case CLGET_SERVER_ADDR:
479
                if (info == NULL)
480
                        return(FALSE);
481
                *(struct sockaddr_in *)info = cu->cu_raddr;
482
                break;
483
        case CLGET_FD:
484
                if (info == NULL)
485
                        return(FALSE);
486
                *(int *)info = cu->cu_sock;
487
                break;
488
        case CLGET_XID:
489
                /*
490
                 * use the knowledge that xid is the
491
                 * first element in the call structure *.
492
                 * This will get the xid of the PREVIOUS call
493
                 */
494
                if (info == NULL)
495
                        return(FALSE);
496
                *(u_long *)info = ntohl(*(u_long *)cu->cu_outbuf);
497
                break;
498
        case CLSET_XID:
499
                /* This will set the xid of the NEXT call */
500
                if (info == NULL)
501
                        return(FALSE);
502
                *(u_long *)cu->cu_outbuf =  htonl(*(u_long *)info - 1);
503
                /* decrement by 1 as clntudp_call() increments once */
504
        case CLGET_VERS:
505
                /*
506
                 * This RELIES on the information that, in the call body,
507
                 * the version number field is the fifth field from the
508
                 * begining of the RPC header. MUST be changed if the
509
                 * call_struct is changed
510
                 */
511
                if (info == NULL)
512
                        return(FALSE);
513
                *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf +
514
                                                4 * BYTES_PER_XDR_UNIT));
515
                break;
516
        case CLSET_VERS:
517
                if (info == NULL)
518
                        return(FALSE);
519
                *(u_long *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT)
520
                                = htonl(*(u_long *)info);
521
                break;
522
        case CLGET_PROG:
523
                /*
524
                 * This RELIES on the information that, in the call body,
525
                 * the program number field is the  field from the
526
                 * begining of the RPC header. MUST be changed if the
527
                 * call_struct is changed
528
                 */
529
                if (info == NULL)
530
                        return(FALSE);
531
                *(u_long *)info = ntohl(*(u_long *)(cu->cu_outbuf +
532
                                                3 * BYTES_PER_XDR_UNIT));
533
                break;
534
        case CLSET_PROG:
535
                if (info == NULL)
536
                        return(FALSE);
537
                *(u_long *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT)
538
                                = htonl(*(u_long *)info);
539
                break;
540
        case CLGET_LOCAL_ADDR:
541
                len = sizeof(struct sockaddr);
542
                if (getsockname(cu->cu_sock, (struct sockaddr *)info, &len) <0)
543
                        return(FALSE);
544
                break;
545
        case CLGET_SVC_ADDR:
546
        case CLSET_SVC_ADDR:
547
        case CLSET_PUSH_TIMOD:
548
        case CLSET_POP_TIMOD:
549
        default:
550
                return (FALSE);
551
        }
552
        return (TRUE);
553
}
554
 
555
static void
556
clntudp_destroy(cl)
557
        CLIENT *cl;
558
{
559
        register struct cu_data *cu = (struct cu_data *)cl->cl_private;
560
 
561
        if (cu->cu_closeit) {
562
                (void)_close(cu->cu_sock);
563
        }
564
        XDR_DESTROY(&(cu->cu_outxdrs));
565
        mem_free((caddr_t)cu, (sizeof(*cu) + cu->cu_sendsz + cu->cu_recvsz));
566
        mem_free((caddr_t)cl, sizeof(CLIENT));
567
}

powered by: WebSVN 2.1.0

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