]> git.saurik.com Git - apple/libinfo.git/blob - rpc.subproj/xdr_rec.c
77fffecf074483f4d8c5f076752aa8bb3c1354f6
[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 in network byte order. 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 #include <unistd.h>
89
90 #include <rpc/types.h>
91 #include <rpc/xdr.h>
92 #include <rpc/auth.h>
93 #include <rpc/svc.h>
94 #include <rpc/clnt.h>
95
96 #ifdef __LP64__
97 static bool_t xdrrec_getlong(XDR *, int *);
98 static bool_t xdrrec_putlong(XDR *, const int *);
99 #else
100 static bool_t xdrrec_getlong(XDR *, long *);
101 static bool_t xdrrec_putlong(XDR *, const long *);
102 #endif
103
104 static bool_t xdrrec_getbytes(XDR *, char *, u_int);
105
106 static bool_t xdrrec_putbytes(XDR *, const char *, u_int);
107 static u_int xdrrec_getpos(XDR *);
108 static bool_t xdrrec_setpos(XDR *, u_int);
109 static int32_t *xdrrec_inline(XDR *, u_int);
110 static void xdrrec_destroy(XDR *);
111
112 bool_t __xdrrec_getrec(XDR *, enum xprt_stat *, bool_t);
113
114 static const struct xdr_ops xdrrec_ops = {
115 xdrrec_getlong,
116 xdrrec_putlong,
117 xdrrec_getbytes,
118 xdrrec_putbytes,
119 xdrrec_getpos,
120 xdrrec_setpos,
121 xdrrec_inline,
122 xdrrec_destroy
123 };
124
125 /*
126 * A record is composed of one or more record fragments.
127 * A record fragment is a four-byte header followed by zero to
128 * 2**32-1 bytes. The header is treated as an unsigned 32-bit integer and is
129 * encode/decoded to the network via htonl/ntohl. The low order 31 bits
130 * are a byte count of the fragment. The highest order bit is a boolean:
131 * 1 => this fragment is the last fragment of the record,
132 * 0 => this fragment is followed by more fragment(s).
133 *
134 * The fragment/record machinery is not general; it is constructed to
135 * meet the needs of xdr and rpc based on tcp.
136 */
137
138 #define LAST_FRAG ((u_int32_t)(1 << 31))
139
140 typedef struct rec_strm {
141 void *tcp_handle;
142 /*
143 * out-goung bits
144 */
145 int (*writeit)(void *, void *, int);
146 char *out_base; /* output buffer (points to frag header) */
147 char *out_finger; /* next output position */
148 char *out_boundry; /* data cannot up to this address */
149 u_int32_t *frag_header; /* beginning of curren fragment */
150 bool_t frag_sent; /* true if buffer sent in middle of record */
151 /*
152 * in-coming bits
153 */
154 int (*readit)(void *, void *, int);
155 size_t in_size; /* fixed size of the input buffer */
156 char *in_base;
157 char *in_finger; /* location of next byte to be had */
158 char *in_boundry; /* can read up to this location */
159 int fbtbc; /* fragment bytes to be consumed */
160 bool_t last_frag;
161 u_int sendsize;
162 u_int recvsize;
163
164 bool_t nonblock;
165 bool_t in_haveheader;
166 u_int32_t in_header;
167 char *in_hdrp;
168 int in_hdrlen;
169 int in_reclen;
170 int in_received;
171 int in_maxrec;
172 } RECSTREAM;
173
174 static u_int fix_buf_size(u_int);
175 static bool_t flush_out(RECSTREAM *, bool_t);
176 static bool_t fill_input_buf(RECSTREAM *);
177 static bool_t get_input_bytes(RECSTREAM *, char *, int);
178 static bool_t set_input_fragment(RECSTREAM *);
179 static bool_t skip_input_bytes(RECSTREAM *, int);
180 static bool_t realloc_stream(RECSTREAM *, int);
181
182
183 /*
184 * Create an xdr handle for xdrrec
185 * xdrrec_create fills in xdrs. Sendsize and recvsize are
186 * send and recv buffer sizes (0 => use default).
187 * tcp_handle is an opaque handle that is passed as the first parameter to
188 * the procedures readit and writeit. Readit and writeit are read and
189 * write respectively. They are like the system
190 * calls expect that they take an opaque handle rather than an fd.
191 */
192 void
193 xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit)
194 XDR *xdrs;
195 u_int sendsize;
196 u_int recvsize;
197 void *tcp_handle;
198 /* like read, but pass it a tcp_handle, not sock */
199 int (*readit)(void *, void *, int);
200 /* like write, but pass it a tcp_handle, not sock */
201 int (*writeit)(void *, void *, int);
202 {
203 RECSTREAM *rstrm = mem_alloc(sizeof(RECSTREAM));
204
205 if (rstrm == NULL) {
206 warnx("xdrrec_create: out of memory");
207 /*
208 * This is bad. Should rework xdrrec_create to
209 * return a handle, and in this case return NULL
210 */
211 return;
212 }
213 rstrm->sendsize = sendsize = fix_buf_size(sendsize);
214 rstrm->out_base = mem_alloc(rstrm->sendsize);
215 if (rstrm->out_base == NULL) {
216 warnx("xdrrec_create: out of memory");
217 mem_free(rstrm, sizeof(RECSTREAM));
218 return;
219 }
220 rstrm->recvsize = recvsize = fix_buf_size(recvsize);
221 rstrm->in_base = mem_alloc(recvsize);
222 if (rstrm->in_base == NULL) {
223 warnx("xdrrec_create: out of memory");
224 mem_free(rstrm->out_base, sendsize);
225 mem_free(rstrm, sizeof(RECSTREAM));
226 return;
227 }
228 /*
229 * now the rest ...
230 */
231 xdrs->x_ops = &xdrrec_ops;
232 xdrs->x_private = rstrm;
233 rstrm->tcp_handle = tcp_handle;
234 rstrm->readit = readit;
235 rstrm->writeit = writeit;
236 rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
237 rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base;
238 rstrm->out_finger += sizeof(u_int32_t);
239 rstrm->out_boundry += sendsize;
240 rstrm->frag_sent = FALSE;
241 rstrm->in_size = recvsize;
242 rstrm->in_boundry = rstrm->in_base;
243 rstrm->in_finger = (rstrm->in_boundry += recvsize);
244 rstrm->fbtbc = 0;
245 rstrm->last_frag = TRUE;
246 rstrm->in_haveheader = FALSE;
247 rstrm->in_hdrlen = 0;
248 rstrm->in_hdrp = (char *)(void *)&rstrm->in_header;
249 rstrm->nonblock = FALSE;
250 rstrm->in_reclen = 0;
251 rstrm->in_received = 0;
252 }
253
254
255 /*
256 * The reoutines defined below are the xdr ops which will go into the
257 * xdr handle filled in by xdrrec_create.
258 */
259
260 static bool_t
261 xdrrec_getlong(xdrs, lp)
262 XDR *xdrs;
263 #ifdef __LP64__
264 int *lp;
265 #else
266 long *lp;
267 #endif
268 {
269 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
270 int32_t *buflp = (int32_t *)(void *)(rstrm->in_finger);
271 int32_t mylong;
272
273 /* first try the inline, fast case */
274 if ((rstrm->fbtbc >= sizeof(int32_t)) && ((rstrm->in_boundry - (char *)buflp) >= sizeof(int32_t)))
275 {
276 *lp = ntohl(*buflp);
277 rstrm->fbtbc -= sizeof(int32_t);
278 rstrm->in_finger += sizeof(int32_t);
279 }
280 else
281 {
282 if (! xdrrec_getbytes(xdrs, (char *)(void *)&mylong, sizeof(int32_t))) return (FALSE);
283 *lp = ntohl(mylong);
284 }
285
286 return (TRUE);
287 }
288
289 static bool_t
290 xdrrec_putlong(xdrs, lp)
291 XDR *xdrs;
292 #ifdef __LP64__
293 const int *lp;
294 #else
295 const long *lp;
296 #endif
297 {
298 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
299 int32_t *dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
300
301 if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry)
302 {
303 /*
304 * this case should almost never happen so the code is
305 * inefficient
306 */
307 rstrm->out_finger -= sizeof(int32_t);
308 rstrm->frag_sent = TRUE;
309 if (! flush_out(rstrm, FALSE)) return (FALSE);
310 dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
311 rstrm->out_finger += sizeof(int32_t);
312 }
313
314 *dest_lp = htonl(*lp);
315 return (TRUE);
316 }
317
318 static bool_t /* must manage buffers, fragments, and records */
319 xdrrec_getbytes(xdrs, addr, len)
320 XDR *xdrs;
321 char *addr;
322 u_int len;
323 {
324 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
325 int current;
326
327 while (len > 0) {
328 current = (int)rstrm->fbtbc;
329 if (current == 0) {
330 if (rstrm->last_frag)
331 return (FALSE);
332 if (! set_input_fragment(rstrm))
333 return (FALSE);
334 continue;
335 }
336 current = (len < current) ? len : current;
337 if (! get_input_bytes(rstrm, addr, current))
338 return (FALSE);
339 addr += current;
340 rstrm->fbtbc -= current;
341 len -= current;
342 }
343 return (TRUE);
344 }
345
346 static bool_t
347 xdrrec_putbytes(xdrs, addr, len)
348 XDR *xdrs;
349 const char *addr;
350 u_int len;
351 {
352 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
353 size_t current;
354
355 while (len > 0) {
356 current = (size_t)(rstrm->out_boundry - rstrm->out_finger);
357 current = (len < current) ? len : current;
358 memmove(rstrm->out_finger, addr, current);
359 rstrm->out_finger += current;
360 addr += current;
361 len -= current;
362 if (rstrm->out_finger == rstrm->out_boundry) {
363 rstrm->frag_sent = TRUE;
364 if (! flush_out(rstrm, FALSE))
365 return (FALSE);
366 }
367 }
368 return (TRUE);
369 }
370
371 static u_int
372 xdrrec_getpos(xdrs)
373 XDR *xdrs;
374 {
375 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
376 off_t pos;
377 int hfd;
378
379 /* tcp_handle is in actual fact just a file descriptor */
380 hfd = 0;
381 memcpy(&hfd, rstrm->tcp_handle, sizeof(hfd));
382
383 pos = lseek(hfd, 0, 1);
384 if (pos != -1)
385 switch (xdrs->x_op) {
386
387 case XDR_ENCODE:
388 pos += rstrm->out_finger - rstrm->out_base;
389 break;
390
391 case XDR_DECODE:
392 pos -= rstrm->in_boundry - rstrm->in_finger;
393 break;
394
395 default:
396 pos = (off_t) -1;
397 break;
398 }
399 return ((u_int) pos);
400 }
401
402 static bool_t
403 xdrrec_setpos(xdrs, pos)
404 XDR *xdrs;
405 u_int pos;
406 {
407 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
408 u_int currpos = xdrrec_getpos(xdrs);
409 int delta = currpos - pos;
410 char *newpos;
411
412 if ((int)currpos != -1)
413 switch (xdrs->x_op) {
414
415 case XDR_ENCODE:
416 newpos = rstrm->out_finger - delta;
417 if ((newpos > (char *)(void *)(rstrm->frag_header)) &&
418 (newpos < rstrm->out_boundry)) {
419 rstrm->out_finger = newpos;
420 return (TRUE);
421 }
422 break;
423
424 case XDR_DECODE:
425 newpos = rstrm->in_finger - delta;
426 if ((delta < (int)(rstrm->fbtbc)) &&
427 (newpos <= rstrm->in_boundry) &&
428 (newpos >= rstrm->in_base)) {
429 rstrm->in_finger = newpos;
430 rstrm->fbtbc -= delta;
431 return (TRUE);
432 }
433 break;
434
435 case XDR_FREE:
436 break;
437 }
438 return (FALSE);
439 }
440
441 static int32_t *
442 xdrrec_inline(xdrs, len)
443 XDR *xdrs;
444 u_int len;
445 {
446 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
447 int32_t *buf = NULL;
448
449 switch (xdrs->x_op) {
450
451 case XDR_ENCODE:
452 if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
453 buf = (int32_t *)(void *)rstrm->out_finger;
454 rstrm->out_finger += len;
455 }
456 break;
457
458 case XDR_DECODE:
459 if ((len <= rstrm->fbtbc) &&
460 ((rstrm->in_finger + len) <= rstrm->in_boundry)) {
461 buf = (int32_t *)(void *)rstrm->in_finger;
462 rstrm->fbtbc -= len;
463 rstrm->in_finger += len;
464 }
465 break;
466
467 case XDR_FREE:
468 break;
469 }
470 return (buf);
471 }
472
473 static void
474 xdrrec_destroy(xdrs)
475 XDR *xdrs;
476 {
477 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
478
479 mem_free(rstrm->out_base, rstrm->sendsize);
480 mem_free(rstrm->in_base, rstrm->recvsize);
481 mem_free(rstrm, sizeof(RECSTREAM));
482 }
483
484
485 /*
486 * Exported routines to manage xdr records
487 */
488
489 /*
490 * Before reading (deserializing from the stream, one should always call
491 * this procedure to guarantee proper record alignment.
492 */
493 bool_t
494 xdrrec_skiprecord(xdrs)
495 XDR *xdrs;
496 {
497 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
498 enum xprt_stat xstat;
499
500 if (rstrm->nonblock) {
501 if (__xdrrec_getrec(xdrs, &xstat, FALSE)) {
502 rstrm->fbtbc = 0;
503 return TRUE;
504 }
505 if (rstrm->in_finger == rstrm->in_boundry &&
506 xstat == XPRT_MOREREQS) {
507 rstrm->fbtbc = 0;
508 return TRUE;
509 }
510 return FALSE;
511 }
512
513 while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
514 if (! skip_input_bytes(rstrm, rstrm->fbtbc))
515 return (FALSE);
516 rstrm->fbtbc = 0;
517 if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
518 return (FALSE);
519 }
520 rstrm->last_frag = FALSE;
521 return (TRUE);
522 }
523
524 /*
525 * Look ahead function.
526 * Returns TRUE iff there is no more input in the buffer
527 * after consuming the rest of the current record.
528 */
529 bool_t
530 xdrrec_eof(xdrs)
531 XDR *xdrs;
532 {
533 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
534
535 while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
536 if (! skip_input_bytes(rstrm, rstrm->fbtbc))
537 return (TRUE);
538 rstrm->fbtbc = 0;
539 if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
540 return (TRUE);
541 }
542 if (rstrm->in_finger == rstrm->in_boundry)
543 return (TRUE);
544 return (FALSE);
545 }
546
547 /*
548 * The client must tell the package when an end-of-record has occurred.
549 * The second paraemters tells whether the record should be flushed to the
550 * (output) tcp stream. (This let's the package support batched or
551 * pipelined procedure calls.) TRUE => immmediate flush to tcp connection.
552 */
553 bool_t
554 xdrrec_endofrecord(xdrs, sendnow)
555 XDR *xdrs;
556 bool_t sendnow;
557 {
558 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
559 unsigned int len; /* fragment length */
560
561 if (sendnow || rstrm->frag_sent ||
562 (rstrm->out_finger + sizeof(u_int32_t) >= rstrm->out_boundry)) {
563 rstrm->frag_sent = FALSE;
564 return (flush_out(rstrm, TRUE));
565 }
566 len = rstrm->out_finger - (char *)(rstrm->frag_header) - sizeof(u_int32_t);
567 *(rstrm->frag_header) = htonl(len | LAST_FRAG);
568 rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_finger;
569 rstrm->out_finger += sizeof(u_int32_t);
570 return (TRUE);
571 }
572
573 /*
574 * Fill the stream buffer with a record for a non-blocking connection.
575 * Return true if a record is available in the buffer, false if not.
576 */
577 bool_t
578 __xdrrec_getrec(xdrs, statp, expectdata)
579 XDR *xdrs;
580 enum xprt_stat *statp;
581 bool_t expectdata;
582 {
583 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
584 ssize_t n;
585 int fraglen;
586
587 if (!rstrm->in_haveheader) {
588 n = rstrm->readit(rstrm->tcp_handle, rstrm->in_hdrp,
589 (int)sizeof (rstrm->in_header) - rstrm->in_hdrlen);
590 if (n == 0) {
591 *statp = expectdata ? XPRT_DIED : XPRT_IDLE;
592 return FALSE;
593 }
594 if (n < 0) {
595 *statp = XPRT_DIED;
596 return FALSE;
597 }
598 rstrm->in_hdrp += n;
599 rstrm->in_hdrlen += n;
600 if (rstrm->in_hdrlen < sizeof (rstrm->in_header)) {
601 *statp = XPRT_MOREREQS;
602 return FALSE;
603 }
604 rstrm->in_header = ntohl(rstrm->in_header);
605 fraglen = (int)(rstrm->in_header & ~LAST_FRAG);
606 if (fraglen == 0 || fraglen > rstrm->in_maxrec ||
607 (rstrm->in_reclen + fraglen) > rstrm->in_maxrec) {
608 *statp = XPRT_DIED;
609 return FALSE;
610 }
611 rstrm->in_reclen += fraglen;
612 if (rstrm->in_reclen > rstrm->recvsize)
613 realloc_stream(rstrm, rstrm->in_reclen);
614 if (rstrm->in_header & LAST_FRAG) {
615 rstrm->in_header &= ~LAST_FRAG;
616 rstrm->last_frag = TRUE;
617 }
618 }
619
620 n = rstrm->readit(rstrm->tcp_handle,
621 rstrm->in_base + rstrm->in_received,
622 (rstrm->in_reclen - rstrm->in_received));
623
624 if (n < 0) {
625 *statp = XPRT_DIED;
626 return FALSE;
627 }
628
629 if (n == 0) {
630 *statp = expectdata ? XPRT_DIED : XPRT_IDLE;
631 return FALSE;
632 }
633
634 rstrm->in_received += n;
635
636 if (rstrm->in_received == rstrm->in_reclen) {
637 rstrm->in_haveheader = FALSE;
638 rstrm->in_hdrp = (char *)(void *)&rstrm->in_header;
639 rstrm->in_hdrlen = 0;
640 if (rstrm->last_frag) {
641 rstrm->fbtbc = rstrm->in_reclen;
642 rstrm->in_boundry = rstrm->in_base + rstrm->in_reclen;
643 rstrm->in_finger = rstrm->in_base;
644 rstrm->in_reclen = rstrm->in_received = 0;
645 *statp = XPRT_MOREREQS;
646 return TRUE;
647 }
648 }
649
650 *statp = XPRT_MOREREQS;
651 return FALSE;
652 }
653
654 bool_t
655 __xdrrec_setnonblock(xdrs, maxrec)
656 XDR *xdrs;
657 int maxrec;
658 {
659 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
660
661 rstrm->nonblock = TRUE;
662 if (maxrec == 0)
663 maxrec = rstrm->recvsize;
664 rstrm->in_maxrec = maxrec;
665 return TRUE;
666 }
667
668 /*
669 * Internal useful routines
670 */
671 static bool_t
672 flush_out(rstrm, eor)
673 RECSTREAM *rstrm;
674 bool_t eor;
675 {
676 u_int32_t eormask = (eor == TRUE) ? LAST_FRAG : 0;
677 u_int32_t len = rstrm->out_finger - (char *)(rstrm->frag_header) - sizeof(u_int32_t);
678
679 *(rstrm->frag_header) = htonl(len | eormask);
680 len = rstrm->out_finger - rstrm->out_base;
681 if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, len) != len)
682 return (FALSE);
683 rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base;
684 rstrm->out_finger = (char *)rstrm->out_base + sizeof(u_int32_t);
685 return (TRUE);
686 }
687
688 static bool_t /* knows nothing about records! Only about input buffers */
689 fill_input_buf(rstrm)
690 RECSTREAM *rstrm;
691 {
692 char *where;
693 u_int32_t i;
694 int len;
695
696 if (rstrm->nonblock)
697 return FALSE;
698
699 where = rstrm->in_base;
700 i = (size_t)(rstrm->in_boundry) % BYTES_PER_XDR_UNIT;
701 where += i;
702 len = rstrm->in_size - i;
703 if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
704 return (FALSE);
705 rstrm->in_finger = where;
706 where += len;
707 rstrm->in_boundry = where;
708 return (TRUE);
709 }
710
711 static bool_t /* knows nothing about records! Only about input buffers */
712 get_input_bytes(rstrm, addr, len)
713 RECSTREAM *rstrm;
714 char *addr;
715 int len;
716 {
717 size_t current;
718
719 if (rstrm->nonblock) {
720 if (len > (int)(rstrm->in_boundry - rstrm->in_finger))
721 return FALSE;
722 memcpy(addr, rstrm->in_finger, (size_t)len);
723 rstrm->in_finger += len;
724 return TRUE;
725 }
726
727 while (len > 0) {
728 current = (size_t)(rstrm->in_boundry - rstrm->in_finger);
729 if (current == 0) {
730 if (! fill_input_buf(rstrm))
731 return (FALSE);
732 continue;
733 }
734 current = (len < current) ? len : current;
735 memmove(addr, rstrm->in_finger, current);
736 rstrm->in_finger += current;
737 addr += current;
738 len -= current;
739 }
740 return (TRUE);
741 }
742
743 static bool_t /* next two bytes of the input stream are treated as a header */
744 set_input_fragment(rstrm)
745 RECSTREAM *rstrm;
746 {
747 u_int32_t header;
748
749 if (rstrm->nonblock)
750 return FALSE;
751 if (! get_input_bytes(rstrm, (char *)(void *)&header, sizeof(header)))
752 return (FALSE);
753 header = ntohl(header);
754 rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
755 /*
756 * Sanity check. Try not to accept wildly incorrect
757 * record sizes. Unfortunately, the only record size
758 * we can positively identify as being 'wildly incorrect'
759 * is zero. Ridiculously large record sizes may look wrong,
760 * but we don't have any way to be certain that they aren't
761 * what the client actually intended to send us.
762 */
763 if (header == 0)
764 return(FALSE);
765 rstrm->fbtbc = header & (~LAST_FRAG);
766 return (TRUE);
767 }
768
769 static bool_t /* consumes input bytes; knows nothing about records! */
770 skip_input_bytes(rstrm, cnt)
771 RECSTREAM *rstrm;
772 int cnt;
773 {
774 u_int32_t current;
775
776 while (cnt > 0) {
777 current = (size_t)(rstrm->in_boundry - rstrm->in_finger);
778 if (current == 0) {
779 if (! fill_input_buf(rstrm))
780 return (FALSE);
781 continue;
782 }
783 current = (cnt < current) ? cnt : current;
784 rstrm->in_finger += current;
785 cnt -= current;
786 }
787 return (TRUE);
788 }
789
790 static u_int
791 fix_buf_size(s)
792 u_int s;
793 {
794
795 if (s < 100)
796 s = 4000;
797 return (RNDUP(s));
798 }
799
800 /*
801 * Reallocate the input buffer for a non-block stream.
802 */
803 static bool_t
804 realloc_stream(rstrm, size)
805 RECSTREAM *rstrm;
806 int size;
807 {
808 int diff;
809 char *buf;
810
811 if (size > rstrm->recvsize) {
812 buf = realloc(rstrm->in_base, (size_t)size);
813 if (buf == NULL)
814 return FALSE;
815 diff = buf - rstrm->in_base;
816 rstrm->in_finger += diff;
817 rstrm->in_base = buf;
818 rstrm->in_boundry = buf + size;
819 rstrm->recvsize = size;
820 rstrm->in_size = size;
821 }
822
823 return TRUE;
824 }