18360efbdSAlfred Perlstein /* $NetBSD: xdr_rec.c,v 1.18 2000/07/06 03:10:35 christos Exp $ */ 28360efbdSAlfred Perlstein 3eae561b3SGarrett Wollman /* 4eae561b3SGarrett Wollman * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5eae561b3SGarrett Wollman * unrestricted use provided that this legend is included on all tape 6eae561b3SGarrett Wollman * media and as a part of the software program in whole or part. Users 7eae561b3SGarrett Wollman * may copy or modify Sun RPC without charge, but are not authorized 8eae561b3SGarrett Wollman * to license or distribute it to anyone else except as part of a product or 9eae561b3SGarrett Wollman * program developed by the user. 10eae561b3SGarrett Wollman * 11eae561b3SGarrett Wollman * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12eae561b3SGarrett Wollman * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13eae561b3SGarrett Wollman * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14eae561b3SGarrett Wollman * 15eae561b3SGarrett Wollman * Sun RPC is provided with no support and without any obligation on the 16eae561b3SGarrett Wollman * part of Sun Microsystems, Inc. to assist in its use, correction, 17eae561b3SGarrett Wollman * modification or enhancement. 18eae561b3SGarrett Wollman * 19eae561b3SGarrett Wollman * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20eae561b3SGarrett Wollman * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21eae561b3SGarrett Wollman * OR ANY PART THEREOF. 22eae561b3SGarrett Wollman * 23eae561b3SGarrett Wollman * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24eae561b3SGarrett Wollman * or profits or other special, indirect and consequential damages, even if 25eae561b3SGarrett Wollman * Sun has been advised of the possibility of such damages. 26eae561b3SGarrett Wollman * 27eae561b3SGarrett Wollman * Sun Microsystems, Inc. 28eae561b3SGarrett Wollman * 2550 Garcia Avenue 29eae561b3SGarrett Wollman * Mountain View, California 94043 30eae561b3SGarrett Wollman */ 318360efbdSAlfred Perlstein 328360efbdSAlfred Perlstein #include <sys/cdefs.h> 33eae561b3SGarrett Wollman #if defined(LIBC_SCCS) && !defined(lint) 34333fc21eSDavid E. O'Brien static char *sccsid = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 35333fc21eSDavid E. O'Brien static char *sccsid = "@(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC"; 36eae561b3SGarrett Wollman #endif 37333fc21eSDavid E. O'Brien #include <sys/cdefs.h> 38333fc21eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 39eae561b3SGarrett Wollman 40eae561b3SGarrett Wollman /* 41eae561b3SGarrett Wollman * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking" 42eae561b3SGarrett Wollman * layer above tcp (for rpc's use). 43eae561b3SGarrett Wollman * 44eae561b3SGarrett Wollman * Copyright (C) 1984, Sun Microsystems, Inc. 45eae561b3SGarrett Wollman * 46eae561b3SGarrett Wollman * These routines interface XDRSTREAMS to a tcp/ip connection. 47eae561b3SGarrett Wollman * There is a record marking layer between the xdr stream 48eae561b3SGarrett Wollman * and the tcp transport level. A record is composed on one or more 49eae561b3SGarrett Wollman * record fragments. A record fragment is a thirty-two bit header followed 50eae561b3SGarrett Wollman * by n bytes of data, where n is contained in the header. The header 51eae561b3SGarrett Wollman * is represented as a htonl(u_long). Thegh order bit encodes 52eae561b3SGarrett Wollman * whether or not the fragment is the last fragment of the record 53eae561b3SGarrett Wollman * (1 => fragment is last, 0 => more fragments to follow. 54eae561b3SGarrett Wollman * The other 31 bits encode the byte length of the fragment. 55eae561b3SGarrett Wollman */ 56eae561b3SGarrett Wollman 578360efbdSAlfred Perlstein #include "namespace.h" 588360efbdSAlfred Perlstein #include <sys/types.h> 598360efbdSAlfred Perlstein 608360efbdSAlfred Perlstein #include <netinet/in.h> 618360efbdSAlfred Perlstein 628360efbdSAlfred Perlstein #include <err.h> 63eae561b3SGarrett Wollman #include <stdio.h> 64eae561b3SGarrett Wollman #include <stdlib.h> 6529285d6cSPoul-Henning Kamp #include <string.h> 668360efbdSAlfred Perlstein 67eae561b3SGarrett Wollman #include <rpc/types.h> 68eae561b3SGarrett Wollman #include <rpc/xdr.h> 698360efbdSAlfred Perlstein #include "un-namespace.h" 70eae561b3SGarrett Wollman 71c05ac53bSDavid E. O'Brien static bool_t xdrrec_getlong(XDR *, long *); 72c05ac53bSDavid E. O'Brien static bool_t xdrrec_putlong(XDR *, const long *); 73c05ac53bSDavid E. O'Brien static bool_t xdrrec_getbytes(XDR *, char *, u_int); 74eae561b3SGarrett Wollman 75c05ac53bSDavid E. O'Brien static bool_t xdrrec_putbytes(XDR *, const char *, u_int); 76c05ac53bSDavid E. O'Brien static u_int xdrrec_getpos(XDR *); 77c05ac53bSDavid E. O'Brien static bool_t xdrrec_setpos(XDR *, u_int); 78c05ac53bSDavid E. O'Brien static int32_t *xdrrec_inline(XDR *, u_int); 79c05ac53bSDavid E. O'Brien static void xdrrec_destroy(XDR *); 80eae561b3SGarrett Wollman 818360efbdSAlfred Perlstein static const struct xdr_ops xdrrec_ops = { 82eae561b3SGarrett Wollman xdrrec_getlong, 83eae561b3SGarrett Wollman xdrrec_putlong, 84eae561b3SGarrett Wollman xdrrec_getbytes, 85eae561b3SGarrett Wollman xdrrec_putbytes, 86eae561b3SGarrett Wollman xdrrec_getpos, 87eae561b3SGarrett Wollman xdrrec_setpos, 88eae561b3SGarrett Wollman xdrrec_inline, 89eae561b3SGarrett Wollman xdrrec_destroy 90eae561b3SGarrett Wollman }; 91eae561b3SGarrett Wollman 92eae561b3SGarrett Wollman /* 93eae561b3SGarrett Wollman * A record is composed of one or more record fragments. 94eae561b3SGarrett Wollman * A record fragment is a two-byte header followed by zero to 95eae561b3SGarrett Wollman * 2**32-1 bytes. The header is treated as a long unsigned and is 96eae561b3SGarrett Wollman * encode/decoded to the network via htonl/ntohl. The low order 31 bits 97eae561b3SGarrett Wollman * are a byte count of the fragment. The highest order bit is a boolean: 98eae561b3SGarrett Wollman * 1 => this fragment is the last fragment of the record, 99eae561b3SGarrett Wollman * 0 => this fragment is followed by more fragment(s). 100eae561b3SGarrett Wollman * 101eae561b3SGarrett Wollman * The fragment/record machinery is not general; it is constructed to 102eae561b3SGarrett Wollman * meet the needs of xdr and rpc based on tcp. 103eae561b3SGarrett Wollman */ 104eae561b3SGarrett Wollman 1051ad08a09SPeter Wemm #define LAST_FRAG ((u_int32_t)(1 << 31)) 106eae561b3SGarrett Wollman 107eae561b3SGarrett Wollman typedef struct rec_strm { 1088360efbdSAlfred Perlstein char *tcp_handle; 1098360efbdSAlfred Perlstein char *the_buffer; 110eae561b3SGarrett Wollman /* 111eae561b3SGarrett Wollman * out-goung bits 112eae561b3SGarrett Wollman */ 113f249dbccSDag-Erling Smørgrav int (*writeit)(void *, void *, int); 1148360efbdSAlfred Perlstein char *out_base; /* output buffer (points to frag header) */ 1158360efbdSAlfred Perlstein char *out_finger; /* next output position */ 1168360efbdSAlfred Perlstein char *out_boundry; /* data cannot up to this address */ 1178360efbdSAlfred Perlstein u_int32_t *frag_header; /* beginning of curren fragment */ 118eae561b3SGarrett Wollman bool_t frag_sent; /* true if buffer sent in middle of record */ 119eae561b3SGarrett Wollman /* 120eae561b3SGarrett Wollman * in-coming bits 121eae561b3SGarrett Wollman */ 122f249dbccSDag-Erling Smørgrav int (*readit)(void *, void *, int); 123eae561b3SGarrett Wollman u_long in_size; /* fixed size of the input buffer */ 1248360efbdSAlfred Perlstein char *in_base; 1258360efbdSAlfred Perlstein char *in_finger; /* location of next byte to be had */ 1268360efbdSAlfred Perlstein char *in_boundry; /* can read up to this location */ 127eae561b3SGarrett Wollman long fbtbc; /* fragment bytes to be consumed */ 128eae561b3SGarrett Wollman bool_t last_frag; 129eae561b3SGarrett Wollman u_int sendsize; 130eae561b3SGarrett Wollman u_int recvsize; 131eae561b3SGarrett Wollman } RECSTREAM; 132eae561b3SGarrett Wollman 133c05ac53bSDavid E. O'Brien static u_int fix_buf_size(u_int); 134c05ac53bSDavid E. O'Brien static bool_t flush_out(RECSTREAM *, bool_t); 135c05ac53bSDavid E. O'Brien static bool_t fill_input_buf(RECSTREAM *); 136c05ac53bSDavid E. O'Brien static bool_t get_input_bytes(RECSTREAM *, char *, int); 137c05ac53bSDavid E. O'Brien static bool_t set_input_fragment(RECSTREAM *); 138c05ac53bSDavid E. O'Brien static bool_t skip_input_bytes(RECSTREAM *, long); 1398360efbdSAlfred Perlstein 140eae561b3SGarrett Wollman 141eae561b3SGarrett Wollman /* 142eae561b3SGarrett Wollman * Create an xdr handle for xdrrec 143eae561b3SGarrett Wollman * xdrrec_create fills in xdrs. Sendsize and recvsize are 144eae561b3SGarrett Wollman * send and recv buffer sizes (0 => use default). 145eae561b3SGarrett Wollman * tcp_handle is an opaque handle that is passed as the first parameter to 146eae561b3SGarrett Wollman * the procedures readit and writeit. Readit and writeit are read and 147eae561b3SGarrett Wollman * write respectively. They are like the system 148eae561b3SGarrett Wollman * calls expect that they take an opaque handle rather than an fd. 149eae561b3SGarrett Wollman */ 150eae561b3SGarrett Wollman void 151eae561b3SGarrett Wollman xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit) 1528360efbdSAlfred Perlstein XDR *xdrs; 1538360efbdSAlfred Perlstein u_int sendsize; 1548360efbdSAlfred Perlstein u_int recvsize; 155f249dbccSDag-Erling Smørgrav void *tcp_handle; 1568360efbdSAlfred Perlstein /* like read, but pass it a tcp_handle, not sock */ 157f249dbccSDag-Erling Smørgrav int (*readit)(void *, void *, int); 1588360efbdSAlfred Perlstein /* like write, but pass it a tcp_handle, not sock */ 159f249dbccSDag-Erling Smørgrav int (*writeit)(void *, void *, int); 160eae561b3SGarrett Wollman { 1618360efbdSAlfred Perlstein RECSTREAM *rstrm = mem_alloc(sizeof(RECSTREAM)); 162eae561b3SGarrett Wollman 163eae561b3SGarrett Wollman if (rstrm == NULL) { 1648360efbdSAlfred Perlstein warnx("xdrrec_create: out of memory"); 165eae561b3SGarrett Wollman /* 166eae561b3SGarrett Wollman * This is bad. Should rework xdrrec_create to 167eae561b3SGarrett Wollman * return a handle, and in this case return NULL 168eae561b3SGarrett Wollman */ 169eae561b3SGarrett Wollman return; 170eae561b3SGarrett Wollman } 171eae561b3SGarrett Wollman /* 172eae561b3SGarrett Wollman * adjust sizes and allocate buffer quad byte aligned 173eae561b3SGarrett Wollman */ 174eae561b3SGarrett Wollman rstrm->sendsize = sendsize = fix_buf_size(sendsize); 175eae561b3SGarrett Wollman rstrm->recvsize = recvsize = fix_buf_size(recvsize); 176eae561b3SGarrett Wollman rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT); 177eae561b3SGarrett Wollman if (rstrm->the_buffer == NULL) { 1788360efbdSAlfred Perlstein warnx("xdrrec_create: out of memory"); 179eae561b3SGarrett Wollman return; 180eae561b3SGarrett Wollman } 181eae561b3SGarrett Wollman for (rstrm->out_base = rstrm->the_buffer; 1821ad08a09SPeter Wemm (u_long)rstrm->out_base % BYTES_PER_XDR_UNIT != 0; 183eae561b3SGarrett Wollman rstrm->out_base++); 184eae561b3SGarrett Wollman rstrm->in_base = rstrm->out_base + sendsize; 185eae561b3SGarrett Wollman /* 186eae561b3SGarrett Wollman * now the rest ... 187eae561b3SGarrett Wollman */ 188eae561b3SGarrett Wollman xdrs->x_ops = &xdrrec_ops; 1898360efbdSAlfred Perlstein xdrs->x_private = rstrm; 190eae561b3SGarrett Wollman rstrm->tcp_handle = tcp_handle; 191eae561b3SGarrett Wollman rstrm->readit = readit; 192eae561b3SGarrett Wollman rstrm->writeit = writeit; 193eae561b3SGarrett Wollman rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; 1948360efbdSAlfred Perlstein rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base; 1951ad08a09SPeter Wemm rstrm->out_finger += sizeof(u_int32_t); 196eae561b3SGarrett Wollman rstrm->out_boundry += sendsize; 197eae561b3SGarrett Wollman rstrm->frag_sent = FALSE; 198eae561b3SGarrett Wollman rstrm->in_size = recvsize; 199eae561b3SGarrett Wollman rstrm->in_boundry = rstrm->in_base; 200eae561b3SGarrett Wollman rstrm->in_finger = (rstrm->in_boundry += recvsize); 201eae561b3SGarrett Wollman rstrm->fbtbc = 0; 202eae561b3SGarrett Wollman rstrm->last_frag = TRUE; 203eae561b3SGarrett Wollman } 204eae561b3SGarrett Wollman 205eae561b3SGarrett Wollman 206eae561b3SGarrett Wollman /* 207eae561b3SGarrett Wollman * The reoutines defined below are the xdr ops which will go into the 208eae561b3SGarrett Wollman * xdr handle filled in by xdrrec_create. 209eae561b3SGarrett Wollman */ 210eae561b3SGarrett Wollman 211eae561b3SGarrett Wollman static bool_t 212eae561b3SGarrett Wollman xdrrec_getlong(xdrs, lp) 213eae561b3SGarrett Wollman XDR *xdrs; 214eae561b3SGarrett Wollman long *lp; 215eae561b3SGarrett Wollman { 2168360efbdSAlfred Perlstein RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 2178360efbdSAlfred Perlstein int32_t *buflp = (int32_t *)(void *)(rstrm->in_finger); 2181ad08a09SPeter Wemm int32_t mylong; 219eae561b3SGarrett Wollman 220eae561b3SGarrett Wollman /* first try the inline, fast case */ 2211ad08a09SPeter Wemm if ((rstrm->fbtbc >= sizeof(int32_t)) && 2221ad08a09SPeter Wemm (((long)rstrm->in_boundry - (long)buflp) >= sizeof(int32_t))) { 2231ad08a09SPeter Wemm *lp = (long)ntohl((u_int32_t)(*buflp)); 2241ad08a09SPeter Wemm rstrm->fbtbc -= sizeof(int32_t); 2251ad08a09SPeter Wemm rstrm->in_finger += sizeof(int32_t); 226eae561b3SGarrett Wollman } else { 2278360efbdSAlfred Perlstein if (! xdrrec_getbytes(xdrs, (char *)(void *)&mylong, 2288360efbdSAlfred Perlstein sizeof(int32_t))) 229eae561b3SGarrett Wollman return (FALSE); 2301ad08a09SPeter Wemm *lp = (long)ntohl((u_int32_t)mylong); 231eae561b3SGarrett Wollman } 232eae561b3SGarrett Wollman return (TRUE); 233eae561b3SGarrett Wollman } 234eae561b3SGarrett Wollman 235eae561b3SGarrett Wollman static bool_t 236eae561b3SGarrett Wollman xdrrec_putlong(xdrs, lp) 237eae561b3SGarrett Wollman XDR *xdrs; 2388360efbdSAlfred Perlstein const long *lp; 239eae561b3SGarrett Wollman { 2408360efbdSAlfred Perlstein RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 2418360efbdSAlfred Perlstein int32_t *dest_lp = ((int32_t *)(void *)(rstrm->out_finger)); 242eae561b3SGarrett Wollman 2431ad08a09SPeter Wemm if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry) { 244eae561b3SGarrett Wollman /* 245eae561b3SGarrett Wollman * this case should almost never happen so the code is 246eae561b3SGarrett Wollman * inefficient 247eae561b3SGarrett Wollman */ 2481ad08a09SPeter Wemm rstrm->out_finger -= sizeof(int32_t); 249eae561b3SGarrett Wollman rstrm->frag_sent = TRUE; 250eae561b3SGarrett Wollman if (! flush_out(rstrm, FALSE)) 251eae561b3SGarrett Wollman return (FALSE); 2528360efbdSAlfred Perlstein dest_lp = ((int32_t *)(void *)(rstrm->out_finger)); 2531ad08a09SPeter Wemm rstrm->out_finger += sizeof(int32_t); 254eae561b3SGarrett Wollman } 2551ad08a09SPeter Wemm *dest_lp = (int32_t)htonl((u_int32_t)(*lp)); 256eae561b3SGarrett Wollman return (TRUE); 257eae561b3SGarrett Wollman } 258eae561b3SGarrett Wollman 259eae561b3SGarrett Wollman static bool_t /* must manage buffers, fragments, and records */ 260eae561b3SGarrett Wollman xdrrec_getbytes(xdrs, addr, len) 261eae561b3SGarrett Wollman XDR *xdrs; 2628360efbdSAlfred Perlstein char *addr; 2638360efbdSAlfred Perlstein u_int len; 264eae561b3SGarrett Wollman { 2658360efbdSAlfred Perlstein RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 2668360efbdSAlfred Perlstein int current; 267eae561b3SGarrett Wollman 268eae561b3SGarrett Wollman while (len > 0) { 2698360efbdSAlfred Perlstein current = (int)rstrm->fbtbc; 270eae561b3SGarrett Wollman if (current == 0) { 271eae561b3SGarrett Wollman if (rstrm->last_frag) 272eae561b3SGarrett Wollman return (FALSE); 273eae561b3SGarrett Wollman if (! set_input_fragment(rstrm)) 274eae561b3SGarrett Wollman return (FALSE); 275eae561b3SGarrett Wollman continue; 276eae561b3SGarrett Wollman } 277eae561b3SGarrett Wollman current = (len < current) ? len : current; 278eae561b3SGarrett Wollman if (! get_input_bytes(rstrm, addr, current)) 279eae561b3SGarrett Wollman return (FALSE); 280eae561b3SGarrett Wollman addr += current; 281eae561b3SGarrett Wollman rstrm->fbtbc -= current; 282eae561b3SGarrett Wollman len -= current; 283eae561b3SGarrett Wollman } 284eae561b3SGarrett Wollman return (TRUE); 285eae561b3SGarrett Wollman } 286eae561b3SGarrett Wollman 287eae561b3SGarrett Wollman static bool_t 288eae561b3SGarrett Wollman xdrrec_putbytes(xdrs, addr, len) 289eae561b3SGarrett Wollman XDR *xdrs; 2908360efbdSAlfred Perlstein const char *addr; 2918360efbdSAlfred Perlstein u_int len; 292eae561b3SGarrett Wollman { 2938360efbdSAlfred Perlstein RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 2948360efbdSAlfred Perlstein size_t current; 295eae561b3SGarrett Wollman 296eae561b3SGarrett Wollman while (len > 0) { 2978360efbdSAlfred Perlstein current = (size_t)((u_long)rstrm->out_boundry - 2988360efbdSAlfred Perlstein (u_long)rstrm->out_finger); 299eae561b3SGarrett Wollman current = (len < current) ? len : current; 3008360efbdSAlfred Perlstein memmove(rstrm->out_finger, addr, current); 301eae561b3SGarrett Wollman rstrm->out_finger += current; 302eae561b3SGarrett Wollman addr += current; 303eae561b3SGarrett Wollman len -= current; 304eae561b3SGarrett Wollman if (rstrm->out_finger == rstrm->out_boundry) { 305eae561b3SGarrett Wollman rstrm->frag_sent = TRUE; 306eae561b3SGarrett Wollman if (! flush_out(rstrm, FALSE)) 307eae561b3SGarrett Wollman return (FALSE); 308eae561b3SGarrett Wollman } 309eae561b3SGarrett Wollman } 310eae561b3SGarrett Wollman return (TRUE); 311eae561b3SGarrett Wollman } 312eae561b3SGarrett Wollman 313eae561b3SGarrett Wollman static u_int 314eae561b3SGarrett Wollman xdrrec_getpos(xdrs) 3158360efbdSAlfred Perlstein XDR *xdrs; 316eae561b3SGarrett Wollman { 3178360efbdSAlfred Perlstein RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 3188360efbdSAlfred Perlstein off_t pos; 319eae561b3SGarrett Wollman 3208360efbdSAlfred Perlstein pos = lseek((int)(u_long)rstrm->tcp_handle, (off_t)0, 1); 321eae561b3SGarrett Wollman if (pos != -1) 322eae561b3SGarrett Wollman switch (xdrs->x_op) { 323eae561b3SGarrett Wollman 324eae561b3SGarrett Wollman case XDR_ENCODE: 325eae561b3SGarrett Wollman pos += rstrm->out_finger - rstrm->out_base; 326eae561b3SGarrett Wollman break; 327eae561b3SGarrett Wollman 328eae561b3SGarrett Wollman case XDR_DECODE: 329eae561b3SGarrett Wollman pos -= rstrm->in_boundry - rstrm->in_finger; 330eae561b3SGarrett Wollman break; 331eae561b3SGarrett Wollman 332eae561b3SGarrett Wollman default: 3338360efbdSAlfred Perlstein pos = (off_t) -1; 334eae561b3SGarrett Wollman break; 335eae561b3SGarrett Wollman } 336eae561b3SGarrett Wollman return ((u_int) pos); 337eae561b3SGarrett Wollman } 338eae561b3SGarrett Wollman 339eae561b3SGarrett Wollman static bool_t 340eae561b3SGarrett Wollman xdrrec_setpos(xdrs, pos) 3418360efbdSAlfred Perlstein XDR *xdrs; 342eae561b3SGarrett Wollman u_int pos; 343eae561b3SGarrett Wollman { 3448360efbdSAlfred Perlstein RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 345eae561b3SGarrett Wollman u_int currpos = xdrrec_getpos(xdrs); 346eae561b3SGarrett Wollman int delta = currpos - pos; 3478360efbdSAlfred Perlstein char *newpos; 348eae561b3SGarrett Wollman 349eae561b3SGarrett Wollman if ((int)currpos != -1) 350eae561b3SGarrett Wollman switch (xdrs->x_op) { 351eae561b3SGarrett Wollman 352eae561b3SGarrett Wollman case XDR_ENCODE: 353eae561b3SGarrett Wollman newpos = rstrm->out_finger - delta; 3548360efbdSAlfred Perlstein if ((newpos > (char *)(void *)(rstrm->frag_header)) && 355eae561b3SGarrett Wollman (newpos < rstrm->out_boundry)) { 356eae561b3SGarrett Wollman rstrm->out_finger = newpos; 357eae561b3SGarrett Wollman return (TRUE); 358eae561b3SGarrett Wollman } 359eae561b3SGarrett Wollman break; 360eae561b3SGarrett Wollman 361eae561b3SGarrett Wollman case XDR_DECODE: 362eae561b3SGarrett Wollman newpos = rstrm->in_finger - delta; 363eae561b3SGarrett Wollman if ((delta < (int)(rstrm->fbtbc)) && 364eae561b3SGarrett Wollman (newpos <= rstrm->in_boundry) && 365eae561b3SGarrett Wollman (newpos >= rstrm->in_base)) { 366eae561b3SGarrett Wollman rstrm->in_finger = newpos; 367eae561b3SGarrett Wollman rstrm->fbtbc -= delta; 368eae561b3SGarrett Wollman return (TRUE); 369eae561b3SGarrett Wollman } 370eae561b3SGarrett Wollman break; 3718360efbdSAlfred Perlstein 3728360efbdSAlfred Perlstein case XDR_FREE: 3738360efbdSAlfred Perlstein break; 374eae561b3SGarrett Wollman } 375eae561b3SGarrett Wollman return (FALSE); 376eae561b3SGarrett Wollman } 377eae561b3SGarrett Wollman 3781ad08a09SPeter Wemm static int32_t * 379eae561b3SGarrett Wollman xdrrec_inline(xdrs, len) 3808360efbdSAlfred Perlstein XDR *xdrs; 3818360efbdSAlfred Perlstein u_int len; 382eae561b3SGarrett Wollman { 3838360efbdSAlfred Perlstein RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 3841ad08a09SPeter Wemm int32_t *buf = NULL; 385eae561b3SGarrett Wollman 386eae561b3SGarrett Wollman switch (xdrs->x_op) { 387eae561b3SGarrett Wollman 388eae561b3SGarrett Wollman case XDR_ENCODE: 389eae561b3SGarrett Wollman if ((rstrm->out_finger + len) <= rstrm->out_boundry) { 3908360efbdSAlfred Perlstein buf = (int32_t *)(void *)rstrm->out_finger; 391eae561b3SGarrett Wollman rstrm->out_finger += len; 392eae561b3SGarrett Wollman } 393eae561b3SGarrett Wollman break; 394eae561b3SGarrett Wollman 395eae561b3SGarrett Wollman case XDR_DECODE: 396eae561b3SGarrett Wollman if ((len <= rstrm->fbtbc) && 397eae561b3SGarrett Wollman ((rstrm->in_finger + len) <= rstrm->in_boundry)) { 3988360efbdSAlfred Perlstein buf = (int32_t *)(void *)rstrm->in_finger; 399eae561b3SGarrett Wollman rstrm->fbtbc -= len; 400eae561b3SGarrett Wollman rstrm->in_finger += len; 401eae561b3SGarrett Wollman } 402eae561b3SGarrett Wollman break; 4038360efbdSAlfred Perlstein 4048360efbdSAlfred Perlstein case XDR_FREE: 4058360efbdSAlfred Perlstein break; 406eae561b3SGarrett Wollman } 407eae561b3SGarrett Wollman return (buf); 408eae561b3SGarrett Wollman } 409eae561b3SGarrett Wollman 410eae561b3SGarrett Wollman static void 411eae561b3SGarrett Wollman xdrrec_destroy(xdrs) 4128360efbdSAlfred Perlstein XDR *xdrs; 413eae561b3SGarrett Wollman { 4148360efbdSAlfred Perlstein RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 415eae561b3SGarrett Wollman 416eae561b3SGarrett Wollman mem_free(rstrm->the_buffer, 417eae561b3SGarrett Wollman rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT); 4188360efbdSAlfred Perlstein mem_free(rstrm, sizeof(RECSTREAM)); 419eae561b3SGarrett Wollman } 420eae561b3SGarrett Wollman 421eae561b3SGarrett Wollman 422eae561b3SGarrett Wollman /* 423eae561b3SGarrett Wollman * Exported routines to manage xdr records 424eae561b3SGarrett Wollman */ 425eae561b3SGarrett Wollman 426eae561b3SGarrett Wollman /* 427eae561b3SGarrett Wollman * Before reading (deserializing from the stream, one should always call 428eae561b3SGarrett Wollman * this procedure to guarantee proper record alignment. 429eae561b3SGarrett Wollman */ 430eae561b3SGarrett Wollman bool_t 431eae561b3SGarrett Wollman xdrrec_skiprecord(xdrs) 432eae561b3SGarrett Wollman XDR *xdrs; 433eae561b3SGarrett Wollman { 4348360efbdSAlfred Perlstein RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 435eae561b3SGarrett Wollman 436eae561b3SGarrett Wollman while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { 437eae561b3SGarrett Wollman if (! skip_input_bytes(rstrm, rstrm->fbtbc)) 438eae561b3SGarrett Wollman return (FALSE); 439eae561b3SGarrett Wollman rstrm->fbtbc = 0; 440eae561b3SGarrett Wollman if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) 441eae561b3SGarrett Wollman return (FALSE); 442eae561b3SGarrett Wollman } 443eae561b3SGarrett Wollman rstrm->last_frag = FALSE; 444eae561b3SGarrett Wollman return (TRUE); 445eae561b3SGarrett Wollman } 446eae561b3SGarrett Wollman 447eae561b3SGarrett Wollman /* 4488360efbdSAlfred Perlstein * Look ahead function. 449eae561b3SGarrett Wollman * Returns TRUE iff there is no more input in the buffer 450eae561b3SGarrett Wollman * after consuming the rest of the current record. 451eae561b3SGarrett Wollman */ 452eae561b3SGarrett Wollman bool_t 453eae561b3SGarrett Wollman xdrrec_eof(xdrs) 454eae561b3SGarrett Wollman XDR *xdrs; 455eae561b3SGarrett Wollman { 4568360efbdSAlfred Perlstein RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 457eae561b3SGarrett Wollman 458eae561b3SGarrett Wollman while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { 459eae561b3SGarrett Wollman if (! skip_input_bytes(rstrm, rstrm->fbtbc)) 460eae561b3SGarrett Wollman return (TRUE); 461eae561b3SGarrett Wollman rstrm->fbtbc = 0; 462eae561b3SGarrett Wollman if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) 463eae561b3SGarrett Wollman return (TRUE); 464eae561b3SGarrett Wollman } 465eae561b3SGarrett Wollman if (rstrm->in_finger == rstrm->in_boundry) 466eae561b3SGarrett Wollman return (TRUE); 467eae561b3SGarrett Wollman return (FALSE); 468eae561b3SGarrett Wollman } 469eae561b3SGarrett Wollman 470eae561b3SGarrett Wollman /* 471eae561b3SGarrett Wollman * The client must tell the package when an end-of-record has occurred. 472eae561b3SGarrett Wollman * The second paraemters tells whether the record should be flushed to the 473eae561b3SGarrett Wollman * (output) tcp stream. (This let's the package support batched or 474eae561b3SGarrett Wollman * pipelined procedure calls.) TRUE => immmediate flush to tcp connection. 475eae561b3SGarrett Wollman */ 476eae561b3SGarrett Wollman bool_t 477eae561b3SGarrett Wollman xdrrec_endofrecord(xdrs, sendnow) 478eae561b3SGarrett Wollman XDR *xdrs; 479eae561b3SGarrett Wollman bool_t sendnow; 480eae561b3SGarrett Wollman { 4818360efbdSAlfred Perlstein RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 4828360efbdSAlfred Perlstein u_long len; /* fragment length */ 483eae561b3SGarrett Wollman 484eae561b3SGarrett Wollman if (sendnow || rstrm->frag_sent || 4851ad08a09SPeter Wemm ((u_long)rstrm->out_finger + sizeof(u_int32_t) >= 486eae561b3SGarrett Wollman (u_long)rstrm->out_boundry)) { 487eae561b3SGarrett Wollman rstrm->frag_sent = FALSE; 488eae561b3SGarrett Wollman return (flush_out(rstrm, TRUE)); 489eae561b3SGarrett Wollman } 490eae561b3SGarrett Wollman len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) - 4911ad08a09SPeter Wemm sizeof(u_int32_t); 4928360efbdSAlfred Perlstein *(rstrm->frag_header) = htonl((u_int32_t)len | LAST_FRAG); 4938360efbdSAlfred Perlstein rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_finger; 4941ad08a09SPeter Wemm rstrm->out_finger += sizeof(u_int32_t); 495eae561b3SGarrett Wollman return (TRUE); 496eae561b3SGarrett Wollman } 497eae561b3SGarrett Wollman 498eae561b3SGarrett Wollman 499eae561b3SGarrett Wollman /* 500eae561b3SGarrett Wollman * Internal useful routines 501eae561b3SGarrett Wollman */ 502eae561b3SGarrett Wollman static bool_t 503eae561b3SGarrett Wollman flush_out(rstrm, eor) 5048360efbdSAlfred Perlstein RECSTREAM *rstrm; 505eae561b3SGarrett Wollman bool_t eor; 506eae561b3SGarrett Wollman { 5078360efbdSAlfred Perlstein u_int32_t eormask = (eor == TRUE) ? LAST_FRAG : 0; 5088360efbdSAlfred Perlstein u_int32_t len = (u_int32_t)((u_long)(rstrm->out_finger) - 5098360efbdSAlfred Perlstein (u_long)(rstrm->frag_header) - sizeof(u_int32_t)); 510eae561b3SGarrett Wollman 511eae561b3SGarrett Wollman *(rstrm->frag_header) = htonl(len | eormask); 5128360efbdSAlfred Perlstein len = (u_int32_t)((u_long)(rstrm->out_finger) - 5138360efbdSAlfred Perlstein (u_long)(rstrm->out_base)); 514eae561b3SGarrett Wollman if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len) 515eae561b3SGarrett Wollman != (int)len) 516eae561b3SGarrett Wollman return (FALSE); 5178360efbdSAlfred Perlstein rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base; 5188360efbdSAlfred Perlstein rstrm->out_finger = (char *)rstrm->out_base + sizeof(u_int32_t); 519eae561b3SGarrett Wollman return (TRUE); 520eae561b3SGarrett Wollman } 521eae561b3SGarrett Wollman 522eae561b3SGarrett Wollman static bool_t /* knows nothing about records! Only about input buffers */ 523eae561b3SGarrett Wollman fill_input_buf(rstrm) 5248360efbdSAlfred Perlstein RECSTREAM *rstrm; 525eae561b3SGarrett Wollman { 5268360efbdSAlfred Perlstein char *where; 5278360efbdSAlfred Perlstein u_int32_t i; 5288360efbdSAlfred Perlstein int len; 529eae561b3SGarrett Wollman 530eae561b3SGarrett Wollman where = rstrm->in_base; 5318360efbdSAlfred Perlstein i = (u_int32_t)((u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT); 532eae561b3SGarrett Wollman where += i; 5338360efbdSAlfred Perlstein len = (u_int32_t)(rstrm->in_size - i); 534eae561b3SGarrett Wollman if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1) 535eae561b3SGarrett Wollman return (FALSE); 536eae561b3SGarrett Wollman rstrm->in_finger = where; 537eae561b3SGarrett Wollman where += len; 538eae561b3SGarrett Wollman rstrm->in_boundry = where; 539eae561b3SGarrett Wollman return (TRUE); 540eae561b3SGarrett Wollman } 541eae561b3SGarrett Wollman 542eae561b3SGarrett Wollman static bool_t /* knows nothing about records! Only about input buffers */ 543eae561b3SGarrett Wollman get_input_bytes(rstrm, addr, len) 5448360efbdSAlfred Perlstein RECSTREAM *rstrm; 5458360efbdSAlfred Perlstein char *addr; 5468360efbdSAlfred Perlstein int len; 547eae561b3SGarrett Wollman { 5488360efbdSAlfred Perlstein size_t current; 549eae561b3SGarrett Wollman 550eae561b3SGarrett Wollman while (len > 0) { 5518360efbdSAlfred Perlstein current = (size_t)((long)rstrm->in_boundry - 5528360efbdSAlfred Perlstein (long)rstrm->in_finger); 553eae561b3SGarrett Wollman if (current == 0) { 554eae561b3SGarrett Wollman if (! fill_input_buf(rstrm)) 555eae561b3SGarrett Wollman return (FALSE); 556eae561b3SGarrett Wollman continue; 557eae561b3SGarrett Wollman } 558eae561b3SGarrett Wollman current = (len < current) ? len : current; 5598360efbdSAlfred Perlstein memmove(addr, rstrm->in_finger, current); 560eae561b3SGarrett Wollman rstrm->in_finger += current; 561eae561b3SGarrett Wollman addr += current; 562eae561b3SGarrett Wollman len -= current; 563eae561b3SGarrett Wollman } 564eae561b3SGarrett Wollman return (TRUE); 565eae561b3SGarrett Wollman } 566eae561b3SGarrett Wollman 567eae561b3SGarrett Wollman static bool_t /* next two bytes of the input stream are treated as a header */ 568eae561b3SGarrett Wollman set_input_fragment(rstrm) 5698360efbdSAlfred Perlstein RECSTREAM *rstrm; 570eae561b3SGarrett Wollman { 5711ad08a09SPeter Wemm u_int32_t header; 572eae561b3SGarrett Wollman 5738360efbdSAlfred Perlstein if (! get_input_bytes(rstrm, (char *)(void *)&header, sizeof(header))) 574eae561b3SGarrett Wollman return (FALSE); 5758360efbdSAlfred Perlstein header = ntohl(header); 576eae561b3SGarrett Wollman rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; 577a9352e90SBill Paul /* 578a9352e90SBill Paul * Sanity check. Try not to accept wildly incorrect 5791ce4aec2SBill Paul * record sizes. Unfortunately, the only record size 5801ce4aec2SBill Paul * we can positively identify as being 'wildly incorrect' 5811ce4aec2SBill Paul * is zero. Ridiculously large record sizes may look wrong, 5821ce4aec2SBill Paul * but we don't have any way to be certain that they aren't 5831ce4aec2SBill Paul * what the client actually intended to send us. 584a9352e90SBill Paul */ 585c50a9e8fSBill Paul if (header == 0) 586a9352e90SBill Paul return(FALSE); 587eae561b3SGarrett Wollman rstrm->fbtbc = header & (~LAST_FRAG); 588eae561b3SGarrett Wollman return (TRUE); 589eae561b3SGarrett Wollman } 590eae561b3SGarrett Wollman 591eae561b3SGarrett Wollman static bool_t /* consumes input bytes; knows nothing about records! */ 592eae561b3SGarrett Wollman skip_input_bytes(rstrm, cnt) 5938360efbdSAlfred Perlstein RECSTREAM *rstrm; 594eae561b3SGarrett Wollman long cnt; 595eae561b3SGarrett Wollman { 5968360efbdSAlfred Perlstein u_int32_t current; 597eae561b3SGarrett Wollman 598eae561b3SGarrett Wollman while (cnt > 0) { 5998360efbdSAlfred Perlstein current = (size_t)((long)rstrm->in_boundry - 6008360efbdSAlfred Perlstein (long)rstrm->in_finger); 601eae561b3SGarrett Wollman if (current == 0) { 602eae561b3SGarrett Wollman if (! fill_input_buf(rstrm)) 603eae561b3SGarrett Wollman return (FALSE); 604eae561b3SGarrett Wollman continue; 605eae561b3SGarrett Wollman } 6068360efbdSAlfred Perlstein current = (u_int32_t)((cnt < current) ? cnt : current); 607eae561b3SGarrett Wollman rstrm->in_finger += current; 608eae561b3SGarrett Wollman cnt -= current; 609eae561b3SGarrett Wollman } 610eae561b3SGarrett Wollman return (TRUE); 611eae561b3SGarrett Wollman } 612eae561b3SGarrett Wollman 613eae561b3SGarrett Wollman static u_int 614eae561b3SGarrett Wollman fix_buf_size(s) 6158360efbdSAlfred Perlstein u_int s; 616eae561b3SGarrett Wollman { 617eae561b3SGarrett Wollman 618eae561b3SGarrett Wollman if (s < 100) 619eae561b3SGarrett Wollman s = 4000; 620eae561b3SGarrett Wollman return (RNDUP(s)); 621eae561b3SGarrett Wollman } 622