3 * Server side for UDP/IP based RPC. (Does some caching in the hopes of
4 * achieving execute-at-most-once semantics.)
6 * Copyright (C) 2012-2016 Free Software Foundation, Inc.
7 * This file is part of the GNU C Library.
9 * The GNU C Library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * The GNU C Library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with the GNU C Library; if not, see
21 * <http://www.gnu.org/licenses/>.
23 * Copyright (c) 2010, Oracle America, Inc.
25 * Redistribution and use in source and binary forms, with or without
26 * modification, are permitted provided that the following conditions are
29 * * Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * * Redistributions in binary form must reproduce the above
32 * copyright notice, this list of conditions and the following
33 * disclaimer in the documentation and/or other materials
34 * provided with the distribution.
35 * * Neither the name of the "Oracle America, Inc." nor the names of its
36 * contributors may be used to endorse or promote products derived
37 * from this software without specific prior written permission.
39 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
40 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
41 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
42 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
43 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
44 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
46 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
47 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
48 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
49 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 #include <sys/socket.h>
66 #include <libio/iolibio.h>
68 #define rpc_buffer(xprt) ((xprt)->xp_p1)
70 #define MAX(a, b) ((a > b) ? a : b)
73 static bool_t
svcudp_recv (SVCXPRT
*, struct rpc_msg
*);
74 static bool_t
svcudp_reply (SVCXPRT
*, struct rpc_msg
*);
75 static enum xprt_stat
svcudp_stat (SVCXPRT
*);
76 static bool_t
svcudp_getargs (SVCXPRT
*, xdrproc_t
, caddr_t
);
77 static bool_t
svcudp_freeargs (SVCXPRT
*, xdrproc_t
, caddr_t
);
78 static void svcudp_destroy (SVCXPRT
*);
80 static const struct xp_ops svcudp_op
=
90 static int cache_get (SVCXPRT
*, struct rpc_msg
*, char **replyp
,
92 static void cache_set (SVCXPRT
*xprt
, u_long replylen
);
99 u_int su_iosz
; /* byte size of send.recv buffer */
100 u_long su_xid
; /* transaction id */
101 XDR su_xdrs
; /* XDR handle */
102 char su_verfbody
[MAX_AUTH_BYTES
]; /* verifier body */
103 char *su_cache
; /* cached data, NULL if no cache */
105 #define su_data(xprt) ((struct svcudp_data *)(xprt->xp_p2))
109 * xprt = svcudp_create(sock);
111 * If sock<0 then a socket is created, else sock is used.
112 * If the socket, sock is not bound to a port then svcudp_create
113 * binds it to an arbitrary port. In any (successful) case,
114 * xprt->xp_sock is the registered socket number and xprt->xp_port is the
115 * associated port number.
116 * Once *xprt is initialized, it is registered as a transporter;
117 * see (svc.h, xprt_register).
118 * The routines returns NULL if a problem occurred.
121 svcudp_bufcreate (int sock
, u_int sendsz
, u_int recvsz
)
123 bool_t madesock
= FALSE
;
125 struct svcudp_data
*su
;
126 struct sockaddr_in addr
;
127 socklen_t len
= sizeof (struct sockaddr_in
);
131 if (sock
== RPC_ANYSOCK
)
133 if ((sock
= __socket (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) < 0)
135 perror (_("svcudp_create: socket creation problem"));
136 return (SVCXPRT
*) NULL
;
140 __bzero ((char *) &addr
, sizeof (addr
));
141 addr
.sin_family
= AF_INET
;
142 if (bindresvport (sock
, &addr
))
145 (void) __bind (sock
, (struct sockaddr
*) &addr
, len
);
147 if (__getsockname (sock
, (struct sockaddr
*) &addr
, &len
) != 0)
149 perror (_("svcudp_create - cannot getsockname"));
151 (void) __close (sock
);
152 return (SVCXPRT
*) NULL
;
154 xprt
= (SVCXPRT
*) mem_alloc (sizeof (SVCXPRT
));
155 su
= (struct svcudp_data
*) mem_alloc (sizeof (*su
));
156 buf
= mem_alloc (((MAX (sendsz
, recvsz
) + 3) / 4) * 4);
157 if (xprt
== NULL
|| su
== NULL
|| buf
== NULL
)
159 (void) __fxprintf (NULL
, "%s: %s",
160 "svcudp_create", _("out of memory\n"));
161 mem_free (xprt
, sizeof (SVCXPRT
));
162 mem_free (su
, sizeof (*su
));
163 mem_free (buf
, ((MAX (sendsz
, recvsz
) + 3) / 4) * 4);
166 su
->su_iosz
= ((MAX (sendsz
, recvsz
) + 3) / 4) * 4;
167 rpc_buffer (xprt
) = buf
;
168 xdrmem_create (&(su
->su_xdrs
), rpc_buffer (xprt
), su
->su_iosz
, XDR_DECODE
);
170 xprt
->xp_p2
= (caddr_t
) su
;
171 xprt
->xp_verf
.oa_base
= su
->su_verfbody
;
172 xprt
->xp_ops
= &svcudp_op
;
173 xprt
->xp_port
= ntohs (addr
.sin_port
);
174 xprt
->xp_sock
= sock
;
177 if ((sizeof (struct iovec
) + sizeof (struct msghdr
)
178 + sizeof(struct cmsghdr
) + sizeof (struct in_pktinfo
))
179 > sizeof (xprt
->xp_pad
))
181 (void) __fxprintf (NULL
,"%s", _("\
182 svcudp_create: xp_pad is too small for IP_PKTINFO\n"));
186 if (__setsockopt (sock
, SOL_IP
, IP_PKTINFO
, (void *) &pad
,
188 /* Set the padding to all 1s. */
192 /* Clear the padding. */
194 memset (&xprt
->xp_pad
[0], pad
, sizeof (xprt
->xp_pad
));
196 xprt_register (xprt
);
199 #ifdef EXPORT_RPC_SYMBOLS
200 libc_hidden_def (svcudp_bufcreate
)
202 libc_hidden_nolink_sunrpc (svcudp_bufcreate
, GLIBC_2_0
)
206 svcudp_create (int sock
)
208 return svcudp_bufcreate (sock
, UDPMSGSIZE
, UDPMSGSIZE
);
210 #ifdef EXPORT_RPC_SYMBOLS
211 libc_hidden_def (svcudp_create
)
213 libc_hidden_nolink_sunrpc (svcudp_create
, GLIBC_2_0
)
216 static enum xprt_stat
217 svcudp_stat (SVCXPRT
*xprt
)
224 svcudp_recv (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
226 struct svcudp_data
*su
= su_data (xprt
);
227 XDR
*xdrs
= &(su
->su_xdrs
);
233 /* It is very tricky when you have IP aliases. We want to make sure
234 that we are sending the packet from the IP address where the
235 incoming packet is addressed to. H.J. */
238 struct msghdr
*mesgp
;
242 /* FIXME -- should xp_addrlen be a size_t? */
243 len
= (socklen_t
) sizeof(struct sockaddr_in
);
245 iovp
= (struct iovec
*) &xprt
->xp_pad
[0];
246 mesgp
= (struct msghdr
*) &xprt
->xp_pad
[sizeof (struct iovec
)];
247 if (mesgp
->msg_iovlen
)
249 iovp
->iov_base
= rpc_buffer (xprt
);
250 iovp
->iov_len
= su
->su_iosz
;
251 mesgp
->msg_iov
= iovp
;
252 mesgp
->msg_iovlen
= 1;
253 mesgp
->msg_name
= &(xprt
->xp_raddr
);
254 mesgp
->msg_namelen
= len
;
255 mesgp
->msg_control
= &xprt
->xp_pad
[sizeof (struct iovec
)
256 + sizeof (struct msghdr
)];
257 mesgp
->msg_controllen
= sizeof(xprt
->xp_pad
)
258 - sizeof (struct iovec
) - sizeof (struct msghdr
);
259 rlen
= __recvmsg (xprt
->xp_sock
, mesgp
, 0);
262 struct cmsghdr
*cmsg
;
263 len
= mesgp
->msg_namelen
;
264 cmsg
= CMSG_FIRSTHDR (mesgp
);
266 || CMSG_NXTHDR (mesgp
, cmsg
) != NULL
267 || cmsg
->cmsg_level
!= SOL_IP
268 || cmsg
->cmsg_type
!= IP_PKTINFO
269 || cmsg
->cmsg_len
< (sizeof (struct cmsghdr
)
270 + sizeof (struct in_pktinfo
)))
272 /* Not a simple IP_PKTINFO, ignore it. */
273 mesgp
->msg_control
= NULL
;
274 mesgp
->msg_controllen
= 0;
278 /* It was a simple IP_PKTIFO as we expected, discard the
280 struct in_pktinfo
*pkti
= (struct in_pktinfo
*) CMSG_DATA (cmsg
);
281 pkti
->ipi_ifindex
= 0;
287 rlen
= __recvfrom (xprt
->xp_sock
, rpc_buffer (xprt
),
288 (int) su
->su_iosz
, 0,
289 (struct sockaddr
*) &(xprt
->xp_raddr
), &len
);
290 xprt
->xp_addrlen
= len
;
295 __svc_accept_failed ();
297 if (rlen
< 16) /* < 4 32-bit ints? */
299 xdrs
->x_op
= XDR_DECODE
;
300 XDR_SETPOS (xdrs
, 0);
301 if (!xdr_callmsg (xdrs
, msg
))
303 su
->su_xid
= msg
->rm_xid
;
304 if (su
->su_cache
!= NULL
)
306 if (cache_get (xprt
, msg
, &reply
, &replylen
))
309 if (mesgp
->msg_iovlen
)
311 iovp
->iov_base
= reply
;
312 iovp
->iov_len
= replylen
;
313 (void) __sendmsg (xprt
->xp_sock
, mesgp
, 0);
317 (void) __sendto (xprt
->xp_sock
, reply
, (int) replylen
, 0,
318 (struct sockaddr
*) &xprt
->xp_raddr
, len
);
326 svcudp_reply (SVCXPRT
*xprt
, struct rpc_msg
*msg
)
328 struct svcudp_data
*su
= su_data (xprt
);
329 XDR
*xdrs
= &(su
->su_xdrs
);
334 struct msghdr
*mesgp
;
337 xdrs
->x_op
= XDR_ENCODE
;
338 XDR_SETPOS (xdrs
, 0);
339 msg
->rm_xid
= su
->su_xid
;
340 if (xdr_replymsg (xdrs
, msg
))
342 slen
= (int) XDR_GETPOS (xdrs
);
344 mesgp
= (struct msghdr
*) &xprt
->xp_pad
[sizeof (struct iovec
)];
345 if (mesgp
->msg_iovlen
)
347 iovp
= (struct iovec
*) &xprt
->xp_pad
[0];
348 iovp
->iov_base
= rpc_buffer (xprt
);
349 iovp
->iov_len
= slen
;
350 sent
= __sendmsg (xprt
->xp_sock
, mesgp
, 0);
354 sent
= __sendto (xprt
->xp_sock
, rpc_buffer (xprt
), slen
, 0,
355 (struct sockaddr
*) &(xprt
->xp_raddr
),
360 if (su
->su_cache
&& slen
>= 0)
362 cache_set (xprt
, (u_long
) slen
);
370 svcudp_getargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
373 return (*xdr_args
) (&(su_data (xprt
)->su_xdrs
), args_ptr
);
377 svcudp_freeargs (SVCXPRT
*xprt
, xdrproc_t xdr_args
, caddr_t args_ptr
)
379 XDR
*xdrs
= &(su_data (xprt
)->su_xdrs
);
381 xdrs
->x_op
= XDR_FREE
;
382 return (*xdr_args
) (xdrs
, args_ptr
);
386 svcudp_destroy (SVCXPRT
*xprt
)
388 struct svcudp_data
*su
= su_data (xprt
);
390 xprt_unregister (xprt
);
391 (void) __close (xprt
->xp_sock
);
392 XDR_DESTROY (&(su
->su_xdrs
));
393 mem_free (rpc_buffer (xprt
), su
->su_iosz
);
394 mem_free ((caddr_t
) su
, sizeof (struct svcudp_data
));
395 mem_free ((caddr_t
) xprt
, sizeof (SVCXPRT
));
399 /***********this could be a separate file*********************/
402 * Fifo cache for udp server
403 * Copies pointers to reply buffers into fifo cache
404 * Buffers are sent again if retransmissions are detected.
407 #define SPARSENESS 4 /* 75% sparse */
409 #define CACHE_PERROR(msg) \
410 (void) __fxprintf(NULL, "%s\n", msg)
412 #define ALLOC(type, size) \
413 (type *) mem_alloc((unsigned) (sizeof(type) * (size)))
415 #define CALLOC(type, size) \
416 (type *) calloc (sizeof (type), size)
419 * An entry in the cache
421 typedef struct cache_node
*cache_ptr
;
425 * Index into cache is xid, proc, vers, prog and address
431 struct sockaddr_in cache_addr
;
433 * The cached reply and length
436 u_long cache_replylen
;
438 * Next node on the list, if there is a collision
440 cache_ptr cache_next
;
450 u_long uc_size
; /* size of cache */
451 cache_ptr
*uc_entries
; /* hash table of entries in cache */
452 cache_ptr
*uc_fifo
; /* fifo list of entries in cache */
453 u_long uc_nextvictim
; /* points to next victim in fifo list */
454 u_long uc_prog
; /* saved program number */
455 u_long uc_vers
; /* saved version number */
456 u_long uc_proc
; /* saved procedure number */
457 struct sockaddr_in uc_addr
; /* saved caller's address */
462 * the hashing function
464 #define CACHE_LOC(transp, xid) \
465 (xid % (SPARSENESS*((struct udp_cache *) su_data(transp)->su_cache)->uc_size))
469 * Enable use of the cache.
470 * Note: there is no disable.
473 svcudp_enablecache (SVCXPRT
*transp
, u_long size
)
475 struct svcudp_data
*su
= su_data (transp
);
476 struct udp_cache
*uc
;
478 if (su
->su_cache
!= NULL
)
480 CACHE_PERROR (_("enablecache: cache already enabled"));
483 uc
= ALLOC (struct udp_cache
, 1);
486 CACHE_PERROR (_("enablecache: could not allocate cache"));
490 uc
->uc_nextvictim
= 0;
491 uc
->uc_entries
= CALLOC (cache_ptr
, size
* SPARSENESS
);
492 if (uc
->uc_entries
== NULL
)
494 mem_free (uc
, sizeof (struct udp_cache
));
495 CACHE_PERROR (_("enablecache: could not allocate cache data"));
498 uc
->uc_fifo
= CALLOC (cache_ptr
, size
);
499 if (uc
->uc_fifo
== NULL
)
501 mem_free (uc
->uc_entries
, size
* SPARSENESS
);
502 mem_free (uc
, sizeof (struct udp_cache
));
503 CACHE_PERROR (_("enablecache: could not allocate cache fifo"));
506 su
->su_cache
= (char *) uc
;
509 libc_hidden_nolink_sunrpc (svcudp_enablecache
, GLIBC_2_0
)
513 * Set an entry in the cache
516 cache_set (SVCXPRT
*xprt
, u_long replylen
)
520 struct svcudp_data
*su
= su_data (xprt
);
521 struct udp_cache
*uc
= (struct udp_cache
*) su
->su_cache
;
526 * Find space for the new entry, either by
527 * reusing an old entry, or by mallocing a new one
529 victim
= uc
->uc_fifo
[uc
->uc_nextvictim
];
532 loc
= CACHE_LOC (xprt
, victim
->cache_xid
);
533 for (vicp
= &uc
->uc_entries
[loc
];
534 *vicp
!= NULL
&& *vicp
!= victim
;
535 vicp
= &(*vicp
)->cache_next
)
539 CACHE_PERROR (_("cache_set: victim not found"));
542 *vicp
= victim
->cache_next
; /* remote from cache */
543 newbuf
= victim
->cache_reply
;
547 victim
= ALLOC (struct cache_node
, 1);
550 CACHE_PERROR (_("cache_set: victim alloc failed"));
553 newbuf
= mem_alloc (su
->su_iosz
);
556 mem_free (victim
, sizeof (struct cache_node
));
557 CACHE_PERROR (_("cache_set: could not allocate new rpc_buffer"));
565 victim
->cache_replylen
= replylen
;
566 victim
->cache_reply
= rpc_buffer (xprt
);
567 rpc_buffer (xprt
) = newbuf
;
568 xdrmem_create (&(su
->su_xdrs
), rpc_buffer (xprt
), su
->su_iosz
, XDR_ENCODE
);
569 victim
->cache_xid
= su
->su_xid
;
570 victim
->cache_proc
= uc
->uc_proc
;
571 victim
->cache_vers
= uc
->uc_vers
;
572 victim
->cache_prog
= uc
->uc_prog
;
573 victim
->cache_addr
= uc
->uc_addr
;
574 loc
= CACHE_LOC (xprt
, victim
->cache_xid
);
575 victim
->cache_next
= uc
->uc_entries
[loc
];
576 uc
->uc_entries
[loc
] = victim
;
577 uc
->uc_fifo
[uc
->uc_nextvictim
++] = victim
;
578 uc
->uc_nextvictim
%= uc
->uc_size
;
582 * Try to get an entry from the cache
583 * return 1 if found, 0 if not found
586 cache_get (SVCXPRT
*xprt
, struct rpc_msg
*msg
, char **replyp
,
591 struct svcudp_data
*su
= su_data (xprt
);
592 struct udp_cache
*uc
= (struct udp_cache
*) su
->su_cache
;
594 #define EQADDR(a1, a2) (memcmp((char*)&a1, (char*)&a2, sizeof(a1)) == 0)
596 loc
= CACHE_LOC (xprt
, su
->su_xid
);
597 for (ent
= uc
->uc_entries
[loc
]; ent
!= NULL
; ent
= ent
->cache_next
)
599 if (ent
->cache_xid
== su
->su_xid
&&
600 ent
->cache_proc
== uc
->uc_proc
&&
601 ent
->cache_vers
== uc
->uc_vers
&&
602 ent
->cache_prog
== uc
->uc_prog
&&
603 EQADDR (ent
->cache_addr
, uc
->uc_addr
))
605 *replyp
= ent
->cache_reply
;
606 *replylenp
= ent
->cache_replylen
;
611 * Failed to find entry
612 * Remember a few things so we can do a set later
614 uc
->uc_proc
= msg
->rm_call
.cb_proc
;
615 uc
->uc_vers
= msg
->rm_call
.cb_vers
;
616 uc
->uc_prog
= msg
->rm_call
.cb_prog
;
617 memcpy (&uc
->uc_addr
, &xprt
->xp_raddr
, sizeof (uc
->uc_addr
));