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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [cpukit/] [librpc/] [src/] [rpc/] [svc_udp.c] - Blame information for rev 1026

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

Line No. Rev Author Line
1 1026 ivang
/*
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_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro";*/
32
/*static char *sccsid = "from: @(#)svc_udp.c    2.2 88/07/29 4.0 RPCSRC";*/
33
static char *rcsid = "$FreeBSD: src/lib/libc/rpc/svc_udp.c,v 1.13 2000/01/27 23:06:41 jasone Exp $";
34
#endif
35
 
36
/*
37
 * svc_udp.c,
38
 * Server side for UDP/IP based RPC.  (Does some caching in the hopes of
39
 * achieving execute-at-most-once semantics.)
40
 *
41
 * Copyright (C) 1984, Sun Microsystems, Inc.
42
 */
43
 
44
#include <stdio.h>
45
#include <stdlib.h>
46
#include <unistd.h>
47
#include <string.h>
48
#include <rpc/rpc.h>
49
#include <sys/socket.h>
50
#include <errno.h>
51
 
52
#define rpc_buffer(xprt) ((xprt)->xp_p1)
53
#define MAX(a, b)     ((a > b) ? a : b)
54
 
55
static bool_t           svcudp_recv();
56
static bool_t           svcudp_reply();
57
static enum xprt_stat   svcudp_stat();
58
static bool_t           svcudp_getargs();
59
static bool_t           svcudp_freeargs();
60
static void             svcudp_destroy();
61
static void             cache_set __P((SVCXPRT *, u_long));
62
static int              cache_get __P((SVCXPRT *, struct rpc_msg *, char **, u_long *));
63
 
64
static struct xp_ops svcudp_op = {
65
        svcudp_recv,
66
        svcudp_stat,
67
        svcudp_getargs,
68
        svcudp_reply,
69
        svcudp_freeargs,
70
        svcudp_destroy
71
};
72
 
73
/*
74
 * kept in xprt->xp_p2
75
 */
76
struct svcudp_data {
77
        u_int   su_iosz;        /* byte size of send.recv buffer */
78
        u_long  su_xid;         /* transaction id */
79
        XDR     su_xdrs;        /* XDR handle */
80
        char    su_verfbody[MAX_AUTH_BYTES];    /* verifier body */
81
        char *  su_cache;       /* cached data, NULL if no cache */
82
};
83
#define su_data(xprt)   ((struct svcudp_data *)(xprt->xp_p2))
84
 
85
/*
86
 * Usage:
87
 *      xprt = svcudp_create(sock);
88
 *
89
 * If sock<0 then a socket is created, else sock is used.
90
 * If the socket, sock is not bound to a port then svcudp_create
91
 * binds it to an arbitrary port.  In any (successful) case,
92
 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
93
 * associated port number.
94
 * Once *xprt is initialized, it is registered as a transporter;
95
 * see (svc.h, xprt_register).
96
 * The routines returns NULL if a problem occurred.
97
 */
98
SVCXPRT *
99
svcudp_bufcreate(sock, sendsz, recvsz)
100
        register int sock;
101
        u_int sendsz, recvsz;
102
{
103
        bool_t madesock = FALSE;
104
        register SVCXPRT *xprt;
105
        register struct svcudp_data *su;
106
        struct sockaddr_in addr;
107
        int len = sizeof(struct sockaddr_in);
108
 
109
        if (sock == RPC_ANYSOCK) {
110
                if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
111
                        perror("svcudp_create: socket creation problem");
112
                        return ((SVCXPRT *)NULL);
113
                }
114
                madesock = TRUE;
115
        }
116
        memset((char *)&addr, 0, sizeof (addr));
117
        addr.sin_len = sizeof(struct sockaddr_in);
118
        addr.sin_family = AF_INET;
119
        if (bindresvport(sock, &addr)) {
120
                addr.sin_port = 0;
121
                (void)bind(sock, (struct sockaddr *)&addr, len);
122
        }
123
        if (getsockname(sock, (struct sockaddr *)&addr, &len) != 0) {
124
                perror("svcudp_create - cannot getsockname");
125
                if (madesock)
126
                        (void)_RPC_close(sock);
127
                return ((SVCXPRT *)NULL);
128
        }
129
        xprt = (SVCXPRT *)mem_alloc(sizeof(SVCXPRT));
130
        if (xprt == NULL) {
131
                (void)fprintf(stderr, "svcudp_create: out of memory\n");
132
                return (NULL);
133
        }
134
        su = (struct svcudp_data *)mem_alloc(sizeof(*su));
135
        if (su == NULL) {
136
                (void)fprintf(stderr, "svcudp_create: out of memory\n");
137
                return (NULL);
138
        }
139
        su->su_iosz = ((MAX(sendsz, recvsz) + 3) / 4) * 4;
140
        if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL) {
141
                (void)fprintf(stderr, "svcudp_create: out of memory\n");
142
                return (NULL);
143
        }
144
        xdrmem_create(
145
            &(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_DECODE);
146
        su->su_cache = NULL;
147
        xprt->xp_p2 = (caddr_t)su;
148
        xprt->xp_verf.oa_base = su->su_verfbody;
149
        xprt->xp_ops = &svcudp_op;
150
        xprt->xp_port = ntohs(addr.sin_port);
151
        xprt->xp_sock = sock;
152
        xprt_register(xprt);
153
        return (xprt);
154
}
155
 
156
SVCXPRT *
157
svcudp_create(sock)
158
        int sock;
159
{
160
 
161
        return(svcudp_bufcreate(sock, UDPMSGSIZE, UDPMSGSIZE));
162
}
163
 
164
static enum xprt_stat
165
svcudp_stat(xprt)
166
        SVCXPRT *xprt;
167
{
168
 
169
        return (XPRT_IDLE);
170
}
171
 
172
static bool_t
173
svcudp_recv(xprt, msg)
174
        register SVCXPRT *xprt;
175
        struct rpc_msg *msg;
176
{
177
        register struct svcudp_data *su = su_data(xprt);
178
        register XDR *xdrs = &(su->su_xdrs);
179
        register int rlen;
180
        char *reply;
181
        u_long replylen;
182
 
183
    again:
184
        xprt->xp_addrlen = sizeof(struct sockaddr_in);
185
        rlen = recvfrom(xprt->xp_sock, rpc_buffer(xprt), (int) su->su_iosz,
186
            0, (struct sockaddr *)&(xprt->xp_raddr), &(xprt->xp_addrlen));
187
        if (rlen == -1 && errno == EINTR)
188
                goto again;
189
        if (rlen == -1 || rlen < 4*sizeof(u_int32_t))
190
                return (FALSE);
191
        xdrs->x_op = XDR_DECODE;
192
        XDR_SETPOS(xdrs, 0);
193
        if (! xdr_callmsg(xdrs, msg))
194
                return (FALSE);
195
        su->su_xid = msg->rm_xid;
196
        if (su->su_cache != NULL) {
197
                if (cache_get(xprt, msg, &reply, &replylen)) {
198
                        (void) sendto(xprt->xp_sock, reply, (int) replylen, 0,
199
                          (struct sockaddr *) &xprt->xp_raddr, xprt->xp_addrlen);
200
                        return (TRUE);
201
                }
202
        }
203
        return (TRUE);
204
}
205
 
206
static bool_t
207
svcudp_reply(xprt, msg)
208
        register SVCXPRT *xprt;
209
        struct rpc_msg *msg;
210
{
211
        register struct svcudp_data *su = su_data(xprt);
212
        register XDR *xdrs = &(su->su_xdrs);
213
        register int slen;
214
        register bool_t stat = FALSE;
215
 
216
        xdrs->x_op = XDR_ENCODE;
217
        XDR_SETPOS(xdrs, 0);
218
        msg->rm_xid = su->su_xid;
219
        if (xdr_replymsg(xdrs, msg)) {
220
                slen = (int)XDR_GETPOS(xdrs);
221
                if (sendto(xprt->xp_sock, rpc_buffer(xprt), slen, 0,
222
                    (struct sockaddr *)&(xprt->xp_raddr), xprt->xp_addrlen)
223
                    == slen) {
224
                        stat = TRUE;
225
                        if (su->su_cache && slen >= 0) {
226
                                cache_set(xprt, (u_long) slen);
227
                        }
228
                }
229
        }
230
        return (stat);
231
}
232
 
233
static bool_t
234
svcudp_getargs(xprt, xdr_args, args_ptr)
235
        SVCXPRT *xprt;
236
        xdrproc_t xdr_args;
237
        caddr_t args_ptr;
238
{
239
 
240
        return ((*xdr_args)(&(su_data(xprt)->su_xdrs), args_ptr));
241
}
242
 
243
static bool_t
244
svcudp_freeargs(xprt, xdr_args, args_ptr)
245
        SVCXPRT *xprt;
246
        xdrproc_t xdr_args;
247
        caddr_t args_ptr;
248
{
249
        register XDR *xdrs = &(su_data(xprt)->su_xdrs);
250
 
251
        xdrs->x_op = XDR_FREE;
252
        return ((*xdr_args)(xdrs, args_ptr));
253
}
254
 
255
static void
256
svcudp_destroy(xprt)
257
        register SVCXPRT *xprt;
258
{
259
        register struct svcudp_data *su = su_data(xprt);
260
 
261
        xprt_unregister(xprt);
262
        (void)_RPC_close(xprt->xp_sock);
263
        XDR_DESTROY(&(su->su_xdrs));
264
        mem_free(rpc_buffer(xprt), su->su_iosz);
265
        mem_free((caddr_t)su, sizeof(struct svcudp_data));
266
        mem_free((caddr_t)xprt, sizeof(SVCXPRT));
267
}
268
 
269
 
270
/***********this could be a separate file*********************/
271
 
272
/*
273
 * Fifo cache for udp server
274
 * Copies pointers to reply buffers into fifo cache
275
 * Buffers are sent again if retransmissions are detected.
276
 */
277
 
278
#define SPARSENESS 4    /* 75% sparse */
279
 
280
#define CACHE_PERROR(msg)       \
281
        (void) fprintf(stderr,"%s\n", msg)
282
 
283
#define ALLOC(type, size)       \
284
        (type *) mem_alloc((unsigned) (sizeof(type) * (size)))
285
 
286
#define BZERO(addr, type, size)  \
287
        memset((char *) addr, 0, sizeof(type) * (int) (size))
288
 
289
/*
290
 * An entry in the cache
291
 */
292
typedef struct cache_node *cache_ptr;
293
struct cache_node {
294
        /*
295
         * Index into cache is xid, proc, vers, prog and address
296
         */
297
        u_long cache_xid;
298
        u_long cache_proc;
299
        u_long cache_vers;
300
        u_long cache_prog;
301
        struct sockaddr_in cache_addr;
302
        /*
303
         * The cached reply and length
304
         */
305
        char * cache_reply;
306
        u_long cache_replylen;
307
        /*
308
         * Next node on the list, if there is a collision
309
         */
310
        cache_ptr cache_next;
311
};
312
 
313
 
314
 
315
/*
316
 * The entire cache
317
 */
318
struct udp_cache {
319
        u_long uc_size;         /* size of cache */
320
        cache_ptr *uc_entries;  /* hash table of entries in cache */
321
        cache_ptr *uc_fifo;     /* fifo list of entries in cache */
322
        u_long uc_nextvictim;   /* points to next victim in fifo list */
323
        u_long uc_prog;         /* saved program number */
324
        u_long uc_vers;         /* saved version number */
325
        u_long uc_proc;         /* saved procedure number */
326
        struct sockaddr_in uc_addr; /* saved caller's address */
327
};
328
 
329
 
330
/*
331
 * the hashing function
332
 */
333
#define CACHE_LOC(transp, xid)  \
334
 (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size))
335
 
336
 
337
/*
338
 * Enable use of the cache.
339
 * Note: there is no disable.
340
 */
341
int svcudp_enablecache(transp, size)
342
        SVCXPRT *transp;
343
        u_long size;
344
{
345
        struct svcudp_data *su = su_data(transp);
346
        struct udp_cache *uc;
347
 
348
        if (su->su_cache != NULL) {
349
                CACHE_PERROR("enablecache: cache already enabled");
350
                return(0);
351
        }
352
        uc = ALLOC(struct udp_cache, 1);
353
        if (uc == NULL) {
354
                CACHE_PERROR("enablecache: could not allocate cache");
355
                return(0);
356
        }
357
        uc->uc_size = size;
358
        uc->uc_nextvictim = 0;
359
        uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS);
360
        if (uc->uc_entries == NULL) {
361
                CACHE_PERROR("enablecache: could not allocate cache data");
362
                return(0);
363
        }
364
        BZERO(uc->uc_entries, cache_ptr, size * SPARSENESS);
365
        uc->uc_fifo = ALLOC(cache_ptr, size);
366
        if (uc->uc_fifo == NULL) {
367
                CACHE_PERROR("enablecache: could not allocate cache fifo");
368
                return(0);
369
        }
370
        BZERO(uc->uc_fifo, cache_ptr, size);
371
        su->su_cache = (char *) uc;
372
        return(1);
373
}
374
 
375
 
376
/*
377
 * Set an entry in the cache
378
 */
379
static void
380
cache_set(xprt, replylen)
381
        SVCXPRT *xprt;
382
        u_long replylen;
383
{
384
        register cache_ptr victim;
385
        register cache_ptr *vicp;
386
        register struct svcudp_data *su = su_data(xprt);
387
        struct udp_cache *uc = (struct udp_cache *) su->su_cache;
388
        u_int loc;
389
        char *newbuf;
390
 
391
        /*
392
         * Find space for the new entry, either by
393
         * reusing an old entry, or by mallocing a new one
394
         */
395
        victim = uc->uc_fifo[uc->uc_nextvictim];
396
        if (victim != NULL) {
397
                loc = CACHE_LOC(xprt, victim->cache_xid);
398
                for (vicp = &uc->uc_entries[loc];
399
                  *vicp != NULL && *vicp != victim;
400
                  vicp = &(*vicp)->cache_next)
401
                                ;
402
                if (*vicp == NULL) {
403
                        CACHE_PERROR("cache_set: victim not found");
404
                        return;
405
                }
406
                *vicp = victim->cache_next;     /* remote from cache */
407
                newbuf = victim->cache_reply;
408
        } else {
409
                victim = ALLOC(struct cache_node, 1);
410
                if (victim == NULL) {
411
                        CACHE_PERROR("cache_set: victim alloc failed");
412
                        return;
413
                }
414
                newbuf = mem_alloc(su->su_iosz);
415
                if (newbuf == NULL) {
416
                        CACHE_PERROR("cache_set: could not allocate new rpc_buffer");
417
                        return;
418
                }
419
        }
420
 
421
        /*
422
         * Store it away
423
         */
424
        victim->cache_replylen = replylen;
425
        victim->cache_reply = rpc_buffer(xprt);
426
        rpc_buffer(xprt) = newbuf;
427
        xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz, XDR_ENCODE);
428
        victim->cache_xid = su->su_xid;
429
        victim->cache_proc = uc->uc_proc;
430
        victim->cache_vers = uc->uc_vers;
431
        victim->cache_prog = uc->uc_prog;
432
        victim->cache_addr = uc->uc_addr;
433
        loc = CACHE_LOC(xprt, victim->cache_xid);
434
        victim->cache_next = uc->uc_entries[loc];
435
        uc->uc_entries[loc] = victim;
436
        uc->uc_fifo[uc->uc_nextvictim++] = victim;
437
        uc->uc_nextvictim %= uc->uc_size;
438
}
439
 
440
/*
441
 * Try to get an entry from the cache
442
 * return 1 if found, 0 if not found
443
 */
444
static int
445
cache_get(xprt, msg, replyp, replylenp)
446
        SVCXPRT *xprt;
447
        struct rpc_msg *msg;
448
        char **replyp;
449
        u_long *replylenp;
450
{
451
        u_int loc;
452
        register cache_ptr ent;
453
        register struct svcudp_data *su = su_data(xprt);
454
        register struct udp_cache *uc = (struct udp_cache *) su->su_cache;
455
 
456
#       define EQADDR(a1, a2)   (memcmp(&a1, &a2, sizeof(a1)) == 0)
457
 
458
        loc = CACHE_LOC(xprt, su->su_xid);
459
        for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) {
460
                if (ent->cache_xid == su->su_xid &&
461
                  ent->cache_proc == uc->uc_proc &&
462
                  ent->cache_vers == uc->uc_vers &&
463
                  ent->cache_prog == uc->uc_prog &&
464
                  EQADDR(ent->cache_addr, uc->uc_addr)) {
465
                        *replyp = ent->cache_reply;
466
                        *replylenp = ent->cache_replylen;
467
                        return(1);
468
                }
469
        }
470
        /*
471
         * Failed to find entry
472
         * Remember a few things so we can do a set later
473
         */
474
        uc->uc_proc = msg->rm_call.cb_proc;
475
        uc->uc_vers = msg->rm_call.cb_vers;
476
        uc->uc_prog = msg->rm_call.cb_prog;
477
        uc->uc_addr = xprt->xp_raddr;
478
        return(0);
479
}
480
 

powered by: WebSVN 2.1.0

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