]> git.saurik.com Git - apple/libinfo.git/blame - rpc.subproj/xdr_rec.c
Libinfo-392.1.tar.gz
[apple/libinfo.git] / rpc.subproj / xdr_rec.c
CommitLineData
03fb6eb0
A
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
ad21edcc
A
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.
03fb6eb0
A
13 *
14 * The Original Code and all software distributed under the License are
ad21edcc 15 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
03fb6eb0
A
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
ad21edcc
A
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.
03fb6eb0
A
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
c29f2fcc
A
24
25/* $NetBSD: xdr_rec.c,v 1.18 2000/07/06 03:10:35 christos Exp $ */
26
03fb6eb0
A
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.
c29f2fcc 34 *
03fb6eb0
A
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.
c29f2fcc 38 *
03fb6eb0
A
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.
c29f2fcc 42 *
03fb6eb0
A
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.
c29f2fcc 46 *
03fb6eb0
A
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.
c29f2fcc 50 *
03fb6eb0
A
51 * Sun Microsystems, Inc.
52 * 2550 Garcia Avenue
53 * Mountain View, California 94043
54 */
c29f2fcc
A
55
56#include <sys/cdefs.h>
03fb6eb0 57#if defined(LIBC_SCCS) && !defined(lint)
c29f2fcc
A
58static char *sccsid = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";
59static char *sccsid = "@(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC";
03fb6eb0 60#endif
c29f2fcc 61#include <sys/cdefs.h>
03fb6eb0
A
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
b3dd680f 74 * is in network byte order. Thegh order bit encodes
03fb6eb0
A
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
c29f2fcc
A
80#include <sys/types.h>
81
82#include <netinet/in.h>
83
84#include <err.h>
03fb6eb0
A
85#include <stdio.h>
86#include <stdlib.h>
3b7c7bd7 87#include <string.h>
b3dd680f 88#include <unistd.h>
c29f2fcc 89
03fb6eb0
A
90#include <rpc/types.h>
91#include <rpc/xdr.h>
c29f2fcc
A
92#include <rpc/auth.h>
93#include <rpc/svc.h>
94#include <rpc/clnt.h>
95
b3dd680f
A
96#ifdef __LP64__
97static bool_t xdrrec_getlong(XDR *, int *);
98static bool_t xdrrec_putlong(XDR *, const int *);
99#else
c29f2fcc
A
100static bool_t xdrrec_getlong(XDR *, long *);
101static bool_t xdrrec_putlong(XDR *, const long *);
b3dd680f
A
102#endif
103
c29f2fcc 104static bool_t xdrrec_getbytes(XDR *, char *, u_int);
03fb6eb0 105
c29f2fcc
A
106static bool_t xdrrec_putbytes(XDR *, const char *, u_int);
107static u_int xdrrec_getpos(XDR *);
108static bool_t xdrrec_setpos(XDR *, u_int);
109static int32_t *xdrrec_inline(XDR *, u_int);
110static void xdrrec_destroy(XDR *);
111
b3dd680f
A
112bool_t __xdrrec_getrec(XDR *, enum xprt_stat *, bool_t);
113
c29f2fcc 114static const struct xdr_ops xdrrec_ops = {
03fb6eb0
A
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.
c29f2fcc 127 * A record fragment is a four-byte header followed by zero to
b3dd680f 128 * 2**32-1 bytes. The header is treated as an unsigned 32-bit integer and is
03fb6eb0
A
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
c29f2fcc 138#define LAST_FRAG ((u_int32_t)(1 << 31))
03fb6eb0
A
139
140typedef struct rec_strm {
b3dd680f 141 void *tcp_handle;
03fb6eb0
A
142 /*
143 * out-goung bits
144 */
c29f2fcc
A
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 */
03fb6eb0
A
150 bool_t frag_sent; /* true if buffer sent in middle of record */
151 /*
152 * in-coming bits
153 */
c29f2fcc 154 int (*readit)(void *, void *, int);
b3dd680f 155 size_t in_size; /* fixed size of the input buffer */
c29f2fcc
A
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 */
b3dd680f 159 int fbtbc; /* fragment bytes to be consumed */
03fb6eb0
A
160 bool_t last_frag;
161 u_int sendsize;
162 u_int recvsize;
c29f2fcc
A
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;
03fb6eb0
A
172} RECSTREAM;
173
c29f2fcc
A
174static u_int fix_buf_size(u_int);
175static bool_t flush_out(RECSTREAM *, bool_t);
176static bool_t fill_input_buf(RECSTREAM *);
177static bool_t get_input_bytes(RECSTREAM *, char *, int);
178static bool_t set_input_fragment(RECSTREAM *);
b3dd680f 179static bool_t skip_input_bytes(RECSTREAM *, int);
c29f2fcc
A
180static bool_t realloc_stream(RECSTREAM *, int);
181
03fb6eb0
A
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 */
192void
193xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit)
c29f2fcc
A
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);
03fb6eb0 202{
c29f2fcc 203 RECSTREAM *rstrm = mem_alloc(sizeof(RECSTREAM));
03fb6eb0
A
204
205 if (rstrm == NULL) {
c29f2fcc 206 warnx("xdrrec_create: out of memory");
03fb6eb0
A
207 /*
208 * This is bad. Should rework xdrrec_create to
209 * return a handle, and in this case return NULL
210 */
211 return;
212 }
03fb6eb0 213 rstrm->sendsize = sendsize = fix_buf_size(sendsize);
c29f2fcc
A
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 }
03fb6eb0 220 rstrm->recvsize = recvsize = fix_buf_size(recvsize);
c29f2fcc
A
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));
03fb6eb0
A
226 return;
227 }
03fb6eb0
A
228 /*
229 * now the rest ...
230 */
231 xdrs->x_ops = &xdrrec_ops;
c29f2fcc 232 xdrs->x_private = rstrm;
03fb6eb0
A
233 rstrm->tcp_handle = tcp_handle;
234 rstrm->readit = readit;
235 rstrm->writeit = writeit;
236 rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
c29f2fcc
A
237 rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base;
238 rstrm->out_finger += sizeof(u_int32_t);
03fb6eb0
A
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;
c29f2fcc
A
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;
03fb6eb0
A
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
260static bool_t
261xdrrec_getlong(xdrs, lp)
262 XDR *xdrs;
b3dd680f
A
263#ifdef __LP64__
264 int *lp;
265#else
03fb6eb0 266 long *lp;
b3dd680f 267#endif
03fb6eb0 268{
c29f2fcc
A
269 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
270 int32_t *buflp = (int32_t *)(void *)(rstrm->in_finger);
271 int32_t mylong;
03fb6eb0
A
272
273 /* first try the inline, fast case */
b3dd680f
A
274 if ((rstrm->fbtbc >= sizeof(int32_t)) && ((rstrm->in_boundry - (char *)buflp) >= sizeof(int32_t)))
275 {
276 *lp = ntohl(*buflp);
c29f2fcc
A
277 rstrm->fbtbc -= sizeof(int32_t);
278 rstrm->in_finger += sizeof(int32_t);
03fb6eb0 279 }
b3dd680f
A
280 else
281 {
282 if (! xdrrec_getbytes(xdrs, (char *)(void *)&mylong, sizeof(int32_t))) return (FALSE);
283 *lp = ntohl(mylong);
284 }
285
03fb6eb0
A
286 return (TRUE);
287}
288
289static bool_t
290xdrrec_putlong(xdrs, lp)
291 XDR *xdrs;
b3dd680f
A
292#ifdef __LP64__
293 const int *lp;
294#else
c29f2fcc 295 const long *lp;
b3dd680f 296#endif
03fb6eb0 297{
c29f2fcc
A
298 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
299 int32_t *dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
03fb6eb0 300
b3dd680f
A
301 if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry)
302 {
03fb6eb0
A
303 /*
304 * this case should almost never happen so the code is
305 * inefficient
306 */
c29f2fcc 307 rstrm->out_finger -= sizeof(int32_t);
03fb6eb0 308 rstrm->frag_sent = TRUE;
b3dd680f 309 if (! flush_out(rstrm, FALSE)) return (FALSE);
c29f2fcc
A
310 dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
311 rstrm->out_finger += sizeof(int32_t);
03fb6eb0 312 }
b3dd680f
A
313
314 *dest_lp = htonl(*lp);
03fb6eb0
A
315 return (TRUE);
316}
317
318static bool_t /* must manage buffers, fragments, and records */
319xdrrec_getbytes(xdrs, addr, len)
320 XDR *xdrs;
c29f2fcc
A
321 char *addr;
322 u_int len;
03fb6eb0 323{
c29f2fcc
A
324 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
325 int current;
03fb6eb0
A
326
327 while (len > 0) {
c29f2fcc 328 current = (int)rstrm->fbtbc;
03fb6eb0
A
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
346static bool_t
347xdrrec_putbytes(xdrs, addr, len)
348 XDR *xdrs;
c29f2fcc
A
349 const char *addr;
350 u_int len;
03fb6eb0 351{
c29f2fcc
A
352 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
353 size_t current;
03fb6eb0
A
354
355 while (len > 0) {
b3dd680f 356 current = (size_t)(rstrm->out_boundry - rstrm->out_finger);
03fb6eb0 357 current = (len < current) ? len : current;
c29f2fcc 358 memmove(rstrm->out_finger, addr, current);
03fb6eb0
A
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
371static u_int
372xdrrec_getpos(xdrs)
c29f2fcc 373 XDR *xdrs;
03fb6eb0 374{
c29f2fcc
A
375 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
376 off_t pos;
b3dd680f
A
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));
03fb6eb0 382
b3dd680f 383 pos = lseek(hfd, 0, 1);
03fb6eb0
A
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:
c29f2fcc 396 pos = (off_t) -1;
03fb6eb0
A
397 break;
398 }
399 return ((u_int) pos);
400}
401
402static bool_t
403xdrrec_setpos(xdrs, pos)
c29f2fcc 404 XDR *xdrs;
03fb6eb0
A
405 u_int pos;
406{
c29f2fcc 407 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
03fb6eb0
A
408 u_int currpos = xdrrec_getpos(xdrs);
409 int delta = currpos - pos;
c29f2fcc 410 char *newpos;
03fb6eb0
A
411
412 if ((int)currpos != -1)
413 switch (xdrs->x_op) {
414
415 case XDR_ENCODE:
416 newpos = rstrm->out_finger - delta;
c29f2fcc 417 if ((newpos > (char *)(void *)(rstrm->frag_header)) &&
03fb6eb0
A
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;
c29f2fcc
A
434
435 case XDR_FREE:
436 break;
03fb6eb0
A
437 }
438 return (FALSE);
439}
440
c29f2fcc 441static int32_t *
03fb6eb0 442xdrrec_inline(xdrs, len)
c29f2fcc
A
443 XDR *xdrs;
444 u_int len;
03fb6eb0 445{
c29f2fcc
A
446 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
447 int32_t *buf = NULL;
03fb6eb0
A
448
449 switch (xdrs->x_op) {
450
451 case XDR_ENCODE:
452 if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
c29f2fcc 453 buf = (int32_t *)(void *)rstrm->out_finger;
03fb6eb0
A
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)) {
c29f2fcc 461 buf = (int32_t *)(void *)rstrm->in_finger;
03fb6eb0
A
462 rstrm->fbtbc -= len;
463 rstrm->in_finger += len;
464 }
465 break;
c29f2fcc
A
466
467 case XDR_FREE:
468 break;
03fb6eb0
A
469 }
470 return (buf);
471}
472
473static void
474xdrrec_destroy(xdrs)
c29f2fcc 475 XDR *xdrs;
03fb6eb0 476{
c29f2fcc 477 RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
03fb6eb0 478
c29f2fcc
A
479 mem_free(rstrm->out_base, rstrm->sendsize);
480 mem_free(rstrm->in_base, rstrm->recvsize);
481 mem_free(rstrm, sizeof(RECSTREAM));
03fb6eb0
A
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 */
493bool_t
494xdrrec_skiprecord(xdrs)
495 XDR *xdrs;
496{
c29f2fcc
A
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 }
03fb6eb0
A
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/*
c29f2fcc
A
525 * Look ahead function.
526 * Returns TRUE iff there is no more input in the buffer
03fb6eb0
A
527 * after consuming the rest of the current record.
528 */
529bool_t
530xdrrec_eof(xdrs)
531 XDR *xdrs;
532{
c29f2fcc 533 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
03fb6eb0
A
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 */
553bool_t
554xdrrec_endofrecord(xdrs, sendnow)
555 XDR *xdrs;
556 bool_t sendnow;
557{
c29f2fcc 558 RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
b3dd680f 559 unsigned int len; /* fragment length */
03fb6eb0
A
560
561 if (sendnow || rstrm->frag_sent ||
b3dd680f 562 (rstrm->out_finger + sizeof(u_int32_t) >= rstrm->out_boundry)) {
03fb6eb0
A
563 rstrm->frag_sent = FALSE;
564 return (flush_out(rstrm, TRUE));
565 }
b3dd680f
A
566 len = rstrm->out_finger - (char *)(rstrm->frag_header) - sizeof(u_int32_t);
567 *(rstrm->frag_header) = htonl(len | LAST_FRAG);
c29f2fcc
A
568 rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_finger;
569 rstrm->out_finger += sizeof(u_int32_t);
03fb6eb0
A
570 return (TRUE);
571}
572
c29f2fcc
A
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 */
577bool_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
654bool_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}
03fb6eb0
A
667
668/*
669 * Internal useful routines
670 */
671static bool_t
672flush_out(rstrm, eor)
c29f2fcc 673 RECSTREAM *rstrm;
03fb6eb0
A
674 bool_t eor;
675{
c29f2fcc 676 u_int32_t eormask = (eor == TRUE) ? LAST_FRAG : 0;
b3dd680f 677 u_int32_t len = rstrm->out_finger - (char *)(rstrm->frag_header) - sizeof(u_int32_t);
03fb6eb0
A
678
679 *(rstrm->frag_header) = htonl(len | eormask);
b3dd680f
A
680 len = rstrm->out_finger - rstrm->out_base;
681 if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, len) != len)
03fb6eb0 682 return (FALSE);
c29f2fcc
A
683 rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base;
684 rstrm->out_finger = (char *)rstrm->out_base + sizeof(u_int32_t);
03fb6eb0
A
685 return (TRUE);
686}
687
688static bool_t /* knows nothing about records! Only about input buffers */
689fill_input_buf(rstrm)
c29f2fcc 690 RECSTREAM *rstrm;
03fb6eb0 691{
c29f2fcc
A
692 char *where;
693 u_int32_t i;
694 int len;
695
696 if (rstrm->nonblock)
697 return FALSE;
03fb6eb0
A
698
699 where = rstrm->in_base;
b3dd680f 700 i = (size_t)(rstrm->in_boundry) % BYTES_PER_XDR_UNIT;
03fb6eb0 701 where += i;
b3dd680f 702 len = rstrm->in_size - i;
03fb6eb0
A
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
711static bool_t /* knows nothing about records! Only about input buffers */
712get_input_bytes(rstrm, addr, len)
c29f2fcc
A
713 RECSTREAM *rstrm;
714 char *addr;
715 int len;
03fb6eb0 716{
c29f2fcc
A
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 }
03fb6eb0
A
726
727 while (len > 0) {
b3dd680f 728 current = (size_t)(rstrm->in_boundry - rstrm->in_finger);
03fb6eb0
A
729 if (current == 0) {
730 if (! fill_input_buf(rstrm))
731 return (FALSE);
732 continue;
733 }
734 current = (len < current) ? len : current;
c29f2fcc 735 memmove(addr, rstrm->in_finger, current);
03fb6eb0
A
736 rstrm->in_finger += current;
737 addr += current;
738 len -= current;
739 }
740 return (TRUE);
741}
742
743static bool_t /* next two bytes of the input stream are treated as a header */
744set_input_fragment(rstrm)
c29f2fcc 745 RECSTREAM *rstrm;
03fb6eb0 746{
c29f2fcc 747 u_int32_t header;
03fb6eb0 748
c29f2fcc
A
749 if (rstrm->nonblock)
750 return FALSE;
751 if (! get_input_bytes(rstrm, (char *)(void *)&header, sizeof(header)))
03fb6eb0 752 return (FALSE);
c29f2fcc 753 header = ntohl(header);
03fb6eb0 754 rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
c29f2fcc
A
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);
03fb6eb0
A
765 rstrm->fbtbc = header & (~LAST_FRAG);
766 return (TRUE);
767}
768
769static bool_t /* consumes input bytes; knows nothing about records! */
770skip_input_bytes(rstrm, cnt)
c29f2fcc 771 RECSTREAM *rstrm;
b3dd680f 772 int cnt;
03fb6eb0 773{
c29f2fcc 774 u_int32_t current;
03fb6eb0
A
775
776 while (cnt > 0) {
b3dd680f 777 current = (size_t)(rstrm->in_boundry - rstrm->in_finger);
03fb6eb0
A
778 if (current == 0) {
779 if (! fill_input_buf(rstrm))
780 return (FALSE);
781 continue;
782 }
b3dd680f 783 current = (cnt < current) ? cnt : current;
03fb6eb0
A
784 rstrm->in_finger += current;
785 cnt -= current;
786 }
787 return (TRUE);
788}
789
790static u_int
791fix_buf_size(s)
c29f2fcc 792 u_int s;
03fb6eb0
A
793{
794
795 if (s < 100)
796 s = 4000;
797 return (RNDUP(s));
798}
c29f2fcc
A
799
800/*
801 * Reallocate the input buffer for a non-block stream.
802 */
803static bool_t
804realloc_stream(rstrm, size)
805 RECSTREAM *rstrm;
806 int size;
807{
b3dd680f 808 int diff;
c29f2fcc
A
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}