source: rtems/cpukit/librpc/src/xdr/xdr_rec.c @ 7d7d5e8e

4.104.114.9
Last change on this file since 7d7d5e8e was 7d7d5e8e, checked in by Ralf Corsepius <ralf.corsepius@…>, on Aug 1, 2008 at 7:28:48 AM

Remove register vars.

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