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