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