STREAMS Programming Guide

Using Anchors

An anchor can be placed on a STREAMS module by adding an [anchor] flag to an autopush configuration file or by directly calling the I_ANCHOR ioctl.

For example, this configuration file specifies that autopush should place an anchor between foo and babar in the bb stream:


#	major      minor       lastminor     modules

	aa         0           0             foo babar
	bb         0           1             foo [anchor] babar
	bb         131072      131073        foo [anchor] babar

The following two examples illustrate the use of anchors in a client/server setting in which file descriptors are being passed. They call the I_ANCHOR ioctl directly.

In this example, the server program, fd_server.c, opens a stream, pushes modules on to it, and places an anchor on rlmod. The client program, fd_client.c attempts to pop modules, but can only pop rlmod or any modules below it if the client is run as root. That is, if the client is run as non-root, the I_POP fails.

This example also shows that once the module with the anchor on it is popped by the privileged root process, the anchor is destroyed (technically, it is moved back to the driver, where it has no effect). Subsequent attempts by the client to pop modules will succeed, even if the client is run as non-root.

Finally, this example also illustrates the effect of passing file descriptors, rather than copying modules or the stream as a whole. Specifically, because the stream is not duplicated, all instances of the client operate on the same stream. In this case, running the client repeatedly causes it to work down the list of modules, popping each one off in turn, until all modules have been removed from the stream.


Example 11–4 STREAMS Anchors fd_server.c

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <stropts.h>
#include <sys/conf.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>

#define	SPIPE_PATH	"/tmp/mypipe"

int
main(void)
{
	int 			pipefd[2];
	struct strrecvfd	strrecvfd;
	int			streamfd;

	/*
	 * Open a stream to hand back to the client.  Since this
	 * is just an example, we don't really care what we open;
	 * make a rlmod<->udp<->ip stream.  Stick an anchor above
	 * rlmod so the client cannot I_POP rlmod unless it's root.
	 */
	streamfd = open("/dev/udp", O_RDWR);
	if (streamfd == -1) {
		perror("open");
		return (EXIT_FAILURE);
	}

	if (ioctl(streamfd, I_PUSH, "rlmod") == -1) {
		perror("ioctl (I_PUSH) rlmod");
		return (EXIT_FAILURE);
	}

	if (ioctl(streamfd, I_ANCHOR, 0) == -1) {
		perror("ioctl (I_ANCHOR)");
		return (EXIT_FAILURE);
	}

	/*
	 * Open ourselves for business by making a mounted stream.
	 */
	if (pipe(pipefd) == -1) {
		perror("pipe");
		return (EXIT_FAILURE);
	}

	if (ioctl(pipefd[1], I_PUSH, "connld") == -1) {
		perror("ioctl (I_PUSH) connld");
		return (EXIT_FAILURE);
	}

	(void) umask(0);
	(void) close(creat(SPIPE_PATH, 0666));

	if (fattach(pipefd[1], SPIPE_PATH) == -1) {
		perror("fattach");
		return (EXIT_FAILURE);
	}

	/*
	 * Accept clients (iterative server)
	 */
	for (;;) {

		if (ioctl(pipefd[0], I_RECVFD, &strrecvfd) == -1) {
			perror("ioctl (I_RECVFD)");
			return (EXIT_FAILURE);
		}

		/*
		 * Send the STREAMS descriptor back to the client.
		 */
		if (ioctl(strrecvfd.fd, I_SENDFD, streamfd) == -1) {
			perror("ioctl (I_SENDFD)");
			return (EXIT_FAILURE);
		}
	}
}


Example 11–5 STREAMS Anchors fd_client.c

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <stropts.h>
#include <sys/conf.h>
#include <unistd.h>
#include <stdlib.h>

#define	SPIPE_PATH	"/tmp/mypipe"

int
main(void)
{
	int 			serverfd;
	struct strrecvfd	strrecvfd;

	/*
	 * Open a connection to the server.
	 */
	serverfd = open(SPIPE_PATH, O_RDWR);
	if (serverfd == -1) {
		perror("open");
		return (EXIT_FAILURE);
	}

	/*
	 * Receive the STREAMS descriptor from the server.
	 */
	if (ioctl(serverfd, I_RECVFD, &strrecvfd) == -1) {
		perror("ioctl (I_RECVFD)");
		return (EXIT_FAILURE);
	}

	(void) printf("received the STREAMS descriptor; attempting to pop "
	    "the top module\n");

	/*
	 * Try to remove the top module from the stream.
	 */
	if (ioctl(strrecvfd.fd, I_POP, 0) == -1)
		perror("ioctl (I_POP)");

	(void) printf("modules on the stream: ");
	(void) fflush(stdout);

	/*
	 * Print out what the stream currently looks like.
	 */
	(void) dup2(strrecvfd.fd, 0);
	(void) system("strconf | paste -s -d' ' -");

	return (EXIT_SUCCESS);
}