174462Salfred/* $NetBSD: xdr_rec.c,v 1.18 2000/07/06 03:10:35 christos Exp $ */ 274462Salfred 31902Swollman/* 41902Swollman * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 51902Swollman * unrestricted use provided that this legend is included on all tape 61902Swollman * media and as a part of the software program in whole or part. Users 71902Swollman * may copy or modify Sun RPC without charge, but are not authorized 81902Swollman * to license or distribute it to anyone else except as part of a product or 91902Swollman * program developed by the user. 108870Srgrimes * 111902Swollman * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 121902Swollman * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 131902Swollman * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 148870Srgrimes * 151902Swollman * Sun RPC is provided with no support and without any obligation on the 161902Swollman * part of Sun Microsystems, Inc. to assist in its use, correction, 171902Swollman * modification or enhancement. 188870Srgrimes * 191902Swollman * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 201902Swollman * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 211902Swollman * OR ANY PART THEREOF. 228870Srgrimes * 231902Swollman * In no event will Sun Microsystems, Inc. be liable for any lost revenue 241902Swollman * or profits or other special, indirect and consequential damages, even if 251902Swollman * Sun has been advised of the possibility of such damages. 268870Srgrimes * 271902Swollman * Sun Microsystems, Inc. 281902Swollman * 2550 Garcia Avenue 291902Swollman * Mountain View, California 94043 301902Swollman */ 3174462Salfred 3274462Salfred#if defined(LIBC_SCCS) && !defined(lint) 33136582Sobrienstatic char *sccsid2 = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro"; 3492986Sobrienstatic char *sccsid = "@(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC"; 351902Swollman#endif 3692986Sobrien#include <sys/cdefs.h> 3792986Sobrien__FBSDID("$FreeBSD$"); 381902Swollman 391902Swollman/* 401902Swollman * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking" 411902Swollman * layer above tcp (for rpc's use). 421902Swollman * 431902Swollman * Copyright (C) 1984, Sun Microsystems, Inc. 441902Swollman * 451902Swollman * These routines interface XDRSTREAMS to a tcp/ip connection. 461902Swollman * There is a record marking layer between the xdr stream 471902Swollman * and the tcp transport level. A record is composed on one or more 481902Swollman * record fragments. A record fragment is a thirty-two bit header followed 491902Swollman * by n bytes of data, where n is contained in the header. The header 501902Swollman * is represented as a htonl(u_long). Thegh order bit encodes 511902Swollman * whether or not the fragment is the last fragment of the record 5274462Salfred * (1 => fragment is last, 0 => more fragments to follow. 531902Swollman * The other 31 bits encode the byte length of the fragment. 541902Swollman */ 551902Swollman 5674462Salfred#include "namespace.h" 5774462Salfred#include <sys/types.h> 5874462Salfred 5974462Salfred#include <netinet/in.h> 6074462Salfred 6174462Salfred#include <err.h> 621902Swollman#include <stdio.h> 631902Swollman#include <stdlib.h> 6411669Sphk#include <string.h> 6574462Salfred 661902Swollman#include <rpc/types.h> 671902Swollman#include <rpc/xdr.h> 68109359Smbr#include <rpc/auth.h> 69109359Smbr#include <rpc/svc.h> 70109359Smbr#include <rpc/clnt.h> 71109359Smbr#include <sys/stddef.h> 7274462Salfred#include "un-namespace.h" 73111618Snectar#include "rpc_com.h" 741902Swollman 7592905Sobrienstatic bool_t xdrrec_getlong(XDR *, long *); 7692905Sobrienstatic bool_t xdrrec_putlong(XDR *, const long *); 7792905Sobrienstatic bool_t xdrrec_getbytes(XDR *, char *, u_int); 781902Swollman 7992905Sobrienstatic bool_t xdrrec_putbytes(XDR *, const char *, u_int); 8092905Sobrienstatic u_int xdrrec_getpos(XDR *); 8192905Sobrienstatic bool_t xdrrec_setpos(XDR *, u_int); 8292905Sobrienstatic int32_t *xdrrec_inline(XDR *, u_int); 8392905Sobrienstatic void xdrrec_destroy(XDR *); 841902Swollman 8574462Salfredstatic const struct xdr_ops xdrrec_ops = { 861902Swollman xdrrec_getlong, 871902Swollman xdrrec_putlong, 881902Swollman xdrrec_getbytes, 891902Swollman xdrrec_putbytes, 901902Swollman xdrrec_getpos, 911902Swollman xdrrec_setpos, 921902Swollman xdrrec_inline, 931902Swollman xdrrec_destroy 941902Swollman}; 951902Swollman 961902Swollman/* 971902Swollman * A record is composed of one or more record fragments. 98109359Smbr * A record fragment is a four-byte header followed by zero to 991902Swollman * 2**32-1 bytes. The header is treated as a long unsigned and is 1001902Swollman * encode/decoded to the network via htonl/ntohl. The low order 31 bits 1011902Swollman * are a byte count of the fragment. The highest order bit is a boolean: 1021902Swollman * 1 => this fragment is the last fragment of the record, 1031902Swollman * 0 => this fragment is followed by more fragment(s). 1041902Swollman * 1051902Swollman * The fragment/record machinery is not general; it is constructed to 1061902Swollman * meet the needs of xdr and rpc based on tcp. 1071902Swollman */ 1081902Swollman 10921062Speter#define LAST_FRAG ((u_int32_t)(1 << 31)) 1101902Swollman 1111902Swollmantypedef struct rec_strm { 11274462Salfred char *tcp_handle; 1131902Swollman /* 1141902Swollman * out-goung bits 1151902Swollman */ 11695658Sdes int (*writeit)(void *, void *, int); 11774462Salfred char *out_base; /* output buffer (points to frag header) */ 11874462Salfred char *out_finger; /* next output position */ 11974462Salfred char *out_boundry; /* data cannot up to this address */ 12074462Salfred u_int32_t *frag_header; /* beginning of curren fragment */ 1211902Swollman bool_t frag_sent; /* true if buffer sent in middle of record */ 1221902Swollman /* 1231902Swollman * in-coming bits 1241902Swollman */ 12595658Sdes int (*readit)(void *, void *, int); 1261902Swollman u_long in_size; /* fixed size of the input buffer */ 12774462Salfred char *in_base; 12874462Salfred char *in_finger; /* location of next byte to be had */ 12974462Salfred char *in_boundry; /* can read up to this location */ 1301902Swollman long fbtbc; /* fragment bytes to be consumed */ 1311902Swollman bool_t last_frag; 1321902Swollman u_int sendsize; 1331902Swollman u_int recvsize; 134109359Smbr 135109359Smbr bool_t nonblock; 136109359Smbr bool_t in_haveheader; 137109359Smbr u_int32_t in_header; 138109359Smbr char *in_hdrp; 139109359Smbr int in_hdrlen; 140109359Smbr int in_reclen; 141109359Smbr int in_received; 142109359Smbr int in_maxrec; 1431902Swollman} RECSTREAM; 1441902Swollman 14592905Sobrienstatic u_int fix_buf_size(u_int); 14692905Sobrienstatic bool_t flush_out(RECSTREAM *, bool_t); 14792905Sobrienstatic bool_t fill_input_buf(RECSTREAM *); 14892905Sobrienstatic bool_t get_input_bytes(RECSTREAM *, char *, int); 14992905Sobrienstatic bool_t set_input_fragment(RECSTREAM *); 15092905Sobrienstatic bool_t skip_input_bytes(RECSTREAM *, long); 151109359Smbrstatic bool_t realloc_stream(RECSTREAM *, int); 1521902Swollman 15374462Salfred 1541902Swollman/* 1551902Swollman * Create an xdr handle for xdrrec 1561902Swollman * xdrrec_create fills in xdrs. Sendsize and recvsize are 1571902Swollman * send and recv buffer sizes (0 => use default). 1581902Swollman * tcp_handle is an opaque handle that is passed as the first parameter to 1591902Swollman * the procedures readit and writeit. Readit and writeit are read and 1601902Swollman * write respectively. They are like the system 1611902Swollman * calls expect that they take an opaque handle rather than an fd. 1621902Swollman */ 1631902Swollmanvoid 1641902Swollmanxdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit) 16574462Salfred XDR *xdrs; 16674462Salfred u_int sendsize; 16774462Salfred u_int recvsize; 16895658Sdes void *tcp_handle; 16974462Salfred /* like read, but pass it a tcp_handle, not sock */ 17095658Sdes int (*readit)(void *, void *, int); 17174462Salfred /* like write, but pass it a tcp_handle, not sock */ 17295658Sdes int (*writeit)(void *, void *, int); 1731902Swollman{ 17474462Salfred RECSTREAM *rstrm = mem_alloc(sizeof(RECSTREAM)); 1751902Swollman 1761902Swollman if (rstrm == NULL) { 17774462Salfred warnx("xdrrec_create: out of memory"); 17874462Salfred /* 17974462Salfred * This is bad. Should rework xdrrec_create to 1801902Swollman * return a handle, and in this case return NULL 1811902Swollman */ 1821902Swollman return; 1831902Swollman } 1841902Swollman rstrm->sendsize = sendsize = fix_buf_size(sendsize); 185109359Smbr rstrm->out_base = mem_alloc(rstrm->sendsize); 186109359Smbr if (rstrm->out_base == NULL) { 187109359Smbr warnx("xdrrec_create: out of memory"); 188109359Smbr mem_free(rstrm, sizeof(RECSTREAM)); 189109359Smbr return; 190109359Smbr } 1911902Swollman rstrm->recvsize = recvsize = fix_buf_size(recvsize); 192109359Smbr rstrm->in_base = mem_alloc(recvsize); 193109359Smbr if (rstrm->in_base == NULL) { 19474462Salfred warnx("xdrrec_create: out of memory"); 195109359Smbr mem_free(rstrm->out_base, sendsize); 196109359Smbr mem_free(rstrm, sizeof(RECSTREAM)); 1971902Swollman return; 1981902Swollman } 1991902Swollman /* 2001902Swollman * now the rest ... 2011902Swollman */ 2021902Swollman xdrs->x_ops = &xdrrec_ops; 20374462Salfred xdrs->x_private = rstrm; 2041902Swollman rstrm->tcp_handle = tcp_handle; 2051902Swollman rstrm->readit = readit; 2061902Swollman rstrm->writeit = writeit; 2071902Swollman rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; 20874462Salfred rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base; 20921062Speter rstrm->out_finger += sizeof(u_int32_t); 2101902Swollman rstrm->out_boundry += sendsize; 2111902Swollman rstrm->frag_sent = FALSE; 2121902Swollman rstrm->in_size = recvsize; 2131902Swollman rstrm->in_boundry = rstrm->in_base; 2141902Swollman rstrm->in_finger = (rstrm->in_boundry += recvsize); 2151902Swollman rstrm->fbtbc = 0; 2161902Swollman rstrm->last_frag = TRUE; 217109359Smbr rstrm->in_haveheader = FALSE; 218109359Smbr rstrm->in_hdrlen = 0; 219109359Smbr rstrm->in_hdrp = (char *)(void *)&rstrm->in_header; 220109359Smbr rstrm->nonblock = FALSE; 221109359Smbr rstrm->in_reclen = 0; 222109359Smbr rstrm->in_received = 0; 2231902Swollman} 2241902Swollman 2251902Swollman 2261902Swollman/* 2271902Swollman * The reoutines defined below are the xdr ops which will go into the 2281902Swollman * xdr handle filled in by xdrrec_create. 2291902Swollman */ 2301902Swollman 2311902Swollmanstatic bool_t 2321902Swollmanxdrrec_getlong(xdrs, lp) 2331902Swollman XDR *xdrs; 2341902Swollman long *lp; 2351902Swollman{ 23674462Salfred RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 23774462Salfred int32_t *buflp = (int32_t *)(void *)(rstrm->in_finger); 23821062Speter int32_t mylong; 2391902Swollman 2401902Swollman /* first try the inline, fast case */ 24121062Speter if ((rstrm->fbtbc >= sizeof(int32_t)) && 24221062Speter (((long)rstrm->in_boundry - (long)buflp) >= sizeof(int32_t))) { 24321062Speter *lp = (long)ntohl((u_int32_t)(*buflp)); 24421062Speter rstrm->fbtbc -= sizeof(int32_t); 24521062Speter rstrm->in_finger += sizeof(int32_t); 2461902Swollman } else { 24774462Salfred if (! xdrrec_getbytes(xdrs, (char *)(void *)&mylong, 24874462Salfred sizeof(int32_t))) 2491902Swollman return (FALSE); 25021062Speter *lp = (long)ntohl((u_int32_t)mylong); 2511902Swollman } 2521902Swollman return (TRUE); 2531902Swollman} 2541902Swollman 2551902Swollmanstatic bool_t 2561902Swollmanxdrrec_putlong(xdrs, lp) 2571902Swollman XDR *xdrs; 25874462Salfred const long *lp; 2591902Swollman{ 26074462Salfred RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 26174462Salfred int32_t *dest_lp = ((int32_t *)(void *)(rstrm->out_finger)); 2621902Swollman 26321062Speter if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry) { 2641902Swollman /* 2651902Swollman * this case should almost never happen so the code is 2661902Swollman * inefficient 2671902Swollman */ 26821062Speter rstrm->out_finger -= sizeof(int32_t); 2691902Swollman rstrm->frag_sent = TRUE; 2701902Swollman if (! flush_out(rstrm, FALSE)) 2711902Swollman return (FALSE); 27274462Salfred dest_lp = ((int32_t *)(void *)(rstrm->out_finger)); 27321062Speter rstrm->out_finger += sizeof(int32_t); 2741902Swollman } 27521062Speter *dest_lp = (int32_t)htonl((u_int32_t)(*lp)); 2761902Swollman return (TRUE); 2771902Swollman} 2781902Swollman 2791902Swollmanstatic bool_t /* must manage buffers, fragments, and records */ 2801902Swollmanxdrrec_getbytes(xdrs, addr, len) 2811902Swollman XDR *xdrs; 28274462Salfred char *addr; 28374462Salfred u_int len; 2841902Swollman{ 28574462Salfred RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 28674462Salfred int current; 2871902Swollman 2881902Swollman while (len > 0) { 28974462Salfred current = (int)rstrm->fbtbc; 2901902Swollman if (current == 0) { 2911902Swollman if (rstrm->last_frag) 2921902Swollman return (FALSE); 2931902Swollman if (! set_input_fragment(rstrm)) 2941902Swollman return (FALSE); 2951902Swollman continue; 2961902Swollman } 2971902Swollman current = (len < current) ? len : current; 2981902Swollman if (! get_input_bytes(rstrm, addr, current)) 2991902Swollman return (FALSE); 30074462Salfred addr += current; 3011902Swollman rstrm->fbtbc -= current; 3021902Swollman len -= current; 3031902Swollman } 3041902Swollman return (TRUE); 3051902Swollman} 3061902Swollman 3071902Swollmanstatic bool_t 3081902Swollmanxdrrec_putbytes(xdrs, addr, len) 3091902Swollman XDR *xdrs; 31074462Salfred const char *addr; 31174462Salfred u_int len; 3121902Swollman{ 31374462Salfred RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 31474462Salfred size_t current; 3151902Swollman 3161902Swollman while (len > 0) { 31774462Salfred current = (size_t)((u_long)rstrm->out_boundry - 31874462Salfred (u_long)rstrm->out_finger); 3191902Swollman current = (len < current) ? len : current; 32074462Salfred memmove(rstrm->out_finger, addr, current); 3211902Swollman rstrm->out_finger += current; 3221902Swollman addr += current; 3231902Swollman len -= current; 3241902Swollman if (rstrm->out_finger == rstrm->out_boundry) { 3251902Swollman rstrm->frag_sent = TRUE; 3261902Swollman if (! flush_out(rstrm, FALSE)) 3271902Swollman return (FALSE); 3281902Swollman } 3291902Swollman } 3301902Swollman return (TRUE); 3311902Swollman} 3321902Swollman 3331902Swollmanstatic u_int 3341902Swollmanxdrrec_getpos(xdrs) 33574462Salfred XDR *xdrs; 3361902Swollman{ 33774462Salfred RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 33874462Salfred off_t pos; 3391902Swollman 34074462Salfred pos = lseek((int)(u_long)rstrm->tcp_handle, (off_t)0, 1); 341181344Sdfr if (pos == -1) 342181344Sdfr pos = 0; 343181344Sdfr switch (xdrs->x_op) { 3441902Swollman 345181344Sdfr case XDR_ENCODE: 346181344Sdfr pos += rstrm->out_finger - rstrm->out_base; 347181344Sdfr break; 3481902Swollman 349181344Sdfr case XDR_DECODE: 350181344Sdfr pos -= rstrm->in_boundry - rstrm->in_finger; 351181344Sdfr break; 3521902Swollman 353181344Sdfr default: 354181344Sdfr pos = (off_t) -1; 355181344Sdfr break; 356181344Sdfr } 3571902Swollman return ((u_int) pos); 3581902Swollman} 3591902Swollman 3601902Swollmanstatic bool_t 3611902Swollmanxdrrec_setpos(xdrs, pos) 36274462Salfred XDR *xdrs; 3631902Swollman u_int pos; 3641902Swollman{ 36574462Salfred RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 3661902Swollman u_int currpos = xdrrec_getpos(xdrs); 3671902Swollman int delta = currpos - pos; 36874462Salfred char *newpos; 3691902Swollman 3701902Swollman if ((int)currpos != -1) 3711902Swollman switch (xdrs->x_op) { 3721902Swollman 3731902Swollman case XDR_ENCODE: 3741902Swollman newpos = rstrm->out_finger - delta; 37574462Salfred if ((newpos > (char *)(void *)(rstrm->frag_header)) && 3761902Swollman (newpos < rstrm->out_boundry)) { 3771902Swollman rstrm->out_finger = newpos; 3781902Swollman return (TRUE); 3791902Swollman } 3801902Swollman break; 3811902Swollman 3821902Swollman case XDR_DECODE: 3831902Swollman newpos = rstrm->in_finger - delta; 3841902Swollman if ((delta < (int)(rstrm->fbtbc)) && 3851902Swollman (newpos <= rstrm->in_boundry) && 3861902Swollman (newpos >= rstrm->in_base)) { 3871902Swollman rstrm->in_finger = newpos; 3881902Swollman rstrm->fbtbc -= delta; 3891902Swollman return (TRUE); 3901902Swollman } 3911902Swollman break; 39274462Salfred 39374462Salfred case XDR_FREE: 39474462Salfred break; 3951902Swollman } 3961902Swollman return (FALSE); 3971902Swollman} 3981902Swollman 39921062Speterstatic int32_t * 4001902Swollmanxdrrec_inline(xdrs, len) 40174462Salfred XDR *xdrs; 40274462Salfred u_int len; 4031902Swollman{ 40474462Salfred RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 40574462Salfred int32_t *buf = NULL; 4061902Swollman 4071902Swollman switch (xdrs->x_op) { 4081902Swollman 4091902Swollman case XDR_ENCODE: 4101902Swollman if ((rstrm->out_finger + len) <= rstrm->out_boundry) { 41174462Salfred buf = (int32_t *)(void *)rstrm->out_finger; 4121902Swollman rstrm->out_finger += len; 4131902Swollman } 4141902Swollman break; 4151902Swollman 4161902Swollman case XDR_DECODE: 4171902Swollman if ((len <= rstrm->fbtbc) && 4181902Swollman ((rstrm->in_finger + len) <= rstrm->in_boundry)) { 41974462Salfred buf = (int32_t *)(void *)rstrm->in_finger; 4201902Swollman rstrm->fbtbc -= len; 4211902Swollman rstrm->in_finger += len; 4221902Swollman } 4231902Swollman break; 42474462Salfred 42574462Salfred case XDR_FREE: 42674462Salfred break; 4271902Swollman } 4281902Swollman return (buf); 4291902Swollman} 4301902Swollman 4311902Swollmanstatic void 4321902Swollmanxdrrec_destroy(xdrs) 43374462Salfred XDR *xdrs; 4341902Swollman{ 43574462Salfred RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 4361902Swollman 437109359Smbr mem_free(rstrm->out_base, rstrm->sendsize); 438109359Smbr mem_free(rstrm->in_base, rstrm->recvsize); 43974462Salfred mem_free(rstrm, sizeof(RECSTREAM)); 4401902Swollman} 4411902Swollman 4421902Swollman 4431902Swollman/* 4441902Swollman * Exported routines to manage xdr records 4451902Swollman */ 4461902Swollman 4471902Swollman/* 4481902Swollman * Before reading (deserializing from the stream, one should always call 4491902Swollman * this procedure to guarantee proper record alignment. 4501902Swollman */ 4511902Swollmanbool_t 4521902Swollmanxdrrec_skiprecord(xdrs) 4531902Swollman XDR *xdrs; 4541902Swollman{ 45574462Salfred RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 456109359Smbr enum xprt_stat xstat; 4571902Swollman 458109359Smbr if (rstrm->nonblock) { 459109359Smbr if (__xdrrec_getrec(xdrs, &xstat, FALSE)) { 460109359Smbr rstrm->fbtbc = 0; 461109359Smbr return TRUE; 462109359Smbr } 463109359Smbr if (rstrm->in_finger == rstrm->in_boundry && 464109359Smbr xstat == XPRT_MOREREQS) { 465109359Smbr rstrm->fbtbc = 0; 466109359Smbr return TRUE; 467109359Smbr } 468109359Smbr return FALSE; 469109359Smbr } 470109359Smbr 4711902Swollman while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { 4721902Swollman if (! skip_input_bytes(rstrm, rstrm->fbtbc)) 4731902Swollman return (FALSE); 4741902Swollman rstrm->fbtbc = 0; 4751902Swollman if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) 4761902Swollman return (FALSE); 4771902Swollman } 4781902Swollman rstrm->last_frag = FALSE; 4791902Swollman return (TRUE); 4801902Swollman} 4811902Swollman 4821902Swollman/* 48374462Salfred * Look ahead function. 4848870Srgrimes * Returns TRUE iff there is no more input in the buffer 4851902Swollman * after consuming the rest of the current record. 4861902Swollman */ 4871902Swollmanbool_t 4881902Swollmanxdrrec_eof(xdrs) 4891902Swollman XDR *xdrs; 4901902Swollman{ 49174462Salfred RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 4921902Swollman 4931902Swollman while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) { 4941902Swollman if (! skip_input_bytes(rstrm, rstrm->fbtbc)) 4951902Swollman return (TRUE); 4961902Swollman rstrm->fbtbc = 0; 4971902Swollman if ((! rstrm->last_frag) && (! set_input_fragment(rstrm))) 4981902Swollman return (TRUE); 4991902Swollman } 5001902Swollman if (rstrm->in_finger == rstrm->in_boundry) 5011902Swollman return (TRUE); 5021902Swollman return (FALSE); 5031902Swollman} 5041902Swollman 5051902Swollman/* 5061902Swollman * The client must tell the package when an end-of-record has occurred. 5071902Swollman * The second paraemters tells whether the record should be flushed to the 5081902Swollman * (output) tcp stream. (This let's the package support batched or 5091902Swollman * pipelined procedure calls.) TRUE => immmediate flush to tcp connection. 5101902Swollman */ 5111902Swollmanbool_t 5121902Swollmanxdrrec_endofrecord(xdrs, sendnow) 5131902Swollman XDR *xdrs; 5141902Swollman bool_t sendnow; 5151902Swollman{ 51674462Salfred RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 51774462Salfred u_long len; /* fragment length */ 5181902Swollman 5191902Swollman if (sendnow || rstrm->frag_sent || 52021062Speter ((u_long)rstrm->out_finger + sizeof(u_int32_t) >= 5211902Swollman (u_long)rstrm->out_boundry)) { 5221902Swollman rstrm->frag_sent = FALSE; 5231902Swollman return (flush_out(rstrm, TRUE)); 5241902Swollman } 5251902Swollman len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) - 52621062Speter sizeof(u_int32_t); 52774462Salfred *(rstrm->frag_header) = htonl((u_int32_t)len | LAST_FRAG); 52874462Salfred rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_finger; 52921062Speter rstrm->out_finger += sizeof(u_int32_t); 5301902Swollman return (TRUE); 5311902Swollman} 5321902Swollman 533109359Smbr/* 534109359Smbr * Fill the stream buffer with a record for a non-blocking connection. 535109359Smbr * Return true if a record is available in the buffer, false if not. 536109359Smbr */ 537109359Smbrbool_t 538109359Smbr__xdrrec_getrec(xdrs, statp, expectdata) 539109359Smbr XDR *xdrs; 540109359Smbr enum xprt_stat *statp; 541109359Smbr bool_t expectdata; 542109359Smbr{ 543109359Smbr RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 544109359Smbr ssize_t n; 545109359Smbr int fraglen; 5461902Swollman 547109359Smbr if (!rstrm->in_haveheader) { 548109359Smbr n = rstrm->readit(rstrm->tcp_handle, rstrm->in_hdrp, 549109359Smbr (int)sizeof (rstrm->in_header) - rstrm->in_hdrlen); 550109359Smbr if (n == 0) { 551109359Smbr *statp = expectdata ? XPRT_DIED : XPRT_IDLE; 552109359Smbr return FALSE; 553109359Smbr } 554109359Smbr if (n < 0) { 555109359Smbr *statp = XPRT_DIED; 556109359Smbr return FALSE; 557109359Smbr } 558109359Smbr rstrm->in_hdrp += n; 559109359Smbr rstrm->in_hdrlen += n; 560109359Smbr if (rstrm->in_hdrlen < sizeof (rstrm->in_header)) { 561109359Smbr *statp = XPRT_MOREREQS; 562109359Smbr return FALSE; 563109359Smbr } 564109359Smbr rstrm->in_header = ntohl(rstrm->in_header); 565109359Smbr fraglen = (int)(rstrm->in_header & ~LAST_FRAG); 566109359Smbr if (fraglen == 0 || fraglen > rstrm->in_maxrec || 567109359Smbr (rstrm->in_reclen + fraglen) > rstrm->in_maxrec) { 568109359Smbr *statp = XPRT_DIED; 569109359Smbr return FALSE; 570109359Smbr } 571109359Smbr rstrm->in_reclen += fraglen; 572109359Smbr if (rstrm->in_reclen > rstrm->recvsize) 573109359Smbr realloc_stream(rstrm, rstrm->in_reclen); 574109359Smbr if (rstrm->in_header & LAST_FRAG) { 575109359Smbr rstrm->in_header &= ~LAST_FRAG; 576109359Smbr rstrm->last_frag = TRUE; 577109359Smbr } 578177736Sdfr /* 579177736Sdfr * We can only reasonably expect to read once from a 580177736Sdfr * non-blocking stream. Reading the fragment header 581177736Sdfr * may have drained the stream. 582177736Sdfr */ 583177736Sdfr expectdata = FALSE; 584109359Smbr } 585109359Smbr 586109359Smbr n = rstrm->readit(rstrm->tcp_handle, 587109359Smbr rstrm->in_base + rstrm->in_received, 588109359Smbr (rstrm->in_reclen - rstrm->in_received)); 589109359Smbr 590109359Smbr if (n < 0) { 591109359Smbr *statp = XPRT_DIED; 592109359Smbr return FALSE; 593109359Smbr } 594109359Smbr 595109359Smbr if (n == 0) { 596109359Smbr *statp = expectdata ? XPRT_DIED : XPRT_IDLE; 597109359Smbr return FALSE; 598109359Smbr } 599109359Smbr 600109359Smbr rstrm->in_received += n; 601109359Smbr 602109359Smbr if (rstrm->in_received == rstrm->in_reclen) { 603109359Smbr rstrm->in_haveheader = FALSE; 604109359Smbr rstrm->in_hdrp = (char *)(void *)&rstrm->in_header; 605109359Smbr rstrm->in_hdrlen = 0; 606109359Smbr if (rstrm->last_frag) { 607109359Smbr rstrm->fbtbc = rstrm->in_reclen; 608109359Smbr rstrm->in_boundry = rstrm->in_base + rstrm->in_reclen; 609109359Smbr rstrm->in_finger = rstrm->in_base; 610109950Smbr rstrm->in_reclen = rstrm->in_received = 0; 611109359Smbr *statp = XPRT_MOREREQS; 612109359Smbr return TRUE; 613109359Smbr } 614109359Smbr } 615109359Smbr 616109359Smbr *statp = XPRT_MOREREQS; 617109359Smbr return FALSE; 618109359Smbr} 619109359Smbr 620109359Smbrbool_t 621109359Smbr__xdrrec_setnonblock(xdrs, maxrec) 622109359Smbr XDR *xdrs; 623109359Smbr int maxrec; 624109359Smbr{ 625109359Smbr RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 626109359Smbr 627109359Smbr rstrm->nonblock = TRUE; 628109359Smbr if (maxrec == 0) 629109359Smbr maxrec = rstrm->recvsize; 630109359Smbr rstrm->in_maxrec = maxrec; 631109359Smbr return TRUE; 632109359Smbr} 633109359Smbr 6341902Swollman/* 6351902Swollman * Internal useful routines 6361902Swollman */ 6371902Swollmanstatic bool_t 6381902Swollmanflush_out(rstrm, eor) 63974462Salfred RECSTREAM *rstrm; 6401902Swollman bool_t eor; 6411902Swollman{ 64274462Salfred u_int32_t eormask = (eor == TRUE) ? LAST_FRAG : 0; 64374462Salfred u_int32_t len = (u_int32_t)((u_long)(rstrm->out_finger) - 64474462Salfred (u_long)(rstrm->frag_header) - sizeof(u_int32_t)); 6451902Swollman 6461902Swollman *(rstrm->frag_header) = htonl(len | eormask); 64774462Salfred len = (u_int32_t)((u_long)(rstrm->out_finger) - 64874462Salfred (u_long)(rstrm->out_base)); 6491902Swollman if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len) 6501902Swollman != (int)len) 6511902Swollman return (FALSE); 65274462Salfred rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base; 65374462Salfred rstrm->out_finger = (char *)rstrm->out_base + sizeof(u_int32_t); 6541902Swollman return (TRUE); 6551902Swollman} 6561902Swollman 6571902Swollmanstatic bool_t /* knows nothing about records! Only about input buffers */ 6581902Swollmanfill_input_buf(rstrm) 65974462Salfred RECSTREAM *rstrm; 6601902Swollman{ 66174462Salfred char *where; 66274462Salfred u_int32_t i; 66374462Salfred int len; 6641902Swollman 665109359Smbr if (rstrm->nonblock) 666109359Smbr return FALSE; 667109359Smbr 6681902Swollman where = rstrm->in_base; 66974462Salfred i = (u_int32_t)((u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT); 6701902Swollman where += i; 67174462Salfred len = (u_int32_t)(rstrm->in_size - i); 6721902Swollman if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1) 6731902Swollman return (FALSE); 6741902Swollman rstrm->in_finger = where; 6751902Swollman where += len; 6761902Swollman rstrm->in_boundry = where; 6771902Swollman return (TRUE); 6781902Swollman} 6791902Swollman 6801902Swollmanstatic bool_t /* knows nothing about records! Only about input buffers */ 6811902Swollmanget_input_bytes(rstrm, addr, len) 68274462Salfred RECSTREAM *rstrm; 68374462Salfred char *addr; 68474462Salfred int len; 6851902Swollman{ 68674462Salfred size_t current; 6871902Swollman 688109950Smbr if (rstrm->nonblock) { 689109950Smbr if (len > (int)(rstrm->in_boundry - rstrm->in_finger)) 690109950Smbr return FALSE; 691109950Smbr memcpy(addr, rstrm->in_finger, (size_t)len); 692109950Smbr rstrm->in_finger += len; 693109950Smbr return TRUE; 694109950Smbr } 695109950Smbr 6961902Swollman while (len > 0) { 69774462Salfred current = (size_t)((long)rstrm->in_boundry - 69874462Salfred (long)rstrm->in_finger); 6991902Swollman if (current == 0) { 7001902Swollman if (! fill_input_buf(rstrm)) 7011902Swollman return (FALSE); 7021902Swollman continue; 7031902Swollman } 7041902Swollman current = (len < current) ? len : current; 70574462Salfred memmove(addr, rstrm->in_finger, current); 7061902Swollman rstrm->in_finger += current; 7071902Swollman addr += current; 7081902Swollman len -= current; 7091902Swollman } 7101902Swollman return (TRUE); 7111902Swollman} 7121902Swollman 7131902Swollmanstatic bool_t /* next two bytes of the input stream are treated as a header */ 7141902Swollmanset_input_fragment(rstrm) 71574462Salfred RECSTREAM *rstrm; 7161902Swollman{ 71721062Speter u_int32_t header; 7181902Swollman 719115363Smbr if (rstrm->nonblock) 720115363Smbr return FALSE; 72174462Salfred if (! get_input_bytes(rstrm, (char *)(void *)&header, sizeof(header))) 7221902Swollman return (FALSE); 72374462Salfred header = ntohl(header); 7241902Swollman rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; 72536087Swpaul /* 72636087Swpaul * Sanity check. Try not to accept wildly incorrect 72736257Swpaul * record sizes. Unfortunately, the only record size 72836257Swpaul * we can positively identify as being 'wildly incorrect' 72936257Swpaul * is zero. Ridiculously large record sizes may look wrong, 73036257Swpaul * but we don't have any way to be certain that they aren't 73136257Swpaul * what the client actually intended to send us. 73236087Swpaul */ 73356273Swpaul if (header == 0) 73436087Swpaul return(FALSE); 7351902Swollman rstrm->fbtbc = header & (~LAST_FRAG); 7361902Swollman return (TRUE); 7371902Swollman} 7381902Swollman 7391902Swollmanstatic bool_t /* consumes input bytes; knows nothing about records! */ 7401902Swollmanskip_input_bytes(rstrm, cnt) 74174462Salfred RECSTREAM *rstrm; 7421902Swollman long cnt; 7431902Swollman{ 74474462Salfred u_int32_t current; 7451902Swollman 7461902Swollman while (cnt > 0) { 74774462Salfred current = (size_t)((long)rstrm->in_boundry - 74874462Salfred (long)rstrm->in_finger); 7491902Swollman if (current == 0) { 7501902Swollman if (! fill_input_buf(rstrm)) 7511902Swollman return (FALSE); 7521902Swollman continue; 7531902Swollman } 75474462Salfred current = (u_int32_t)((cnt < current) ? cnt : current); 7551902Swollman rstrm->in_finger += current; 7561902Swollman cnt -= current; 7571902Swollman } 7581902Swollman return (TRUE); 7591902Swollman} 7601902Swollman 7611902Swollmanstatic u_int 7621902Swollmanfix_buf_size(s) 76374462Salfred u_int s; 7641902Swollman{ 7651902Swollman 7661902Swollman if (s < 100) 7671902Swollman s = 4000; 7681902Swollman return (RNDUP(s)); 7691902Swollman} 770109359Smbr 771109359Smbr/* 772109359Smbr * Reallocate the input buffer for a non-block stream. 773109359Smbr */ 774109359Smbrstatic bool_t 775109359Smbrrealloc_stream(rstrm, size) 776109359Smbr RECSTREAM *rstrm; 777109359Smbr int size; 778109359Smbr{ 779109359Smbr ptrdiff_t diff; 780109359Smbr char *buf; 781109359Smbr 782109359Smbr if (size > rstrm->recvsize) { 783109359Smbr buf = realloc(rstrm->in_base, (size_t)size); 784109359Smbr if (buf == NULL) 785109359Smbr return FALSE; 786109359Smbr diff = buf - rstrm->in_base; 787109359Smbr rstrm->in_finger += diff; 788109359Smbr rstrm->in_base = buf; 789109359Smbr rstrm->in_boundry = buf + size; 790109359Smbr rstrm->recvsize = size; 791109359Smbr rstrm->in_size = size; 792109359Smbr } 793109359Smbr 794109359Smbr return TRUE; 795109359Smbr} 796