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