home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / lib / librpc / rpc / xdr_rec.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-24  |  15.1 KB  |  585 lines

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