Back to index

glibc  2.9
xdr_rec.c
Go to the documentation of this file.
00001 /*
00002  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
00003  * unrestricted use provided that this legend is included on all tape
00004  * media and as a part of the software program in whole or part.  Users
00005  * may copy or modify Sun RPC without charge, but are not authorized
00006  * to license or distribute it to anyone else except as part of a product or
00007  * program developed by the user.
00008  *
00009  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
00010  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
00011  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
00012  *
00013  * Sun RPC is provided with no support and without any obligation on the
00014  * part of Sun Microsystems, Inc. to assist in its use, correction,
00015  * modification or enhancement.
00016  *
00017  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
00018  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
00019  * OR ANY PART THEREOF.
00020  *
00021  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
00022  * or profits or other special, indirect and consequential damages, even if
00023  * Sun has been advised of the possibility of such damages.
00024  *
00025  * Sun Microsystems, Inc.
00026  * 2550 Garcia Avenue
00027  * Mountain View, California  94043
00028  */
00029 
00030 /*
00031  * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
00032  * layer above tcp (for rpc's use).
00033  *
00034  * Copyright (C) 1984, Sun Microsystems, Inc.
00035  *
00036  * These routines interface XDRSTREAMS to a tcp/ip connection.
00037  * There is a record marking layer between the xdr stream
00038  * and the tcp transport level.  A record is composed on one or more
00039  * record fragments.  A record fragment is a thirty-two bit header followed
00040  * by n bytes of data, where n is contained in the header.  The header
00041  * is represented as a htonl(u_long).  The high order bit encodes
00042  * whether or not the fragment is the last fragment of the record
00043  * (1 => fragment is last, 0 => more fragments to follow.
00044  * The other 31 bits encode the byte length of the fragment.
00045  */
00046 
00047 #include <stdio.h>
00048 #include <string.h>
00049 #include <unistd.h>
00050 #include <rpc/rpc.h>
00051 #include <libintl.h>
00052 
00053 #ifdef USE_IN_LIBIO
00054 # include <wchar.h>
00055 # include <libio/iolibio.h>
00056 #endif
00057 
00058 static bool_t xdrrec_getlong (XDR *, long *);
00059 static bool_t xdrrec_putlong (XDR *, const long *);
00060 static bool_t xdrrec_getbytes (XDR *, caddr_t, u_int);
00061 static bool_t xdrrec_putbytes (XDR *, const char *, u_int);
00062 static u_int xdrrec_getpos (const XDR *);
00063 static bool_t xdrrec_setpos (XDR *, u_int);
00064 static int32_t *xdrrec_inline (XDR *, u_int);
00065 static void xdrrec_destroy (XDR *);
00066 static bool_t xdrrec_getint32 (XDR *, int32_t *);
00067 static bool_t xdrrec_putint32 (XDR *, const int32_t *);
00068 
00069 static const struct xdr_ops xdrrec_ops = {
00070   xdrrec_getlong,
00071   xdrrec_putlong,
00072   xdrrec_getbytes,
00073   xdrrec_putbytes,
00074   xdrrec_getpos,
00075   xdrrec_setpos,
00076   xdrrec_inline,
00077   xdrrec_destroy,
00078   xdrrec_getint32,
00079   xdrrec_putint32
00080 };
00081 
00082 /*
00083  * A record is composed of one or more record fragments.
00084  * A record fragment is a two-byte header followed by zero to
00085  * 2**32-1 bytes.  The header is treated as a long unsigned and is
00086  * encode/decoded to the network via htonl/ntohl.  The low order 31 bits
00087  * are a byte count of the fragment.  The highest order bit is a boolean:
00088  * 1 => this fragment is the last fragment of the record,
00089  * 0 => this fragment is followed by more fragment(s).
00090  *
00091  * The fragment/record machinery is not general;  it is constructed to
00092  * meet the needs of xdr and rpc based on tcp.
00093  */
00094 
00095 #define LAST_FRAG (1UL << 31)
00096 
00097 typedef struct rec_strm
00098   {
00099     caddr_t tcp_handle;
00100     caddr_t the_buffer;
00101     /*
00102      * out-going bits
00103      */
00104     int (*writeit) (char *, char *, int);
00105     caddr_t out_base;              /* output buffer (points to frag header) */
00106     caddr_t out_finger;            /* next output position */
00107     caddr_t out_boundry;    /* data cannot up to this address */
00108     u_int32_t *frag_header; /* beginning of curren fragment */
00109     bool_t frag_sent;              /* true if buffer sent in middle of record */
00110     /*
00111      * in-coming bits
00112      */
00113     int (*readit) (char *, char *, int);
00114     u_long in_size;         /* fixed size of the input buffer */
00115     caddr_t in_base;
00116     caddr_t in_finger;             /* location of next byte to be had */
00117     caddr_t in_boundry;            /* can read up to this location */
00118     long fbtbc;                    /* fragment bytes to be consumed */
00119     bool_t last_frag;
00120     u_int sendsize;
00121     u_int recvsize;
00122   }
00123 RECSTREAM;
00124 
00125 static u_int fix_buf_size (u_int) internal_function;
00126 static bool_t skip_input_bytes (RECSTREAM *, long) internal_function;
00127 static bool_t flush_out (RECSTREAM *, bool_t) internal_function;
00128 static bool_t set_input_fragment (RECSTREAM *) internal_function;
00129 static bool_t get_input_bytes (RECSTREAM *, caddr_t, int) internal_function;
00130 
00131 /*
00132  * Create an xdr handle for xdrrec
00133  * xdrrec_create fills in xdrs.  Sendsize and recvsize are
00134  * send and recv buffer sizes (0 => use default).
00135  * tcp_handle is an opaque handle that is passed as the first parameter to
00136  * the procedures readit and writeit.  Readit and writeit are read and
00137  * write respectively.   They are like the system
00138  * calls expect that they take an opaque handle rather than an fd.
00139  */
00140 void
00141 xdrrec_create (XDR *xdrs, u_int sendsize,
00142               u_int recvsize, caddr_t tcp_handle,
00143               int (*readit) (char *, char *, int),
00144               int (*writeit) (char *, char *, int))
00145 {
00146   RECSTREAM *rstrm = (RECSTREAM *) mem_alloc (sizeof (RECSTREAM));
00147   caddr_t tmp;
00148   char *buf;
00149 
00150   sendsize = fix_buf_size (sendsize);
00151   recvsize = fix_buf_size (recvsize);
00152   buf = mem_alloc (sendsize + recvsize + BYTES_PER_XDR_UNIT);
00153 
00154   if (rstrm == NULL || buf == NULL)
00155     {
00156       (void) __fxprintf (NULL, "%s: %s", __func__, _("out of memory\n"));
00157       mem_free (rstrm, sizeof (RECSTREAM));
00158       mem_free (buf, sendsize + recvsize + BYTES_PER_XDR_UNIT);
00159       /*
00160        *  This is bad.  Should rework xdrrec_create to
00161        *  return a handle, and in this case return NULL
00162        */
00163       return;
00164     }
00165   /*
00166    * adjust sizes and allocate buffer quad byte aligned
00167    */
00168   rstrm->sendsize = sendsize;
00169   rstrm->recvsize = recvsize;
00170   rstrm->the_buffer = buf;
00171   tmp = rstrm->the_buffer;
00172   if ((size_t)tmp % BYTES_PER_XDR_UNIT)
00173     tmp += BYTES_PER_XDR_UNIT - (size_t)tmp % BYTES_PER_XDR_UNIT;
00174   rstrm->out_base = tmp;
00175   rstrm->in_base = tmp + sendsize;
00176   /*
00177    * now the rest ...
00178    */
00179   /* We have to add the cast since the `struct xdr_ops' in `struct XDR'
00180      is not `const'.  */
00181   xdrs->x_ops = (struct xdr_ops *) &xdrrec_ops;
00182   xdrs->x_private = (caddr_t) rstrm;
00183   rstrm->tcp_handle = tcp_handle;
00184   rstrm->readit = readit;
00185   rstrm->writeit = writeit;
00186   rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
00187   rstrm->frag_header = (u_int32_t *) rstrm->out_base;
00188   rstrm->out_finger += 4;
00189   rstrm->out_boundry += sendsize;
00190   rstrm->frag_sent = FALSE;
00191   rstrm->in_size = recvsize;
00192   rstrm->in_boundry = rstrm->in_base;
00193   rstrm->in_finger = (rstrm->in_boundry += recvsize);
00194   rstrm->fbtbc = 0;
00195   rstrm->last_frag = TRUE;
00196 }
00197 INTDEF(xdrrec_create)
00198 
00199 
00200 /*
00201  * The routines defined below are the xdr ops which will go into the
00202  * xdr handle filled in by xdrrec_create.
00203  */
00204 
00205 static bool_t
00206 xdrrec_getlong (XDR *xdrs, long *lp)
00207 {
00208   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00209   int32_t *buflp = (int32_t *) rstrm->in_finger;
00210   int32_t mylong;
00211 
00212   /* first try the inline, fast case */
00213   if (rstrm->fbtbc >= BYTES_PER_XDR_UNIT &&
00214       rstrm->in_boundry - (char *) buflp >= BYTES_PER_XDR_UNIT)
00215     {
00216       *lp = (int32_t) ntohl (*buflp);
00217       rstrm->fbtbc -= BYTES_PER_XDR_UNIT;
00218       rstrm->in_finger += BYTES_PER_XDR_UNIT;
00219     }
00220   else
00221     {
00222       if (!xdrrec_getbytes (xdrs, (caddr_t) & mylong,
00223                          BYTES_PER_XDR_UNIT))
00224        return FALSE;
00225       *lp = (int32_t) ntohl (mylong);
00226     }
00227   return TRUE;
00228 }
00229 
00230 static bool_t
00231 xdrrec_putlong (XDR *xdrs, const long *lp)
00232 {
00233   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00234   int32_t *dest_lp = (int32_t *) rstrm->out_finger;
00235 
00236   if ((rstrm->out_finger += BYTES_PER_XDR_UNIT) > rstrm->out_boundry)
00237     {
00238       /*
00239        * this case should almost never happen so the code is
00240        * inefficient
00241        */
00242       rstrm->out_finger -= BYTES_PER_XDR_UNIT;
00243       rstrm->frag_sent = TRUE;
00244       if (!flush_out (rstrm, FALSE))
00245        return FALSE;
00246       dest_lp = (int32_t *) rstrm->out_finger;
00247       rstrm->out_finger += BYTES_PER_XDR_UNIT;
00248     }
00249   *dest_lp = htonl (*lp);
00250   return TRUE;
00251 }
00252 
00253 static bool_t    /* must manage buffers, fragments, and records */
00254 xdrrec_getbytes (XDR *xdrs, caddr_t addr, u_int len)
00255 {
00256   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00257   u_int current;
00258 
00259   while (len > 0)
00260     {
00261       current = rstrm->fbtbc;
00262       if (current == 0)
00263        {
00264          if (rstrm->last_frag)
00265            return FALSE;
00266          if (!set_input_fragment (rstrm))
00267            return FALSE;
00268          continue;
00269        }
00270       current = (len < current) ? len : current;
00271       if (!get_input_bytes (rstrm, addr, current))
00272        return FALSE;
00273       addr += current;
00274       rstrm->fbtbc -= current;
00275       len -= current;
00276     }
00277   return TRUE;
00278 }
00279 
00280 static bool_t
00281 xdrrec_putbytes (XDR *xdrs, const char *addr, u_int len)
00282 {
00283   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00284   u_int current;
00285 
00286   while (len > 0)
00287     {
00288       current = rstrm->out_boundry - rstrm->out_finger;
00289       current = (len < current) ? len : current;
00290       memcpy (rstrm->out_finger, addr, current);
00291       rstrm->out_finger += current;
00292       addr += current;
00293       len -= current;
00294       if (rstrm->out_finger == rstrm->out_boundry && len > 0)
00295        {
00296          rstrm->frag_sent = TRUE;
00297          if (!flush_out (rstrm, FALSE))
00298            return FALSE;
00299        }
00300     }
00301   return TRUE;
00302 }
00303 
00304 static u_int
00305 xdrrec_getpos (const XDR *xdrs)
00306 {
00307   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00308   long pos;
00309 
00310   pos = __lseek ((int) (long) rstrm->tcp_handle, (long) 0, 1);
00311   if (pos != -1)
00312     switch (xdrs->x_op)
00313       {
00314 
00315       case XDR_ENCODE:
00316        pos += rstrm->out_finger - rstrm->out_base;
00317        break;
00318 
00319       case XDR_DECODE:
00320        pos -= rstrm->in_boundry - rstrm->in_finger;
00321        break;
00322 
00323       default:
00324        pos = (u_int) - 1;
00325        break;
00326       }
00327   return (u_int) pos;
00328 }
00329 
00330 static bool_t
00331 xdrrec_setpos (XDR *xdrs, u_int pos)
00332 {
00333   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00334   u_int currpos = xdrrec_getpos (xdrs);
00335   int delta = currpos - pos;
00336   caddr_t newpos;
00337 
00338   if ((int) currpos != -1)
00339     switch (xdrs->x_op)
00340       {
00341 
00342       case XDR_ENCODE:
00343        newpos = rstrm->out_finger - delta;
00344        if (newpos > (caddr_t) rstrm->frag_header &&
00345            newpos < rstrm->out_boundry)
00346          {
00347            rstrm->out_finger = newpos;
00348            return TRUE;
00349          }
00350        break;
00351 
00352       case XDR_DECODE:
00353        newpos = rstrm->in_finger - delta;
00354        if ((delta < (int) (rstrm->fbtbc)) &&
00355            (newpos <= rstrm->in_boundry) &&
00356            (newpos >= rstrm->in_base))
00357          {
00358            rstrm->in_finger = newpos;
00359            rstrm->fbtbc -= delta;
00360            return TRUE;
00361          }
00362        break;
00363 
00364       default:
00365        break;
00366       }
00367   return FALSE;
00368 }
00369 
00370 static int32_t *
00371 xdrrec_inline (XDR *xdrs, u_int len)
00372 {
00373   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00374   int32_t *buf = NULL;
00375 
00376   switch (xdrs->x_op)
00377     {
00378 
00379     case XDR_ENCODE:
00380       if ((rstrm->out_finger + len) <= rstrm->out_boundry)
00381        {
00382          buf = (int32_t *) rstrm->out_finger;
00383          rstrm->out_finger += len;
00384        }
00385       break;
00386 
00387     case XDR_DECODE:
00388       if ((len <= rstrm->fbtbc) &&
00389          ((rstrm->in_finger + len) <= rstrm->in_boundry))
00390        {
00391          buf = (int32_t *) rstrm->in_finger;
00392          rstrm->fbtbc -= len;
00393          rstrm->in_finger += len;
00394        }
00395       break;
00396 
00397     default:
00398       break;
00399     }
00400   return buf;
00401 }
00402 
00403 static void
00404 xdrrec_destroy (XDR *xdrs)
00405 {
00406   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00407 
00408   mem_free (rstrm->the_buffer,
00409            rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
00410   mem_free ((caddr_t) rstrm, sizeof (RECSTREAM));
00411 }
00412 
00413 static bool_t
00414 xdrrec_getint32 (XDR *xdrs, int32_t *ip)
00415 {
00416   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00417   int32_t *bufip = (int32_t *) rstrm->in_finger;
00418   int32_t mylong;
00419 
00420   /* first try the inline, fast case */
00421   if (rstrm->fbtbc >= BYTES_PER_XDR_UNIT &&
00422       rstrm->in_boundry - (char *) bufip >= BYTES_PER_XDR_UNIT)
00423     {
00424       *ip = ntohl (*bufip);
00425       rstrm->fbtbc -= BYTES_PER_XDR_UNIT;
00426       rstrm->in_finger += BYTES_PER_XDR_UNIT;
00427     }
00428   else
00429     {
00430       if (!xdrrec_getbytes (xdrs, (caddr_t) &mylong,
00431                          BYTES_PER_XDR_UNIT))
00432        return FALSE;
00433       *ip = ntohl (mylong);
00434     }
00435   return TRUE;
00436 }
00437 
00438 static bool_t
00439 xdrrec_putint32 (XDR *xdrs, const int32_t *ip)
00440 {
00441   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00442   int32_t *dest_ip = (int32_t *) rstrm->out_finger;
00443 
00444   if ((rstrm->out_finger += BYTES_PER_XDR_UNIT) > rstrm->out_boundry)
00445     {
00446       /*
00447        * this case should almost never happen so the code is
00448        * inefficient
00449        */
00450       rstrm->out_finger -= BYTES_PER_XDR_UNIT;
00451       rstrm->frag_sent = TRUE;
00452       if (!flush_out (rstrm, FALSE))
00453        return FALSE;
00454       dest_ip = (int32_t *) rstrm->out_finger;
00455       rstrm->out_finger += BYTES_PER_XDR_UNIT;
00456     }
00457   *dest_ip = htonl (*ip);
00458   return TRUE;
00459 }
00460 
00461 /*
00462  * Exported routines to manage xdr records
00463  */
00464 
00465 /*
00466  * Before reading (deserializing from the stream, one should always call
00467  * this procedure to guarantee proper record alignment.
00468  */
00469 bool_t
00470 xdrrec_skiprecord (XDR *xdrs)
00471 {
00472   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00473 
00474   while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
00475     {
00476       if (!skip_input_bytes (rstrm, rstrm->fbtbc))
00477        return FALSE;
00478       rstrm->fbtbc = 0;
00479       if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
00480        return FALSE;
00481     }
00482   rstrm->last_frag = FALSE;
00483   return TRUE;
00484 }
00485 INTDEF(xdrrec_skiprecord)
00486 
00487 /*
00488  * Lookahead function.
00489  * Returns TRUE iff there is no more input in the buffer
00490  * after consuming the rest of the current record.
00491  */
00492 bool_t
00493 xdrrec_eof (XDR *xdrs)
00494 {
00495   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00496 
00497   while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
00498     {
00499       if (!skip_input_bytes (rstrm, rstrm->fbtbc))
00500        return TRUE;
00501       rstrm->fbtbc = 0;
00502       if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
00503        return TRUE;
00504     }
00505   if (rstrm->in_finger == rstrm->in_boundry)
00506     return TRUE;
00507   return FALSE;
00508 }
00509 INTDEF(xdrrec_eof)
00510 
00511 /*
00512  * The client must tell the package when an end-of-record has occurred.
00513  * The second parameter tells whether the record should be flushed to the
00514  * (output) tcp stream.  (This lets the package support batched or
00515  * pipelined procedure calls.)  TRUE => immediate flush to tcp connection.
00516  */
00517 bool_t
00518 xdrrec_endofrecord (XDR *xdrs, bool_t sendnow)
00519 {
00520   RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
00521   u_long len;        /* fragment length */
00522 
00523   if (sendnow || rstrm->frag_sent
00524       || rstrm->out_finger + BYTES_PER_XDR_UNIT >= rstrm->out_boundry)
00525     {
00526       rstrm->frag_sent = FALSE;
00527       return flush_out (rstrm, TRUE);
00528     }
00529   len = (rstrm->out_finger - (char *) rstrm->frag_header
00530         - BYTES_PER_XDR_UNIT);
00531   *rstrm->frag_header = htonl ((u_long) len | LAST_FRAG);
00532   rstrm->frag_header = (u_int32_t *) rstrm->out_finger;
00533   rstrm->out_finger += BYTES_PER_XDR_UNIT;
00534   return TRUE;
00535 }
00536 INTDEF(xdrrec_endofrecord)
00537 
00538 
00539 /*
00540  * Internal useful routines
00541  */
00542 static bool_t
00543 internal_function
00544 flush_out (RECSTREAM *rstrm, bool_t eor)
00545 {
00546   u_long eormask = (eor == TRUE) ? LAST_FRAG : 0;
00547   u_long len = (rstrm->out_finger - (char *) rstrm->frag_header
00548               - BYTES_PER_XDR_UNIT);
00549 
00550   *rstrm->frag_header = htonl (len | eormask);
00551   len = rstrm->out_finger - rstrm->out_base;
00552   if ((*(rstrm->writeit)) (rstrm->tcp_handle, rstrm->out_base, (int) len)
00553       != (int) len)
00554     return FALSE;
00555   rstrm->frag_header = (u_int32_t *) rstrm->out_base;
00556   rstrm->out_finger = (caddr_t) rstrm->out_base + BYTES_PER_XDR_UNIT;
00557   return TRUE;
00558 }
00559 
00560 static bool_t /* knows nothing about records!  Only about input buffers */
00561 fill_input_buf (RECSTREAM *rstrm)
00562 {
00563   caddr_t where;
00564   size_t i;
00565   int len;
00566 
00567   where = rstrm->in_base;
00568   i = (size_t) rstrm->in_boundry % BYTES_PER_XDR_UNIT;
00569   where += i;
00570   len = rstrm->in_size - i;
00571   if ((len = (*(rstrm->readit)) (rstrm->tcp_handle, where, len)) == -1)
00572     return FALSE;
00573   rstrm->in_finger = where;
00574   where += len;
00575   rstrm->in_boundry = where;
00576   return TRUE;
00577 }
00578 
00579 static bool_t /* knows nothing about records!  Only about input buffers */
00580 internal_function
00581 get_input_bytes (RECSTREAM *rstrm, caddr_t addr, int len)
00582 {
00583   int current;
00584 
00585   while (len > 0)
00586     {
00587       current = rstrm->in_boundry - rstrm->in_finger;
00588       if (current == 0)
00589        {
00590          if (!fill_input_buf (rstrm))
00591            return FALSE;
00592          continue;
00593        }
00594       current = (len < current) ? len : current;
00595       memcpy (addr, rstrm->in_finger, current);
00596       rstrm->in_finger += current;
00597       addr += current;
00598       len -= current;
00599     }
00600   return TRUE;
00601 }
00602 
00603 static bool_t /* next two bytes of the input stream are treated as a header */
00604 internal_function
00605 set_input_fragment (RECSTREAM *rstrm)
00606 {
00607   uint32_t header;
00608 
00609   if (! get_input_bytes (rstrm, (caddr_t)&header, BYTES_PER_XDR_UNIT))
00610     return FALSE;
00611   header = ntohl (header);
00612   rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
00613   /*
00614    * Sanity check. Try not to accept wildly incorrect fragment
00615    * sizes. Unfortunately, only a size of zero can be identified as
00616    * 'wildely incorrect', and this only, if it is not the last
00617    * fragment of a message. Ridiculously large fragment sizes may look
00618    * wrong, but we don't have any way to be certain that they aren't
00619    * what the client actually intended to send us. Many existing RPC
00620    * implementations may sent a fragment of size zero as the last
00621    * fragment of a message.
00622    */
00623   if (header == 0)
00624     return FALSE;
00625   rstrm->fbtbc = header & ~LAST_FRAG;
00626   return TRUE;
00627 }
00628 
00629 static bool_t /* consumes input bytes; knows nothing about records! */
00630 internal_function
00631 skip_input_bytes (RECSTREAM *rstrm, long cnt)
00632 {
00633   int current;
00634 
00635   while (cnt > 0)
00636     {
00637       current = rstrm->in_boundry - rstrm->in_finger;
00638       if (current == 0)
00639        {
00640          if (!fill_input_buf (rstrm))
00641            return FALSE;
00642          continue;
00643        }
00644       current = (cnt < current) ? cnt : current;
00645       rstrm->in_finger += current;
00646       cnt -= current;
00647     }
00648   return TRUE;
00649 }
00650 
00651 static u_int
00652 internal_function
00653 fix_buf_size (u_int s)
00654 {
00655   if (s < 100)
00656     s = 4000;
00657   return RNDUP (s);
00658 }