|
|
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.