spx -- STREAMS bi-directional pipe device


#include  <sys/stropts.h>
#include  <sys/stream.h>


A stream pipe provides a full-duplex communication path between two processes, and allows the passing of file descriptors. The processes can communicate over a stream pipe using ordinary read(S) and write(S) system calls. Stream pipes are used by dbxtra(CP) and the X server.

The STREAMS pipe device driver sp is accessed through the character special file /dev/spx. ioctl(S) commands for controlling the sp driver are described in the streamio(M) manual page. sp is an example of a ``clone'' device; successive open(S) 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(M).)

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 command (see streamio(M)). 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(S) 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 its effective user ID to root. Any process may then open 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 effective user and group IDs 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.


CONFIG: sp: spclose - Cannot allocate STREAMS block
CONFIG: sp: spopen - Cannot allocate STREAMS block
A STREAMS message block could not be allocated. You may need to increase the value of NSTRPAGES, the maximum amount of memory that STREAMS will use. This tunable kernel parameter uses units of 4KB pages. The default value is 125 pages (500KB); this can be increased with configure(ADM).


A routine to create an unnamed bi-directional stream pipe in the manner of pipe(S):
#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"

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); }

A routine to create a named stream pipe from a unnamed one (this requires root privilege):
   int nspipe(fd, pipename)
   int *fd;
   char *pipename;
     struct stat status;
     int omask;

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); }

A routine to pass a file descriptor to another process:
   int passfd(fd, sendfd)
   int fd, sendfd;
      if ( ioctl(fd, I_SENDFD, sendfd) < 0 ) /* send descriptor sendfd */
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 */ }


/dev/spx must exist and the sp driver must be linked into the kernel before stream pipes can be used. The sp driver is part of the standard distribution, however, the special file /dev/spx is not. (Note that /dev/spx is created if you install TCP/IP.) Use the mknod(C) command to create /dev/spx:

/etc/mknod /dev/spx c 40 60

Here it is assumed that /etc/conf/cf.d/mdevice defines sp as using major device number 40.


sp STREAMS pipe driver special file (minor device number 60)

See also

Intro(S), clone(M), close(S), getmsg(S), ioctl(S), mknod(S), open(S), pipe(S), putmsg(S), read(S), streamio(M), write(S)

AT&T STREAMS Programmer's Guide

Standards conformance

spx is conformant with AT&T SVID Issue 2.
© 2003 Caldera International, Inc. All rights reserved.
SCO OpenServer Release 5.0.7 -- 11 February 2003