STREAMS Programming Guide

Accessing the Service Provider

The first routine presented, inter_open, opens the protocol driver device file specified by path and binds the protocol address contained in addr so that it can receive data. On success, the routine returns the file descriptor associated with the open stream; on failure, it returns -1 and sets errno to indicate the appropriate UNIX system error value. Example 3-1 shows the inter_open routine.


Example 3-1 inter_open Routine

inter_open (char *path, oflags, addr)
{
 	intt fd;
 	struct bind_req bind_req;
 	struct strbuf ctlbuf;
 	union  primitives rcvbuf;
 	struct error_ack *error_ack;
 	int flags;

		if ((fd = open(path, oflags)) < 0)
			return(-1);

	/* send bind request msg down stream */

		bind_req.PRIM_type = BIND_REQ;
 	bind_req.BIND_addr = addr;
 	ctlbuf.len = sizeof(struct bind_req);
 	ctlbuf.buf = (char *)&bind_req;

		if (putmsg(fd, &ctlbuf, NULL, 0) < 0) {
			close(fd);
			return(-1);
		}
}

After opening the protocol driver, inter_open packages a bind request message to send downstream. putmsg is called to send the request to the service provider. The bind request message contains a control part that holds a bind_req structure, but it has no data part. ctlbuf is a structure of type strbuf, and it is initialized with the primitive type and address. Notice that the maxlen field of ctlbuf is not set before calling putmsg. That is because putmsg ignores this field. The dataptr argument to putmsg is set to NULL to indicate that the message contains no data part. The flags argument is 0, which specifies that the message is not a high-priority message.

After inter_open sends the bind request, it must wait for an acknowledgment from the service provider, as Example 3-2 shows:


Example 3-2 Service Provider

/* wait for ack of request */

 ctlbuf.maxlen = sizeof(union primitives);
 ctlbuf.len = 0;
 ctlbuf.buf = (char *)&rcvbuf;
 flags = RS_HIPRI;

 if (getmsg(fd, &ctlbuf, NULL, &flags) < 0) {
 	close(fd);
 	return(-1);
}

 /* did we get enough to determine type? */
 if (ctlbuf.len < sizeof(long)) {
 	close(fd);
 	errno = EPROTO;
 	return(-1);
}

 /* switch on type (first long in rcvbuf) */
 	switch(rcvbuf.type) {
 	default:
 			close(fd);
 			errno = EPROTO;
 			return(-1);

	case OK_ACK:
 			return(fd);

	case ERROR_ACK:
 			if (ctlbuf.len < sizeof(struct error_ack)) {
 				close(fd);
 				errno = EPROTO;
 				return(-1);
 			}
 			error_ack = (struct error_ack *)&rcvbuf;
 			close(fd);
 			errno = error_ack->UNIX_error;
 			return(-1);
	}
}

getmsg is called to retrieve the acknowledgment of the bind request. The acknowledgment message consists of a control part that contains either an OK_ACK or an error_ack structure, and no data part.

The acknowledgment primitives are defined as high-priority messages. Messages are queued in a first-in, first-out (FIFO) manner within their priority at the stream head; high-priority messages are placed at the front of the stream head queue, followed by priority band messages and ordinary messages. The STREAMS mechanism allows only one high-priority message per stream at the stream head at one time. Any additional high-priority messages are discarded on reaching the stream head. (There can be only one high-priority message present on the stream head read queue at any time.) High-priority messages are particularly suitable for acknowledging service requests when the acknowledgment should be placed ahead of any other messages at the stream head.

Before calling getmsg, this routine must initialize the strbuf structure for the control part. buf should point to a buffer large enough to hold the expected control part, and maxlen must be set to indicate the maximum number of bytes this buffer can hold.

Because neither acknowledgment primitive contains a data part, the dataptr argument to getmsg is set to NULL. The flagsp argument points to an integer containing the value RS_HIPRI. This flag indicates that getmsg should wait for a STREAMS high-priority message before returning. It is set because you want to catch the acknowledgment primitives that are priority messages. Otherwise, if the flag is zero, the first message is taken. With RS_HIPRI set, even if a normal message is available, getmsg blocks until a high-priority message arrives.

On return from getmsg, check the len field to ensure that the control part of the retrieved message is an appropriate size. The example then checks the primitive type and takes appropriate actions. An OK_ACK indicates a successful bind operation, and inter_open returns the file descriptor of the open stream. An error_ack indicates a bind failure, and errno is set to identify the problem with the request.