source: rtems-libbsd/services/librpc/src/xdr/xdr_rec.c @ cd450d2

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since cd450d2 was cd450d2, checked in by Joel Sherrill <joel.sherrill@…>, on 08/06/12 at 00:10:35

librpc: now compiles

  • Property mode set to 100644
File size: 15.8 KB
Line 
1/*
2 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
3 * unrestricted use provided that this legend is included on all tape
4 * media and as a part of the software program in whole or part.  Users
5 * may copy or modify Sun RPC without charge, but are not authorized
6 * to license or distribute it to anyone else except as part of a product or
7 * program developed by the user.
8 *
9 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
10 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
11 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12 *
13 * Sun RPC is provided with no support and without any obligation on the
14 * part of Sun Microsystems, Inc. to assist in its use, correction,
15 * modification or enhancement.
16 *
17 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
18 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
19 * OR ANY PART THEREOF.
20 *
21 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
22 * or profits or other special, indirect and consequential damages, even if
23 * Sun has been advised of the possibility of such damages.
24 *
25 * Sun Microsystems, Inc.
26 * 2550 Garcia Avenue
27 * Mountain View, California  94043
28 */
29#if defined(LIBC_SCCS) && !defined(lint)
30/*static char *sccsid = "from: @(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";*/
31/*static char *sccsid = "from: @(#)xdr_rec.c    2.2 88/08/01 4.0 RPCSRC";*/
32static char *rcsid = "$FreeBSD: src/lib/libc/xdr/xdr_rec.c,v 1.12 2000/01/19 06:12:32 wpaul Exp $";
33#endif
34
35/*
36 * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
37 * layer above tcp (for rpc's use).
38 *
39 * Copyright (C) 1984, Sun Microsystems, Inc.
40 *
41 * These routines interface XDRSTREAMS to a tcp/ip connection.
42 * There is a record marking layer between the xdr stream
43 * and the tcp transport level.  A record is composed on one or more
44 * record fragments.  A record fragment is a thirty-two bit header followed
45 * by n bytes of data, where n is contained in the header.  The header
46 * is represented as a htonl(u_long).  Thegh order bit encodes
47 * whether or not the fragment is the last fragment of the record
48 * (1 => fragment is last, 0 => more fragments to follow.
49 * The other 31 bits encode the byte length of the fragment.
50 */
51
52#ifdef HAVE_CONFIG_H
53#include "config.h"
54#endif
55
56#include <freebsd/bsd.h>
57#include <stdio.h>
58#include <stdlib.h>
59#include <string.h>
60#include <rpc/types.h>
61#include <rpc/xdr.h>
62#include <netinet/in.h>
63#include <unistd.h>   /* for lseek() */
64
65typedef struct rec_strm RECSTREAM;
66
67static u_int    fix_buf_size(u_int);
68static bool_t   flush_out(RECSTREAM *rstrm, bool_t eor);
69static bool_t   get_input_bytes(RECSTREAM *rstrm, caddr_t addr, int len);
70static bool_t   set_input_fragment(RECSTREAM *rstrm);
71static bool_t   skip_input_bytes(RECSTREAM *rstrm, long cnt);
72
73static bool_t   xdrrec_getlong(XDR *xdrs, long *lp);
74static bool_t   xdrrec_putlong(XDR *xdrs, const long *lp);
75static bool_t   xdrrec_getbytes(XDR *xdrs, caddr_t addr, u_int len);
76static bool_t   xdrrec_putbytes(XDR *xdrs, const char *addr, u_int len);
77static u_int    xdrrec_getpos(XDR *xdrs);
78static bool_t   xdrrec_setpos(XDR *xdrs, u_int pos);
79static int32_t *xdrrec_inline(XDR *xdrs, u_int len);
80static void     xdrrec_destroy(XDR *xdrs);
81
82static struct  xdr_ops xdrrec_ops = {
83        xdrrec_getlong,
84        xdrrec_putlong,
85        xdrrec_getbytes,
86        xdrrec_putbytes,
87        xdrrec_getpos,
88        xdrrec_setpos,
89        xdrrec_inline,
90        xdrrec_destroy
91};
92
93/*
94 * A record is composed of one or more record fragments.
95 * A record fragment is a two-byte header followed by zero to
96 * 2**32-1 bytes.  The header is treated as a long unsigned and is
97 * encode/decoded to the network via htonl/ntohl.  The low order 31 bits
98 * are a byte count of the fragment.  The highest order bit is a boolean:
99 * 1 => this fragment is the last fragment of the record,
100 * 0 => this fragment is followed by more fragment(s).
101 *
102 * The fragment/record machinery is not general;  it is constructed to
103 * meet the needs of xdr and rpc based on tcp.
104 */
105
106#define LAST_FRAG ((u_int32_t)(1L << 31))
107
108struct rec_strm {
109        caddr_t tcp_handle;
110        caddr_t the_buffer;
111        /*
112         * out-goung bits
113         */
114        int (*writeit) (caddr_t, caddr_t, int);
115        caddr_t out_base;       /* output buffer (points to frag header) */
116        caddr_t out_finger;     /* next output position */
117        caddr_t out_boundry;    /* data cannot up to this address */
118        u_int32_t *frag_header; /* beginning of current fragment */
119        bool_t frag_sent;       /* true if buffer sent in middle of record */
120        /*
121         * in-coming bits
122         */
123        int (*readit) (caddr_t, caddr_t, int);
124        u_long in_size; /* fixed size of the input buffer */
125        caddr_t in_base;
126        caddr_t in_finger;      /* location of next byte to be had */
127        caddr_t in_boundry;     /* can read up to this location */
128        long fbtbc;             /* fragment bytes to be consumed */
129        bool_t last_frag;
130        u_int sendsize;
131        u_int recvsize;
132};
133
134
135/*
136 * Create an xdr handle for xdrrec
137 * xdrrec_create fills in xdrs.  Sendsize and recvsize are
138 * send and recv buffer sizes (0 => use default).
139 * tcp_handle is an opaque handle that is passed as the first parameter to
140 * the procedures readit and writeit.  Readit and writeit are read and
141 * write respectively.   They are like the system
142 * calls expect that they take an opaque handle rather than an fd.
143 */
144void
145xdrrec_create(
146        XDR *xdrs,
147        u_int sendsize,
148        u_int recvsize,
149        void *tcp_handle,
150        int (*readit)(void*, void*, int),  /* like read, but pass it a tcp_handle, not sock */
151        int (*writeit)(void*, void*, int)  /* like write, but pass it a tcp_handle, not sock */
152)
153{
154        RECSTREAM *rstrm =
155                (RECSTREAM *)mem_alloc(sizeof(RECSTREAM));
156
157        if (rstrm == NULL) {
158                (void)fprintf(stderr, "xdrrec_create: out of memory\n");
159                /*
160                 *  This is bad.  Should rework xdrrec_create to
161                 *  return a handle, and in this case return NULL
162                 */
163                return;
164        }
165        /*
166         * adjust sizes and allocate buffer quad byte aligned
167         */
168        rstrm->sendsize = sendsize = fix_buf_size(sendsize);
169        rstrm->recvsize = recvsize = fix_buf_size(recvsize);
170        rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT);
171        if (rstrm->the_buffer == NULL) {
172                (void)fprintf(stderr, "xdrrec_create: out of memory\n");
173                return;
174        }
175        for (rstrm->out_base = rstrm->the_buffer;
176                (uintptr_t)rstrm->out_base % BYTES_PER_XDR_UNIT != 0;
177                rstrm->out_base++);
178        rstrm->in_base = rstrm->out_base + sendsize;
179        /*
180         * now the rest ...
181         */
182        xdrs->x_ops = &xdrrec_ops;
183        xdrs->x_private = (caddr_t)rstrm;
184        rstrm->tcp_handle = tcp_handle;
185        rstrm->readit = readit;
186        rstrm->writeit = writeit;
187        rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
188        rstrm->frag_header = (u_int32_t *)rstrm->out_base;
189        rstrm->out_finger += sizeof(u_int32_t);
190        rstrm->out_boundry += sendsize;
191        rstrm->frag_sent = FALSE;
192        rstrm->in_size = recvsize;
193        rstrm->in_boundry = rstrm->in_base;
194        rstrm->in_finger = (rstrm->in_boundry += recvsize);
195        rstrm->fbtbc = 0;
196        rstrm->last_frag = TRUE;
197}
198
199
200/*
201 * The reoutines defined below are the xdr ops which will go into the
202 * xdr handle filled in by xdrrec_create.
203 */
204
205static bool_t
206xdrrec_getlong(
207        XDR *xdrs,
208        long *lp)
209{
210        RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
211        int32_t *buflp = (int32_t *)(rstrm->in_finger);
212        int32_t mylong;
213
214        /* first try the inline, fast case */
215        if ((rstrm->fbtbc >= sizeof(int32_t)) &&
216                (((intptr_t)rstrm->in_boundry - (intptr_t)buflp) >= sizeof(int32_t))) {
217                *lp = (long)ntohl((u_int32_t)(*buflp));
218                rstrm->fbtbc -= sizeof(int32_t);
219                rstrm->in_finger += sizeof(int32_t);
220        } else {
221                if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof(int32_t)))
222                        return (FALSE);
223                *lp = (long)ntohl((u_int32_t)mylong);
224        }
225        return (TRUE);
226}
227
228static bool_t
229xdrrec_putlong(
230        XDR *xdrs,
231        const long *lp)
232{
233        RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
234        int32_t *dest_lp = ((int32_t *)(rstrm->out_finger));
235
236        if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry) {
237                /*
238                 * this case should almost never happen so the code is
239                 * inefficient
240                 */
241                rstrm->out_finger -= sizeof(int32_t);
242                rstrm->frag_sent = TRUE;
243                if (! flush_out(rstrm, FALSE))
244                        return (FALSE);
245                dest_lp = ((int32_t *)(rstrm->out_finger));
246                rstrm->out_finger += sizeof(int32_t);
247        }
248        *dest_lp = (int32_t)htonl((u_int32_t)(*lp));
249        return (TRUE);
250}
251
252static bool_t  /* must manage buffers, fragments, and records */
253xdrrec_getbytes(
254        XDR *xdrs,
255        caddr_t addr,
256        u_int len)
257{
258        RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
259        int current;
260
261        while (len > 0) {
262                current = rstrm->fbtbc;
263                if (current == 0) {
264                        if (rstrm->last_frag)
265                                return (FALSE);
266                        if (! set_input_fragment(rstrm))
267                                return (FALSE);
268                        continue;
269                }
270                current = (len < current) ? len : current;
271                if (! get_input_bytes(rstrm, addr, current))
272                        return (FALSE);
273                addr += current;
274                rstrm->fbtbc -= current;
275                len -= current;
276        }
277        return (TRUE);
278}
279
280static bool_t
281xdrrec_putbytes(
282        XDR *xdrs,
283        const char *addr,
284        u_int len)
285{
286        RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
287        long current;
288
289        while (len > 0) {
290                current = (intptr_t)rstrm->out_boundry -
291                        (intptr_t)rstrm->out_finger;
292                current = (len < current) ? len : current;
293                memcpy(rstrm->out_finger, addr, current);
294                rstrm->out_finger += current;
295                addr += current;
296                len -= current;
297                if (rstrm->out_finger == rstrm->out_boundry) {
298                        rstrm->frag_sent = TRUE;
299                        if (! flush_out(rstrm, FALSE))
300                                return (FALSE);
301                }
302        }
303        return (TRUE);
304}
305
306static u_int
307xdrrec_getpos(
308        XDR *xdrs)
309{
310        RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
311        long pos;
312
313        pos = lseek((intptr_t)rstrm->tcp_handle, (off_t) 0, 1);
314        if (pos != -1)
315                switch (xdrs->x_op) {
316
317                case XDR_ENCODE:
318                        pos += rstrm->out_finger - rstrm->out_base;
319                        break;
320
321                case XDR_DECODE:
322                        pos -= rstrm->in_boundry - rstrm->in_finger;
323                        break;
324
325                default:
326                        pos = -1;
327                        break;
328                }
329        return ((u_int) pos);
330}
331
332static bool_t
333xdrrec_setpos(
334        XDR *xdrs,
335        u_int pos)
336{
337        RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
338        u_int currpos = xdrrec_getpos(xdrs);
339        int delta = currpos - pos;
340        caddr_t newpos;
341
342        if ((int)currpos != -1)
343                switch (xdrs->x_op) {
344
345                case XDR_ENCODE:
346                        newpos = rstrm->out_finger - delta;
347                        if ((newpos > (caddr_t)(rstrm->frag_header)) &&
348                                (newpos < rstrm->out_boundry)) {
349                                rstrm->out_finger = newpos;
350                                return (TRUE);
351                        }
352                        break;
353
354                case XDR_DECODE:
355                        newpos = rstrm->in_finger - delta;
356                        if ((delta < (int)(rstrm->fbtbc)) &&
357                                (newpos <= rstrm->in_boundry) &&
358                                (newpos >= rstrm->in_base)) {
359                                rstrm->in_finger = newpos;
360                                rstrm->fbtbc -= delta;
361                                return (TRUE);
362                        }
363                        break;
364                case XDR_FREE:  /* to avoid warning */
365                        break;
366                }
367        return (FALSE);
368}
369
370static int32_t *
371xdrrec_inline(
372        XDR *xdrs,
373        u_int len)
374{
375        RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
376        int32_t * buf = NULL;
377
378        switch (xdrs->x_op) {
379
380        case XDR_ENCODE:
381                if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
382                        buf = (int32_t *) rstrm->out_finger;
383                        rstrm->out_finger += len;
384                }
385                break;
386
387        case XDR_DECODE:
388                if ((len <= rstrm->fbtbc) &&
389                        ((rstrm->in_finger + len) <= rstrm->in_boundry)) {
390                        buf = (int32_t *) rstrm->in_finger;
391                        rstrm->fbtbc -= len;
392                        rstrm->in_finger += len;
393                }
394                break;
395        case XDR_FREE:  /* to avoid warning */
396                break;
397        }
398        return (buf);
399}
400
401static void
402xdrrec_destroy(
403        XDR *xdrs)
404{
405        RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
406
407        mem_free(rstrm->the_buffer,
408                rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
409        mem_free((caddr_t)rstrm, sizeof(RECSTREAM));
410}
411
412
413/*
414 * Exported routines to manage xdr records
415 */
416
417/*
418 * Before reading (deserializing from the stream, one should always call
419 * this procedure to guarantee proper record alignment.
420 */
421bool_t
422xdrrec_skiprecord(
423        XDR *xdrs)
424{
425        RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
426
427        while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
428                if (! skip_input_bytes(rstrm, rstrm->fbtbc))
429                        return (FALSE);
430                rstrm->fbtbc = 0;
431                if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
432                        return (FALSE);
433        }
434        rstrm->last_frag = FALSE;
435        return (TRUE);
436}
437
438/*
439 * Look ahead fuction.
440 * Returns TRUE iff there is no more input in the buffer
441 * after consuming the rest of the current record.
442 */
443bool_t
444xdrrec_eof(
445        XDR *xdrs)
446{
447        RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
448
449        while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
450                if (! skip_input_bytes(rstrm, rstrm->fbtbc))
451                        return (TRUE);
452                rstrm->fbtbc = 0;
453                if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
454                        return (TRUE);
455        }
456        if (rstrm->in_finger == rstrm->in_boundry)
457                return (TRUE);
458        return (FALSE);
459}
460
461/*
462 * The client must tell the package when an end-of-record has occurred.
463 * The second paraemters tells whether the record should be flushed to the
464 * (output) tcp stream.  (This let's the package support batched or
465 * pipelined procedure calls.)  TRUE => immmediate flush to tcp connection.
466 */
467bool_t
468xdrrec_endofrecord(
469        XDR *xdrs,
470        int sendnow)
471{
472        RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
473        u_long len;  /* fragment length */
474
475        if (sendnow || rstrm->frag_sent ||
476                ((uintptr_t)rstrm->out_finger + sizeof(u_int32_t) >=
477                (uintptr_t)rstrm->out_boundry)) {
478                rstrm->frag_sent = FALSE;
479                return (flush_out(rstrm, TRUE));
480        }
481        len = (uintptr_t)(rstrm->out_finger) - (uintptr_t)(rstrm->frag_header) -
482           sizeof(u_int32_t);
483        *(rstrm->frag_header) = htonl((u_int32_t)len | LAST_FRAG);
484        rstrm->frag_header = (u_int32_t *)rstrm->out_finger;
485        rstrm->out_finger += sizeof(u_int32_t);
486        return (TRUE);
487}
488
489
490/*
491 * Internal useful routines
492 */
493static bool_t
494flush_out(
495        RECSTREAM *rstrm,
496        bool_t eor)
497{
498        u_int32_t eormask = (eor == TRUE) ? LAST_FRAG : 0;
499        u_int32_t len = (uintptr_t)(rstrm->out_finger) -
500                (uintptr_t)(rstrm->frag_header) - sizeof(u_int32_t);
501
502        *(rstrm->frag_header) = htonl(len | eormask);
503        len = (uintptr_t)(rstrm->out_finger) - (uintptr_t)(rstrm->out_base);
504        if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
505                != (int)len)
506                return (FALSE);
507        rstrm->frag_header = (u_int32_t *)rstrm->out_base;
508        rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(u_int32_t);
509        return (TRUE);
510}
511
512static bool_t  /* knows nothing about records!  Only about input buffers */
513fill_input_buf(
514        RECSTREAM *rstrm)
515{
516        caddr_t where;
517        u_long i;
518        long len;
519
520        where = rstrm->in_base;
521        i = (uintptr_t)rstrm->in_boundry % BYTES_PER_XDR_UNIT;
522        where += i;
523        len = rstrm->in_size - i;
524        if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
525                return (FALSE);
526        rstrm->in_finger = where;
527        where += len;
528        rstrm->in_boundry = where;
529        return (TRUE);
530}
531
532static bool_t  /* knows nothing about records!  Only about input buffers */
533get_input_bytes(
534        RECSTREAM *rstrm,
535        caddr_t addr,
536        int len)
537{
538        long current;
539
540        while (len > 0) {
541                current = (intptr_t)rstrm->in_boundry - (intptr_t)rstrm->in_finger;
542                if (current == 0) {
543                        if (! fill_input_buf(rstrm))
544                                return (FALSE);
545                        continue;
546                }
547                current = (len < current) ? len : current;
548                memcpy(addr, rstrm->in_finger, current);
549                rstrm->in_finger += current;
550                addr += current;
551                len -= current;
552        }
553        return (TRUE);
554}
555
556static bool_t  /* next two bytes of the input stream are treated as a header */
557set_input_fragment(
558        RECSTREAM *rstrm)
559{
560        u_int32_t header;
561
562        if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header)))
563                return (FALSE);
564        header = (long)ntohl(header);
565        rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
566        /*
567         * Sanity check. Try not to accept wildly incorrect
568         * record sizes. Unfortunately, the only record size
569         * we can positively identify as being 'wildly incorrect'
570         * is zero. Ridiculously large record sizes may look wrong,
571         * but we don't have any way to be certain that they aren't
572         * what the client actually intended to send us.
573         */
574        if (header == 0)
575                return(FALSE);
576        rstrm->fbtbc = header & (~LAST_FRAG);
577        return (TRUE);
578}
579
580static bool_t  /* consumes input bytes; knows nothing about records! */
581skip_input_bytes(
582        RECSTREAM *rstrm,
583        long cnt)
584{
585        long current;
586
587        while (cnt > 0) {
588                current = (intptr_t)rstrm->in_boundry - (intptr_t)rstrm->in_finger;
589                if (current == 0) {
590                        if (! fill_input_buf(rstrm))
591                                return (FALSE);
592                        continue;
593                }
594                current = (cnt < current) ? cnt : current;
595                rstrm->in_finger += current;
596                cnt -= current;
597        }
598        return (TRUE);
599}
600
601static u_int
602fix_buf_size(
603        u_int s)
604{
605
606        if (s < 100)
607                s = 4000;
608        return (RNDUP(s));
609}
Note: See TracBrowser for help on using the repository browser.