145098Smckusick /* @(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC */ 245098Smckusick /* 345098Smckusick * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 445098Smckusick * unrestricted use provided that this legend is included on all tape 545098Smckusick * media and as a part of the software program in whole or part. Users 645098Smckusick * may copy or modify Sun RPC without charge, but are not authorized 745098Smckusick * to license or distribute it to anyone else except as part of a product or 845098Smckusick * program developed by the user. 945098Smckusick * 1045098Smckusick * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 1145098Smckusick * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 1245098Smckusick * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 1345098Smckusick * 1445098Smckusick * Sun RPC is provided with no support and without any obligation on the 1545098Smckusick * part of Sun Microsystems, Inc. to assist in its use, correction, 1645098Smckusick * modification or enhancement. 1745098Smckusick * 1845098Smckusick * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 1945098Smckusick * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 2045098Smckusick * OR ANY PART THEREOF. 2145098Smckusick * 2245098Smckusick * In no event will Sun Microsystems, Inc. be liable for any lost revenue 2345098Smckusick * or profits or other special, indirect and consequential damages, even if 2445098Smckusick * Sun has been advised of the possibility of such damages. 2545098Smckusick * 2645098Smckusick * Sun Microsystems, Inc. 2745098Smckusick * 2550 Garcia Avenue 2845098Smckusick * Mountain View, California 94043 2945098Smckusick */ 3045098Smckusick #if !defined(lint) && defined(SCCSIDS) 3145098Smckusick static char sccsid[] = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 3245098Smckusick #endif 3345098Smckusick 3445098Smckusick /* 3545098Smckusick * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking" 3645098Smckusick * layer above tcp (for rpc's use). 3745098Smckusick * 3845098Smckusick * Copyright (C) 1984, Sun Microsystems, Inc. 3945098Smckusick * 4045098Smckusick * These routines interface XDRSTREAMS to a tcp/ip connection. 4145098Smckusick * There is a record marking layer between the xdr stream 4245098Smckusick * and the tcp transport level. A record is composed on one or more 4345098Smckusick * record fragments. A record fragment is a thirty-two bit header followed 4445098Smckusick * by n bytes of data, where n is contained in the header. The header 4545098Smckusick * is represented as a htonl(u_long). Thegh order bit encodes 4645098Smckusick * whether or not the fragment is the last fragment of the record 4745098Smckusick * (1 => fragment is last, 0 => more fragments to follow. 4845098Smckusick * The other 31 bits encode the byte length of the fragment. 4945098Smckusick */ 5045098Smckusick 5145098Smckusick #include <stdio.h> 5245098Smckusick #include <rpc/types.h> 5345098Smckusick #include <rpc/xdr.h> 5445098Smckusick #include <netinet/in.h> 5545098Smckusick 5645098Smckusick extern long lseek(); 5745098Smckusick 5845098Smckusick static u_int fix_buf_size(); 59*46639Sbostic static bool_t flush_out(); 60*46639Sbostic static bool_t get_input_bytes(); 61*46639Sbostic static bool_t set_input_fragment(); 62*46639Sbostic static bool_t skip_input_bytes(); 6345098Smckusick 6445098Smckusick static bool_t xdrrec_getlong(); 6545098Smckusick static bool_t xdrrec_putlong(); 6645098Smckusick static bool_t xdrrec_getbytes(); 6745098Smckusick static bool_t xdrrec_putbytes(); 6845098Smckusick static u_int xdrrec_getpos(); 6945098Smckusick static bool_t xdrrec_setpos(); 7045098Smckusick static long * xdrrec_inline(); 7145098Smckusick static void xdrrec_destroy(); 7245098Smckusick 7345098Smckusick static struct xdr_ops xdrrec_ops = { 7445098Smckusick xdrrec_getlong, 7545098Smckusick xdrrec_putlong, 7645098Smckusick xdrrec_getbytes, 7745098Smckusick xdrrec_putbytes, 7845098Smckusick xdrrec_getpos, 7945098Smckusick xdrrec_setpos, 8045098Smckusick xdrrec_inline, 8145098Smckusick xdrrec_destroy 8245098Smckusick }; 8345098Smckusick 8445098Smckusick /* 8545098Smckusick * A record is composed of one or more record fragments. 8645098Smckusick * A record fragment is a two-byte header followed by zero to 8745098Smckusick * 2**32-1 bytes. The header is treated as a long unsigned and is 8845098Smckusick * encode/decoded to the network via htonl/ntohl. The low order 31 bits 8945098Smckusick * are a byte count of the fragment. The highest order bit is a boolean: 9045098Smckusick * 1 => this fragment is the last fragment of the record, 9145098Smckusick * 0 => this fragment is followed by more fragment(s). 9245098Smckusick * 9345098Smckusick * The fragment/record machinery is not general; it is constructed to 9445098Smckusick * meet the needs of xdr and rpc based on tcp. 9545098Smckusick */ 9645098Smckusick 9745098Smckusick #define LAST_FRAG ((u_long)(1 << 31)) 9845098Smckusick 9945098Smckusick typedef struct rec_strm { 10045098Smckusick caddr_t tcp_handle; 10145098Smckusick caddr_t the_buffer; 10245098Smckusick /* 10345098Smckusick * out-goung bits 10445098Smckusick */ 10545098Smckusick int (*writeit)(); 10645098Smckusick caddr_t out_base; /* output buffer (points to frag header) */ 10745098Smckusick caddr_t out_finger; /* next output position */ 10845098Smckusick caddr_t out_boundry; /* data cannot up to this address */ 10945098Smckusick u_long *frag_header; /* beginning of curren fragment */ 11045098Smckusick bool_t frag_sent; /* true if buffer sent in middle of record */ 11145098Smckusick /* 11245098Smckusick * in-coming bits 11345098Smckusick */ 11445098Smckusick int (*readit)(); 11545098Smckusick u_long in_size; /* fixed size of the input buffer */ 11645098Smckusick caddr_t in_base; 11745098Smckusick caddr_t in_finger; /* location of next byte to be had */ 11845098Smckusick caddr_t in_boundry; /* can read up to this location */ 11945098Smckusick long fbtbc; /* fragment bytes to be consumed */ 12045098Smckusick bool_t last_frag; 12145098Smckusick u_int sendsize; 12245098Smckusick u_int recvsize; 12345098Smckusick } RECSTREAM; 12445098Smckusick 12545098Smckusick 12645098Smckusick /* 12745098Smckusick * Create an xdr handle for xdrrec 12845098Smckusick * xdrrec_create fills in xdrs. Sendsize and recvsize are 12945098Smckusick * send and recv buffer sizes (0 => use default). 13045098Smckusick * tcp_handle is an opaque handle that is passed as the first parameter to 13145098Smckusick * the procedures readit and writeit. Readit and writeit are read and 13245098Smckusick * write respectively. They are like the system 13345098Smckusick * calls expect that they take an opaque handle rather than an fd. 13445098Smckusick */ 13545098Smckusick void 13645098Smckusick xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit) 13745098Smckusick register XDR *xdrs; 13845098Smckusick register u_int sendsize; 13945098Smckusick register u_int recvsize; 14045098Smckusick caddr_t tcp_handle; 14145098Smckusick int (*readit)(); /* like read, but pass it a tcp_handle, not sock */ 14245098Smckusick int (*writeit)(); /* like write, but pass it a tcp_handle, not sock */ 14345098Smckusick { 14445098Smckusick register RECSTREAM *rstrm = 14545098Smckusick (RECSTREAM *)mem_alloc(sizeof(RECSTREAM)); 14645098Smckusick 14745098Smckusick if (rstrm == NULL) { 14845098Smckusick (void)fprintf(stderr, "xdrrec_create: out of memory\n"); 14945098Smckusick /* 15045098Smckusick * This is bad. Should rework xdrrec_create to 15145098Smckusick * return a handle, and in this case return NULL 15245098Smckusick */ 15345098Smckusick return; 15445098Smckusick } 15545098Smckusick /* 15645098Smckusick * adjust sizes and allocate buffer quad byte aligned 15745098Smckusick */ 15845098Smckusick rstrm->sendsize = sendsize = fix_buf_size(sendsize); 15945098Smckusick rstrm->recvsize = recvsize = fix_buf_size(recvsize); 16045098Smckusick rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT); 16145098Smckusick if (rstrm->the_buffer == NULL) { 16245098Smckusick (void)fprintf(stderr, "xdrrec_create: out of memory\n"); 16345098Smckusick return; 16445098Smckusick } 16545098Smckusick for (rstrm->out_base = rstrm->the_buffer; 16645098Smckusick (u_int)rstrm->out_base % BYTES_PER_XDR_UNIT != 0; 16745098Smckusick rstrm->out_base++); 16845098Smckusick rstrm->in_base = rstrm->out_base + sendsize; 16945098Smckusick /* 17045098Smckusick * now the rest ... 17145098Smckusick */ 17245098Smckusick xdrs->x_ops = &xdrrec_ops; 17345098Smckusick xdrs->x_private = (caddr_t)rstrm; 17445098Smckusick rstrm->tcp_handle = tcp_handle; 17545098Smckusick rstrm->readit = readit; 17645098Smckusick rstrm->writeit = writeit; 17745098Smckusick rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; 17845098Smckusick rstrm->frag_header = (u_long *)rstrm->out_base; 17945098Smckusick rstrm->out_finger += sizeof(u_long); 18045098Smckusick rstrm->out_boundry += sendsize; 18145098Smckusick rstrm->frag_sent = FALSE; 18245098Smckusick rstrm->in_size = recvsize; 18345098Smckusick rstrm->in_boundry = rstrm->in_base; 18445098Smckusick rstrm->in_finger = (rstrm->in_boundry += recvsize); 18545098Smckusick rstrm->fbtbc = 0; 18645098Smckusick rstrm->last_frag = TRUE; 18745098Smckusick } 18845098Smckusick 18945098Smckusick 19045098Smckusick /* 19145098Smckusick * The reoutines defined below are the xdr ops which will go into the 19245098Smckusick * xdr handle filled in by xdrrec_create. 19345098Smckusick */ 19445098Smckusick 19545098Smckusick static bool_t 19645098Smckusick xdrrec_getlong(xdrs, lp) 19745098Smckusick XDR *xdrs; 19845098Smckusick long *lp; 19945098Smckusick { 20045098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 20145098Smckusick register long *buflp = (long *)(rstrm->in_finger); 20245098Smckusick long mylong; 20345098Smckusick 20445098Smckusick /* first try the inline, fast case */ 20545098Smckusick if ((rstrm->fbtbc >= sizeof(long)) && 20645098Smckusick (((int)rstrm->in_boundry - (int)buflp) >= sizeof(long))) { 20745098Smckusick *lp = (long)ntohl((u_long)(*buflp)); 20845098Smckusick rstrm->fbtbc -= sizeof(long); 20945098Smckusick rstrm->in_finger += sizeof(long); 21045098Smckusick } else { 21145098Smckusick if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof(long))) 21245098Smckusick return (FALSE); 21345098Smckusick *lp = (long)ntohl((u_long)mylong); 21445098Smckusick } 21545098Smckusick return (TRUE); 21645098Smckusick } 21745098Smckusick 21845098Smckusick static bool_t 21945098Smckusick xdrrec_putlong(xdrs, lp) 22045098Smckusick XDR *xdrs; 22145098Smckusick long *lp; 22245098Smckusick { 22345098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 22445098Smckusick register long *dest_lp = ((long *)(rstrm->out_finger)); 22545098Smckusick 22645098Smckusick if ((rstrm->out_finger += sizeof(long)) > rstrm->out_boundry) { 22745098Smckusick /* 22845098Smckusick * this case should almost never happen so the code is 22945098Smckusick * inefficient 23045098Smckusick */ 23145098Smckusick rstrm->out_finger -= sizeof(long); 23245098Smckusick rstrm->frag_sent = TRUE; 23345098Smckusick if (! flush_out(rstrm, FALSE)) 23445098Smckusick return (FALSE); 23545098Smckusick dest_lp = ((long *)(rstrm->out_finger)); 23645098Smckusick rstrm->out_finger += sizeof(long); 23745098Smckusick } 23845098Smckusick *dest_lp = (long)htonl((u_long)(*lp)); 23945098Smckusick return (TRUE); 24045098Smckusick } 24145098Smckusick 24245098Smckusick static bool_t /* must manage buffers, fragments, and records */ 24345098Smckusick xdrrec_getbytes(xdrs, addr, len) 24445098Smckusick XDR *xdrs; 24545098Smckusick register caddr_t addr; 24645098Smckusick register u_int len; 24745098Smckusick { 24845098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 24945098Smckusick register int current; 25045098Smckusick 25145098Smckusick while (len > 0) { 25245098Smckusick current = rstrm->fbtbc; 25345098Smckusick if (current == 0) { 25445098Smckusick if (rstrm->last_frag) 25545098Smckusick return (FALSE); 25645098Smckusick if (! set_input_fragment(rstrm)) 25745098Smckusick return (FALSE); 25845098Smckusick continue; 25945098Smckusick } 26045098Smckusick current = (len < current) ? len : current; 26145098Smckusick if (! get_input_bytes(rstrm, addr, current)) 26245098Smckusick return (FALSE); 26345098Smckusick addr += current; 26445098Smckusick rstrm->fbtbc -= current; 26545098Smckusick len -= current; 26645098Smckusick } 26745098Smckusick return (TRUE); 26845098Smckusick } 26945098Smckusick 27045098Smckusick static bool_t 27145098Smckusick xdrrec_putbytes(xdrs, addr, len) 27245098Smckusick XDR *xdrs; 27345098Smckusick register caddr_t addr; 27445098Smckusick register u_int len; 27545098Smckusick { 27645098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 27745098Smckusick register int current; 27845098Smckusick 27945098Smckusick while (len > 0) { 28045098Smckusick current = (u_int)rstrm->out_boundry - (u_int)rstrm->out_finger; 28145098Smckusick current = (len < current) ? len : current; 28245098Smckusick bcopy(addr, rstrm->out_finger, current); 28345098Smckusick rstrm->out_finger += current; 28445098Smckusick addr += current; 28545098Smckusick len -= current; 28645098Smckusick if (rstrm->out_finger == rstrm->out_boundry) { 28745098Smckusick rstrm->frag_sent = TRUE; 28845098Smckusick if (! flush_out(rstrm, FALSE)) 28945098Smckusick return (FALSE); 29045098Smckusick } 29145098Smckusick } 29245098Smckusick return (TRUE); 29345098Smckusick } 29445098Smckusick 29545098Smckusick static u_int 29645098Smckusick xdrrec_getpos(xdrs) 29745098Smckusick register XDR *xdrs; 29845098Smckusick { 29945098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 30045098Smckusick register long pos; 30145098Smckusick 30245098Smckusick pos = lseek((int)rstrm->tcp_handle, (long) 0, 1); 30345098Smckusick if (pos != -1) 30445098Smckusick switch (xdrs->x_op) { 30545098Smckusick 30645098Smckusick case XDR_ENCODE: 30745098Smckusick pos += rstrm->out_finger - rstrm->out_base; 30845098Smckusick break; 30945098Smckusick 31045098Smckusick case XDR_DECODE: 31145098Smckusick pos -= rstrm->in_boundry - rstrm->in_finger; 31245098Smckusick break; 31345098Smckusick 31445098Smckusick default: 31545098Smckusick pos = (u_int) -1; 31645098Smckusick break; 31745098Smckusick } 31845098Smckusick return ((u_int) pos); 31945098Smckusick } 32045098Smckusick 32145098Smckusick static bool_t 32245098Smckusick xdrrec_setpos(xdrs, pos) 32345098Smckusick register XDR *xdrs; 32445098Smckusick u_int pos; 32545098Smckusick { 32645098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 32745098Smckusick u_int currpos = xdrrec_getpos(xdrs); 32845098Smckusick int delta = currpos - pos; 32945098Smckusick caddr_t newpos; 33045098Smckusick 33145098Smckusick if ((int)currpos != -1) 33245098Smckusick switch (xdrs->x_op) { 33345098Smckusick 33445098Smckusick case XDR_ENCODE: 33545098Smckusick newpos = rstrm->out_finger - delta; 33645098Smckusick if ((newpos > (caddr_t)(rstrm->frag_header)) && 33745098Smckusick (newpos < rstrm->out_boundry)) { 33845098Smckusick rstrm->out_finger = newpos; 33945098Smckusick return (TRUE); 34045098Smckusick } 34145098Smckusick break; 34245098Smckusick 34345098Smckusick case XDR_DECODE: 34445098Smckusick newpos = rstrm->in_finger - delta; 34545098Smckusick if ((delta < (int)(rstrm->fbtbc)) && 34645098Smckusick (newpos <= rstrm->in_boundry) && 34745098Smckusick (newpos >= rstrm->in_base)) { 34845098Smckusick rstrm->in_finger = newpos; 34945098Smckusick rstrm->fbtbc -= delta; 35045098Smckusick return (TRUE); 35145098Smckusick } 35245098Smckusick break; 35345098Smckusick } 35445098Smckusick return (FALSE); 35545098Smckusick } 35645098Smckusick 35745098Smckusick static long * 35845098Smckusick xdrrec_inline(xdrs, len) 35945098Smckusick register XDR *xdrs; 36045098Smckusick int len; 36145098Smckusick { 36245098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 36345098Smckusick long * buf = NULL; 36445098Smckusick 36545098Smckusick switch (xdrs->x_op) { 36645098Smckusick 36745098Smckusick case XDR_ENCODE: 36845098Smckusick if ((rstrm->out_finger + len) <= rstrm->out_boundry) { 36945098Smckusick buf = (long *) rstrm->out_finger; 37045098Smckusick rstrm->out_finger += len; 37145098Smckusick } 37245098Smckusick break; 37345098Smckusick 37445098Smckusick case XDR_DECODE: 37545098Smckusick if ((len <= rstrm->fbtbc) && 37645098Smckusick ((rstrm->in_finger + len) <= rstrm->in_boundry)) { 37745098Smckusick buf = (long *) rstrm->in_finger; 37845098Smckusick rstrm->fbtbc -= len; 37945098Smckusick rstrm->in_finger += len; 38045098Smckusick } 38145098Smckusick break; 38245098Smckusick } 38345098Smckusick return (buf); 38445098Smckusick } 38545098Smckusick 38645098Smckusick static void 38745098Smckusick xdrrec_destroy(xdrs) 38845098Smckusick register XDR *xdrs; 38945098Smckusick { 39045098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 39145098Smckusick 39245098Smckusick mem_free(rstrm->the_buffer, 39345098Smckusick rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT); 39445098Smckusick mem_free((caddr_t)rstrm, sizeof(RECSTREAM)); 39545098Smckusick } 39645098Smckusick 39745098Smckusick 39845098Smckusick /* 39945098Smckusick * Exported routines to manage xdr records 40045098Smckusick */ 40145098Smckusick 40245098Smckusick /* 40345098Smckusick * Before reading (deserializing from the stream, one should always call 40445098Smckusick * this procedure to guarantee proper record alignment. 40545098Smckusick */ 40645098Smckusick bool_t 40745098Smckusick xdrrec_skiprecord(xdrs) 40845098Smckusick XDR *xdrs; 40945098Smckusick { 41045098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 41145098Smckusick 41245098Smckusick while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { 41345098Smckusick if (! skip_input_bytes(rstrm, rstrm->fbtbc)) 41445098Smckusick return (FALSE); 41545098Smckusick rstrm->fbtbc = 0; 41645098Smckusick if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) 41745098Smckusick return (FALSE); 41845098Smckusick } 41945098Smckusick rstrm->last_frag = FALSE; 42045098Smckusick return (TRUE); 42145098Smckusick } 42245098Smckusick 42345098Smckusick /* 42445098Smckusick * Look ahead fuction. 42545098Smckusick * Returns TRUE iff there is no more input in the buffer 42645098Smckusick * after consuming the rest of the current record. 42745098Smckusick */ 42845098Smckusick bool_t 42945098Smckusick xdrrec_eof(xdrs) 43045098Smckusick XDR *xdrs; 43145098Smckusick { 43245098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 43345098Smckusick 43445098Smckusick while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { 43545098Smckusick if (! skip_input_bytes(rstrm, rstrm->fbtbc)) 43645098Smckusick return (TRUE); 43745098Smckusick rstrm->fbtbc = 0; 43845098Smckusick if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) 43945098Smckusick return (TRUE); 44045098Smckusick } 44145098Smckusick if (rstrm->in_finger == rstrm->in_boundry) 44245098Smckusick return (TRUE); 44345098Smckusick return (FALSE); 44445098Smckusick } 44545098Smckusick 44645098Smckusick /* 44745098Smckusick * The client must tell the package when an end-of-record has occurred. 44845098Smckusick * The second paraemters tells whether the record should be flushed to the 44945098Smckusick * (output) tcp stream. (This let's the package support batched or 45045098Smckusick * pipelined procedure calls.) TRUE => immmediate flush to tcp connection. 45145098Smckusick */ 45245098Smckusick bool_t 45345098Smckusick xdrrec_endofrecord(xdrs, sendnow) 45445098Smckusick XDR *xdrs; 45545098Smckusick bool_t sendnow; 45645098Smckusick { 45745098Smckusick register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 45845098Smckusick register u_long len; /* fragment length */ 45945098Smckusick 46045098Smckusick if (sendnow || rstrm->frag_sent || 46145098Smckusick ((u_long)rstrm->out_finger + sizeof(u_long) >= 46245098Smckusick (u_long)rstrm->out_boundry)) { 46345098Smckusick rstrm->frag_sent = FALSE; 46445098Smckusick return (flush_out(rstrm, TRUE)); 46545098Smckusick } 46645098Smckusick len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) - 46745098Smckusick sizeof(u_long); 46845098Smckusick *(rstrm->frag_header) = htonl((u_long)len | LAST_FRAG); 46945098Smckusick rstrm->frag_header = (u_long *)rstrm->out_finger; 47045098Smckusick rstrm->out_finger += sizeof(u_long); 47145098Smckusick return (TRUE); 47245098Smckusick } 47345098Smckusick 47445098Smckusick 47545098Smckusick /* 47645098Smckusick * Internal useful routines 47745098Smckusick */ 47845098Smckusick static bool_t 47945098Smckusick flush_out(rstrm, eor) 48045098Smckusick register RECSTREAM *rstrm; 48145098Smckusick bool_t eor; 48245098Smckusick { 48345098Smckusick register u_long eormask = (eor == TRUE) ? LAST_FRAG : 0; 48445098Smckusick register u_long len = (u_long)(rstrm->out_finger) - 48545098Smckusick (u_long)(rstrm->frag_header) - sizeof(u_long); 48645098Smckusick 48745098Smckusick *(rstrm->frag_header) = htonl(len | eormask); 48845098Smckusick len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->out_base); 48945098Smckusick if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len) 49045098Smckusick != (int)len) 49145098Smckusick return (FALSE); 49245098Smckusick rstrm->frag_header = (u_long *)rstrm->out_base; 49345098Smckusick rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(u_long); 49445098Smckusick return (TRUE); 49545098Smckusick } 49645098Smckusick 49745098Smckusick static bool_t /* knows nothing about records! Only about input buffers */ 49845098Smckusick fill_input_buf(rstrm) 49945098Smckusick register RECSTREAM *rstrm; 50045098Smckusick { 50145098Smckusick register caddr_t where; 50245098Smckusick u_int i; 50345098Smckusick register int len; 50445098Smckusick 50545098Smckusick where = rstrm->in_base; 50645098Smckusick i = (u_int)rstrm->in_boundry % BYTES_PER_XDR_UNIT; 50745098Smckusick where += i; 50845098Smckusick len = rstrm->in_size - i; 50945098Smckusick if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1) 51045098Smckusick return (FALSE); 51145098Smckusick rstrm->in_finger = where; 51245098Smckusick where += len; 51345098Smckusick rstrm->in_boundry = where; 51445098Smckusick return (TRUE); 51545098Smckusick } 51645098Smckusick 51745098Smckusick static bool_t /* knows nothing about records! Only about input buffers */ 51845098Smckusick get_input_bytes(rstrm, addr, len) 51945098Smckusick register RECSTREAM *rstrm; 52045098Smckusick register caddr_t addr; 52145098Smckusick register int len; 52245098Smckusick { 52345098Smckusick register int current; 52445098Smckusick 52545098Smckusick while (len > 0) { 52645098Smckusick current = (int)rstrm->in_boundry - (int)rstrm->in_finger; 52745098Smckusick if (current == 0) { 52845098Smckusick if (! fill_input_buf(rstrm)) 52945098Smckusick return (FALSE); 53045098Smckusick continue; 53145098Smckusick } 53245098Smckusick current = (len < current) ? len : current; 53345098Smckusick bcopy(rstrm->in_finger, addr, current); 53445098Smckusick rstrm->in_finger += current; 53545098Smckusick addr += current; 53645098Smckusick len -= current; 53745098Smckusick } 53845098Smckusick return (TRUE); 53945098Smckusick } 54045098Smckusick 54145098Smckusick static bool_t /* next two bytes of the input stream are treated as a header */ 54245098Smckusick set_input_fragment(rstrm) 54345098Smckusick register RECSTREAM *rstrm; 54445098Smckusick { 54545098Smckusick u_long header; 54645098Smckusick 54745098Smckusick if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header))) 54845098Smckusick return (FALSE); 54945098Smckusick header = (long)ntohl(header); 55045098Smckusick rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; 55145098Smckusick rstrm->fbtbc = header & (~LAST_FRAG); 55245098Smckusick return (TRUE); 55345098Smckusick } 55445098Smckusick 55545098Smckusick static bool_t /* consumes input bytes; knows nothing about records! */ 55645098Smckusick skip_input_bytes(rstrm, cnt) 55745098Smckusick register RECSTREAM *rstrm; 55845098Smckusick long cnt; 55945098Smckusick { 56045098Smckusick register int current; 56145098Smckusick 56245098Smckusick while (cnt > 0) { 56345098Smckusick current = (int)rstrm->in_boundry - (int)rstrm->in_finger; 56445098Smckusick if (current == 0) { 56545098Smckusick if (! fill_input_buf(rstrm)) 56645098Smckusick return (FALSE); 56745098Smckusick continue; 56845098Smckusick } 56945098Smckusick current = (cnt < current) ? cnt : current; 57045098Smckusick rstrm->in_finger += current; 57145098Smckusick cnt -= current; 57245098Smckusick } 57345098Smckusick return (TRUE); 57445098Smckusick } 57545098Smckusick 57645098Smckusick static u_int 57745098Smckusick fix_buf_size(s) 57845098Smckusick register u_int s; 57945098Smckusick { 58045098Smckusick 58145098Smckusick if (s < 100) 58245098Smckusick s = 4000; 58345098Smckusick return (RNDUP(s)); 58445098Smckusick } 585