1 /* $OpenBSD: xdr_rec.c,v 1.21 2015/10/04 06:37:21 guenther 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 <unistd.h> 56 #include <rpc/types.h> 57 #include <rpc/xdr.h> 58 #include <rpc/auth.h> 59 #include <rpc/clnt.h> 60 #include <rpc/rpc_msg.h> 61 #include <rpc/svc.h> 62 63 static bool_t xdrrec_getlong(XDR *, long *); 64 static bool_t xdrrec_putlong(XDR *, long *); 65 static bool_t xdrrec_getbytes(XDR *, caddr_t, u_int); 66 static bool_t xdrrec_putbytes(XDR *, caddr_t, u_int); 67 static u_int xdrrec_getpos(XDR *); 68 static bool_t xdrrec_setpos(XDR *, u_int); 69 static int32_t *xdrrec_inline(XDR *, u_int); 70 static void xdrrec_destroy(XDR *); 71 72 /* 73 * Not clear if these are used externally 74 */ 75 bool_t __xdrrec_setnonblock(XDR *, int); 76 PROTO_STD_DEPRECATED(__xdrrec_setnonblock); 77 78 bool_t __xdrrec_getrec(XDR *xdrs, enum xprt_stat *statp, bool_t expectdata); 79 PROTO_NORMAL(__xdrrec_getrec); 80 81 struct ct_data; 82 83 static struct xdr_ops xdrrec_ops = { 84 xdrrec_getlong, 85 xdrrec_putlong, 86 xdrrec_getbytes, 87 xdrrec_putbytes, 88 xdrrec_getpos, 89 xdrrec_setpos, 90 xdrrec_inline, 91 xdrrec_destroy, 92 NULL, /* xdrrec_control */ 93 }; 94 95 /* 96 * A record is composed of one or more record fragments. 97 * A record fragment is a four-byte header followed by zero to 98 * 2**32-1 bytes. The header is treated as a long unsigned and is 99 * encode/decoded to the network via htonl/ntohl. The low order 31 bits 100 * are a byte count of the fragment. The highest order bit is a boolean: 101 * 1 => this fragment is the last fragment of the record, 102 * 0 => this fragment is followed by more fragment(s). 103 * 104 * The fragment/record machinery is not general; it is constructed to 105 * meet the needs of xdr and rpc based on tcp. 106 */ 107 108 #define LAST_FRAG ((u_int32_t)(1U << 31)) 109 110 typedef struct rec_strm { 111 caddr_t tcp_handle; 112 /* 113 * out-goung bits 114 */ 115 int (*writeit)(caddr_t, caddr_t, int); 116 caddr_t out_base; /* output buffer (points to frag header) */ 117 caddr_t out_finger; /* next output position */ 118 caddr_t out_boundry; /* data cannot up to this address */ 119 u_int32_t *frag_header; /* beginning of current fragment */ 120 bool_t frag_sent; /* true if buffer sent in middle of record */ 121 /* 122 * in-coming bits 123 */ 124 int (*readit)(caddr_t, caddr_t, int); 125 u_long in_size; /* fixed size of the input buffer */ 126 caddr_t in_base; 127 caddr_t in_finger; /* location of next byte to be had */ 128 caddr_t in_boundry; /* can read up to this location */ 129 long fbtbc; /* fragment bytes to be consumed */ 130 bool_t last_frag; 131 u_int sendsize; 132 u_int recvsize; 133 134 bool_t nonblock; 135 bool_t in_haveheader; 136 u_int32_t in_header; 137 char *in_hdrp; 138 int in_hdrlen; 139 int in_reclen; 140 int in_received; 141 int in_maxrec; 142 } RECSTREAM; 143 144 static u_int fix_buf_size(u_int); 145 static bool_t flush_out(RECSTREAM *, bool_t); 146 static bool_t fill_input_buf(RECSTREAM *); 147 static bool_t get_input_bytes(RECSTREAM *, caddr_t, int); 148 static bool_t set_input_fragment(RECSTREAM *); 149 static bool_t skip_input_bytes(RECSTREAM *, long); 150 static bool_t realloc_stream(RECSTREAM *, int); 151 152 /* 153 * Create an xdr handle for xdrrec 154 * xdrrec_create fills in xdrs. Sendsize and recvsize are 155 * send and recv buffer sizes (0 => use default). 156 * tcp_handle is an opaque handle that is passed as the first parameter to 157 * the procedures readit and writeit. Readit and writeit are read and 158 * write respectively. They are like the system 159 * calls expect that they take an opaque handle rather than an fd. 160 */ 161 void 162 xdrrec_create(XDR *xdrs, u_int sendsize, u_int recvsize, caddr_t tcp_handle, 163 int (*readit)(caddr_t, caddr_t, int), /* like read, but pass it a 164 tcp_handle, not sock */ 165 int (*writeit)(caddr_t, caddr_t, int)) /* like write, but pass it a 166 tcp_handle, not sock */ 167 { 168 RECSTREAM *rstrm = 169 (RECSTREAM *)mem_alloc(sizeof(RECSTREAM)); 170 171 if (rstrm == NULL) { 172 /* 173 * This is bad. Should rework xdrrec_create to 174 * return a handle, and in this case return NULL 175 */ 176 return; 177 } 178 179 rstrm->sendsize = sendsize = fix_buf_size(sendsize); 180 rstrm->out_base = malloc(rstrm->sendsize); 181 if (rstrm->out_base == NULL) { 182 mem_free(rstrm, sizeof(RECSTREAM)); 183 return; 184 } 185 186 rstrm->recvsize = recvsize = fix_buf_size(recvsize); 187 rstrm->in_base = malloc(recvsize); 188 if (rstrm->in_base == NULL) { 189 mem_free(rstrm->out_base, sendsize); 190 mem_free(rstrm, sizeof(RECSTREAM)); 191 return; 192 } 193 /* 194 * now the rest ... 195 */ 196 xdrs->x_ops = &xdrrec_ops; 197 xdrs->x_private = (caddr_t)rstrm; 198 rstrm->tcp_handle = tcp_handle; 199 rstrm->readit = readit; 200 rstrm->writeit = writeit; 201 rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; 202 rstrm->frag_header = (u_int32_t *)rstrm->out_base; 203 rstrm->out_finger += sizeof(u_int32_t); 204 rstrm->out_boundry += sendsize; 205 rstrm->frag_sent = FALSE; 206 rstrm->in_size = recvsize; 207 rstrm->in_boundry = rstrm->in_base; 208 rstrm->in_finger = (rstrm->in_boundry += recvsize); 209 rstrm->fbtbc = 0; 210 rstrm->last_frag = TRUE; 211 rstrm->in_haveheader = FALSE; 212 rstrm->in_hdrlen = 0; 213 rstrm->in_hdrp = (char *)(void *)&rstrm->in_header; 214 rstrm->nonblock = FALSE; 215 rstrm->in_reclen = 0; 216 rstrm->in_received = 0; 217 } 218 DEF_WEAK(xdrrec_create); 219 220 221 /* 222 * The reoutines 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 int *lp) 228 { 229 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 230 int32_t *buflp = (int32_t *)(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((u_int32_t)(*buflp)); 237 rstrm->fbtbc -= sizeof(int32_t); 238 rstrm->in_finger += sizeof(int32_t); 239 } else { 240 if (! xdrrec_getbytes(xdrs, (caddr_t)(void *)&mylong, 241 sizeof(int32_t))) 242 return (FALSE); 243 *lp = (long)ntohl((u_int32_t)mylong); 244 } 245 return (TRUE); 246 } 247 248 static bool_t 249 xdrrec_putlong(XDR *xdrs, long int *lp) 250 { 251 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 252 int32_t *dest_lp = ((int32_t *)(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((u_int32_t)(*lp)); 267 return (TRUE); 268 } 269 270 static bool_t /* must manage buffers, fragments, and records */ 271 xdrrec_getbytes(XDR *xdrs, caddr_t addr, u_int len) 272 { 273 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 274 int current; 275 276 while (len > 0) { 277 current = 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, caddr_t addr, u_int len) 297 { 298 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 299 long current; 300 301 while (len > 0) { 302 current = (u_long)rstrm->out_boundry - 303 (u_long)rstrm->out_finger; 304 current = (len < current) ? len : current; 305 memcpy(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)(long)rstrm->tcp_handle, (off_t)0, SEEK_CUR); 325 if (pos != (off_t)-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 = -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 caddr_t 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 > (caddr_t)(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 *) 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 *) rstrm->in_finger; 399 rstrm->fbtbc -= len; 400 rstrm->in_finger += len; 401 } 402 break; 403 404 case XDR_FREE: 405 break; 406 } 407 return (buf); 408 } 409 410 static void 411 xdrrec_destroy(XDR *xdrs) 412 { 413 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 414 415 mem_free(rstrm->out_base, rstrm->sendsize); 416 mem_free(rstrm->in_base, rstrm->recvsize); 417 mem_free(rstrm, sizeof(RECSTREAM)); 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 while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { 447 if (! skip_input_bytes(rstrm, rstrm->fbtbc)) 448 return (FALSE); 449 rstrm->fbtbc = 0; 450 if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) 451 return (FALSE); 452 } 453 rstrm->last_frag = FALSE; 454 return (TRUE); 455 } 456 DEF_WEAK(xdrrec_skiprecord); 457 458 /* 459 * Look ahead fuction. 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 DEF_WEAK(xdrrec_eof); 480 481 /* 482 * The client must tell the package when an end-of-record has occurred. 483 * The second paraemters tells whether the record should be flushed to the 484 * (output) tcp stream. (This let's the package support batched or 485 * pipelined procedure calls.) TRUE => immmediate flush to tcp connection. 486 */ 487 bool_t 488 xdrrec_endofrecord(XDR *xdrs, int32_t sendnow) 489 { 490 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 491 u_long len; /* fragment length */ 492 493 if (sendnow || rstrm->frag_sent || 494 ((u_long)rstrm->out_finger + sizeof(u_int32_t) >= 495 (u_long)rstrm->out_boundry)) { 496 rstrm->frag_sent = FALSE; 497 return (flush_out(rstrm, TRUE)); 498 } 499 len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) - 500 sizeof(u_int32_t); 501 *(rstrm->frag_header) = htonl((u_long)len | LAST_FRAG); 502 rstrm->frag_header = (u_int32_t *)rstrm->out_finger; 503 rstrm->out_finger += sizeof(u_int32_t); 504 return (TRUE); 505 } 506 DEF_WEAK(xdrrec_endofrecord); 507 508 /* 509 * Fill the stream buffer with a record for a non-blocking connection. 510 * Return true if a record is available in the buffer, false if not. 511 */ 512 bool_t 513 __xdrrec_getrec(XDR *xdrs, enum xprt_stat *statp, bool_t expectdata) 514 { 515 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 516 ssize_t n; 517 int fraglen; 518 519 if (!rstrm->in_haveheader) { 520 n = rstrm->readit(rstrm->tcp_handle, rstrm->in_hdrp, 521 (int)sizeof (rstrm->in_header) - rstrm->in_hdrlen); 522 if (n == 0) { 523 *statp = expectdata ? XPRT_DIED : XPRT_IDLE; 524 return (FALSE); 525 } 526 if (n < 0) { 527 *statp = XPRT_DIED; 528 return (FALSE); 529 } 530 rstrm->in_hdrp += n; 531 rstrm->in_hdrlen += n; 532 if (rstrm->in_hdrlen < sizeof (rstrm->in_header)) { 533 *statp = XPRT_MOREREQS; 534 return (FALSE); 535 } 536 rstrm->in_header = ntohl(rstrm->in_header); 537 fraglen = (int)(rstrm->in_header & ~LAST_FRAG); 538 if (fraglen == 0 || fraglen > rstrm->in_maxrec || 539 (rstrm->in_reclen + fraglen) > rstrm->in_maxrec) { 540 *statp = XPRT_DIED; 541 return (FALSE); 542 } 543 rstrm->in_reclen += fraglen; 544 if (rstrm->in_reclen > rstrm->recvsize) 545 realloc_stream(rstrm, rstrm->in_reclen); 546 if (rstrm->in_header & LAST_FRAG) { 547 rstrm->in_header &= ~LAST_FRAG; 548 rstrm->last_frag = TRUE; 549 } 550 } 551 552 n = rstrm->readit(rstrm->tcp_handle, 553 rstrm->in_base + rstrm->in_received, 554 (rstrm->in_reclen - rstrm->in_received)); 555 556 if (n < 0) { 557 *statp = XPRT_DIED; 558 return (FALSE); 559 } 560 561 if (n == 0) { 562 *statp = expectdata ? XPRT_DIED : XPRT_IDLE; 563 return (FALSE); 564 } 565 566 rstrm->in_received += n; 567 568 if (rstrm->in_received == rstrm->in_reclen) { 569 rstrm->in_haveheader = (FALSE); 570 rstrm->in_hdrp = (char *)(void *)&rstrm->in_header; 571 rstrm->in_hdrlen = 0; 572 if (rstrm->last_frag) { 573 rstrm->fbtbc = rstrm->in_reclen; 574 rstrm->in_boundry = rstrm->in_base + rstrm->in_reclen; 575 rstrm->in_finger = rstrm->in_base; 576 rstrm->in_reclen = rstrm->in_received = 0; 577 *statp = XPRT_MOREREQS; 578 return (TRUE); 579 } 580 } 581 582 *statp = XPRT_MOREREQS; 583 return (FALSE); 584 } 585 DEF_STRONG(__xdrrec_getrec); 586 587 bool_t 588 __xdrrec_setnonblock(XDR *xdrs, int maxrec) 589 { 590 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 591 592 rstrm->nonblock = TRUE; 593 if (maxrec == 0) 594 maxrec = rstrm->recvsize; 595 rstrm->in_maxrec = maxrec; 596 return (TRUE); 597 } 598 599 600 /* 601 * Internal useful routines 602 */ 603 static bool_t 604 flush_out(RECSTREAM *rstrm, int32_t eor) 605 { 606 u_long eormask = (eor == TRUE) ? LAST_FRAG : 0; 607 u_int32_t len = (u_long)(rstrm->out_finger) - 608 (u_long)(rstrm->frag_header) - sizeof(u_int32_t); 609 610 *(rstrm->frag_header) = htonl(len | eormask); 611 len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->out_base); 612 if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len) 613 != (int)len) 614 return (FALSE); 615 rstrm->frag_header = (u_int32_t *)rstrm->out_base; 616 rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(u_int32_t); 617 return (TRUE); 618 } 619 620 static bool_t /* knows nothing about records! Only about input buffers */ 621 fill_input_buf(RECSTREAM *rstrm) 622 { 623 caddr_t where; 624 u_long i; 625 long len; 626 627 if (rstrm->nonblock) 628 return FALSE; 629 where = rstrm->in_base; 630 i = (u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT; 631 where += i; 632 len = rstrm->in_size - i; 633 if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1) 634 return (FALSE); 635 rstrm->in_finger = where; 636 where += len; 637 rstrm->in_boundry = where; 638 return (TRUE); 639 } 640 641 static bool_t /* knows nothing about records! Only about input buffers */ 642 get_input_bytes(RECSTREAM *rstrm, caddr_t addr, int len) 643 { 644 long current; 645 646 if (rstrm->nonblock) { 647 if (len > (int)(rstrm->in_boundry - rstrm->in_finger)) 648 return FALSE; 649 memcpy(addr, rstrm->in_finger, (size_t)len); 650 rstrm->in_finger += len; 651 return (TRUE); 652 } 653 654 while (len > 0) { 655 current = (long)rstrm->in_boundry - (long)rstrm->in_finger; 656 if (current == 0) { 657 if (! fill_input_buf(rstrm)) 658 return (FALSE); 659 continue; 660 } 661 current = (len < current) ? len : current; 662 memcpy(addr, rstrm->in_finger, current); 663 rstrm->in_finger += current; 664 addr += current; 665 len -= current; 666 } 667 return (TRUE); 668 } 669 670 static bool_t /* next four bytes of the input stream are treated as a header */ 671 set_input_fragment(RECSTREAM *rstrm) 672 { 673 u_int32_t header; 674 675 if (rstrm->nonblock) 676 return (FALSE); 677 if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header))) 678 return (FALSE); 679 header = (long)ntohl(header); 680 rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; 681 /* 682 * Sanity check. Try not to accept wildly incorrect 683 * record sizes. Unfortunately, the only record size 684 * we can positively identify as being 'wildly incorrect' 685 * is zero. Ridiculously large record sizes may look wrong, 686 * but we don't have any way to be certain that they aren't 687 * what the client actually intended to send us. 688 */ 689 if (header == 0) 690 return(FALSE); 691 rstrm->fbtbc = header & (~LAST_FRAG); 692 return (TRUE); 693 } 694 695 static bool_t /* consumes input bytes; knows nothing about records! */ 696 skip_input_bytes(RECSTREAM *rstrm, long int cnt) 697 { 698 long current; 699 700 while (cnt > 0) { 701 current = (long)rstrm->in_boundry - (long)rstrm->in_finger; 702 if (current == 0) { 703 if (! fill_input_buf(rstrm)) 704 return (FALSE); 705 continue; 706 } 707 current = (cnt < current) ? cnt : current; 708 rstrm->in_finger += current; 709 cnt -= current; 710 } 711 return (TRUE); 712 } 713 714 static u_int 715 fix_buf_size(u_int s) 716 { 717 718 if (s < 100) 719 s = 4000; 720 return (RNDUP(s)); 721 } 722 723 /* 724 * Reallocate the input buffer for a non-block stream. 725 */ 726 static bool_t 727 realloc_stream(RECSTREAM *rstrm, int size) 728 { 729 ptrdiff_t diff; 730 char *buf; 731 732 if (size > rstrm->recvsize) { 733 buf = realloc(rstrm->in_base, (size_t)size); 734 if (buf == NULL) 735 return (FALSE); 736 diff = buf - rstrm->in_base; 737 rstrm->in_finger += diff; 738 rstrm->in_base = buf; 739 rstrm->in_boundry = buf + size; 740 rstrm->recvsize = size; 741 rstrm->in_size = size; 742 } 743 744 return (TRUE); 745 } 746