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