STREAMS Programming Guide

Receiving Data

The final routine in Example 3–4, inter_rcv, retrieves the next available data. buf points to a buffer where the data should be stored, len indicates the size of that buffer, and addr points to a long integer where the source address of the data is placed. On successful completion, inter_rcv returns the number of bytes of retrieved data; on failure, it returns -1 and an appropriate UNIX system error value.


Example 3–4 Receiving Data

int inter_rcv (int fd, char *buf, int len, long *addr, int *errorp)
{
 	struct strbuf ctlbuf;
 	struct strbuf databuf;
 	struct unitdata_ind unitdata_ind;
 	int retval;
 	int flagsp;

	ctlbuf.maxlen = sizeof(struct unitdata_ind);
	ctlbuf.len = 0;
	ctlbuf.buf = (char *)&unitdata_ind;
	databuf.maxlen = len;
	databuf.len = 0;
	databuf.buf = buf;
	flagsp = 0;

	if((retval=getmsg(fd,&ctlbuf,&databuf,&flagsp))<0) {
			*errorp = EIO;
			return(-1);
	}
	if (retval) {
			*errorp = EIO;
			return(-1)
	}
	if (unitdata_ind.PRIM_type != UNITDATA_IND) {
			*errorp = EPROTO;
			return(-1);
	}
	*addr = unitdata_ind.SRC_addr;
	return(databuf.len);
}

getmsg is called to retrieve the data indication primitive, where that primitive contains both a control and data part. The control part consists of a unitdata_ind structure that identifies the primitive type and the source address of the data sender. The data part contains the data itself. In ctlbuf, buf points to a buffer containing the control information, and maxlen indicates the maximum size of the buffer. Similar initialization is done for databuf.

The integer pointed to by flagsp in the getmsg call is set to zero, indicating that the next message should be retrieved from the stream head regardless of its priority. Data arrives in normal priority messages. If there is no message at the stream head, getmsg blocks until a message arrives.

The user's control and data buffers should be large enough to hold any incoming data. If both buffers are large enough, getmsg processes the data indication and returns 0, indicating that a full message was retrieved successfully. However, if neither buffer is large enough, getmsg only returns the part of the message that fits into each user buffer. The remainder of the message is saved for subsequent retrieval (in message non-discard mode), and a positive, nonzero value is returned to the user. A return value of MORECTL indicates that more control information is waiting for retrieval. A return value of MOREDATA indicates that more data is waiting for retrieval. A return value of (MORECTL | MOREDATA) indicates that data from both parts of the message remain. In the example, if the user buffers are not large enough (that is, getmsg returns a positive, nonzero value), the function sets errno to EIO and fails.

The type of the primitive returned by getmsg is checked to make sure it is a data indication (UNITDATA_IND in the example). The source address is then set and the number of bytes of data is returned.

The example presented is a simplified service interface. It shows typical uses of putmsg(2) and getmsg(2). The state transition rules for the interface are not presented and this example does not handle expedited data.