Streams Loop-Around driver...

Geoff Kuenning geoff at desint.UUCP
Fri Jan 23 17:09:38 AEST 1987


In article <1341 at cadovax.UUCP> mitchell at cadovax.UUCP (Mitchell Lerner) writes:

> Is the Loop-Around driver as shown in the the System V version 3 Streams 
> Programmers Guide in chapter 12 a way that I can do inter-process 
> communication?  I'm not sure that you can actually open the driver from streams
> on two separate processes (or more?) and have the driver connect the two 
> streams.  Can I use this type of Streams driver as the basis for an inter-
> process communications facility?

Yes, except that you are better off using the "stream pipe" driver, "sp.c",
that comes with V.3.  Sp.c works by cross-linking stream structures, so it
is more efficient.

The sp driver performs the cross-link when an M_PROTO (I think that's
the right one) control message is sent.  The control message contains
a pointer to the other stream which is to be cross-linked;  this pointer
is generated using the I_PASSFP (pass file pointer) ioctl.  (The details
are undocumented;  what you need to know is that the message contains
the file pointer at offset zero and nothing else.)

The tricky part is that I_PASSFP needs to be sent by someone who has
an fd for the relevant stream.  To make things clearer, here is the
single-process case (the funny ioctl syntax is because the info actually
goes through a structure, and I don't remember details):

	fd 4 (e.g.)			    fd 5 (e.g.)
	    |					|
	    |					V
	    |				ioctl (5, I_PASSFP (..., 4))
	    |					|
	    V					V
	Stream A			    Stream B

When the PASSFP of fd 4 is sent on fd 5, the cross-link happens and
everything is hunky-dory.  This is very easy to arrange in a single
process, and you then have a two-way stream pipe that can be used much
like a regular pipe, notably by forking children.  Careful attention to
open modes can even make it into a one-way pipe.

The no-common-ancestor case is a bit trickier.  What saves you is that
the I_PASSFP ioctl can be used to pass a file pointer in a data message,
which can be read by another process.  Here's how I did it for LX-Windows,
for Locus Computing Corp:

	Server:

	(1) Open up a pair of well-known sp minor numbers (I use the highest
	    two in the sp minor list, e.g., 30 and 31 for 32 sp's) and
	    cross-link them.
	(2) Enter main "listening" loop.  One of the well-known devices is
	    held open, but otherwise ignored.  The other is the "connection
	    request" device;  the server listens on this stream for new
	    clients.  We will assume that 31 is the device the server
	    listens on.  (Actually, I give them mnemonic names in /dev).

	Client:

	(3) Open the well-known "request" device (minor 30).  Also open up
	    an unused 'sp' minor number, creating it with the clone driver.
	    Say we get minor 0.
	(4) Send a single byte on the "request" device, minor 30.  The
	    contents do not matter.

	Server:

	(5) When a request byte arrives on minor 31, open up another unused
	    'sp' minor number with the clone driver.  Call this minor 1,
	    and suppose it gets fd 9.
	(6) Using an I_PASSFP ioctl, send the address of minor 1 (fd 9)'s
	    data structures back out on minor 31 as a *data* message.
	    Note that, in the case of simultaneous requests by multiple
	    clients, we are not sure which client this will go to.
	    However, it turns out that this doesn't hurt us.

	Client:

	(7) Read the PASSFP message from minor 30.  Since it is a data
	    message, you will receive the value of a kernel pointer
	    to a stream structure.
	(8) Using the pointer from step 7, create an M_PROTO message
	    and send it on minor 0, which we opened in step 3.  This
	    message is *not* sent with I_PASSFP;  instead it is sent
	    as an ordinary M_PROTO control message.  The sp driver will
	    see this message and cross-link minor 0 to minor 1 (because
	    minor 1 was the pointer passed in step 6).
	(9) Close the well-known request device (minor 30).

The ugly thing about this is that steps 7 and 8 actually take a kernel
pointer and pass it back to the kernel via the client process.  The
REALLY UGLY thing about this is that the sp driver does not do any checking
for the validity of the pointer;  it grabs it from the message and
promptly dereferences it.  This is obviously a security hole that you
will want to fix if you plan to ship 'sp.c'.

One last note:  the stream buffer allocation scheme is simply stupid in
combination with the high/low water mechanism.  I won't go into details,
but if you send a lot of small packets that clog up, you will exhaust
the stream buffer pool long before you hit the high-water mark.  In our
case, the X clients used up the pool with line-drawing requests, and
the server then couldn't get a buffer to post a mouse-click event that
was necessary to terminate the line-drawing requests!
-- 

	Geoff Kuenning
	{hplabs,ihnp4}!trwrb!desint!geoff



More information about the Comp.unix.wizards mailing list