OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems/] [c/] [src/] [librpc/] [src/] [xdr/] [xdr_rec.c] - Blame information for rev 1771

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.