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