4.2BSD/usr/doc/ipc/5.t

Compare this file to the similar file:
Show the results in this format:

.ds RH "Advanced Topics
.bp
.nr H1 5
.nr H2 0
.bp
.LG
.B
.ce
5. ADVANCED TOPICS
.sp 2
.R
.NL
.PP
A number of facilities have yet to be discussed.  For most users
of the ipc the mechanisms already
described will suffice in constructing distributed
applications.  However, others will find need to utilize some
of the features which we consider in this section.
.NH 2
Out of band data
.PP
The stream socket abstraction includes the notion of \*(lqout
of band\*(rq data.  Out of band data is a logically independent 
transmission channel associated with each pair of connected
stream sockets.  Out of band data is delivered to the user
independently of normal data along with the SIGURG signal.
In addition to the information passed, a logical mark is placed in
the data stream to indicate the point at which the out
of band data was sent.  The remote login and remote shell
applications use this facility to propagate signals from between
client and server processes.  When a signal is expected to
flush any pending output from the remote process(es), all
data up to the mark in the data stream is discarded.
.PP
The
stream abstraction defines that the out of band data facilities
must support the reliable delivery of at least one
out of band message at a time.  This message may contain at least one
byte of data, and at least one message may be pending delivery
to the user at any one time.  For communications protocols which
support only in-band signaling (i.e. the urgent data is
delivered in sequence with the normal data) the system extracts
the data from the normal data stream and stores it separately.
This allows users to choose between receiving the urgent data
in order and receiving it out of sequence without having to
buffer all the intervening data.
.PP
To send an out of band message the SOF_OOB flag is supplied to
a \fIsend\fP or \fIsendto\fP calls,
while to receive out of band data SOF_OOB should be indicated
when performing a \fIrecvfrom\fP or \fIrecv\fP call.
To find out if the read pointer is currently pointing at
the mark in the data stream, the SIOCATMARK ioctl is provided:
.DS
ioctl(s, SIOCATMARK, &yes);
.DE
If \fIyes\fP is a 1 on return, the next read will return data
after the mark.  Otherwise (assuming out of band data has arrived), 
the next read will provide data sent by the client prior
to transmission of the out of band signal.  The routine used
in the remote login process to flush output on receipt of an
interrupt or quit signal is shown in Figure 5.
.KF
.DS
oob()
{
	int out = 1+1;
	char waste[BUFSIZ], mark;

	signal(SIGURG, oob);
	/* flush local terminal input and output */
	ioctl(1, TIOCFLUSH, (char *)&out);
	for (;;) {
		if (ioctl(rem, SIOCATMARK, &mark) < 0) {
			perror("ioctl");
			break;
		}
		if (mark)
			break;
		(void) read(rem, waste, sizeof (waste));
	}
	recv(rem, &mark, 1, SOF_OOB);
	...
}
.DE
.ce
Figure 5.  Flushing terminal i/o on receipt of out of band data.
.sp
.KE
.NH 2
Signals and process groups
.PP
Due to the existence of the SIGURG and SIGIO signals each socket has an
associated process group (just as is done for terminals).
This process group is initialized to the process group of its
creator, but may be redefined at a later time with the SIOCSPGRP
ioctl:
.DS
ioctl(s, SIOCSPGRP, &pgrp);
.DE
A similar ioctl, SIOCGPGRP, is available for determining the
current process group of a socket.
.NH 2
Pseudo terminals
.PP
Many programs will not function properly without a terminal
for standard input and output.  Since a socket is not a terminal,
it is often necessary to have a process communicating over
the network do so through a \fIpseudo terminal\fP.  A pseudo
terminal is actually a pair of devices, master and slave,
which allow a process to serve as an active agent in communication
between processes and users.  Data written on the slave side
of a pseudo terminal is supplied as input to a process reading
from the master side.  Data written on the master side is
given the slave as input.  In this way, the process manipulating
the master side of the pseudo terminal has control over the
information read and written on the slave side.  The remote
login server uses pseudo terminals for remote login sessions.
A user logging in to a machine across the network is provided
a shell with a slave pseudo terminal as standard input, output,
and error.  The server process then handles the communication
between the programs invoked by the remote shell and the user's
local client process.  When a user sends an interrupt or quit
signal to a process executing on a remote machine, the client
login program traps the signal, sends an out of band message
to the server process who then uses the signal number, sent
as the data value in the out of band message, to perform a
\fIkillpg\fP(2) on the appropriate process group.  
.NH 2
Internet address binding
.PP
Binding addresses to sockets in the Internet domain can be
fairly complex.  Communicating processes are bound
by an \fIassociation\fP.  An association 
is composed of local and foreign
addresses, and local and foreign ports.  Port numbers are
allocated out of separate spaces, one for each Internet
protocol.  Associations are always unique.  That is, there
may never be duplicate <protocol, local address, local port, foreign
address, foreign port> tuples. 
.PP
The bind system call allows a process to specify half of
an association, <local address, local port>, while the connect
and accept primitives are used to complete a socket's association.
Since the association is created in two steps the association
uniqueness requirement indicated above could be violated unless
care is taken.  Further, it is unrealistic to expect user
programs to always know proper values to use for the local address
and local port since a host may reside on multiple networks and
the set of allocated port numbers is not directly accessible
to a user.
.PP
To simplify local address binding the notion of a
\*(lqwildcard\*(rq address has been provided.  When an address
is specified as INADDR_ANY (a manifest constant defined in
<netinet/in.h>), the system interprets the address as 
\*(lqany valid address\*(rq.  For example, to bind a specific
port number to a socket, but leave the local address unspecified,
the following code might be used:
.DS
#include <sys/types.h>
#include <netinet/in.h>
 ...
struct sockaddr_in sin;
 ...
s = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = MYPORT;
bind(s, (char *)&sin, sizeof (sin));
.DE
Sockets with wildcarded local addresses may receive messages
directed to the specified port number, and addressed to any
of the possible addresses assigned a host.  For example,
if a host is on a networks 46 and 10 and a socket is bound as
above, then an accept call is performed, the process will be
able to accept connection requests which arrive either from
network 46 or network 10.
.PP
In a similar fashion, a local port may be left unspecified
(specified as zero), in which case the system will select an
appropriate port number for it.  For example:
.DS
sin.sin_addr.s_addr = MYADDRESS;
sin.sin_port = 0;
bind(s, (char *)&sin, sizeof (sin));
.DE
The system selects the port number based on two criteria.
The first is that ports numbered 0 through 1023 are reserved
for privileged users (i.e. the super user).  The second is
that the port number is not currently bound to some other
socket.  In order to find a free port number in the privileged
range the following code is used by the remote shell server:
.DS
struct sockaddr_in sin;
 ...
lport = IPPORT_RESERVED \- 1;
sin.sin_addr.s_addr = INADDR_ANY;
 ...
for (;;) {
	sin.sin_port = htons((u_short)lport);
	if (bind(s, (caddr_t)&sin, sizeof (sin)) >= 0)
		break;
	if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) {
		perror("socket");
		break;
	}
	lport--;
	if (lport == IPPORT_RESERVED/2) {
		fprintf(stderr, "socket: All ports in use\en");
		break;
	}
}
.DE
The restriction on allocating ports was done to allow processes
executing in a \*(lqsecure\*(rq environment to perform authentication
based on the originating address and port number.
.PP
In certain cases the algorithm used by the system in selecting
port numbers is unsuitable for an application.  This is due to
associations being created in a two step process.  For example,
the Internet file transfer protocol, FTP, specifies that data
connections must always originate from the same local port.  However,
duplicate associations are avoided by connecting to different foreign
ports.  In this situation the system would disallow binding the
same local address and port number to a socket if a previous data
connection's socket were around.  To override the default port
selection algorithm then an option call must be performed prior
to address binding:
.DS
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)0, 0);
bind(s, (char *)&sin, sizeof (sin));
.DE
With the above call, local addresses may be bound which
are already in use.  This does not violate the uniqueness
requirement as the system still checks at connect time to
be sure any other sockets with the same local address and
port do not have the same foreign address and port (if an
association already exists, the error EADDRINUSE is returned).
.PP
Local address binding by the system is currently
done somewhat haphazardly when a host is on multiple
networks.  Logically, one would expect
the system to bind the local address associated with
the network through which a peer was communicating.
For instance, if the local host is connected to networks
46 and 10 and the foreign host is on network 32, and
traffic from network 32 were arriving via network
10, the local address to be bound would be the host's address
on network 10, not network 46.  This unfortunately, is
not always the case.  For reasons too complicated to discuss
here, the local address bound may be appear to be chosen
at random.  This property of local address binding
will normally be invisible to users unless the foreign
host does not understand how to reach the address
selected*.
.FS
* For example, if network 46 were unknown to the host on
network 32, and the local address were bound to that located
on network 46, then even though a route between the two hosts
existed through network 10, a connection would fail.
.FE
.NH 2
Broadcasting and datagram sockets
.PP
By using a datagram socket it is possible to send broadcast
packets on many networks supported by the system (the network
itself must support the notion of broadcasting; the system
provides no broadcast simulation in software).  Broadcast
messages can place a high load on a network since they force
every host on the network to service them.  Consequently,
the ability to send broadcast packets has been limited to
the super user.
.PP
To send a broadcast message, an Internet datagram socket 
should be created:
.DS
s = socket(AF_INET, SOCK_DGRAM, 0);
.DE
and at least a port number should be bound to the socket:
.DS
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = MYPORT;
bind(s, (char *)&sin, sizeof (sin));
.DE
Then the message should be addressed as:
.DS
dst.sin_family = AF_INET;
dst.sin_addr.s_addr = INADDR_ANY;
dst.sin_port = DESTPORT;
.DE
and, finally, a sendto call may be used:
.DS
sendto(s, buf, buflen, 0, &dst, sizeof (dst));
.DE
.PP
Received broadcast messages contain the senders address
and port (datagram sockets are anchored before
a message is allowed to go out).  
.NH 2
Signals
.PP
Two new signals have been added to the system which may
be used in conjunction with the interprocess communication
facilities.  The SIGURG signal is associated with the existence
of an \*(lqurgent condition\*(rq.  The SIGIO signal is used
with \*(lqinterrupt driven i/o\*(rq (not presently implemented).
SIGURG is currently supplied a process when out of band data
is present at a socket.  If multiple sockets have out of band
data awaiting delivery, a select call may be used to determine
those sockets with such data.
.PP
An old signal which is useful when constructing server processes
is SIGCHLD.  This signal is delivered to a process when any
children processes have changed state.  Normally servers use
the signal to \*(lqreap\*(rq child processes after exiting.
For example, the remote login server loop shown in Figure 2
may be augmented as follows:
.DS
int reaper();
 ...
sigset(SIGCHLD, reaper);
listen(f, 10);
for (;;) {
	int g, len = sizeof (from);

	g = accept(f, &from, &len, 0);
	if (g < 0) {
		if (errno != EINTR)
			perror("rlogind: accept");
		continue;
	}
	...
}
 ...
#include <wait.h>
reaper()
{
	union wait status;

	while (wait3(&status, WNOHANG, 0) > 0)
		;
}
.DE
.PP
If the parent server process fails to reap its children,
a large number of \*(lqzombie\*(rq processes may be created.