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