* sunrpc/etc.rpc (fedfs_admin): Add entry.
[platform/upstream/glibc.git] / sunrpc / xdr_rec.c
1 /*
2  * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
3  * layer above tcp (for rpc's use).
4  *
5  * Copyright (c) 2010, Oracle America, Inc.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are
9  * met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above
14  *       copyright notice, this list of conditions and the following
15  *       disclaimer in the documentation and/or other materials
16  *       provided with the distribution.
17  *     * Neither the name of the "Oracle America, Inc." nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  *   FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  *   COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
26  *   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
28  *   GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  *   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31  *   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  *
34  * These routines interface XDRSTREAMS to a tcp/ip connection.
35  * There is a record marking layer between the xdr stream
36  * and the tcp transport level.  A record is composed on one or more
37  * record fragments.  A record fragment is a thirty-two bit header followed
38  * by n bytes of data, where n is contained in the header.  The header
39  * is represented as a htonl(u_long).  The high order bit encodes
40  * whether or not the fragment is the last fragment of the record
41  * (1 => fragment is last, 0 => more fragments to follow.
42  * The other 31 bits encode the byte length of the fragment.
43  */
44
45 #include <stdio.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <rpc/rpc.h>
49 #include <libintl.h>
50 #include <wchar.h>
51 #include <libio/iolibio.h>
52
53 static bool_t xdrrec_getlong (XDR *, long *);
54 static bool_t xdrrec_putlong (XDR *, const long *);
55 static bool_t xdrrec_getbytes (XDR *, caddr_t, u_int);
56 static bool_t xdrrec_putbytes (XDR *, const char *, u_int);
57 static u_int xdrrec_getpos (const XDR *);
58 static bool_t xdrrec_setpos (XDR *, u_int);
59 static int32_t *xdrrec_inline (XDR *, u_int);
60 static void xdrrec_destroy (XDR *);
61 static bool_t xdrrec_getint32 (XDR *, int32_t *);
62 static bool_t xdrrec_putint32 (XDR *, const int32_t *);
63
64 static const struct xdr_ops xdrrec_ops = {
65   xdrrec_getlong,
66   xdrrec_putlong,
67   xdrrec_getbytes,
68   xdrrec_putbytes,
69   xdrrec_getpos,
70   xdrrec_setpos,
71   xdrrec_inline,
72   xdrrec_destroy,
73   xdrrec_getint32,
74   xdrrec_putint32
75 };
76
77 /*
78  * A record is composed of one or more record fragments.
79  * A record fragment is a two-byte header followed by zero to
80  * 2**32-1 bytes.  The header is treated as a long unsigned and is
81  * encode/decoded to the network via htonl/ntohl.  The low order 31 bits
82  * are a byte count of the fragment.  The highest order bit is a boolean:
83  * 1 => this fragment is the last fragment of the record,
84  * 0 => this fragment is followed by more fragment(s).
85  *
86  * The fragment/record machinery is not general;  it is constructed to
87  * meet the needs of xdr and rpc based on tcp.
88  */
89
90 #define LAST_FRAG (1UL << 31)
91
92 typedef struct rec_strm
93   {
94     caddr_t tcp_handle;
95     caddr_t the_buffer;
96     /*
97      * out-going bits
98      */
99     int (*writeit) (char *, char *, int);
100     caddr_t out_base;           /* output buffer (points to frag header) */
101     caddr_t out_finger;         /* next output position */
102     caddr_t out_boundry;        /* data cannot up to this address */
103     u_int32_t *frag_header;     /* beginning of curren fragment */
104     bool_t frag_sent;           /* true if buffer sent in middle of record */
105     /*
106      * in-coming bits
107      */
108     int (*readit) (char *, char *, int);
109     u_long in_size;             /* fixed size of the input buffer */
110     caddr_t in_base;
111     caddr_t in_finger;          /* location of next byte to be had */
112     caddr_t in_boundry;         /* can read up to this location */
113     long fbtbc;                 /* fragment bytes to be consumed */
114     bool_t last_frag;
115     u_int sendsize;
116     u_int recvsize;
117   }
118 RECSTREAM;
119
120 static u_int fix_buf_size (u_int) internal_function;
121 static bool_t skip_input_bytes (RECSTREAM *, long) internal_function;
122 static bool_t flush_out (RECSTREAM *, bool_t) internal_function;
123 static bool_t set_input_fragment (RECSTREAM *) internal_function;
124 static bool_t get_input_bytes (RECSTREAM *, caddr_t, int) internal_function;
125
126 /*
127  * Create an xdr handle for xdrrec
128  * xdrrec_create fills in xdrs.  Sendsize and recvsize are
129  * send and recv buffer sizes (0 => use default).
130  * tcp_handle is an opaque handle that is passed as the first parameter to
131  * the procedures readit and writeit.  Readit and writeit are read and
132  * write respectively.   They are like the system
133  * calls expect that they take an opaque handle rather than an fd.
134  */
135 void
136 xdrrec_create (XDR *xdrs, u_int sendsize,
137                u_int recvsize, caddr_t tcp_handle,
138                int (*readit) (char *, char *, int),
139                int (*writeit) (char *, char *, int))
140 {
141   RECSTREAM *rstrm = (RECSTREAM *) mem_alloc (sizeof (RECSTREAM));
142   caddr_t tmp;
143   char *buf;
144
145   sendsize = fix_buf_size (sendsize);
146   recvsize = fix_buf_size (recvsize);
147   buf = mem_alloc (sendsize + recvsize + BYTES_PER_XDR_UNIT);
148
149   if (rstrm == NULL || buf == NULL)
150     {
151       (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
152       mem_free (rstrm, sizeof (RECSTREAM));
153       mem_free (buf, sendsize + recvsize + BYTES_PER_XDR_UNIT);
154       /*
155        *  This is bad.  Should rework xdrrec_create to
156        *  return a handle, and in this case return NULL
157        */
158       return;
159     }
160   /*
161    * adjust sizes and allocate buffer quad byte aligned
162    */
163   rstrm->sendsize = sendsize;
164   rstrm->recvsize = recvsize;
165   rstrm->the_buffer = buf;
166   tmp = rstrm->the_buffer;
167   if ((size_t)tmp % BYTES_PER_XDR_UNIT)
168     tmp += BYTES_PER_XDR_UNIT - (size_t)tmp % BYTES_PER_XDR_UNIT;
169   rstrm->out_base = tmp;
170   rstrm->in_base = tmp + sendsize;
171   /*
172    * now the rest ...
173    */
174   /* We have to add the cast since the `struct xdr_ops' in `struct XDR'
175      is not `const'.  */
176   xdrs->x_ops = (struct xdr_ops *) &xdrrec_ops;
177   xdrs->x_private = (caddr_t) rstrm;
178   rstrm->tcp_handle = tcp_handle;
179   rstrm->readit = readit;
180   rstrm->writeit = writeit;
181   rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
182   rstrm->frag_header = (u_int32_t *) rstrm->out_base;
183   rstrm->out_finger += 4;
184   rstrm->out_boundry += sendsize;
185   rstrm->frag_sent = FALSE;
186   rstrm->in_size = recvsize;
187   rstrm->in_boundry = rstrm->in_base;
188   rstrm->in_finger = (rstrm->in_boundry += recvsize);
189   rstrm->fbtbc = 0;
190   rstrm->last_frag = TRUE;
191 }
192 libc_hidden_nolink_sunrpc (xdrrec_create, GLIBC_2_0)
193
194
195 /*
196  * The routines defined below are the xdr ops which will go into the
197  * xdr handle filled in by xdrrec_create.
198  */
199
200 static bool_t
201 xdrrec_getlong (XDR *xdrs, long *lp)
202 {
203   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
204   int32_t *buflp = (int32_t *) rstrm->in_finger;
205   int32_t mylong;
206
207   /* first try the inline, fast case */
208   if (rstrm->fbtbc >= BYTES_PER_XDR_UNIT &&
209       rstrm->in_boundry - (char *) buflp >= BYTES_PER_XDR_UNIT)
210     {
211       *lp = (int32_t) ntohl (*buflp);
212       rstrm->fbtbc -= BYTES_PER_XDR_UNIT;
213       rstrm->in_finger += BYTES_PER_XDR_UNIT;
214     }
215   else
216     {
217       if (!xdrrec_getbytes (xdrs, (caddr_t) & mylong,
218                             BYTES_PER_XDR_UNIT))
219         return FALSE;
220       *lp = (int32_t) ntohl (mylong);
221     }
222   return TRUE;
223 }
224
225 static bool_t
226 xdrrec_putlong (XDR *xdrs, const long *lp)
227 {
228   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
229   int32_t *dest_lp = (int32_t *) rstrm->out_finger;
230
231   if ((rstrm->out_finger += BYTES_PER_XDR_UNIT) > rstrm->out_boundry)
232     {
233       /*
234        * this case should almost never happen so the code is
235        * inefficient
236        */
237       rstrm->out_finger -= BYTES_PER_XDR_UNIT;
238       rstrm->frag_sent = TRUE;
239       if (!flush_out (rstrm, FALSE))
240         return FALSE;
241       dest_lp = (int32_t *) rstrm->out_finger;
242       rstrm->out_finger += BYTES_PER_XDR_UNIT;
243     }
244   *dest_lp = htonl (*lp);
245   return TRUE;
246 }
247
248 static bool_t      /* must manage buffers, fragments, and records */
249 xdrrec_getbytes (XDR *xdrs, caddr_t addr, u_int len)
250 {
251   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
252   u_int current;
253
254   while (len > 0)
255     {
256       current = rstrm->fbtbc;
257       if (current == 0)
258         {
259           if (rstrm->last_frag)
260             return FALSE;
261           if (!set_input_fragment (rstrm))
262             return FALSE;
263           continue;
264         }
265       current = (len < current) ? len : current;
266       if (!get_input_bytes (rstrm, addr, current))
267         return FALSE;
268       addr += current;
269       rstrm->fbtbc -= current;
270       len -= current;
271     }
272   return TRUE;
273 }
274
275 static bool_t
276 xdrrec_putbytes (XDR *xdrs, const char *addr, u_int len)
277 {
278   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
279   u_int current;
280
281   while (len > 0)
282     {
283       current = rstrm->out_boundry - rstrm->out_finger;
284       current = (len < current) ? len : current;
285       memcpy (rstrm->out_finger, addr, current);
286       rstrm->out_finger += current;
287       addr += current;
288       len -= current;
289       if (rstrm->out_finger == rstrm->out_boundry && len > 0)
290         {
291           rstrm->frag_sent = TRUE;
292           if (!flush_out (rstrm, FALSE))
293             return FALSE;
294         }
295     }
296   return TRUE;
297 }
298
299 static u_int
300 xdrrec_getpos (const XDR *xdrs)
301 {
302   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
303   long pos;
304
305   pos = __lseek ((int) (long) rstrm->tcp_handle, (long) 0, 1);
306   if (pos != -1)
307     switch (xdrs->x_op)
308       {
309
310       case XDR_ENCODE:
311         pos += rstrm->out_finger - rstrm->out_base;
312         break;
313
314       case XDR_DECODE:
315         pos -= rstrm->in_boundry - rstrm->in_finger;
316         break;
317
318       default:
319         pos = (u_int) - 1;
320         break;
321       }
322   return (u_int) pos;
323 }
324
325 static bool_t
326 xdrrec_setpos (XDR *xdrs, u_int pos)
327 {
328   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
329   u_int currpos = xdrrec_getpos (xdrs);
330   int delta = currpos - pos;
331   caddr_t newpos;
332
333   if ((int) currpos != -1)
334     switch (xdrs->x_op)
335       {
336
337       case XDR_ENCODE:
338         newpos = rstrm->out_finger - delta;
339         if (newpos > (caddr_t) rstrm->frag_header &&
340             newpos < rstrm->out_boundry)
341           {
342             rstrm->out_finger = newpos;
343             return TRUE;
344           }
345         break;
346
347       case XDR_DECODE:
348         newpos = rstrm->in_finger - delta;
349         if ((delta < (int) (rstrm->fbtbc)) &&
350             (newpos <= rstrm->in_boundry) &&
351             (newpos >= rstrm->in_base))
352           {
353             rstrm->in_finger = newpos;
354             rstrm->fbtbc -= delta;
355             return TRUE;
356           }
357         break;
358
359       default:
360         break;
361       }
362   return FALSE;
363 }
364
365 static int32_t *
366 xdrrec_inline (XDR *xdrs, u_int len)
367 {
368   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
369   int32_t *buf = NULL;
370
371   switch (xdrs->x_op)
372     {
373
374     case XDR_ENCODE:
375       if ((rstrm->out_finger + len) <= rstrm->out_boundry)
376         {
377           buf = (int32_t *) rstrm->out_finger;
378           rstrm->out_finger += len;
379         }
380       break;
381
382     case XDR_DECODE:
383       if ((len <= rstrm->fbtbc) &&
384           ((rstrm->in_finger + len) <= rstrm->in_boundry))
385         {
386           buf = (int32_t *) rstrm->in_finger;
387           rstrm->fbtbc -= len;
388           rstrm->in_finger += len;
389         }
390       break;
391
392     default:
393       break;
394     }
395   return buf;
396 }
397
398 static void
399 xdrrec_destroy (XDR *xdrs)
400 {
401   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
402
403   mem_free (rstrm->the_buffer,
404             rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
405   mem_free ((caddr_t) rstrm, sizeof (RECSTREAM));
406 }
407
408 static bool_t
409 xdrrec_getint32 (XDR *xdrs, int32_t *ip)
410 {
411   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
412   int32_t *bufip = (int32_t *) rstrm->in_finger;
413   int32_t mylong;
414
415   /* first try the inline, fast case */
416   if (rstrm->fbtbc >= BYTES_PER_XDR_UNIT &&
417       rstrm->in_boundry - (char *) bufip >= BYTES_PER_XDR_UNIT)
418     {
419       *ip = ntohl (*bufip);
420       rstrm->fbtbc -= BYTES_PER_XDR_UNIT;
421       rstrm->in_finger += BYTES_PER_XDR_UNIT;
422     }
423   else
424     {
425       if (!xdrrec_getbytes (xdrs, (caddr_t) &mylong,
426                             BYTES_PER_XDR_UNIT))
427         return FALSE;
428       *ip = ntohl (mylong);
429     }
430   return TRUE;
431 }
432
433 static bool_t
434 xdrrec_putint32 (XDR *xdrs, const int32_t *ip)
435 {
436   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
437   int32_t *dest_ip = (int32_t *) rstrm->out_finger;
438
439   if ((rstrm->out_finger += BYTES_PER_XDR_UNIT) > rstrm->out_boundry)
440     {
441       /*
442        * this case should almost never happen so the code is
443        * inefficient
444        */
445       rstrm->out_finger -= BYTES_PER_XDR_UNIT;
446       rstrm->frag_sent = TRUE;
447       if (!flush_out (rstrm, FALSE))
448         return FALSE;
449       dest_ip = (int32_t *) rstrm->out_finger;
450       rstrm->out_finger += BYTES_PER_XDR_UNIT;
451     }
452   *dest_ip = htonl (*ip);
453   return TRUE;
454 }
455
456 /*
457  * Exported routines to manage xdr records
458  */
459
460 /*
461  * Before reading (deserializing from the stream, one should always call
462  * this procedure to guarantee proper record alignment.
463  */
464 bool_t
465 xdrrec_skiprecord (XDR *xdrs)
466 {
467   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
468
469   while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
470     {
471       if (!skip_input_bytes (rstrm, rstrm->fbtbc))
472         return FALSE;
473       rstrm->fbtbc = 0;
474       if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
475         return FALSE;
476     }
477   rstrm->last_frag = FALSE;
478   return TRUE;
479 }
480 libc_hidden_nolink_sunrpc (xdrrec_skiprecord, GLIBC_2_0)
481
482 /*
483  * Lookahead function.
484  * Returns TRUE iff there is no more input in the buffer
485  * after consuming the rest of the current record.
486  */
487 bool_t
488 xdrrec_eof (XDR *xdrs)
489 {
490   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
491
492   while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
493     {
494       if (!skip_input_bytes (rstrm, rstrm->fbtbc))
495         return TRUE;
496       rstrm->fbtbc = 0;
497       if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
498         return TRUE;
499     }
500   if (rstrm->in_finger == rstrm->in_boundry)
501     return TRUE;
502   return FALSE;
503 }
504 libc_hidden_nolink_sunrpc (xdrrec_eof, GLIBC_2_0)
505
506 /*
507  * The client must tell the package when an end-of-record has occurred.
508  * The second parameter tells whether the record should be flushed to the
509  * (output) tcp stream.  (This lets the package support batched or
510  * pipelined procedure calls.)  TRUE => immediate flush to tcp connection.
511  */
512 bool_t
513 xdrrec_endofrecord (XDR *xdrs, bool_t sendnow)
514 {
515   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
516   u_long len;           /* fragment length */
517
518   if (sendnow || rstrm->frag_sent
519       || rstrm->out_finger + BYTES_PER_XDR_UNIT >= rstrm->out_boundry)
520     {
521       rstrm->frag_sent = FALSE;
522       return flush_out (rstrm, TRUE);
523     }
524   len = (rstrm->out_finger - (char *) rstrm->frag_header
525          - BYTES_PER_XDR_UNIT);
526   *rstrm->frag_header = htonl ((u_long) len | LAST_FRAG);
527   rstrm->frag_header = (u_int32_t *) rstrm->out_finger;
528   rstrm->out_finger += BYTES_PER_XDR_UNIT;
529   return TRUE;
530 }
531 libc_hidden_nolink_sunrpc (xdrrec_endofrecord, GLIBC_2_0)
532
533
534 /*
535  * Internal useful routines
536  */
537 static bool_t
538 internal_function
539 flush_out (RECSTREAM *rstrm, bool_t eor)
540 {
541   u_long eormask = (eor == TRUE) ? LAST_FRAG : 0;
542   u_long len = (rstrm->out_finger - (char *) rstrm->frag_header
543                 - BYTES_PER_XDR_UNIT);
544
545   *rstrm->frag_header = htonl (len | eormask);
546   len = rstrm->out_finger - rstrm->out_base;
547   if ((*(rstrm->writeit)) (rstrm->tcp_handle, rstrm->out_base, (int) len)
548       != (int) len)
549     return FALSE;
550   rstrm->frag_header = (u_int32_t *) rstrm->out_base;
551   rstrm->out_finger = (caddr_t) rstrm->out_base + BYTES_PER_XDR_UNIT;
552   return TRUE;
553 }
554
555 static bool_t   /* knows nothing about records!  Only about input buffers */
556 fill_input_buf (RECSTREAM *rstrm)
557 {
558   caddr_t where;
559   size_t i;
560   int len;
561
562   where = rstrm->in_base;
563   i = (size_t) rstrm->in_boundry % BYTES_PER_XDR_UNIT;
564   where += i;
565   len = rstrm->in_size - i;
566   if ((len = (*(rstrm->readit)) (rstrm->tcp_handle, where, len)) == -1)
567     return FALSE;
568   rstrm->in_finger = where;
569   where += len;
570   rstrm->in_boundry = where;
571   return TRUE;
572 }
573
574 static bool_t   /* knows nothing about records!  Only about input buffers */
575 internal_function
576 get_input_bytes (RECSTREAM *rstrm, caddr_t addr, int len)
577 {
578   int current;
579
580   while (len > 0)
581     {
582       current = rstrm->in_boundry - rstrm->in_finger;
583       if (current == 0)
584         {
585           if (!fill_input_buf (rstrm))
586             return FALSE;
587           continue;
588         }
589       current = (len < current) ? len : current;
590       memcpy (addr, rstrm->in_finger, current);
591       rstrm->in_finger += current;
592       addr += current;
593       len -= current;
594     }
595   return TRUE;
596 }
597
598 static bool_t /* next two bytes of the input stream are treated as a header */
599 internal_function
600 set_input_fragment (RECSTREAM *rstrm)
601 {
602   uint32_t header;
603
604   if (! get_input_bytes (rstrm, (caddr_t)&header, BYTES_PER_XDR_UNIT))
605     return FALSE;
606   header = ntohl (header);
607   rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
608   /*
609    * Sanity check. Try not to accept wildly incorrect fragment
610    * sizes. Unfortunately, only a size of zero can be identified as
611    * 'wildely incorrect', and this only, if it is not the last
612    * fragment of a message. Ridiculously large fragment sizes may look
613    * wrong, but we don't have any way to be certain that they aren't
614    * what the client actually intended to send us. Many existing RPC
615    * implementations may sent a fragment of size zero as the last
616    * fragment of a message.
617    */
618   if (header == 0)
619     return FALSE;
620   rstrm->fbtbc = header & ~LAST_FRAG;
621   return TRUE;
622 }
623
624 static bool_t   /* consumes input bytes; knows nothing about records! */
625 internal_function
626 skip_input_bytes (RECSTREAM *rstrm, long cnt)
627 {
628   int current;
629
630   while (cnt > 0)
631     {
632       current = rstrm->in_boundry - rstrm->in_finger;
633       if (current == 0)
634         {
635           if (!fill_input_buf (rstrm))
636             return FALSE;
637           continue;
638         }
639       current = (cnt < current) ? cnt : current;
640       rstrm->in_finger += current;
641       cnt -= current;
642     }
643   return TRUE;
644 }
645
646 static u_int
647 internal_function
648 fix_buf_size (u_int s)
649 {
650   if (s < 100)
651     s = 4000;
652   return RNDUP (s);
653 }