Annotation of 43BSDReno/lib/librpc/xdr_rec.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.