17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 22*61961e0fSrobinson 237c478bd9Sstevel@tonic-gate /* 24*61961e0fSrobinson * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 317c478bd9Sstevel@tonic-gate * 4.3 BSD under license from the Regents of the University of 327c478bd9Sstevel@tonic-gate * California. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate /* 387c478bd9Sstevel@tonic-gate * xdr_rec.c, Implements (TCP/IP based) XDR streams with a "record marking" 397c478bd9Sstevel@tonic-gate * layer above connection oriented transport layer (e.g. tcp) (for rpc's use). 407c478bd9Sstevel@tonic-gate * 417c478bd9Sstevel@tonic-gate * 427c478bd9Sstevel@tonic-gate * These routines interface XDRSTREAMS to a (tcp/ip) connection transport. 437c478bd9Sstevel@tonic-gate * There is a record marking layer between the xdr stream 447c478bd9Sstevel@tonic-gate * and the (tcp) cv transport level. A record is composed on one or more 457c478bd9Sstevel@tonic-gate * record fragments. A record fragment is a thirty-two bit header followed 467c478bd9Sstevel@tonic-gate * by n bytes of data, where n is contained in the header. The header 477c478bd9Sstevel@tonic-gate * is represented as a htonl(ulong_t). The order bit encodes 487c478bd9Sstevel@tonic-gate * whether or not the fragment is the last fragment of the record 497c478bd9Sstevel@tonic-gate * (1 => fragment is last, 0 => more fragments to follow. 507c478bd9Sstevel@tonic-gate * The other 31 bits encode the byte length of the fragment. 517c478bd9Sstevel@tonic-gate */ 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate #include "mt.h" 547c478bd9Sstevel@tonic-gate #include "rpc_mt.h" 557c478bd9Sstevel@tonic-gate #include <stdio.h> 567c478bd9Sstevel@tonic-gate #include <rpc/types.h> 577c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 587c478bd9Sstevel@tonic-gate #include <sys/types.h> 597c478bd9Sstevel@tonic-gate #include <syslog.h> 607c478bd9Sstevel@tonic-gate #include <memory.h> 617c478bd9Sstevel@tonic-gate #include <stdlib.h> 627c478bd9Sstevel@tonic-gate #include <unistd.h> 637c478bd9Sstevel@tonic-gate #include <inttypes.h> 647c478bd9Sstevel@tonic-gate #include <string.h> 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate /* 677c478bd9Sstevel@tonic-gate * A record is composed of one or more record fragments. 687c478bd9Sstevel@tonic-gate * A record fragment is a four-byte header followed by zero to 697c478bd9Sstevel@tonic-gate * 2**32-1 bytes. The header is treated as a long unsigned and is 707c478bd9Sstevel@tonic-gate * encode/decoded to the network via htonl/ntohl. The low order 31 bits 717c478bd9Sstevel@tonic-gate * are a byte count of the fragment. The highest order bit is a boolean: 727c478bd9Sstevel@tonic-gate * 1 => this fragment is the last fragment of the record, 737c478bd9Sstevel@tonic-gate * 0 => this fragment is followed by more fragment(s). 747c478bd9Sstevel@tonic-gate * 757c478bd9Sstevel@tonic-gate * The fragment/record machinery is not general; it is constructed to 767c478bd9Sstevel@tonic-gate * meet the needs of xdr and rpc based on tcp. 777c478bd9Sstevel@tonic-gate */ 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate #define LAST_FRAG (((uint32_t)1 << 31)) 807c478bd9Sstevel@tonic-gate 817c478bd9Sstevel@tonic-gate /* 827c478bd9Sstevel@tonic-gate * Minimum fragment size is size of rpc callmsg over TCP: 837c478bd9Sstevel@tonic-gate * xid direction vers prog vers proc 847c478bd9Sstevel@tonic-gate * cred flavor, cred length, cred 857c478bd9Sstevel@tonic-gate * verf flavor, verf length, verf 867c478bd9Sstevel@tonic-gate * (with no cred or verf allocated) 877c478bd9Sstevel@tonic-gate */ 887c478bd9Sstevel@tonic-gate #define MIN_FRAG (10 * BYTES_PER_XDR_UNIT) 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate typedef struct rec_strm { 917c478bd9Sstevel@tonic-gate caddr_t tcp_handle; 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * out-going bits 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate int (*writeit)(); 967c478bd9Sstevel@tonic-gate caddr_t out_base; /* output buffer (points to frag header) */ 977c478bd9Sstevel@tonic-gate caddr_t out_finger; /* next output position */ 987c478bd9Sstevel@tonic-gate caddr_t out_boundry; /* data cannot up to this address */ 997c478bd9Sstevel@tonic-gate uint32_t *frag_header; /* beginning of current fragment */ 1007c478bd9Sstevel@tonic-gate bool_t frag_sent; /* true if buffer sent in middle of record */ 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * in-coming bits 1037c478bd9Sstevel@tonic-gate */ 1047c478bd9Sstevel@tonic-gate int (*readit)(); 1057c478bd9Sstevel@tonic-gate caddr_t in_base; /* input buffer */ 1067c478bd9Sstevel@tonic-gate caddr_t in_finger; /* location of next byte to be had */ 1077c478bd9Sstevel@tonic-gate caddr_t in_boundry; /* can read up to this location */ 1087c478bd9Sstevel@tonic-gate int fbtbc; /* fragment bytes to be consumed */ 1097c478bd9Sstevel@tonic-gate bool_t last_frag; 1107c478bd9Sstevel@tonic-gate uint_t sendsize; 1117c478bd9Sstevel@tonic-gate uint_t recvsize; 1127c478bd9Sstevel@tonic-gate /* 1137c478bd9Sstevel@tonic-gate * Is this the first time that the 1147c478bd9Sstevel@tonic-gate * getbytes routine has been called ? 1157c478bd9Sstevel@tonic-gate */ 1167c478bd9Sstevel@tonic-gate uint_t firsttime; 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * Is this non-blocked? 1197c478bd9Sstevel@tonic-gate */ 1207c478bd9Sstevel@tonic-gate uint_t in_nonblock; /* non-blocked input */ 1217c478bd9Sstevel@tonic-gate uint_t in_needpoll; /* need to poll to get more data ? */ 1227c478bd9Sstevel@tonic-gate uint32_t in_maxrecsz; /* maximum record size */ 1237c478bd9Sstevel@tonic-gate caddr_t in_nextrec; /* start of next record */ 1247c478bd9Sstevel@tonic-gate uint32_t in_nextrecsz; /* part of next record in buffer */ 1257c478bd9Sstevel@tonic-gate } RECSTREAM; 1267c478bd9Sstevel@tonic-gate 127*61961e0fSrobinson static uint_t fix_buf_size(uint_t); 128*61961e0fSrobinson static struct xdr_ops *xdrrec_ops(void); 129*61961e0fSrobinson static bool_t xdrrec_getbytes(XDR *, caddr_t, int); 130*61961e0fSrobinson static bool_t flush_out(RECSTREAM *, bool_t); 131*61961e0fSrobinson static bool_t get_input_bytes(RECSTREAM *, caddr_t, int, bool_t); 132*61961e0fSrobinson static bool_t set_input_fragment(RECSTREAM *); 133*61961e0fSrobinson static bool_t skip_input_bytes(RECSTREAM *, int32_t); 134*61961e0fSrobinson 135*61961e0fSrobinson bool_t __xdrrec_getbytes_nonblock(XDR *, enum xprt_stat *); 136*61961e0fSrobinson 1377c478bd9Sstevel@tonic-gate /* 1387c478bd9Sstevel@tonic-gate * Create an xdr handle for xdrrec 1397c478bd9Sstevel@tonic-gate * xdrrec_create fills in xdrs. Sendsize and recvsize are 1407c478bd9Sstevel@tonic-gate * send and recv buffer sizes (0 => use default). 1417c478bd9Sstevel@tonic-gate * vc_handle is an opaque handle that is passed as the first parameter to 1427c478bd9Sstevel@tonic-gate * the procedures readit and writeit. Readit and writeit are read and 1437c478bd9Sstevel@tonic-gate * write respectively. They are like the system calls expect that they 1447c478bd9Sstevel@tonic-gate * take an opaque handle rather than an fd. 1457c478bd9Sstevel@tonic-gate */ 1467c478bd9Sstevel@tonic-gate 1477c478bd9Sstevel@tonic-gate static const char mem_err_msg_rec[] = "xdrrec_create: out of memory"; 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate void 150*61961e0fSrobinson xdrrec_create(XDR *xdrs, const uint_t sendsize, const uint_t recvsize, 151*61961e0fSrobinson const caddr_t tcp_handle, int (*readit)(), int (*writeit)()) 1527c478bd9Sstevel@tonic-gate { 153*61961e0fSrobinson RECSTREAM *rstrm = malloc(sizeof (RECSTREAM)); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* 1567c478bd9Sstevel@tonic-gate * XXX: Should still rework xdrrec_create to return a handle, 1577c478bd9Sstevel@tonic-gate * and in any malloc-failure case return NULL. 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate if (rstrm == NULL) { 1607c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, mem_err_msg_rec); 1617c478bd9Sstevel@tonic-gate return; 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate /* 164*61961e0fSrobinson * Adjust sizes and allocate buffers; malloc(3C) 165*61961e0fSrobinson * provides a buffer suitably aligned for any use, so 1667c478bd9Sstevel@tonic-gate * there's no need for us to mess around with alignment. 1677c478bd9Sstevel@tonic-gate * 1687c478bd9Sstevel@tonic-gate * Since non-blocking connections may need to reallocate the input 169*61961e0fSrobinson * buffer, we use separate malloc()s for input and output. 1707c478bd9Sstevel@tonic-gate */ 171*61961e0fSrobinson rstrm->sendsize = fix_buf_size(sendsize); 172*61961e0fSrobinson rstrm->recvsize = fix_buf_size(recvsize); 173*61961e0fSrobinson rstrm->out_base = malloc(rstrm->sendsize); 1747c478bd9Sstevel@tonic-gate if (rstrm->out_base == NULL) { 1757c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, mem_err_msg_rec); 176*61961e0fSrobinson free(rstrm); 1777c478bd9Sstevel@tonic-gate return; 1787c478bd9Sstevel@tonic-gate } 179*61961e0fSrobinson rstrm->in_base = malloc(rstrm->recvsize); 1807c478bd9Sstevel@tonic-gate if (rstrm->in_base == NULL) { 1817c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, mem_err_msg_rec); 182*61961e0fSrobinson free(rstrm->out_base); 183*61961e0fSrobinson free(rstrm); 1847c478bd9Sstevel@tonic-gate return; 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * now the rest ... 1897c478bd9Sstevel@tonic-gate */ 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate xdrs->x_ops = xdrrec_ops(); 1927c478bd9Sstevel@tonic-gate xdrs->x_private = (caddr_t)rstrm; 1937c478bd9Sstevel@tonic-gate rstrm->tcp_handle = tcp_handle; 1947c478bd9Sstevel@tonic-gate rstrm->readit = readit; 1957c478bd9Sstevel@tonic-gate rstrm->writeit = writeit; 1967c478bd9Sstevel@tonic-gate rstrm->out_finger = rstrm->out_boundry = rstrm->out_base; 197*61961e0fSrobinson /* LINTED pointer cast */ 1987c478bd9Sstevel@tonic-gate rstrm->frag_header = (uint32_t *)rstrm->out_base; 1997c478bd9Sstevel@tonic-gate rstrm->out_finger += sizeof (uint_t); 200*61961e0fSrobinson rstrm->out_boundry += rstrm->sendsize; 2017c478bd9Sstevel@tonic-gate rstrm->frag_sent = FALSE; 2027c478bd9Sstevel@tonic-gate rstrm->in_boundry = rstrm->in_base; 203*61961e0fSrobinson rstrm->in_finger = (rstrm->in_boundry += rstrm->recvsize); 2047c478bd9Sstevel@tonic-gate rstrm->fbtbc = 0; 2057c478bd9Sstevel@tonic-gate rstrm->last_frag = TRUE; 2067c478bd9Sstevel@tonic-gate rstrm->firsttime = 0; 2077c478bd9Sstevel@tonic-gate rstrm->in_nonblock = 0; 2087c478bd9Sstevel@tonic-gate rstrm->in_needpoll = 1; 2097c478bd9Sstevel@tonic-gate rstrm->in_maxrecsz = 0; 2107c478bd9Sstevel@tonic-gate rstrm->in_nextrec = rstrm->in_base; 2117c478bd9Sstevel@tonic-gate rstrm->in_nextrecsz = 0; 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate /* 2157c478bd9Sstevel@tonic-gate * Align input stream. If all applications behaved correctly, this 2167c478bd9Sstevel@tonic-gate * defensive procedure will not be necessary, since received data will be 2177c478bd9Sstevel@tonic-gate * aligned correctly. 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate static void 2207c478bd9Sstevel@tonic-gate align_instream(RECSTREAM *rstrm) 2217c478bd9Sstevel@tonic-gate { 2227c478bd9Sstevel@tonic-gate int current = rstrm->in_boundry - rstrm->in_finger; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate (void) memcpy(rstrm->in_base, rstrm->in_finger, current); 2257c478bd9Sstevel@tonic-gate rstrm->in_finger = rstrm->in_base; 2267c478bd9Sstevel@tonic-gate rstrm->in_boundry = rstrm->in_finger + current; 2277c478bd9Sstevel@tonic-gate } 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * The routines defined below are the xdr ops which will go into the 2317c478bd9Sstevel@tonic-gate * xdr handle filled in by xdrrec_create. 2327c478bd9Sstevel@tonic-gate */ 2337c478bd9Sstevel@tonic-gate static bool_t 2347c478bd9Sstevel@tonic-gate xdrrec_getint32(XDR *xdrs, int32_t *ip) 2357c478bd9Sstevel@tonic-gate { 236*61961e0fSrobinson /* LINTED pointer cast */ 2377c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 238*61961e0fSrobinson /* LINTED pointer cast */ 2397c478bd9Sstevel@tonic-gate int32_t *buflp = (int32_t *)(rstrm->in_finger); 2407c478bd9Sstevel@tonic-gate int32_t mylong; 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate /* first try the inline, fast case */ 2437c478bd9Sstevel@tonic-gate if ((rstrm->fbtbc >= (int)sizeof (int32_t)) && 2447c478bd9Sstevel@tonic-gate ((uint_t)(rstrm->in_boundry - (caddr_t)buflp) >= 2457c478bd9Sstevel@tonic-gate (uint_t)sizeof (int32_t))) { 2467c478bd9Sstevel@tonic-gate /* 2477c478bd9Sstevel@tonic-gate * Check if buflp is longword aligned. If not, align it. 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate if (((uintptr_t)buflp) & ((int)sizeof (int32_t) - 1)) { 2507c478bd9Sstevel@tonic-gate align_instream(rstrm); 251*61961e0fSrobinson /* LINTED pointer cast */ 2527c478bd9Sstevel@tonic-gate buflp = (int32_t *)(rstrm->in_finger); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate *ip = (int32_t)ntohl((uint32_t)(*buflp)); 2557c478bd9Sstevel@tonic-gate rstrm->fbtbc -= (int)sizeof (int32_t); 2567c478bd9Sstevel@tonic-gate rstrm->in_finger += sizeof (int32_t); 2577c478bd9Sstevel@tonic-gate } else { 258*61961e0fSrobinson if (!xdrrec_getbytes(xdrs, (caddr_t)&mylong, sizeof (int32_t))) 2597c478bd9Sstevel@tonic-gate return (FALSE); 2607c478bd9Sstevel@tonic-gate *ip = (int32_t)ntohl((uint32_t)mylong); 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate return (TRUE); 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate static bool_t 2667c478bd9Sstevel@tonic-gate xdrrec_putint32(XDR *xdrs, int32_t *ip) 2677c478bd9Sstevel@tonic-gate { 268*61961e0fSrobinson /* LINTED pointer cast */ 2697c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 270*61961e0fSrobinson /* LINTED pointer cast */ 2717c478bd9Sstevel@tonic-gate int32_t *dest_lp = ((int32_t *)(rstrm->out_finger)); 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate if ((rstrm->out_finger += sizeof (int32_t)) > rstrm->out_boundry) { 2747c478bd9Sstevel@tonic-gate /* 2757c478bd9Sstevel@tonic-gate * this case should almost never happen so the code is 2767c478bd9Sstevel@tonic-gate * inefficient 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate rstrm->out_finger -= sizeof (int32_t); 2797c478bd9Sstevel@tonic-gate rstrm->frag_sent = TRUE; 280*61961e0fSrobinson if (!flush_out(rstrm, FALSE)) 2817c478bd9Sstevel@tonic-gate return (FALSE); 282*61961e0fSrobinson /* LINTED pointer cast */ 2837c478bd9Sstevel@tonic-gate dest_lp = ((int32_t *)(rstrm->out_finger)); 2847c478bd9Sstevel@tonic-gate rstrm->out_finger += sizeof (int32_t); 2857c478bd9Sstevel@tonic-gate } 2867c478bd9Sstevel@tonic-gate *dest_lp = (int32_t)htonl((uint32_t)(*ip)); 2877c478bd9Sstevel@tonic-gate return (TRUE); 2887c478bd9Sstevel@tonic-gate } 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate static bool_t 2917c478bd9Sstevel@tonic-gate xdrrec_getlong(XDR *xdrs, long *lp) 2927c478bd9Sstevel@tonic-gate { 2937c478bd9Sstevel@tonic-gate int32_t i; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate if (!xdrrec_getint32(xdrs, &i)) 2967c478bd9Sstevel@tonic-gate return (FALSE); 2977c478bd9Sstevel@tonic-gate *lp = (long)i; 2987c478bd9Sstevel@tonic-gate return (TRUE); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate 3017c478bd9Sstevel@tonic-gate static bool_t 3027c478bd9Sstevel@tonic-gate xdrrec_putlong(XDR *xdrs, long *lp) 3037c478bd9Sstevel@tonic-gate { 3047c478bd9Sstevel@tonic-gate int32_t i; 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate #if defined(_LP64) 307*61961e0fSrobinson if ((*lp > INT32_MAX) || (*lp < INT32_MIN)) 3087c478bd9Sstevel@tonic-gate return (FALSE); 3097c478bd9Sstevel@tonic-gate #endif 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate i = (int32_t)*lp; 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate return (xdrrec_putint32(xdrs, &i)); 3147c478bd9Sstevel@tonic-gate } 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate static bool_t /* must manage buffers, fragments, and records */ 3177c478bd9Sstevel@tonic-gate xdrrec_getbytes(XDR *xdrs, caddr_t addr, int len) 3187c478bd9Sstevel@tonic-gate { 319*61961e0fSrobinson /* LINTED pointer cast */ 3207c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 3217c478bd9Sstevel@tonic-gate int current; 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate while (len > 0) { 3247c478bd9Sstevel@tonic-gate current = rstrm->fbtbc; 3257c478bd9Sstevel@tonic-gate if (current == 0) { 326*61961e0fSrobinson if (rstrm->last_frag) 3277c478bd9Sstevel@tonic-gate return (FALSE); 328*61961e0fSrobinson if (!set_input_fragment(rstrm)) 3297c478bd9Sstevel@tonic-gate return (FALSE); 3307c478bd9Sstevel@tonic-gate continue; 3317c478bd9Sstevel@tonic-gate } 3327c478bd9Sstevel@tonic-gate current = (len < current) ? len : current; 333*61961e0fSrobinson if (!get_input_bytes(rstrm, addr, current, FALSE)) 3347c478bd9Sstevel@tonic-gate return (FALSE); 3357c478bd9Sstevel@tonic-gate addr += current; 3367c478bd9Sstevel@tonic-gate rstrm->fbtbc -= current; 3377c478bd9Sstevel@tonic-gate len -= current; 3387c478bd9Sstevel@tonic-gate } 3397c478bd9Sstevel@tonic-gate return (TRUE); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate static bool_t 3437c478bd9Sstevel@tonic-gate xdrrec_putbytes(XDR *xdrs, caddr_t addr, int len) 3447c478bd9Sstevel@tonic-gate { 345*61961e0fSrobinson /* LINTED pointer cast */ 3467c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 3477c478bd9Sstevel@tonic-gate int current; 3487c478bd9Sstevel@tonic-gate 3497c478bd9Sstevel@tonic-gate while (len > 0) { 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate current = (uintptr_t)rstrm->out_boundry - 3527c478bd9Sstevel@tonic-gate (uintptr_t)rstrm->out_finger; 3537c478bd9Sstevel@tonic-gate current = (len < current) ? len : current; 3547c478bd9Sstevel@tonic-gate (void) memcpy(rstrm->out_finger, addr, current); 3557c478bd9Sstevel@tonic-gate rstrm->out_finger += current; 3567c478bd9Sstevel@tonic-gate addr += current; 3577c478bd9Sstevel@tonic-gate len -= current; 3587c478bd9Sstevel@tonic-gate if (rstrm->out_finger == rstrm->out_boundry) { 3597c478bd9Sstevel@tonic-gate rstrm->frag_sent = TRUE; 360*61961e0fSrobinson if (!flush_out(rstrm, FALSE)) 3617c478bd9Sstevel@tonic-gate return (FALSE); 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate return (TRUE); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * This is just like the ops vector x_getbytes(), except that 3687c478bd9Sstevel@tonic-gate * instead of returning success or failure on getting a certain number 3697c478bd9Sstevel@tonic-gate * of bytes, it behaves much more like the read() system call against a 3707c478bd9Sstevel@tonic-gate * pipe -- it returns up to the number of bytes requested and a return of 3717c478bd9Sstevel@tonic-gate * zero indicates end-of-record. A -1 means something very bad happened. 3727c478bd9Sstevel@tonic-gate */ 3737c478bd9Sstevel@tonic-gate uint_t /* must manage buffers, fragments, and records */ 3747c478bd9Sstevel@tonic-gate xdrrec_readbytes(XDR *xdrs, caddr_t addr, uint_t l) 3757c478bd9Sstevel@tonic-gate { 376*61961e0fSrobinson /* LINTED pointer cast */ 3777c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 3787c478bd9Sstevel@tonic-gate int current, len; 3797c478bd9Sstevel@tonic-gate 3807c478bd9Sstevel@tonic-gate len = l; 3817c478bd9Sstevel@tonic-gate while (len > 0) { 3827c478bd9Sstevel@tonic-gate current = rstrm->fbtbc; 3837c478bd9Sstevel@tonic-gate if (current == 0) { 3847c478bd9Sstevel@tonic-gate if (rstrm->last_frag) 3857c478bd9Sstevel@tonic-gate return (l - len); 3867c478bd9Sstevel@tonic-gate if (!set_input_fragment(rstrm)) 3877c478bd9Sstevel@tonic-gate return ((uint_t)-1); 3887c478bd9Sstevel@tonic-gate continue; 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate current = (len < current) ? len : current; 3917c478bd9Sstevel@tonic-gate if (!get_input_bytes(rstrm, addr, current, FALSE)) 3927c478bd9Sstevel@tonic-gate return ((uint_t)-1); 3937c478bd9Sstevel@tonic-gate addr += current; 3947c478bd9Sstevel@tonic-gate rstrm->fbtbc -= current; 3957c478bd9Sstevel@tonic-gate len -= current; 3967c478bd9Sstevel@tonic-gate } 3977c478bd9Sstevel@tonic-gate return (l - len); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate static uint_t 4017c478bd9Sstevel@tonic-gate xdrrec_getpos(XDR *xdrs) 4027c478bd9Sstevel@tonic-gate { 403*61961e0fSrobinson /* LINTED pointer cast */ 4047c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 4057c478bd9Sstevel@tonic-gate int32_t pos; 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate pos = lseek((intptr_t)rstrm->tcp_handle, 0, 1); 4087c478bd9Sstevel@tonic-gate if (pos != -1) 4097c478bd9Sstevel@tonic-gate switch (xdrs->x_op) { 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate case XDR_ENCODE: 4127c478bd9Sstevel@tonic-gate pos += rstrm->out_finger - rstrm->out_base; 4137c478bd9Sstevel@tonic-gate break; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate case XDR_DECODE: 4167c478bd9Sstevel@tonic-gate pos -= rstrm->in_boundry - rstrm->in_finger; 4177c478bd9Sstevel@tonic-gate break; 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate default: 4207c478bd9Sstevel@tonic-gate pos = (uint_t)-1; 4217c478bd9Sstevel@tonic-gate break; 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate return ((uint_t)pos); 4247c478bd9Sstevel@tonic-gate } 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate static bool_t 4277c478bd9Sstevel@tonic-gate xdrrec_setpos(XDR *xdrs, uint_t pos) 4287c478bd9Sstevel@tonic-gate { 429*61961e0fSrobinson /* LINTED pointer cast */ 4307c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 4317c478bd9Sstevel@tonic-gate uint_t currpos = xdrrec_getpos(xdrs); 4327c478bd9Sstevel@tonic-gate int delta = currpos - pos; 4337c478bd9Sstevel@tonic-gate caddr_t newpos; 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate if ((int)currpos != -1) 4367c478bd9Sstevel@tonic-gate switch (xdrs->x_op) { 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate case XDR_ENCODE: 4397c478bd9Sstevel@tonic-gate newpos = rstrm->out_finger - delta; 4407c478bd9Sstevel@tonic-gate if ((newpos > (caddr_t)(rstrm->frag_header)) && 4417c478bd9Sstevel@tonic-gate (newpos < rstrm->out_boundry)) { 4427c478bd9Sstevel@tonic-gate rstrm->out_finger = newpos; 4437c478bd9Sstevel@tonic-gate return (TRUE); 4447c478bd9Sstevel@tonic-gate } 4457c478bd9Sstevel@tonic-gate break; 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate case XDR_DECODE: 4487c478bd9Sstevel@tonic-gate newpos = rstrm->in_finger - delta; 4497c478bd9Sstevel@tonic-gate if ((delta < (int)(rstrm->fbtbc)) && 4507c478bd9Sstevel@tonic-gate (newpos <= rstrm->in_boundry) && 4517c478bd9Sstevel@tonic-gate (newpos >= rstrm->in_base)) { 4527c478bd9Sstevel@tonic-gate rstrm->in_finger = newpos; 4537c478bd9Sstevel@tonic-gate rstrm->fbtbc -= delta; 4547c478bd9Sstevel@tonic-gate return (TRUE); 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate break; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate return (FALSE); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate static rpc_inline_t * 4627c478bd9Sstevel@tonic-gate xdrrec_inline(XDR *xdrs, int len) 4637c478bd9Sstevel@tonic-gate { 464*61961e0fSrobinson /* LINTED pointer cast */ 4657c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 4667c478bd9Sstevel@tonic-gate rpc_inline_t *buf = NULL; 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate switch (xdrs->x_op) { 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate case XDR_ENCODE: 4717c478bd9Sstevel@tonic-gate if ((rstrm->out_finger + len) <= rstrm->out_boundry) { 472*61961e0fSrobinson /* LINTED pointer cast */ 4737c478bd9Sstevel@tonic-gate buf = (rpc_inline_t *)rstrm->out_finger; 4747c478bd9Sstevel@tonic-gate rstrm->out_finger += len; 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate break; 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate case XDR_DECODE: 4797c478bd9Sstevel@tonic-gate if ((len <= rstrm->fbtbc) && 4807c478bd9Sstevel@tonic-gate ((rstrm->in_finger + len) <= rstrm->in_boundry)) { 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * Check if rstrm->in_finger is longword aligned; 4837c478bd9Sstevel@tonic-gate * if not, align it. 4847c478bd9Sstevel@tonic-gate */ 4857c478bd9Sstevel@tonic-gate if (((intptr_t)rstrm->in_finger) & 4867c478bd9Sstevel@tonic-gate (sizeof (int32_t) - 1)) 4877c478bd9Sstevel@tonic-gate align_instream(rstrm); 488*61961e0fSrobinson /* LINTED pointer cast */ 4897c478bd9Sstevel@tonic-gate buf = (rpc_inline_t *)rstrm->in_finger; 4907c478bd9Sstevel@tonic-gate rstrm->fbtbc -= len; 4917c478bd9Sstevel@tonic-gate rstrm->in_finger += len; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate break; 4947c478bd9Sstevel@tonic-gate } 4957c478bd9Sstevel@tonic-gate return (buf); 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate static void 4997c478bd9Sstevel@tonic-gate xdrrec_destroy(XDR *xdrs) 5007c478bd9Sstevel@tonic-gate { 501*61961e0fSrobinson /* LINTED pointer cast */ 5027c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private; 5037c478bd9Sstevel@tonic-gate 504*61961e0fSrobinson free(rstrm->out_base); 505*61961e0fSrobinson free(rstrm->in_base); 506*61961e0fSrobinson free(rstrm); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * Exported routines to manage xdr records 5127c478bd9Sstevel@tonic-gate */ 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* 5157c478bd9Sstevel@tonic-gate * Before reading (deserializing) from the stream, one should always call 5167c478bd9Sstevel@tonic-gate * this procedure to guarantee proper record alignment. 5177c478bd9Sstevel@tonic-gate */ 5187c478bd9Sstevel@tonic-gate bool_t 5197c478bd9Sstevel@tonic-gate xdrrec_skiprecord(XDR *xdrs) 5207c478bd9Sstevel@tonic-gate { 521*61961e0fSrobinson /* LINTED pointer cast */ 5227c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate if (rstrm->in_nonblock) { 5257c478bd9Sstevel@tonic-gate enum xprt_stat pstat; 5267c478bd9Sstevel@tonic-gate /* 5277c478bd9Sstevel@tonic-gate * Read and discard a record from the non-blocking 5287c478bd9Sstevel@tonic-gate * buffer. Return succes only if a complete record can 5297c478bd9Sstevel@tonic-gate * be retrieved without blocking, or if the buffer was 5307c478bd9Sstevel@tonic-gate * empty and there was no data to fetch. 5317c478bd9Sstevel@tonic-gate */ 5327c478bd9Sstevel@tonic-gate if (__xdrrec_getbytes_nonblock(xdrs, &pstat) || 5337c478bd9Sstevel@tonic-gate (pstat == XPRT_MOREREQS && 5347c478bd9Sstevel@tonic-gate rstrm->in_finger == rstrm->in_boundry)) { 5357c478bd9Sstevel@tonic-gate rstrm->fbtbc = 0; 5367c478bd9Sstevel@tonic-gate return (TRUE); 5377c478bd9Sstevel@tonic-gate } 538*61961e0fSrobinson return (FALSE); 5397c478bd9Sstevel@tonic-gate } 5407c478bd9Sstevel@tonic-gate while (rstrm->fbtbc > 0 || (!rstrm->last_frag)) { 541*61961e0fSrobinson if (!skip_input_bytes(rstrm, rstrm->fbtbc)) 5427c478bd9Sstevel@tonic-gate return (FALSE); 5437c478bd9Sstevel@tonic-gate rstrm->fbtbc = 0; 544*61961e0fSrobinson if ((!rstrm->last_frag) && (!set_input_fragment(rstrm))) 5457c478bd9Sstevel@tonic-gate return (FALSE); 5467c478bd9Sstevel@tonic-gate } 5477c478bd9Sstevel@tonic-gate rstrm->last_frag = FALSE; 5487c478bd9Sstevel@tonic-gate return (TRUE); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * Look ahead fuction. 5537c478bd9Sstevel@tonic-gate * Returns TRUE iff there is no more input in the buffer 5547c478bd9Sstevel@tonic-gate * after consuming the rest of the current record. 5557c478bd9Sstevel@tonic-gate */ 5567c478bd9Sstevel@tonic-gate bool_t 5577c478bd9Sstevel@tonic-gate xdrrec_eof(XDR *xdrs) 5587c478bd9Sstevel@tonic-gate { 559*61961e0fSrobinson /* LINTED pointer cast */ 5607c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate if (rstrm->in_nonblock) { 5637c478bd9Sstevel@tonic-gate /* 5647c478bd9Sstevel@tonic-gate * If in_needpoll is true, the non-blocking XDR stream 5657c478bd9Sstevel@tonic-gate * does not have a complete record. 5667c478bd9Sstevel@tonic-gate */ 5677c478bd9Sstevel@tonic-gate return (rstrm->in_needpoll); 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate while (rstrm->fbtbc > 0 || (!rstrm->last_frag)) { 570*61961e0fSrobinson if (!skip_input_bytes(rstrm, rstrm->fbtbc)) 5717c478bd9Sstevel@tonic-gate return (TRUE); 5727c478bd9Sstevel@tonic-gate rstrm->fbtbc = 0; 573*61961e0fSrobinson if ((!rstrm->last_frag) && (!set_input_fragment(rstrm))) 5747c478bd9Sstevel@tonic-gate return (TRUE); 5757c478bd9Sstevel@tonic-gate } 576*61961e0fSrobinson if (rstrm->in_finger == rstrm->in_boundry) 5777c478bd9Sstevel@tonic-gate return (TRUE); 5787c478bd9Sstevel@tonic-gate return (FALSE); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate /* 5827c478bd9Sstevel@tonic-gate * The client must tell the package when an end-of-record has occurred. 5837c478bd9Sstevel@tonic-gate * The second parameters tells whether the record should be flushed to the 5847c478bd9Sstevel@tonic-gate * (output) tcp stream. (This let's the package support batched or 5857c478bd9Sstevel@tonic-gate * pipelined procedure calls.) TRUE => immmediate flush to tcp connection. 5867c478bd9Sstevel@tonic-gate */ 5877c478bd9Sstevel@tonic-gate bool_t 5887c478bd9Sstevel@tonic-gate xdrrec_endofrecord(XDR *xdrs, bool_t sendnow) 5897c478bd9Sstevel@tonic-gate { 590*61961e0fSrobinson /* LINTED pointer cast */ 5917c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 5927c478bd9Sstevel@tonic-gate uint32_t len; /* fragment length */ 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate if (sendnow || rstrm->frag_sent || 5957c478bd9Sstevel@tonic-gate ((uintptr_t)rstrm->out_finger + sizeof (uint32_t) >= 5967c478bd9Sstevel@tonic-gate (uintptr_t)rstrm->out_boundry)) { 5977c478bd9Sstevel@tonic-gate rstrm->frag_sent = FALSE; 598*61961e0fSrobinson return (flush_out(rstrm, TRUE)); 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate len = (uintptr_t)(rstrm->out_finger) - (uintptr_t)(rstrm->frag_header) - 6017c478bd9Sstevel@tonic-gate sizeof (uint32_t); 6027c478bd9Sstevel@tonic-gate *(rstrm->frag_header) = htonl((uint32_t)len | LAST_FRAG); 603*61961e0fSrobinson /* LINTED pointer cast */ 6047c478bd9Sstevel@tonic-gate rstrm->frag_header = (uint32_t *)rstrm->out_finger; 6057c478bd9Sstevel@tonic-gate rstrm->out_finger += sizeof (uint32_t); 6067c478bd9Sstevel@tonic-gate return (TRUE); 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate /* 6117c478bd9Sstevel@tonic-gate * Internal useful routines 6127c478bd9Sstevel@tonic-gate */ 6137c478bd9Sstevel@tonic-gate static bool_t 6147c478bd9Sstevel@tonic-gate flush_out(RECSTREAM *rstrm, bool_t eor) 6157c478bd9Sstevel@tonic-gate { 6167c478bd9Sstevel@tonic-gate uint32_t eormask = (eor == TRUE) ? LAST_FRAG : 0; 6177c478bd9Sstevel@tonic-gate uint32_t len = (uintptr_t)(rstrm->out_finger) - 6187c478bd9Sstevel@tonic-gate (uintptr_t)(rstrm->frag_header) - sizeof (uint32_t); 6197c478bd9Sstevel@tonic-gate int written; 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate *(rstrm->frag_header) = htonl(len | eormask); 6227c478bd9Sstevel@tonic-gate len = (uintptr_t)(rstrm->out_finger) - (uintptr_t)(rstrm->out_base); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate written = (*(rstrm->writeit)) 6257c478bd9Sstevel@tonic-gate (rstrm->tcp_handle, rstrm->out_base, (int)len); 6267c478bd9Sstevel@tonic-gate /* 6277c478bd9Sstevel@tonic-gate * Handle the specific 'CANT_STORE' error. In this case, the 6287c478bd9Sstevel@tonic-gate * fragment must be cleared. 6297c478bd9Sstevel@tonic-gate */ 630*61961e0fSrobinson if ((written != (int)len) && (written != -2)) 6317c478bd9Sstevel@tonic-gate return (FALSE); 632*61961e0fSrobinson /* LINTED pointer cast */ 6337c478bd9Sstevel@tonic-gate rstrm->frag_header = (uint32_t *)rstrm->out_base; 6347c478bd9Sstevel@tonic-gate rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof (uint32_t); 6357c478bd9Sstevel@tonic-gate 6367c478bd9Sstevel@tonic-gate return (TRUE); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate /* knows nothing about records! Only about input buffers */ 6407c478bd9Sstevel@tonic-gate static bool_t 6417c478bd9Sstevel@tonic-gate fill_input_buf(RECSTREAM *rstrm, bool_t do_align) 6427c478bd9Sstevel@tonic-gate { 6437c478bd9Sstevel@tonic-gate caddr_t where; 6447c478bd9Sstevel@tonic-gate int len; 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate if (rstrm->in_nonblock) { 6477c478bd9Sstevel@tonic-gate /* Should never get here in the non-blocking case */ 6487c478bd9Sstevel@tonic-gate return (FALSE); 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate where = rstrm->in_base; 6517c478bd9Sstevel@tonic-gate if (do_align) { 6527c478bd9Sstevel@tonic-gate len = rstrm->recvsize; 6537c478bd9Sstevel@tonic-gate } else { 6547c478bd9Sstevel@tonic-gate uint_t i = (uintptr_t)rstrm->in_boundry % BYTES_PER_XDR_UNIT; 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate where += i; 6577c478bd9Sstevel@tonic-gate len = rstrm->recvsize - i; 6587c478bd9Sstevel@tonic-gate } 659*61961e0fSrobinson if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1) 6607c478bd9Sstevel@tonic-gate return (FALSE); 6617c478bd9Sstevel@tonic-gate rstrm->in_finger = where; 6627c478bd9Sstevel@tonic-gate where += len; 6637c478bd9Sstevel@tonic-gate rstrm->in_boundry = where; 6647c478bd9Sstevel@tonic-gate return (TRUE); 6657c478bd9Sstevel@tonic-gate } 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate /* knows nothing about records! Only about input buffers */ 6687c478bd9Sstevel@tonic-gate static bool_t 6697c478bd9Sstevel@tonic-gate get_input_bytes(RECSTREAM *rstrm, caddr_t addr, 6707c478bd9Sstevel@tonic-gate int len, bool_t do_align) 6717c478bd9Sstevel@tonic-gate { 6727c478bd9Sstevel@tonic-gate int current; 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate if (rstrm->in_nonblock) { 6757c478bd9Sstevel@tonic-gate /* 6767c478bd9Sstevel@tonic-gate * Data should already be in the rstrm buffer, so we just 6777c478bd9Sstevel@tonic-gate * need to copy it to 'addr'. 6787c478bd9Sstevel@tonic-gate */ 6797c478bd9Sstevel@tonic-gate current = (int)(rstrm->in_boundry - rstrm->in_finger); 680*61961e0fSrobinson if (len > current) 6817c478bd9Sstevel@tonic-gate return (FALSE); 6827c478bd9Sstevel@tonic-gate (void) memcpy(addr, rstrm->in_finger, len); 6837c478bd9Sstevel@tonic-gate rstrm->in_finger += len; 6847c478bd9Sstevel@tonic-gate addr += len; 6857c478bd9Sstevel@tonic-gate return (TRUE); 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate while (len > 0) { 6897c478bd9Sstevel@tonic-gate current = (intptr_t)rstrm->in_boundry - 6907c478bd9Sstevel@tonic-gate (intptr_t)rstrm->in_finger; 6917c478bd9Sstevel@tonic-gate if (current == 0) { 692*61961e0fSrobinson if (!fill_input_buf(rstrm, do_align)) 6937c478bd9Sstevel@tonic-gate return (FALSE); 6947c478bd9Sstevel@tonic-gate continue; 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate current = (len < current) ? len : current; 6977c478bd9Sstevel@tonic-gate (void) memcpy(addr, rstrm->in_finger, current); 6987c478bd9Sstevel@tonic-gate rstrm->in_finger += current; 6997c478bd9Sstevel@tonic-gate addr += current; 7007c478bd9Sstevel@tonic-gate len -= current; 7017c478bd9Sstevel@tonic-gate do_align = FALSE; 7027c478bd9Sstevel@tonic-gate } 7037c478bd9Sstevel@tonic-gate return (TRUE); 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate /* next four bytes of the input stream are treated as a header */ 7077c478bd9Sstevel@tonic-gate static bool_t 7087c478bd9Sstevel@tonic-gate set_input_fragment(RECSTREAM *rstrm) 7097c478bd9Sstevel@tonic-gate { 7107c478bd9Sstevel@tonic-gate uint32_t header; 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate if (rstrm->in_nonblock) { 7137c478bd9Sstevel@tonic-gate /* 7147c478bd9Sstevel@tonic-gate * In the non-blocking case, the fragment headers should 7157c478bd9Sstevel@tonic-gate * already have been consumed, so we should never get 7167c478bd9Sstevel@tonic-gate * here. Might as well return failure right away. 7177c478bd9Sstevel@tonic-gate */ 7187c478bd9Sstevel@tonic-gate return (FALSE); 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate if (!get_input_bytes(rstrm, (caddr_t)&header, (int)sizeof (header), 721*61961e0fSrobinson rstrm->last_frag)) 7227c478bd9Sstevel@tonic-gate return (FALSE); 7237c478bd9Sstevel@tonic-gate header = (uint32_t)ntohl(header); 7247c478bd9Sstevel@tonic-gate rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE; 7257c478bd9Sstevel@tonic-gate rstrm->fbtbc = header & (~LAST_FRAG); 7267c478bd9Sstevel@tonic-gate return (TRUE); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate /* consumes input bytes; knows nothing about records! */ 7307c478bd9Sstevel@tonic-gate static bool_t 7317c478bd9Sstevel@tonic-gate skip_input_bytes(RECSTREAM *rstrm, int32_t cnt) 7327c478bd9Sstevel@tonic-gate { 7337c478bd9Sstevel@tonic-gate int current; 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate while (cnt > 0) { 7367c478bd9Sstevel@tonic-gate current = (intptr_t)rstrm->in_boundry - 7377c478bd9Sstevel@tonic-gate (intptr_t)rstrm->in_finger; 7387c478bd9Sstevel@tonic-gate if (current == 0) { 739*61961e0fSrobinson if (!fill_input_buf(rstrm, FALSE)) 7407c478bd9Sstevel@tonic-gate return (FALSE); 7417c478bd9Sstevel@tonic-gate continue; 7427c478bd9Sstevel@tonic-gate } 7437c478bd9Sstevel@tonic-gate current = (cnt < current) ? cnt : current; 7447c478bd9Sstevel@tonic-gate rstrm->in_finger += current; 7457c478bd9Sstevel@tonic-gate cnt -= current; 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate return (TRUE); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate static bool_t 7527c478bd9Sstevel@tonic-gate __xdrrec_nonblock_realloc(RECSTREAM *rstrm, uint32_t newsize) 7537c478bd9Sstevel@tonic-gate { 7547c478bd9Sstevel@tonic-gate caddr_t newbuf = rstrm->in_base; 7557c478bd9Sstevel@tonic-gate ptrdiff_t offset; 7567c478bd9Sstevel@tonic-gate bool_t ret = TRUE; 7577c478bd9Sstevel@tonic-gate 7587c478bd9Sstevel@tonic-gate if (newsize > rstrm->recvsize) { 7597c478bd9Sstevel@tonic-gate newbuf = (caddr_t)realloc(newbuf, newsize); 7607c478bd9Sstevel@tonic-gate if (newbuf == 0) { 7617c478bd9Sstevel@tonic-gate ret = FALSE; 7627c478bd9Sstevel@tonic-gate } else { 7637c478bd9Sstevel@tonic-gate /* Make pointers valid for the new buffer */ 7647c478bd9Sstevel@tonic-gate offset = newbuf - rstrm->in_base; 7657c478bd9Sstevel@tonic-gate rstrm->in_finger += offset; 7667c478bd9Sstevel@tonic-gate rstrm->in_boundry += offset; 7677c478bd9Sstevel@tonic-gate rstrm->in_nextrec += offset; 7687c478bd9Sstevel@tonic-gate rstrm->in_base = newbuf; 7697c478bd9Sstevel@tonic-gate rstrm->recvsize = newsize; 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate 7737c478bd9Sstevel@tonic-gate return (ret); 7747c478bd9Sstevel@tonic-gate } 7757c478bd9Sstevel@tonic-gate 7767c478bd9Sstevel@tonic-gate /* 7777c478bd9Sstevel@tonic-gate * adjust sizes and allocate buffer quad byte aligned 7787c478bd9Sstevel@tonic-gate */ 7797c478bd9Sstevel@tonic-gate bool_t 7807c478bd9Sstevel@tonic-gate __xdrrec_set_conn_nonblock(XDR *xdrs, uint32_t tcp_maxrecsz) 7817c478bd9Sstevel@tonic-gate { 782*61961e0fSrobinson /* LINTED pointer cast */ 7837c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 7847c478bd9Sstevel@tonic-gate size_t newsize; 7857c478bd9Sstevel@tonic-gate 7867c478bd9Sstevel@tonic-gate rstrm->in_nonblock = TRUE; 7877c478bd9Sstevel@tonic-gate if (tcp_maxrecsz == 0) { 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * If maxrecsz has not been set, use the default 7907c478bd9Sstevel@tonic-gate * that was set from xdrrec_create() and 7917c478bd9Sstevel@tonic-gate * fix_buf_size() 7927c478bd9Sstevel@tonic-gate */ 7937c478bd9Sstevel@tonic-gate rstrm->in_maxrecsz = rstrm->recvsize; 7947c478bd9Sstevel@tonic-gate return (TRUE); 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate rstrm->in_maxrecsz = tcp_maxrecsz; 7977c478bd9Sstevel@tonic-gate if (tcp_maxrecsz <= rstrm->recvsize) 7987c478bd9Sstevel@tonic-gate return (TRUE); 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate /* 8017c478bd9Sstevel@tonic-gate * For nonblocked connection, the entire record is read into the 8027c478bd9Sstevel@tonic-gate * buffer before any xdr processing. This implies that the record 8037c478bd9Sstevel@tonic-gate * size must allow for the maximum expected message size of the 8047c478bd9Sstevel@tonic-gate * service. However, it's inconvenient to allocate very large 8057c478bd9Sstevel@tonic-gate * buffers up front, so we limit ourselves to a reasonable 8067c478bd9Sstevel@tonic-gate * default size here, and reallocate (up to the maximum record 8077c478bd9Sstevel@tonic-gate * size allowed for the connection) as necessary. 8087c478bd9Sstevel@tonic-gate */ 8097c478bd9Sstevel@tonic-gate if ((newsize = tcp_maxrecsz) > RPC_MAXDATASIZE) { 8107c478bd9Sstevel@tonic-gate newsize = RPC_MAXDATASIZE; 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate if (!__xdrrec_nonblock_realloc(rstrm, newsize)) { 8137c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, mem_err_msg_rec); 814*61961e0fSrobinson free(rstrm->out_base); 815*61961e0fSrobinson free(rstrm->in_base); 816*61961e0fSrobinson free(rstrm); 8177c478bd9Sstevel@tonic-gate return (FALSE); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate return (TRUE); 8217c478bd9Sstevel@tonic-gate } 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate /* 8247c478bd9Sstevel@tonic-gate * Retrieve input data from the non-blocking connection, increase 8257c478bd9Sstevel@tonic-gate * the size of the read buffer if necessary, and check that the 8267c478bd9Sstevel@tonic-gate * record size stays below the allowed maximum for the connection. 8277c478bd9Sstevel@tonic-gate */ 8287c478bd9Sstevel@tonic-gate bool_t 8297c478bd9Sstevel@tonic-gate __xdrrec_getbytes_nonblock(XDR *xdrs, enum xprt_stat *pstat) 8307c478bd9Sstevel@tonic-gate { 831*61961e0fSrobinson /* LINTED pointer cast */ 8327c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 8337c478bd9Sstevel@tonic-gate uint32_t prevbytes_thisrec, minreqrecsize; 8347c478bd9Sstevel@tonic-gate uint32_t *header; 835*61961e0fSrobinson int32_t len_received = 0; 836*61961e0fSrobinson uint32_t unprocessed = 0; 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate /* 8397c478bd9Sstevel@tonic-gate * For connection oriented protocols, there's no guarantee that 8407c478bd9Sstevel@tonic-gate * we will receive the data nicely chopped into records, no 8417c478bd9Sstevel@tonic-gate * matter how it was sent. We use the in_nextrec pointer to 8427c478bd9Sstevel@tonic-gate * indicate where in the buffer the next record starts. If 8437c478bd9Sstevel@tonic-gate * in_nextrec != in_base, there's data in the buffer from 8447c478bd9Sstevel@tonic-gate * previous reads, and if in_nextrecsz > 0, we need to copy 8457c478bd9Sstevel@tonic-gate * the portion of the next record already read to the start of 8467c478bd9Sstevel@tonic-gate * the input buffer 8477c478bd9Sstevel@tonic-gate */ 8487c478bd9Sstevel@tonic-gate if (rstrm->in_nextrecsz > 0) { 8497c478bd9Sstevel@tonic-gate /* Starting on new record with data already in the buffer */ 8507c478bd9Sstevel@tonic-gate (void) memmove(rstrm->in_base, rstrm->in_nextrec, 8517c478bd9Sstevel@tonic-gate rstrm->in_nextrecsz); 8527c478bd9Sstevel@tonic-gate rstrm->in_nextrec = rstrm->in_finger = rstrm->in_base; 8537c478bd9Sstevel@tonic-gate rstrm->in_boundry = rstrm->in_nextrec + rstrm->in_nextrecsz; 8547c478bd9Sstevel@tonic-gate unprocessed = rstrm->in_nextrecsz; 8557c478bd9Sstevel@tonic-gate rstrm->in_nextrecsz = 0; 8567c478bd9Sstevel@tonic-gate } else if (rstrm->in_nextrec == rstrm->in_base) { 8577c478bd9Sstevel@tonic-gate /* Starting on new record with empty buffer */ 8587c478bd9Sstevel@tonic-gate rstrm->in_boundry = rstrm->in_finger = rstrm->in_base; 8597c478bd9Sstevel@tonic-gate rstrm->last_frag = FALSE; 8607c478bd9Sstevel@tonic-gate rstrm->in_needpoll = TRUE; 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate 8637c478bd9Sstevel@tonic-gate prevbytes_thisrec = (uint32_t)(rstrm->in_boundry - rstrm->in_base); 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate /* Do we need to retrieve data ? */ 8667c478bd9Sstevel@tonic-gate if (rstrm->in_needpoll) { 8677c478bd9Sstevel@tonic-gate int len_requested, len_total_received; 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate rstrm->in_needpoll = FALSE; 8707c478bd9Sstevel@tonic-gate len_total_received = 8717c478bd9Sstevel@tonic-gate (int)(rstrm->in_boundry - rstrm->in_base); 8727c478bd9Sstevel@tonic-gate len_requested = rstrm->recvsize - len_total_received; 8737c478bd9Sstevel@tonic-gate /* 8747c478bd9Sstevel@tonic-gate * if len_requested is 0, this means that the input 8757c478bd9Sstevel@tonic-gate * buffer is full and need to be increased. 8767c478bd9Sstevel@tonic-gate * The minimum record size we will need is whatever's 8777c478bd9Sstevel@tonic-gate * already in the buffer, plus what's yet to be 8787c478bd9Sstevel@tonic-gate * consumed in the current fragment, plus space for at 8797c478bd9Sstevel@tonic-gate * least one more fragment header, if this is not the 8807c478bd9Sstevel@tonic-gate * last fragment. We use the RNDUP() macro to 8817c478bd9Sstevel@tonic-gate * account for possible realignment of the next 8827c478bd9Sstevel@tonic-gate * fragment header. 8837c478bd9Sstevel@tonic-gate */ 8847c478bd9Sstevel@tonic-gate if (len_requested == 0) { 8857c478bd9Sstevel@tonic-gate minreqrecsize = rstrm->recvsize + 8867c478bd9Sstevel@tonic-gate rstrm->fbtbc + 8877c478bd9Sstevel@tonic-gate (rstrm->last_frag ? 0 : sizeof (*header)); 8887c478bd9Sstevel@tonic-gate minreqrecsize = RNDUP(minreqrecsize); 8897c478bd9Sstevel@tonic-gate if (minreqrecsize == rstrm->recvsize) { 8907c478bd9Sstevel@tonic-gate /* 8917c478bd9Sstevel@tonic-gate * no more bytes to be consumed and 8927c478bd9Sstevel@tonic-gate * last fragment. We should never end up 8937c478bd9Sstevel@tonic-gate * here. Might as well return failure 8947c478bd9Sstevel@tonic-gate * right away. 8957c478bd9Sstevel@tonic-gate */ 8967c478bd9Sstevel@tonic-gate *pstat = XPRT_DIED; 8977c478bd9Sstevel@tonic-gate return (FALSE); 8987c478bd9Sstevel@tonic-gate } 899*61961e0fSrobinson if (minreqrecsize > rstrm->in_maxrecsz) 900*61961e0fSrobinson goto recsz_invalid; 901*61961e0fSrobinson else 902*61961e0fSrobinson goto needpoll; 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate if ((len_received = (*(rstrm->readit))(rstrm->tcp_handle, 9057c478bd9Sstevel@tonic-gate rstrm->in_boundry, len_requested)) == -1) { 9067c478bd9Sstevel@tonic-gate *pstat = XPRT_DIED; 9077c478bd9Sstevel@tonic-gate return (FALSE); 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate rstrm->in_boundry += len_received; 9107c478bd9Sstevel@tonic-gate rstrm->in_nextrec = rstrm->in_boundry; 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate /* Account for any left over data from previous processing */ 9147c478bd9Sstevel@tonic-gate len_received += unprocessed; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate /* Set a lower limit on the buffer space we'll need */ 9177c478bd9Sstevel@tonic-gate minreqrecsize = prevbytes_thisrec + rstrm->fbtbc; 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* 9207c478bd9Sstevel@tonic-gate * Consume bytes for this record until it's either complete, 9217c478bd9Sstevel@tonic-gate * rejected, or we need to poll for more bytes. 9227c478bd9Sstevel@tonic-gate * 9237c478bd9Sstevel@tonic-gate * If fbtbc == 0, in_finger points to the start of the fragment 9247c478bd9Sstevel@tonic-gate * header. Otherwise, it points to the start of the fragment data. 9257c478bd9Sstevel@tonic-gate */ 9267c478bd9Sstevel@tonic-gate while (len_received > 0) { 9277c478bd9Sstevel@tonic-gate if (rstrm->fbtbc == 0) { 9287c478bd9Sstevel@tonic-gate uint32_t hdrlen, minfraglen = 0; 9297c478bd9Sstevel@tonic-gate uint32_t len_recvd_thisfrag; 9307c478bd9Sstevel@tonic-gate bool_t last_frag; 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate len_recvd_thisfrag = (uint32_t)(rstrm->in_boundry - 9337c478bd9Sstevel@tonic-gate rstrm->in_finger); 934*61961e0fSrobinson /* LINTED pointer cast */ 9357c478bd9Sstevel@tonic-gate header = (uint32_t *)rstrm->in_finger; 9367c478bd9Sstevel@tonic-gate hdrlen = (len_recvd_thisfrag < sizeof (*header)) ? 9377c478bd9Sstevel@tonic-gate len_recvd_thisfrag : sizeof (*header); 938*61961e0fSrobinson (void) memcpy(&minfraglen, header, hdrlen); 9397c478bd9Sstevel@tonic-gate last_frag = (ntohl(minfraglen) & LAST_FRAG) != 0; 9407c478bd9Sstevel@tonic-gate minfraglen = ntohl(minfraglen) & (~LAST_FRAG); 9417c478bd9Sstevel@tonic-gate /* 9427c478bd9Sstevel@tonic-gate * The minimum record size we will need is whatever's 9437c478bd9Sstevel@tonic-gate * already in the buffer, plus the size of this 9447c478bd9Sstevel@tonic-gate * fragment, plus (if this isn't the last fragment) 9457c478bd9Sstevel@tonic-gate * space for at least one more fragment header. We 9467c478bd9Sstevel@tonic-gate * use the RNDUP() macro to account for possible 9477c478bd9Sstevel@tonic-gate * realignment of the next fragment header. 9487c478bd9Sstevel@tonic-gate */ 9497c478bd9Sstevel@tonic-gate minreqrecsize += minfraglen + 9507c478bd9Sstevel@tonic-gate (last_frag?0:sizeof (*header)); 9517c478bd9Sstevel@tonic-gate minreqrecsize = RNDUP(minreqrecsize); 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate if (hdrlen < sizeof (*header)) { 9547c478bd9Sstevel@tonic-gate /* 9557c478bd9Sstevel@tonic-gate * We only have a partial fragment header, 9567c478bd9Sstevel@tonic-gate * but we can still put a lower limit on the 9577c478bd9Sstevel@tonic-gate * final fragment size, and check against the 9587c478bd9Sstevel@tonic-gate * maximum allowed. 9597c478bd9Sstevel@tonic-gate */ 9607c478bd9Sstevel@tonic-gate if (len_recvd_thisfrag > 0 && 9617c478bd9Sstevel@tonic-gate (minreqrecsize > rstrm->in_maxrecsz)) { 9627c478bd9Sstevel@tonic-gate goto recsz_invalid; 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate /* Need more bytes to obtain fbtbc value */ 9657c478bd9Sstevel@tonic-gate goto needpoll; 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate /* 9687c478bd9Sstevel@tonic-gate * We've got a complete fragment header, so 9697c478bd9Sstevel@tonic-gate * 'minfraglen' is the actual fragment length, and 9707c478bd9Sstevel@tonic-gate * 'minreqrecsize' the requested record size. 9717c478bd9Sstevel@tonic-gate */ 9727c478bd9Sstevel@tonic-gate rstrm->last_frag = last_frag; 9737c478bd9Sstevel@tonic-gate rstrm->fbtbc = minfraglen; 9747c478bd9Sstevel@tonic-gate /* 9757c478bd9Sstevel@tonic-gate * Check that the sum of the total number of bytes read 9767c478bd9Sstevel@tonic-gate * so far (for the record) and the size of the incoming 9777c478bd9Sstevel@tonic-gate * fragment is less than the maximum allowed. 9787c478bd9Sstevel@tonic-gate * 9797c478bd9Sstevel@tonic-gate * If this is the last fragment, also check that the 9807c478bd9Sstevel@tonic-gate * record (message) meets the minimum length 9817c478bd9Sstevel@tonic-gate * requirement. 9827c478bd9Sstevel@tonic-gate * 9837c478bd9Sstevel@tonic-gate * If this isn't the last fragment, check for a zero 9847c478bd9Sstevel@tonic-gate * fragment length. Accepting such fragments would 9857c478bd9Sstevel@tonic-gate * leave us open to an attack where the sender keeps 9867c478bd9Sstevel@tonic-gate * the connection open indefinitely, without any 9877c478bd9Sstevel@tonic-gate * progress, by occasionally sending a zero length 9887c478bd9Sstevel@tonic-gate * fragment. 9897c478bd9Sstevel@tonic-gate */ 9907c478bd9Sstevel@tonic-gate if ((minreqrecsize > rstrm->in_maxrecsz) || 9917c478bd9Sstevel@tonic-gate (rstrm->last_frag && minreqrecsize < MIN_FRAG) || 9927c478bd9Sstevel@tonic-gate (!rstrm->last_frag && minfraglen == 0)) { 9937c478bd9Sstevel@tonic-gate recsz_invalid: 9947c478bd9Sstevel@tonic-gate rstrm->fbtbc = 0; 9957c478bd9Sstevel@tonic-gate rstrm->last_frag = 1; 9967c478bd9Sstevel@tonic-gate *pstat = XPRT_DIED; 9977c478bd9Sstevel@tonic-gate return (FALSE); 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate /* 10007c478bd9Sstevel@tonic-gate * Make this fragment abut the previous one. If it's 10017c478bd9Sstevel@tonic-gate * the first fragment, just advance in_finger past 10027c478bd9Sstevel@tonic-gate * the header. This avoids buffer copying for the 10037c478bd9Sstevel@tonic-gate * usual case where there's one fragment per record. 10047c478bd9Sstevel@tonic-gate */ 10057c478bd9Sstevel@tonic-gate if (rstrm->in_finger == rstrm->in_base) { 10067c478bd9Sstevel@tonic-gate rstrm->in_finger += sizeof (*header); 10077c478bd9Sstevel@tonic-gate } else { 10087c478bd9Sstevel@tonic-gate rstrm->in_boundry -= sizeof (*header); 10097c478bd9Sstevel@tonic-gate (void) memmove(rstrm->in_finger, 10107c478bd9Sstevel@tonic-gate rstrm->in_finger + sizeof (*header), 10117c478bd9Sstevel@tonic-gate rstrm->in_boundry - rstrm->in_finger); 10127c478bd9Sstevel@tonic-gate } 10137c478bd9Sstevel@tonic-gate /* Consume the fragment header */ 10147c478bd9Sstevel@tonic-gate if (len_received > sizeof (*header)) { 10157c478bd9Sstevel@tonic-gate len_received -= sizeof (*header); 10167c478bd9Sstevel@tonic-gate } else { 10177c478bd9Sstevel@tonic-gate len_received = 0; 10187c478bd9Sstevel@tonic-gate } 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate /* 10217c478bd9Sstevel@tonic-gate * Consume whatever fragment bytes we have. 10227c478bd9Sstevel@tonic-gate * If we've received all bytes for this fragment, advance 10237c478bd9Sstevel@tonic-gate * in_finger to point to the start of the next fragment 10247c478bd9Sstevel@tonic-gate * header. Otherwise, make fbtbc tell how much is left in 10257c478bd9Sstevel@tonic-gate * in this fragment and advance finger to point to end of 10267c478bd9Sstevel@tonic-gate * fragment data. 10277c478bd9Sstevel@tonic-gate */ 10287c478bd9Sstevel@tonic-gate if (len_received >= rstrm->fbtbc) { 10297c478bd9Sstevel@tonic-gate len_received -= rstrm->fbtbc; 10307c478bd9Sstevel@tonic-gate rstrm->in_finger += rstrm->fbtbc; 10317c478bd9Sstevel@tonic-gate rstrm->fbtbc = 0; 10327c478bd9Sstevel@tonic-gate } else { 10337c478bd9Sstevel@tonic-gate rstrm->fbtbc -= len_received; 10347c478bd9Sstevel@tonic-gate rstrm->in_finger += len_received; 10357c478bd9Sstevel@tonic-gate len_received = 0; 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate /* 10387c478bd9Sstevel@tonic-gate * If there's more data in the buffer, there are two 10397c478bd9Sstevel@tonic-gate * possibilities: 10407c478bd9Sstevel@tonic-gate * 10417c478bd9Sstevel@tonic-gate * (1) This is the last fragment, so the extra data 10427c478bd9Sstevel@tonic-gate * presumably belongs to the next record. 10437c478bd9Sstevel@tonic-gate * 10447c478bd9Sstevel@tonic-gate * (2) Not the last fragment, so we'll start over 10457c478bd9Sstevel@tonic-gate * from the top of the loop. 10467c478bd9Sstevel@tonic-gate */ 10477c478bd9Sstevel@tonic-gate if (len_received > 0 && rstrm->last_frag) { 10487c478bd9Sstevel@tonic-gate rstrm->in_nextrec = rstrm->in_finger; 10497c478bd9Sstevel@tonic-gate rstrm->in_nextrecsz = (uint32_t)(rstrm->in_boundry - 10507c478bd9Sstevel@tonic-gate rstrm->in_nextrec); 10517c478bd9Sstevel@tonic-gate len_received = 0; 10527c478bd9Sstevel@tonic-gate } 10537c478bd9Sstevel@tonic-gate } 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* Was this the last fragment, and have we read the entire record ? */ 10567c478bd9Sstevel@tonic-gate if (rstrm->last_frag && rstrm->fbtbc == 0) { 10577c478bd9Sstevel@tonic-gate *pstat = XPRT_MOREREQS; 10587c478bd9Sstevel@tonic-gate /* 10597c478bd9Sstevel@tonic-gate * We've been using both in_finger and fbtbc for our own 10607c478bd9Sstevel@tonic-gate * purposes. Now's the time to update them to be what 10617c478bd9Sstevel@tonic-gate * xdrrec_inline() expects. Set in_finger to point to the 10627c478bd9Sstevel@tonic-gate * start of data for this record, and fbtbc to the number 10637c478bd9Sstevel@tonic-gate * of bytes in the record. 10647c478bd9Sstevel@tonic-gate */ 10657c478bd9Sstevel@tonic-gate rstrm->fbtbc = (int)(rstrm->in_finger - 10667c478bd9Sstevel@tonic-gate rstrm->in_base - sizeof (*header)); 10677c478bd9Sstevel@tonic-gate rstrm->in_finger = rstrm->in_base + sizeof (*header); 10687c478bd9Sstevel@tonic-gate if (rstrm->in_nextrecsz == 0) 10697c478bd9Sstevel@tonic-gate rstrm->in_nextrec = rstrm->in_base; 10707c478bd9Sstevel@tonic-gate return (TRUE); 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate needpoll: 10737c478bd9Sstevel@tonic-gate /* 10747c478bd9Sstevel@tonic-gate * Need more bytes, so we set the needpoll flag, and go back to 10757c478bd9Sstevel@tonic-gate * the main RPC request loop. However, first we reallocate the 10767c478bd9Sstevel@tonic-gate * input buffer, if necessary. 10777c478bd9Sstevel@tonic-gate */ 10787c478bd9Sstevel@tonic-gate if (minreqrecsize > rstrm->recvsize) { 10797c478bd9Sstevel@tonic-gate if (!__xdrrec_nonblock_realloc(rstrm, minreqrecsize)) { 10807c478bd9Sstevel@tonic-gate rstrm->fbtbc = 0; 10817c478bd9Sstevel@tonic-gate rstrm->last_frag = 1; 10827c478bd9Sstevel@tonic-gate *pstat = XPRT_DIED; 10837c478bd9Sstevel@tonic-gate return (FALSE); 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate rstrm->in_needpoll = TRUE; 10887c478bd9Sstevel@tonic-gate *pstat = XPRT_MOREREQS; 10897c478bd9Sstevel@tonic-gate return (FALSE); 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate 10927c478bd9Sstevel@tonic-gate int 10937c478bd9Sstevel@tonic-gate __is_xdrrec_first(XDR *xdrs) 10947c478bd9Sstevel@tonic-gate { 1095*61961e0fSrobinson /* LINTED pointer cast */ 10967c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 10977c478bd9Sstevel@tonic-gate return ((rstrm->firsttime == TRUE) ? 1 : 0); 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate 11007c478bd9Sstevel@tonic-gate int 11017c478bd9Sstevel@tonic-gate __xdrrec_setfirst(XDR *xdrs) 11027c478bd9Sstevel@tonic-gate { 1103*61961e0fSrobinson /* LINTED pointer cast */ 11047c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate /* 11077c478bd9Sstevel@tonic-gate * Set rstrm->firsttime only if the input buffer is empty. 11087c478bd9Sstevel@tonic-gate * Otherwise, the first read from the network could skip 11097c478bd9Sstevel@tonic-gate * a poll. 11107c478bd9Sstevel@tonic-gate */ 11117c478bd9Sstevel@tonic-gate if (rstrm->in_finger == rstrm->in_boundry) 11127c478bd9Sstevel@tonic-gate rstrm->firsttime = TRUE; 11137c478bd9Sstevel@tonic-gate else 11147c478bd9Sstevel@tonic-gate rstrm->firsttime = FALSE; 11157c478bd9Sstevel@tonic-gate return (1); 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate int 11197c478bd9Sstevel@tonic-gate __xdrrec_resetfirst(XDR *xdrs) 11207c478bd9Sstevel@tonic-gate { 1121*61961e0fSrobinson /* LINTED pointer cast */ 11227c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate rstrm->firsttime = FALSE; 11257c478bd9Sstevel@tonic-gate return (1); 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate static uint_t 11307c478bd9Sstevel@tonic-gate fix_buf_size(uint_t s) 11317c478bd9Sstevel@tonic-gate { 11327c478bd9Sstevel@tonic-gate if (s < 100) 11337c478bd9Sstevel@tonic-gate s = 4000; 1134*61961e0fSrobinson return (RNDUP(s)); 11357c478bd9Sstevel@tonic-gate } 11367c478bd9Sstevel@tonic-gate 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate 11397c478bd9Sstevel@tonic-gate static bool_t 11407c478bd9Sstevel@tonic-gate xdrrec_control(XDR *xdrs, int request, void *info) 11417c478bd9Sstevel@tonic-gate { 1142*61961e0fSrobinson /* LINTED pointer cast */ 11437c478bd9Sstevel@tonic-gate RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private); 11447c478bd9Sstevel@tonic-gate xdr_bytesrec *xptr; 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate switch (request) { 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate case XDR_GET_BYTES_AVAIL: 11497c478bd9Sstevel@tonic-gate /* Check if at end of fragment and not last fragment */ 11507c478bd9Sstevel@tonic-gate if ((rstrm->fbtbc == 0) && (!rstrm->last_frag)) 11517c478bd9Sstevel@tonic-gate if (!set_input_fragment(rstrm)) { 11527c478bd9Sstevel@tonic-gate return (FALSE); 11537c478bd9Sstevel@tonic-gate }; 11547c478bd9Sstevel@tonic-gate 11557c478bd9Sstevel@tonic-gate xptr = (xdr_bytesrec *)info; 11567c478bd9Sstevel@tonic-gate xptr->xc_is_last_record = rstrm->last_frag; 11577c478bd9Sstevel@tonic-gate xptr->xc_num_avail = rstrm->fbtbc; 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate return (TRUE); 11607c478bd9Sstevel@tonic-gate default: 11617c478bd9Sstevel@tonic-gate return (FALSE); 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate } 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate } 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate static struct xdr_ops * 1168*61961e0fSrobinson xdrrec_ops(void) 11697c478bd9Sstevel@tonic-gate { 11707c478bd9Sstevel@tonic-gate static struct xdr_ops ops; 11717c478bd9Sstevel@tonic-gate extern mutex_t ops_lock; 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY ops_lock: ops */ 11747c478bd9Sstevel@tonic-gate 1175*61961e0fSrobinson (void) mutex_lock(&ops_lock); 11767c478bd9Sstevel@tonic-gate if (ops.x_getlong == NULL) { 11777c478bd9Sstevel@tonic-gate ops.x_getlong = xdrrec_getlong; 11787c478bd9Sstevel@tonic-gate ops.x_putlong = xdrrec_putlong; 11797c478bd9Sstevel@tonic-gate ops.x_getbytes = xdrrec_getbytes; 11807c478bd9Sstevel@tonic-gate ops.x_putbytes = xdrrec_putbytes; 11817c478bd9Sstevel@tonic-gate ops.x_getpostn = xdrrec_getpos; 11827c478bd9Sstevel@tonic-gate ops.x_setpostn = xdrrec_setpos; 11837c478bd9Sstevel@tonic-gate ops.x_inline = xdrrec_inline; 11847c478bd9Sstevel@tonic-gate ops.x_destroy = xdrrec_destroy; 11857c478bd9Sstevel@tonic-gate ops.x_control = xdrrec_control; 11867c478bd9Sstevel@tonic-gate #if defined(_LP64) 11877c478bd9Sstevel@tonic-gate ops.x_getint32 = xdrrec_getint32; 11887c478bd9Sstevel@tonic-gate ops.x_putint32 = xdrrec_putint32; 11897c478bd9Sstevel@tonic-gate #endif 11907c478bd9Sstevel@tonic-gate } 1191*61961e0fSrobinson (void) mutex_unlock(&ops_lock); 11927c478bd9Sstevel@tonic-gate return (&ops); 11937c478bd9Sstevel@tonic-gate } 1194