|
|
#include <sys/stropts.h> #include <sys/stream.h>
The STREAMS pipe device driver sp is accessed through the character special file /dev/spx. ioctl(2) commands for controlling the sp driver are described in the streamio(7) manual page. sp is an example of a ``clone'' device; successive open(2) calls on /dev/spx cause the driver to make available arbitrary and unique minor devices. (Clone devices represent all their minor devices using only one special file. See clone(7).)
Each open on /dev/spx returns a file descriptor to the stream head of a different loop-back driver (input on the descriptor is echoed straight back as output that can be read from the descriptor).
Unnamed stream pipes may be used whenever a parent process needs to establish full-duplex communication between itself and a child process yet to be spawned. The parent process opens /dev/spx twice; the two file descriptors returned each point to the stream head of a loop-back driver. The parent then connects the two loop-back drivers using the I_FDINSERT ioctl. A write to either descriptor can then be read from the other. After the parent forks, it closes one file descriptor and the child closes the other. Parent and child communicate by writing to or reading from the remaining descriptor. (If necessary, the I_SRDOPT ioctl command can be used to change read modes.)
Named stream pipes allow full-duplex communication between an arbitrary pair of processes (that are not necessarily parent and child). A named stream pipe is created by calling mknod(2) to bind a name to a unnamed stream pipe. The mknod system call, however, requires root privilege to create this file type. An auxiliary program can be used to create the named stream pipe provided that it has set it has root credentials. Any process may then open(2) the named stream pipe and write to it, subject to the normal filesystem permissions. The named stream pipe remains in existence after the process that created it exits.
File descriptors can be sent from one process to another down a stream pipe. Descriptors are sent and received using the I_SENDFD and I_RECVFD ioctl commands. The receiving process also has access to the credentials of the sending process if these are needed for the purpose of security.
Typically, a network server daemon would first create and open a named stream pipe. A client opens the named pipe and sends a message to the server requesting connection; the server establishes the connection by sending a file descriptor down the pipe.
Extra functionality can be added to a stream pipe by pushing further STREAMS modules onto it.
Developing STREAMS modules and drivers in Developing STREAMS modules and drivers
#include <unistd.h> #include <sys/types.h> #include <sys/fcntl.h> #include <sys/stream.h> #include <sys/stropts.h> #include <sys/stat.h> #include <termio.h> #include <signal.h> #define SPX "/dev/spx"A routine to create a named stream pipe from a unnamed one (this requires root privilege):int spipe(fd) int *fd; { struct strfdinsert s; long p;
if ( ( fd[0] = open(SPX, O_RDWR) ) < 0 ) return(-1); if ( ( fd[1] = open(SPX, O_RDWR) ) < 0 ) /* open different minor */ return(-1);
s.ctlbuf.buf = (caddr_t) &p ; s.ctlbuf.maxlen = s.ctlbuf.len = sizeof(long); s.databuf.buf = (caddr_t) NULL; s.databuf.maxlen = s.databuf.len = -1; s.fildes = fd[1]; s.offset = s.flags = 0;
if ( ioctl(fd[0], I_FDINSERT, &s) < 0 ) /* join loop drivers */ return(-1); return(0); }
int nspipe(fd, pipename) int *fd; char *pipename; { struct stat status; int omask;A routine to pass a file descriptor to another process:if ( spipe(fd) < 0 ) return(-1);
if ( fstat(fd[0],&status) < 0 ) return(-1);
unlink(pipename); omask = umask(0); if ( mknod(pipename, S_IFCHR|0666, status.st_rdev) < 0 ) /* create node */ return(-1); umask(omask);
return(0); }
int passfd(fd, sendfd) int fd, sendfd; { if ( ioctl(fd, I_SENDFD, sendfd) < 0 ) /* send descriptor sendfd */ return(-1); }A routine to receive a file descriptor from a process:
int recvfd(fd) int fd; { struct strrecvfd s;if ( ioctl(fd, I_RECVFD, (char *) &s) < 0 ) return(-1);
/* s.uid received effective user ID of sender s.gid received effective group ID of sender */ return(s.fd); /* received file descriptor */ }