|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.