(_ISwbit): Protext use of parameter with parentheses.
[glibc.git] / sunrpc / xdr_rec.c
blob30be6393a29352c0069d09d1859e27c01e16255c
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.
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.
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.
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.
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.
26 * Sun Microsystems, Inc.
27 * 2550 Garcia Avenue
28 * Mountain View, California 94043
30 #if !defined(lint) && defined(SCCSIDS)
31 static char sccsid[] = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";
32 #endif
35 * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
36 * layer above tcp (for rpc's use).
38 * Copyright (C) 1984, Sun Microsystems, Inc.
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). The high 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.
51 #include <stdio.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <rpc/rpc.h>
56 #ifdef USE_IN_LIBIO
57 # include <libio/iolibio.h>
58 # define fputs(s, f) _IO_fputs (s, f)
59 #endif
61 static bool_t xdrrec_getlong (XDR *, long *);
62 static bool_t xdrrec_putlong (XDR *, const long *);
63 static bool_t xdrrec_getbytes (XDR *, caddr_t, u_int);
64 static bool_t xdrrec_putbytes (XDR *, const char *, u_int);
65 static u_int xdrrec_getpos (const XDR *);
66 static bool_t xdrrec_setpos (XDR *, u_int);
67 static long *xdrrec_inline (XDR *, int);
68 static void xdrrec_destroy (XDR *);
70 static const struct xdr_ops xdrrec_ops =
72 xdrrec_getlong,
73 xdrrec_putlong,
74 xdrrec_getbytes,
75 xdrrec_putbytes,
76 xdrrec_getpos,
77 xdrrec_setpos,
78 xdrrec_inline,
79 xdrrec_destroy
83 * A record is composed of one or more record fragments.
84 * A record fragment is a two-byte header followed by zero to
85 * 2**32-1 bytes. The header is treated as a long unsigned and is
86 * encode/decoded to the network via htonl/ntohl. The low order 31 bits
87 * are a byte count of the fragment. The highest order bit is a boolean:
88 * 1 => this fragment is the last fragment of the record,
89 * 0 => this fragment is followed by more fragment(s).
91 * The fragment/record machinery is not general; it is constructed to
92 * meet the needs of xdr and rpc based on tcp.
95 #define LAST_FRAG (1UL << 31)
97 typedef struct rec_strm
99 caddr_t tcp_handle;
100 caddr_t the_buffer;
102 * out-going bits
104 int (*writeit) (char *, char *, int);
105 caddr_t out_base; /* output buffer (points to frag header) */
106 caddr_t out_finger; /* next output position */
107 caddr_t out_boundry; /* data cannot up to this address */
108 u_int32_t *frag_header; /* beginning of curren fragment */
109 bool_t frag_sent; /* true if buffer sent in middle of record */
111 * in-coming bits
113 int (*readit) (char *, char *, int);
114 u_long in_size; /* fixed size of the input buffer */
115 caddr_t in_base;
116 caddr_t in_finger; /* location of next byte to be had */
117 caddr_t in_boundry; /* can read up to this location */
118 long fbtbc; /* fragment bytes to be consumed */
119 bool_t last_frag;
120 u_int sendsize;
121 u_int recvsize;
123 RECSTREAM;
125 static u_int fix_buf_size (u_int) internal_function;
126 static bool_t skip_input_bytes (RECSTREAM *, long) internal_function;
127 static bool_t flush_out (RECSTREAM *, bool_t) internal_function;
128 static bool_t set_input_fragment (RECSTREAM *) internal_function;
129 static bool_t get_input_bytes (RECSTREAM *, caddr_t, int) internal_function;
132 * Create an xdr handle for xdrrec
133 * xdrrec_create fills in xdrs. Sendsize and recvsize are
134 * send and recv buffer sizes (0 => use default).
135 * tcp_handle is an opaque handle that is passed as the first parameter to
136 * the procedures readit and writeit. Readit and writeit are read and
137 * write respectively. They are like the system
138 * calls expect that they take an opaque handle rather than an fd.
140 void
141 xdrrec_create (XDR *xdrs, u_int sendsize,
142 u_int recvsize, caddr_t tcp_handle,
143 int (*readit) (char *, char *, int),
144 int (*writeit) (char *, char *, int))
146 RECSTREAM *rstrm = (RECSTREAM *) mem_alloc (sizeof (RECSTREAM));
147 caddr_t tmp;
149 if (rstrm == NULL)
151 (void) fputs (_("xdrrec_create: out of memory\n"), stderr);
153 * This is bad. Should rework xdrrec_create to
154 * return a handle, and in this case return NULL
156 return;
159 * adjust sizes and allocate buffer quad byte aligned
161 rstrm->sendsize = sendsize = fix_buf_size (sendsize);
162 rstrm->recvsize = recvsize = fix_buf_size (recvsize);
163 rstrm->the_buffer = mem_alloc (sendsize + recvsize + BYTES_PER_XDR_UNIT);
164 if (rstrm->the_buffer == NULL)
166 (void) fputs (_("xdrrec_create: out of memory\n"), stderr);
167 return;
169 tmp = rstrm->the_buffer;
170 if ((size_t)tmp % BYTES_PER_XDR_UNIT)
171 tmp += BYTES_PER_XDR_UNIT - (size_t)tmp % BYTES_PER_XDR_UNIT;
172 rstrm->out_base = tmp;
173 rstrm->in_base = tmp + sendsize;
175 * now the rest ...
177 /* We have to add the const since the `struct xdr_ops' in `struct XDR'
178 is not `const'. */
179 xdrs->x_ops = (struct xdr_ops *) &xdrrec_ops;
180 xdrs->x_private = (caddr_t) rstrm;
181 rstrm->tcp_handle = tcp_handle;
182 rstrm->readit = readit;
183 rstrm->writeit = writeit;
184 rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
185 rstrm->frag_header = (u_int32_t *) rstrm->out_base;
186 rstrm->out_finger += 4;
187 rstrm->out_boundry += sendsize;
188 rstrm->frag_sent = FALSE;
189 rstrm->in_size = recvsize;
190 rstrm->in_boundry = rstrm->in_base;
191 rstrm->in_finger = (rstrm->in_boundry += recvsize);
192 rstrm->fbtbc = 0;
193 rstrm->last_frag = TRUE;
198 * The routines defined below are the xdr ops which will go into the
199 * xdr handle filled in by xdrrec_create.
202 static bool_t
203 xdrrec_getlong (xdrs, lp)
204 XDR *xdrs;
205 long *lp;
207 RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
208 int32_t *buflp = (int32_t *) rstrm->in_finger;
209 int32_t mylong;
211 /* first try the inline, fast case */
212 if (rstrm->fbtbc >= BYTES_PER_XDR_UNIT &&
213 rstrm->in_boundry - (char *) buflp >= BYTES_PER_XDR_UNIT)
215 *lp = (int32_t) ntohl (*buflp);
216 rstrm->fbtbc -= BYTES_PER_XDR_UNIT;
217 rstrm->in_finger += BYTES_PER_XDR_UNIT;
219 else
221 if (!xdrrec_getbytes (xdrs, (caddr_t) & mylong,
222 BYTES_PER_XDR_UNIT))
223 return FALSE;
224 *lp = (int32_t) ntohl (mylong);
226 return TRUE;
229 static bool_t
230 xdrrec_putlong (xdrs, lp)
231 XDR *xdrs;
232 const long *lp;
234 RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
235 int32_t *dest_lp = (int32_t *) rstrm->out_finger;
237 if ((rstrm->out_finger += BYTES_PER_XDR_UNIT) > rstrm->out_boundry)
240 * this case should almost never happen so the code is
241 * inefficient
243 rstrm->out_finger -= BYTES_PER_XDR_UNIT;
244 rstrm->frag_sent = TRUE;
245 if (!flush_out (rstrm, FALSE))
246 return FALSE;
247 dest_lp = (int32_t *) rstrm->out_finger;
248 rstrm->out_finger += BYTES_PER_XDR_UNIT;
250 *dest_lp = htonl (*lp);
251 return TRUE;
254 static bool_t /* must manage buffers, fragments, and records */
255 xdrrec_getbytes (xdrs, addr, len)
256 XDR *xdrs;
257 caddr_t addr;
258 u_int len;
260 RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
261 u_int current;
263 while (len > 0)
265 current = rstrm->fbtbc;
266 if (current == 0)
268 if (rstrm->last_frag)
269 return FALSE;
270 if (!set_input_fragment (rstrm))
271 return FALSE;
272 continue;
274 current = (len < current) ? len : current;
275 if (!get_input_bytes (rstrm, addr, current))
276 return FALSE;
277 addr += current;
278 rstrm->fbtbc -= current;
279 len -= current;
281 return TRUE;
284 static bool_t
285 xdrrec_putbytes (xdrs, addr, len)
286 XDR *xdrs;
287 const char *addr;
288 u_int len;
290 RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
291 u_int current;
293 while (len > 0)
295 current = rstrm->out_boundry - rstrm->out_finger;
296 current = (len < current) ? len : current;
297 bcopy (addr, rstrm->out_finger, current);
298 rstrm->out_finger += current;
299 addr += current;
300 len -= current;
301 if (rstrm->out_finger == rstrm->out_boundry)
303 rstrm->frag_sent = TRUE;
304 if (!flush_out (rstrm, FALSE))
305 return FALSE;
308 return TRUE;
311 static u_int
312 xdrrec_getpos (const XDR *xdrs)
314 RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
315 long pos;
317 pos = __lseek ((int) rstrm->tcp_handle, (long) 0, 1);
318 if (pos != -1)
319 switch (xdrs->x_op)
322 case XDR_ENCODE:
323 pos += rstrm->out_finger - rstrm->out_base;
324 break;
326 case XDR_DECODE:
327 pos -= rstrm->in_boundry - rstrm->in_finger;
328 break;
330 default:
331 pos = (u_int) - 1;
332 break;
334 return (u_int) pos;
337 static bool_t
338 xdrrec_setpos (xdrs, pos)
339 XDR *xdrs;
340 u_int pos;
342 RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
343 u_int currpos = xdrrec_getpos (xdrs);
344 int delta = currpos - pos;
345 caddr_t newpos;
347 if ((int) currpos != -1)
348 switch (xdrs->x_op)
351 case XDR_ENCODE:
352 newpos = rstrm->out_finger - delta;
353 if (newpos > (caddr_t) rstrm->frag_header &&
354 newpos < rstrm->out_boundry)
356 rstrm->out_finger = newpos;
357 return TRUE;
359 break;
361 case XDR_DECODE:
362 newpos = rstrm->in_finger - delta;
363 if ((delta < (int) (rstrm->fbtbc)) &&
364 (newpos <= rstrm->in_boundry) &&
365 (newpos >= rstrm->in_base))
367 rstrm->in_finger = newpos;
368 rstrm->fbtbc -= delta;
369 return TRUE;
371 break;
373 default:
374 break;
376 return FALSE;
379 static long *
380 xdrrec_inline (XDR *xdrs, int len)
382 RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
383 long *buf = NULL;
385 switch (xdrs->x_op)
388 case XDR_ENCODE:
389 if ((rstrm->out_finger + len) <= rstrm->out_boundry)
391 buf = (long *) rstrm->out_finger;
392 rstrm->out_finger += len;
394 break;
396 case XDR_DECODE:
397 if ((len <= rstrm->fbtbc) &&
398 ((rstrm->in_finger + len) <= rstrm->in_boundry))
400 buf = (long *) rstrm->in_finger;
401 rstrm->fbtbc -= len;
402 rstrm->in_finger += len;
404 break;
406 default:
407 break;
409 return buf;
412 static void
413 xdrrec_destroy (xdrs)
414 XDR *xdrs;
416 RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
418 mem_free (rstrm->the_buffer,
419 rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
420 mem_free ((caddr_t) rstrm, sizeof (RECSTREAM));
425 * Exported routines to manage xdr records
429 * Before reading (deserializing from the stream, one should always call
430 * this procedure to guarantee proper record alignment.
432 bool_t
433 xdrrec_skiprecord (xdrs)
434 XDR *xdrs;
436 RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
438 while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
440 if (!skip_input_bytes (rstrm, rstrm->fbtbc))
441 return FALSE;
442 rstrm->fbtbc = 0;
443 if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
444 return FALSE;
446 rstrm->last_frag = FALSE;
447 return TRUE;
451 * Lookahead function.
452 * Returns TRUE iff there is no more input in the buffer
453 * after consuming the rest of the current record.
455 bool_t
456 xdrrec_eof (xdrs)
457 XDR *xdrs;
459 RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
461 while (rstrm->fbtbc > 0 || (!rstrm->last_frag))
463 if (!skip_input_bytes (rstrm, rstrm->fbtbc))
464 return TRUE;
465 rstrm->fbtbc = 0;
466 if ((!rstrm->last_frag) && (!set_input_fragment (rstrm)))
467 return TRUE;
469 if (rstrm->in_finger == rstrm->in_boundry)
470 return TRUE;
471 return FALSE;
475 * The client must tell the package when an end-of-record has occurred.
476 * The second parameter tells whether the record should be flushed to the
477 * (output) tcp stream. (This lets the package support batched or
478 * pipelined procedure calls.) TRUE => immediate flush to tcp connection.
480 bool_t
481 xdrrec_endofrecord (xdrs, sendnow)
482 XDR *xdrs;
483 bool_t sendnow;
485 RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private;
486 u_long len; /* fragment length */
488 if (sendnow || rstrm->frag_sent
489 || rstrm->out_finger + BYTES_PER_XDR_UNIT >= rstrm->out_boundry)
491 rstrm->frag_sent = FALSE;
492 return flush_out (rstrm, TRUE);
494 len = (rstrm->out_finger - (char *) rstrm->frag_header
495 - BYTES_PER_XDR_UNIT);
496 *rstrm->frag_header = htonl ((u_long) len | LAST_FRAG);
497 rstrm->frag_header = (u_int32_t *) rstrm->out_finger;
498 rstrm->out_finger += BYTES_PER_XDR_UNIT;
499 return TRUE;
504 * Internal useful routines
506 static bool_t
507 internal_function
508 flush_out (RECSTREAM *rstrm, bool_t eor)
510 u_long eormask = (eor == TRUE) ? LAST_FRAG : 0;
511 u_long len = (rstrm->out_finger - (char *) rstrm->frag_header
512 - BYTES_PER_XDR_UNIT);
514 *rstrm->frag_header = htonl (len | eormask);
515 len = rstrm->out_finger - rstrm->out_base;
516 if ((*(rstrm->writeit)) (rstrm->tcp_handle, rstrm->out_base, (int) len)
517 != (int) len)
518 return FALSE;
519 rstrm->frag_header = (u_int32_t *) rstrm->out_base;
520 rstrm->out_finger = (caddr_t) rstrm->out_base + BYTES_PER_XDR_UNIT;
521 return TRUE;
524 static bool_t /* knows nothing about records! Only about input buffers */
525 fill_input_buf (RECSTREAM *rstrm)
527 caddr_t where;
528 size_t i;
529 int len;
531 where = rstrm->in_base;
532 i = (size_t) rstrm->in_boundry % BYTES_PER_XDR_UNIT;
533 where += i;
534 len = rstrm->in_size - i;
535 if ((len = (*(rstrm->readit)) (rstrm->tcp_handle, where, len)) == -1)
536 return FALSE;
537 rstrm->in_finger = where;
538 where += len;
539 rstrm->in_boundry = where;
540 return TRUE;
543 static bool_t /* knows nothing about records! Only about input buffers */
544 internal_function
545 get_input_bytes (RECSTREAM *rstrm, caddr_t addr, int len)
547 int current;
549 while (len > 0)
551 current = rstrm->in_boundry - rstrm->in_finger;
552 if (current == 0)
554 if (!fill_input_buf (rstrm))
555 return FALSE;
556 continue;
558 current = (len < current) ? len : current;
559 bcopy (rstrm->in_finger, addr, current);
560 rstrm->in_finger += current;
561 addr += current;
562 len -= current;
564 return TRUE;
567 static bool_t /* next two bytes of the input stream are treated as a header */
568 internal_function
569 set_input_fragment (RECSTREAM *rstrm)
571 u_long header;
573 if (! get_input_bytes (rstrm, (caddr_t)&header, BYTES_PER_XDR_UNIT))
574 return FALSE;
575 header = ntohl (header);
576 rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
578 * Sanity check. Try not to accept wildly incorrect
579 * record sizes. Unfortunately, the only record size
580 * we can positively identify as being 'wildly incorrect'
581 * is zero. Ridiculously large record sizes may look wrong,
582 * but we don't have any way to be certain that they aren't
583 * what the client actually intended to send us.
585 if ((header & (~LAST_FRAG)) == 0)
586 return FALSE;
587 rstrm->fbtbc = header & ~LAST_FRAG;
588 return TRUE;
591 static bool_t /* consumes input bytes; knows nothing about records! */
592 internal_function
593 skip_input_bytes (RECSTREAM *rstrm, long cnt)
595 int current;
597 while (cnt > 0)
599 current = rstrm->in_boundry - rstrm->in_finger;
600 if (current == 0)
602 if (!fill_input_buf (rstrm))
603 return FALSE;
604 continue;
606 current = (cnt < current) ? cnt : current;
607 rstrm->in_finger += current;
608 cnt -= current;
610 return TRUE;
613 static u_int
614 internal_function
615 fix_buf_size (u_int s)
617 if (s < 100)
618 s = 4000;
619 return RNDUP (s);