xdr_rec.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. /*
  2. * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
  3. * unrestricted use provided that this legend is included on all tape
  4. * media and as a part of the software program in whole or part. Users
  5. * may copy or modify Sun RPC without charge, but are not authorized
  6. * to license or distribute it to anyone else except as part of a product or
  7. * program developed by the user.
  8. *
  9. * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
  10. * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
  11. * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
  12. *
  13. * Sun RPC is provided with no support and without any obligation on the
  14. * part of Sun Microsystems, Inc. to assist in its use, correction,
  15. * modification or enhancement.
  16. *
  17. * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
  18. * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
  19. * OR ANY PART THEREOF.
  20. *
  21. * In no event will Sun Microsystems, Inc. be liable for any lost revenue
  22. * or profits or other special, indirect and consequential damages, even if
  23. * Sun has been advised of the possibility of such damages.
  24. *
  25. * Sun Microsystems, Inc.
  26. * 2550 Garcia Avenue
  27. * Mountain View, California 94043
  28. */
  29. /*
  30. * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
  31. * layer above tcp (for rpc's use).
  32. *
  33. * Copyright (C) 1984, Sun Microsystems, Inc.
  34. *
  35. * These routines interface XDRSTREAMS to a tcp/ip connection.
  36. * There is a record marking layer between the xdr stream
  37. * and the tcp transport level. A record is composed on one or more
  38. * record fragments. A record fragment is a thirty-two bit header followed
  39. * by n bytes of data, where n is contained in the header. The header
  40. * is represented as a htonl(u_long). The high order bit encodes
  41. * whether or not the fragment is the last fragment of the record
  42. * (1 => fragment is last, 0 => more fragments to follow.
  43. * The other 31 bits encode the byte length of the fragment.
  44. */
  45. #define __FORCE_GLIBC
  46. #include <features.h>
  47. #include <stdio.h>
  48. #include <string.h>
  49. #include <unistd.h>
  50. #include <rpc/rpc.h>
  51. #ifdef USE_IN_LIBIO
  52. # include <wchar.h>
  53. # include <libio/iolibio.h>
  54. # define fputs(s, f) _IO_fputs (s, f)
  55. #endif
  56. static bool_t xdrrec_getbytes (XDR *, caddr_t, u_int);
  57. static bool_t xdrrec_putbytes (XDR *, const char *, u_int);
  58. static bool_t xdrrec_getint32 (XDR *, int32_t *);
  59. static bool_t xdrrec_putint32 (XDR *, const int32_t *);
  60. #if ULONG_MAX != 0xffffffff
  61. static bool_t xdrrec_getlong (XDR *, long *);
  62. static bool_t xdrrec_putlong (XDR *, const long *);
  63. #endif
  64. static u_int xdrrec_getpos (const XDR *);
  65. static bool_t xdrrec_setpos (XDR *, u_int);
  66. static int32_t *xdrrec_inline (XDR *, u_int);
  67. static void xdrrec_destroy (XDR *);
  68. static const struct xdr_ops xdrrec_ops = {
  69. #if ULONG_MAX == 0xffffffff
  70. (bool_t (*)(XDR *, long *)) xdrrec_getint32,
  71. (bool_t (*)(XDR *, const long *)) xdrrec_putint32,
  72. #else
  73. xdrrec_getlong,
  74. xdrrec_putlong,
  75. #endif
  76. xdrrec_getbytes,
  77. xdrrec_putbytes,
  78. xdrrec_getpos,
  79. xdrrec_setpos,
  80. xdrrec_inline,
  81. xdrrec_destroy,
  82. xdrrec_getint32,
  83. xdrrec_putint32
  84. };
  85. /*
  86. * A record is composed of one or more record fragments.
  87. * A record fragment is a two-byte header followed by zero to
  88. * 2**32-1 bytes. The header is treated as a long unsigned and is
  89. * encode/decoded to the network via htonl/ntohl. The low order 31 bits
  90. * are a byte count of the fragment. The highest order bit is a boolean:
  91. * 1 => this fragment is the last fragment of the record,
  92. * 0 => this fragment is followed by more fragment(s).
  93. *
  94. * The fragment/record machinery is not general; it is constructed to
  95. * meet the needs of xdr and rpc based on tcp.
  96. */
  97. #define LAST_FRAG (1UL << 31)
  98. typedef struct rec_strm
  99. {
  100. caddr_t tcp_handle;
  101. caddr_t the_buffer;
  102. /*
  103. * out-going bits
  104. */
  105. int (*writeit) (char *, char *, int);
  106. caddr_t out_base; /* output buffer (points to frag header) */
  107. caddr_t out_finger; /* next output position */
  108. caddr_t out_boundry; /* data cannot up to this address */
  109. u_int32_t *frag_header; /* beginning of curren fragment */
  110. bool_t frag_sent; /* true if buffer sent in middle of record */
  111. /*
  112. * in-coming bits
  113. */
  114. int (*readit) (char *, char *, int);
  115. u_long in_size; /* fixed size of the input buffer */
  116. caddr_t in_base;
  117. caddr_t in_finger; /* location of next byte to be had */
  118. caddr_t in_boundry; /* can read up to this location */
  119. long fbtbc; /* fragment bytes to be consumed */
  120. bool_t last_frag;
  121. u_int sendsize;
  122. u_int recvsize;
  123. }
  124. RECSTREAM;
  125. static u_int fix_buf_size (u_int) internal_function;
  126. static bool_t skip_input_bytes (RECSTREAM *, long) internal_function;
  127. static bool_t flush_out (RECSTREAM *, bool_t) internal_function;
  128. static bool_t set_input_fragment (RECSTREAM *) internal_function;
  129. static bool_t get_input_bytes (RECSTREAM *, caddr_t, int) internal_function;
  130. /*
  131. * Create an xdr handle for xdrrec
  132. * xdrrec_create fills in xdrs. Sendsize and recvsize are
  133. * send and recv buffer sizes (0 => use default).
  134. * tcp_handle is an opaque handle that is passed as the first parameter to
  135. * the procedures readit and writeit. Readit and writeit are read and
  136. * write respectively. They are like the system
  137. * calls expect that they take an opaque handle rather than an fd.
  138. */
  139. void
  140. xdrrec_create (XDR *xdrs, u_int sendsize,
  141. u_int recvsize, caddr_t tcp_handle,
  142. int (*readit) (char *, char *, int),
  143. int (*writeit) (char *, char *, int))
  144. {
  145. RECSTREAM *rstrm = (RECSTREAM *) mem_alloc (sizeof (RECSTREAM));
  146. caddr_t tmp;
  147. char *buf;
  148. sendsize = fix_buf_size (sendsize);
  149. recvsize = fix_buf_size (recvsize);
  150. buf = mem_alloc (sendsize + recvsize + BYTES_PER_XDR_UNIT);
  151. if (rstrm == NULL || buf == NULL)
  152. {
  153. #ifdef USE_IN_LIBIO
  154. if (_IO_fwide (stderr, 0) > 0)
  155. (void) fwprintf (stderr, L"%s", _("xdrrec_create: out of memory\n"));
  156. else
  157. #endif
  158. (void) fputs (_("xdrrec_create: out of memory\n"), stderr);
  159. mem_free (rstrm, sizeof (RECSTREAM));
  160. mem_free (buf, sendsize + recvsize + BYTES_PER_XDR_UNIT);
  161. /*
  162. * This is bad. Should rework xdrrec_create to
  163. * return a handle, and in this case return NULL
  164. */
  165. return;
  166. }
  167. /*
  168. * adjust sizes and allocate buffer quad byte aligned
  169. */
  170. rstrm->sendsize = sendsize;
  171. rstrm->recvsize = recvsize;
  172. rstrm->the_buffer = buf;
  173. tmp = rstrm->the_buffer;
  174. if ((size_t)tmp % BYTES_PER_XDR_UNIT)
  175. tmp += BYTES_PER_XDR_UNIT - (size_t)tmp % BYTES_PER_XDR_UNIT;
  176. rstrm->out_base = tmp;
  177. rstrm->in_base = tmp + sendsize;
  178. /*
  179. * now the rest ...
  180. */
  181. /* We have to add the const since the `struct xdr_ops' in `struct XDR'
  182. is not `const'. */
  183. xdrs->x_ops = (struct xdr_ops *) &xdrrec_ops;
  184. xdrs->x_private = (caddr_t) rstrm;
  185. rstrm->tcp_handle = tcp_handle;
  186. rstrm->readit = readit;
  187. rstrm->writeit = writeit;
  188. rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
  189. rstrm->frag_header = (u_int32_t *) rstrm->out_base;
  190. rstrm->out_finger += 4;
  191. rstrm->out_boundry += sendsize;
  192. rstrm->frag_sent = FALSE;
  193. rstrm->in_size = recvsize;
  194. rstrm->in_boundry = rstrm->in_base;
  195. rstrm->in_finger = (rstrm->in_boundry += recvsize);
  196. rstrm->fbtbc = 0;
  197. rstrm->last_frag = TRUE;
  198. }
  199. libc_hidden_def(xdrrec_create)
  200. /*
  201. * The routines defined below are the xdr ops which will go into the
  202. * xdr handle filled in by xdrrec_create.
  203. */
  204. static bool_t
  205. xdrrec_getint32 (XDR *xdrs, int32_t *ip)
  206. {
  207. RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
  208. int32_t *bufip = (int32_t *) rstrm->in_finger;
  209. int32_t mylong;
  210. /* first try the inline, fast case */
  211. if (rstrm->fbtbc >= BYTES_PER_XDR_UNIT &&
  212. rstrm->in_boundry - (char *) bufip >= BYTES_PER_XDR_UNIT)
  213. {
  214. *ip = ntohl (*bufip);
  215. rstrm->fbtbc -= BYTES_PER_XDR_UNIT;
  216. rstrm->in_finger += BYTES_PER_XDR_UNIT;
  217. }
  218. else
  219. {
  220. if (!xdrrec_getbytes (xdrs, (caddr_t) &mylong,
  221. BYTES_PER_XDR_UNIT))
  222. return FALSE;
  223. *ip = ntohl (mylong);
  224. }
  225. return TRUE;
  226. }
  227. #if ULONG_MAX != 0xffffffff
  228. static bool_t
  229. xdrrec_getlong (XDR *xdrs, long *lp)
  230. {
  231. int32_t v;
  232. bool_t r = xdrrec_getint32 (xdrs, &v);
  233. *lp = v;
  234. return r;
  235. }
  236. #endif
  237. static bool_t
  238. xdrrec_putint32 (XDR *xdrs, const int32_t *ip)
  239. {
  240. RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
  241. int32_t *dest_ip = (int32_t *) rstrm->out_finger;
  242. if ((rstrm->out_finger += BYTES_PER_XDR_UNIT) > rstrm->out_boundry)
  243. {
  244. /*
  245. * this case should almost never happen so the code is
  246. * inefficient
  247. */
  248. rstrm->out_finger -= BYTES_PER_XDR_UNIT;
  249. rstrm->frag_sent = TRUE;
  250. if (!flush_out (rstrm, FALSE))
  251. return FALSE;
  252. dest_ip = (int32_t *) rstrm->out_finger;
  253. rstrm->out_finger += BYTES_PER_XDR_UNIT;
  254. }
  255. *dest_ip = htonl (*ip);
  256. return TRUE;
  257. }
  258. #if ULONG_MAX != 0xffffffff
  259. static bool_t
  260. xdrrec_putlong (XDR *xdrs, const long *lp)
  261. {
  262. int32_t v = *lp;
  263. return xdrrec_putint32 (xdrs, &v);
  264. }
  265. #endif
  266. static bool_t /* must manage buffers, fragments, and records */
  267. xdrrec_getbytes (XDR *xdrs, caddr_t addr, u_int len)
  268. {
  269. RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
  270. u_int current;
  271. while (len > 0)
  272. {
  273. current = rstrm->fbtbc;
  274. if (current == 0)
  275. {
  276. if (rstrm->last_frag)
  277. return FALSE;
  278. if (!set_input_fragment (rstrm))
  279. return FALSE;
  280. continue;
  281. }
  282. current = (len < current) ? len : current;
  283. if (!get_input_bytes (rstrm, addr, current))
  284. return FALSE;
  285. addr += current;
  286. rstrm->fbtbc -= current;
  287. len -= current;
  288. }
  289. return TRUE;
  290. }
  291. static bool_t
  292. xdrrec_putbytes (XDR *xdrs, const char *addr, u_int len)
  293. {
  294. RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
  295. u_int current;
  296. while (len > 0)
  297. {
  298. current = rstrm->out_boundry - rstrm->out_finger;
  299. current = (len < current) ? len : current;
  300. memcpy (rstrm->out_finger, addr, current);
  301. rstrm->out_finger += current;
  302. addr += current;
  303. len -= current;
  304. if (rstrm->out_finger == rstrm->out_boundry && len > 0)
  305. {
  306. rstrm->frag_sent = TRUE;
  307. if (!flush_out (rstrm, FALSE))
  308. return FALSE;
  309. }
  310. }
  311. return TRUE;
  312. }
  313. static u_int
  314. xdrrec_getpos (const XDR *xdrs)
  315. {
  316. RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
  317. long pos;
  318. pos = lseek ((int) (long) rstrm->tcp_handle, (long) 0, 1);
  319. if (pos != -1)
  320. switch (xdrs->x_op)
  321. {
  322. case XDR_ENCODE:
  323. pos += rstrm->out_finger - rstrm->out_base;
  324. break;
  325. case XDR_DECODE:
  326. pos -= rstrm->in_boundry - rstrm->in_finger;
  327. break;
  328. default:
  329. pos = (u_int) - 1;
  330. break;
  331. }
  332. return (u_int) pos;
  333. }
  334. static bool_t
  335. xdrrec_setpos (XDR *xdrs, u_int pos)
  336. {
  337. RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
  338. u_int currpos = xdrrec_getpos (xdrs);
  339. int delta = currpos - pos;
  340. caddr_t newpos;
  341. if ((int) currpos != -1)
  342. switch (xdrs->x_op)
  343. {
  344. case XDR_ENCODE:
  345. newpos = rstrm->out_finger - delta;
  346. if (newpos > (caddr_t) rstrm->frag_header &&
  347. newpos < rstrm->out_boundry)
  348. {
  349. rstrm->out_finger = newpos;
  350. return TRUE;
  351. }
  352. break;
  353. case XDR_DECODE:
  354. newpos = rstrm->in_finger - delta;
  355. if ((delta < (int) (rstrm->fbtbc)) &&
  356. (newpos <= rstrm->in_boundry) &&
  357. (newpos >= rstrm->in_base))
  358. {
  359. rstrm->in_finger = newpos;
  360. rstrm->fbtbc -= delta;
  361. return TRUE;
  362. }
  363. break;
  364. default:
  365. break;
  366. }
  367. return FALSE;
  368. }
  369. static int32_t *
  370. xdrrec_inline (XDR *xdrs, u_int len)
  371. {
  372. RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
  373. int32_t *buf = NULL;
  374. switch (xdrs->x_op)
  375. {
  376. case XDR_ENCODE:
  377. if ((rstrm->out_finger + len) <= rstrm->out_boundry)
  378. {
  379. buf = (int32_t *) rstrm->out_finger;
  380. rstrm->out_finger += len;
  381. }
  382. break;
  383. case XDR_DECODE:
  384. if ((len <= rstrm->fbtbc) &&
  385. ((rstrm->in_finger + len) <= rstrm->in_boundry))
  386. {
  387. buf = (int32_t *) rstrm->in_finger;
  388. rstrm->fbtbc -= len;
  389. rstrm->in_finger += len;
  390. }
  391. break;
  392. default:
  393. break;
  394. }
  395. return buf;
  396. }
  397. static void
  398. xdrrec_destroy (XDR *xdrs)
  399. {
  400. RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
  401. mem_free (rstrm->the_buffer,
  402. rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
  403. mem_free ((caddr_t) rstrm, sizeof (RECSTREAM));
  404. }
  405. /*
  406. * Exported routines to manage xdr records
  407. */
  408. /*
  409. * Before reading (deserializing from the stream, one should always call
  410. * this procedure to guarantee proper record alignment.
  411. */
  412. bool_t
  413. xdrrec_skiprecord (XDR *xdrs)
  414. {
  415. RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
  416. while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
  417. {
  418. if (!skip_input_bytes (rstrm, rstrm->fbtbc))
  419. return FALSE;
  420. rstrm->fbtbc = 0;
  421. if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
  422. return FALSE;
  423. }
  424. rstrm->last_frag = FALSE;
  425. return TRUE;
  426. }
  427. libc_hidden_def(xdrrec_skiprecord)
  428. /*
  429. * Lookahead function.
  430. * Returns TRUE iff there is no more input in the buffer
  431. * after consuming the rest of the current record.
  432. */
  433. bool_t
  434. xdrrec_eof (XDR *xdrs)
  435. {
  436. RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
  437. while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
  438. {
  439. if (!skip_input_bytes (rstrm, rstrm->fbtbc))
  440. return TRUE;
  441. rstrm->fbtbc = 0;
  442. if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
  443. return TRUE;
  444. }
  445. if (rstrm->in_finger == rstrm->in_boundry)
  446. return TRUE;
  447. return FALSE;
  448. }
  449. libc_hidden_def(xdrrec_eof)
  450. /*
  451. * The client must tell the package when an end-of-record has occurred.
  452. * The second parameter tells whether the record should be flushed to the
  453. * (output) tcp stream. (This lets the package support batched or
  454. * pipelined procedure calls.) TRUE => immediate flush to tcp connection.
  455. */
  456. bool_t
  457. xdrrec_endofrecord (XDR *xdrs, bool_t sendnow)
  458. {
  459. RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
  460. u_long len; /* fragment length */
  461. if (sendnow || rstrm->frag_sent
  462. || rstrm->out_finger + BYTES_PER_XDR_UNIT >= rstrm->out_boundry)
  463. {
  464. rstrm->frag_sent = FALSE;
  465. return flush_out (rstrm, TRUE);
  466. }
  467. len = (rstrm->out_finger - (char *) rstrm->frag_header
  468. - BYTES_PER_XDR_UNIT);
  469. *rstrm->frag_header = htonl ((u_long) len | LAST_FRAG);
  470. rstrm->frag_header = (u_int32_t *) rstrm->out_finger;
  471. rstrm->out_finger += BYTES_PER_XDR_UNIT;
  472. return TRUE;
  473. }
  474. libc_hidden_def(xdrrec_endofrecord)
  475. /*
  476. * Internal useful routines
  477. */
  478. static bool_t
  479. internal_function
  480. flush_out (RECSTREAM *rstrm, bool_t eor)
  481. {
  482. u_long eormask = (eor == TRUE) ? LAST_FRAG : 0;
  483. u_long len = (rstrm->out_finger - (char *) rstrm->frag_header
  484. - BYTES_PER_XDR_UNIT);
  485. *rstrm->frag_header = htonl (len | eormask);
  486. len = rstrm->out_finger - rstrm->out_base;
  487. if ((*(rstrm->writeit)) (rstrm->tcp_handle, rstrm->out_base, (int) len)
  488. != (int) len)
  489. return FALSE;
  490. rstrm->frag_header = (u_int32_t *) rstrm->out_base;
  491. rstrm->out_finger = (caddr_t) rstrm->out_base + BYTES_PER_XDR_UNIT;
  492. return TRUE;
  493. }
  494. static bool_t /* knows nothing about records! Only about input buffers */
  495. fill_input_buf (RECSTREAM *rstrm)
  496. {
  497. caddr_t where;
  498. size_t i;
  499. int len;
  500. where = rstrm->in_base;
  501. i = (size_t) rstrm->in_boundry % BYTES_PER_XDR_UNIT;
  502. where += i;
  503. len = rstrm->in_size - i;
  504. if ((len = (*(rstrm->readit)) (rstrm->tcp_handle, where, len)) == -1)
  505. return FALSE;
  506. rstrm->in_finger = where;
  507. where += len;
  508. rstrm->in_boundry = where;
  509. return TRUE;
  510. }
  511. static bool_t /* knows nothing about records! Only about input buffers */
  512. internal_function
  513. get_input_bytes (RECSTREAM *rstrm, caddr_t addr, int len)
  514. {
  515. int current;
  516. while (len > 0)
  517. {
  518. current = rstrm->in_boundry - rstrm->in_finger;
  519. if (current == 0)
  520. {
  521. if (!fill_input_buf (rstrm))
  522. return FALSE;
  523. continue;
  524. }
  525. current = (len < current) ? len : current;
  526. memcpy (addr, rstrm->in_finger, current);
  527. rstrm->in_finger += current;
  528. addr += current;
  529. len -= current;
  530. }
  531. return TRUE;
  532. }
  533. static bool_t /* next two bytes of the input stream are treated as a header */
  534. internal_function
  535. set_input_fragment (RECSTREAM *rstrm)
  536. {
  537. uint32_t header;
  538. if (! get_input_bytes (rstrm, (caddr_t)&header, BYTES_PER_XDR_UNIT))
  539. return FALSE;
  540. header = ntohl (header);
  541. rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
  542. /*
  543. * Sanity check. Try not to accept wildly incorrect fragment
  544. * sizes. Unfortunately, only a size of zero can be identified as
  545. * 'wildely incorrect', and this only, if it is not the last
  546. * fragment of a message. Ridiculously large fragment sizes may look
  547. * wrong, but we don't have any way to be certain that they aren't
  548. * what the client actually intended to send us. Many existing RPC
  549. * implementations may sent a fragment of size zero as the last
  550. * fragment of a message.
  551. */
  552. if (header == 0)
  553. return FALSE;
  554. rstrm->fbtbc = header & ~LAST_FRAG;
  555. return TRUE;
  556. }
  557. static bool_t /* consumes input bytes; knows nothing about records! */
  558. internal_function
  559. skip_input_bytes (RECSTREAM *rstrm, long cnt)
  560. {
  561. int current;
  562. while (cnt > 0)
  563. {
  564. current = rstrm->in_boundry - rstrm->in_finger;
  565. if (current == 0)
  566. {
  567. if (!fill_input_buf (rstrm))
  568. return FALSE;
  569. continue;
  570. }
  571. current = (cnt < current) ? cnt : current;
  572. rstrm->in_finger += current;
  573. cnt -= current;
  574. }
  575. return TRUE;
  576. }
  577. static u_int
  578. internal_function
  579. fix_buf_size (u_int s)
  580. {
  581. if (s < 100)
  582. s = 4000;
  583. return RNDUP (s);
  584. }