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