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 * @(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro 30 * @(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC 31 * $NetBSD: xdr_rec.c,v 1.18 2000/07/06 03:10:35 christos Exp $ 32 * $FreeBSD: src/lib/libc/xdr/xdr_rec.c,v 1.22 2008/03/30 09:35:04 dfr Exp $ 33 */ 34 35 /* 36 * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking" 37 * layer above tcp (for rpc's use). 38 * 39 * Copyright (C) 1984, Sun Microsystems, Inc. 40 * 41 * These routines interface XDRSTREAMS to a tcp/ip connection. 42 * There is a record marking layer between the xdr stream 43 * and the tcp transport level. A record is composed on one or more 44 * record fragments. A record fragment is a thirty-two bit header followed 45 * by n bytes of data, where n is contained in the header. The header 46 * is represented as a htonl(u_long). Thegh order bit encodes 47 * whether or not the fragment is the last fragment of the record 48 * (1 => fragment is last, 0 => more fragments to follow. 49 * The other 31 bits encode the byte length of the fragment. 50 */ 51 52 #include "namespace.h" 53 #include <sys/types.h> 54 55 #include <netinet/in.h> 56 57 #include <err.h> 58 #include <stddef.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 #include <rpc/types.h> 65 #include <rpc/xdr.h> 66 #include <rpc/auth.h> 67 #include <rpc/svc.h> 68 #include <rpc/clnt.h> 69 #include "un-namespace.h" 70 #include "rpc_com.h" 71 72 static bool_t xdrrec_getlong(XDR *, long *); 73 static bool_t xdrrec_putlong(XDR *, const long *); 74 static bool_t xdrrec_getbytes(XDR *, char *, u_int); 75 76 static bool_t xdrrec_putbytes(XDR *, const char *, u_int); 77 static u_int xdrrec_getpos(XDR *); 78 static bool_t xdrrec_setpos(XDR *, u_int); 79 static int32_t *xdrrec_inline(XDR *, u_int); 80 static void xdrrec_destroy(XDR *); 81 82 static const struct xdr_ops xdrrec_ops = { 83 xdrrec_getlong, 84 xdrrec_putlong, 85 xdrrec_getbytes, 86 xdrrec_putbytes, 87 xdrrec_getpos, 88 xdrrec_setpos, 89 xdrrec_inline, 90 xdrrec_destroy, 91 NULL 92 }; 93 94 /* 95 * A record is composed of one or more record fragments. 96 * A record fragment is a four-byte header followed by zero to 97 * 2**32-1 bytes. The header is treated as an unsigned long and is 98 * encode/decoded to the network via htonl/ntohl. The low order 31 bits 99 * are a byte count of the fragment. The highest order bit is a boolean: 100 * 1 => this fragment is the last fragment of the record, 101 * 0 => this fragment is followed by more fragment(s). 102 * 103 * The fragment/record machinery is not general; it is constructed to 104 * meet the needs of xdr and rpc based on tcp. 105 */ 106 107 #define LAST_FRAG ((uint32_t)(1 << 31)) 108 109 typedef struct rec_strm { 110 char *tcp_handle; 111 /* 112 * out-going bits 113 */ 114 int (*writeit)(void *, void *, int); 115 char *out_base; /* output buffer (points to frag header) */ 116 char *out_finger; /* next output position */ 117 char *out_boundry; /* data cannot up to this address */ 118 uint32_t *frag_header; /* beginning of current fragment */ 119 bool_t frag_sent; /* true if buffer sent in middle of record */ 120 /* 121 * in-coming bits 122 */ 123 int (*readit)(void *, void *, int); 124 u_long in_size; /* fixed size of the input buffer */ 125 char *in_base; 126 char *in_finger; /* location of next byte to be had */ 127 char *in_boundry; /* can read up to this location */ 128 long fbtbc; /* fragment bytes to be consumed */ 129 bool_t last_frag; 130 u_int sendsize; 131 u_int recvsize; 132 133 bool_t nonblock; 134 bool_t in_haveheader; 135 uint32_t in_header; 136 char *in_hdrp; 137 int in_hdrlen; 138 int in_reclen; 139 int in_received; 140 int in_maxrec; 141 } RECSTREAM; 142 143 static u_int fix_buf_size(u_int); 144 static bool_t flush_out(RECSTREAM *, bool_t); 145 static bool_t fill_input_buf(RECSTREAM *); 146 static bool_t get_input_bytes(RECSTREAM *, char *, int); 147 static bool_t set_input_fragment(RECSTREAM *); 148 static bool_t skip_input_bytes(RECSTREAM *, long); 149 static bool_t realloc_stream(RECSTREAM *, int); 150 151 /* 152 * Create an xdr handle for xdrrec 153 * xdrrec_create fills in xdrs. Sendsize and recvsize are 154 * send and recv buffer sizes (0 => use default). 155 * tcp_handle is an opaque handle that is passed as the first parameter to 156 * the procedures readit and writeit. Readit and writeit are read and 157 * write respectively. They are like the system 158 * calls expect that they take an opaque handle rather than an fd. 159 * 160 * Parameters: 161 * readit: like read, but pass it a tcp_handle, not sock 162 * writeit: lite write, but pass it a tcp_handle, not sock 163 */ 164 void 165 xdrrec_create(XDR *xdrs, u_int sendsize, u_int recvsize, void *tcp_handle, 166 int (*readit)(void *, void *, int), 167 int (*writeit)(void *, void *, int)) 168 { 169 RECSTREAM *rstrm = mem_alloc(sizeof(RECSTREAM)); 170 171 if (rstrm == NULL) { 172 warnx("xdrrec_create: out of memory"); 173 /* 174 * This is bad. Should rework xdrrec_create to 175 * return a handle, and in this case return NULL 176 */ 177 return; 178 } 179 rstrm->sendsize = sendsize = fix_buf_size(sendsize); 180 rstrm->out_base = mem_alloc(rstrm->sendsize); 181 if (rstrm->out_base == NULL) { 182 warnx("xdrrec_create: out of memory"); 183 mem_free(rstrm, sizeof(RECSTREAM)); 184 return; 185 } 186 rstrm->recvsize = recvsize = fix_buf_size(recvsize); 187 rstrm->in_base = mem_alloc(recvsize); 188 if (rstrm->in_base == NULL) { 189 warnx("xdrrec_create: out of memory"); 190 mem_free(rstrm->out_base, sendsize); 191 mem_free(rstrm, sizeof(RECSTREAM)); 192 return; 193 } 194 /* 195 * now the rest ... 196 */ 197 xdrs->x_ops = &xdrrec_ops; 198 xdrs->x_private = rstrm; 199 rstrm->tcp_handle = tcp_handle; 200 rstrm->readit = readit; 201 rstrm->writeit = writeit; 202 rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; 203 rstrm->frag_header = (uint32_t *)(void *)rstrm->out_base; 204 rstrm->out_finger += sizeof(uint32_t); 205 rstrm->out_boundry += sendsize; 206 rstrm->frag_sent = FALSE; 207 rstrm->in_size = recvsize; 208 rstrm->in_boundry = rstrm->in_base; 209 rstrm->in_finger = (rstrm->in_boundry += recvsize); 210 rstrm->fbtbc = 0; 211 rstrm->last_frag = TRUE; 212 rstrm->in_haveheader = FALSE; 213 rstrm->in_hdrlen = 0; 214 rstrm->in_hdrp = (char *)(void *)&rstrm->in_header; 215 rstrm->nonblock = FALSE; 216 rstrm->in_reclen = 0; 217 rstrm->in_received = 0; 218 } 219 220 221 /* 222 * The routines defined below are the xdr ops which will go into the 223 * xdr handle filled in by xdrrec_create. 224 */ 225 226 static bool_t 227 xdrrec_getlong(XDR *xdrs, long *lp) 228 { 229 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 230 int32_t *buflp = (int32_t *)(void *)(rstrm->in_finger); 231 int32_t mylong; 232 233 /* first try the inline, fast case */ 234 if ((rstrm->fbtbc >= sizeof(int32_t)) && 235 (((long)rstrm->in_boundry - (long)buflp) >= sizeof(int32_t))) { 236 *lp = (long)ntohl((uint32_t)(*buflp)); 237 rstrm->fbtbc -= sizeof(int32_t); 238 rstrm->in_finger += sizeof(int32_t); 239 } else { 240 if (! xdrrec_getbytes(xdrs, (char *)(void *)&mylong, 241 sizeof(int32_t))) 242 return (FALSE); 243 *lp = (long)ntohl((uint32_t)mylong); 244 } 245 return (TRUE); 246 } 247 248 static bool_t 249 xdrrec_putlong(XDR *xdrs, const long *lp) 250 { 251 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 252 int32_t *dest_lp = ((int32_t *)(void *)(rstrm->out_finger)); 253 254 if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry) { 255 /* 256 * this case should almost never happen so the code is 257 * inefficient 258 */ 259 rstrm->out_finger -= sizeof(int32_t); 260 rstrm->frag_sent = TRUE; 261 if (! flush_out(rstrm, FALSE)) 262 return (FALSE); 263 dest_lp = ((int32_t *)(void *)(rstrm->out_finger)); 264 rstrm->out_finger += sizeof(int32_t); 265 } 266 *dest_lp = (int32_t)htonl((uint32_t)(*lp)); 267 return (TRUE); 268 } 269 270 static bool_t /* must manage buffers, fragments, and records */ 271 xdrrec_getbytes(XDR *xdrs, char *addr, u_int len) 272 { 273 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 274 int current; 275 276 while (len > 0) { 277 current = (int)rstrm->fbtbc; 278 if (current == 0) { 279 if (rstrm->last_frag) 280 return (FALSE); 281 if (! set_input_fragment(rstrm)) 282 return (FALSE); 283 continue; 284 } 285 current = (len < current) ? len : current; 286 if (! get_input_bytes(rstrm, addr, current)) 287 return (FALSE); 288 addr += current; 289 rstrm->fbtbc -= current; 290 len -= current; 291 } 292 return (TRUE); 293 } 294 295 static bool_t 296 xdrrec_putbytes(XDR *xdrs, const char *addr, u_int len) 297 { 298 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 299 size_t current; 300 301 while (len > 0) { 302 current = (size_t)((u_long)rstrm->out_boundry - 303 (u_long)rstrm->out_finger); 304 current = (len < current) ? len : current; 305 memmove(rstrm->out_finger, addr, current); 306 rstrm->out_finger += current; 307 addr += current; 308 len -= current; 309 if (rstrm->out_finger == rstrm->out_boundry) { 310 rstrm->frag_sent = TRUE; 311 if (! flush_out(rstrm, FALSE)) 312 return (FALSE); 313 } 314 } 315 return (TRUE); 316 } 317 318 static u_int 319 xdrrec_getpos(XDR *xdrs) 320 { 321 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 322 off_t pos; 323 324 pos = lseek((int)(u_long)rstrm->tcp_handle, (off_t)0, 1); 325 if (pos != -1) 326 switch (xdrs->x_op) { 327 328 case XDR_ENCODE: 329 pos += rstrm->out_finger - rstrm->out_base; 330 break; 331 332 case XDR_DECODE: 333 pos -= rstrm->in_boundry - rstrm->in_finger; 334 break; 335 336 default: 337 pos = (off_t) -1; 338 break; 339 } 340 return ((u_int) pos); 341 } 342 343 static bool_t 344 xdrrec_setpos(XDR *xdrs, u_int pos) 345 { 346 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 347 u_int currpos = xdrrec_getpos(xdrs); 348 int delta = currpos - pos; 349 char *newpos; 350 351 if ((int)currpos != -1) 352 switch (xdrs->x_op) { 353 354 case XDR_ENCODE: 355 newpos = rstrm->out_finger - delta; 356 if ((newpos > (char *)(void *)(rstrm->frag_header)) && 357 (newpos < rstrm->out_boundry)) { 358 rstrm->out_finger = newpos; 359 return (TRUE); 360 } 361 break; 362 363 case XDR_DECODE: 364 newpos = rstrm->in_finger - delta; 365 if ((delta < (int)(rstrm->fbtbc)) && 366 (newpos <= rstrm->in_boundry) && 367 (newpos >= rstrm->in_base)) { 368 rstrm->in_finger = newpos; 369 rstrm->fbtbc -= delta; 370 return (TRUE); 371 } 372 break; 373 374 case XDR_FREE: 375 break; 376 } 377 return (FALSE); 378 } 379 380 static int32_t * 381 xdrrec_inline(XDR *xdrs, u_int len) 382 { 383 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 384 int32_t *buf = NULL; 385 386 switch (xdrs->x_op) { 387 388 case XDR_ENCODE: 389 if ((rstrm->out_finger + len) <= rstrm->out_boundry) { 390 buf = (int32_t *)(void *)rstrm->out_finger; 391 rstrm->out_finger += len; 392 } 393 break; 394 395 case XDR_DECODE: 396 if ((len <= rstrm->fbtbc) && 397 ((rstrm->in_finger + len) <= rstrm->in_boundry)) { 398 buf = (int32_t *)(void *)rstrm->in_finger; 399 rstrm->fbtbc -= len; 400 rstrm->in_finger += len; 401 } 402 break; 403 case XDR_FREE: 404 break; 405 } 406 return (buf); 407 } 408 409 static void 410 xdrrec_destroy(XDR *xdrs) 411 { 412 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 413 414 mem_free(rstrm->out_base, rstrm->sendsize); 415 mem_free(rstrm->in_base, rstrm->recvsize); 416 mem_free(rstrm, sizeof(RECSTREAM)); 417 } 418 419 420 /* 421 * Exported routines to manage xdr records 422 */ 423 424 /* 425 * Before reading (deserializing from the stream, one should always call 426 * this procedure to guarantee proper record alignment. 427 */ 428 bool_t 429 xdrrec_skiprecord(XDR *xdrs) 430 { 431 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 432 enum xprt_stat xstat; 433 434 if (rstrm->nonblock) { 435 if (__xdrrec_getrec(xdrs, &xstat, FALSE)) { 436 rstrm->fbtbc = 0; 437 return TRUE; 438 } 439 if (rstrm->in_finger == rstrm->in_boundry && 440 xstat == XPRT_MOREREQS) { 441 rstrm->fbtbc = 0; 442 return TRUE; 443 } 444 return FALSE; 445 } 446 447 while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { 448 if (! skip_input_bytes(rstrm, rstrm->fbtbc)) 449 return (FALSE); 450 rstrm->fbtbc = 0; 451 if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) 452 return (FALSE); 453 } 454 rstrm->last_frag = FALSE; 455 return (TRUE); 456 } 457 458 /* 459 * Look ahead function. 460 * Returns TRUE iff there is no more input in the buffer 461 * after consuming the rest of the current record. 462 */ 463 bool_t 464 xdrrec_eof(XDR *xdrs) 465 { 466 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 467 468 while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { 469 if (! skip_input_bytes(rstrm, rstrm->fbtbc)) 470 return (TRUE); 471 rstrm->fbtbc = 0; 472 if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) 473 return (TRUE); 474 } 475 if (rstrm->in_finger == rstrm->in_boundry) 476 return (TRUE); 477 return (FALSE); 478 } 479 480 /* 481 * The client must tell the package when an end-of-record has occurred. 482 * The second paraemters tells whether the record should be flushed to the 483 * (output) tcp stream. (This let's the package support batched or 484 * pipelined procedure calls.) TRUE => immmediate flush to tcp connection. 485 */ 486 bool_t 487 xdrrec_endofrecord(XDR *xdrs, bool_t sendnow) 488 { 489 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 490 u_long len; /* fragment length */ 491 492 if (sendnow || rstrm->frag_sent || 493 ((u_long)rstrm->out_finger + sizeof(uint32_t) >= 494 (u_long)rstrm->out_boundry)) { 495 rstrm->frag_sent = FALSE; 496 return (flush_out(rstrm, TRUE)); 497 } 498 len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) - 499 sizeof(uint32_t); 500 *(rstrm->frag_header) = htonl((uint32_t)len | LAST_FRAG); 501 rstrm->frag_header = (uint32_t *)(void *)rstrm->out_finger; 502 rstrm->out_finger += sizeof(uint32_t); 503 return (TRUE); 504 } 505 506 /* 507 * Fill the stream buffer with a record for a non-blocking connection. 508 * Return true if a record is available in the buffer, false if not. 509 */ 510 bool_t 511 __xdrrec_getrec(XDR *xdrs, enum xprt_stat *statp, bool_t expectdata) 512 { 513 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 514 ssize_t n; 515 int fraglen; 516 517 if (!rstrm->in_haveheader) { 518 n = rstrm->readit(rstrm->tcp_handle, rstrm->in_hdrp, 519 (int)sizeof (rstrm->in_header) - rstrm->in_hdrlen); 520 if (n == 0) { 521 *statp = expectdata ? XPRT_DIED : XPRT_IDLE; 522 return FALSE; 523 } 524 if (n < 0) { 525 *statp = XPRT_DIED; 526 return FALSE; 527 } 528 rstrm->in_hdrp += n; 529 rstrm->in_hdrlen += n; 530 if (rstrm->in_hdrlen < sizeof (rstrm->in_header)) { 531 *statp = XPRT_MOREREQS; 532 return FALSE; 533 } 534 rstrm->in_header = ntohl(rstrm->in_header); 535 fraglen = (int)(rstrm->in_header & ~LAST_FRAG); 536 if (fraglen == 0 || fraglen > rstrm->in_maxrec || 537 (rstrm->in_reclen + fraglen) > rstrm->in_maxrec) { 538 *statp = XPRT_DIED; 539 return FALSE; 540 } 541 rstrm->in_reclen += fraglen; 542 if (rstrm->in_reclen > rstrm->recvsize) 543 realloc_stream(rstrm, rstrm->in_reclen); 544 if (rstrm->in_header & LAST_FRAG) { 545 rstrm->in_header &= ~LAST_FRAG; 546 rstrm->last_frag = TRUE; 547 } 548 /* 549 * We can only reasonably expect to read once from a 550 * non-blocking stream. Reading the fragment header 551 * may have drained the stream. 552 */ 553 expectdata = FALSE; 554 } 555 556 n = rstrm->readit(rstrm->tcp_handle, 557 rstrm->in_base + rstrm->in_received, 558 (rstrm->in_reclen - rstrm->in_received)); 559 560 if (n < 0) { 561 *statp = XPRT_DIED; 562 return FALSE; 563 } 564 565 if (n == 0) { 566 *statp = expectdata ? XPRT_DIED : XPRT_IDLE; 567 return FALSE; 568 } 569 570 rstrm->in_received += n; 571 572 if (rstrm->in_received == rstrm->in_reclen) { 573 rstrm->in_haveheader = FALSE; 574 rstrm->in_hdrp = (char *)(void *)&rstrm->in_header; 575 rstrm->in_hdrlen = 0; 576 if (rstrm->last_frag) { 577 rstrm->fbtbc = rstrm->in_reclen; 578 rstrm->in_boundry = rstrm->in_base + rstrm->in_reclen; 579 rstrm->in_finger = rstrm->in_base; 580 rstrm->in_reclen = rstrm->in_received = 0; 581 *statp = XPRT_MOREREQS; 582 return TRUE; 583 } 584 } 585 586 *statp = XPRT_MOREREQS; 587 return FALSE; 588 } 589 590 bool_t 591 __xdrrec_setnonblock(XDR *xdrs, int maxrec) 592 { 593 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 594 595 rstrm->nonblock = TRUE; 596 if (maxrec == 0) 597 maxrec = rstrm->recvsize; 598 rstrm->in_maxrec = maxrec; 599 return TRUE; 600 } 601 602 /* 603 * Internal useful routines 604 */ 605 static bool_t 606 flush_out(RECSTREAM *rstrm, bool_t eor) 607 { 608 uint32_t eormask = (eor == TRUE) ? LAST_FRAG : 0; 609 uint32_t len = (uint32_t)((u_long)(rstrm->out_finger) - 610 (u_long)(rstrm->frag_header) - sizeof(uint32_t)); 611 612 *(rstrm->frag_header) = htonl(len | eormask); 613 len = (uint32_t)((u_long)(rstrm->out_finger) - 614 (u_long)(rstrm->out_base)); 615 if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len) 616 != (int)len) 617 return (FALSE); 618 rstrm->frag_header = (uint32_t *)(void *)rstrm->out_base; 619 rstrm->out_finger = (char *)rstrm->out_base + sizeof(uint32_t); 620 return (TRUE); 621 } 622 623 static bool_t /* knows nothing about records! Only about input buffers */ 624 fill_input_buf(RECSTREAM *rstrm) 625 { 626 char *where; 627 uint32_t i; 628 int len; 629 630 if (rstrm->nonblock) 631 return FALSE; 632 633 where = rstrm->in_base; 634 i = (uint32_t)((u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT); 635 where += i; 636 len = (uint32_t)(rstrm->in_size - i); 637 if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1) 638 return (FALSE); 639 rstrm->in_finger = where; 640 where += len; 641 rstrm->in_boundry = where; 642 return (TRUE); 643 } 644 645 static bool_t /* knows nothing about records! Only about input buffers */ 646 get_input_bytes(RECSTREAM *rstrm, char *addr, int len) 647 { 648 size_t current; 649 650 if (rstrm->nonblock) { 651 if (len > (int)(rstrm->in_boundry - rstrm->in_finger)) 652 return FALSE; 653 memcpy(addr, rstrm->in_finger, (size_t)len); 654 rstrm->in_finger += len; 655 return TRUE; 656 } 657 658 while (len > 0) { 659 current = (size_t)((long)rstrm->in_boundry - 660 (long)rstrm->in_finger); 661 if (current == 0) { 662 if (! fill_input_buf(rstrm)) 663 return (FALSE); 664 continue; 665 } 666 current = (len < current) ? len : current; 667 memmove(addr, rstrm->in_finger, current); 668 rstrm->in_finger += current; 669 addr += current; 670 len -= current; 671 } 672 return (TRUE); 673 } 674 675 static bool_t /* next two bytes of the input stream are treated as a header */ 676 set_input_fragment(RECSTREAM *rstrm) 677 { 678 uint32_t header; 679 680 if (rstrm->nonblock) 681 return FALSE; 682 if (! get_input_bytes(rstrm, (char *)(void *)&header, sizeof(header))) 683 return (FALSE); 684 header = ntohl(header); 685 rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; 686 /* 687 * Sanity check. Try not to accept wildly incorrect 688 * record sizes. Unfortunately, the only record size 689 * we can positively identify as being 'wildly incorrect' 690 * is zero. Ridiculously large record sizes may look wrong, 691 * but we don't have any way to be certain that they aren't 692 * what the client actually intended to send us. 693 */ 694 if (header == 0) 695 return(FALSE); 696 rstrm->fbtbc = header & (~LAST_FRAG); 697 return (TRUE); 698 } 699 700 static bool_t /* consumes input bytes; knows nothing about records! */ 701 skip_input_bytes(RECSTREAM *rstrm, long cnt) 702 { 703 uint32_t current; 704 705 while (cnt > 0) { 706 current = (size_t)((long)rstrm->in_boundry - 707 (long)rstrm->in_finger); 708 if (current == 0) { 709 if (! fill_input_buf(rstrm)) 710 return (FALSE); 711 continue; 712 } 713 current = (uint32_t)((cnt < current) ? cnt : current); 714 rstrm->in_finger += current; 715 cnt -= current; 716 } 717 return (TRUE); 718 } 719 720 static u_int 721 fix_buf_size(u_int s) 722 { 723 724 if (s < 100) 725 s = 4000; 726 return (RNDUP(s)); 727 } 728 729 /* 730 * Reallocate the input buffer for a non-block stream. 731 */ 732 static bool_t 733 realloc_stream(RECSTREAM *rstrm, int size) 734 { 735 ptrdiff_t diff; 736 char *buf; 737 738 if (size > rstrm->recvsize) { 739 buf = realloc(rstrm->in_base, (size_t)size); 740 if (buf == NULL) 741 return FALSE; 742 diff = buf - rstrm->in_base; 743 rstrm->in_finger += diff; 744 rstrm->in_base = buf; 745 rstrm->in_boundry = buf + size; 746 rstrm->recvsize = size; 747 rstrm->in_size = size; 748 } 749 750 return TRUE; 751 } 752