1 | /* |
2 | * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking" |
3 | * layer above tcp (for rpc's use). |
4 | * |
5 | * Copyright (c) 2010, Oracle America, Inc. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions are |
9 | * met: |
10 | * |
11 | * * Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. |
13 | * * Redistributions in binary form must reproduce the above |
14 | * copyright notice, this list of conditions and the following |
15 | * disclaimer in the documentation and/or other materials |
16 | * provided with the distribution. |
17 | * * Neither the name of the "Oracle America, Inc." nor the names of its |
18 | * contributors may be used to endorse or promote products derived |
19 | * from this software without specific prior written permission. |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
25 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
26 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
28 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
30 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
31 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
32 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
33 | * |
34 | * These routines interface XDRSTREAMS to a tcp/ip connection. |
35 | * There is a record marking layer between the xdr stream |
36 | * and the tcp transport level. A record is composed on one or more |
37 | * record fragments. A record fragment is a thirty-two bit header followed |
38 | * by n bytes of data, where n is contained in the header. The header |
39 | * is represented as a htonl(u_long). The high order bit encodes |
40 | * whether or not the fragment is the last fragment of the record |
41 | * (1 => fragment is last, 0 => more fragments to follow. |
42 | * The other 31 bits encode the byte length of the fragment. |
43 | */ |
44 | |
45 | #include <stdio.h> |
46 | #include <string.h> |
47 | #include <unistd.h> |
48 | #include <stdint.h> |
49 | #include <rpc/rpc.h> |
50 | #include <libintl.h> |
51 | #include <wchar.h> |
52 | #include <libio/iolibio.h> |
53 | #include <shlib-compat.h> |
54 | |
55 | static bool_t xdrrec_getlong (XDR *, long *); |
56 | static bool_t xdrrec_putlong (XDR *, const long *); |
57 | static bool_t xdrrec_getbytes (XDR *, caddr_t, u_int); |
58 | static bool_t xdrrec_putbytes (XDR *, const char *, u_int); |
59 | static u_int xdrrec_getpos (const XDR *); |
60 | static bool_t xdrrec_setpos (XDR *, u_int); |
61 | static int32_t *xdrrec_inline (XDR *, u_int); |
62 | static void xdrrec_destroy (XDR *); |
63 | static bool_t xdrrec_getint32 (XDR *, int32_t *); |
64 | static bool_t xdrrec_putint32 (XDR *, const int32_t *); |
65 | |
66 | static const struct xdr_ops xdrrec_ops = { |
67 | xdrrec_getlong, |
68 | xdrrec_putlong, |
69 | xdrrec_getbytes, |
70 | xdrrec_putbytes, |
71 | xdrrec_getpos, |
72 | xdrrec_setpos, |
73 | xdrrec_inline, |
74 | xdrrec_destroy, |
75 | xdrrec_getint32, |
76 | xdrrec_putint32 |
77 | }; |
78 | |
79 | /* |
80 | * A record is composed of one or more record fragments. |
81 | * A record fragment is a two-byte header followed by zero to |
82 | * 2**32-1 bytes. The header is treated as a long unsigned and is |
83 | * encode/decoded to the network via htonl/ntohl. The low order 31 bits |
84 | * are a byte count of the fragment. The highest order bit is a boolean: |
85 | * 1 => this fragment is the last fragment of the record, |
86 | * 0 => this fragment is followed by more fragment(s). |
87 | * |
88 | * The fragment/record machinery is not general; it is constructed to |
89 | * meet the needs of xdr and rpc based on tcp. |
90 | */ |
91 | |
92 | #define LAST_FRAG (1UL << 31) |
93 | |
94 | typedef struct rec_strm |
95 | { |
96 | caddr_t tcp_handle; |
97 | caddr_t the_buffer; |
98 | /* |
99 | * out-going bits |
100 | */ |
101 | int (*writeit) (char *, char *, int); |
102 | caddr_t out_base; /* output buffer (points to frag header) */ |
103 | caddr_t out_finger; /* next output position */ |
104 | caddr_t out_boundry; /* data cannot up to this address */ |
105 | uint32_t *; /* beginning of current fragment */ |
106 | bool_t frag_sent; /* true if buffer sent in middle of record */ |
107 | /* |
108 | * in-coming bits |
109 | */ |
110 | int (*readit) (char *, char *, int); |
111 | u_long in_size; /* fixed size of the input buffer */ |
112 | caddr_t in_base; |
113 | caddr_t in_finger; /* location of next byte to be had */ |
114 | caddr_t in_boundry; /* can read up to this location */ |
115 | long fbtbc; /* fragment bytes to be consumed */ |
116 | bool_t last_frag; |
117 | u_int sendsize; |
118 | u_int recvsize; |
119 | } |
120 | RECSTREAM; |
121 | |
122 | static u_int fix_buf_size (u_int); |
123 | static bool_t skip_input_bytes (RECSTREAM *, long); |
124 | static bool_t flush_out (RECSTREAM *, bool_t); |
125 | static bool_t set_input_fragment (RECSTREAM *); |
126 | static bool_t get_input_bytes (RECSTREAM *, caddr_t, int); |
127 | |
128 | /* |
129 | * Create an xdr handle for xdrrec |
130 | * xdrrec_create fills in xdrs. Sendsize and recvsize are |
131 | * send and recv buffer sizes (0 => use default). |
132 | * tcp_handle is an opaque handle that is passed as the first parameter to |
133 | * the procedures readit and writeit. Readit and writeit are read and |
134 | * write respectively. They are like the system |
135 | * calls expect that they take an opaque handle rather than an fd. |
136 | */ |
137 | void |
138 | xdrrec_create (XDR *xdrs, u_int sendsize, |
139 | u_int recvsize, caddr_t tcp_handle, |
140 | int (*readit) (char *, char *, int), |
141 | int (*writeit) (char *, char *, int)) |
142 | { |
143 | RECSTREAM *rstrm = (RECSTREAM *) mem_alloc (sizeof (RECSTREAM)); |
144 | caddr_t tmp; |
145 | char *buf; |
146 | |
147 | sendsize = fix_buf_size (sendsize); |
148 | recvsize = fix_buf_size (recvsize); |
149 | buf = mem_alloc (sendsize + recvsize + BYTES_PER_XDR_UNIT); |
150 | |
151 | if (rstrm == NULL || buf == NULL) |
152 | { |
153 | (void) __fxprintf (NULL, "%s: %s" , __func__, _("out of memory\n" )); |
154 | mem_free (rstrm, sizeof (RECSTREAM)); |
155 | mem_free (buf, sendsize + recvsize + BYTES_PER_XDR_UNIT); |
156 | /* |
157 | * This is bad. Should rework xdrrec_create to |
158 | * return a handle, and in this case return NULL |
159 | */ |
160 | return; |
161 | } |
162 | /* |
163 | * adjust sizes and allocate buffer quad byte aligned |
164 | */ |
165 | rstrm->sendsize = sendsize; |
166 | rstrm->recvsize = recvsize; |
167 | rstrm->the_buffer = buf; |
168 | tmp = rstrm->the_buffer; |
169 | if ((size_t)tmp % BYTES_PER_XDR_UNIT) |
170 | tmp += BYTES_PER_XDR_UNIT - (size_t)tmp % BYTES_PER_XDR_UNIT; |
171 | rstrm->out_base = tmp; |
172 | rstrm->in_base = tmp + sendsize; |
173 | /* |
174 | * now the rest ... |
175 | */ |
176 | /* We have to add the cast since the `struct xdr_ops' in `struct XDR' |
177 | is not `const'. */ |
178 | xdrs->x_ops = (struct xdr_ops *) &xdrrec_ops; |
179 | xdrs->x_private = (caddr_t) rstrm; |
180 | rstrm->tcp_handle = tcp_handle; |
181 | rstrm->readit = readit; |
182 | rstrm->writeit = writeit; |
183 | rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; |
184 | rstrm->frag_header = (uint32_t *) rstrm->out_base; |
185 | rstrm->out_finger += 4; |
186 | rstrm->out_boundry += sendsize; |
187 | rstrm->frag_sent = FALSE; |
188 | rstrm->in_size = recvsize; |
189 | rstrm->in_boundry = rstrm->in_base; |
190 | rstrm->in_finger = (rstrm->in_boundry += recvsize); |
191 | rstrm->fbtbc = 0; |
192 | rstrm->last_frag = TRUE; |
193 | } |
194 | libc_hidden_nolink_sunrpc (xdrrec_create, GLIBC_2_0) |
195 | |
196 | |
197 | /* |
198 | * The routines defined below are the xdr ops which will go into the |
199 | * xdr handle filled in by xdrrec_create. |
200 | */ |
201 | |
202 | static bool_t |
203 | xdrrec_getlong (XDR *xdrs, long *lp) |
204 | { |
205 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
206 | int32_t *buflp = (int32_t *) rstrm->in_finger; |
207 | int32_t mylong; |
208 | |
209 | /* first try the inline, fast case */ |
210 | if (rstrm->fbtbc >= BYTES_PER_XDR_UNIT && |
211 | rstrm->in_boundry - (char *) buflp >= BYTES_PER_XDR_UNIT) |
212 | { |
213 | *lp = (int32_t) ntohl (*buflp); |
214 | rstrm->fbtbc -= BYTES_PER_XDR_UNIT; |
215 | rstrm->in_finger += BYTES_PER_XDR_UNIT; |
216 | } |
217 | else |
218 | { |
219 | if (!xdrrec_getbytes (xdrs, (caddr_t) & mylong, |
220 | BYTES_PER_XDR_UNIT)) |
221 | return FALSE; |
222 | *lp = (int32_t) ntohl (mylong); |
223 | } |
224 | return TRUE; |
225 | } |
226 | |
227 | static bool_t |
228 | xdrrec_putlong (XDR *xdrs, const long *lp) |
229 | { |
230 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
231 | int32_t *dest_lp = (int32_t *) rstrm->out_finger; |
232 | |
233 | if ((rstrm->out_finger += BYTES_PER_XDR_UNIT) > rstrm->out_boundry) |
234 | { |
235 | /* |
236 | * this case should almost never happen so the code is |
237 | * inefficient |
238 | */ |
239 | rstrm->out_finger -= BYTES_PER_XDR_UNIT; |
240 | rstrm->frag_sent = TRUE; |
241 | if (!flush_out (rstrm, FALSE)) |
242 | return FALSE; |
243 | dest_lp = (int32_t *) rstrm->out_finger; |
244 | rstrm->out_finger += BYTES_PER_XDR_UNIT; |
245 | } |
246 | *dest_lp = htonl (*lp); |
247 | return TRUE; |
248 | } |
249 | |
250 | static bool_t /* must manage buffers, fragments, and records */ |
251 | xdrrec_getbytes (XDR *xdrs, caddr_t addr, u_int len) |
252 | { |
253 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
254 | u_int current; |
255 | |
256 | while (len > 0) |
257 | { |
258 | current = rstrm->fbtbc; |
259 | if (current == 0) |
260 | { |
261 | if (rstrm->last_frag) |
262 | return FALSE; |
263 | if (!set_input_fragment (rstrm)) |
264 | return FALSE; |
265 | continue; |
266 | } |
267 | current = (len < current) ? len : current; |
268 | if (!get_input_bytes (rstrm, addr, current)) |
269 | return FALSE; |
270 | addr += current; |
271 | rstrm->fbtbc -= current; |
272 | len -= current; |
273 | } |
274 | return TRUE; |
275 | } |
276 | |
277 | static bool_t |
278 | xdrrec_putbytes (XDR *xdrs, const char *addr, u_int len) |
279 | { |
280 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
281 | u_int current; |
282 | |
283 | while (len > 0) |
284 | { |
285 | current = rstrm->out_boundry - rstrm->out_finger; |
286 | current = (len < current) ? len : current; |
287 | memcpy (rstrm->out_finger, addr, current); |
288 | rstrm->out_finger += current; |
289 | addr += current; |
290 | len -= current; |
291 | if (rstrm->out_finger == rstrm->out_boundry && len > 0) |
292 | { |
293 | rstrm->frag_sent = TRUE; |
294 | if (!flush_out (rstrm, FALSE)) |
295 | return FALSE; |
296 | } |
297 | } |
298 | return TRUE; |
299 | } |
300 | |
301 | static u_int |
302 | xdrrec_getpos (const XDR *xdrs) |
303 | { |
304 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
305 | long pos; |
306 | |
307 | pos = __lseek ((int) (long) rstrm->tcp_handle, (long) 0, 1); |
308 | if (pos != -1) |
309 | switch (xdrs->x_op) |
310 | { |
311 | |
312 | case XDR_ENCODE: |
313 | pos += rstrm->out_finger - rstrm->out_base; |
314 | break; |
315 | |
316 | case XDR_DECODE: |
317 | pos -= rstrm->in_boundry - rstrm->in_finger; |
318 | break; |
319 | |
320 | default: |
321 | pos = (u_int) - 1; |
322 | break; |
323 | } |
324 | return (u_int) pos; |
325 | } |
326 | |
327 | static bool_t |
328 | xdrrec_setpos (XDR *xdrs, u_int pos) |
329 | { |
330 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
331 | u_int currpos = xdrrec_getpos (xdrs); |
332 | int delta = currpos - pos; |
333 | caddr_t newpos; |
334 | |
335 | if ((int) currpos != -1) |
336 | switch (xdrs->x_op) |
337 | { |
338 | |
339 | case XDR_ENCODE: |
340 | newpos = rstrm->out_finger - delta; |
341 | if (newpos > (caddr_t) rstrm->frag_header && |
342 | newpos < rstrm->out_boundry) |
343 | { |
344 | rstrm->out_finger = newpos; |
345 | return TRUE; |
346 | } |
347 | break; |
348 | |
349 | case XDR_DECODE: |
350 | newpos = rstrm->in_finger - delta; |
351 | if ((delta < (int) (rstrm->fbtbc)) && |
352 | (newpos <= rstrm->in_boundry) && |
353 | (newpos >= rstrm->in_base)) |
354 | { |
355 | rstrm->in_finger = newpos; |
356 | rstrm->fbtbc -= delta; |
357 | return TRUE; |
358 | } |
359 | break; |
360 | |
361 | default: |
362 | break; |
363 | } |
364 | return FALSE; |
365 | } |
366 | |
367 | static int32_t * |
368 | xdrrec_inline (XDR *xdrs, u_int len) |
369 | { |
370 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
371 | int32_t *buf = NULL; |
372 | |
373 | switch (xdrs->x_op) |
374 | { |
375 | |
376 | case XDR_ENCODE: |
377 | if ((rstrm->out_finger + len) <= rstrm->out_boundry) |
378 | { |
379 | buf = (int32_t *) rstrm->out_finger; |
380 | rstrm->out_finger += len; |
381 | } |
382 | break; |
383 | |
384 | case XDR_DECODE: |
385 | if ((len <= rstrm->fbtbc) && |
386 | ((rstrm->in_finger + len) <= rstrm->in_boundry)) |
387 | { |
388 | buf = (int32_t *) rstrm->in_finger; |
389 | rstrm->fbtbc -= len; |
390 | rstrm->in_finger += len; |
391 | } |
392 | break; |
393 | |
394 | default: |
395 | break; |
396 | } |
397 | return buf; |
398 | } |
399 | |
400 | static void |
401 | xdrrec_destroy (XDR *xdrs) |
402 | { |
403 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
404 | |
405 | mem_free (rstrm->the_buffer, |
406 | rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT); |
407 | mem_free ((caddr_t) rstrm, sizeof (RECSTREAM)); |
408 | } |
409 | |
410 | static bool_t |
411 | xdrrec_getint32 (XDR *xdrs, int32_t *ip) |
412 | { |
413 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
414 | int32_t *bufip = (int32_t *) rstrm->in_finger; |
415 | int32_t mylong; |
416 | |
417 | /* first try the inline, fast case */ |
418 | if (rstrm->fbtbc >= BYTES_PER_XDR_UNIT && |
419 | rstrm->in_boundry - (char *) bufip >= BYTES_PER_XDR_UNIT) |
420 | { |
421 | *ip = ntohl (*bufip); |
422 | rstrm->fbtbc -= BYTES_PER_XDR_UNIT; |
423 | rstrm->in_finger += BYTES_PER_XDR_UNIT; |
424 | } |
425 | else |
426 | { |
427 | if (!xdrrec_getbytes (xdrs, (caddr_t) &mylong, |
428 | BYTES_PER_XDR_UNIT)) |
429 | return FALSE; |
430 | *ip = ntohl (mylong); |
431 | } |
432 | return TRUE; |
433 | } |
434 | |
435 | static bool_t |
436 | xdrrec_putint32 (XDR *xdrs, const int32_t *ip) |
437 | { |
438 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
439 | int32_t *dest_ip = (int32_t *) rstrm->out_finger; |
440 | |
441 | if ((rstrm->out_finger += BYTES_PER_XDR_UNIT) > rstrm->out_boundry) |
442 | { |
443 | /* |
444 | * this case should almost never happen so the code is |
445 | * inefficient |
446 | */ |
447 | rstrm->out_finger -= BYTES_PER_XDR_UNIT; |
448 | rstrm->frag_sent = TRUE; |
449 | if (!flush_out (rstrm, FALSE)) |
450 | return FALSE; |
451 | dest_ip = (int32_t *) rstrm->out_finger; |
452 | rstrm->out_finger += BYTES_PER_XDR_UNIT; |
453 | } |
454 | *dest_ip = htonl (*ip); |
455 | return TRUE; |
456 | } |
457 | |
458 | /* |
459 | * Exported routines to manage xdr records |
460 | */ |
461 | |
462 | /* |
463 | * Before reading (deserializing from the stream, one should always call |
464 | * this procedure to guarantee proper record alignment. |
465 | */ |
466 | bool_t |
467 | xdrrec_skiprecord (XDR *xdrs) |
468 | { |
469 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
470 | |
471 | while (rstrm->fbtbc > 0 || (!rstrm->last_frag)) |
472 | { |
473 | if (!skip_input_bytes (rstrm, rstrm->fbtbc)) |
474 | return FALSE; |
475 | rstrm->fbtbc = 0; |
476 | if ((!rstrm->last_frag) && (!set_input_fragment (rstrm))) |
477 | return FALSE; |
478 | } |
479 | rstrm->last_frag = FALSE; |
480 | return TRUE; |
481 | } |
482 | libc_hidden_nolink_sunrpc (xdrrec_skiprecord, GLIBC_2_0) |
483 | |
484 | /* |
485 | * Lookahead function. |
486 | * Returns TRUE iff there is no more input in the buffer |
487 | * after consuming the rest of the current record. |
488 | */ |
489 | bool_t |
490 | xdrrec_eof (XDR *xdrs) |
491 | { |
492 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
493 | |
494 | while (rstrm->fbtbc > 0 || (!rstrm->last_frag)) |
495 | { |
496 | if (!skip_input_bytes (rstrm, rstrm->fbtbc)) |
497 | return TRUE; |
498 | rstrm->fbtbc = 0; |
499 | if ((!rstrm->last_frag) && (!set_input_fragment (rstrm))) |
500 | return TRUE; |
501 | } |
502 | if (rstrm->in_finger == rstrm->in_boundry) |
503 | return TRUE; |
504 | return FALSE; |
505 | } |
506 | libc_hidden_nolink_sunrpc (xdrrec_eof, GLIBC_2_0) |
507 | |
508 | /* |
509 | * The client must tell the package when an end-of-record has occurred. |
510 | * The second parameter tells whether the record should be flushed to the |
511 | * (output) tcp stream. (This lets the package support batched or |
512 | * pipelined procedure calls.) TRUE => immediate flush to tcp connection. |
513 | */ |
514 | bool_t |
515 | xdrrec_endofrecord (XDR *xdrs, bool_t sendnow) |
516 | { |
517 | RECSTREAM *rstrm = (RECSTREAM *) xdrs->x_private; |
518 | u_long len; /* fragment length */ |
519 | |
520 | if (sendnow || rstrm->frag_sent |
521 | || rstrm->out_finger + BYTES_PER_XDR_UNIT >= rstrm->out_boundry) |
522 | { |
523 | rstrm->frag_sent = FALSE; |
524 | return flush_out (rstrm, TRUE); |
525 | } |
526 | len = (rstrm->out_finger - (char *) rstrm->frag_header |
527 | - BYTES_PER_XDR_UNIT); |
528 | *rstrm->frag_header = htonl ((u_long) len | LAST_FRAG); |
529 | rstrm->frag_header = (uint32_t *) rstrm->out_finger; |
530 | rstrm->out_finger += BYTES_PER_XDR_UNIT; |
531 | return TRUE; |
532 | } |
533 | libc_hidden_nolink_sunrpc (xdrrec_endofrecord, GLIBC_2_0) |
534 | |
535 | |
536 | /* |
537 | * Internal useful routines |
538 | */ |
539 | static bool_t |
540 | flush_out (RECSTREAM *rstrm, bool_t eor) |
541 | { |
542 | u_long eormask = (eor == TRUE) ? LAST_FRAG : 0; |
543 | u_long len = (rstrm->out_finger - (char *) rstrm->frag_header |
544 | - BYTES_PER_XDR_UNIT); |
545 | |
546 | *rstrm->frag_header = htonl (len | eormask); |
547 | len = rstrm->out_finger - rstrm->out_base; |
548 | if ((*(rstrm->writeit)) (rstrm->tcp_handle, rstrm->out_base, (int) len) |
549 | != (int) len) |
550 | return FALSE; |
551 | rstrm->frag_header = (uint32_t *) rstrm->out_base; |
552 | rstrm->out_finger = (caddr_t) rstrm->out_base + BYTES_PER_XDR_UNIT; |
553 | return TRUE; |
554 | } |
555 | |
556 | static bool_t /* knows nothing about records! Only about input buffers */ |
557 | fill_input_buf (RECSTREAM *rstrm) |
558 | { |
559 | caddr_t where; |
560 | size_t i; |
561 | int len; |
562 | |
563 | where = rstrm->in_base; |
564 | i = (size_t) rstrm->in_boundry % BYTES_PER_XDR_UNIT; |
565 | where += i; |
566 | len = rstrm->in_size - i; |
567 | if ((len = (*(rstrm->readit)) (rstrm->tcp_handle, where, len)) == -1) |
568 | return FALSE; |
569 | rstrm->in_finger = where; |
570 | where += len; |
571 | rstrm->in_boundry = where; |
572 | return TRUE; |
573 | } |
574 | |
575 | static bool_t /* knows nothing about records! Only about input buffers */ |
576 | get_input_bytes (RECSTREAM *rstrm, caddr_t addr, int len) |
577 | { |
578 | int current; |
579 | |
580 | while (len > 0) |
581 | { |
582 | current = rstrm->in_boundry - rstrm->in_finger; |
583 | if (current == 0) |
584 | { |
585 | if (!fill_input_buf (rstrm)) |
586 | return FALSE; |
587 | continue; |
588 | } |
589 | current = (len < current) ? len : current; |
590 | memcpy (addr, rstrm->in_finger, current); |
591 | rstrm->in_finger += current; |
592 | addr += current; |
593 | len -= current; |
594 | } |
595 | return TRUE; |
596 | } |
597 | |
598 | static bool_t /* next two bytes of the input stream are treated as a header */ |
599 | set_input_fragment (RECSTREAM *rstrm) |
600 | { |
601 | uint32_t ; |
602 | |
603 | if (! get_input_bytes (rstrm, (caddr_t)&header, BYTES_PER_XDR_UNIT)) |
604 | return FALSE; |
605 | header = ntohl (header); |
606 | rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; |
607 | /* |
608 | * Sanity check. Try not to accept wildly incorrect fragment |
609 | * sizes. Unfortunately, only a size of zero can be identified as |
610 | * 'wildely incorrect', and this only, if it is not the last |
611 | * fragment of a message. Ridiculously large fragment sizes may look |
612 | * wrong, but we don't have any way to be certain that they aren't |
613 | * what the client actually intended to send us. Many existing RPC |
614 | * implementations may sent a fragment of size zero as the last |
615 | * fragment of a message. |
616 | */ |
617 | if (header == 0) |
618 | return FALSE; |
619 | rstrm->fbtbc = header & ~LAST_FRAG; |
620 | return TRUE; |
621 | } |
622 | |
623 | static bool_t /* consumes input bytes; knows nothing about records! */ |
624 | skip_input_bytes (RECSTREAM *rstrm, long cnt) |
625 | { |
626 | int current; |
627 | |
628 | while (cnt > 0) |
629 | { |
630 | current = rstrm->in_boundry - rstrm->in_finger; |
631 | if (current == 0) |
632 | { |
633 | if (!fill_input_buf (rstrm)) |
634 | return FALSE; |
635 | continue; |
636 | } |
637 | current = (cnt < current) ? cnt : current; |
638 | rstrm->in_finger += current; |
639 | cnt -= current; |
640 | } |
641 | return TRUE; |
642 | } |
643 | |
644 | static u_int |
645 | fix_buf_size (u_int s) |
646 | { |
647 | if (s < 100) |
648 | s = 4000; |
649 | return RNDUP (s); |
650 | } |
651 | |