source: rtems-libbsd/freebsd/lib/libc/xdr/xdr_rec.c @ f41a394

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since f41a394 was f41a394, checked in by Sebastian Huber <sebastian.huber@…>, on 06/09/16 at 09:46:09

XDR(3): Import from FreeBSD

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