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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [uClibc/] [libc/] [inet/] [rpc/] [svc_udp.c] - Blame information for rev 1325

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

Line No. Rev Author Line
1 1325 phoenix
/* @(#)svc_udp.c        2.2 88/07/29 4.0 RPCSRC */
2
/*
3
 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
4
 * unrestricted use provided that this legend is included on all tape
5
 * media and as a part of the software program in whole or part.  Users
6
 * may copy or modify Sun RPC without charge, but are not authorized
7
 * to license or distribute it to anyone else except as part of a product or
8
 * program developed by the user.
9
 *
10
 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
11
 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
12
 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
13
 *
14
 * Sun RPC is provided with no support and without any obligation on the
15
 * part of Sun Microsystems, Inc. to assist in its use, correction,
16
 * modification or enhancement.
17
 *
18
 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
19
 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
20
 * OR ANY PART THEREOF.
21
 *
22
 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
23
 * or profits or other special, indirect and consequential damages, even if
24
 * Sun has been advised of the possibility of such damages.
25
 *
26
 * Sun Microsystems, Inc.
27
 * 2550 Garcia Avenue
28
 * Mountain View, California  94043
29
 */
30
#if 0
31
static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro";
32
#endif
33
 
34
/*
35
 * svc_udp.c,
36
 * Server side for UDP/IP based RPC.  (Does some caching in the hopes of
37
 * achieving execute-at-most-once semantics.)
38
 *
39
 * Copyright (C) 1984, Sun Microsystems, Inc.
40
 */
41
 
42
#define __FORCE_GLIBC
43
#define _GNU_SOURCE
44
#include <features.h>
45
 
46
#include <stdio.h>
47
#include <unistd.h>
48
#include <string.h>
49
#include <rpc/rpc.h>
50
#include <sys/socket.h>
51
#include <errno.h>
52
 
53
#ifdef IP_PKTINFO
54
#include <sys/uio.h>
55
#endif
56
 
57
#ifdef USE_IN_LIBIO
58
# include <wchar.h>
59
# include <libio/iolibio.h>
60
# define fputs(s, f) _IO_fputs (s, f)
61
#endif
62
 
63
#define rpc_buffer(xprt) ((xprt)->xp_p1)
64
#ifndef MAX
65
#define MAX(a, b)     ((a > b) ? a : b)
66
#endif
67
 
68
static bool_t svcudp_recv (SVCXPRT *, struct rpc_msg *);
69
static bool_t svcudp_reply (SVCXPRT *, struct rpc_msg *);
70
static enum xprt_stat svcudp_stat (SVCXPRT *);
71
static bool_t svcudp_getargs (SVCXPRT *, xdrproc_t, caddr_t);
72
static bool_t svcudp_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
73
static void svcudp_destroy (SVCXPRT *);
74
 
75
static const struct xp_ops svcudp_op =
76
{
77
  svcudp_recv,
78
  svcudp_stat,
79
  svcudp_getargs,
80
  svcudp_reply,
81
  svcudp_freeargs,
82
  svcudp_destroy
83
};
84
 
85
static int cache_get (SVCXPRT *, struct rpc_msg *, char **replyp,
86
                      u_long *replylenp);
87
static void cache_set (SVCXPRT *xprt, u_long replylen);
88
 
89
/*
90
 * kept in xprt->xp_p2
91
 */
92
struct svcudp_data
93
  {
94
    u_int su_iosz;              /* byte size of send.recv buffer */
95
    u_long su_xid;              /* transaction id */
96
    XDR su_xdrs;                /* XDR handle */
97
    char su_verfbody[MAX_AUTH_BYTES];   /* verifier body */
98
    char *su_cache;             /* cached data, NULL if no cache */
99
  };
100
#define su_data(xprt)   ((struct svcudp_data *)(xprt->xp_p2))
101
 
102
/*
103
 * Usage:
104
 *      xprt = svcudp_create(sock);
105
 *
106
 * If sock<0 then a socket is created, else sock is used.
107
 * If the socket, sock is not bound to a port then svcudp_create
108
 * binds it to an arbitrary port.  In any (successful) case,
109
 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
110
 * associated port number.
111
 * Once *xprt is initialized, it is registered as a transporter;
112
 * see (svc.h, xprt_register).
113
 * The routines returns NULL if a problem occurred.
114
 */
115
SVCXPRT *
116
svcudp_bufcreate (sock, sendsz, recvsz)
117
     int sock;
118
     u_int sendsz, recvsz;
119
{
120
  bool_t madesock = FALSE;
121
  SVCXPRT *xprt;
122
  struct svcudp_data *su;
123
  struct sockaddr_in addr;
124
  socklen_t len = sizeof (struct sockaddr_in);
125
  int pad;
126
  void *buf;
127
 
128
  if (sock == RPC_ANYSOCK)
129
    {
130
      if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
131
        {
132
          perror (_("svcudp_create: socket creation problem"));
133
          return (SVCXPRT *) NULL;
134
        }
135
      madesock = TRUE;
136
    }
137
  bzero ((char *) &addr, sizeof (addr));
138
  addr.sin_family = AF_INET;
139
  if (bindresvport (sock, &addr))
140
    {
141
      addr.sin_port = 0;
142
      (void) bind (sock, (struct sockaddr *) &addr, len);
143
    }
144
  if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0)
145
    {
146
      perror (_("svcudp_create - cannot getsockname"));
147
      if (madesock)
148
        (void) close (sock);
149
      return (SVCXPRT *) NULL;
150
    }
151
  xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
152
  su = (struct svcudp_data *) mem_alloc (sizeof (*su));
153
  buf = mem_alloc (((MAX (sendsz, recvsz) + 3) / 4) * 4);
154
  if (xprt == NULL || su == NULL || buf == NULL)
155
    {
156
#ifdef USE_IN_LIBIO
157
      if (_IO_fwide (stderr, 0) > 0)
158
        (void) __fwprintf (stderr, L"%s", _("svcudp_create: out of memory\n"));
159
      else
160
#endif
161
        (void) fputs (_("svcudp_create: out of memory\n"), stderr);
162
      mem_free (xprt, sizeof (SVCXPRT));
163
      mem_free (su, sizeof (*su));
164
      mem_free (buf, ((MAX (sendsz, recvsz) + 3) / 4) * 4);
165
      return NULL;
166
    }
167
  su->su_iosz = ((MAX (sendsz, recvsz) + 3) / 4) * 4;
168
  rpc_buffer (xprt) = buf;
169
  xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_DECODE);
170
  su->su_cache = NULL;
171
  xprt->xp_p2 = (caddr_t) su;
172
  xprt->xp_verf.oa_base = su->su_verfbody;
173
  xprt->xp_ops = &svcudp_op;
174
  xprt->xp_port = ntohs (addr.sin_port);
175
  xprt->xp_sock = sock;
176
 
177
#ifdef IP_PKTINFO
178
  if ((sizeof (struct iovec) + sizeof (struct msghdr)
179
       + sizeof(struct cmsghdr) + sizeof (struct in_pktinfo))
180
      > sizeof (xprt->xp_pad))
181
    {
182
# ifdef USE_IN_LIBIO
183
      if (_IO_fwide (stderr, 0) > 0)
184
        (void) __fwprintf (stderr, L"%s",
185
                           _("svcudp_create: xp_pad is too small for IP_PKTINFO\n"));
186
      else
187
# endif
188
        (void) fputs (_("svcudp_create: xp_pad is too small for IP_PKTINFO\n"),
189
                      stderr);
190
      return NULL;
191
    }
192
  pad = 1;
193
  if (setsockopt (sock, SOL_IP, IP_PKTINFO, (void *) &pad,
194
                  sizeof (pad)) == 0)
195
    /* Set the padding to all 1s. */
196
    pad = 0xff;
197
  else
198
#endif
199
    /* Clear the padding. */
200
    pad = 0;
201
  memset (&xprt->xp_pad [0], pad, sizeof (xprt->xp_pad));
202
 
203
  xprt_register (xprt);
204
  return xprt;
205
}
206
 
207
SVCXPRT *
208
svcudp_create (sock)
209
     int sock;
210
{
211
 
212
  return svcudp_bufcreate (sock, UDPMSGSIZE, UDPMSGSIZE);
213
}
214
 
215
static enum xprt_stat
216
svcudp_stat (xprt)
217
     SVCXPRT *xprt;
218
{
219
 
220
  return XPRT_IDLE;
221
}
222
 
223
static bool_t
224
svcudp_recv (xprt, msg)
225
     SVCXPRT *xprt;
226
     struct rpc_msg *msg;
227
{
228
  struct svcudp_data *su = su_data (xprt);
229
  XDR *xdrs = &(su->su_xdrs);
230
  int rlen;
231
  char *reply;
232
  u_long replylen;
233
  socklen_t len;
234
 
235
  /* It is very tricky when you have IP aliases. We want to make sure
236
     that we are sending the packet from the IP address where the
237
     incoming packet is addressed to. H.J. */
238
#ifdef IP_PKTINFO
239
  struct iovec *iovp;
240
  struct msghdr *mesgp;
241
#endif
242
 
243
again:
244
  /* FIXME -- should xp_addrlen be a size_t?  */
245
  len = (socklen_t) sizeof(struct sockaddr_in);
246
#ifdef IP_PKTINFO
247
  iovp = (struct iovec *) &xprt->xp_pad [0];
248
  mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
249
  if (mesgp->msg_iovlen)
250
    {
251
      iovp->iov_base = rpc_buffer (xprt);
252
      iovp->iov_len = su->su_iosz;
253
      mesgp->msg_iov = iovp;
254
      mesgp->msg_iovlen = 1;
255
      mesgp->msg_name = &(xprt->xp_raddr);
256
      mesgp->msg_namelen = len;
257
      mesgp->msg_control = &xprt->xp_pad [sizeof (struct iovec)
258
                                          + sizeof (struct msghdr)];
259
      mesgp->msg_controllen = sizeof(xprt->xp_pad)
260
                              - sizeof (struct iovec) - sizeof (struct msghdr);
261
      rlen = recvmsg (xprt->xp_sock, mesgp, 0);
262
      if (rlen >= 0)
263
        len = mesgp->msg_namelen;
264
    }
265
  else
266
#endif
267
    rlen = recvfrom (xprt->xp_sock, rpc_buffer (xprt),
268
                     (int) su->su_iosz, 0,
269
                     (struct sockaddr *) &(xprt->xp_raddr), &len);
270
  xprt->xp_addrlen = len;
271
  if (rlen == -1 && errno == EINTR)
272
    goto again;
273
  if (rlen < 16)                /* < 4 32-bit ints? */
274
    return FALSE;
275
  xdrs->x_op = XDR_DECODE;
276
  XDR_SETPOS (xdrs, 0);
277
  if (!xdr_callmsg (xdrs, msg))
278
    return FALSE;
279
  su->su_xid = msg->rm_xid;
280
  if (su->su_cache != NULL)
281
    {
282
      if (cache_get (xprt, msg, &reply, &replylen))
283
        {
284
#ifdef IP_PKTINFO
285
          if (mesgp->msg_iovlen)
286
            {
287
              iovp->iov_base = reply;
288
              iovp->iov_len = replylen;
289
              (void) sendmsg (xprt->xp_sock, mesgp, 0);
290
            }
291
          else
292
#endif
293
            (void) sendto (xprt->xp_sock, reply, (int) replylen, 0,
294
                           (struct sockaddr *) &xprt->xp_raddr, len);
295
          return TRUE;
296
        }
297
    }
298
  return TRUE;
299
}
300
 
301
static bool_t
302
svcudp_reply (xprt, msg)
303
     SVCXPRT *xprt;
304
     struct rpc_msg *msg;
305
{
306
  struct svcudp_data *su = su_data (xprt);
307
  XDR *xdrs = &(su->su_xdrs);
308
  int slen, sent;
309
  bool_t stat = FALSE;
310
#ifdef IP_PKTINFO
311
  struct iovec *iovp;
312
  struct msghdr *mesgp;
313
#endif
314
 
315
  xdrs->x_op = XDR_ENCODE;
316
  XDR_SETPOS (xdrs, 0);
317
  msg->rm_xid = su->su_xid;
318
  if (xdr_replymsg (xdrs, msg))
319
    {
320
      slen = (int) XDR_GETPOS (xdrs);
321
#ifdef IP_PKTINFO
322
      mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
323
      if (mesgp->msg_iovlen)
324
        {
325
          iovp = (struct iovec *) &xprt->xp_pad [0];
326
          iovp->iov_base = rpc_buffer (xprt);
327
          iovp->iov_len = slen;
328
          sent = sendmsg (xprt->xp_sock, mesgp, 0);
329
        }
330
      else
331
#endif
332
        sent = sendto (xprt->xp_sock, rpc_buffer (xprt), slen, 0,
333
                       (struct sockaddr *) &(xprt->xp_raddr),
334
                       xprt->xp_addrlen);
335
      if (sent == slen)
336
        {
337
          stat = TRUE;
338
          if (su->su_cache && slen >= 0)
339
            {
340
              cache_set (xprt, (u_long) slen);
341
            }
342
        }
343
    }
344
  return stat;
345
}
346
 
347
static bool_t
348
svcudp_getargs (xprt, xdr_args, args_ptr)
349
     SVCXPRT *xprt;
350
     xdrproc_t xdr_args;
351
     caddr_t args_ptr;
352
{
353
 
354
  return (*xdr_args) (&(su_data (xprt)->su_xdrs), args_ptr);
355
}
356
 
357
static bool_t
358
svcudp_freeargs (xprt, xdr_args, args_ptr)
359
     SVCXPRT *xprt;
360
     xdrproc_t xdr_args;
361
     caddr_t args_ptr;
362
{
363
  XDR *xdrs = &(su_data (xprt)->su_xdrs);
364
 
365
  xdrs->x_op = XDR_FREE;
366
  return (*xdr_args) (xdrs, args_ptr);
367
}
368
 
369
static void
370
svcudp_destroy (xprt)
371
     SVCXPRT *xprt;
372
{
373
  struct svcudp_data *su = su_data (xprt);
374
 
375
  xprt_unregister (xprt);
376
  (void) close (xprt->xp_sock);
377
  XDR_DESTROY (&(su->su_xdrs));
378
  mem_free (rpc_buffer (xprt), su->su_iosz);
379
  mem_free ((caddr_t) su, sizeof (struct svcudp_data));
380
  mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
381
}
382
 
383
 
384
/***********this could be a separate file*********************/
385
 
386
/*
387
 * Fifo cache for udp server
388
 * Copies pointers to reply buffers into fifo cache
389
 * Buffers are sent again if retransmissions are detected.
390
 */
391
 
392
#define SPARSENESS 4            /* 75% sparse */
393
 
394
#ifdef USE_IN_LIBIO
395
# define CACHE_PERROR(msg)      \
396
        if (_IO_fwide (stderr, 0) > 0)                                          \
397
                (void) __fwprintf(stderr, L"%s\n", msg);                      \
398
        else                                                                  \
399
                (void) fprintf(stderr, "%s\n", msg)
400
#else
401
# define CACHE_PERROR(msg)      \
402
        (void) fprintf(stderr,"%s\n", msg)
403
#endif
404
 
405
#define ALLOC(type, size)       \
406
        (type *) mem_alloc((unsigned) (sizeof(type) * (size)))
407
 
408
#define BZERO(addr, type, size)  \
409
        bzero((char *) addr, sizeof(type) * (int) (size))
410
 
411
/*
412
 * An entry in the cache
413
 */
414
typedef struct cache_node *cache_ptr;
415
struct cache_node
416
  {
417
    /*
418
     * Index into cache is xid, proc, vers, prog and address
419
     */
420
    u_long cache_xid;
421
    u_long cache_proc;
422
    u_long cache_vers;
423
    u_long cache_prog;
424
    struct sockaddr_in cache_addr;
425
    /*
426
     * The cached reply and length
427
     */
428
    char *cache_reply;
429
    u_long cache_replylen;
430
    /*
431
     * Next node on the list, if there is a collision
432
     */
433
    cache_ptr cache_next;
434
  };
435
 
436
 
437
 
438
/*
439
 * The entire cache
440
 */
441
struct udp_cache
442
  {
443
    u_long uc_size;             /* size of cache */
444
    cache_ptr *uc_entries;      /* hash table of entries in cache */
445
    cache_ptr *uc_fifo;         /* fifo list of entries in cache */
446
    u_long uc_nextvictim;       /* points to next victim in fifo list */
447
    u_long uc_prog;             /* saved program number */
448
    u_long uc_vers;             /* saved version number */
449
    u_long uc_proc;             /* saved procedure number */
450
    struct sockaddr_in uc_addr; /* saved caller's address */
451
  };
452
 
453
 
454
/*
455
 * the hashing function
456
 */
457
#define CACHE_LOC(transp, xid)  \
458
 (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size))
459
 
460
 
461
/*
462
 * Enable use of the cache.
463
 * Note: there is no disable.
464
 */
465
int
466
svcudp_enablecache (SVCXPRT *transp, u_long size)
467
{
468
  struct svcudp_data *su = su_data (transp);
469
  struct udp_cache *uc;
470
 
471
  if (su->su_cache != NULL)
472
    {
473
      CACHE_PERROR (_("enablecache: cache already enabled"));
474
      return 0;
475
    }
476
  uc = ALLOC (struct udp_cache, 1);
477
  if (uc == NULL)
478
    {
479
      CACHE_PERROR (_("enablecache: could not allocate cache"));
480
      return 0;
481
    }
482
  uc->uc_size = size;
483
  uc->uc_nextvictim = 0;
484
  uc->uc_entries = ALLOC (cache_ptr, size * SPARSENESS);
485
  if (uc->uc_entries == NULL)
486
    {
487
      CACHE_PERROR (_("enablecache: could not allocate cache data"));
488
      return 0;
489
    }
490
  BZERO (uc->uc_entries, cache_ptr, size * SPARSENESS);
491
  uc->uc_fifo = ALLOC (cache_ptr, size);
492
  if (uc->uc_fifo == NULL)
493
    {
494
      CACHE_PERROR (_("enablecache: could not allocate cache fifo"));
495
      return 0;
496
    }
497
  BZERO (uc->uc_fifo, cache_ptr, size);
498
  su->su_cache = (char *) uc;
499
  return 1;
500
}
501
 
502
 
503
/*
504
 * Set an entry in the cache
505
 */
506
static void
507
cache_set (SVCXPRT *xprt, u_long replylen)
508
{
509
  cache_ptr victim;
510
  cache_ptr *vicp;
511
  struct svcudp_data *su = su_data (xprt);
512
  struct udp_cache *uc = (struct udp_cache *) su->su_cache;
513
  u_int loc;
514
  char *newbuf;
515
 
516
  /*
517
   * Find space for the new entry, either by
518
   * reusing an old entry, or by mallocing a new one
519
   */
520
  victim = uc->uc_fifo[uc->uc_nextvictim];
521
  if (victim != NULL)
522
    {
523
      loc = CACHE_LOC (xprt, victim->cache_xid);
524
      for (vicp = &uc->uc_entries[loc];
525
           *vicp != NULL && *vicp != victim;
526
           vicp = &(*vicp)->cache_next)
527
        ;
528
      if (*vicp == NULL)
529
        {
530
          CACHE_PERROR (_("cache_set: victim not found"));
531
          return;
532
        }
533
      *vicp = victim->cache_next;       /* remote from cache */
534
      newbuf = victim->cache_reply;
535
    }
536
  else
537
    {
538
      victim = ALLOC (struct cache_node, 1);
539
      if (victim == NULL)
540
        {
541
          CACHE_PERROR (_("cache_set: victim alloc failed"));
542
          return;
543
        }
544
      newbuf = mem_alloc (su->su_iosz);
545
      if (newbuf == NULL)
546
        {
547
          CACHE_PERROR (_("cache_set: could not allocate new rpc_buffer"));
548
          return;
549
        }
550
    }
551
 
552
  /*
553
   * Store it away
554
   */
555
  victim->cache_replylen = replylen;
556
  victim->cache_reply = rpc_buffer (xprt);
557
  rpc_buffer (xprt) = newbuf;
558
  xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_ENCODE);
559
  victim->cache_xid = su->su_xid;
560
  victim->cache_proc = uc->uc_proc;
561
  victim->cache_vers = uc->uc_vers;
562
  victim->cache_prog = uc->uc_prog;
563
  victim->cache_addr = uc->uc_addr;
564
  loc = CACHE_LOC (xprt, victim->cache_xid);
565
  victim->cache_next = uc->uc_entries[loc];
566
  uc->uc_entries[loc] = victim;
567
  uc->uc_fifo[uc->uc_nextvictim++] = victim;
568
  uc->uc_nextvictim %= uc->uc_size;
569
}
570
 
571
/*
572
 * Try to get an entry from the cache
573
 * return 1 if found, 0 if not found
574
 */
575
static int
576
cache_get (xprt, msg, replyp, replylenp)
577
     SVCXPRT *xprt;
578
     struct rpc_msg *msg;
579
     char **replyp;
580
     u_long *replylenp;
581
{
582
  u_int loc;
583
  cache_ptr ent;
584
  struct svcudp_data *su = su_data (xprt);
585
  struct udp_cache *uc = (struct udp_cache *) su->su_cache;
586
 
587
#define EQADDR(a1, a2)  (memcmp((char*)&a1, (char*)&a2, sizeof(a1)) == 0)
588
 
589
  loc = CACHE_LOC (xprt, su->su_xid);
590
  for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next)
591
    {
592
      if (ent->cache_xid == su->su_xid &&
593
          ent->cache_proc == uc->uc_proc &&
594
          ent->cache_vers == uc->uc_vers &&
595
          ent->cache_prog == uc->uc_prog &&
596
          EQADDR (ent->cache_addr, uc->uc_addr))
597
        {
598
          *replyp = ent->cache_reply;
599
          *replylenp = ent->cache_replylen;
600
          return 1;
601
        }
602
    }
603
  /*
604
   * Failed to find entry
605
   * Remember a few things so we can do a set later
606
   */
607
  uc->uc_proc = msg->rm_call.cb_proc;
608
  uc->uc_vers = msg->rm_call.cb_vers;
609
  uc->uc_prog = msg->rm_call.cb_prog;
610
  memcpy (&uc->uc_addr, &xprt->xp_raddr, sizeof (uc->uc_addr));
611
  return 0;
612
}

powered by: WebSVN 2.1.0

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