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