source: trunk/libs/newlib/src/newlib/libc/xdr/xdr_rec.c @ 543

Last change on this file since 543 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 25.0 KB
Line 
1
2/*
3 * Copyright (c) 2009, Sun Microsystems, Inc.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * - Redistributions of source code must retain the above copyright notice,
9 *   this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright notice,
11 *   this list of conditions and the following disclaimer in the documentation
12 *   and/or other materials provided with the distribution.
13 * - Neither the name of Sun Microsystems, Inc. nor the names of its
14 *   contributors may be used to endorse or promote products derived
15 *   from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*
31 * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
32 * layer above tcp (for rpc's use).
33 *
34 * Copyright (C) 1984, Sun Microsystems, Inc.
35 *
36 * These routines interface XDRSTREAMS to a tcp/ip connection.
37 * There is a record marking layer between the xdr stream
38 * and the tcp transport level.  A record is composed on one or more
39 * record fragments.  A record fragment is a thirty-two bit header followed
40 * by n bytes of data, where n is contained in the header.  The header
41 * is represented as a htonl(u_long).  Thegh order bit encodes
42 * whether or not the fragment is the last fragment of the record
43 * (1 => fragment is last, 0 => more fragments to follow.
44 * The other 31 bits encode the byte length of the fragment.
45 */
46
47#include <stddef.h>
48#include <sys/types.h>
49#include <stdlib.h>
50#include <string.h>
51#include <assert.h>
52#include <unistd.h>
53#include <errno.h>
54#include <limits.h>
55
56#include <rpc/types.h>
57#include <rpc/xdr.h>
58
59#include "xdr_private.h"
60
61#ifndef ntohl
62# define ntohl(x) xdr_ntohl(x)
63#endif
64#ifndef htonl
65# define htonl(x) xdr_htonl(x)
66#endif
67
68enum xprt_stat
69{
70  XPRT_DIED,
71  XPRT_MOREREQS,
72  XPRT_IDLE
73};
74
75static bool_t xdrrec_getlong (XDR *, long *);
76static bool_t xdrrec_putlong (XDR *, const long *);
77static bool_t xdrrec_getbytes (XDR *, char *, u_int);
78static bool_t xdrrec_putbytes (XDR *, const char *, u_int);
79static u_int xdrrec_getpos (XDR *);
80static bool_t xdrrec_setpos (XDR *, u_int);
81static int32_t * xdrrec_inline (XDR *, u_int);
82static void xdrrec_destroy (XDR *);
83static bool_t xdrrec_getint32 (XDR *, int32_t *);
84static bool_t xdrrec_putint32 (XDR *, const int32_t *);
85
86static const struct xdr_ops xdrrec_ops = {
87  xdrrec_getlong,
88  xdrrec_putlong,
89  xdrrec_getbytes,
90  xdrrec_putbytes,
91  xdrrec_getpos,
92  xdrrec_setpos,
93  xdrrec_inline,
94  xdrrec_destroy,
95  xdrrec_getint32,
96  xdrrec_putint32
97};
98
99/*
100 * A record is composed of one or more record fragments.
101 * A record fragment is a four-byte header followed by zero to
102 * 2**32-1 bytes.  The header is treated as a long unsigned and is
103 * encode/decoded to the network via htonl/ntohl.  The low order 31 bits
104 * are a byte count of the fragment.  The highest order bit is a boolean:
105 * 1 => this fragment is the last fragment of the record,
106 * 0 => this fragment is followed by more fragment(s).
107 *
108 * The fragment/record machinery is not general;  it is constructed to
109 * meet the needs of xdr and rpc based on tcp.
110 */
111
112#define LAST_FRAG ((u_int32_t)(UINT32_C(1) << 31))
113
114typedef struct rec_strm
115{
116  caddr_t tcp_handle;
117  /*
118   * out-goung bits
119   */
120  caddr_t out_buffer;           /* buffer as allocated; may not be aligned */
121  int (*writeit) (void *, void *, int);
122  caddr_t out_base;             /* output buffer (points to frag header) */
123  caddr_t out_finger;           /* next output position */
124  caddr_t out_boundry;          /* data cannot up to this address */
125  u_int32_t *frag_header;       /* beginning of curren fragment */
126  bool_t frag_sent;             /* true if buffer sent in middle of record */
127  /*
128   * in-coming bits
129   */
130  caddr_t in_buffer;            /* buffer as allocated; may not be aligned */
131  int (*readit) (void *, void *, int);
132  u_long in_size;               /* fixed size of the input buffer */
133  caddr_t in_base;
134  caddr_t in_finger;            /* location of next byte to be had */
135  caddr_t in_boundry;           /* can read up to this location */
136  long fbtbc;                   /* fragment bytes to be consumed */
137  bool_t last_frag;
138  u_int sendsize;               /* must be <= INT_MAX */
139  u_int recvsize;               /* must be <= INT_MAX */
140
141  bool_t nonblock;
142  bool_t in_haveheader;
143  u_int32_t in_header;
144  char *in_hdrp;
145  int in_hdrlen;
146  int in_reclen;
147  int in_received;
148  int in_maxrec;
149} RECSTREAM;
150
151static u_int fix_buf_size (u_int);
152static bool_t flush_out (RECSTREAM *, bool_t);
153static bool_t fill_input_buf (RECSTREAM *);
154static bool_t get_input_bytes (RECSTREAM *, char *, size_t);
155static bool_t set_input_fragment (RECSTREAM *);
156static bool_t skip_input_bytes (RECSTREAM *, long);
157static bool_t realloc_stream (RECSTREAM *, int);
158
159bool_t __xdrrec_getrec (XDR *, enum xprt_stat *, bool_t);
160bool_t __xdrrec_setnonblock (XDR *, int);
161
162/*
163 * Create an xdr handle for xdrrec
164 * xdrrec_create fills in xdrs.  Sendsize and recvsize are
165 * send and recv buffer sizes (0 => use default), and must be <= INT_MAX.
166 * tcp_handle is an opaque handle that is passed as the first parameter to
167 * the procedures readit and writeit.  Readit and writeit are read and
168 * write respectively.   They are like the system
169 * calls except that they take an opaque handle rather than an fd.
170 */
171void
172xdrrec_create (XDR * xdrs,
173        u_int sendsize,
174        u_int recvsize,
175        void *tcp_handle,
176        int (*readit) (void *, void *, int),
177        int (*writeit) (void *, void *, int))
178{
179  RECSTREAM *rstrm;
180  /* Although sendsize and recvsize are u_int, we require
181   * that they be less than INT_MAX, because often we need
182   * to compare against values held in (signed) integers.
183   * Please don't try to use send/recv buffers > 2GB...
184   */
185  assert (sendsize < (u_int)INT_MAX);
186  assert (recvsize < (u_int)INT_MAX);
187
188  rstrm = (RECSTREAM *) mem_alloc (sizeof (RECSTREAM));
189  if (rstrm == NULL)
190    {
191      xdr_warnx ("xdrrec_create: out of memory");
192      /*
193       *  This is bad.  Should rework xdrrec_create to
194       *  return a handle, and in this case return NULL
195       */
196      errno = ENOMEM;
197      return;
198    }
199
200
201  /* allocate send buffer; insure BYTES_PER_UNIT alignment */
202  rstrm->sendsize = sendsize = fix_buf_size (sendsize);
203  rstrm->out_buffer = mem_alloc (rstrm->sendsize + BYTES_PER_XDR_UNIT);
204  if (rstrm->out_buffer == NULL)
205    {
206      xdr_warnx ("xdrrec_create: out of memory");
207      mem_free (rstrm, sizeof (RECSTREAM));
208      errno = ENOMEM;
209      return;
210    }
211  for (rstrm->out_base = rstrm->out_buffer;
212       (long) rstrm->out_base % BYTES_PER_XDR_UNIT != 0; rstrm->out_base++)
213    ;
214
215  /* allocate recv buffer; insure BYTES_PER_UNIT alignment */
216  rstrm->recvsize = recvsize = fix_buf_size (recvsize);
217  rstrm->in_buffer = mem_alloc (recvsize + BYTES_PER_XDR_UNIT);
218  if (rstrm->in_buffer == NULL)
219    {
220      xdr_warnx ("xdrrec_create: out of memory");
221      mem_free (rstrm->out_buffer, sendsize + BYTES_PER_XDR_UNIT);
222      mem_free (rstrm, sizeof (RECSTREAM));
223      errno = ENOMEM;
224      return;
225    }
226  for (rstrm->in_base = rstrm->in_buffer;
227       (long) rstrm->in_base % BYTES_PER_XDR_UNIT != 0; rstrm->in_base++)
228    ;
229
230  /*
231   * now the rest ...
232   */
233  xdrs->x_ops = &xdrrec_ops;
234  xdrs->x_private = rstrm;
235  rstrm->tcp_handle = tcp_handle;
236  rstrm->readit = readit;
237  rstrm->writeit = writeit;
238  rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
239  rstrm->frag_header = (u_int32_t *) (void *) rstrm->out_base;
240  rstrm->out_finger += sizeof (u_int32_t);
241  rstrm->out_boundry += sendsize;
242  rstrm->frag_sent = FALSE;
243  rstrm->in_size = recvsize;
244  rstrm->in_boundry = rstrm->in_base;
245  rstrm->in_finger = (rstrm->in_boundry += recvsize);
246  rstrm->fbtbc = 0;
247  rstrm->last_frag = TRUE;
248  rstrm->in_haveheader = FALSE;
249  rstrm->in_hdrlen = 0;
250  rstrm->in_hdrp = (char *) (void *) &rstrm->in_header;
251  rstrm->nonblock = FALSE;
252  rstrm->in_reclen = 0;
253  rstrm->in_received = 0;
254}
255
256
257/*
258 * The reoutines defined below are the xdr ops which will go into the
259 * xdr handle filled in by xdrrec_create.
260 */
261
262static bool_t
263xdrrec_getlong (XDR * xdrs,
264        long *lp)
265{
266  RECSTREAM *rstrm = (RECSTREAM *) (xdrs->x_private);
267  int32_t *buflp = (int32_t *) (void *) (rstrm->in_finger);
268  int32_t mylong;
269
270  /* first try the inline, fast case */
271  if ((rstrm->fbtbc >= sizeof (int32_t)) &&
272      (((long) rstrm->in_boundry - (long) buflp) >= sizeof (int32_t)))
273    {
274      *lp = (long) ntohl ((u_int32_t) (*buflp));
275      rstrm->fbtbc -= sizeof (int32_t);
276      rstrm->in_finger += sizeof (int32_t);
277    }
278  else
279    {
280      if (!xdrrec_getbytes (xdrs, (char *) (void *) &mylong,
281                            sizeof (int32_t)))
282        return FALSE;
283      *lp = (long) ntohl ((u_int32_t) mylong);
284    }
285  return TRUE;
286}
287
288static bool_t
289xdrrec_putlong (XDR * xdrs,
290        const long *lp)
291{
292  RECSTREAM *rstrm = (RECSTREAM *) (xdrs->x_private);
293  int32_t *dest_lp = ((int32_t *) (void *) (rstrm->out_finger));
294
295  if ((rstrm->out_finger += sizeof (int32_t)) > rstrm->out_boundry)
296    {
297      /*
298       * this case should almost never happen so the code is
299       * inefficient
300       */
301      rstrm->out_finger -= sizeof (int32_t);
302      rstrm->frag_sent = TRUE;
303      if (!flush_out (rstrm, FALSE))
304        return FALSE;
305      dest_lp = ((int32_t *) (void *) (rstrm->out_finger));
306      rstrm->out_finger += sizeof (int32_t);
307    }
308  *dest_lp = (int32_t) htonl ((u_int32_t) (*lp));
309  return TRUE;
310}
311
312static bool_t                   /* must manage buffers, fragments, and records */
313xdrrec_getbytes (XDR * xdrs,
314        char *addr,
315        u_int len)
316{
317  RECSTREAM *rstrm = (RECSTREAM *) (xdrs->x_private);
318  size_t current;
319
320  while (len > 0)
321    {
322      current = (int) rstrm->fbtbc;
323      if (current == 0)
324        {
325          if (rstrm->last_frag)
326            return FALSE;
327          if (!set_input_fragment (rstrm))
328            return FALSE;
329          continue;
330        }
331      current = (len < current) ? len : current;
332      if (!get_input_bytes (rstrm, addr, current))
333        return FALSE;
334      addr += current;
335      rstrm->fbtbc -= current;
336      len -= current;
337    }
338  return TRUE;
339}
340
341static bool_t
342xdrrec_putbytes (XDR * xdrs,
343        const char *addr,
344        u_int len)
345{
346  RECSTREAM *rstrm = (RECSTREAM *) (xdrs->x_private);
347  size_t current;
348
349  while (len > 0)
350    {
351      current = (size_t) ((u_long) rstrm->out_boundry -
352                          (u_long) rstrm->out_finger);
353      current = (len < current) ? len : current;
354      memmove (rstrm->out_finger, addr, current);
355      rstrm->out_finger += current;
356      addr += current;
357      len -= current;
358      if (rstrm->out_finger == rstrm->out_boundry)
359        {
360          rstrm->frag_sent = TRUE;
361          if (!flush_out (rstrm, FALSE))
362            return FALSE;
363        }
364    }
365  return TRUE;
366}
367
368static u_int
369xdrrec_getpos (XDR * xdrs)
370{
371  RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
372  off_t pos;
373
374  pos = lseek ((int) (u_long) rstrm->tcp_handle, (off_t) 0, 1);
375  if (pos != -1)
376    switch (xdrs->x_op)
377      {
378
379      case XDR_ENCODE:
380        pos += rstrm->out_finger - rstrm->out_base;
381        break;
382
383      case XDR_DECODE:
384        pos -= rstrm->in_boundry - rstrm->in_finger;
385        break;
386
387      default:
388        pos = (off_t) - 1;
389        break;
390      }
391  return ((u_int) pos);
392}
393
394static bool_t
395xdrrec_setpos (XDR * xdrs,
396        u_int pos)
397{
398  RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
399  u_int currpos = xdrrec_getpos (xdrs);
400  int delta = currpos - pos;
401  char *newpos;
402
403  if ((int) currpos != -1)
404    switch (xdrs->x_op)
405      {
406
407      case XDR_ENCODE:
408        newpos = rstrm->out_finger - delta;
409        if ((newpos > (char *) (void *) (rstrm->frag_header)) &&
410            (newpos < rstrm->out_boundry))
411          {
412            rstrm->out_finger = newpos;
413            return TRUE;
414          }
415        break;
416
417      case XDR_DECODE:
418        newpos = rstrm->in_finger - delta;
419        if ((delta < (int) (rstrm->fbtbc)) &&
420            (newpos <= rstrm->in_boundry) && (newpos >= rstrm->in_base))
421          {
422            rstrm->in_finger = newpos;
423            rstrm->fbtbc -= delta;
424            return TRUE;
425          }
426        break;
427
428      case XDR_FREE:
429        break;
430      }
431  return FALSE;
432}
433
434static int32_t *
435xdrrec_inline (XDR * xdrs,
436        u_int len)
437{
438  RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
439  int32_t *buf = NULL;
440  /* len represents the number of bytes to extract
441   * from the buffer. The number of bytes remaining
442   * in the buffer is rstrm->fbtbc, which is a long.
443   * Thus, the buffer size maximum is 2GB (!), and
444   * we require that no one ever try to read more
445   * than than number of bytes at once.
446   */
447  assert (len < (u_int)LONG_MAX);
448
449  switch (xdrs->x_op)
450    {
451
452    case XDR_ENCODE:
453      if ((rstrm->out_finger + len) <= rstrm->out_boundry)
454        {
455          buf = (int32_t *) (void *) rstrm->out_finger;
456          rstrm->out_finger += len;
457        }
458      break;
459
460    case XDR_DECODE:
461      if (((long)len <= rstrm->fbtbc) &&
462          ((rstrm->in_finger + len) <= rstrm->in_boundry))
463        {
464          buf = (int32_t *) (void *) rstrm->in_finger;
465          rstrm->fbtbc -= len;
466          rstrm->in_finger += len;
467        }
468      break;
469
470    case XDR_FREE:
471      break;
472    }
473  return (buf);
474}
475
476static void
477xdrrec_destroy (XDR * xdrs)
478{
479  RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
480
481  mem_free (rstrm->out_buffer, rstrm->sendsize + BYTES_PER_XDR_UNIT);
482  mem_free (rstrm->in_buffer, rstrm->recvsize + BYTES_PER_XDR_UNIT);
483  mem_free (rstrm, sizeof (RECSTREAM));
484}
485
486static bool_t
487xdrrec_getint32 (XDR *xdrs,
488        int32_t *ip)
489{
490  RECSTREAM *rstrm = (RECSTREAM *) (xdrs->x_private);
491  int32_t *bufip = (int32_t *) (void *) (rstrm->in_finger);
492  int32_t mylong;
493
494  /* first try the inline, fast case */
495  if ((rstrm->fbtbc >= sizeof (int32_t)) &&
496      (( rstrm->in_boundry - (char *) bufip) >= sizeof (int32_t)))
497    {
498      *ip = (int32_t) ntohl (*bufip);
499      rstrm->fbtbc -= sizeof (int32_t);
500      rstrm->in_finger += sizeof (int32_t);
501    }
502  else
503    {
504      if (!xdrrec_getbytes (xdrs, (char *) (void *) &mylong,
505                            sizeof (int32_t)))
506        return FALSE;
507      *ip = (int32_t) ntohl (mylong);
508    }
509  return TRUE;
510}
511
512static bool_t
513xdrrec_putint32 (XDR *xdrs,
514        const int32_t *ip)
515{
516  RECSTREAM *rstrm = (RECSTREAM *) (xdrs->x_private);
517  int32_t *dest_ip = ((int32_t *) (void *) (rstrm->out_finger));
518
519  if ((rstrm->out_finger += sizeof (int32_t)) > rstrm->out_boundry)
520    {
521      /*
522       * this case should almost never happen so the code is
523       * inefficient
524       */
525      rstrm->out_finger -= sizeof (int32_t);
526      rstrm->frag_sent = TRUE;
527      if (!flush_out (rstrm, FALSE))
528        return FALSE;
529      dest_ip = ((int32_t *) (void *) (rstrm->out_finger));
530      rstrm->out_finger += sizeof (int32_t);
531    }
532  *dest_ip = (int32_t) htonl (*ip);
533  return TRUE;
534}
535
536/*
537 * Exported routines to manage xdr records
538 */
539
540/*
541 * Before reading (deserializing from the stream, one should always call
542 * this procedure to guarantee proper record alignment.
543 */
544bool_t
545xdrrec_skiprecord (XDR * xdrs)
546{
547  RECSTREAM *rstrm = (RECSTREAM *) (xdrs->x_private);
548  enum xprt_stat xstat;
549
550  if (rstrm->nonblock)
551    {
552      if (__xdrrec_getrec (xdrs, &xstat, FALSE))
553        {
554          rstrm->fbtbc = 0;
555          return TRUE;
556        }
557      if (rstrm->in_finger == rstrm->in_boundry && xstat == XPRT_MOREREQS)
558        {
559          rstrm->fbtbc = 0;
560          return TRUE;
561        }
562      return FALSE;
563    }
564
565  while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
566    {
567      if (!skip_input_bytes (rstrm, rstrm->fbtbc))
568        return FALSE;
569      rstrm->fbtbc = 0;
570      if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
571        return FALSE;
572    }
573  rstrm->last_frag = FALSE;
574  return TRUE;
575}
576
577/*
578 * Look ahead function.
579 * Returns TRUE iff there is no more input in the buffer
580 * after consuming the rest of the current record.
581 */
582bool_t
583xdrrec_eof (XDR * xdrs)
584{
585  RECSTREAM *rstrm = (RECSTREAM *) (xdrs->x_private);
586
587  while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
588    {
589      if (!skip_input_bytes (rstrm, rstrm->fbtbc))
590        return TRUE;
591      rstrm->fbtbc = 0;
592      if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
593        return TRUE;
594    }
595  if (rstrm->in_finger == rstrm->in_boundry)
596    return TRUE;
597  return FALSE;
598}
599
600/*
601 * The client must tell the package when an end-of-record has occurred.
602 * The second paraemters tells whether the record should be flushed to the
603 * (output) tcp stream.  (This let's the package support batched or
604 * pipelined procedure calls.)  TRUE => immmediate flush to tcp connection.
605 */
606bool_t
607xdrrec_endofrecord (XDR * xdrs,
608        bool_t sendnow)
609{
610  RECSTREAM *rstrm = (RECSTREAM *) (xdrs->x_private);
611  u_long len;                   /* fragment length */
612
613  if (sendnow || rstrm->frag_sent ||
614      ((u_long) rstrm->out_finger + sizeof (u_int32_t) >=
615       (u_long) rstrm->out_boundry))
616    {
617      rstrm->frag_sent = FALSE;
618      return (flush_out (rstrm, TRUE));
619    }
620  len = (u_long) (rstrm->out_finger) - (u_long) (rstrm->frag_header) -
621    sizeof (u_int32_t);
622  *(rstrm->frag_header) = htonl ((u_int32_t) len | LAST_FRAG);
623  rstrm->frag_header = (u_int32_t *) (void *) rstrm->out_finger;
624  rstrm->out_finger += sizeof (u_int32_t);
625  return TRUE;
626}
627
628/*
629 * Fill the stream buffer with a record for a non-blocking connection.
630 * Return true if a record is available in the buffer, false if not.
631 */
632bool_t
633__xdrrec_getrec (XDR * xdrs,
634        enum xprt_stat * statp,
635        bool_t expectdata)
636{
637  RECSTREAM *rstrm = (RECSTREAM *) (xdrs->x_private);
638  ssize_t n;
639  int fraglen;
640
641  if (!rstrm->in_haveheader)
642    {
643      n = rstrm->readit (rstrm->tcp_handle, rstrm->in_hdrp,
644                         (int) sizeof (rstrm->in_header) - rstrm->in_hdrlen);
645      if (n == 0)
646        {
647          *statp = expectdata ? XPRT_DIED : XPRT_IDLE;
648          return FALSE;
649        }
650      if (n < 0)
651        {
652          *statp = XPRT_DIED;
653          return FALSE;
654        }
655      rstrm->in_hdrp += n;
656      rstrm->in_hdrlen += n;
657      if (rstrm->in_hdrlen < sizeof (rstrm->in_header))
658        {
659          *statp = XPRT_MOREREQS;
660          return FALSE;
661        }
662      rstrm->in_header = ntohl (rstrm->in_header);
663      fraglen = (int) (rstrm->in_header & ~LAST_FRAG);
664      if (fraglen == 0 || fraglen > rstrm->in_maxrec ||
665          (rstrm->in_reclen + fraglen) > rstrm->in_maxrec)
666        {
667          *statp = XPRT_DIED;
668          return FALSE;
669        }
670      rstrm->in_reclen += fraglen;
671      if (rstrm->in_reclen > (int)rstrm->recvsize) /* guaranteed recvsize < INT_MAX */
672        realloc_stream (rstrm, rstrm->in_reclen);
673      if (rstrm->in_header & LAST_FRAG)
674        {
675          rstrm->in_header &= ~LAST_FRAG;
676          rstrm->last_frag = TRUE;
677        }
678      /*
679       * We can only reasonably expect to read once from a
680       * non-blocking stream. Reading the fragment header
681       * may have drained the stream.
682       */
683      expectdata = FALSE;
684    }
685
686  n = rstrm->readit (rstrm->tcp_handle,
687                     rstrm->in_base + rstrm->in_received,
688                     (rstrm->in_reclen - rstrm->in_received));
689
690  if (n < 0)
691    {
692      *statp = XPRT_DIED;
693      return FALSE;
694    }
695
696  if (n == 0)
697    {
698      *statp = expectdata ? XPRT_DIED : XPRT_IDLE;
699      return FALSE;
700    }
701
702  rstrm->in_received += n;
703
704  if (rstrm->in_received == rstrm->in_reclen)
705    {
706      rstrm->in_haveheader = FALSE;
707      rstrm->in_hdrp = (char *) (void *) &rstrm->in_header;
708      rstrm->in_hdrlen = 0;
709      if (rstrm->last_frag)
710        {
711          rstrm->fbtbc = rstrm->in_reclen;
712          rstrm->in_boundry = rstrm->in_base + rstrm->in_reclen;
713          rstrm->in_finger = rstrm->in_base;
714          rstrm->in_reclen = rstrm->in_received = 0;
715          *statp = XPRT_MOREREQS;
716          return TRUE;
717        }
718    }
719
720  *statp = XPRT_MOREREQS;
721  return FALSE;
722}
723
724bool_t
725__xdrrec_setnonblock (XDR * xdrs,
726        int maxrec)
727{
728  RECSTREAM *rstrm = (RECSTREAM *) (xdrs->x_private);
729
730  rstrm->nonblock = TRUE;
731  if (maxrec == 0)
732    maxrec = rstrm->recvsize;
733  rstrm->in_maxrec = maxrec;
734  return TRUE;
735}
736
737/*
738 * Internal useful routines
739 */
740static bool_t
741flush_out (RECSTREAM * rstrm,
742        bool_t eor)
743{
744  u_int32_t eormask = (eor == TRUE) ? LAST_FRAG : 0;
745  u_int32_t len = (u_int32_t) ((u_long) (rstrm->out_finger) -
746                               (u_long) (rstrm->frag_header) -
747                               sizeof (u_int32_t));
748
749  *(rstrm->frag_header) = htonl (len | eormask);
750  len = (u_int32_t) ((u_long) (rstrm->out_finger) -
751                     (u_long) (rstrm->out_base));
752  if ((*(rstrm->writeit)) (rstrm->tcp_handle, rstrm->out_base, (int) len)
753      != (int) len)
754    return FALSE;
755  rstrm->frag_header = (u_int32_t *) (void *) rstrm->out_base;
756  rstrm->out_finger = (char *) rstrm->out_base + sizeof (u_int32_t);
757  return TRUE;
758}
759
760static bool_t                   /* knows nothing about records!  Only about input buffers */
761fill_input_buf (RECSTREAM * rstrm)
762{
763  char *where;
764  u_int32_t i;
765  int len;
766
767  if (rstrm->nonblock)
768    return FALSE;
769
770  where = rstrm->in_base;
771  i = (u_int32_t) ((u_long) rstrm->in_boundry % BYTES_PER_XDR_UNIT);
772  where += i;
773  len = (u_int32_t) (rstrm->in_size - i);
774  if ((len = (*(rstrm->readit)) (rstrm->tcp_handle, where, len)) == -1)
775    return FALSE;
776  rstrm->in_finger = where;
777  where += len;
778  rstrm->in_boundry = where;
779  return TRUE;
780}
781
782static bool_t                   /* knows nothing about records!  Only about input buffers */
783get_input_bytes (RECSTREAM * rstrm,
784        char *addr,
785        size_t len)
786{
787  size_t current;
788
789  if (rstrm->nonblock)
790    {
791      if ((rstrm->in_boundry < rstrm->in_finger) ||               /* <-- should never happen, but avoids... */
792         (len > (size_t) (rstrm->in_boundry - rstrm->in_finger))) /* <-- signed/unsigned comparison */
793        return FALSE;
794      memcpy (addr, rstrm->in_finger, (size_t) len);
795      rstrm->in_finger += len;
796      return TRUE;
797    }
798
799  while (len > 0)
800    {
801      current = (size_t) ((long) rstrm->in_boundry - (long) rstrm->in_finger);
802      if (current == 0)
803        {
804          if (!fill_input_buf (rstrm))
805            return FALSE;
806          continue;
807        }
808      current = (len < current) ? len : current;
809      memmove (addr, rstrm->in_finger, current);
810      rstrm->in_finger += current;
811      addr += current;
812      len -= current;
813    }
814  return TRUE;
815}
816
817static bool_t                   /* next two bytes of the input stream are treated as a header */
818set_input_fragment (RECSTREAM * rstrm)
819{
820  u_int32_t header;
821
822  if (rstrm->nonblock)
823    return FALSE;
824  if (!get_input_bytes (rstrm, (char *) (void *) &header, sizeof (header)))
825    return FALSE;
826  header = ntohl (header);
827  rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
828  /*
829   * Sanity check. Try not to accept wildly incorrect
830   * record sizes. Unfortunately, the only record size
831   * we can positively identify as being 'wildly incorrect'
832   * is zero. Ridiculously large record sizes may look wrong,
833   * but we don't have any way to be certain that they aren't
834   * what the client actually intended to send us.
835   */
836  if (header == 0)
837    return FALSE;
838  rstrm->fbtbc = header & (~LAST_FRAG);
839  return TRUE;
840}
841
842static bool_t                   /* consumes input bytes; knows nothing about records! */
843skip_input_bytes (RECSTREAM * rstrm,
844        long cnt)
845{
846  size_t current;
847
848  while (cnt > 0)
849    {
850      current = (size_t) ((long) rstrm->in_boundry - (long) rstrm->in_finger);
851      if (current == 0)
852        {
853          if (!fill_input_buf (rstrm))
854            return FALSE;
855          continue;
856        }
857      /* in this loop (prior to last line), cnt > 0 so size_t cast is safe*/
858      current = (size_t) (((size_t)cnt < current) ? (size_t)cnt : current);
859      rstrm->in_finger += current;
860      cnt -= current;
861    }
862  return TRUE;
863}
864
865static u_int
866fix_buf_size (u_int s)
867{
868
869  if (s < 100)
870    s = 4000;
871  return (RNDUP (s));
872}
873
874/*
875 * Reallocate the input buffer for a non-block stream.
876 */
877static bool_t
878realloc_stream (RECSTREAM * rstrm,
879        int size)
880{
881  ptrdiff_t diff;
882  char *buf;
883  char *buf_algn;
884
885  if (size > (int)rstrm->recvsize) /* recvsize guaranteed < INT_MAX */
886    {
887      buf = realloc (rstrm->in_buffer, (size_t) (size + BYTES_PER_XDR_UNIT));
888      if (buf == NULL)
889        return FALSE;
890      for (buf_algn = buf;
891           (long) buf_algn % BYTES_PER_XDR_UNIT != 0; buf_algn++)
892        ;
893      diff = buf_algn - rstrm->in_base;
894      rstrm->in_finger += diff;
895      rstrm->in_base = buf_algn;
896      rstrm->in_buffer = buf;
897      rstrm->in_boundry = buf_algn + size;
898      rstrm->recvsize = size;
899      rstrm->in_size = size;
900    }
901
902  return TRUE;
903}
904
Note: See TracBrowser for help on using the repository browser.