1 /* @(#)svc_udp.c 2.2 88/07/29 4.0 RPCSRC */
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.
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.
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.
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.
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.
26 * Sun Microsystems, Inc.
28 * Mountain View, California 94043
31 static char sccsid[] = "@(#)svc_udp.c 1.24 87/08/11 Copyr 1984 Sun Micro";
36 * Server side for UDP/IP based RPC. (Does some caching in the hopes of
37 * achieving execute-at-most-once semantics.)
39 * Copyright (C) 1984, Sun Microsystems, Inc.
45 #include "rpc_private.h"
46 #include <sys/socket.h>
53 #define rpc_buffer(xprt) ((xprt)->xp_p1)
55 #define MAX(a, b) ((a > b) ? a : b)
58 static bool_t svcudp_recv (SVCXPRT *, struct rpc_msg *);
59 static bool_t svcudp_reply (SVCXPRT *, struct rpc_msg *);
60 static enum xprt_stat svcudp_stat (SVCXPRT *);
61 static bool_t svcudp_getargs (SVCXPRT *, xdrproc_t, caddr_t);
62 static bool_t svcudp_freeargs (SVCXPRT *, xdrproc_t, caddr_t);
63 static void svcudp_destroy (SVCXPRT *);
65 static const struct xp_ops svcudp_op =
75 static int cache_get (SVCXPRT *, struct rpc_msg *, char **replyp,
77 static void cache_set (SVCXPRT *xprt, u_long replylen);
84 u_int su_iosz; /* byte size of send.recv buffer */
85 u_long su_xid; /* transaction id */
86 XDR su_xdrs; /* XDR handle */
87 char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */
88 char *su_cache; /* cached data, NULL if no cache */
90 #define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2))
94 * xprt = svcudp_create(sock);
96 * If sock<0 then a socket is created, else sock is used.
97 * If the socket, sock is not bound to a port then svcudp_create
98 * binds it to an arbitrary port. In any (successful) case,
99 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
100 * associated port number.
101 * Once *xprt is initialized, it is registered as a transporter;
102 * see (svc.h, xprt_register).
103 * The routines returns NULL if a problem occurred.
106 svcudp_bufcreate (int sock, u_int sendsz, u_int recvsz)
108 bool_t madesock = FALSE;
110 struct svcudp_data *su;
111 struct sockaddr_in addr;
112 socklen_t len = sizeof (struct sockaddr_in);
116 if (sock == RPC_ANYSOCK)
118 if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
120 perror (_("svcudp_create: socket creation problem"));
121 return (SVCXPRT *) NULL;
125 memset ((char *) &addr, 0, sizeof (addr));
126 addr.sin_family = AF_INET;
127 if (bindresvport (sock, &addr))
130 (void) bind (sock, (struct sockaddr *) &addr, len);
132 if (getsockname (sock, (struct sockaddr *) &addr, &len) != 0)
134 perror (_("svcudp_create - cannot getsockname"));
137 return (SVCXPRT *) NULL;
139 xprt = (SVCXPRT *) mem_alloc (sizeof (SVCXPRT));
140 su = (struct svcudp_data *) mem_alloc (sizeof (*su));
141 buf = mem_alloc (((MAX (sendsz, recvsz) + 3) / 4) * 4);
142 if (xprt == NULL || su == NULL || buf == NULL)
144 (void) fputs (_("svcudp_create: out of memory\n"), stderr);
145 mem_free (xprt, sizeof (SVCXPRT));
146 mem_free (su, sizeof (*su));
147 mem_free (buf, ((MAX (sendsz, recvsz) + 3) / 4) * 4);
150 su->su_iosz = ((MAX (sendsz, recvsz) + 3) / 4) * 4;
151 rpc_buffer (xprt) = buf;
152 xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_DECODE);
154 xprt->xp_p2 = (caddr_t) su;
155 xprt->xp_verf.oa_base = su->su_verfbody;
156 xprt->xp_ops = &svcudp_op;
157 xprt->xp_port = ntohs (addr.sin_port);
158 xprt->xp_sock = sock;
161 if ((sizeof (struct iovec) + sizeof (struct msghdr)
162 + sizeof(struct cmsghdr) + sizeof (struct in_pktinfo))
163 > sizeof (xprt->xp_pad))
165 (void) fputs (_("svcudp_create: xp_pad is too small for IP_PKTINFO\n"),
170 if (setsockopt (sock, SOL_IP, IP_PKTINFO, (void *) &pad,
172 /* Set the padding to all 1s. */
176 /* Clear the padding. */
178 memset (&xprt->xp_pad [0], pad, sizeof (xprt->xp_pad));
180 xprt_register (xprt);
183 libc_hidden_def(svcudp_bufcreate)
186 svcudp_create (int sock)
189 return svcudp_bufcreate (sock, UDPMSGSIZE, UDPMSGSIZE);
191 libc_hidden_def(svcudp_create)
193 static enum xprt_stat
194 svcudp_stat (SVCXPRT *xprt attribute_unused)
201 svcudp_recv (SVCXPRT *xprt, struct rpc_msg *msg)
203 struct svcudp_data *su = su_data (xprt);
204 XDR *xdrs = &(su->su_xdrs);
210 /* It is very tricky when you have IP aliases. We want to make sure
211 that we are sending the packet from the IP address where the
212 incoming packet is addressed to. H.J. */
215 struct msghdr *mesgp;
219 /* FIXME -- should xp_addrlen be a size_t? */
220 len = (socklen_t) sizeof(struct sockaddr_in);
222 iovp = (struct iovec *) &xprt->xp_pad [0];
223 mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
224 if (mesgp->msg_iovlen)
226 iovp->iov_base = rpc_buffer (xprt);
227 iovp->iov_len = su->su_iosz;
228 mesgp->msg_iov = iovp;
229 mesgp->msg_iovlen = 1;
230 mesgp->msg_name = &(xprt->xp_raddr);
231 mesgp->msg_namelen = len;
232 mesgp->msg_control = &xprt->xp_pad [sizeof (struct iovec)
233 + sizeof (struct msghdr)];
234 mesgp->msg_controllen = sizeof(xprt->xp_pad)
235 - sizeof (struct iovec) - sizeof (struct msghdr);
236 rlen = recvmsg (xprt->xp_sock, mesgp, 0);
238 len = mesgp->msg_namelen;
242 rlen = recvfrom (xprt->xp_sock, rpc_buffer (xprt),
243 (int) su->su_iosz, 0,
244 (struct sockaddr *) &(xprt->xp_raddr), &len);
245 xprt->xp_addrlen = len;
246 if (rlen == -1 && errno == EINTR)
248 if (rlen < 16) /* < 4 32-bit ints? */
250 xdrs->x_op = XDR_DECODE;
251 XDR_SETPOS (xdrs, 0);
252 if (!xdr_callmsg (xdrs, msg))
254 su->su_xid = msg->rm_xid;
255 if (su->su_cache != NULL)
257 if (cache_get (xprt, msg, &reply, &replylen))
260 if (mesgp->msg_iovlen)
262 iovp->iov_base = reply;
263 iovp->iov_len = replylen;
264 (void) sendmsg (xprt->xp_sock, mesgp, 0);
268 (void) sendto (xprt->xp_sock, reply, (int) replylen, 0,
269 (struct sockaddr *) &xprt->xp_raddr, len);
277 svcudp_reply (SVCXPRT *xprt, struct rpc_msg *msg)
279 struct svcudp_data *su = su_data (xprt);
280 XDR *xdrs = &(su->su_xdrs);
285 struct msghdr *mesgp;
288 xdrs->x_op = XDR_ENCODE;
289 XDR_SETPOS (xdrs, 0);
290 msg->rm_xid = su->su_xid;
291 if (xdr_replymsg (xdrs, msg))
293 slen = (int) XDR_GETPOS (xdrs);
295 mesgp = (struct msghdr *) &xprt->xp_pad [sizeof (struct iovec)];
296 if (mesgp->msg_iovlen)
298 iovp = (struct iovec *) &xprt->xp_pad [0];
299 iovp->iov_base = rpc_buffer (xprt);
300 iovp->iov_len = slen;
301 sent = sendmsg (xprt->xp_sock, mesgp, 0);
305 sent = sendto (xprt->xp_sock, rpc_buffer (xprt), slen, 0,
306 (struct sockaddr *) &(xprt->xp_raddr),
311 if (su->su_cache && slen >= 0)
313 cache_set (xprt, (u_long) slen);
321 svcudp_getargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
324 return (*xdr_args) (&(su_data (xprt)->su_xdrs), args_ptr);
328 svcudp_freeargs (SVCXPRT *xprt, xdrproc_t xdr_args, caddr_t args_ptr)
330 XDR *xdrs = &(su_data (xprt)->su_xdrs);
332 xdrs->x_op = XDR_FREE;
333 return (*xdr_args) (xdrs, args_ptr);
337 svcudp_destroy (SVCXPRT *xprt)
339 struct svcudp_data *su = su_data (xprt);
341 xprt_unregister (xprt);
342 (void) close (xprt->xp_sock);
343 XDR_DESTROY (&(su->su_xdrs));
344 mem_free (rpc_buffer (xprt), su->su_iosz);
345 mem_free ((caddr_t) su, sizeof (struct svcudp_data));
346 mem_free ((caddr_t) xprt, sizeof (SVCXPRT));
350 /***********this could be a separate file*********************/
353 * Fifo cache for udp server
354 * Copies pointers to reply buffers into fifo cache
355 * Buffers are sent again if retransmissions are detected.
358 #define SPARSENESS 4 /* 75% sparse */
360 #define CACHE_PERROR(msg) \
361 (void) fprintf(stderr,"%s\n", msg)
363 #define ALLOC(type, size) \
364 (type *) mem_alloc((unsigned) (sizeof(type) * (size)))
366 #define BZERO(addr, type, size) \
367 memset((char *) addr, 0, sizeof(type) * (int) (size))
370 * An entry in the cache
372 typedef struct cache_node *cache_ptr;
376 * Index into cache is xid, proc, vers, prog and address
382 struct sockaddr_in cache_addr;
384 * The cached reply and length
387 u_long cache_replylen;
389 * Next node on the list, if there is a collision
391 cache_ptr cache_next;
401 u_long uc_size; /* size of cache */
402 cache_ptr *uc_entries; /* hash table of entries in cache */
403 cache_ptr *uc_fifo; /* fifo list of entries in cache */
404 u_long uc_nextvictim; /* points to next victim in fifo list */
405 u_long uc_prog; /* saved program number */
406 u_long uc_vers; /* saved version number */
407 u_long uc_proc; /* saved procedure number */
408 struct sockaddr_in uc_addr; /* saved caller's address */
413 * the hashing function
415 #define CACHE_LOC(transp, xid) \
416 (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size))
420 * Enable use of the cache.
421 * Note: there is no disable.
423 int svcudp_enablecache (SVCXPRT *transp, u_long size);
425 svcudp_enablecache (SVCXPRT *transp, u_long size)
427 struct svcudp_data *su = su_data (transp);
428 struct udp_cache *uc;
430 if (su->su_cache != NULL)
432 CACHE_PERROR (_("enablecache: cache already enabled"));
435 uc = ALLOC (struct udp_cache, 1);
438 CACHE_PERROR (_("enablecache: could not allocate cache"));
442 uc->uc_nextvictim = 0;
443 uc->uc_entries = ALLOC (cache_ptr, size * SPARSENESS);
444 if (uc->uc_entries == NULL)
446 CACHE_PERROR (_("enablecache: could not allocate cache data"));
449 BZERO (uc->uc_entries, cache_ptr, size * SPARSENESS);
450 uc->uc_fifo = ALLOC (cache_ptr, size);
451 if (uc->uc_fifo == NULL)
453 CACHE_PERROR (_("enablecache: could not allocate cache fifo"));
456 BZERO (uc->uc_fifo, cache_ptr, size);
457 su->su_cache = (char *) uc;
463 * Set an entry in the cache
466 cache_set (SVCXPRT *xprt, u_long replylen)
470 struct svcudp_data *su = su_data (xprt);
471 struct udp_cache *uc = (struct udp_cache *) su->su_cache;
476 * Find space for the new entry, either by
477 * reusing an old entry, or by mallocing a new one
479 victim = uc->uc_fifo[uc->uc_nextvictim];
482 loc = CACHE_LOC (xprt, victim->cache_xid);
483 for (vicp = &uc->uc_entries[loc];
484 *vicp != NULL && *vicp != victim;
485 vicp = &(*vicp)->cache_next)
489 CACHE_PERROR (_("cache_set: victim not found"));
492 *vicp = victim->cache_next; /* remote from cache */
493 newbuf = victim->cache_reply;
497 victim = ALLOC (struct cache_node, 1);
500 CACHE_PERROR (_("cache_set: victim alloc failed"));
503 newbuf = mem_alloc (su->su_iosz);
506 CACHE_PERROR (_("cache_set: could not allocate new rpc_buffer"));
514 victim->cache_replylen = replylen;
515 victim->cache_reply = rpc_buffer (xprt);
516 rpc_buffer (xprt) = newbuf;
517 xdrmem_create (&(su->su_xdrs), rpc_buffer (xprt), su->su_iosz, XDR_ENCODE);
518 victim->cache_xid = su->su_xid;
519 victim->cache_proc = uc->uc_proc;
520 victim->cache_vers = uc->uc_vers;
521 victim->cache_prog = uc->uc_prog;
522 victim->cache_addr = uc->uc_addr;
523 loc = CACHE_LOC (xprt, victim->cache_xid);
524 victim->cache_next = uc->uc_entries[loc];
525 uc->uc_entries[loc] = victim;
526 uc->uc_fifo[uc->uc_nextvictim++] = victim;
527 uc->uc_nextvictim %= uc->uc_size;
531 * Try to get an entry from the cache
532 * return 1 if found, 0 if not found
535 cache_get (SVCXPRT *xprt, struct rpc_msg *msg, char **replyp, u_long *replylenp)
539 struct svcudp_data *su = su_data (xprt);
540 struct udp_cache *uc = (struct udp_cache *) su->su_cache;
542 #define EQADDR(a1, a2) (memcmp((char*)&a1, (char*)&a2, sizeof(a1)) == 0)
544 loc = CACHE_LOC (xprt, su->su_xid);
545 for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next)
547 if (ent->cache_xid == su->su_xid &&
548 ent->cache_proc == uc->uc_proc &&
549 ent->cache_vers == uc->uc_vers &&
550 ent->cache_prog == uc->uc_prog &&
551 EQADDR (ent->cache_addr, uc->uc_addr))
553 *replyp = ent->cache_reply;
554 *replylenp = ent->cache_replylen;
559 * Failed to find entry
560 * Remember a few things so we can do a set later
562 uc->uc_proc = msg->rm_call.cb_proc;
563 uc->uc_vers = msg->rm_call.cb_vers;
564 uc->uc_prog = msg->rm_call.cb_prog;
565 memcpy (&uc->uc_addr, &xprt->xp_raddr, sizeof (uc->uc_addr));