1*45098Smckusick /* @(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC */ 2*45098Smckusick /* 3*45098Smckusick * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 4*45098Smckusick * unrestricted use provided that this legend is included on all tape 5*45098Smckusick * media and as a part of the software program in whole or part. Users 6*45098Smckusick * may copy or modify Sun RPC without charge, but are not authorized 7*45098Smckusick * to license or distribute it to anyone else except as part of a product or 8*45098Smckusick * program developed by the user. 9*45098Smckusick * 10*45098Smckusick * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 11*45098Smckusick * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 12*45098Smckusick * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 13*45098Smckusick * 14*45098Smckusick * Sun RPC is provided with no support and without any obligation on the 15*45098Smckusick * part of Sun Microsystems, Inc. to assist in its use, correction, 16*45098Smckusick * modification or enhancement. 17*45098Smckusick * 18*45098Smckusick * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 19*45098Smckusick * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 20*45098Smckusick * OR ANY PART THEREOF. 21*45098Smckusick * 22*45098Smckusick * In no event will Sun Microsystems, Inc. be liable for any lost revenue 23*45098Smckusick * or profits or other special, indirect and consequential damages, even if 24*45098Smckusick * Sun has been advised of the possibility of such damages. 25*45098Smckusick * 26*45098Smckusick * Sun Microsystems, Inc. 27*45098Smckusick * 2550 Garcia Avenue 28*45098Smckusick * Mountain View, California 94043 29*45098Smckusick */ 30*45098Smckusick #if !defined(lint) && defined(SCCSIDS) 31*45098Smckusick static char sccsid[] = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 32*45098Smckusick #endif 33*45098Smckusick 34*45098Smckusick /* 35*45098Smckusick * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking" 36*45098Smckusick * layer above tcp (for rpc's use). 37*45098Smckusick * 38*45098Smckusick * Copyright (C) 1984, Sun Microsystems, Inc. 39*45098Smckusick * 40*45098Smckusick * These routines interface XDRSTREAMS to a tcp/ip connection. 41*45098Smckusick * There is a record marking layer between the xdr stream 42*45098Smckusick * and the tcp transport level. A record is composed on one or more 43*45098Smckusick * record fragments. A record fragment is a thirty-two bit header followed 44*45098Smckusick * by n bytes of data, where n is contained in the header. The header 45*45098Smckusick * is represented as a htonl(u_long). Thegh order bit encodes 46*45098Smckusick * whether or not the fragment is the last fragment of the record 47*45098Smckusick * (1 => fragment is last, 0 => more fragments to follow. 48*45098Smckusick * The other 31 bits encode the byte length of the fragment. 49*45098Smckusick */ 50*45098Smckusick 51*45098Smckusick #include <stdio.h> 52*45098Smckusick #include <rpc/types.h> 53*45098Smckusick #include <rpc/xdr.h> 54*45098Smckusick #include <netinet/in.h> 55*45098Smckusick 56*45098Smckusick extern long lseek(); 57*45098Smckusick 58*45098Smckusick static u_int fix_buf_size(); 59*45098Smckusick 60*45098Smckusick static bool_t xdrrec_getlong(); 61*45098Smckusick static bool_t xdrrec_putlong(); 62*45098Smckusick static bool_t xdrrec_getbytes(); 63*45098Smckusick static bool_t xdrrec_putbytes(); 64*45098Smckusick static u_int xdrrec_getpos(); 65*45098Smckusick static bool_t xdrrec_setpos(); 66*45098Smckusick static long * xdrrec_inline(); 67*45098Smckusick static void xdrrec_destroy(); 68*45098Smckusick 69*45098Smckusick static struct xdr_ops xdrrec_ops = { 70*45098Smckusick xdrrec_getlong, 71*45098Smckusick xdrrec_putlong, 72*45098Smckusick xdrrec_getbytes, 73*45098Smckusick xdrrec_putbytes, 74*45098Smckusick xdrrec_getpos, 75*45098Smckusick xdrrec_setpos, 76*45098Smckusick xdrrec_inline, 77*45098Smckusick xdrrec_destroy 78*45098Smckusick }; 79*45098Smckusick 80*45098Smckusick /* 81*45098Smckusick * A record is composed of one or more record fragments. 82*45098Smckusick * A record fragment is a two-byte header followed by zero to 83*45098Smckusick * 2**32-1 bytes. The header is treated as a long unsigned and is 84*45098Smckusick * encode/decoded to the network via htonl/ntohl. The low order 31 bits 85*45098Smckusick * are a byte count of the fragment. The highest order bit is a boolean: 86*45098Smckusick * 1 => this fragment is the last fragment of the record, 87*45098Smckusick * 0 => this fragment is followed by more fragment(s). 88*45098Smckusick * 89*45098Smckusick * The fragment/record machinery is not general; it is constructed to 90*45098Smckusick * meet the needs of xdr and rpc based on tcp. 91*45098Smckusick */ 92*45098Smckusick 93*45098Smckusick #define LAST_FRAG ((u_long)(1 << 31)) 94*45098Smckusick 95*45098Smckusick typedef struct rec_strm { 96*45098Smckusick caddr_t tcp_handle; 97*45098Smckusick caddr_t the_buffer; 98*45098Smckusick /* 99*45098Smckusick * out-goung bits 100*45098Smckusick */ 101*45098Smckusick int (*writeit)(); 102*45098Smckusick caddr_t out_base; /* output buffer (points to frag header) */ 103*45098Smckusick caddr_t out_finger; /* next output position */ 104*45098Smckusick caddr_t out_boundry; /* data cannot up to this address */ 105*45098Smckusick u_long *frag_header; /* beginning of curren fragment */ 106*45098Smckusick bool_t frag_sent; /* true if buffer sent in middle of record */ 107*45098Smckusick /* 108*45098Smckusick * in-coming bits 109*45098Smckusick */ 110*45098Smckusick int (*readit)(); 111*45098Smckusick u_long in_size; /* fixed size of the input buffer */ 112*45098Smckusick caddr_t in_base; 113*45098Smckusick caddr_t in_finger; /* location of next byte to be had */ 114*45098Smckusick caddr_t in_boundry; /* can read up to this location */ 115*45098Smckusick long fbtbc; /* fragment bytes to be consumed */ 116*45098Smckusick bool_t last_frag; 117*45098Smckusick u_int sendsize; 118*45098Smckusick u_int recvsize; 119*45098Smckusick } RECSTREAM; 120*45098Smckusick 121*45098Smckusick 122*45098Smckusick /* 123*45098Smckusick * Create an xdr handle for xdrrec 124*45098Smckusick * xdrrec_create fills in xdrs. Sendsize and recvsize are 125*45098Smckusick * send and recv buffer sizes (0 => use default). 126*45098Smckusick * tcp_handle is an opaque handle that is passed as the first parameter to 127*45098Smckusick * the procedures readit and writeit. Readit and writeit are read and 128*45098Smckusick * write respectively. They are like the system 129*45098Smckusick * calls expect that they take an opaque handle rather than an fd. 130*45098Smckusick */ 131*45098Smckusick void 132*45098Smckusick xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit) 133*45098Smckusick register XDR *xdrs; 134*45098Smckusick register u_int sendsize; 135*45098Smckusick register u_int recvsize; 136*45098Smckusick caddr_t tcp_handle; 137*45098Smckusick int (*readit)(); /* like read, but pass it a tcp_handle, not sock */ 138*45098Smckusick int (*writeit)(); /* like write, but pass it a tcp_handle, not sock */ 139*45098Smckusick { 140*45098Smckusick register RECSTREAM *rstrm = 141*45098Smckusick (RECSTREAM *)mem_alloc(sizeof(RECSTREAM)); 142*45098Smckusick 143*45098Smckusick if (rstrm == NULL) { 144*45098Smckusick (void)fprintf(stderr, "xdrrec_create: out of memory\n"); 145*45098Smckusick /* 146*45098Smckusick * This is bad. Should rework xdrrec_create to 147*45098Smckusick * return a handle, and in this case return NULL 148*45098Smckusick */ 149*45098Smckusick return; 150*45098Smckusick } 151*45098Smckusick /* 152*45098Smckusick * adjust sizes and allocate buffer quad byte aligned 153*45098Smckusick */ 154*45098Smckusick rstrm->sendsize = sendsize = fix_buf_size(sendsize); 155*45098Smckusick rstrm->recvsize = recvsize = fix_buf_size(recvsize); 156*45098Smckusick rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT); 157*45098Smckusick if (rstrm->the_buffer == NULL) { 158*45098Smckusick (void)fprintf(stderr, "xdrrec_create: out of memory\n"); 159*45098Smckusick return; 160*45098Smckusick } 161*45098Smckusick for (rstrm->out_base = rstrm->the_buffer; 162*45098Smckusick (u_int)rstrm->out_base % BYTES_PER_XDR_UNIT != 0; 163*45098Smckusick rstrm->out_base++); 164*45098Smckusick rstrm->in_base = rstrm->out_base + sendsize; 165*45098Smckusick /* 166*45098Smckusick * now the rest ... 167*45098Smckusick */ 168*45098Smckusick xdrs->x_ops = &xdrrec_ops; 169*45098Smckusick xdrs->x_private = (caddr_t)rstrm; 170*45098Smckusick rstrm->tcp_handle = tcp_handle; 171*45098Smckusick rstrm->readit = readit; 172*45098Smckusick rstrm->writeit = writeit; 173*45098Smckusick rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; 174*45098Smckusick rstrm->frag_header = (u_long *)rstrm->out_base; 175*45098Smckusick rstrm->out_finger += sizeof(u_long); 176*45098Smckusick rstrm->out_boundry += sendsize; 177*45098Smckusick rstrm->frag_sent = FALSE; 178*45098Smckusick rstrm->in_size = recvsize; 179*45098Smckusick rstrm->in_boundry = rstrm->in_base; 180*45098Smckusick rstrm->in_finger = (rstrm->in_boundry += recvsize); 181*45098Smckusick rstrm->fbtbc = 0; 182*45098Smckusick rstrm->last_frag = TRUE; 183*45098Smckusick } 184*45098Smckusick 185*45098Smckusick 186*45098Smckusick /* 187*45098Smckusick * The reoutines defined below are the xdr ops which will go into the 188*45098Smckusick * xdr handle filled in by xdrrec_create. 189*45098Smckusick */ 190*45098Smckusick 191*45098Smckusick static bool_t 192*45098Smckusick xdrrec_getlong(xdrs, lp) 193*45098Smckusick XDR *xdrs; 194*45098Smckusick long *lp; 195*45098Smckusick { 196*45098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 197*45098Smckusick register long *buflp = (long *)(rstrm->in_finger); 198*45098Smckusick long mylong; 199*45098Smckusick 200*45098Smckusick /* first try the inline, fast case */ 201*45098Smckusick if ((rstrm->fbtbc >= sizeof(long)) && 202*45098Smckusick (((int)rstrm->in_boundry - (int)buflp) >= sizeof(long))) { 203*45098Smckusick *lp = (long)ntohl((u_long)(*buflp)); 204*45098Smckusick rstrm->fbtbc -= sizeof(long); 205*45098Smckusick rstrm->in_finger += sizeof(long); 206*45098Smckusick } else { 207*45098Smckusick if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof(long))) 208*45098Smckusick return (FALSE); 209*45098Smckusick *lp = (long)ntohl((u_long)mylong); 210*45098Smckusick } 211*45098Smckusick return (TRUE); 212*45098Smckusick } 213*45098Smckusick 214*45098Smckusick static bool_t 215*45098Smckusick xdrrec_putlong(xdrs, lp) 216*45098Smckusick XDR *xdrs; 217*45098Smckusick long *lp; 218*45098Smckusick { 219*45098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 220*45098Smckusick register long *dest_lp = ((long *)(rstrm->out_finger)); 221*45098Smckusick 222*45098Smckusick if ((rstrm->out_finger += sizeof(long)) > rstrm->out_boundry) { 223*45098Smckusick /* 224*45098Smckusick * this case should almost never happen so the code is 225*45098Smckusick * inefficient 226*45098Smckusick */ 227*45098Smckusick rstrm->out_finger -= sizeof(long); 228*45098Smckusick rstrm->frag_sent = TRUE; 229*45098Smckusick if (! flush_out(rstrm, FALSE)) 230*45098Smckusick return (FALSE); 231*45098Smckusick dest_lp = ((long *)(rstrm->out_finger)); 232*45098Smckusick rstrm->out_finger += sizeof(long); 233*45098Smckusick } 234*45098Smckusick *dest_lp = (long)htonl((u_long)(*lp)); 235*45098Smckusick return (TRUE); 236*45098Smckusick } 237*45098Smckusick 238*45098Smckusick static bool_t /* must manage buffers, fragments, and records */ 239*45098Smckusick xdrrec_getbytes(xdrs, addr, len) 240*45098Smckusick XDR *xdrs; 241*45098Smckusick register caddr_t addr; 242*45098Smckusick register u_int len; 243*45098Smckusick { 244*45098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 245*45098Smckusick register int current; 246*45098Smckusick 247*45098Smckusick while (len > 0) { 248*45098Smckusick current = rstrm->fbtbc; 249*45098Smckusick if (current == 0) { 250*45098Smckusick if (rstrm->last_frag) 251*45098Smckusick return (FALSE); 252*45098Smckusick if (! set_input_fragment(rstrm)) 253*45098Smckusick return (FALSE); 254*45098Smckusick continue; 255*45098Smckusick } 256*45098Smckusick current = (len < current) ? len : current; 257*45098Smckusick if (! get_input_bytes(rstrm, addr, current)) 258*45098Smckusick return (FALSE); 259*45098Smckusick addr += current; 260*45098Smckusick rstrm->fbtbc -= current; 261*45098Smckusick len -= current; 262*45098Smckusick } 263*45098Smckusick return (TRUE); 264*45098Smckusick } 265*45098Smckusick 266*45098Smckusick static bool_t 267*45098Smckusick xdrrec_putbytes(xdrs, addr, len) 268*45098Smckusick XDR *xdrs; 269*45098Smckusick register caddr_t addr; 270*45098Smckusick register u_int len; 271*45098Smckusick { 272*45098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 273*45098Smckusick register int current; 274*45098Smckusick 275*45098Smckusick while (len > 0) { 276*45098Smckusick current = (u_int)rstrm->out_boundry - (u_int)rstrm->out_finger; 277*45098Smckusick current = (len < current) ? len : current; 278*45098Smckusick bcopy(addr, rstrm->out_finger, current); 279*45098Smckusick rstrm->out_finger += current; 280*45098Smckusick addr += current; 281*45098Smckusick len -= current; 282*45098Smckusick if (rstrm->out_finger == rstrm->out_boundry) { 283*45098Smckusick rstrm->frag_sent = TRUE; 284*45098Smckusick if (! flush_out(rstrm, FALSE)) 285*45098Smckusick return (FALSE); 286*45098Smckusick } 287*45098Smckusick } 288*45098Smckusick return (TRUE); 289*45098Smckusick } 290*45098Smckusick 291*45098Smckusick static u_int 292*45098Smckusick xdrrec_getpos(xdrs) 293*45098Smckusick register XDR *xdrs; 294*45098Smckusick { 295*45098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 296*45098Smckusick register long pos; 297*45098Smckusick 298*45098Smckusick pos = lseek((int)rstrm->tcp_handle, (long) 0, 1); 299*45098Smckusick if (pos != -1) 300*45098Smckusick switch (xdrs->x_op) { 301*45098Smckusick 302*45098Smckusick case XDR_ENCODE: 303*45098Smckusick pos += rstrm->out_finger - rstrm->out_base; 304*45098Smckusick break; 305*45098Smckusick 306*45098Smckusick case XDR_DECODE: 307*45098Smckusick pos -= rstrm->in_boundry - rstrm->in_finger; 308*45098Smckusick break; 309*45098Smckusick 310*45098Smckusick default: 311*45098Smckusick pos = (u_int) -1; 312*45098Smckusick break; 313*45098Smckusick } 314*45098Smckusick return ((u_int) pos); 315*45098Smckusick } 316*45098Smckusick 317*45098Smckusick static bool_t 318*45098Smckusick xdrrec_setpos(xdrs, pos) 319*45098Smckusick register XDR *xdrs; 320*45098Smckusick u_int pos; 321*45098Smckusick { 322*45098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 323*45098Smckusick u_int currpos = xdrrec_getpos(xdrs); 324*45098Smckusick int delta = currpos - pos; 325*45098Smckusick caddr_t newpos; 326*45098Smckusick 327*45098Smckusick if ((int)currpos != -1) 328*45098Smckusick switch (xdrs->x_op) { 329*45098Smckusick 330*45098Smckusick case XDR_ENCODE: 331*45098Smckusick newpos = rstrm->out_finger - delta; 332*45098Smckusick if ((newpos > (caddr_t)(rstrm->frag_header)) && 333*45098Smckusick (newpos < rstrm->out_boundry)) { 334*45098Smckusick rstrm->out_finger = newpos; 335*45098Smckusick return (TRUE); 336*45098Smckusick } 337*45098Smckusick break; 338*45098Smckusick 339*45098Smckusick case XDR_DECODE: 340*45098Smckusick newpos = rstrm->in_finger - delta; 341*45098Smckusick if ((delta < (int)(rstrm->fbtbc)) && 342*45098Smckusick (newpos <= rstrm->in_boundry) && 343*45098Smckusick (newpos >= rstrm->in_base)) { 344*45098Smckusick rstrm->in_finger = newpos; 345*45098Smckusick rstrm->fbtbc -= delta; 346*45098Smckusick return (TRUE); 347*45098Smckusick } 348*45098Smckusick break; 349*45098Smckusick } 350*45098Smckusick return (FALSE); 351*45098Smckusick } 352*45098Smckusick 353*45098Smckusick static long * 354*45098Smckusick xdrrec_inline(xdrs, len) 355*45098Smckusick register XDR *xdrs; 356*45098Smckusick int len; 357*45098Smckusick { 358*45098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 359*45098Smckusick long * buf = NULL; 360*45098Smckusick 361*45098Smckusick switch (xdrs->x_op) { 362*45098Smckusick 363*45098Smckusick case XDR_ENCODE: 364*45098Smckusick if ((rstrm->out_finger + len) <= rstrm->out_boundry) { 365*45098Smckusick buf = (long *) rstrm->out_finger; 366*45098Smckusick rstrm->out_finger += len; 367*45098Smckusick } 368*45098Smckusick break; 369*45098Smckusick 370*45098Smckusick case XDR_DECODE: 371*45098Smckusick if ((len <= rstrm->fbtbc) && 372*45098Smckusick ((rstrm->in_finger + len) <= rstrm->in_boundry)) { 373*45098Smckusick buf = (long *) rstrm->in_finger; 374*45098Smckusick rstrm->fbtbc -= len; 375*45098Smckusick rstrm->in_finger += len; 376*45098Smckusick } 377*45098Smckusick break; 378*45098Smckusick } 379*45098Smckusick return (buf); 380*45098Smckusick } 381*45098Smckusick 382*45098Smckusick static void 383*45098Smckusick xdrrec_destroy(xdrs) 384*45098Smckusick register XDR *xdrs; 385*45098Smckusick { 386*45098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 387*45098Smckusick 388*45098Smckusick mem_free(rstrm->the_buffer, 389*45098Smckusick rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT); 390*45098Smckusick mem_free((caddr_t)rstrm, sizeof(RECSTREAM)); 391*45098Smckusick } 392*45098Smckusick 393*45098Smckusick 394*45098Smckusick /* 395*45098Smckusick * Exported routines to manage xdr records 396*45098Smckusick */ 397*45098Smckusick 398*45098Smckusick /* 399*45098Smckusick * Before reading (deserializing from the stream, one should always call 400*45098Smckusick * this procedure to guarantee proper record alignment. 401*45098Smckusick */ 402*45098Smckusick bool_t 403*45098Smckusick xdrrec_skiprecord(xdrs) 404*45098Smckusick XDR *xdrs; 405*45098Smckusick { 406*45098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 407*45098Smckusick 408*45098Smckusick while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { 409*45098Smckusick if (! skip_input_bytes(rstrm, rstrm->fbtbc)) 410*45098Smckusick return (FALSE); 411*45098Smckusick rstrm->fbtbc = 0; 412*45098Smckusick if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) 413*45098Smckusick return (FALSE); 414*45098Smckusick } 415*45098Smckusick rstrm->last_frag = FALSE; 416*45098Smckusick return (TRUE); 417*45098Smckusick } 418*45098Smckusick 419*45098Smckusick /* 420*45098Smckusick * Look ahead fuction. 421*45098Smckusick * Returns TRUE iff there is no more input in the buffer 422*45098Smckusick * after consuming the rest of the current record. 423*45098Smckusick */ 424*45098Smckusick bool_t 425*45098Smckusick xdrrec_eof(xdrs) 426*45098Smckusick XDR *xdrs; 427*45098Smckusick { 428*45098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 429*45098Smckusick 430*45098Smckusick while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { 431*45098Smckusick if (! skip_input_bytes(rstrm, rstrm->fbtbc)) 432*45098Smckusick return (TRUE); 433*45098Smckusick rstrm->fbtbc = 0; 434*45098Smckusick if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) 435*45098Smckusick return (TRUE); 436*45098Smckusick } 437*45098Smckusick if (rstrm->in_finger == rstrm->in_boundry) 438*45098Smckusick return (TRUE); 439*45098Smckusick return (FALSE); 440*45098Smckusick } 441*45098Smckusick 442*45098Smckusick /* 443*45098Smckusick * The client must tell the package when an end-of-record has occurred. 444*45098Smckusick * The second paraemters tells whether the record should be flushed to the 445*45098Smckusick * (output) tcp stream. (This let's the package support batched or 446*45098Smckusick * pipelined procedure calls.) TRUE => immmediate flush to tcp connection. 447*45098Smckusick */ 448*45098Smckusick bool_t 449*45098Smckusick xdrrec_endofrecord(xdrs, sendnow) 450*45098Smckusick XDR *xdrs; 451*45098Smckusick bool_t sendnow; 452*45098Smckusick { 453*45098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 454*45098Smckusick register u_long len; /* fragment length */ 455*45098Smckusick 456*45098Smckusick if (sendnow || rstrm->frag_sent || 457*45098Smckusick ((u_long)rstrm->out_finger + sizeof(u_long) >= 458*45098Smckusick (u_long)rstrm->out_boundry)) { 459*45098Smckusick rstrm->frag_sent = FALSE; 460*45098Smckusick return (flush_out(rstrm, TRUE)); 461*45098Smckusick } 462*45098Smckusick len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) - 463*45098Smckusick sizeof(u_long); 464*45098Smckusick *(rstrm->frag_header) = htonl((u_long)len | LAST_FRAG); 465*45098Smckusick rstrm->frag_header = (u_long *)rstrm->out_finger; 466*45098Smckusick rstrm->out_finger += sizeof(u_long); 467*45098Smckusick return (TRUE); 468*45098Smckusick } 469*45098Smckusick 470*45098Smckusick 471*45098Smckusick /* 472*45098Smckusick * Internal useful routines 473*45098Smckusick */ 474*45098Smckusick static bool_t 475*45098Smckusick flush_out(rstrm, eor) 476*45098Smckusick register RECSTREAM *rstrm; 477*45098Smckusick bool_t eor; 478*45098Smckusick { 479*45098Smckusick register u_long eormask = (eor == TRUE) ? LAST_FRAG : 0; 480*45098Smckusick register u_long len = (u_long)(rstrm->out_finger) - 481*45098Smckusick (u_long)(rstrm->frag_header) - sizeof(u_long); 482*45098Smckusick 483*45098Smckusick *(rstrm->frag_header) = htonl(len | eormask); 484*45098Smckusick len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->out_base); 485*45098Smckusick if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len) 486*45098Smckusick != (int)len) 487*45098Smckusick return (FALSE); 488*45098Smckusick rstrm->frag_header = (u_long *)rstrm->out_base; 489*45098Smckusick rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(u_long); 490*45098Smckusick return (TRUE); 491*45098Smckusick } 492*45098Smckusick 493*45098Smckusick static bool_t /* knows nothing about records! Only about input buffers */ 494*45098Smckusick fill_input_buf(rstrm) 495*45098Smckusick register RECSTREAM *rstrm; 496*45098Smckusick { 497*45098Smckusick register caddr_t where; 498*45098Smckusick u_int i; 499*45098Smckusick register int len; 500*45098Smckusick 501*45098Smckusick where = rstrm->in_base; 502*45098Smckusick i = (u_int)rstrm->in_boundry % BYTES_PER_XDR_UNIT; 503*45098Smckusick where += i; 504*45098Smckusick len = rstrm->in_size - i; 505*45098Smckusick if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1) 506*45098Smckusick return (FALSE); 507*45098Smckusick rstrm->in_finger = where; 508*45098Smckusick where += len; 509*45098Smckusick rstrm->in_boundry = where; 510*45098Smckusick return (TRUE); 511*45098Smckusick } 512*45098Smckusick 513*45098Smckusick static bool_t /* knows nothing about records! Only about input buffers */ 514*45098Smckusick get_input_bytes(rstrm, addr, len) 515*45098Smckusick register RECSTREAM *rstrm; 516*45098Smckusick register caddr_t addr; 517*45098Smckusick register int len; 518*45098Smckusick { 519*45098Smckusick register int current; 520*45098Smckusick 521*45098Smckusick while (len > 0) { 522*45098Smckusick current = (int)rstrm->in_boundry - (int)rstrm->in_finger; 523*45098Smckusick if (current == 0) { 524*45098Smckusick if (! fill_input_buf(rstrm)) 525*45098Smckusick return (FALSE); 526*45098Smckusick continue; 527*45098Smckusick } 528*45098Smckusick current = (len < current) ? len : current; 529*45098Smckusick bcopy(rstrm->in_finger, addr, current); 530*45098Smckusick rstrm->in_finger += current; 531*45098Smckusick addr += current; 532*45098Smckusick len -= current; 533*45098Smckusick } 534*45098Smckusick return (TRUE); 535*45098Smckusick } 536*45098Smckusick 537*45098Smckusick static bool_t /* next two bytes of the input stream are treated as a header */ 538*45098Smckusick set_input_fragment(rstrm) 539*45098Smckusick register RECSTREAM *rstrm; 540*45098Smckusick { 541*45098Smckusick u_long header; 542*45098Smckusick 543*45098Smckusick if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header))) 544*45098Smckusick return (FALSE); 545*45098Smckusick header = (long)ntohl(header); 546*45098Smckusick rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; 547*45098Smckusick rstrm->fbtbc = header & (~LAST_FRAG); 548*45098Smckusick return (TRUE); 549*45098Smckusick } 550*45098Smckusick 551*45098Smckusick static bool_t /* consumes input bytes; knows nothing about records! */ 552*45098Smckusick skip_input_bytes(rstrm, cnt) 553*45098Smckusick register RECSTREAM *rstrm; 554*45098Smckusick long cnt; 555*45098Smckusick { 556*45098Smckusick register int current; 557*45098Smckusick 558*45098Smckusick while (cnt > 0) { 559*45098Smckusick current = (int)rstrm->in_boundry - (int)rstrm->in_finger; 560*45098Smckusick if (current == 0) { 561*45098Smckusick if (! fill_input_buf(rstrm)) 562*45098Smckusick return (FALSE); 563*45098Smckusick continue; 564*45098Smckusick } 565*45098Smckusick current = (cnt < current) ? cnt : current; 566*45098Smckusick rstrm->in_finger += current; 567*45098Smckusick cnt -= current; 568*45098Smckusick } 569*45098Smckusick return (TRUE); 570*45098Smckusick } 571*45098Smckusick 572*45098Smckusick static u_int 573*45098Smckusick fix_buf_size(s) 574*45098Smckusick register u_int s; 575*45098Smckusick { 576*45098Smckusick 577*45098Smckusick if (s < 100) 578*45098Smckusick s = 4000; 579*45098Smckusick return (RNDUP(s)); 580*45098Smckusick } 581