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