Main Page   Class Hierarchy   Alphabetical List   Data Structures   File List   Data Fields   Globals  

xdr_rec.c

Go to the documentation of this file.
00001 /*********************************************************************
00002  * RPC for the Windows NT Operating System
00003  * 1993 by Martin F. Gergeleit
00004  * Users may use, copy or modify Sun RPC for the Windows NT Operating
00005  * System according to the Sun copyright below.
00006  *
00007  * RPC for the Windows NT Operating System COMES WITH ABSOLUTELY NO
00008  * WARRANTY, NOR WILL I BE LIABLE FOR ANY DAMAGES INCURRED FROM THE
00009  * USE OF. USE ENTIRELY AT YOUR OWN RISK!!!
00010  *********************************************************************/
00011 
00012 /* @(#)xdr_rec.c        2.2 88/08/01 4.0 RPCSRC */
00013 /*
00014  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
00015  * unrestricted use provided that this legend is included on all tape
00016  * media and as a part of the software program in whole or part.  Users
00017  * may copy or modify Sun RPC without charge, but are not authorized
00018  * to license or distribute it to anyone else except as part of a product or
00019  * program developed by the user.
00020  *
00021  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
00022  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
00023  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
00024  *
00025  * Sun RPC is provided with no support and without any obligation on the
00026  * part of Sun Microsystems, Inc. to assist in its use, correction,
00027  * modification or enhancement.
00028  *
00029  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
00030  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
00031  * OR ANY PART THEREOF.
00032  *
00033  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
00034  * or profits or other special, indirect and consequential damages, even if
00035  * Sun has been advised of the possibility of such damages.
00036  *
00037  * Sun Microsystems, Inc.
00038  * 2550 Garcia Avenue
00039  * Mountain View, California  94043
00040  */
00041 #if !defined(lint) && defined(SCCSIDS)
00042 static char sccsid[] = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";
00043 #endif
00044 
00045 /*
00046  * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
00047  * layer above tcp (for rpc's use).
00048  *
00049  * Copyright (C) 1984, Sun Microsystems, Inc.
00050  *
00051  * These routines interface XDRSTREAMS to a tcp/ip connection.
00052  * There is a record marking layer between the xdr stream
00053  * and the tcp transport level.  A record is composed on one or more
00054  * record fragments.  A record fragment is a thirty-two bit header followed
00055  * by n bytes of data, where n is contained in the header.  The header
00056  * is represented as a htonl(u_long).  Thegh order bit encodes
00057  * whether or not the fragment is the last fragment of the record
00058  * (1 => fragment is last, 0 => more fragments to follow.
00059  * The other 31 bits encode the byte length of the fragment.
00060  */
00061 
00062 #if !defined(UNDER_CE) && !defined(WINDOWS_CE)
00063 #include <stdio.h>
00064 #endif
00065 
00066 #include "xdr.h"
00067 
00068 #ifdef WIN32
00069 #include <io.h>
00070 #else
00071 #include <netinet/in.h>
00072 
00073 extern long     lseek();
00074 #endif
00075 
00076 static u_int    fix_buf_size();
00077 
00078 static bool_t   xdrrec_getlong();
00079 static bool_t   xdrrec_putlong();
00080 static bool_t   xdrrec_getbytes();
00081 static bool_t   xdrrec_putbytes();
00082 static u_int    xdrrec_getpos();
00083 static bool_t   xdrrec_setpos();
00084 static long *   xdrrec_inline();
00085 static void     xdrrec_destroy();
00086 
00087 static struct  xdr_ops xdrrec_ops = {
00088         xdrrec_getlong,
00089         xdrrec_putlong,
00090         xdrrec_getbytes,
00091         xdrrec_putbytes,
00092         xdrrec_getpos,
00093         xdrrec_setpos,
00094         xdrrec_inline,
00095         xdrrec_destroy
00096 };
00097 
00098 /*
00099  * A record is composed of one or more record fragments.
00100  * A record fragment is a two-byte header followed by zero to
00101  * 2**32-1 bytes.  The header is treated as a long unsigned and is
00102  * encode/decoded to the network via htonl/ntohl.  The low order 31 bits
00103  * are a byte count of the fragment.  The highest order bit is a boolean:
00104  * 1 => this fragment is the last fragment of the record,
00105  * 0 => this fragment is followed by more fragment(s).
00106  *
00107  * The fragment/record machinery is not general;  it is constructed to
00108  * meet the needs of xdr and rpc based on tcp.
00109  */
00110 
00111 #define LAST_FRAG ((u_long)(1 << 31))
00112 
00113 typedef struct rec_strm {
00114         caddr_t tcp_handle;
00115         caddr_t the_buffer;
00116         /*
00117          * out-goung bits
00118          */
00119         int (*writeit)();
00120         caddr_t out_base;       /* output buffer (points to frag header) */
00121         caddr_t out_finger;     /* next output position */
00122         caddr_t out_boundry;    /* data cannot up to this address */
00123         u_long *frag_header;    /* beginning of curren fragment */
00124         bool_t frag_sent;       /* true if buffer sent in middle of record */
00125         /*
00126          * in-coming bits
00127          */
00128         int (*readit)();
00129         u_long in_size; /* fixed size of the input buffer */
00130         caddr_t in_base;
00131         caddr_t in_finger;      /* location of next byte to be had */
00132         caddr_t in_boundry;     /* can read up to this location */
00133         long fbtbc;             /* fragment bytes to be consumed */
00134         bool_t last_frag;
00135         u_int sendsize;
00136         u_int recvsize;
00137 } RECSTREAM;
00138 
00139 
00140 /*
00141  * Create an xdr handle for xdrrec
00142  * xdrrec_create fills in xdrs.  Sendsize and recvsize are
00143  * send and recv buffer sizes (0 => use default).
00144  * tcp_handle is an opaque handle that is passed as the first parameter to
00145  * the procedures readit and writeit.  Readit and writeit are read and
00146  * write respectively.   They are like the system
00147  * calls expect that they take an opaque handle rather than an fd.
00148  */
00149 void
00150 xdrrec_create(xdrs, sendsize, recvsize, tcp_handle, readit, writeit)
00151         register XDR *xdrs;
00152         register u_int sendsize;
00153         register u_int recvsize;
00154         caddr_t tcp_handle;
00155         int (*readit)();  /* like read, but pass it a tcp_handle, not sock */
00156         int (*writeit)();  /* like write, but pass it a tcp_handle, not sock */
00157 {
00158         register RECSTREAM *rstrm =
00159                 (RECSTREAM *)mem_alloc(sizeof(RECSTREAM));
00160 
00161         if (rstrm == NULL) {
00162 #if !defined(UNDER_CE) && !defined(WINDOWS_CE)
00163 #ifdef WIN32
00164                 nt_rpc_report("xdrrec_create: out of memory\n");
00165 #else
00166                 (void)fprintf(stderr, "xdrrec_create: out of memory\n");
00167 #endif
00168 #endif
00169                 /*
00170                  *  This is bad.  Should rework xdrrec_create to
00171                  *  return a handle, and in this case return NULL
00172                  */
00173                 return;
00174         }
00175         /*
00176          * adjust sizes and allocate buffer quad byte aligned
00177          */
00178         rstrm->sendsize = sendsize = fix_buf_size(sendsize);
00179         rstrm->recvsize = recvsize = fix_buf_size(recvsize);
00180         rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT);
00181         if (rstrm->the_buffer == NULL) {
00182 #if !defined(UNDER_CE) && !defined(WINDOWS_CE)
00183 #ifdef WIN32
00184                 nt_rpc_report("xdrrec_create: out of memory\n");
00185 #else
00186                 (void)fprintf(stderr, "xdrrec_create: out of memory\n");
00187 #endif
00188 #endif
00189                 return;
00190         }
00191         for (rstrm->out_base = rstrm->the_buffer;
00192                 (u_int)rstrm->out_base % BYTES_PER_XDR_UNIT != 0;
00193                 rstrm->out_base++);
00194         rstrm->in_base = rstrm->out_base + sendsize;
00195         /*
00196          * now the rest ...
00197          */
00198         xdrs->x_ops = &xdrrec_ops;
00199         xdrs->x_private = (caddr_t)rstrm;
00200         rstrm->tcp_handle = tcp_handle;
00201         rstrm->readit = readit;
00202         rstrm->writeit = writeit;
00203         rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
00204         rstrm->frag_header = (u_long *)rstrm->out_base;
00205         rstrm->out_finger += sizeof(u_long);
00206         rstrm->out_boundry += sendsize;
00207         rstrm->frag_sent = FALSE;
00208         rstrm->in_size = recvsize;
00209         rstrm->in_boundry = rstrm->in_base;
00210         rstrm->in_finger = (rstrm->in_boundry += recvsize);
00211         rstrm->fbtbc = 0;
00212         rstrm->last_frag = TRUE;
00213 }
00214 
00215 
00216 /*
00217  * The reoutines defined below are the xdr ops which will go into the
00218  * xdr handle filled in by xdrrec_create.
00219  */
00220 
00221 static bool_t
00222 xdrrec_getlong(xdrs, lp)
00223         XDR *xdrs;
00224         long *lp;
00225 {
00226         register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
00227         register long *buflp = (long *)(rstrm->in_finger);
00228         long mylong;
00229 
00230         /* first try the inline, fast case */
00231         if ((rstrm->fbtbc >= sizeof(long)) &&
00232                 (((int)rstrm->in_boundry - (int)buflp) >= sizeof(long))) {
00233                 *lp = (long)ntohl((u_long)(*buflp));
00234                 rstrm->fbtbc -= sizeof(long);
00235                 rstrm->in_finger += sizeof(long);
00236         } else {
00237                 if (! xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof(long)))
00238                         return (FALSE);
00239                 *lp = (long)ntohl((u_long)mylong);
00240         }
00241         return (TRUE);
00242 }
00243 
00244 static bool_t
00245 xdrrec_putlong(xdrs, lp)
00246         XDR *xdrs;
00247         long *lp;
00248 {
00249         register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
00250         register long *dest_lp = ((long *)(rstrm->out_finger));
00251 
00252         if ((rstrm->out_finger += sizeof(long)) > rstrm->out_boundry) {
00253                 /*
00254                  * this case should almost never happen so the code is
00255                  * inefficient
00256                  */
00257                 rstrm->out_finger -= sizeof(long);
00258                 rstrm->frag_sent = TRUE;
00259                 if (! flush_out(rstrm, FALSE))
00260                         return (FALSE);
00261                 dest_lp = ((long *)(rstrm->out_finger));
00262                 rstrm->out_finger += sizeof(long);
00263         }
00264         *dest_lp = (long)htonl((u_long)(*lp));
00265         return (TRUE);
00266 }
00267 
00268 static bool_t  /* must manage buffers, fragments, and records */
00269 xdrrec_getbytes(xdrs, addr, len)
00270         XDR *xdrs;
00271         register caddr_t addr;
00272         register u_int len;
00273 {
00274         register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
00275         register int current;
00276 
00277         while (len > 0) {
00278                 current = rstrm->fbtbc;
00279                 if (current == 0) {
00280                         if (rstrm->last_frag)
00281                                 return (FALSE);
00282                         if (! set_input_fragment(rstrm))
00283                                 return (FALSE);
00284                         continue;
00285                 }
00286                 current = (len < current) ? len : current;
00287                 if (! get_input_bytes(rstrm, addr, current))
00288                         return (FALSE);
00289                 addr += current;
00290                 rstrm->fbtbc -= current;
00291                 len -= current;
00292         }
00293         return (TRUE);
00294 }
00295 
00296 static bool_t
00297 xdrrec_putbytes(xdrs, addr, len)
00298         XDR *xdrs;
00299         register caddr_t addr;
00300         register u_int len;
00301 {
00302         register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
00303         register int current;
00304 
00305         while (len > 0) {
00306                 current = (u_int)rstrm->out_boundry - (u_int)rstrm->out_finger;
00307                 current = (len < current) ? len : current;
00308                 bcopy(addr, rstrm->out_finger, current);
00309                 rstrm->out_finger += current;
00310                 addr += current;
00311                 len -= current;
00312                 if (rstrm->out_finger == rstrm->out_boundry) {
00313                         rstrm->frag_sent = TRUE;
00314                         if (! flush_out(rstrm, FALSE))
00315                                 return (FALSE);
00316                 }
00317         }
00318         return (TRUE);
00319 }
00320 
00321 static u_int
00322 xdrrec_getpos(xdrs)
00323         register XDR *xdrs;
00324 {
00325         register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
00326         register long pos;
00327 
00328         pos = lseek((int)rstrm->tcp_handle, (long) 0, 1);
00329         if (pos != -1)
00330                 switch (xdrs->x_op) {
00331 
00332                 case XDR_ENCODE:
00333                         pos += rstrm->out_finger - rstrm->out_base;
00334                         break;
00335 
00336                 case XDR_DECODE:
00337                         pos -= rstrm->in_boundry - rstrm->in_finger;
00338                         break;
00339 
00340                 default:
00341                         pos = (u_int) -1;
00342                         break;
00343                 }
00344         return ((u_int) pos);
00345 }
00346 
00347 static bool_t
00348 xdrrec_setpos(xdrs, pos)
00349         register XDR *xdrs;
00350         u_int pos;
00351 {
00352         register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
00353         u_int currpos = xdrrec_getpos(xdrs);
00354         int delta = currpos - pos;
00355         caddr_t newpos;
00356 
00357         if ((int)currpos != -1)
00358                 switch (xdrs->x_op) {
00359 
00360                 case XDR_ENCODE:
00361                         newpos = rstrm->out_finger - delta;
00362                         if ((newpos > (caddr_t)(rstrm->frag_header)) &&
00363                                 (newpos < rstrm->out_boundry)) {
00364                                 rstrm->out_finger = newpos;
00365                                 return (TRUE);
00366                         }
00367                         break;
00368 
00369                 case XDR_DECODE:
00370                         newpos = rstrm->in_finger - delta;
00371                         if ((delta < (int)(rstrm->fbtbc)) &&
00372                                 (newpos <= rstrm->in_boundry) &&
00373                                 (newpos >= rstrm->in_base)) {
00374                                 rstrm->in_finger = newpos;
00375                                 rstrm->fbtbc -= delta;
00376                                 return (TRUE);
00377                         }
00378                         break;
00379                 }
00380         return (FALSE);
00381 }
00382 
00383 static long *
00384 xdrrec_inline(xdrs, len)
00385         register XDR *xdrs;
00386         int len;
00387 {
00388         register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
00389         long * buf = NULL;
00390 
00391         switch (xdrs->x_op) {
00392 
00393         case XDR_ENCODE:
00394                 if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
00395                         buf = (long *) rstrm->out_finger;
00396                         rstrm->out_finger += len;
00397                 }
00398                 break;
00399 
00400         case XDR_DECODE:
00401                 if ((len <= rstrm->fbtbc) &&
00402                         ((rstrm->in_finger + len) <= rstrm->in_boundry)) {
00403                         buf = (long *) rstrm->in_finger;
00404                         rstrm->fbtbc -= len;
00405                         rstrm->in_finger += len;
00406                 }
00407                 break;
00408         }
00409         return (buf);
00410 }
00411 
00412 static void
00413 xdrrec_destroy(xdrs)
00414         register XDR *xdrs;
00415 {
00416         register RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
00417 
00418         mem_free(rstrm->the_buffer,
00419                 rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
00420         mem_free((caddr_t)rstrm, sizeof(RECSTREAM));
00421 }
00422 
00423 
00424 /*
00425  * Exported routines to manage xdr records
00426  */
00427 
00428 /*
00429  * Before reading (deserializing from the stream, one should always call
00430  * this procedure to guarantee proper record alignment.
00431  */
00432 bool_t
00433 xdrrec_skiprecord(xdrs)
00434         XDR *xdrs;
00435 {
00436         register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
00437 
00438         while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
00439                 if (! skip_input_bytes(rstrm, rstrm->fbtbc))
00440                         return (FALSE);
00441                 rstrm->fbtbc = 0;
00442                 if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
00443                         return (FALSE);
00444         }
00445         rstrm->last_frag = FALSE;
00446         return (TRUE);
00447 }
00448 
00449 /*
00450  * Look ahead fuction.
00451  * Returns TRUE iff there is no more input in the buffer
00452  * after consuming the rest of the current record.
00453  */
00454 bool_t
00455 xdrrec_eof(xdrs)
00456         XDR *xdrs;
00457 {
00458         register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
00459 
00460         while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
00461                 if (! skip_input_bytes(rstrm, rstrm->fbtbc))
00462                         return (TRUE);
00463                 rstrm->fbtbc = 0;
00464                 if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
00465                         return (TRUE);
00466         }
00467         if (rstrm->in_finger == rstrm->in_boundry)
00468                 return (TRUE);
00469         return (FALSE);
00470 }
00471 
00472 /*
00473  * The client must tell the package when an end-of-record has occurred.
00474  * The second paraemters tells whether the record should be flushed to the
00475  * (output) tcp stream.  (This let's the package support batched or
00476  * pipelined procedure calls.)  TRUE => immmediate flush to tcp connection.
00477  */
00478 bool_t
00479 xdrrec_endofrecord(xdrs, sendnow)
00480         XDR *xdrs;
00481         bool_t sendnow;
00482 {
00483         register RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
00484         register u_long len;  /* fragment length */
00485 
00486         if (sendnow || rstrm->frag_sent ||
00487                 ((u_long)rstrm->out_finger + sizeof(u_long) >=
00488                 (u_long)rstrm->out_boundry)) {
00489                 rstrm->frag_sent = FALSE;
00490                 return (flush_out(rstrm, TRUE));
00491         }
00492         len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) -
00493            sizeof(u_long);
00494         *(rstrm->frag_header) = htonl((u_long)len | LAST_FRAG);
00495         rstrm->frag_header = (u_long *)rstrm->out_finger;
00496         rstrm->out_finger += sizeof(u_long);
00497         return (TRUE);
00498 }
00499 
00500 
00501 /*
00502  * Internal useful routines
00503  */
00504 static bool_t
00505 flush_out(rstrm, eor)
00506         register RECSTREAM *rstrm;
00507         bool_t eor;
00508 {
00509         register u_long eormask = (eor == TRUE) ? LAST_FRAG : 0;
00510         register u_long len = (u_long)(rstrm->out_finger) -
00511                 (u_long)(rstrm->frag_header) - sizeof(u_long);
00512 
00513         *(rstrm->frag_header) = htonl(len | eormask);
00514         len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->out_base);
00515         if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
00516                 != (int)len)
00517                 return (FALSE);
00518         rstrm->frag_header = (u_long *)rstrm->out_base;
00519         rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof(u_long);
00520         return (TRUE);
00521 }
00522 
00523 static bool_t  /* knows nothing about records!  Only about input buffers */
00524 fill_input_buf(rstrm)
00525         register RECSTREAM *rstrm;
00526 {
00527         register caddr_t where;
00528         u_int i;
00529         register int len;
00530 
00531         where = rstrm->in_base;
00532         i = (u_int)rstrm->in_boundry % BYTES_PER_XDR_UNIT;
00533         where += i;
00534         len = rstrm->in_size - i;
00535         if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
00536                 return (FALSE);
00537         rstrm->in_finger = where;
00538         where += len;
00539         rstrm->in_boundry = where;
00540         return (TRUE);
00541 }
00542 
00543 static bool_t  /* knows nothing about records!  Only about input buffers */
00544 get_input_bytes(rstrm, addr, len)
00545         register RECSTREAM *rstrm;
00546         register caddr_t addr;
00547         register int len;
00548 {
00549         register int current;
00550 
00551         while (len > 0) {
00552                 current = (int)rstrm->in_boundry - (int)rstrm->in_finger;
00553                 if (current == 0) {
00554                         if (! fill_input_buf(rstrm))
00555                                 return (FALSE);
00556                         continue;
00557                 }
00558                 current = (len < current) ? len : current;
00559                 bcopy(rstrm->in_finger, addr, current);
00560                 rstrm->in_finger += current;
00561                 addr += current;
00562                 len -= current;
00563         }
00564         return (TRUE);
00565 }
00566 
00567 static bool_t  /* next two bytes of the input stream are treated as a header */
00568 set_input_fragment(rstrm)
00569         register RECSTREAM *rstrm;
00570 {
00571         u_long header;
00572 
00573         if (! get_input_bytes(rstrm, (caddr_t)&header, sizeof(header)))
00574                 return (FALSE);
00575         header = (long)ntohl(header);
00576         rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
00577         rstrm->fbtbc = header & (~LAST_FRAG);
00578         return (TRUE);
00579 }
00580 
00581 static bool_t  /* consumes input bytes; knows nothing about records! */
00582 skip_input_bytes(rstrm, cnt)
00583         register RECSTREAM *rstrm;
00584         long cnt;
00585 {
00586         register int current;
00587 
00588         while (cnt > 0) {
00589                 current = (int)rstrm->in_boundry - (int)rstrm->in_finger;
00590                 if (current == 0) {
00591                         if (! fill_input_buf(rstrm))
00592                                 return (FALSE);
00593                         continue;
00594                 }
00595                 current = (cnt < current) ? cnt : current;
00596                 rstrm->in_finger += current;
00597                 cnt -= current;
00598         }
00599         return (TRUE);
00600 }
00601 
00602 static u_int
00603 fix_buf_size(s)
00604         register u_int s;
00605 {
00606 
00607         if (s < 100)
00608                 s = 4000;
00609         return (RNDUP(s));
00610 }

Generated on Sun Dec 2 15:56:54 2001 for rcslib by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001