Libinfo-221.tar.gz
[apple/libinfo.git] / rpc.subproj / xdr_rec.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.1 (the "License"). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 /* $NetBSD: xdr_rec.c,v 1.18 2000/07/06 03:10:35 christos Exp $ */
26
27 /*
28 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
29 * unrestricted use provided that this legend is included on all tape
30 * media and as a part of the software program in whole or part. Users
31 * may copy or modify Sun RPC without charge, but are not authorized
32 * to license or distribute it to anyone else except as part of a product or
33 * program developed by the user.
34 *
35 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
36 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
37 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
38 *
39 * Sun RPC is provided with no support and without any obligation on the
40 * part of Sun Microsystems, Inc. to assist in its use, correction,
41 * modification or enhancement.
42 *
43 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
44 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
45 * OR ANY PART THEREOF.
46 *
47 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
48 * or profits or other special, indirect and consequential damages, even if
49 * Sun has been advised of the possibility of such damages.
50 *
51 * Sun Microsystems, Inc.
52 * 2550 Garcia Avenue
53 * Mountain View, California 94043
54 */
55
56 #include <sys/cdefs.h>
57 #if defined(LIBC_SCCS) && !defined(lint)
58 static char *sccsid = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";
59 static char *sccsid = "@(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC";
60 #endif
61 #include <sys/cdefs.h>
62
63 /*
64 * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
65 * layer above tcp (for rpc's use).
66 *
67 * Copyright (C) 1984, Sun Microsystems, Inc.
68 *
69 * These routines interface XDRSTREAMS to a tcp/ip connection.
70 * There is a record marking layer between the xdr stream
71 * and the tcp transport level. A record is composed on one or more
72 * record fragments. A record fragment is a thirty-two bit header followed
73 * by n bytes of data, where n is contained in the header. The header
74 * is represented as a htonl(u_long). Thegh order bit encodes
75 * whether or not the fragment is the last fragment of the record
76 * (1 => fragment is last, 0 => more fragments to follow.
77 * The other 31 bits encode the byte length of the fragment.
78 */
79
80 #include <sys/types.h>
81
82 #include <netinet/in.h>
83
84 #include <err.h>
85 #include <stdio.h>
86 #include <stdlib.h>
87 #include <string.h>
88
89 #include <rpc/types.h>
90 #include <rpc/xdr.h>
91 #include <rpc/auth.h>
92 #include <rpc/svc.h>
93 #include <rpc/clnt.h>
94
95 static bool_t xdrrec_getlong(XDR *, long *);
96 static bool_t xdrrec_putlong(XDR *, const long *);
97 static bool_t xdrrec_getbytes(XDR *, char *, u_int);
98
99 static bool_t xdrrec_putbytes(XDR *, const char *, u_int);
100 static u_int xdrrec_getpos(XDR *);
101 static bool_t xdrrec_setpos(XDR *, u_int);
102 static int32_t *xdrrec_inline(XDR *, u_int);
103 static void xdrrec_destroy(XDR *);
104
105 static const struct xdr_ops xdrrec_ops = {
106 xdrrec_getlong,
107 xdrrec_putlong,
108 xdrrec_getbytes,
109 xdrrec_putbytes,
110 xdrrec_getpos,
111 xdrrec_setpos,
112 xdrrec_inline,
113 xdrrec_destroy
114 };
115
116 /*
117 * A record is composed of one or more record fragments.
118 * A record fragment is a four-byte header followed by zero to
119 * 2**32-1 bytes. The header is treated as a long unsigned and is
120 * encode/decoded to the network via htonl/ntohl. The low order 31 bits
121 * are a byte count of the fragment. The highest order bit is a boolean:
122 * 1 => this fragment is the last fragment of the record,
123 * 0 => this fragment is followed by more fragment(s).
124 *
125 * The fragment/record machinery is not general; it is constructed to
126 * meet the needs of xdr and rpc based on tcp.
127 */
128
129 #define LAST_FRAG ((u_int32_t)(1 << 31))
130
131 typedef struct rec_strm {
132 char *tcp_handle;
133 /*
134 * out-goung bits
135 */
136 int (*writeit)(void *, void *, int);
137 char *out_base; /* output buffer (points to frag header) */
138 char *out_finger; /* next output position */
139 char *out_boundry; /* data cannot up to this address */
140 u_int32_t *frag_header; /* beginning of curren fragment */
141 bool_t frag_sent; /* true if buffer sent in middle of record */
142 /*
143 * in-coming bits
144 */
145 int (*readit)(void *, void *, int);
146 u_long in_size; /* fixed size of the input buffer */
147 char *in_base;
148 char *in_finger; /* location of next byte to be had */
149 char *in_boundry; /* can read up to this location */
150 long fbtbc; /* fragment bytes to be consumed */
151 bool_t last_frag;
152 u_int sendsize;
153 u_int recvsize;
154
155 bool_t nonblock;
156 bool_t in_haveheader;
157 u_int32_t in_header;
158 char *in_hdrp;
159 int in_hdrlen;
160 int in_reclen;
161 int in_received;
162 int in_maxrec;
163 } RECSTREAM;
164
165 static u_int fix_buf_size(u_int);
166 static bool_t flush_out(RECSTREAM *, bool_t);
167 static bool_t fill_input_buf(RECSTREAM *);
168 static bool_t get_input_bytes(RECSTREAM *, char *, int);
169 static bool_t set_input_fragment(RECSTREAM *);
170 static bool_t skip_input_bytes(RECSTREAM *, long);
171 static bool_t realloc_stream(RECSTREAM *, int);
172
173
174 /*
175 * Create an xdr handle for xdrrec
176 * xdrrec_create fills in xdrs. Sendsize and recvsize are
177 * send and recv buffer sizes (0 => use default).
178 * tcp_handle is an opaque handle that is passed as the first parameter to
179 * the procedures readit and writeit. Readit and writeit are read and
180 * write respectively. They are like the system
181 * calls expect that they take an opaque handle rather than an fd.
182 */
183 void
184 xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit)
185 XDR *xdrs;
186 u_int sendsize;
187 u_int recvsize;
188 void *tcp_handle;
189 /* like read, but pass it a tcp_handle, not sock */
190 int (*readit)(void *, void *, int);
191 /* like write, but pass it a tcp_handle, not sock */
192 int (*writeit)(void *, void *, int);
193 {
194 RECSTREAM *rstrm = mem_alloc(sizeof(RECSTREAM));
195
196 if (rstrm == NULL) {
197 warnx("xdrrec_create: out of memory");
198 /*
199 * This is bad. Should rework xdrrec_create to
200 * return a handle, and in this case return NULL
201 */
202 return;
203 }
204 rstrm->sendsize = sendsize = fix_buf_size(sendsize);
205 rstrm->out_base = mem_alloc(rstrm->sendsize);
206 if (rstrm->out_base == NULL) {
207 warnx("xdrrec_create: out of memory");
208 mem_free(rstrm, sizeof(RECSTREAM));
209 return;
210 }
211 rstrm->recvsize = recvsize = fix_buf_size(recvsize);
212 rstrm->in_base = mem_alloc(recvsize);
213 if (rstrm->in_base == NULL) {
214 warnx("xdrrec_create: out of memory");
215 mem_free(rstrm->out_base, sendsize);
216 mem_free(rstrm, sizeof(RECSTREAM));
217 return;
218 }
219 /*
220 * now the rest ...
221 */
222 xdrs->x_ops = &xdrrec_ops;
223 xdrs->x_private = rstrm;
224 rstrm->tcp_handle = tcp_handle;
225 rstrm->readit = readit;
226 rstrm->writeit = writeit;
227 rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
228 rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base;
229 rstrm->out_finger += sizeof(u_int32_t);
230 rstrm->out_boundry += sendsize;
231 rstrm->frag_sent = FALSE;
232 rstrm->in_size = recvsize;
233 rstrm->in_boundry = rstrm->in_base;
234 rstrm->in_finger = (rstrm->in_boundry += recvsize);
235 rstrm->fbtbc = 0;
236 rstrm->last_frag = TRUE;
237 rstrm->in_haveheader = FALSE;
238 rstrm->in_hdrlen = 0;
239 rstrm->in_hdrp = (char *)(void *)&rstrm->in_header;
240 rstrm->nonblock = FALSE;
241 rstrm->in_reclen = 0;
242 rstrm->in_received = 0;
243 }
244
245
246 /*
247 * The reoutines defined below are the xdr ops which will go into the
248 * xdr handle filled in by xdrrec_create.
249 */
250
251 static bool_t
252 xdrrec_getlong(xdrs, lp)
253 XDR *xdrs;
254 long *lp;
255 {
256 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
257 int32_t *buflp = (int32_t *)(void *)(rstrm->in_finger);
258 int32_t mylong;
259
260 /* first try the inline, fast case */
261 if ((rstrm->fbtbc >= sizeof(int32_t)) &&
262 (((long)rstrm->in_boundry - (long)buflp) >= sizeof(int32_t))) {
263 *lp = (long)ntohl((u_int32_t)(*buflp));
264 rstrm->fbtbc -= sizeof(int32_t);
265 rstrm->in_finger += sizeof(int32_t);
266 } else {
267 if (! xdrrec_getbytes(xdrs, (char *)(void *)&mylong,
268 sizeof(int32_t)))
269 return (FALSE);
270 *lp = (long)ntohl((u_int32_t)mylong);
271 }
272 return (TRUE);
273 }
274
275 static bool_t
276 xdrrec_putlong(xdrs, lp)
277 XDR *xdrs;
278 const long *lp;
279 {
280 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
281 int32_t *dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
282
283 if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry) {
284 /*
285 * this case should almost never happen so the code is
286 * inefficient
287 */
288 rstrm->out_finger -= sizeof(int32_t);
289 rstrm->frag_sent = TRUE;
290 if (! flush_out(rstrm, FALSE))
291 return (FALSE);
292 dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
293 rstrm->out_finger += sizeof(int32_t);
294 }
295 *dest_lp = (int32_t)htonl((u_int32_t)(*lp));
296 return (TRUE);
297 }
298
299 static bool_t /* must manage buffers, fragments, and records */
300 xdrrec_getbytes(xdrs, addr, len)
301 XDR *xdrs;
302 char *addr;
303 u_int len;
304 {
305 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
306 int current;
307
308 while (len > 0) {
309 current = (int)rstrm->fbtbc;
310 if (current == 0) {
311 if (rstrm->last_frag)
312 return (FALSE);
313 if (! set_input_fragment(rstrm))
314 return (FALSE);
315 continue;
316 }
317 current = (len < current) ? len : current;
318 if (! get_input_bytes(rstrm, addr, current))
319 return (FALSE);
320 addr += current;
321 rstrm->fbtbc -= current;
322 len -= current;
323 }
324 return (TRUE);
325 }
326
327 static bool_t
328 xdrrec_putbytes(xdrs, addr, len)
329 XDR *xdrs;
330 const char *addr;
331 u_int len;
332 {
333 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
334 size_t current;
335
336 while (len > 0) {
337 current = (size_t)((u_long)rstrm->out_boundry -
338 (u_long)rstrm->out_finger);
339 current = (len < current) ? len : current;
340 memmove(rstrm->out_finger, addr, current);
341 rstrm->out_finger += current;
342 addr += current;
343 len -= current;
344 if (rstrm->out_finger == rstrm->out_boundry) {
345 rstrm->frag_sent = TRUE;
346 if (! flush_out(rstrm, FALSE))
347 return (FALSE);
348 }
349 }
350 return (TRUE);
351 }
352
353 static u_int
354 xdrrec_getpos(xdrs)
355 XDR *xdrs;
356 {
357 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
358 off_t pos;
359
360 pos = lseek((int)(u_long)rstrm->tcp_handle, (off_t)0, 1);
361 if (pos != -1)
362 switch (xdrs->x_op) {
363
364 case XDR_ENCODE:
365 pos += rstrm->out_finger - rstrm->out_base;
366 break;
367
368 case XDR_DECODE:
369 pos -= rstrm->in_boundry - rstrm->in_finger;
370 break;
371
372 default:
373 pos = (off_t) -1;
374 break;
375 }
376 return ((u_int) pos);
377 }
378
379 static bool_t
380 xdrrec_setpos(xdrs, pos)
381 XDR *xdrs;
382 u_int pos;
383 {
384 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
385 u_int currpos = xdrrec_getpos(xdrs);
386 int delta = currpos - pos;
387 char *newpos;
388
389 if ((int)currpos != -1)
390 switch (xdrs->x_op) {
391
392 case XDR_ENCODE:
393 newpos = rstrm->out_finger - delta;
394 if ((newpos > (char *)(void *)(rstrm->frag_header)) &&
395 (newpos < rstrm->out_boundry)) {
396 rstrm->out_finger = newpos;
397 return (TRUE);
398 }
399 break;
400
401 case XDR_DECODE:
402 newpos = rstrm->in_finger - delta;
403 if ((delta < (int)(rstrm->fbtbc)) &&
404 (newpos <= rstrm->in_boundry) &&
405 (newpos >= rstrm->in_base)) {
406 rstrm->in_finger = newpos;
407 rstrm->fbtbc -= delta;
408 return (TRUE);
409 }
410 break;
411
412 case XDR_FREE:
413 break;
414 }
415 return (FALSE);
416 }
417
418 static int32_t *
419 xdrrec_inline(xdrs, len)
420 XDR *xdrs;
421 u_int len;
422 {
423 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
424 int32_t *buf = NULL;
425
426 switch (xdrs->x_op) {
427
428 case XDR_ENCODE:
429 if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
430 buf = (int32_t *)(void *)rstrm->out_finger;
431 rstrm->out_finger += len;
432 }
433 break;
434
435 case XDR_DECODE:
436 if ((len <= rstrm->fbtbc) &&
437 ((rstrm->in_finger + len) <= rstrm->in_boundry)) {
438 buf = (int32_t *)(void *)rstrm->in_finger;
439 rstrm->fbtbc -= len;
440 rstrm->in_finger += len;
441 }
442 break;
443
444 case XDR_FREE:
445 break;
446 }
447 return (buf);
448 }
449
450 static void
451 xdrrec_destroy(xdrs)
452 XDR *xdrs;
453 {
454 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
455
456 mem_free(rstrm->out_base, rstrm->sendsize);
457 mem_free(rstrm->in_base, rstrm->recvsize);
458 mem_free(rstrm, sizeof(RECSTREAM));
459 }
460
461
462 /*
463 * Exported routines to manage xdr records
464 */
465
466 /*
467 * Before reading (deserializing from the stream, one should always call
468 * this procedure to guarantee proper record alignment.
469 */
470 bool_t
471 xdrrec_skiprecord(xdrs)
472 XDR *xdrs;
473 {
474 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
475 enum xprt_stat xstat;
476
477 if (rstrm->nonblock) {
478 if (__xdrrec_getrec(xdrs, &xstat, FALSE)) {
479 rstrm->fbtbc = 0;
480 return TRUE;
481 }
482 if (rstrm->in_finger == rstrm->in_boundry &&
483 xstat == XPRT_MOREREQS) {
484 rstrm->fbtbc = 0;
485 return TRUE;
486 }
487 return FALSE;
488 }
489
490 while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
491 if (! skip_input_bytes(rstrm, rstrm->fbtbc))
492 return (FALSE);
493 rstrm->fbtbc = 0;
494 if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
495 return (FALSE);
496 }
497 rstrm->last_frag = FALSE;
498 return (TRUE);
499 }
500
501 /*
502 * Look ahead function.
503 * Returns TRUE iff there is no more input in the buffer
504 * after consuming the rest of the current record.
505 */
506 bool_t
507 xdrrec_eof(xdrs)
508 XDR *xdrs;
509 {
510 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
511
512 while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
513 if (! skip_input_bytes(rstrm, rstrm->fbtbc))
514 return (TRUE);
515 rstrm->fbtbc = 0;
516 if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
517 return (TRUE);
518 }
519 if (rstrm->in_finger == rstrm->in_boundry)
520 return (TRUE);
521 return (FALSE);
522 }
523
524 /*
525 * The client must tell the package when an end-of-record has occurred.
526 * The second paraemters tells whether the record should be flushed to the
527 * (output) tcp stream. (This let's the package support batched or
528 * pipelined procedure calls.) TRUE => immmediate flush to tcp connection.
529 */
530 bool_t
531 xdrrec_endofrecord(xdrs, sendnow)
532 XDR *xdrs;
533 bool_t sendnow;
534 {
535 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
536 u_long len; /* fragment length */
537
538 if (sendnow || rstrm->frag_sent ||
539 ((u_long)rstrm->out_finger + sizeof(u_int32_t) >=
540 (u_long)rstrm->out_boundry)) {
541 rstrm->frag_sent = FALSE;
542 return (flush_out(rstrm, TRUE));
543 }
544 len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) -
545 sizeof(u_int32_t);
546 *(rstrm->frag_header) = htonl((u_int32_t)len | LAST_FRAG);
547 rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_finger;
548 rstrm->out_finger += sizeof(u_int32_t);
549 return (TRUE);
550 }
551
552 /*
553 * Fill the stream buffer with a record for a non-blocking connection.
554 * Return true if a record is available in the buffer, false if not.
555 */
556 bool_t
557 __xdrrec_getrec(xdrs, statp, expectdata)
558 XDR *xdrs;
559 enum xprt_stat *statp;
560 bool_t expectdata;
561 {
562 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
563 ssize_t n;
564 int fraglen;
565
566 if (!rstrm->in_haveheader) {
567 n = rstrm->readit(rstrm->tcp_handle, rstrm->in_hdrp,
568 (int)sizeof (rstrm->in_header) - rstrm->in_hdrlen);
569 if (n == 0) {
570 *statp = expectdata ? XPRT_DIED : XPRT_IDLE;
571 return FALSE;
572 }
573 if (n < 0) {
574 *statp = XPRT_DIED;
575 return FALSE;
576 }
577 rstrm->in_hdrp += n;
578 rstrm->in_hdrlen += n;
579 if (rstrm->in_hdrlen < sizeof (rstrm->in_header)) {
580 *statp = XPRT_MOREREQS;
581 return FALSE;
582 }
583 rstrm->in_header = ntohl(rstrm->in_header);
584 fraglen = (int)(rstrm->in_header & ~LAST_FRAG);
585 if (fraglen == 0 || fraglen > rstrm->in_maxrec ||
586 (rstrm->in_reclen + fraglen) > rstrm->in_maxrec) {
587 *statp = XPRT_DIED;
588 return FALSE;
589 }
590 rstrm->in_reclen += fraglen;
591 if (rstrm->in_reclen > rstrm->recvsize)
592 realloc_stream(rstrm, rstrm->in_reclen);
593 if (rstrm->in_header & LAST_FRAG) {
594 rstrm->in_header &= ~LAST_FRAG;
595 rstrm->last_frag = TRUE;
596 }
597 }
598
599 n = rstrm->readit(rstrm->tcp_handle,
600 rstrm->in_base + rstrm->in_received,
601 (rstrm->in_reclen - rstrm->in_received));
602
603 if (n < 0) {
604 *statp = XPRT_DIED;
605 return FALSE;
606 }
607
608 if (n == 0) {
609 *statp = expectdata ? XPRT_DIED : XPRT_IDLE;
610 return FALSE;
611 }
612
613 rstrm->in_received += n;
614
615 if (rstrm->in_received == rstrm->in_reclen) {
616 rstrm->in_haveheader = FALSE;
617 rstrm->in_hdrp = (char *)(void *)&rstrm->in_header;
618 rstrm->in_hdrlen = 0;
619 if (rstrm->last_frag) {
620 rstrm->fbtbc = rstrm->in_reclen;
621 rstrm->in_boundry = rstrm->in_base + rstrm->in_reclen;
622 rstrm->in_finger = rstrm->in_base;
623 rstrm->in_reclen = rstrm->in_received = 0;
624 *statp = XPRT_MOREREQS;
625 return TRUE;
626 }
627 }
628
629 *statp = XPRT_MOREREQS;
630 return FALSE;
631 }
632
633 bool_t
634 __xdrrec_setnonblock(xdrs, maxrec)
635 XDR *xdrs;
636 int maxrec;
637 {
638 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
639
640 rstrm->nonblock = TRUE;
641 if (maxrec == 0)
642 maxrec = rstrm->recvsize;
643 rstrm->in_maxrec = maxrec;
644 return TRUE;
645 }
646
647 /*
648 * Internal useful routines
649 */
650 static bool_t
651 flush_out(rstrm, eor)
652 RECSTREAM *rstrm;
653 bool_t eor;
654 {
655 u_int32_t eormask = (eor == TRUE) ? LAST_FRAG : 0;
656 u_int32_t len = (u_int32_t)((u_long)(rstrm->out_finger) -
657 (u_long)(rstrm->frag_header) - sizeof(u_int32_t));
658
659 *(rstrm->frag_header) = htonl(len | eormask);
660 len = (u_int32_t)((u_long)(rstrm->out_finger) -
661 (u_long)(rstrm->out_base));
662 if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
663 != (int)len)
664 return (FALSE);
665 rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base;
666 rstrm->out_finger = (char *)rstrm->out_base + sizeof(u_int32_t);
667 return (TRUE);
668 }
669
670 static bool_t /* knows nothing about records! Only about input buffers */
671 fill_input_buf(rstrm)
672 RECSTREAM *rstrm;
673 {
674 char *where;
675 u_int32_t i;
676 int len;
677
678 if (rstrm->nonblock)
679 return FALSE;
680
681 where = rstrm->in_base;
682 i = (u_int32_t)((u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT);
683 where += i;
684 len = (u_int32_t)(rstrm->in_size - i);
685 if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
686 return (FALSE);
687 rstrm->in_finger = where;
688 where += len;
689 rstrm->in_boundry = where;
690 return (TRUE);
691 }
692
693 static bool_t /* knows nothing about records! Only about input buffers */
694 get_input_bytes(rstrm, addr, len)
695 RECSTREAM *rstrm;
696 char *addr;
697 int len;
698 {
699 size_t current;
700
701 if (rstrm->nonblock) {
702 if (len > (int)(rstrm->in_boundry - rstrm->in_finger))
703 return FALSE;
704 memcpy(addr, rstrm->in_finger, (size_t)len);
705 rstrm->in_finger += len;
706 return TRUE;
707 }
708
709 while (len > 0) {
710 current = (size_t)((long)rstrm->in_boundry -
711 (long)rstrm->in_finger);
712 if (current == 0) {
713 if (! fill_input_buf(rstrm))
714 return (FALSE);
715 continue;
716 }
717 current = (len < current) ? len : current;
718 memmove(addr, rstrm->in_finger, current);
719 rstrm->in_finger += current;
720 addr += current;
721 len -= current;
722 }
723 return (TRUE);
724 }
725
726 static bool_t /* next two bytes of the input stream are treated as a header */
727 set_input_fragment(rstrm)
728 RECSTREAM *rstrm;
729 {
730 u_int32_t header;
731
732 if (rstrm->nonblock)
733 return FALSE;
734 if (! get_input_bytes(rstrm, (char *)(void *)&header, sizeof(header)))
735 return (FALSE);
736 header = ntohl(header);
737 rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
738 /*
739 * Sanity check. Try not to accept wildly incorrect
740 * record sizes. Unfortunately, the only record size
741 * we can positively identify as being 'wildly incorrect'
742 * is zero. Ridiculously large record sizes may look wrong,
743 * but we don't have any way to be certain that they aren't
744 * what the client actually intended to send us.
745 */
746 if (header == 0)
747 return(FALSE);
748 rstrm->fbtbc = header & (~LAST_FRAG);
749 return (TRUE);
750 }
751
752 static bool_t /* consumes input bytes; knows nothing about records! */
753 skip_input_bytes(rstrm, cnt)
754 RECSTREAM *rstrm;
755 long cnt;
756 {
757 u_int32_t current;
758
759 while (cnt > 0) {
760 current = (size_t)((long)rstrm->in_boundry -
761 (long)rstrm->in_finger);
762 if (current == 0) {
763 if (! fill_input_buf(rstrm))
764 return (FALSE);
765 continue;
766 }
767 current = (u_int32_t)((cnt < current) ? cnt : current);
768 rstrm->in_finger += current;
769 cnt -= current;
770 }
771 return (TRUE);
772 }
773
774 static u_int
775 fix_buf_size(s)
776 u_int s;
777 {
778
779 if (s < 100)
780 s = 4000;
781 return (RNDUP(s));
782 }
783
784 /*
785 * Reallocate the input buffer for a non-block stream.
786 */
787 static bool_t
788 realloc_stream(rstrm, size)
789 RECSTREAM *rstrm;
790 int size;
791 {
792 long diff;
793 char *buf;
794
795 if (size > rstrm->recvsize) {
796 buf = realloc(rstrm->in_base, (size_t)size);
797 if (buf == NULL)
798 return FALSE;
799 diff = buf - rstrm->in_base;
800 rstrm->in_finger += diff;
801 rstrm->in_base = buf;
802 rstrm->in_boundry = buf + size;
803 rstrm->recvsize = size;
804 rstrm->in_size = size;
805 }
806
807 return TRUE;
808 }