xdr_rec_subr.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
*/
#include "rac_private.h"
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#ifndef NDEBUG
#include <stdio.h>
#endif
#include <malloc.h>
#include <tiuser.h>
/*
* This file supports the reading of packets for multiple recipients on a
* single virtual circuit. Demultiplexing is done at a higher level based
* on RPC XIDs. All packets are assumed to be in RPC record marking
* format (see the ``RECORD MARKING STANDARD'' in RFC 1057).
*
* We export three functions:
*
* pkt_vc_poll(): assemble a packet by fetching each fragment
* header, then the data associated with the
* fragment. Returns (void *)0 when the packet
* is not yet complete, and an opaque handle for
* use by pkt_vc_read() when a complete packet
* has been collected.
*
* pkt_vc_read(): read from a packet (whose representation is
* described below) constructed by pkt_vc_poll().
*
* free_pkt(): free a packet constructed by pkt_vc_poll().
*/
#define FRAGHEADER_SIZE (sizeof (int)) /* size of XDR frag header */
/*
* A packet consists of one or more RPC record marking fragments.
* We represent this structure with a packet header and one or more
* fragment headers.
*
* Buffer headers are allocated on each t_rcv() and contain information
* about that t_rcv() (such as the amount and location of the data).
* They in turn point to buffers, which are shared and reference-counted.
*
* ... ...
* ^ ^
* | fh_next | bh_next
* | |
* frag header --> buf header --> buffer
* ^ ^
* | fh_next | bh_next
* | |
* packet header --> frag header --> buf header --> buffer
* pkt_fragp fh_bhp bh_bufp
*
*/
struct pkthdr {
};
struct fraghdr {
/* did an error occur reading this frag? */
int fh_terrno; /* copy of t_errno from read error */
};
struct bufhdr {
char *bh_begin; /* first byte of buffer */
char *bh_end; /* next read position */
};
struct buf {
char *buf_buf; /* pointer to the actual data area */
};
struct readinfo {
};
struct pollinfo {
};
static struct pollinfo *alloc_pollinfo(void);
static struct pkthdr *alloc_pkthdr(void);
static void free_pkthdr(struct pkthdr *);
static struct fraghdr *alloc_fraghdr(void);
static void free_fraghdr(struct fraghdr *);
static struct bufhdr *alloc_bufhdr(void);
static void free_bufhdr(struct bufhdr *);
#ifdef PRINTFS
#endif
void *
{
register int nread;
int flags;
static uint_t min_bytesfree;
int selerr;
/* minimum usable buffer space */
assert(min_bytesfree != 0);
}
if (*pollinfop == (void *)0) {
pi = alloc_pollinfo();
return ((void *)0);
else
} else
selerr = -1;
break;
}
#ifdef PRINTFS
printf("pkt_vc_poll: poll returned > 0\n");
#endif
/*
* Either we've never read a fragment or we've finished
* reading an entire one and are ready to start the
* next one. We stay in this state until we know we've
* gotten an entire XDR record header.
*/
case (int)BEGINNING_OF_FRAG:
/*
* If there's no packet present (then why did
* select() return positive status?), or if
* the amount of data doesn't exceed the size
* of the XDR record header size, try again later.
*/
return ((void *)0);
if (nreadable < FRAGHEADER_SIZE)
return ((void *)0);
/*
* Enough data have arrived to read a fragment
* header. If this is the first fragment, we
* have to allocate a packet header.
*/
if (!pi->pi_curphdr) {
if (!pi->pi_curphdr)
return ((void *)0);
}
/*
* Allocate a fragment header. If this is not the
* first fragment in this packet, add it on the
* end of the fragment chain.
*/
if (!pi->pi_curfhdr) {
#ifdef PRINTFS
printf("pkt_vc_poll (before alloc_fraghdr): pi->pi_curphdr 0x%p\n",
pi->pi_curphdr);
#endif
#ifdef PRINTFS
printf("pkt_vc_poll (after alloc_fraghdr): pi->pi_curphdr 0x%p\n",
pi->pi_curphdr);
#endif
if (pi->pi_curfhdr)
pi->pi_curfhdr;
else
return ((void *)0);
} else {
fhp = alloc_fraghdr();
if (fhp) {
} else
return ((void *)0);
}
/*
* We allocate a new buffer when there's less than
* min_bytesfree bytes of data left in the current
* buffer (or, of course, if there is no buffer at
* all).
*/
min_bytesfree)) {
if (buf)
else
return ((void *)0);
}
/*
* A buffer header is allocated for each t_rcv()
* we do.
*/
bhdr = alloc_bufhdr();
if (!bhdr)
return ((void *)0);
if (pi->pi_curbhdr) {
} else {
/* XXX why are these asserts commented out? */
/*
* assert(pi->pi_curbuf->buf_refcnt == 0);
* assert(pi->pi_curbuf->buf_bytesused == 0);
*/
}
/*
* We read the fragment into a temporary because
* we want to access it as a longword and data in
* the buffer aren't guaranteed to be properly
* aligned. Later we'll copy it from the temp to
* the buffer.
*/
FRAGHEADER_SIZE, &flags);
#ifdef PRINTFS
#endif
/*
* Deal with short reads or errors.
*/
if (nread == 0) {
*pollinfop = (void *)0;
}
if (nread == -1) {
case T_DISCONNECT:
break;
case T_ORDREL:
/* Received orderly release indication */
/* Send orderly release indicator */
break;
default:
break;
}
*pollinfop = (void *)0;
}
if (fragheader & FH_LASTFRAG)
else
/*
* A fragment header's size doesn't include the
* header itself, so we must manually adjust the
* true size.
*/
#ifdef PRINTFS
printf("pkt_vc_poll: morefrags %d, frag size %d\n",
#endif
break;
/*
* We've received a complete RPC record header, and now
* know how much more data to expect from this fragment.
*/
case (int)NORMAL:
bhdr = alloc_bufhdr();
if (!bhdr)
return ((void *)0);
if (!buf)
return ((void *)0);
} else
#ifdef PRINTFS
printf("pkt_vc_poll: case NORMAL: t_rcv(%d, 0x%p, %d, &flags)",
#endif
#ifdef PRINTFS
#endif
/*
* Deal with short reads or errors.
*/
if (nread == 0) {
*pollinfop = (void *)0;
}
if (nread == -1) {
return ((void *)0);
}
/*
* Got an entire fragment. See whether we've got
* the entire packet.
*/
#ifdef PRINTFS
printf("pkt_vc_poll: fragsize %u, fh_nbytes %u\n",
#endif
#ifdef PRINTFS
#endif
*pollinfop = (void *)0;
}
}
break;
}
}
#ifdef PRINTFS
if (selerr == -1)
else
#endif
return ((void *)0);
}
int
{
register int bytes_read, xferbytes;
#ifdef PRINTFS
#endif
} else {
#ifdef PRINTFS
printf("pkt_vc_read: no fragments; returning 0\n");
printf("pkt_vc_read: ci_readinfo <- 0\n");
#endif
*ripp = (void *)0;
return (0);
}
}
#ifdef PRINTFS
printf("pkt_vc_read: no buf headers; returning 0\n");
printf("pkt_vc_read: ci_readinfo <- 0\n");
#endif
*ripp = (void *)0;
return (0);
}
}
/* lastfhp = fhp; */
#ifdef PRINTFS
#endif
bytes_read += xferbytes;
}
#ifdef PRINTFS
else
#endif
}
}
#ifdef PRINTFS
#endif
#ifdef PRINTFS
printf("pkt_vc_read: lastfhp 0x%p, lastfhp->fh_error TRUE,"
#endif
#ifdef PRINTFS
printf("pkt_vc_read: ci_readinfo <- 0\n");
#endif
*ripp = (void *)0;
return (-1);
}
if (len > 0) {
#ifdef PRINTFS
printf("pkt_vc_read: ci_readinfo <- 0\n");
#endif
*ripp = (void *)0;
}
return (bytes_read);
}
{
if (ri) {
& (sizeof (uint_t) - 1))) == 0);
FRAGHEADER_SIZE)));
return (xid);
}
}
}
}
return (0);
}
void
{
if (--bp->buf_refcnt == 0) {
}
}
}
}
}
static struct pollinfo *
{
}
void
free_pollinfo(void *pi)
{
}
static struct pkthdr *
{
}
static void
{
}
#ifdef PRINTFS
static void
{
}
printf("\tNULL\n");
}
}
#endif
static struct fraghdr *
{
}
static void
{
}
static struct bufhdr *
{
}
static void
{
}
static struct buf *
{
if (bp) {
bp->buf_refcnt = 0;
bp->buf_bytesused = 0;
}
return (bp);
}
static void
{
}