1 /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
2 * unrestricted use provided that this legend is included on all tape
3 * media and as a part of the software program in whole or part. Users
4 * may copy or modify Sun RPC without charge, but are not authorized
5 * to license or distribute it to anyone else except as part of a product or
6 * program developed by the user.
8 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
9 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
10 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
12 * Sun RPC is provided with no support and without any obligation on the
13 * part of Sun Microsystems, Inc. to assist in its use, correction,
14 * modification or enhancement.
16 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
17 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
18 * OR ANY PART THEREOF.
20 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
21 * or profits or other special, indirect and consequential damages, even if
22 * Sun has been advised of the possibility of such damages.
24 * Sun Microsystems, Inc.
26 * Mountain View, California 94043
30 /* * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
31 * layer above tcp (for rpc's use).
33 * Copyright (C) 1984, Sun Microsystems, Inc.
35 * These routines interface XDRSTREAMS to a tcp/ip connection.
36 * There is a record marking layer between the xdr stream
37 * and the tcp transport level. A record is composed on one or more
38 * record fragments. A record fragment is a thirty-two bit header followed
39 * by n bytes of data, where n is contained in the header. The header
40 * is represented as a htonl(afs_uint32). Thegh order bit encodes
41 * whether or not the fragment is the last fragment of the record
42 * (1 => fragment is last, 0 => more fragments to follow.
43 * The other 31 bits encode the byte length of the fragment.
46 #include <afsconfig.h>
47 #include <afs/param.h>
52 /* * A record is composed of one or more record fragments.
53 * A record fragment is a two-byte header followed by zero to
54 * 2**32-1 bytes. The header is treated as an afs_int32 unsigned and is
55 * encode/decoded to the network via htonl/ntohl. The low order 31 bits
56 * are a byte count of the fragment. The highest order bit is a boolean:
57 * 1 => this fragment is the last fragment of the record,
58 * 0 => this fragment is followed by more fragment(s).
60 * The fragment/record machinery is not general; it is constructed to
61 * meet the needs of xdr and rpc based on tcp.
64 #define LAST_FRAG ((afs_uint32)(1u << 31))
66 typedef struct rec_strm
{
70 int (*writeit
) (caddr_t tcp_handle
, caddr_t out_base
, int len
);
71 caddr_t out_base
; /* output buffer (points to frag header) */
72 caddr_t out_finger
; /* next output position */
73 caddr_t out_boundry
; /* data cannot up to this address */
74 afs_uint32
*frag_header
; /* beginning of curren fragment */
75 bool_t frag_sent
; /* true if buffer sent in middle of record */
78 int (*readit
) (caddr_t tcp_handle
, caddr_t out_base
, int len
);
79 afs_uint32 in_size
; /* fixed size of the input buffer */
81 caddr_t in_finger
; /* location of next byte to be had */
82 caddr_t in_boundry
; /* can read up to this location */
83 afs_int32 fbtbc
; /* fragment bytes to be consumed */
89 /* Prototypes for static routines */
90 static bool_t
xdrrec_getint32(XDR
* xdrs
, afs_int32
* lp
);
91 static bool_t
xdrrec_putint32(XDR
* xdrs
, afs_int32
* lp
);
92 static bool_t
xdrrec_getbytes(XDR
* xdrs
, caddr_t addr
,
94 static bool_t
xdrrec_putbytes(XDR
* xdrs
, caddr_t addr
,
96 static u_int
xdrrec_getpos(XDR
* xdrs
);
97 static bool_t
xdrrec_setpos(XDR
* xdrs
, u_int pos
);
98 static afs_int32
*xdrrec_inline(XDR
* xdrs
, u_int len
);
99 static void xdrrec_destroy(XDR
* xdrs
);
100 static bool_t
flush_out(RECSTREAM
* rstrm
, bool_t eor
);
101 static bool_t
fill_input_buf(RECSTREAM
* rstrm
);
102 static bool_t
get_input_bytes(RECSTREAM
* rstrm
,
103 caddr_t addr
, int len
);
104 static bool_t
set_input_fragment(RECSTREAM
* rstrm
);
105 static bool_t
skip_input_bytes(RECSTREAM
* rstrm
, int cnt
);
106 static u_int
fix_buf_size(u_int s
);
108 static struct xdr_ops xdrrec_ops
= {
110 /* Windows does not support labeled assignments */
111 #if !(defined(KERNEL) && defined(AFS_SUN5_ENV))
112 xdrrec_getint32
, /* deserialize an afs_int32 */
113 xdrrec_putint32
, /* serialize an afs_int32 */
115 xdrrec_getbytes
, /* deserialize counted bytes */
116 xdrrec_putbytes
, /* serialize counted bytes */
117 xdrrec_getpos
, /* get offset in the stream: not supported. */
118 xdrrec_setpos
, /* set offset in the stream: not supported. */
119 xdrrec_inline
, /* prime stream for inline macros */
120 xdrrec_destroy
, /* destroy stream */
121 #if (defined(KERNEL) && defined(AFS_SUN5_ENV))
123 xdrrec_getint32
, /* deserialize an afs_int32 */
124 xdrrec_putint32
, /* serialize an afs_int32 */
127 .x_getint32
= xdrrec_getint32
,
128 .x_putint32
= xdrrec_putint32
,
129 .x_getbytes
= xdrrec_getbytes
,
130 .x_putbytes
= xdrrec_putbytes
,
131 .x_getpos
= xdrrec_getpos
,
132 .x_setpos
= xdrrec_setpos
,
133 .x_inline
= xdrrec_inline
,
134 .x_destroy
= xdrrec_destroy
138 /* * Create an xdr handle for xdrrec
139 * xdrrec_create fills in xdrs. Sendsize and recvsize are
140 * send and recv buffer sizes (0 => use default).
141 * tcp_handle is an opaque handle that is passed as the first parameter to
142 * the procedures readit and writeit. Readit and writeit are read and
143 * write respectively. They are like the system
144 * calls expect that they take an opaque handle rather than an fd.
147 int (*readit)(); * like read, but pass it a tcp_handle, not sock *
148 int (*writeit)(); * like write, but pass it a tcp_handle, not sock *
151 xdrrec_create(XDR
* xdrs
, u_int sendsize
, u_int recvsize
,
152 caddr_t tcp_handle
, int (*readit
) (caddr_t tcp_handle
,
153 caddr_t out_base
, int len
),
154 int (*writeit
) (caddr_t tcp_handle
, caddr_t out_base
, int len
))
156 RECSTREAM
*rstrm
= (RECSTREAM
*) osi_alloc(sizeof(RECSTREAM
));
160 * This is bad. Should rework xdrrec_create to
161 * return a handle, and in this case return NULL
165 xdrs
->x_ops
= &xdrrec_ops
;
166 xdrs
->x_private
= (caddr_t
) rstrm
;
167 rstrm
->tcp_handle
= tcp_handle
;
168 rstrm
->readit
= readit
;
169 rstrm
->writeit
= writeit
;
170 sendsize
= fix_buf_size(sendsize
);
171 if ((rstrm
->out_base
= rstrm
->out_finger
= rstrm
->out_boundry
=
172 osi_alloc(sendsize
)) == NULL
) {
175 rstrm
->frag_header
= (afs_uint32
*) rstrm
->out_base
;
176 rstrm
->out_finger
+= sizeof(afs_uint32
);
177 rstrm
->out_boundry
+= sendsize
;
178 rstrm
->frag_sent
= FALSE
;
179 rstrm
->in_size
= recvsize
= fix_buf_size(recvsize
);
180 if ((rstrm
->in_base
= rstrm
->in_boundry
= osi_alloc(recvsize
)) == NULL
) {
183 rstrm
->in_finger
= (rstrm
->in_boundry
+= recvsize
);
185 rstrm
->last_frag
= TRUE
;
186 rstrm
->sendsize
= sendsize
;
187 rstrm
->recvsize
= recvsize
;
191 /* * The reoutines defined below are the xdr ops which will go into the
192 * xdr handle filled in by xdrrec_create.
196 xdrrec_getint32(XDR
* xdrs
, afs_int32
* lp
)
198 RECSTREAM
*rstrm
= (RECSTREAM
*) (xdrs
->x_private
);
199 afs_int32
*buflp
= (afs_int32
*) (rstrm
->in_finger
);
202 /* first try the inline, fast case */
203 if ((rstrm
->fbtbc
>= sizeof(afs_int32
))
204 && (((int)((char *)rstrm
->in_boundry
- (char *)buflp
)) >= sizeof(afs_int32
))) {
206 rstrm
->fbtbc
-= sizeof(afs_int32
);
207 rstrm
->in_finger
+= sizeof(afs_int32
);
209 if (!xdrrec_getbytes(xdrs
, (caddr_t
) & myint32
, sizeof(afs_int32
)))
211 *lp
= ntohl(myint32
);
217 xdrrec_putint32(XDR
* xdrs
, afs_int32
* lp
)
219 RECSTREAM
*rstrm
= (RECSTREAM
*) (xdrs
->x_private
);
220 afs_int32
*dest_lp
= ((afs_int32
*) (rstrm
->out_finger
));
222 if ((rstrm
->out_finger
+= sizeof(afs_int32
)) > rstrm
->out_boundry
) {
224 * this case should almost never happen so the code is
227 rstrm
->out_finger
-= sizeof(afs_int32
);
228 rstrm
->frag_sent
= TRUE
;
229 if (!flush_out(rstrm
, FALSE
))
231 dest_lp
= ((afs_int32
*) (rstrm
->out_finger
));
232 rstrm
->out_finger
+= sizeof(afs_int32
);
234 *dest_lp
= htonl(*lp
);
239 xdrrec_getbytes(XDR
* xdrs
, caddr_t addr
, u_int len
)
241 RECSTREAM
*rstrm
= (RECSTREAM
*) (xdrs
->x_private
);
245 current
= rstrm
->fbtbc
;
247 if (rstrm
->last_frag
)
249 if (!set_input_fragment(rstrm
))
253 current
= (len
< current
) ? len
: current
;
254 if (!get_input_bytes(rstrm
, addr
, current
))
257 rstrm
->fbtbc
-= current
;
264 xdrrec_putbytes(XDR
* xdrs
, caddr_t addr
, u_int len
)
266 RECSTREAM
*rstrm
= (RECSTREAM
*) (xdrs
->x_private
);
270 current
= (u_int
) (rstrm
->out_boundry
- rstrm
->out_finger
);
271 current
= (len
< current
) ? len
: current
;
272 memcpy(rstrm
->out_finger
, addr
, current
);
273 rstrm
->out_finger
+= current
;
276 if (rstrm
->out_finger
== rstrm
->out_boundry
) {
277 rstrm
->frag_sent
= TRUE
;
278 if (!flush_out(rstrm
, FALSE
))
286 xdrrec_getpos(XDR
* xdrs
)
288 RECSTREAM
*rstrm
= (RECSTREAM
*) xdrs
->x_private
;
291 pos
= (u_int
) lseek((int)rstrm
->tcp_handle
, 0, 1);
293 switch (xdrs
->x_op
) {
296 pos
+= (u_int
)(rstrm
->out_finger
- rstrm
->out_base
);
300 pos
-= (u_int
)(rstrm
->in_boundry
- rstrm
->in_finger
);
311 xdrrec_setpos(XDR
* xdrs
, u_int pos
)
313 RECSTREAM
*rstrm
= (RECSTREAM
*) xdrs
->x_private
;
314 u_int currpos
= xdrrec_getpos(xdrs
);
315 int delta
= currpos
- pos
;
318 if ((int)currpos
!= -1)
319 switch (xdrs
->x_op
) {
322 newpos
= rstrm
->out_finger
- delta
;
323 if ((newpos
> (caddr_t
) (rstrm
->frag_header
))
324 && (newpos
< rstrm
->out_boundry
)) {
325 rstrm
->out_finger
= newpos
;
331 newpos
= rstrm
->in_finger
- delta
;
332 if ((delta
< (int)(rstrm
->fbtbc
)) && (newpos
<= rstrm
->in_boundry
)
333 && (newpos
>= rstrm
->in_base
)) {
334 rstrm
->in_finger
= newpos
;
335 rstrm
->fbtbc
-= delta
;
344 xdrrec_inline(XDR
* xdrs
, u_int len
)
346 RECSTREAM
*rstrm
= (RECSTREAM
*) xdrs
->x_private
;
347 afs_int32
*buf
= NULL
;
349 switch (xdrs
->x_op
) {
352 if ((rstrm
->out_finger
+ len
) <= rstrm
->out_boundry
) {
353 buf
= (afs_int32
*) rstrm
->out_finger
;
354 rstrm
->out_finger
+= len
;
359 if ((len
<= rstrm
->fbtbc
)
360 && ((rstrm
->in_finger
+ len
) <= rstrm
->in_boundry
)) {
361 buf
= (afs_int32
*) rstrm
->in_finger
;
363 rstrm
->in_finger
+= len
;
371 xdrrec_destroy(XDR
* xdrs
)
373 RECSTREAM
*rstrm
= (RECSTREAM
*) xdrs
->x_private
;
375 osi_free(rstrm
->out_base
, rstrm
->sendsize
);
376 osi_free(rstrm
->in_base
, rstrm
->recvsize
);
377 osi_free((caddr_t
) rstrm
, sizeof(RECSTREAM
));
382 * Exported routines to manage xdr records
386 * Before reading (deserializing from the stream, one should always call
387 * this procedure to guarantee proper record alignment.
390 xdrrec_skiprecord(XDR
* xdrs
)
392 RECSTREAM
*rstrm
= (RECSTREAM
*) (xdrs
->x_private
);
394 while (rstrm
->fbtbc
> 0 || (!rstrm
->last_frag
)) {
395 if (!skip_input_bytes(rstrm
, rstrm
->fbtbc
))
398 if ((!rstrm
->last_frag
) && (!set_input_fragment(rstrm
)))
401 rstrm
->last_frag
= FALSE
;
406 * Look ahead fuction.
407 * Returns TRUE iff there is no more input in the buffer
408 * after consuming the rest of the current record.
411 xdrrec_eof(XDR
* xdrs
)
413 RECSTREAM
*rstrm
= (RECSTREAM
*) (xdrs
->x_private
);
415 while (rstrm
->fbtbc
> 0 || (!rstrm
->last_frag
)) {
416 if (!skip_input_bytes(rstrm
, rstrm
->fbtbc
))
419 if ((!rstrm
->last_frag
) && (!set_input_fragment(rstrm
)))
422 if (rstrm
->in_finger
== rstrm
->in_boundry
)
428 * The client must tell the package when an end-of-record has occurred.
429 * The second paraemters tells whether the record should be flushed to the
430 * (output) tcp stream. (This let's the package support batched or
431 * pipelined procedure calls.) TRUE => immmediate flush to tcp connection.
434 xdrrec_endofrecord(XDR
* xdrs
, bool_t sendnow
)
436 RECSTREAM
*rstrm
= (RECSTREAM
*) (xdrs
->x_private
);
437 afs_uint32 len
; /* fragment length */
439 if (sendnow
|| rstrm
->frag_sent
440 || ((afs_uint32
) (rstrm
->out_finger
+ sizeof(afs_uint32
)) >=
441 (afs_uint32
) rstrm
->out_boundry
)) {
442 rstrm
->frag_sent
= FALSE
;
443 return (flush_out(rstrm
, TRUE
));
446 (afs_uint32
) (rstrm
->out_finger
- (caddr_t
)rstrm
->frag_header
) -
448 *(rstrm
->frag_header
) = htonl(len
| LAST_FRAG
);
449 rstrm
->frag_header
= (afs_uint32
*) rstrm
->out_finger
;
450 rstrm
->out_finger
+= sizeof(afs_uint32
);
456 * Internal useful routines
459 flush_out(RECSTREAM
* rstrm
, bool_t eor
)
461 afs_uint32 eormask
= (eor
== TRUE
) ? LAST_FRAG
: 0;
463 (afs_uint32
) (rstrm
->out_finger
- (caddr_t
)rstrm
->frag_header
) -
466 *(rstrm
->frag_header
) = htonl(len
| eormask
);
467 len
= (afs_uint32
) (rstrm
->out_finger
) - (afs_uint32
) (rstrm
->out_base
);
468 if ((*(rstrm
->writeit
)) (rstrm
->tcp_handle
, rstrm
->out_base
, (int)len
)
471 rstrm
->frag_header
= (afs_uint32
*) rstrm
->out_base
;
472 rstrm
->out_finger
= (caddr_t
) rstrm
->out_base
+ sizeof(afs_uint32
);
477 fill_input_buf(RECSTREAM
* rstrm
)
479 caddr_t where
= rstrm
->in_base
;
480 int len
= rstrm
->in_size
;
481 u_int adjust
= (u_int
) ((size_t)rstrm
->in_boundry
% BYTES_PER_XDR_UNIT
);
483 /* Bump the current position out to the next alignment boundary */
487 if ((len
= (*(rstrm
->readit
)) (rstrm
->tcp_handle
, where
, len
)) == -1)
489 rstrm
->in_finger
= where
;
491 rstrm
->in_boundry
= where
;
496 get_input_bytes(RECSTREAM
* rstrm
, caddr_t addr
,
502 current
= (int)(rstrm
->in_boundry
- rstrm
->in_finger
);
504 if (!fill_input_buf(rstrm
))
508 current
= (len
< current
) ? len
: current
;
509 memcpy(addr
, rstrm
->in_finger
, current
);
510 rstrm
->in_finger
+= current
;
517 /* next two bytes of the input stream are treated as a header */
519 set_input_fragment(RECSTREAM
* rstrm
)
523 if (!get_input_bytes(rstrm
, (caddr_t
) & header
, sizeof(header
)))
525 header
= ntohl(header
);
526 rstrm
->last_frag
= ((header
& LAST_FRAG
) == 0) ? FALSE
: TRUE
;
527 rstrm
->fbtbc
= header
& (~LAST_FRAG
);
531 /* consumes input bytes; knows nothing about records! */
533 skip_input_bytes(RECSTREAM
* rstrm
, int cnt
)
538 current
= (int)(rstrm
->in_boundry
- rstrm
->in_finger
);
540 if (!fill_input_buf(rstrm
))
544 current
= (cnt
< current
) ? cnt
: current
;
545 rstrm
->in_finger
+= current
;
552 fix_buf_size(u_int s
)
557 return ((s
+ BYTES_PER_XDR_UNIT
- 1) / BYTES_PER_XDR_UNIT
)
558 * BYTES_PER_XDR_UNIT
;