xdr_rec.c revision 21062
138032Speter/*
2261363Sgshapiro * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
364562Sgshapiro * unrestricted use provided that this legend is included on all tape
438032Speter * media and as a part of the software program in whole or part.  Users
538032Speter * may copy or modify Sun RPC without charge, but are not authorized
638032Speter * to license or distribute it to anyone else except as part of a product or
738032Speter * program developed by the user.
838032Speter *
938032Speter * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
1038032Speter * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
1138032Speter * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
1238032Speter *
1338032Speter * Sun RPC is provided with no support and without any obligation on the
1464562Sgshapiro * part of Sun Microsystems, Inc. to assist in its use, correction,
1538032Speter * modification or enhancement.
1638032Speter *
1764562Sgshapiro * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
1890792Sgshapiro * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
1964562Sgshapiro * OR ANY PART THEREOF.
20132943Sgshapiro *
21132943Sgshapiro * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22132943Sgshapiro * or profits or other special, indirect and consequential damages, even if
23132943Sgshapiro * Sun has been advised of the possibility of such damages.
2464562Sgshapiro *
2538032Speter * Sun Microsystems, Inc.
2664562Sgshapiro * 2550 Garcia Avenue
2738032Speter * Mountain View, California  94043
2864562Sgshapiro */
2938032Speter#if defined(LIBC_SCCS) && !defined(lint)
3064562Sgshapiro/*static char *sccsid = "from: @(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";*/
3164562Sgshapiro/*static char *sccsid = "from: @(#)xdr_rec.c	2.2 88/08/01 4.0 RPCSRC";*/
3264562Sgshapirostatic char *rcsid = "$Id: xdr_rec.c,v 1.4 1995/10/22 14:53:56 phk Exp $";
3364562Sgshapiro#endif
3464562Sgshapiro
3590792Sgshapiro/*
3664562Sgshapiro * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
3764562Sgshapiro * layer above tcp (for rpc's use).
3864562Sgshapiro *
3964562Sgshapiro * Copyright (C) 1984, Sun Microsystems, Inc.
4038032Speter *
4138032Speter * These routines interface XDRSTREAMS to a tcp/ip connection.
4264562Sgshapiro * There is a record marking layer between the xdr stream
4338032Speter * and the tcp transport level.  A record is composed on one or more
4464562Sgshapiro * record fragments.  A record fragment is a thirty-two bit header followed
4590792Sgshapiro * by n bytes of data, where n is contained in the header.  The header
4690792Sgshapiro * is represented as a htonl(u_long).  Thegh order bit encodes
4790792Sgshapiro * whether or not the fragment is the last fragment of the record
4890792Sgshapiro * (1 => fragment is last, 0 => more fragments to follow.
4990792Sgshapiro * The other 31 bits encode the byte length of the fragment.
5090792Sgshapiro */
5190792Sgshapiro
5290792Sgshapiro#include <stdio.h>
5390792Sgshapiro#include <stdlib.h>
5490792Sgshapiro#include <string.h>
55266692Sgshapiro#include <rpc/types.h>
5690792Sgshapiro#include <rpc/xdr.h>
5790792Sgshapiro#include <netinet/in.h>
5890792Sgshapiro
5964562Sgshapirostatic u_int	fix_buf_size();
6064562Sgshapirostatic bool_t	flush_out();
6190792Sgshapirostatic bool_t	get_input_bytes();
6290792Sgshapirostatic bool_t	set_input_fragment();
6390792Sgshapirostatic bool_t	skip_input_bytes();
6490792Sgshapiro
6590792Sgshapirostatic bool_t	xdrrec_getlong();
6690792Sgshapirostatic bool_t	xdrrec_putlong();
6790792Sgshapirostatic bool_t	xdrrec_getbytes();
6890792Sgshapirostatic bool_t	xdrrec_putbytes();
6990792Sgshapirostatic u_int	xdrrec_getpos();
7090792Sgshapirostatic bool_t	xdrrec_setpos();
7190792Sgshapirostatic int32_t *xdrrec_inline();
7290792Sgshapirostatic void	xdrrec_destroy();
73168515Sgshapiro
7438032Speterstatic struct  xdr_ops xdrrec_ops = {
7564562Sgshapiro	xdrrec_getlong,
7638032Speter	xdrrec_putlong,
7764562Sgshapiro	xdrrec_getbytes,
7838032Speter	xdrrec_putbytes,
7964562Sgshapiro	xdrrec_getpos,
8064562Sgshapiro	xdrrec_setpos,
8164562Sgshapiro	xdrrec_inline,
8264562Sgshapiro	xdrrec_destroy
8364562Sgshapiro};
8438032Speter
8564562Sgshapiro/*
8664562Sgshapiro * A record is composed of one or more record fragments.
8764562Sgshapiro * A record fragment is a two-byte header followed by zero to
8864562Sgshapiro * 2**32-1 bytes.  The header is treated as a long unsigned and is
8964562Sgshapiro * encode/decoded to the network via htonl/ntohl.  The low order 31 bits
9064562Sgshapiro * are a byte count of the fragment.  The highest order bit is a boolean:
9164562Sgshapiro * 1 => this fragment is the last fragment of the record,
9264562Sgshapiro * 0 => this fragment is followed by more fragment(s).
9364562Sgshapiro *
9464562Sgshapiro * The fragment/record machinery is not general;  it is constructed to
9564562Sgshapiro * meet the needs of xdr and rpc based on tcp.
9638032Speter */
9764562Sgshapiro
9864562Sgshapiro#define LAST_FRAG ((u_int32_t)(1 << 31))
9938032Speter
10064562Sgshapirotypedef struct rec_strm {
10164562Sgshapiro	caddr_t tcp_handle;
10238032Speter	caddr_t the_buffer;
10364562Sgshapiro	/*
10464562Sgshapiro	 * out-goung bits
10538032Speter	 */
10664562Sgshapiro	int (*writeit) __P((caddr_t, caddr_t, int));
10764562Sgshapiro	caddr_t out_base;	/* output buffer (points to frag header) */
10864562Sgshapiro	caddr_t out_finger;	/* next output position */
10964562Sgshapiro	caddr_t out_boundry;	/* data cannot up to this address */
11064562Sgshapiro	u_int32_t *frag_header;	/* beginning of current fragment */
11164562Sgshapiro	bool_t frag_sent;	/* true if buffer sent in middle of record */
11290792Sgshapiro	/*
11390792Sgshapiro	 * in-coming bits
11490792Sgshapiro	 */
11564562Sgshapiro	int (*readit) __P((caddr_t, caddr_t, int));
11638032Speter	u_long in_size;	/* fixed size of the input buffer */
11790792Sgshapiro	caddr_t in_base;
11864562Sgshapiro	caddr_t in_finger;	/* location of next byte to be had */
11964562Sgshapiro	caddr_t in_boundry;	/* can read up to this location */
12064562Sgshapiro	long fbtbc;		/* fragment bytes to be consumed */
12164562Sgshapiro	bool_t last_frag;
12264562Sgshapiro	u_int sendsize;
12338032Speter	u_int recvsize;
12464562Sgshapiro} RECSTREAM;
125285303Sgshapiro
12690792Sgshapiro
127249729Sgshapiro/*
128249729Sgshapiro * Create an xdr handle for xdrrec
129249729Sgshapiro * xdrrec_create fills in xdrs.  Sendsize and recvsize are
130249729Sgshapiro * send and recv buffer sizes (0 => use default).
131249729Sgshapiro * tcp_handle is an opaque handle that is passed as the first parameter to
13290792Sgshapiro * the procedures readit and writeit.  Readit and writeit are read and
13364562Sgshapiro * write respectively.   They are like the system
13464562Sgshapiro * calls expect that they take an opaque handle rather than an fd.
13564562Sgshapiro */
13698121Sgshapirovoid
13798121Sgshapiroxdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit)
13898121Sgshapiro	register XDR *xdrs;
13998121Sgshapiro	register u_int sendsize;
140225906Sume	register u_int recvsize;
14198121Sgshapiro	caddr_t tcp_handle;
142225906Sume	int (*readit)();  /* like read, but pass it a tcp_handle, not sock */
143225906Sume	int (*writeit)();  /* like write, but pass it a tcp_handle, not sock */
144261363Sgshapiro{
14598121Sgshapiro	register RECSTREAM *rstrm =
14698121Sgshapiro		(RECSTREAM *)mem_alloc(sizeof(RECSTREAM));
14798121Sgshapiro
148225906Sume	if (rstrm == NULL) {
14998121Sgshapiro		(void)fprintf(stderr, "xdrrec_create: out of memory\n");
15064562Sgshapiro		/*
15164562Sgshapiro		 *  This is bad.  Should rework xdrrec_create to
15298121Sgshapiro		 *  return a handle, and in this case return NULL
15364562Sgshapiro		 */
15464562Sgshapiro		return;
15598121Sgshapiro	}
15664562Sgshapiro	/*
15764562Sgshapiro	 * adjust sizes and allocate buffer quad byte aligned
15864562Sgshapiro	 */
15964562Sgshapiro	rstrm->sendsize = sendsize = fix_buf_size(sendsize);
16098121Sgshapiro	rstrm->recvsize = recvsize = fix_buf_size(recvsize);
16164562Sgshapiro	rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT);
16264562Sgshapiro	if (rstrm->the_buffer == NULL) {
16364562Sgshapiro		(void)fprintf(stderr, "xdrrec_create: out of memory\n");
16464562Sgshapiro		return;
16564562Sgshapiro	}
16664562Sgshapiro	for (rstrm->out_base = rstrm->the_buffer;
16764562Sgshapiro		(u_long)rstrm->out_base % BYTES_PER_XDR_UNIT != 0;
16864562Sgshapiro		rstrm->out_base++);
16938032Speter	rstrm->in_base = rstrm->out_base + sendsize;
17038032Speter	/*
17138032Speter	 * now the rest ...
17238032Speter	 */
17338032Speter	xdrs->x_ops = &xdrrec_ops;
17438032Speter	xdrs->x_private = (caddr_t)rstrm;
17538032Speter	rstrm->tcp_handle = tcp_handle;
17638032Speter	rstrm->readit = readit;
17738032Speter	rstrm->writeit = writeit;
17838032Speter	rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
17938032Speter	rstrm->frag_header = (u_int32_t *)rstrm->out_base;
18064562Sgshapiro	rstrm->out_finger += sizeof(u_int32_t);
18164562Sgshapiro	rstrm->out_boundry += sendsize;
18264562Sgshapiro	rstrm->frag_sent = FALSE;
18364562Sgshapiro	rstrm->in_size = recvsize;
18438032Speter	rstrm->in_boundry = rstrm->in_base;
18538032Speter	rstrm->in_finger = (rstrm->in_boundry += recvsize);
18664562Sgshapiro	rstrm->fbtbc = 0;
18738032Speter	rstrm->last_frag = TRUE;
18838032Speter}
18964562Sgshapiro
19073188Sgshapiro
19173188Sgshapiro/*
19273188Sgshapiro * The reoutines defined below are the xdr ops which will go into the
19338032Speter * xdr handle filled in by xdrrec_create.
19464562Sgshapiro */
19564562Sgshapiro
19664562Sgshapirostatic bool_t
19738032Speterxdrrec_getlong(xdrs, lp)
19864562Sgshapiro	XDR *xdrs;
19964562Sgshapiro	long *lp;
20064562Sgshapiro{
20138032Speter	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
202285303Sgshapiro	register int32_t *buflp = (int32_t *)(rstrm->in_finger);
203285303Sgshapiro	int32_t mylong;
204285303Sgshapiro
205285303Sgshapiro	/* first try the inline, fast case */
20664562Sgshapiro	if ((rstrm->fbtbc >= sizeof(int32_t)) &&
207120256Sgshapiro		(((long)rstrm->in_boundry - (long)buflp) >= sizeof(int32_t))) {
208285303Sgshapiro		*lp = (long)ntohl((u_int32_t)(*buflp));
209120256Sgshapiro		rstrm->fbtbc -= sizeof(int32_t);
210285303Sgshapiro		rstrm->in_finger += sizeof(int32_t);
211285303Sgshapiro	} else {
212285303Sgshapiro		if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof(int32_t)))
213120256Sgshapiro			return (FALSE);
214285303Sgshapiro		*lp = (long)ntohl((u_int32_t)mylong);
215285303Sgshapiro	}
21690792Sgshapiro	return (TRUE);
21790792Sgshapiro}
21890792Sgshapiro
21990792Sgshapirostatic bool_t
22090792Sgshapiroxdrrec_putlong(xdrs, lp)
22190792Sgshapiro	XDR *xdrs;
22290792Sgshapiro	long *lp;
22390792Sgshapiro{
22490792Sgshapiro	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
22590792Sgshapiro	register int32_t *dest_lp = ((int32_t *)(rstrm->out_finger));
22690792Sgshapiro
22790792Sgshapiro	if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry) {
22890792Sgshapiro		/*
22990792Sgshapiro		 * this case should almost never happen so the code is
23090792Sgshapiro		 * inefficient
23190792Sgshapiro		 */
23238032Speter		rstrm->out_finger -= sizeof(int32_t);
23338032Speter		rstrm->frag_sent = TRUE;
23438032Speter		if (! flush_out(rstrm, FALSE))
23590792Sgshapiro			return (FALSE);
23638032Speter		dest_lp = ((int32_t *)(rstrm->out_finger));
23790792Sgshapiro		rstrm->out_finger += sizeof(int32_t);
23838032Speter	}
23938032Speter	*dest_lp = (int32_t)htonl((u_int32_t)(*lp));
24038032Speter	return (TRUE);
24138032Speter}
24238032Speter
24338032Speterstatic bool_t  /* must manage buffers, fragments, and records */
24438032Speterxdrrec_getbytes(xdrs, addr, len)
24538032Speter	XDR *xdrs;
24638032Speter	register caddr_t addr;
24738032Speter	register u_int len;
24838032Speter{
24990792Sgshapiro	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
25038032Speter	register int current;
25138032Speter
25238032Speter	while (len > 0) {
25338032Speter		current = rstrm->fbtbc;
25438032Speter		if (current == 0) {
25538032Speter			if (rstrm->last_frag)
25638032Speter				return (FALSE);
25738032Speter			if (! set_input_fragment(rstrm))
25890792Sgshapiro				return (FALSE);
25990792Sgshapiro			continue;
26090792Sgshapiro		}
26190792Sgshapiro		current = (len < current) ? len : current;
26238032Speter		if (! get_input_bytes(rstrm, addr, current))
26338032Speter			return (FALSE);
26438032Speter		addr += current;
26538032Speter		rstrm->fbtbc -= current;
26638032Speter		len -= current;
26764562Sgshapiro	}
26890792Sgshapiro	return (TRUE);
26990792Sgshapiro}
27090792Sgshapiro
27190792Sgshapirostatic bool_t
27238032Speterxdrrec_putbytes(xdrs, addr, len)
27338032Speter	XDR *xdrs;
27438032Speter	register caddr_t addr;
27538032Speter	register u_int len;
27664562Sgshapiro{
27764562Sgshapiro	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
27864562Sgshapiro	register long current;
27964562Sgshapiro
28064562Sgshapiro	while (len > 0) {
28164562Sgshapiro		current = (u_long)rstrm->out_boundry -
28264562Sgshapiro			(u_long)rstrm->out_finger;
28364562Sgshapiro		current = (len < current) ? len : current;
28464562Sgshapiro		memcpy(rstrm->out_finger, addr, current);
28564562Sgshapiro		rstrm->out_finger += current;
28690792Sgshapiro		addr += current;
28764562Sgshapiro		len -= current;
28864562Sgshapiro		if (rstrm->out_finger == rstrm->out_boundry) {
28964562Sgshapiro			rstrm->frag_sent = TRUE;
29064562Sgshapiro			if (! flush_out(rstrm, FALSE))
29164562Sgshapiro				return (FALSE);
29290792Sgshapiro		}
29390792Sgshapiro	}
29490792Sgshapiro	return (TRUE);
295285303Sgshapiro}
296285303Sgshapiro
29764562Sgshapirostatic u_int
29864562Sgshapiroxdrrec_getpos(xdrs)
29938032Speter	register XDR *xdrs;
300285303Sgshapiro{
301285303Sgshapiro	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
30264562Sgshapiro	register long pos;
30338032Speter
304285303Sgshapiro	pos = lseek((int)(long)rstrm->tcp_handle, (off_t) 0, 1);
305285303Sgshapiro	if (pos != -1)
306285303Sgshapiro		switch (xdrs->x_op) {
307285303Sgshapiro
308285303Sgshapiro		case XDR_ENCODE:
309285303Sgshapiro			pos += rstrm->out_finger - rstrm->out_base;
310285303Sgshapiro			break;
311285303Sgshapiro
31264562Sgshapiro		case XDR_DECODE:
31364562Sgshapiro			pos -= rstrm->in_boundry - rstrm->in_finger;
31464562Sgshapiro			break;
31564562Sgshapiro
31664562Sgshapiro		default:
31790792Sgshapiro			pos = -1;
31890792Sgshapiro			break;
31938032Speter		}
32090792Sgshapiro	return ((u_int) pos);
32190792Sgshapiro}
32290792Sgshapiro
32390792Sgshapirostatic bool_t
32490792Sgshapiroxdrrec_setpos(xdrs, pos)
32590792Sgshapiro	register XDR *xdrs;
32690792Sgshapiro	u_int pos;
32790792Sgshapiro{
32890792Sgshapiro	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
32990792Sgshapiro	u_int currpos = xdrrec_getpos(xdrs);
33090792Sgshapiro	int delta = currpos - pos;
33190792Sgshapiro	caddr_t newpos;
33290792Sgshapiro
33390792Sgshapiro	if ((int)currpos != -1)
33490792Sgshapiro		switch (xdrs->x_op) {
335102528Sgshapiro
33690792Sgshapiro		case XDR_ENCODE:
33764562Sgshapiro			newpos = rstrm->out_finger - delta;
33864562Sgshapiro			if ((newpos > (caddr_t)(rstrm->frag_header)) &&
33964562Sgshapiro				(newpos < rstrm->out_boundry)) {
34064562Sgshapiro				rstrm->out_finger = newpos;
34164562Sgshapiro				return (TRUE);
34290792Sgshapiro			}
34364562Sgshapiro			break;
34464562Sgshapiro
34564562Sgshapiro		case XDR_DECODE:
34664562Sgshapiro			newpos = rstrm->in_finger - delta;
34764562Sgshapiro			if ((delta < (int)(rstrm->fbtbc)) &&
34890792Sgshapiro				(newpos <= rstrm->in_boundry) &&
34964562Sgshapiro				(newpos >= rstrm->in_base)) {
35090792Sgshapiro				rstrm->in_finger = newpos;
35190792Sgshapiro				rstrm->fbtbc -= delta;
35264562Sgshapiro				return (TRUE);
35390792Sgshapiro			}
35490792Sgshapiro			break;
35564562Sgshapiro		}
35690792Sgshapiro	return (FALSE);
357173340Sgshapiro}
358173340Sgshapiro
35990792Sgshapirostatic int32_t *
360223067Sgshapiroxdrrec_inline(xdrs, len)
36164562Sgshapiro	register XDR *xdrs;
36264562Sgshapiro	int len;
36364562Sgshapiro{
36464562Sgshapiro	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
36564562Sgshapiro	int32_t * buf = NULL;
366285303Sgshapiro
367285303Sgshapiro	switch (xdrs->x_op) {
368285303Sgshapiro
36938032Speter	case XDR_ENCODE:
370168515Sgshapiro		if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
371111823Sgshapiro			buf = (int32_t *) rstrm->out_finger;
37264562Sgshapiro			rstrm->out_finger += len;
37364562Sgshapiro		}
37464562Sgshapiro		break;
37590792Sgshapiro
37690792Sgshapiro	case XDR_DECODE:
37790792Sgshapiro		if ((len <= rstrm->fbtbc) &&
378132943Sgshapiro			((rstrm->in_finger + len) <= rstrm->in_boundry)) {
379132943Sgshapiro			buf = (int32_t *) rstrm->in_finger;
38038032Speter			rstrm->fbtbc -= len;
38164562Sgshapiro			rstrm->in_finger += len;
38290792Sgshapiro		}
38338032Speter		break;
38438032Speter	}
38590792Sgshapiro	return (buf);
38664562Sgshapiro}
38790792Sgshapiro
38864562Sgshapirostatic void
389168515Sgshapiroxdrrec_destroy(xdrs)
390168515Sgshapiro	register XDR *xdrs;
391168515Sgshapiro{
392168515Sgshapiro	register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
393168515Sgshapiro
394168515Sgshapiro	mem_free(rstrm->the_buffer,
39564562Sgshapiro		rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
39690792Sgshapiro	mem_free((caddr_t)rstrm, sizeof(RECSTREAM));
39790792Sgshapiro}
39890792Sgshapiro
39990792Sgshapiro
400168515Sgshapiro/*
401168515Sgshapiro * Exported routines to manage xdr records
402168515Sgshapiro */
403168515Sgshapiro
404168515Sgshapiro/*
405168515Sgshapiro * Before reading (deserializing from the stream, one should always call
406168515Sgshapiro * this procedure to guarantee proper record alignment.
407168515Sgshapiro */
40838032Speterbool_t
40938032Speterxdrrec_skiprecord(xdrs)
41038032Speter	XDR *xdrs;
41138032Speter{
41238032Speter	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
41338032Speter
41438032Speter	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
41538032Speter		if (! skip_input_bytes(rstrm, rstrm->fbtbc))
41638032Speter			return (FALSE);
41738032Speter		rstrm->fbtbc = 0;
41838032Speter		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
41938032Speter			return (FALSE);
42038032Speter	}
42138032Speter	rstrm->last_frag = FALSE;
42238032Speter	return (TRUE);
42338032Speter}
42438032Speter
42538032Speter/*
42664562Sgshapiro * Look ahead fuction.
42738032Speter * Returns TRUE iff there is no more input in the buffer
42838032Speter * after consuming the rest of the current record.
42938032Speter */
43038032Speterbool_t
43138032Speterxdrrec_eof(xdrs)
43238032Speter	XDR *xdrs;
43338032Speter{
43438032Speter	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
43538032Speter
43638032Speter	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
43764562Sgshapiro		if (! skip_input_bytes(rstrm, rstrm->fbtbc))
43838032Speter			return (TRUE);
43964562Sgshapiro		rstrm->fbtbc = 0;
44038032Speter		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
44138032Speter			return (TRUE);
44238032Speter	}
44364562Sgshapiro	if (rstrm->in_finger == rstrm->in_boundry)
44464562Sgshapiro		return (TRUE);
44590792Sgshapiro	return (FALSE);
44638032Speter}
44738032Speter
44838032Speter/*
449285303Sgshapiro * The client must tell the package when an end-of-record has occurred.
45090792Sgshapiro * The second paraemters tells whether the record should be flushed to the
45164562Sgshapiro * (output) tcp stream.  (This let's the package support batched or
45264562Sgshapiro * pipelined procedure calls.)  TRUE => immmediate flush to tcp connection.
453141858Sgshapiro */
45464562Sgshapirobool_t
45564562Sgshapiroxdrrec_endofrecord(xdrs, sendnow)
45664562Sgshapiro	XDR *xdrs;
45738032Speter	bool_t sendnow;
45864562Sgshapiro{
45964562Sgshapiro	register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
46064562Sgshapiro	register u_long len;  /* fragment length */
46138032Speter
46264562Sgshapiro	if (sendnow || rstrm->frag_sent ||
46364562Sgshapiro		((u_long)rstrm->out_finger + sizeof(u_int32_t) >=
46464562Sgshapiro		(u_long)rstrm->out_boundry)) {
46564562Sgshapiro		rstrm->frag_sent = FALSE;
46664562Sgshapiro		return (flush_out(rstrm, TRUE));
46764562Sgshapiro	}
46864562Sgshapiro	len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) -
46964562Sgshapiro	   sizeof(u_int32_t);
47064562Sgshapiro	*(rstrm->frag_header) = htonl((u_long)len | LAST_FRAG);
47164562Sgshapiro	rstrm->frag_header = (u_int32_t *)rstrm->out_finger;
47264562Sgshapiro	rstrm->out_finger += sizeof(u_int32_t);
47338032Speter	return (TRUE);
47464562Sgshapiro}
47564562Sgshapiro
47664562Sgshapiro
477285303Sgshapiro/*
47864562Sgshapiro * Internal useful routines
47938032Speter */
48064562Sgshapirostatic bool_t
48164562Sgshapiroflush_out(rstrm, eor)
48264562Sgshapiro	register RECSTREAM *rstrm;
48364562Sgshapiro	bool_t eor;
48464562Sgshapiro{
48564562Sgshapiro	register u_long eormask = (eor == TRUE) ? LAST_FRAG : 0;
48664562Sgshapiro	register u_int32_t len = (u_long)(rstrm->out_finger) -
48764562Sgshapiro		(u_long)(rstrm->frag_header) - sizeof(u_int32_t);
48838032Speter
48964562Sgshapiro	*(rstrm->frag_header) = htonl(len | eormask);
490132943Sgshapiro	len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->out_base);
49138032Speter	if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
49264562Sgshapiro		!= (int)len)
493285303Sgshapiro		return (FALSE);
494285303Sgshapiro	rstrm->frag_header = (u_int32_t *)rstrm->out_base;
49564562Sgshapiro	rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(u_int32_t);
49690792Sgshapiro	return (TRUE);
49764562Sgshapiro}
49864562Sgshapiro
49990792Sgshapirostatic bool_t  /* knows nothing about records!  Only about input buffers */
500285303Sgshapirofill_input_buf(rstrm)
50164562Sgshapiro	register RECSTREAM *rstrm;
50264562Sgshapiro{
50364562Sgshapiro	register caddr_t where;
50464562Sgshapiro	u_long i;
50564562Sgshapiro	register long len;
50664562Sgshapiro
50764562Sgshapiro	where = rstrm->in_base;
50864562Sgshapiro	i = (u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT;
50964562Sgshapiro	where += i;
51064562Sgshapiro	len = rstrm->in_size - i;
51164562Sgshapiro	if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
51264562Sgshapiro		return (FALSE);
51364562Sgshapiro	rstrm->in_finger = where;
51464562Sgshapiro	where += len;
515261363Sgshapiro	rstrm->in_boundry = where;
51638032Speter	return (TRUE);
51764562Sgshapiro}
51864562Sgshapiro
51964562Sgshapirostatic bool_t  /* knows nothing about records!  Only about input buffers */
52090792Sgshapiroget_input_bytes(rstrm, addr, len)
521141858Sgshapiro	register RECSTREAM *rstrm;
52294334Sgshapiro	register caddr_t addr;
52394334Sgshapiro	register int len;
52494334Sgshapiro{
52538032Speter	register long current;
52690792Sgshapiro
52790792Sgshapiro	while (len > 0) {
52890792Sgshapiro		current = (long)rstrm->in_boundry - (long)rstrm->in_finger;
52990792Sgshapiro		if (current == 0) {
530285303Sgshapiro			if (! fill_input_buf(rstrm))
531285303Sgshapiro				return (FALSE);
532285303Sgshapiro			continue;
53390792Sgshapiro		}
534285303Sgshapiro		current = (len < current) ? len : current;
53590792Sgshapiro		memcpy(addr, rstrm->in_finger, current);
53690792Sgshapiro		rstrm->in_finger += current;
53790792Sgshapiro		addr += current;
53890792Sgshapiro		len -= current;
53990792Sgshapiro	}
54090792Sgshapiro	return (TRUE);
54190792Sgshapiro}
54290792Sgshapiro
54390792Sgshapirostatic bool_t  /* next two bytes of the input stream are treated as a header */
54490792Sgshapiroset_input_fragment(rstrm)
54590792Sgshapiro	register RECSTREAM *rstrm;
54690792Sgshapiro{
54790792Sgshapiro	u_int32_t header;
54890792Sgshapiro
54990792Sgshapiro	if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header)))
55090792Sgshapiro		return (FALSE);
55190792Sgshapiro	header = (long)ntohl(header);
55290792Sgshapiro	rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
55390792Sgshapiro	rstrm->fbtbc = header & (~LAST_FRAG);
55490792Sgshapiro	return (TRUE);
55590792Sgshapiro}
55690792Sgshapiro
55790792Sgshapirostatic bool_t  /* consumes input bytes; knows nothing about records! */
55890792Sgshapiroskip_input_bytes(rstrm, cnt)
55990792Sgshapiro	register RECSTREAM *rstrm;
56090792Sgshapiro	long cnt;
56190792Sgshapiro{
56290792Sgshapiro	register long current;
56390792Sgshapiro
56490792Sgshapiro	while (cnt > 0) {
56590792Sgshapiro		current = (long)rstrm->in_boundry - (long)rstrm->in_finger;
56690792Sgshapiro		if (current == 0) {
56790792Sgshapiro			if (! fill_input_buf(rstrm))
56890792Sgshapiro				return (FALSE);
56990792Sgshapiro			continue;
57090792Sgshapiro		}
57190792Sgshapiro		current = (cnt < current) ? cnt : current;
57290792Sgshapiro		rstrm->in_finger += current;
57390792Sgshapiro		cnt -= current;
57490792Sgshapiro	}
57590792Sgshapiro	return (TRUE);
57690792Sgshapiro}
57790792Sgshapiro
57890792Sgshapirostatic u_int
57990792Sgshapirofix_buf_size(s)
58090792Sgshapiro	register u_int s;
58190792Sgshapiro{
58290792Sgshapiro
58390792Sgshapiro	if (s < 100)
58494334Sgshapiro		s = 4000;
58594334Sgshapiro	return (RNDUP(s));
58694334Sgshapiro}
58794334Sgshapiro