updates for 4.3 from lapsley
authorMike Karels <karels@ucbvax.Berkeley.EDU>
Thu, 1 May 1986 02:22:21 +0000 (18:22 -0800)
committerMike Karels <karels@ucbvax.Berkeley.EDU>
Thu, 1 May 1986 02:22:21 +0000 (18:22 -0800)
SCCS-vsn: share/doc/psd/21.ipc/0.t 1.2
SCCS-vsn: share/doc/psd/21.ipc/1.t 1.2
SCCS-vsn: share/doc/psd/21.ipc/2.t 1.2
SCCS-vsn: share/doc/psd/21.ipc/3.t 1.2
SCCS-vsn: share/doc/psd/21.ipc/4.t 1.2
SCCS-vsn: share/doc/psd/21.ipc/5.t 1.2

usr/src/share/doc/psd/21.ipc/0.t
usr/src/share/doc/psd/21.ipc/1.t
usr/src/share/doc/psd/21.ipc/2.t
usr/src/share/doc/psd/21.ipc/3.t
usr/src/share/doc/psd/21.ipc/4.t
usr/src/share/doc/psd/21.ipc/5.t

index fcccf8d..c46d3da 100644 (file)
@@ -1,3 +1,9 @@
+.\" Copyright (c) 1986 Regents of the University of California.
+.\" All rights reserved.  The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\"    @(#)0.t 1.2 (Berkeley) %G%
+.\"
 .ds lq ``
 .ds rq ''
 .de DT
 .ds lq ``
 .ds rq ''
 .de DT
 ..
 .bd S B 3
 .TL
 ..
 .bd S B 3
 .TL
-A 4.2BSD Interprocess Communication Primer
-.br
-DRAFT of \*(DY
+A 4.3BSD Interprocess Communication Primer
 .AU
 Samuel J. Leffler
 .AU
 Robert S. Fabry
 .AU
 William N. Joy
 .AU
 Samuel J. Leffler
 .AU
 Robert S. Fabry
 .AU
 William N. Joy
+.AU
+\fRRevised December 16, 1985\fI
+.br
+Phil Lapsley
 .AI
 Computer Systems Research Group
 Department of Electrical Engineering and Computer Science
 University of California, Berkeley
 Berkeley, California  94720
 (415) 642-7780
 .AI
 Computer Systems Research Group
 Department of Electrical Engineering and Computer Science
 University of California, Berkeley
 Berkeley, California  94720
 (415) 642-7780
+.sp 0.5i
+\fRAlso revised by\fI
+.AU
+Steve Miller
+.AU
+Chris Torek
+.AI
+Heterogeneous Systems Laboratory
+Department of Computer Science
+University of Maryland, College Park
+College Park, Maryland 20742
+(301) 454-1516
 .de IR
 \fI\\$1\fP\\$2
 ..
 .de IR
 \fI\\$1\fP\\$2
 ..
@@ -31,16 +51,12 @@ UNIX\\$1
 .AB
 .PP
 .FS
 .AB
 .PP
 .FS
-* DEC and VAX are trademarks of
-Digital Equipment Corporation.
-.FE
-.FS
-** \s-2UNIX\s0 is a Trademark of Bell Laboratories.
+* \s-2UNIX\s0 is a Trademark of Bell Laboratories.
 .FE
 This document provides an introduction to the interprocess
 communication facilities included in the
 .FE
 This document provides an introduction to the interprocess
 communication facilities included in the
-4.2BSD release of the VAX*
-.UX **
+4.3BSD release of the
+.UX *
 system.
 .PP
 It discusses the overall model for interprocess communication
 system.
 .PP
 It discusses the overall model for interprocess communication
index b1ed2f1..52e49ea 100644 (file)
@@ -1,10 +1,16 @@
-.ds LH "4.2BSD IPC Primer
+.\" Copyright (c) 1986 Regents of the University of California.
+.\" All rights reserved.  The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\"    @(#)1.t 1.2 (Berkeley) %G%
+.\"
+.ds LH "4.3BSD IPC Primer
 .ds RH Introduction
 .LP
 .nr H1 1
 .bp
 .ds RF "Leffler/Fabry/Joy
 .ds RH Introduction
 .LP
 .nr H1 1
 .bp
 .ds RF "Leffler/Fabry/Joy
-.ds LF "DRAFT of \*(DY
+.ds LF "\*(DY
 .ds CF "
 .LG
 .B
 .ds CF "
 .LG
 .B
 .sp 2
 .R
 .NL
 .sp 2
 .R
 .NL
-One of the most important parts of 4.2BSD is the interprocess
+One of the most important parts of 4.3BSD is the interprocess
 communication facilities.  These facilities are the result of
 more than two years of discussion and research.  The facilities
 communication facilities.  These facilities are the result of
 more than two years of discussion and research.  The facilities
-provided in 4.2BSD incorporate many of the ideas from current
+provided in 4.3BSD incorporate many of the ideas from current
 research, while trying to maintain the UNIX philosophy of
 simplicity and conciseness.  It is hoped that
 the interprocess communication
 research, while trying to maintain the UNIX philosophy of
 simplicity and conciseness.  It is hoped that
 the interprocess communication
-facilities included in 4.2BSD will establish a
+facilities included in 4.3BSD will establish a
 standard for UNIX.  From the response to the design,
 it appears many organizations carrying out
 work with UNIX are adopting it.
 .PP
 UNIX has previously been very weak in the area of interprocess
 standard for UNIX.  From the response to the design,
 it appears many organizations carrying out
 work with UNIX are adopting it.
 .PP
 UNIX has previously been very weak in the area of interprocess
-communication.  Prior to the 4.2BSD facilities, the only
+communication.  Prior to the 4BSD facilities, the only
 standard mechanism which allowed two processes to communicate were
 pipes (the mpx files which were part of Version 7 were
 experimental).  Unfortunately, pipes are very restrictive
 standard mechanism which allowed two processes to communicate were
 pipes (the mpx files which were part of Version 7 were
 experimental).  Unfortunately, pipes are very restrictive
@@ -36,12 +42,12 @@ common ancestor.
 Further, the semantics of pipes makes them almost impossible
 to maintain in a distributed environment. 
 .PP
 Further, the semantics of pipes makes them almost impossible
 to maintain in a distributed environment. 
 .PP
-Earlier attempts at extending the ipc facilities of UNIX have
+Earlier attempts at extending the IPC facilities of UNIX have
 met with mixed reaction.  The majority of the problems have
 met with mixed reaction.  The majority of the problems have
-been related to the fact these facilities have been tied to
+been related to the fact that these facilities have been tied to
 the UNIX file system; either through naming, or implementation.
 the UNIX file system; either through naming, or implementation.
-Consequently, the ipc facilities provided in 4.2BSD have been
-designed as a totally independent subsystem.  The 4.2BSD ipc
+Consequently, the IPC facilities provided in 4.3BSD have been
+designed as a totally independent subsystem.  The 4.3BSD IPC
 allows processes to rendezvous in many ways. 
 Processes may rendezvous through a UNIX file system-like
 name space (a space where all names are path names)
 allows processes to rendezvous in many ways. 
 Processes may rendezvous through a UNIX file system-like
 name space (a space where all names are path names)
@@ -49,7 +55,7 @@ as well as through a
 network name space.  In fact, new name spaces may
 be added at a future time with only minor changes visible
 to users.  Further, the communication facilities 
 network name space.  In fact, new name spaces may
 be added at a future time with only minor changes visible
 to users.  Further, the communication facilities 
-have been extended to included more than the simple byte stream
+have been extended to include more than the simple byte stream
 provided by a pipe-like entity.  These extensions have resulted
 in a completely new part of the system which users will need
 time to familiarize themselves with.  It is likely that as
 provided by a pipe-like entity.  These extensions have resulted
 in a completely new part of the system which users will need
 time to familiarize themselves with.  It is likely that as
@@ -64,4 +70,4 @@ applications.  Section 4 is concerned with the client/server model
 used in developing applications and includes examples of the
 two major types of servers.  Section 5 delves into advanced topics
 which sophisticated users are likely to encounter when using
 used in developing applications and includes examples of the
 two major types of servers.  Section 5 delves into advanced topics
 which sophisticated users are likely to encounter when using
-the ipc facilities.  
+the IPC facilities.  
index 8f430df..297314a 100644 (file)
@@ -1,3 +1,9 @@
+.\" Copyright (c) 1986 Regents of the University of California.
+.\" All rights reserved.  The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\"    @(#)2.t 1.2 (Berkeley) %G%
+.\"
 .ds RH "Basics
 .bp
 .nr H1 2
 .ds RH "Basics
 .bp
 .nr H1 2
@@ -27,17 +33,26 @@ exchange data only with
 sockets in the same domain (it may be possible to cross domain
 boundaries, but only if some translation process is
 performed).  The
 sockets in the same domain (it may be possible to cross domain
 boundaries, but only if some translation process is
 performed).  The
-4.2BSD ipc supports two separate communication domains:
-the UNIX domain, and the Internet domain is used by
+4.3BSD IPC facilities support three separate communication domains:
+the UNIX domain, for on-system communication;
+the Internet domain, which is used by
 processes which communicate
 processes which communicate
-using the the DARPA standard communication protocols. 
+using the the DARPA standard communication protocols;
+and the NS domain, which is used by processes which
+communicate using the Xerox standard communication
+protocols*.
+.FS
+* See \fIInternet Transport Protocols\fP, Xerox System Integration
+Standard (XSIS)028112 for more information.  This document is
+almost a necessity for one trying to write NS applications.
+.FE
 The underlying communication
 facilities provided by these domains have a significant influence
 on the internal system implementation as well as the interface to
 socket facilities available to a user.  An example of the
 latter is that a socket \*(lqoperating\*(rq in the UNIX domain
 The underlying communication
 facilities provided by these domains have a significant influence
 on the internal system implementation as well as the interface to
 socket facilities available to a user.  An example of the
 latter is that a socket \*(lqoperating\*(rq in the UNIX domain
-sees a subset of the possible error conditions which are possible
-when operating in the Internet domain.
+sees a subset of the error conditions which are possible
+when operating in the Internet (or NS) domain.
 .NH 2
 Socket types
 .PP
 .NH 2
 Socket types
 .PP
@@ -50,13 +65,13 @@ nothing that prevents communication between sockets of different
 types should the underlying communication
 protocols support this.
 .PP
 types should the underlying communication
 protocols support this.
 .PP
-Three types of sockets currently are available to a user.
+Four types of sockets currently are available to a user.
 A \fIstream\fP socket provides for the bidirectional, reliable,
 sequenced, and unduplicated flow of data without record boundaries.
 Aside from the bidirectionality of data flow, a pair of connected
 A \fIstream\fP socket provides for the bidirectional, reliable,
 sequenced, and unduplicated flow of data without record boundaries.
 Aside from the bidirectionality of data flow, a pair of connected
-stream sockets provides an interface nearly identical to that of pipes*.
+stream sockets provides an interface nearly identical to that of pipes\(dg.
 .FS
 .FS
-* In the UNIX domain, in fact, the semantics are identical and,
+\(dg In the UNIX domain, in fact, the semantics are identical and,
 as one might expect, pipes have been implemented internally
 as simply a pair of connected stream sockets.
 .FE
 as one might expect, pipes have been implemented internally
 as simply a pair of connected stream sockets.
 .FE
@@ -83,18 +98,28 @@ communication protocols, or for gaining access to some of the more
 esoteric facilities of an existing protocol.  The use of raw sockets
 is considered in section 5.
 .PP
 esoteric facilities of an existing protocol.  The use of raw sockets
 is considered in section 5.
 .PP
-Two potential socket types which have interesting properties are
-the \fIsequenced packet\fP socket and the \fIreliably delivered
-message\fP socket.  A sequenced packet socket is identical to
-a stream socket
-with the exception that record boundaries are preserved.  This interface
-is very similar to that provided by the Xerox NS Sequenced Packet protocol.
+A \fIsequenced packet\fP socket is similar to a stream socket,
+with the exception that record boundaries are preserved.  This 
+interface is provided only as part of the NS socket abstraction,
+and is very important in most serious NS applications.
+Sequenced-packet sockets allow the user to manipulate the
+SPP or IDP headers on a packet or a group of packets either
+by writing a prototype header along with whatever data is
+to be sent, or by specifying a default header to be used with
+all outgoing data, and allows the user to receive the headers
+on incoming packets.  The use of these options is considered in
+section 5.
+.PP
+Another potential socket type which has interesting properties is
+the \fIreliably delivered
+message\fP socket.
 The reliably delivered message socket has
 similar properties to a datagram socket, but with
 The reliably delivered message socket has
 similar properties to a datagram socket, but with
-reliable delivery.  While these two socket types have been loosely defined,
-they are currently unimplemented in 4.2BSD.  As such, in this
-document we will concern ourselves
-only with the three socket types for which support exists.
+reliable delivery.  There is currently no support for this
+type of socket, but a reliably delivered message protocol
+similar to Xerox's Packet Exchange Protocol (PEX) may be
+simulated at the user level.  More information on this topic
+can be found in section 5.
 .NH 2
 Socket creation
 .PP
 .NH 2
 Socket creation
 .PP
@@ -116,8 +141,10 @@ For the UNIX domain the constant is AF_UNIX*;  for the Internet
 * The manifest constants are named AF_whatever as they indicate
 the ``address format'' to use in interpreting names.
 .FE
 * The manifest constants are named AF_whatever as they indicate
 the ``address format'' to use in interpreting names.
 .FE
-domain AF_INET.  The socket types are also defined in this file
-and one of SOCK_STREAM, SOCK_DGRAM, or SOCK_RAW must be specified.
+domain AF_INET; and for the NS domain, AF_NS.  
+The socket types are also defined in this file
+and one of SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, or SOCK_SEQPACKET
+must be specified.
 To create a stream socket in the Internet domain the following
 call might be used:
 .DS
 To create a stream socket in the Internet domain the following
 call might be used:
 .DS
@@ -125,26 +152,17 @@ s = socket(AF_INET, SOCK_STREAM, 0);
 .DE
 This call would result in a stream socket being created with the TCP
 protocol providing the underlying communication support.  To
 .DE
 This call would result in a stream socket being created with the TCP
 protocol providing the underlying communication support.  To
-create a datagram socket for on-machine use a sample call might
+create a datagram socket for on-machine use the call might
 be:
 .DS
 s = socket(AF_UNIX, SOCK_DGRAM, 0);
 .DE
 .PP
 be:
 .DS
 s = socket(AF_UNIX, SOCK_DGRAM, 0);
 .DE
 .PP
-To obtain a particular protocol one selects the protocol number,
-as defined within the communication domain.  For the Internet
-domain the available protocols are defined in <\fInetinet/in.h\fP>
-or, better yet, one may use one of the library routines
-discussed in section 3, such as  \fIgetprotobyname\fP:
-.DS
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
- ...
-pp = getprotobyname("tcp");
-s = socket(AF_INET, SOCK_STREAM, pp->p_proto);
-.DE
+The default protocol (used when the \fIprotocol\fP argument to the
+\fIsocket\fP call is 0) should be correct for most every
+situation.  However, it is possible to specify a protocol
+other than the default; this will be covered in
+section 5.
 .PP
 There are several reasons a socket call may fail.  Aside from
 the rare occurrence of lack of memory (ENOBUFS), a socket
 .PP
 There are several reasons a socket call may fail.  Aside from
 the rare occurrence of lack of memory (ENOBUFS), a socket
@@ -152,41 +170,117 @@ request may fail due to a request for an unknown protocol
 (EPROTONOSUPPORT), or a request for a type of socket for
 which there is no supporting protocol (EPROTOTYPE). 
 .NH 2
 (EPROTONOSUPPORT), or a request for a type of socket for
 which there is no supporting protocol (EPROTOTYPE). 
 .NH 2
-Binding names
+Binding local names
 .PP
 A socket is created without a name.  Until a name is bound
 to a socket, processes have no way to reference it and, consequently,
 .PP
 A socket is created without a name.  Until a name is bound
 to a socket, processes have no way to reference it and, consequently,
-no messages may be received on it.  The \fIbind\fP call is used to
-assign a name to a socket:
+no messages may be received on it.
+Communicating processes are bound
+by an \fIassociation\fP.  In the Internet and NS domains,
+an association 
+is composed of local and foreign
+addresses, and local and foreign ports,
+while in the UNIX domain, an association is composed of
+local and foreign path names (the phrase ``foreign pathname''
+means a pathname created by a foreign process, not a pathname
+on a foreign system).
+Associations are always unique.  That is, in the Internet domain, there
+may never be duplicate <protocol, local address, local port, foreign
+address, foreign port> tuples.  Similarly, in the UNIX domain,
+there may never be duplicate <protocol, local pathname, foreign
+pathname> tuples, and the pathnames must (in 4.3; the situation
+may change in future releases) be unique with respect to the files
+already existing on the system.
+.PP
+The \fIbind\fP system call allows a process to specify half of
+an association, <local address, local port>
+(or <local pathname>), while the \fIconnect\fP
+and \fIaccept\fP primitives are used to complete a socket's association.
+.PP
+In the Internet domain,
+binding names to sockets can be fairly complex.
+Fortunately, it is usually not necessary to specifically bind an
+address and port number to a socket, because the
+\fIconnect\fP and \fIsend\fP calls will automatically
+bind an appropriate address if they are used with an
+unbound socket.  The process of binding names to NS
+sockets is similar in most ways to that of
+binding names to Internet sockets.
+While binding names to sockets in the
+UNIX domain is less complex, the \fIconnect\fP and \fIsend\fP
+calls can still be used to automatically bind local names.
+.PP
+The \fIbind\fP system call is used as follows:
 .DS
 bind(s, name, namelen);
 .DE
 The bound name is a variable length byte string which is interpreted
 by the supporting protocol(s).  Its interpretation may vary from
 communication domain to communication domain (this is one of
 .DS
 bind(s, name, namelen);
 .DE
 The bound name is a variable length byte string which is interpreted
 by the supporting protocol(s).  Its interpretation may vary from
 communication domain to communication domain (this is one of
-the properties which comprise the \*(lqdomain\*(rq).  In the
-UNIX domain names are path names while in the Internet domain
-names contain an Internet address and port number.
-If one wanted to bind the name \*(lq/dev/foo\*(rq to
-a UNIX domain socket, the following would be used:
+the properties which comprise the \*(lqdomain\*(rq).
+As mentioned, in the
+Internet domain names contain an Internet address and port
+number.  NS domain names contain a NS address and
+port number.  In the UNIX domain, names contain a path name and
+a family, which is always AF_UNIX.  If one wanted to bind
+the name \*(lq/tmp/foo\*(rq to a UNIX domain socket, the
+following code would be used*:
+.FS
+* Note that, although the tendency here is to call the \*(lqaddr\*(rq
+structure \*(lqsun\*(rq, doing so would cause problems if the code
+were ever ported to a Sun workstation.
+.FE
 .DS
 .DS
-bind(s, "/dev/foo", sizeof ("/dev/foo") \- 1);
+#include <sys/un.h>
+ ...
+struct sockaddr_un addr;
+ ...
+strcpy(addr.sun_path, "/tmp/foo");
+addr.sun_family = AF_UNIX;
+bind(s, (struct sockaddr *) &addr, strlen(addr.sun_path) +
+    sizeof (addr.sun_family));
 .DE
 .DE
-(Note how the null byte in the name is not counted as part of
-the name.)  In binding an Internet address things become more
-complicated.  The actual call is simple,
+Note that in determining the size of a UNIX domain address null
+bytes are not counted, which is why \fIstrlen\fP is used.  In
+the current implementation of UNIX domain IPC under 4.3BSD,
+the file name
+referred to in \fIaddr.sun_path\fP is created as a socket
+in the system file space.
+The caller must, therefore, have
+write permission in the directory where
+\fIaddr.sun_path\fP is to reside, and this file should be deleted by the
+caller when it is no longer needed.  Future versions of 4BSD
+may not create this file.
+.PP
+In binding an Internet address things become more
+complicated.  The actual call is similar,
 .DS
 #include <sys/types.h>
 #include <netinet/in.h>
  ...
 struct sockaddr_in sin;
  ...
 .DS
 #include <sys/types.h>
 #include <netinet/in.h>
  ...
 struct sockaddr_in sin;
  ...
-bind(s, &sin, sizeof (sin));
+bind(s, (struct sockaddr *) &sin, sizeof (sin));
 .DE
 but the selection of what to place in the address \fIsin\fP
 requires some discussion.  We will come back to the problem
 of formulating Internet addresses in section 3 when 
 the library routines used in name resolution are discussed.
 .DE
 but the selection of what to place in the address \fIsin\fP
 requires some discussion.  We will come back to the problem
 of formulating Internet addresses in section 3 when 
 the library routines used in name resolution are discussed.
+.PP
+Binding a NS address to a socket is even more
+difficult,
+especially since the Internet library routines do not
+work with NS hostnames.  The actual call is again similar:
+.DS
+#include <sys/types.h>
+#include <netns/ns.h>
+ ...
+struct sockaddr_ns sns;
+ ...
+bind(s, (struct sockaddr *) &sns, sizeof (sns));
+.DE
+Again, discussion of what to place in a \*(lqstruct sockaddr_ns\*(rq
+will be deferred to section 3.
 .NH 2
 Connection establishment
 .PP
 .NH 2
 Connection establishment
 .PP
@@ -200,24 +294,39 @@ on its socket.  On the client side the \fIconnect\fP call is
 used to initiate a connection.  Using the UNIX domain, this
 might appear as,
 .DS
 used to initiate a connection.  Using the UNIX domain, this
 might appear as,
 .DS
-connect(s, "server-name", sizeof ("server-name"));
+struct sockaddr_un server;
+ ...
+connect(s, (struct sockaddr *)&server, strlen(server.sun_path) +
+    sizeof (server.sun_family));
 .DE
 while in the Internet domain,
 .DS
 struct sockaddr_in server;
 .DE
 while in the Internet domain,
 .DS
 struct sockaddr_in server;
-connect(s, &server, sizeof (server));
+ ...
+connect(s, (struct sockaddr *)&server, sizeof (server));
+.DE
+and in the NS domain,
+.DS
+struct sockaddr_ns server;
+ ...
+connect(s, (struct sockaddr *)&server, sizeof (server));
 .DE
 .DE
+where \fIserver\fP in the example above would contain either the UNIX
+pathname, Internet address and port number, or NS address and
+port number of the server to which the
+client process wishes to speak.
 If the client process's socket is unbound at the time of
 the connect call,
 the system will automatically select and bind a name to
 the socket; c.f. section 5.4.
 If the client process's socket is unbound at the time of
 the connect call,
 the system will automatically select and bind a name to
 the socket; c.f. section 5.4.
-An error is returned when the connection was unsuccessful
+This is the usual way that local addresses are bound
+to a socket.
+.PP
+An error is returned if the connection was unsuccessful
 (any name automatically bound by the system, however, remains).
 Otherwise, the socket is associated with the server and
 (any name automatically bound by the system, however, remains).
 Otherwise, the socket is associated with the server and
-data transfer may begin.
-.PP
-Many errors can be returned when a connection attempt
-fails.  The most common are:
+data transfer may begin.  Some of the more common errors returned
+when a connection attempt fails are:
 .IP ETIMEDOUT
 .br
 After failing to establish a connection for a period of time,
 .IP ETIMEDOUT
 .br
 After failing to establish a connection for a period of time,
@@ -227,8 +336,8 @@ the destination host is down, or because problems in
 the network resulted in transmissions being lost.
 .IP ECONNREFUSED
 .br
 the network resulted in transmissions being lost.
 .IP ECONNREFUSED
 .br
-The host refused service for some reason.  When connecting
-to a host running 4.2BSD this is usually
+The host refused service for some reason.
+This is usually
 due to a server process
 not being present at the requested name.
 .IP "ENETDOWN or EHOSTDOWN"
 due to a server process
 not being present at the requested name.
 .IP "ENETDOWN or EHOSTDOWN"
@@ -243,7 +352,7 @@ or host is unknown (no route to the network or host is present),
 or because of status information returned by intermediate
 gateways or switching nodes.  Many times the status returned
 is not sufficient to distinguish a network being down from a
 or because of status information returned by intermediate
 gateways or switching nodes.  Many times the status returned
 is not sufficient to distinguish a network being down from a
-host being down.  In these cases the system is conservative and
+host being down, in which case the system
 indicates the entire network is unreachable.
 .PP
 For the server to receive a client's connection it must perform
 indicates the entire network is unreachable.
 .PP
 For the server to receive a client's connection it must perform
@@ -255,7 +364,8 @@ listen(s, 5);
 .DE
 The second parameter to the \fIlisten\fP call specifies the maximum
 number of outstanding connections which may be queued awaiting 
 .DE
 The second parameter to the \fIlisten\fP call specifies the maximum
 number of outstanding connections which may be queued awaiting 
-acceptance by the server process.  Should a connection be
+acceptance by the server process; this number
+may be limited by the system.  Should a connection be
 requested while the queue is full, the connection will not be
 refused, but rather the individual messages which comprise the
 request will be ignored.  This gives a harried server time to 
 requested while the queue is full, the connection will not be
 refused, but rather the individual messages which comprise the
 request will be ignored.  This gives a harried server time to 
@@ -264,7 +374,7 @@ retries the connection request.  Had the connection been returned
 with the ECONNREFUSED error, the client would be unable to tell
 if the server was up or not.  As it is now it is still possible
 to get the ETIMEDOUT error back, though this is unlikely.  The
 with the ECONNREFUSED error, the client would be unable to tell
 if the server was up or not.  As it is now it is still possible
 to get the ETIMEDOUT error back, though this is unlikely.  The
-backlog figure supplied with the listen call is limited
+backlog figure supplied with the listen call is currently limited
 by the system to a maximum of 5 pending connections on any
 one queue.  This avoids the problem of processes hogging system
 resources by setting an infinite backlog, then ignoring
 by the system to a maximum of 5 pending connections on any
 one queue.  This avoids the problem of processes hogging system
 resources by setting an infinite backlog, then ignoring
@@ -273,18 +383,26 @@ all connection requests.
 With a socket marked as listening, a server may \fIaccept\fP
 a connection:
 .DS
 With a socket marked as listening, a server may \fIaccept\fP
 a connection:
 .DS
+struct sockaddr_in from;
+ ...
 fromlen = sizeof (from);
 fromlen = sizeof (from);
-snew = accept(s, &from, &fromlen);
+newsock = accept(s, (struct sockaddr *)&from, &fromlen);
 .DE
 .DE
-A new descriptor is returned on receipt of a connection (along with
+(For the UNIX domain, \fIfrom\fP would be declared as a
+\fIstruct sockaddr_un\fP, and for the NS domain, \fIfrom\fP
+would be declared as a \fIstruct sockaddr_ns\fP,
+but nothing different would need
+to be done as far as \fIfromlen\fP is concerned.  In the examples
+which follow, only Internet routines will be discussed.)  A new
+descriptor is returned on receipt of a connection (along with
 a new socket).  If the server wishes to find out who its client is,
 it may supply a buffer for the client socket's name.  The value-result
 parameter \fIfromlen\fP is initialized by the server to indicate how
 much space is associated with \fIfrom\fP, then modified on return
 to reflect the true size of the name.  If the client's name is not
 a new socket).  If the server wishes to find out who its client is,
 it may supply a buffer for the client socket's name.  The value-result
 parameter \fIfromlen\fP is initialized by the server to indicate how
 much space is associated with \fIfrom\fP, then modified on return
 to reflect the true size of the name.  If the client's name is not
-of interest, the second parameter may be zero.
+of interest, the second parameter may be a null pointer.
 .PP
 .PP
-Accept normally blocks.  That is, the call to accept
+\fIAccept\fP normally blocks.  That is, \fIaccept\fP
 will not return until a connection is available or the system call
 is interrupted by a signal to the process.  Further, there is no
 way for a process to indicate it will accept connections from only
 will not return until a connection is available or the system call
 is interrupted by a signal to the process.  Further, there is no
 way for a process to indicate it will accept connections from only
@@ -292,7 +410,7 @@ a specific individual, or individuals.  It is up to the user process
 to consider who the connection is from and close down the connection
 if it does not wish to speak to the process.  If the server process
 wants to accept connections on more than one socket, or not block
 to consider who the connection is from and close down the connection
 if it does not wish to speak to the process.  If the server process
 wants to accept connections on more than one socket, or not block
-on the accept call there are alternatives;  they will be considered
+on the accept call, there are alternatives;  they will be considered
 in section 5.
 .NH 2
 Data transfer
 in section 5.
 .NH 2
 Data transfer
@@ -302,7 +420,7 @@ and receive data there are a number of possible calls.
 With the peer entity at each end of a connection
 anchored, a user can send or receive a message without specifying
 the peer.  As one might expect, in this case, then
 With the peer entity at each end of a connection
 anchored, a user can send or receive a message without specifying
 the peer.  As one might expect, in this case, then
-the normal \fIread\fP and \fIwrite\fP system calls are useable,
+the normal \fIread\fP and \fIwrite\fP system calls are usable,
 .DS
 write(s, buf, sizeof (buf));
 read(s, buf, sizeof (buf));
 .DS
 write(s, buf, sizeof (buf));
 read(s, buf, sizeof (buf));
@@ -316,15 +434,16 @@ recv(s, buf, sizeof (buf), flags);
 .DE
 While \fIsend\fP and \fIrecv\fP are virtually identical to
 \fIread\fP and \fIwrite\fP,
 .DE
 While \fIsend\fP and \fIrecv\fP are virtually identical to
 \fIread\fP and \fIwrite\fP,
-the extra \fIflags\fP argument is important.  The flags may be
+the extra \fIflags\fP argument is important.  The flags,
+defined in \fI<sys/socket.h>\fP, may be
 specified as a non-zero value if one or more
 of the following is required:
 .DS
 .TS
 l l.
 specified as a non-zero value if one or more
 of the following is required:
 .DS
 .TS
 l l.
-SOF_OOB        send/receive out of band data
-SOF_PREVIEW    look at data without reading
-SOF_DONTROUTE  send data without routing packets
+MSG_OOB        send/receive out of band data
+MSG_PEEK       look at data without reading
+MSG_DONTROUTE  send data without routing packets
 .TE
 .DE
 Out of band data is a notion specific to stream sockets, and one
 .TE
 .DE
 Out of band data is a notion specific to stream sockets, and one
@@ -332,7 +451,7 @@ which we will not immediately consider.  The option to have data
 sent without routing applied to the outgoing packets is currently 
 used only by the routing table management process, and is
 unlikely to be of interest to the casual user.  The ability
 sent without routing applied to the outgoing packets is currently 
 used only by the routing table management process, and is
 unlikely to be of interest to the casual user.  The ability
-to preview data is, however, of interest.  When SOF_PREVIEW
+to preview data is, however, of interest.  When MSG_PEEK
 is specified with a \fIrecv\fP call, any data present is returned
 to the user, but treated as still \*(lqunread\*(rq.  That
 is, the next \fIread\fP or \fIrecv\fP call applied to the socket will
 is specified with a \fIrecv\fP call, any data present is returned
 to the user, but treated as still \*(lqunread\*(rq.  That
 is, the next \fIread\fP or \fIrecv\fP call applied to the socket will
@@ -358,8 +477,7 @@ shutdown(s, how);
 .DE
 where \fIhow\fP is 0 if the user is no longer interested in reading
 data, 1 if no more data will be sent, or 2 if no data is to
 .DE
 where \fIhow\fP is 0 if the user is no longer interested in reading
 data, 1 if no more data will be sent, or 2 if no data is to
-be sent or received.  Applying shutdown to a socket causes
-any data queued to be immediately discarded.
+be sent or received.
 .NH 2
 Connectionless sockets
 .PP
 .NH 2
 Connectionless sockets
 .PP
@@ -377,13 +495,14 @@ have a name bound to it in order that the recipient of
 a message may identify the sender.  To send data,
 the \fIsendto\fP primitive is used,
 .DS
 a message may identify the sender.  To send data,
 the \fIsendto\fP primitive is used,
 .DS
-sendto(s, buf, buflen, flags, &to, tolen);
+sendto(s, buf, buflen, flags, (struct sockaddr *)&to, tolen);
 .DE
 The \fIs\fP, \fIbuf\fP, \fIbuflen\fP, and \fIflags\fP
 parameters are used as before. 
 The \fIto\fP and \fItolen\fP
 values are used to indicate the intended recipient of the
 .DE
 The \fIs\fP, \fIbuf\fP, \fIbuflen\fP, and \fIflags\fP
 parameters are used as before. 
 The \fIto\fP and \fItolen\fP
 values are used to indicate the intended recipient of the
-message.  When using an unreliable datagram interface, it is
+message.  When
+using an unreliable datagram interface, it is
 unlikely any errors will be reported to the sender.  Where
 information is present locally to recognize a message which may
 never be delivered (for instance when a network is unreachable),
 unlikely any errors will be reported to the sender.  Where
 information is present locally to recognize a message which may
 never be delivered (for instance when a network is unreachable),
@@ -393,15 +512,16 @@ contain an error number.
 To receive messages on an unconnected datagram socket, the
 \fIrecvfrom\fP primitive is provided:
 .DS
 To receive messages on an unconnected datagram socket, the
 \fIrecvfrom\fP primitive is provided:
 .DS
-recvfrom(s, buf, buflen, flags, &from, &fromlen);
+recvfrom(s, buf, buflen, flags, (struct sockaddr *)&from, &fromlen);
 .DE
 Once again, the \fIfromlen\fP parameter is handled in
 a value-result fashion, initially containing the size of
 .DE
 Once again, the \fIfromlen\fP parameter is handled in
 a value-result fashion, initially containing the size of
-the \fIfrom\fP buffer.
+the \fIfrom\fP buffer, and modified on return to indicate
+the actual size of the from address.
 .PP
 In addition to the two calls mentioned above, datagram
 sockets may also use the \fIconnect\fP call to associate
 .PP
 In addition to the two calls mentioned above, datagram
 sockets may also use the \fIconnect\fP call to associate
-a socket with a specific address.  In this case, any
+a socket with a specific destination address.  In this case, any
 data sent on the socket will automatically be addressed
 to the connected peer, and only data received from that
 peer will be delivered to the user.  Only one connected
 data sent on the socket will automatically be addressed
 to the connected peer, and only data received from that
 peer will be delivered to the user.  Only one connected
@@ -410,7 +530,8 @@ Connect requests on datagram sockets return immediately,
 as this simply results in the system recording
 the peer's address (as compared to a stream socket where a
 connect request initiates establishment of an end to end
 as this simply results in the system recording
 the peer's address (as compared to a stream socket where a
 connect request initiates establishment of an end to end
-connection).
+connection).  \fIAccept\fP and \fIlisten\fP are not
+used with datagram sockets.
 Other of the less
 important details of datagram sockets are described
 in section 5.
 Other of the less
 important details of datagram sockets are described
 in section 5.
@@ -422,24 +543,56 @@ is the ability to multiplex i/o requests among multiple
 sockets and/or files.  This is done using the \fIselect\fP
 call:
 .DS
 sockets and/or files.  This is done using the \fIselect\fP
 call:
 .DS
-select(nfds, &readfds, &writefds, &execptfds, &timeout);
+#define FD_SETSIZE     128   /* How many file descriptors we're interested in */
+ ...
+#include <sys/time.h>
+#include <sys/types.h>
+ ...
+
+fd_set readmask, writemask, exceptmask;
+struct timeval timeout;
+ ...
+select(nfds, &readmask, &writemask, &exceptmask, &timeout);
 .DE
 .DE
-\fISelect\fP takes as arguments three bit masks, one for
+\fISelect\fP takes as arguments pointers to three sets, one for
 the set of file descriptors for which the caller wishes to
 be able to read data on, one for those descriptors to which
 data is to be written, and one for which exceptional conditions
 the set of file descriptors for which the caller wishes to
 be able to read data on, one for those descriptors to which
 data is to be written, and one for which exceptional conditions
-are pending.  
-Bit masks are created
-by or-ing bits of the form \*(lq1 << fd\*(rq.  That is,
-a descriptor \fIfd\fP is selected if a 1 is present in
-the \fIfd\fP'th bit of the mask.
-The parameter \fInfds\fP specifies the range
+are pending; out-of-band data is the only
+exceptional condition currently implemented by the socket
+abstraction.
+If it is known that the
+that the maximum number of open file descriptors will be less than
+a given value,
+then this number should be used as the definition of FD_SETSIZE
+(which must be done before \fI<sys/types>\fP is included).
+Otherwise, it is acceptable to let FD_SETSIZE default to the
+value specified in \fI<sys/types.h>\fP.
+.PP
+Each set is actually a structure containing an array of
+long integers; the length of the array is implicitly set
+by the definition of FD_SETSIZE, and the array will be
+long enough to hold one bit for each of FD_SETSIZE file descriptors.
+If the user is not interested
+in certain conditions (i.e., read, write, or exceptions),
+the corresponding argument to the \fIselect\fP should
+be a null pointer.
+.PP
+The macros \fIFD_SET(fd, &mask)\fP and
+\fIFD_CLR(fd, &mask)\fP
+have been provided for adding and removing file descriptor
+\fIfd\fP in the set \fImask\fP.  The
+set should be zeroed before use, and
+the macro \fIFD_ZERO(&mask)\fP has been provided
+to clear the set \fImask\fP.
+The parameter \fInfds\fP in the \fIselect\fP call specifies the range
 of file descriptors  (i.e. one plus the value of the largest
 of file descriptors  (i.e. one plus the value of the largest
-descriptor) specified in a mask
+descriptor) specified in a set
 .PP
 A timeout value may be specified if the selection
 is not to last more than a predetermined period of time.  If
 .PP
 A timeout value may be specified if the selection
 is not to last more than a predetermined period of time.  If
-\fItimeout\fP is set to 0, the selection takes the form of a
+the fields in \fItimeout\fP are set to 0, the selection takes
+the form of a
 \fIpoll\fP, returning immediately.  If the last parameter is
 a null pointer, the selection will block indefinitely*.
 .FS
 \fIpoll\fP, returning immediately.  If the last parameter is
 a null pointer, the selection will block indefinitely*.
 .FS
@@ -447,9 +600,71 @@ a null pointer, the selection will block indefinitely*.
 descriptor is selectable, or when a signal is received by
 the caller, interrupting the system call.
 .FE
 descriptor is selectable, or when a signal is received by
 the caller, interrupting the system call.
 .FE
-\fISelect\fP normally returns the number of file descriptors selected.
-If the \fIselect\fP call returns due to the timeout expiring, then
-a value of \-1 is returned along with the error number EINTR.
+\fISelect\fP normally returns the number of file descriptors selected;
+if the \fIselect\fP call returns due to the timeout expiring, then
+the value 0 is returned.
+If the \fIselect\fP terminates because of an error, a \-1 is returned
+with the error number in \fIerrno\fP.
+.PP
+Assuming a successful return, the three sets will
+indicate which
+file descriptors are ready to be read from, written to, or
+have exceptional conditions pending.
+The status of a file descriptor in a select mask may be
+tested with the \fIFD_ISSET(fd, &mask)\fP macro, which
+returns a non-zero value if \fIfd\fP is a member of the set
+\fImask\fP, and 0 if it is not.
+.PP
+To determine if there are connections waiting 
+on a socket to be used with an \fIaccept\fP call,
+\fIselect\fP can be used, followed by
+a \fIFD_ISSET(fd, &mask)\fP macro to check for read
+readiness on the appropriate socket.  If \fIFD_ISSET\fP
+returns a non-zero value, indicating permission to read, then a
+connection is pending on the socket.
+.PP
+As an example, to read data from two sockets, \fIs1\fP and
+\fIs2\fP as it is available from each and with a one-second
+timeout, the following code
+might be used:
+.DS
+#include <sys/time.h>
+#include <sys/types.h>
+ ...
+fd_set read_template;
+struct timeval wait;
+ ...
+for (;;) {
+       wait.tv_sec = 1;                /* one second */
+       wait.tv_usec = 0;
+
+       FD_ZERO(&read_template);
+
+       FD_SET(s1, &read_template);
+       FD_SET(s2, &read_template);
+
+       nb = select(FD_SETSIZE, &read_template, (fd_set *) 0, (fd_set *) 0, &wait);
+       if (nb <= 0) {
+               \fIAn error occurred during the \fPselect\fI, or
+               the \fPselect\fI timed out.\fP
+       }
+
+       if (FD_ISSET(s1, &read_template)) {
+               \fISocket #1 is ready to be read from.\fP
+       }
+
+       if (FD_ISSET(s2, &read_template)) {
+               \fISocket #2 is ready to be read from.\fP
+       }
+}
+.DE
+.PP
+In 4.2, the arguments to \fIselect\fP were pointers to integers
+instead of pointers to \fIfd_set\fPs.  This type of call
+will still work as long as the number of file descriptors
+being examined is less than the number of bits in an
+integer; however, the methods illustrated above should
+be used in all current programs.
 .PP
 \fISelect\fP provides a synchronous multiplexing scheme.
 Asynchronous notification of output completion, input availability,
 .PP
 \fISelect\fP provides a synchronous multiplexing scheme.
 Asynchronous notification of output completion, input availability,
index b14c361..830c544 100644 (file)
@@ -1,3 +1,9 @@
+.\" Copyright (c) 1986 Regents of the University of California.
+.\" All rights reserved.  The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\"    @(#)3.t 1.2 (Berkeley) %G%
+.\"
 .ds RH "Network Library Routines
 .bp
 .nr H1 3
 .ds RH "Network Library Routines
 .bp
 .nr H1 3
@@ -17,16 +23,12 @@ interprocess communication facilities in a distributed
 environment.  To aid in this task a number of routines
 have been added to the standard C run-time library.
 In this section we will consider the new routines provided
 environment.  To aid in this task a number of routines
 have been added to the standard C run-time library.
 In this section we will consider the new routines provided
-to manipulate network addresses.  While the 4.2BSD networking
-facilities support only the DARPA standard Internet protocols,
-these routines have been designed with flexibility in mind.
-As more communication protocols become available, we hope
-the same user interface will be maintained in accessing
-network-related address data bases.  The only difference
-should be the values returned to the user.  Since these
-values are normally supplied the system, users should
-not need to be directly aware of the communication protocol
-and/or naming conventions in use.
+to manipulate network addresses.  While the 4.3BSD networking
+facilities support both the DARPA standard Internet protocols
+and the Xerox NS protocols, most of the routines presented
+in this section do not apply to the NS domain.  Unless otherwise
+stated, it should be assumed that the routines presented in this
+section do not apply to the NS domain.
 .PP
 Locating a service on a remote host requires many levels of
 mapping before client and server may
 .PP
 Locating a service on a remote host requires many levels of
 mapping before client and server may
@@ -37,9 +39,9 @@ This name, and the name of the peer host, must then be translated
 into network \fIaddresses\fP which are not necessarily suitable
 for human consumption.  Finally, the address must then used in locating
 a physical \fIlocation\fP and \fIroute\fP to the service.  The
 into network \fIaddresses\fP which are not necessarily suitable
 for human consumption.  Finally, the address must then used in locating
 a physical \fIlocation\fP and \fIroute\fP to the service.  The
-specifics of these three mappings is likely to vary between
+specifics of these three mappings are likely to vary between
 network architectures.  For instance, it is desirable for a network
 network architectures.  For instance, it is desirable for a network
-to not require hosts
+to not require hosts to
 be named in such a way that their physical location is known by
 the client host.  Instead, underlying services in the network
 may discover the actual location of the host at the time a client
 be named in such a way that their physical location is known by
 the client host.  Instead, underlying services in the network
 may discover the actual location of the host at the time a client
@@ -59,27 +61,38 @@ routines.
 .NH 2
 Host names
 .PP
 .NH 2
 Host names
 .PP
-A host name to address mapping is represented by
+An Internet host name to address mapping is represented by
 the \fIhostent\fP structure:
 .DS
 the \fIhostent\fP structure:
 .DS
-.DT
+.if t .ta 0.6i 1.1i 2.6i
 struct hostent {
        char    *h_name;        /* official name of host */
        char    **h_aliases;    /* alias list */
 struct hostent {
        char    *h_name;        /* official name of host */
        char    **h_aliases;    /* alias list */
-       int     h_addrtype;     /* host address type */
+       int     h_addrtype;     /* host address type (e.g., AF_INET) */
        int     h_length;       /* length of address */
        int     h_length;       /* length of address */
-       char    *h_addr;        /* address */
+       char    **h_addr_list;  /* list of addresses, null terminated */
 };
 };
+
+#define        h_addr  h_addr_list[0]  /* first address, network byte order */
 .DE
 .DE
-The official name of the host and its public aliases are
-returned, along with a variable length address and address
-type.  The routine \fIgethostbyname\fP(3N) takes a host name
+The routine \fIgethostbyname\fP(3N) takes an Internet host name
 and returns a \fIhostent\fP structure,
 while the routine \fIgethostbyaddr\fP(3N)
 and returns a \fIhostent\fP structure,
 while the routine \fIgethostbyaddr\fP(3N)
-maps host addresses into a \fIhostent\fP structure.  It is possible
+maps Internet host addresses into a \fIhostent\fP structure.
+.PP
+The official name of the host and its public aliases are
+returned by these routines,
+along with the address type (family) and a null terminated list of
+variable length address.  This list of addresses is
+required because it is possible
 for a host to have many addresses, all having the same name.
 for a host to have many addresses, all having the same name.
-\fIGethostybyname\fP returns the first matching entry in the data
-base file \fI/etc/hosts\fP; if this is unsuitable, the lower level
+The \fIh_addr\fP definition is provided for backward compatibility,
+and is defined to be the first address in the list of addresses
+in the \fIhostent\fP structure.
+.PP
+The database for these calls is provided either by the
+file \fI/etc/hosts\fP, or by use of a nameserver.  If the data
+returned by \fIgethostbyname\fP are unsuitable, the lower level
 routine \fIgethostent\fP(3N) may be used.  For example, to
 obtain a \fIhostent\fP structure for a
 host on a particular network the following routine might be
 routine \fIgethostent\fP(3N) may be used.  For example, to
 obtain a \fIhostent\fP structure for a
 host on a particular network the following routine might be
@@ -121,6 +134,74 @@ gethostbynameandnet(name, net)
 .DE
 (\fIin_netof\fP(3N) is a standard routine which returns
 the network portion of an Internet address.)
 .DE
 (\fIin_netof\fP(3N) is a standard routine which returns
 the network portion of an Internet address.)
+\fIGethostent\fP can be used only
+by systems which use the \fI/etc/hosts\fP database; systems
+using nameservers cannot execute such a call.
+.PP
+Unlike Internet names, NS names are always mapped into host
+addresses by the use of a standard NS \fIClearinghouse service\fP,
+a distributed name and authentication server.  The algorithms
+for mapping NS names to addresses via a Clearinghouse are
+rather complicated, and the routines are not part of the
+standard libraries.  The user-contributed Courier (Xerox
+remote procedure call protocol) compiler contains routines
+to accomplish this mapping; see the documentation and
+examples provided therein for more information.  It is
+expected that almost all software that has to communicate
+using NS will need to use the facilities of
+the Courier compiler.
+.PP
+A NS host address is represented by the following:
+.DS
+union ns_host {
+       u_char  c_host[6];
+       u_short s_host[3];
+};
+
+union ns_net {
+       u_char  c_net[4];
+       u_short s_net[2];
+};
+
+struct ns_addr {
+       union ns_net    x_net;
+       union ns_host   x_host;
+       u_short x_port;
+};
+.DE
+The following code fragment inserts a known NS address into
+a \fIns_addr\fP:
+.DS
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netns/ns.h>
+ ...
+u_long netnum;
+struct sockaddr_ns dst;
+ ...
+bzero((char *)&dst, sizeof(dst));
+
+/*
+ * There is no convenient way to assign a long
+ * integer to a ``union ns_net'' at present; in
+ * the future, something will hopefully be provided,
+ * but this is the portable way to go for now.
+ */
+netnum = htonl(2266);
+dst.sns_addr.x_net = *(union ns_net *) &netnum;
+dst.sns_family = AF_NS;
+
+/*
+ * host 2.7.1.0.2a.18 == "gyre:Computer Science:UofMaryland"
+ */
+dst.sns_addr.x_host.c_host[0] = 0x02;
+dst.sns_addr.x_host.c_host[1] = 0x07;
+dst.sns_addr.x_host.c_host[2] = 0x01;
+dst.sns_addr.x_host.c_host[3] = 0x00;
+dst.sns_addr.x_host.c_host[4] = 0x2a;
+dst.sns_addr.x_host.c_host[5] = 0x18;
+dst.sns_addr.x_port = htons(75);
+.DE
 .NH 2
 Network names
 .PP
 .NH 2
 Network names
 .PP
@@ -137,16 +218,27 @@ struct    netent {
        char    *n_name;        /* official name of net */
        char    **n_aliases;    /* alias list */
        int     n_addrtype;     /* net address type */
        char    *n_name;        /* official name of net */
        char    **n_aliases;    /* alias list */
        int     n_addrtype;     /* net address type */
-       int     n_net;  /* network # */
+       int     n_net;  /* network number, host byte order */
 };
 .DE
 The routines \fIgetnetbyname\fP(3N), \fIgetnetbynumber\fP(3N),
 and \fIgetnetent\fP(3N) are the network counterparts to the
 };
 .DE
 The routines \fIgetnetbyname\fP(3N), \fIgetnetbynumber\fP(3N),
 and \fIgetnetent\fP(3N) are the network counterparts to the
-host routines described above.
+host routines described above.  The routines extract their
+information from \fI/etc/networks\fP.
+.PP
+NS network numbers are determined either by asking your local
+Xerox Network Administrator (and hardcoding the information
+into your code), or by querying the Clearinghouse for addresses.
+The internetwork router is the only process
+that needs to manipulate network numbers on a regular basis; if
+a process wishes to communicate with a machine, it should ask the
+Clearinghouse for that machine's address (which will include
+the net number).
 .NH 2
 Protocol names
 .PP
 .NH 2
 Protocol names
 .PP
-For protocols the \fIprotoent\fP structure defines the
+For protocols, which are defined in \fI/etc/protocols\fP,
+the \fIprotoent\fP structure defines the
 protocol-name mapping
 used with the routines \fIgetprotobyname\fP(3N),
 \fIgetprotobynumber\fP(3N),
 protocol-name mapping
 used with the routines \fIgetprotobyname\fP(3N),
 \fIgetprotobynumber\fP(3N),
@@ -156,9 +248,13 @@ and \fIgetprotoent\fP(3N):
 struct protoent {
        char    *p_name;        /* official protocol name */
        char    **p_aliases;    /* alias list */
 struct protoent {
        char    *p_name;        /* official protocol name */
        char    **p_aliases;    /* alias list */
-       int     p_proto;        /* protocol # */
+       int     p_proto;        /* protocol number */
 };
 .DE
 };
 .DE
+.PP
+In the NS domain, protocols are indicated by the "client type"
+field of a IDP header.  No protocol database exists; see section
+5 for more information.
 .NH 2
 Service names
 .PP
 .NH 2
 Service names
 .PP
@@ -166,17 +262,18 @@ Information regarding services is a bit more complicated.  A service
 is expected to reside at a specific \*(lqport\*(rq and employ
 a particular communication protocol.  This view is consistent with
 the Internet domain, but inconsistent with other network architectures.
 is expected to reside at a specific \*(lqport\*(rq and employ
 a particular communication protocol.  This view is consistent with
 the Internet domain, but inconsistent with other network architectures.
-Further, a service may reside on multiple ports or support multiple
-protocols.  If either of these occurs, the higher level library routines
+Further, a service may reside on multiple ports.
+If this occurs, the higher level library routines
 will have to be bypassed in favor of homegrown routines similar in
 spirit to the \*(lqgethostbynameandnet\*(rq routine described above.
 will have to be bypassed in favor of homegrown routines similar in
 spirit to the \*(lqgethostbynameandnet\*(rq routine described above.
+Services available are contained in the file \fI/etc/services\fP.
 A service mapping is described by the \fIservent\fP structure,
 .DS
 .DT
 struct servent {
        char    *s_name;        /* official service name */
        char    **s_aliases;    /* alias list */
 A service mapping is described by the \fIservent\fP structure,
 .DS
 .DT
 struct servent {
        char    *s_name;        /* official service name */
        char    **s_aliases;    /* alias list */
-       int     s_port; /* port # */
+       int     s_port; /* port number, network byte order */
        char    *s_proto;       /* protocol to use */
 };
 .DE
        char    *s_proto;       /* protocol to use */
 };
 .DE
@@ -184,7 +281,7 @@ The routine \fIgetservbyname\fP(3N) maps service
 names to a servent structure by specifying a service name and,
 optionally, a qualifying protocol.  Thus the call
 .DS
 names to a servent structure by specifying a service name and,
 optionally, a qualifying protocol.  Thus the call
 .DS
-sp = getservbyname("telnet", (char *)0);
+sp = getservbyname("telnet", (char *) 0);
 .DE
 returns the service specification for a telnet server using
 any protocol, while the call
 .DE
 returns the service specification for a telnet server using
 any protocol, while the call
@@ -196,10 +293,19 @@ The routines \fIgetservbyport\fP(3N) and \fIgetservent\fP(3N) are
 also provided.  The \fIgetservbyport\fP routine has an interface similar
 to that provided by \fIgetservbyname\fP; an optional protocol name may
 be specified to qualify lookups.
 also provided.  The \fIgetservbyport\fP routine has an interface similar
 to that provided by \fIgetservbyname\fP; an optional protocol name may
 be specified to qualify lookups.
+.PP
+In the NS domain, services are handled by a central dispatcher
+provided as part of the Courier remote procedure call facilities.
+Again, the reader is referred to the Courier compiler documentation
+and to the Xerox standard*
+.FS
+* \fICourier: The Remote Procedure Call Protocol\fP, XSIS 038112.
+.FE
+for further details.
 .NH 2
 Miscellaneous
 .PP
 .NH 2
 Miscellaneous
 .PP
-With the support routines described above, an application program
+With the support routines described above, an Internet application program
 should rarely have to deal directly
 with addresses.  This allows
 services to be developed as much as possible in a network independent
 should rarely have to deal directly
 with addresses.  This allows
 services to be developed as much as possible in a network independent
@@ -209,63 +315,13 @@ addresses when naming services and sockets there will always some
 network dependency in a program.  For example, the normal
 code included in client programs, such as the remote login program,
 is of the form shown in Figure 1.
 network dependency in a program.  For example, the normal
 code included in client programs, such as the remote login program,
 is of the form shown in Figure 1.
-.KF
-.DS
-.if t .ta .5i 1.0i 1.5i 2.0i
-.if n .ta .7i 1.4i 2.1i 2.8i
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <stdio.h>
-#include <netdb.h>
- ...
-main(argc, argv)
-       char *argv[];
-{
-       struct sockaddr_in sin;
-       struct servent *sp;
-       struct hostent *hp;
-       int s;
-       ...
-       sp = getservbyname("login", "tcp");
-       if (sp == NULL) {
-               fprintf(stderr, "rlogin: tcp/login: unknown service\en");
-               exit(1);
-       }
-       hp = gethostbyname(argv[1]);
-       if (hp == NULL) {
-               fprintf(stderr, "rlogin: %s: unknown host\en", argv[1]);
-               exit(2);
-       }
-       bzero((char *)&sin, sizeof (sin));
-       bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
-       sin.sin_family = hp->h_addrtype;
-       sin.sin_port = sp->s_port;
-       s = socket(AF_INET, SOCK_STREAM, 0);
-       if (s < 0) {
-               perror("rlogin: socket");
-               exit(3);
-       }
-       ...
-       if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
-               perror("rlogin: connect");
-               exit(5);
-       }
-       ...
-}
-.DE
-.ce
-Figure 1.  Remote login client code.
-.KE
 (This example will be considered in more detail in section 4.)
 .PP
 If we wanted to make the remote login program independent of the 
 Internet protocols and addressing scheme we would be forced to add
 a layer of routines which masked the network dependent aspects from
 the mainstream login code.  For the current facilities available in
 (This example will be considered in more detail in section 4.)
 .PP
 If we wanted to make the remote login program independent of the 
 Internet protocols and addressing scheme we would be forced to add
 a layer of routines which masked the network dependent aspects from
 the mainstream login code.  For the current facilities available in
-the system this does not appear to be worthwhile.  Perhaps when the
-system is adapted to different network architectures the utilities
-will be reorganized more cleanly.
+the system this does not appear to be worthwhile.
 .PP
 Aside from the address-related data base routines, there are several
 other routines available in the run-time library which are of interest
 .PP
 Aside from the address-related data base routines, there are several
 other routines available in the run-time library which are of interest
@@ -295,9 +351,10 @@ Table 1.  C run-time routines.
 .KE
 .PP
 The byte swapping routines are provided because the operating
 .KE
 .PP
 The byte swapping routines are provided because the operating
-system expects addresses to be supplied in network order.  On a
-VAX, or machine with similar architecture, this
-is usually reversed.  Consequently,
+system expects addresses to be supplied in network order.  On
+some architectures, such as the VAX,
+host byte ordering is different than
+network byte ordering.  Consequently,
 programs are sometimes required to byte swap quantities.  The
 library routines which return network addresses provide them
 in network order so that they may simply be copied into the structures
 programs are sometimes required to byte swap quantities.  The
 library routines which return network addresses provide them
 in network order so that they may simply be copied into the structures
@@ -308,5 +365,54 @@ code would be required:
 .DS
 printf("port number %d\en", ntohs(sp->s_port));
 .DE
 .DS
 printf("port number %d\en", ntohs(sp->s_port));
 .DE
-On machines other than the VAX these routines are defined as null
+On machines where unneeded these routines are defined as null
 macros.
 macros.
+.DS
+.if t .ta .5i 1.0i 1.5i 2.0i
+.if n .ta .7i 1.4i 2.1i 2.8i
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <netdb.h>
+ ...
+main(argc, argv)
+       int argc;
+       char *argv[];
+{
+       struct sockaddr_in server;
+       struct servent *sp;
+       struct hostent *hp;
+       int s;
+       ...
+       sp = getservbyname("login", "tcp");
+       if (sp == NULL) {
+               fprintf(stderr, "rlogin: tcp/login: unknown service\en");
+               exit(1);
+       }
+       hp = gethostbyname(argv[1]);
+       if (hp == NULL) {
+               fprintf(stderr, "rlogin: %s: unknown host\en", argv[1]);
+               exit(2);
+       }
+       bzero((char *)&server, sizeof (server));
+       bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
+       server.sin_family = hp->h_addrtype;
+       server.sin_port = sp->s_port;
+       s = socket(AF_INET, SOCK_STREAM, 0);
+       if (s < 0) {
+               perror("rlogin: socket");
+               exit(3);
+       }
+       ...
+       /* Connect does the bind() for us */
+
+       if (connect(s, (char *)&server, sizeof (server)) < 0) {
+               perror("rlogin: connect");
+               exit(5);
+       }
+       ...
+}
+.DE
+.ce
+Figure 1.  Remote login client code.
index 9765059..b7ddda5 100644 (file)
@@ -1,7 +1,14 @@
+.\" Copyright (c) 1986 Regents of the University of California.
+.\" All rights reserved.  The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\"    @(#)4.t 1.2 (Berkeley) %G%
+.\"
 .ds RH "Client/Server Model
 .bp
 .nr H1 4
 .nr H2 0
 .ds RH "Client/Server Model
 .bp
 .nr H1 4
 .nr H2 0
+.sp 8i
 .bp
 .LG
 .B
 .bp
 .LG
 .B
@@ -19,13 +26,13 @@ in section 2.  In this section we will look more closely at the interactions
 between client and server, and consider some of the problems in developing
 client and server applications.
 .PP
 between client and server, and consider some of the problems in developing
 client and server applications.
 .PP
-Client and server require a well known set of conventions before
+The client and server require a well known set of conventions before
 service may be rendered (and accepted).  This set of conventions
 comprises a protocol which must be implemented at both ends of a
 connection.  Depending on the situation, the protocol may be symmetric
 or asymmetric.  In a symmetric protocol, either side may play the 
 master or slave roles.  In an asymmetric protocol, one side is
 service may be rendered (and accepted).  This set of conventions
 comprises a protocol which must be implemented at both ends of a
 connection.  Depending on the situation, the protocol may be symmetric
 or asymmetric.  In a symmetric protocol, either side may play the 
 master or slave roles.  In an asymmetric protocol, one side is
-immutably recognized as the master, with the other the slave.  
+immutably recognized as the master, with the other as the slave.  
 An example of a symmetric protocol is the TELNET protocol used in
 the Internet for remote terminal emulation.  An example
 of an asymmetric protocol is the Internet file transfer protocol,
 An example of a symmetric protocol is the TELNET protocol used in
 the Internet for remote terminal emulation.  An example
 of an asymmetric protocol is the Internet file transfer protocol,
@@ -35,42 +42,53 @@ is a \*(lqclient process\*(rq and a \*(lqserver process\*(rq.  We
 will first consider the properties of server processes, then
 client processes.
 .PP
 will first consider the properties of server processes, then
 client processes.
 .PP
-A server process normally listens at a well know address for
-service requests.  Alternative schemes which use a service server
+A server process normally listens at a well known address for
+service requests.  That is, the server process remains dormant
+until a connection is requested by a client's connection
+to the server's address.  At such a time
+the server process ``wakes up'' and services the client,
+performing whatever appropriate actions the client requests of it.
+.PP
+Alternative schemes which use a service server
 may be used to eliminate a flock of server processes clogging the
 may be used to eliminate a flock of server processes clogging the
-system while remaining dormant most of the time.  The Xerox
-Courier protocol uses the latter scheme.  When using Courier, a
-Courier client process contacts a Courier server at the remote
-host and identifies the service it requires.  The Courier server
-process then creates the appropriate server process based on a
-data base and \*(lqsplices\*(rq the client and server together,
-voiding its part in the transaction.  This scheme is attractive
-in that the Courier server process may provide a single contact
-point for all services, as well as carrying out the initial steps
-in authentication.  However, while this is an attractive possibility
-for standardizing access to services, it does introduce a certain
-amount of overhead due to the intermediate process involved.
-Implementations which provide this type of service within the
-system can minimize the cost of client server
-rendezvous.  The \fIportal\fP notion described
-in the \*(lq4.2BSD System Manual\*(rq embodies many of the ideas
-found in Courier, with the rendezvous mechanism implemented internal
-to the system.
+system while remaining dormant most of the time.  For Internet
+servers in 4.3BSD,
+this scheme has been implemented via \fIinetd\fP, the so called
+``internet super-server.''  \fIInetd\fP listens at a variety
+of ports, determined at start-up by reading a configuration file.
+When a connection is requested to a port on which \fIinetd\fP is
+listening, \fIinetd\fP executes the appropriate server program to handle the
+client.  With this method, clients are unaware that an
+intermediary such as \fIinetd\fP has played any part in the
+connection.  \fIInetd\fP will be described in more detail in
+section 5.
+.PP
+A similar alternative scheme is used by most Xerox services.  In general,
+the Courier dispatch process (if used) accepts connections from
+processes requesting services of some sort or another.  The client
+processes request a particular <program number, version number, procedure
+number> triple.  If the dispatcher knows of such a program, it is
+started to handle the request; if not, an error is reported to the
+client.  In this way, only one port is required to service a large
+variety of different requests.  Again, the Courier facilities are
+not available without the use and installation of the Courier
+compiler.  The information presented in this section applies only
+to NS clients and services that do not use Courier.
 .NH 2
 Servers
 .PP
 .NH 2
 Servers
 .PP
-In 4.2BSD most servers are accessed at well known Internet addresses
-or UNIX domain names.  When a server is started at boot time it
-advertises it services by listening at a well know location.  For
+In 4.3BSD most servers are accessed at well known Internet addresses
+or UNIX domain names.  For
 example, the remote login server's main loop is of the form shown
 in Figure 2.
 .KF
 example, the remote login server's main loop is of the form shown
 in Figure 2.
 .KF
-.if t .ta .5i 1.0i 1.5i 2.0i
-.if n .ta .7i 1.4i 2.1i 2.8i
+.if t .ta .5i 1.0i 1.5i 2.0i 2.5i 3.0i 3.5i
+.if n .ta .7i 1.4i 2.1i 2.8i 3.5i 4.2i 4.9i
+.sp 0.5i
 .DS
 main(argc, argv)
        int argc;
 .DS
 main(argc, argv)
        int argc;
-       char **argv;
+       char *argv[];
 {
        int f;
        struct sockaddr_in from;
 {
        int f;
        struct sockaddr_in from;
@@ -83,14 +101,15 @@ main(argc, argv)
        }
        ...
 #ifndef DEBUG
        }
        ...
 #ifndef DEBUG
-       <<disassociate server from controlling terminal>>
-#endif
+       /* Disassociate server from controlling terminal */
        ...
        ...
-       sin.sin_port = sp->s_port;
+#endif
+
+       sin.sin_port = sp->s_port;      /* Restricted port -- see section 5 */
        ...
        f = socket(AF_INET, SOCK_STREAM, 0);
        ...
        ...
        f = socket(AF_INET, SOCK_STREAM, 0);
        ...
-       if (bind(f, (caddr_t)&sin, sizeof (sin)) < 0) {
+       if (bind(f, (struct sockaddr *) &sin, sizeof (sin)) < 0) {
                ...
        }
        ...
                ...
        }
        ...
@@ -98,10 +117,10 @@ main(argc, argv)
        for (;;) {
                int g, len = sizeof (from);
 
        for (;;) {
                int g, len = sizeof (from);
 
-               g = accept(f, &from, &len);
+               g = accept(f, (struct sockaddr *) &from, &len);
                if (g < 0) {
                        if (errno != EINTR)
                if (g < 0) {
                        if (errno != EINTR)
-                               perror("rlogind: accept");
+                               syslog(LOG_ERR, "rlogind: accept: %m");
                        continue;
                }
                if (fork() == 0) {
                        continue;
                }
                if (fork() == 0) {
@@ -114,7 +133,7 @@ main(argc, argv)
 .DE
 .ce
 Figure 2.  Remote login server.
 .DE
 .ce
 Figure 2.  Remote login server.
-.sp
+.sp 0.5i
 .KE
 .PP
 The first step taken by the server is look up its service
 .KE
 .PP
 The first step taken by the server is look up its service
@@ -132,37 +151,64 @@ if (sp == NULL) {
 .sp 1
 .in -5
 .fi
 .sp 1
 .in -5
 .fi
-This definition is used in later portions of the code to
+The result of the \fIgetservbyname\fP call
+is used in later portions of the code to
 define the Internet port at which it listens for service
 requests (indicated by a connection).
 define the Internet port at which it listens for service
 requests (indicated by a connection).
+.KS
 .PP
 Step two is to disassociate the server from the controlling
 .PP
 Step two is to disassociate the server from the controlling
-terminal of its invoker.  This is important as the server will
+terminal of its invoker:
+.DS
+       for (i = 0; i < 3; ++i)
+               close(i);
+
+       open("/", O_RDONLY);
+       dup2(0, 1);
+       dup2(0, 2);
+
+       i = open("/dev/tty", O_RDWR);
+       if (i >= 0) {
+               ioctl(i, TIOCNOTTY, 0);
+               close(i);
+       }
+.DE
+.KE
+This step is important as the server will
 likely not want to receive signals delivered to the process
 likely not want to receive signals delivered to the process
-group of the controlling terminal. 
+group of the controlling terminal.  Note, however, that
+once a server has disassociated itself it can no longer
+send reports of errors to a terminal, and must log errors
+via \fIsyslog\fP.
 .PP
 Once a server has established a pristine environment, it
 creates a socket and begins accepting service requests.
 The \fIbind\fP call is required to insure the server listens
 .PP
 Once a server has established a pristine environment, it
 creates a socket and begins accepting service requests.
 The \fIbind\fP call is required to insure the server listens
-at its expected location.  The main body of the loop is
-fairly simple:
+at its expected location.  It should be noted that the
+remote login server listens at a restricted port number, and must
+therefore be run
+with a user-id of root.
+This concept of a ``restricted port number'' is 4BSD
+specific, and is covered in section 5.
+.PP
+The main body of the loop is fairly simple:
 .DS
 .if t .ta .5i 1.0i 1.5i 2.0i
 .if n .ta .7i 1.4i 2.1i 2.8i
 for (;;) {
        int g, len = sizeof (from);
 
 .DS
 .if t .ta .5i 1.0i 1.5i 2.0i
 .if n .ta .7i 1.4i 2.1i 2.8i
 for (;;) {
        int g, len = sizeof (from);
 
-       g = accept(f, &from, &len);
+       g = accept(f, (struct sockaddr *)&from, &len);
        if (g < 0) {
                if (errno != EINTR)
        if (g < 0) {
                if (errno != EINTR)
-                       perror("rlogind: accept");
+                       syslog(LOG_ERR, "rlogind: accept: %m");
                continue;
        }
                continue;
        }
-       if (fork() == 0) {
+       if (fork() == 0) {      /* Child */
                close(f);
                doit(g, &from);
        }
                close(f);
                doit(g, &from);
        }
-       close(g);
+       close(g);               /* Parent */
 }
 .DE
 An \fIaccept\fP call blocks the server until
 }
 .DE
 An \fIaccept\fP call blocks the server until
@@ -170,12 +216,16 @@ a client requests service.  This call could return a
 failure status if the call is interrupted by a signal
 such as SIGCHLD (to be discussed in section 5).  Therefore,
 the return value from \fIaccept\fP is checked to insure
 failure status if the call is interrupted by a signal
 such as SIGCHLD (to be discussed in section 5).  Therefore,
 the return value from \fIaccept\fP is checked to insure
-a connection has actually been established.  With a connection
+a connection has actually been established, and
+an error report is logged via \fIsyslog\fP if an error
+has occurred.
+.PP
+With a connection
 in hand, the server then forks a child process and invokes
 the main body of the remote login protocol processing.  Note
 how the socket used by the parent for queueing connection
 requests is closed in the child, while the socket created as
 in hand, the server then forks a child process and invokes
 the main body of the remote login protocol processing.  Note
 how the socket used by the parent for queueing connection
 requests is closed in the child, while the socket created as
-a result of the accept is closed in the parent.  The
+a result of the \fIaccept\fP is closed in the parent.  The
 address of the client is also handed the \fIdoit\fP routine
 because it requires it in authenticating clients.
 .NH 2
 address of the client is also handed the \fIdoit\fP routine
 because it requires it in authenticating clients.
 .NH 2
@@ -189,7 +239,7 @@ listening for client connections, while the client process is
 an active entity, initiating a connection when invoked.  
 .PP
 Let us consider more closely the steps taken
 an active entity, initiating a connection when invoked.  
 .PP
 Let us consider more closely the steps taken
-by the client remote login process.  As in the server process
+by the client remote login process.  As in the server process,
 the first step is to locate the service definition for a remote
 login:
 .DS
 the first step is to locate the service definition for a remote
 login:
 .DS
@@ -212,14 +262,16 @@ With this accomplished, all that is required is to establish a
 connection to the server at the requested host and start up the
 remote login protocol.  The address buffer is cleared, then filled
 in with the Internet address of the foreign host and the port
 connection to the server at the requested host and start up the
 remote login protocol.  The address buffer is cleared, then filled
 in with the Internet address of the foreign host and the port
-number at which the login process resides:
+number at which the login process resides on the foreign host:
 .DS
 .DS
-bzero((char *)&sin, sizeof (sin));
-bcopy(hp->h_addr, (char *)sin.sin_addr, hp->h_length);
-sin.sin_family = hp->h_addrtype;
-sin.sin_port = sp->s_port;
+bzero((char *)&server, sizeof (server));
+bcopy(hp->h_addr, (char *) &server.sin_addr, hp->h_length);
+server.sin_family = hp->h_addrtype;
+server.sin_port = sp->s_port;
 .DE
 .DE
-A socket is created, and a connection initiated.
+A socket is created, and a connection initiated.  Note
+that \fIconnect\fP implicitly performs a \fIbind\fP
+call, since \fIs\fP is unbound.
 .DS
 s = socket(hp->h_addrtype, SOCK_STREAM, 0);
 if (s < 0) {
 .DS
 s = socket(hp->h_addrtype, SOCK_STREAM, 0);
 if (s < 0) {
@@ -227,7 +279,7 @@ if (s < 0) {
        exit(3);
 }
  ...
        exit(3);
 }
  ...
-if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
+if (connect(s, (struct sockaddr *) &server, sizeof (server)) < 0) {
        perror("rlogin: connect");
        exit(4);
 }
        perror("rlogin: connect");
        exit(4);
 }
@@ -311,33 +363,39 @@ main()
        ...
        s = socket(AF_INET, SOCK_DGRAM, 0);
        ...
        ...
        s = socket(AF_INET, SOCK_DGRAM, 0);
        ...
-       bind(s, &sin, sizeof (sin));
+       on = 1;
+       if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
+               syslog(LOG_ERR, "setsockopt SO_BROADCAST: %m");
+               exit(1);
+       }
+       bind(s, (struct sockaddr *) &sin, sizeof (sin));
        ...
        ...
-       sigset(SIGALRM, onalrm);
+       signal(SIGALRM, onalrm);
        onalrm();
        for (;;) {
                struct whod wd;
                int cc, whod, len = sizeof (from);
 
        onalrm();
        for (;;) {
                struct whod wd;
                int cc, whod, len = sizeof (from);
 
-               cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0, &from, &len);
+               cc = recvfrom(s, (char *)&wd, sizeof (struct whod), 0,
+                   (struct sockaddr *)&from, &len);
                if (cc <= 0) {
                        if (cc < 0 && errno != EINTR)
                if (cc <= 0) {
                        if (cc < 0 && errno != EINTR)
-                               perror("rwhod: recv");
+                               syslog(LOG_ERR, "rwhod: recv: %m");
                        continue;
                }
                if (from.sin_port != sp->s_port) {
                        continue;
                }
                if (from.sin_port != sp->s_port) {
-                       fprintf(stderr, "rwhod: %d: bad from port\en",
+                       syslog(LOG_ERR, "rwhod: %d: bad from port",
                                ntohs(from.sin_port));
                        continue;
                }
                ...
                if (!verify(wd.wd_hostname)) {
                                ntohs(from.sin_port));
                        continue;
                }
                ...
                if (!verify(wd.wd_hostname)) {
-                       fprintf(stderr, "rwhod: malformed host name from %x\en",
+                       syslog(LOG_ERR, "rwhod: malformed host name from %x",
                                ntohl(from.sin_addr.s_addr));
                        continue;
                }
                (void) sprintf(path, "%s/whod.%s", RWHODIR, wd.wd_hostname);
                                ntohl(from.sin_addr.s_addr));
                        continue;
                }
                (void) sprintf(path, "%s/whod.%s", RWHODIR, wd.wd_hostname);
-               whod = open(path, FWRONLY|FCREATE|FTRUNCATE, 0666);
+               whod = open(path, O_RDONLY | O_CREAT | O_TRUNC, 0666);
                ...
                (void) time(&wd.wd_recvtime);
                (void) write(whod, (char *)&wd, cc);
                ...
                (void) time(&wd.wd_recvtime);
                (void) write(whod, (char *)&wd, cc);
@@ -347,6 +405,7 @@ main()
 .DE
 .ce
 Figure 4.  rwho server.
 .DE
 .ce
 Figure 4.  rwho server.
+.sp
 .KE
 .PP
 The second task performed by the server is to supply information
 .KE
 .PP
 The second task performed by the server is to supply information
@@ -356,23 +415,27 @@ and broadcasting it on the local network for other rwho servers
 to hear.  The supply function is triggered by a timer and 
 runs off a signal.  Locating the system status
 information is somewhat involved, but uninteresting.  Deciding
 to hear.  The supply function is triggered by a timer and 
 runs off a signal.  Locating the system status
 information is somewhat involved, but uninteresting.  Deciding
-where to transmit the resultant packet does, however, indicates
-some problems with the current protocol.
+where to transmit the resultant packet
+is somewhat problematical, however.
 .PP
 .PP
-Status information is broadcast on the local network.
+Status information must be broadcast on the local network.
 For networks which do not support the notion of broadcast another
 scheme must be used to simulate or
 replace broadcasting.  One possibility is to enumerate the
 For networks which do not support the notion of broadcast another
 scheme must be used to simulate or
 replace broadcasting.  One possibility is to enumerate the
-known neighbors (based on the status received).  This, unfortunately,
-requires some bootstrapping information, as a
-server started up on a quiet network will have no
+known neighbors (based on the status messages received
+from other rwho servers).  This, unfortunately,
+requires some bootstrapping information,
+for a server will have no idea what machines are its
+neighbors until it receives status messages from them.
+Therefore, if all machines on a net are freshly booted,
+no machine will have any
 known neighbors and thus never receive, or send, any status information.
 This is the identical problem faced by the routing table management
 process in propagating routing status information.  The standard
 solution, unsatisfactory as it may be, is to inform one or more servers
 of known neighbors and request that they always communicate with
 these neighbors.  If each server has at least one neighbor supplied
 known neighbors and thus never receive, or send, any status information.
 This is the identical problem faced by the routing table management
 process in propagating routing status information.  The standard
 solution, unsatisfactory as it may be, is to inform one or more servers
 of known neighbors and request that they always communicate with
 these neighbors.  If each server has at least one neighbor supplied
-it, status information may then propagate through
+to it, status information may then propagate through
 a neighbor to hosts which
 are not (possibly) directly neighbors.  If the server is able to
 support networks which provide a broadcast capability, as well as
 a neighbor to hosts which
 are not (possibly) directly neighbors.  If the server is able to
 support networks which provide a broadcast capability, as well as
@@ -385,24 +448,32 @@ will receive status information from itself.  This can lead
 to an endless, wasteful, exchange of information.
 .FE
 .PP
 to an endless, wasteful, exchange of information.
 .FE
 .PP
-The second problem with the current scheme is that the rwho process
-services only a single local network, and this network is found by
-reading a file.  It is important that software operating in a distributed
+It is important that software operating in a distributed
 environment not have any site-dependent information compiled into it.
 This would require a separate copy of the server at each host and
 environment not have any site-dependent information compiled into it.
 This would require a separate copy of the server at each host and
-make maintenance a severe headache.  4.2BSD attempts to isolate
+make maintenance a severe headache.  4.3BSD attempts to isolate
 host-specific information from applications by providing system
 host-specific information from applications by providing system
-calls which return the necessary information\(dg.
+calls which return the necessary information*.
 .FS
 .FS
-\(dg An example of such a system call is the \fIgethostname\fP(2)
+* An example of such a system call is the \fIgethostname\fP(2)
 call which returns the host's \*(lqofficial\*(rq name.
 .FE
 call which returns the host's \*(lqofficial\*(rq name.
 .FE
-Unfortunately, no straightforward mechanism currently
-exists for finding the collection
-of networks to which a host is directly connected.  Thus the
-rwho server performs a lookup in a file
-to find its local network.  A better, though still
-unsatisfactory, scheme used by the routing process is to interrogate
-the system data structures to locate those directly connected
-networks.  A mechanism to acquire this information from the system
-would be a useful addition.
+A mechanism exists, in the form of an \fIioctl\fP call,
+for finding the collection
+of networks to which a host is directly connected.
+Further, a local network broadcasting mechanism
+has been implemented at the socket level.
+Combining these two features allows a process
+to broadcast on any directly connected local
+network which supports the notion of broadcasting
+in a site independent manner.  This allows 4.3BSD
+to solve the problem of deciding how to propagate
+status information in the case of \fIrwho\fP, or
+more generally in broadcasting:
+Such status information is broadcast to connected
+networks at the socket level, where the connected networks
+have been obtained via the appropriate \fIioctl\fP
+calls.
+The specifics of
+such broadcastings are complex, however, and will
+be covered in section 5.
index b5de738..1f204a7 100644 (file)
@@ -1,3 +1,9 @@
+.\" Copyright (c) 1986 Regents of the University of California.
+.\" All rights reserved.  The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\"    @(#)5.t 1.2 (Berkeley) %G%
+.\"
 .ds RH "Advanced Topics
 .bp
 .nr H1 5
 .ds RH "Advanced Topics
 .bp
 .nr H1 5
@@ -12,9 +18,9 @@
 .NL
 .PP
 A number of facilities have yet to be discussed.  For most users
 .NL
 .PP
 A number of facilities have yet to be discussed.  For most users
-of the ipc the mechanisms already
+of the IPC the mechanisms already
 described will suffice in constructing distributed
 described will suffice in constructing distributed
-applications.  However, others will find need to utilize some
+applications.  However, others will find the need to utilize some
 of the features which we consider in this section.
 .NH 2
 Out of band data
 of the features which we consider in this section.
 .NH 2
 Out of band data
@@ -23,11 +29,18 @@ 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
 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.
+independently of normal data along with the SIGURG signal
+(if multiple sockets may have out of band data awaiting
+delivery, a \fIselect\fP call may be used to determine those
+sockets with such data).  A process can set the process group
+or process id to be informed by the SIGURG signal via the
+appropriate \fIfcntl\fP call, as described below for
+SIGIO.
+.PP
 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
 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
+applications use this facility to propagate signals 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.
 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.
@@ -39,15 +52,16 @@ 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
 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
+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
 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.
+buffer all the intervening data.  It is not possible
+to ``peek'' (via MSG_PEEK) at out of band data.
 .PP
 .PP
-To send an out of band message the SOF_OOB flag is supplied to
+To send an out of band message the MSG_OOB flag is supplied to
 a \fIsend\fP or \fIsendto\fP calls,
 a \fIsend\fP or \fIsendto\fP calls,
-while to receive out of band data SOF_OOB should be indicated
+while to receive out of band data MSG_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:
 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:
@@ -62,13 +76,15 @@ in the remote login process to flush output on receipt of an
 interrupt or quit signal is shown in Figure 5.
 .KF
 .DS
 interrupt or quit signal is shown in Figure 5.
 .KF
 .DS
+#include <sys/ioctl.h>
+#include <sys/file.h>
+ ...
 oob()
 {
 oob()
 {
-       int out = 1+1;
+       int out = FWRITE;
        char waste[BUFSIZ], mark;
 
        char waste[BUFSIZ], mark;
 
-       signal(SIGURG, oob);
-       /* flush local terminal input and output */
+       /* flush local terminal output */
        ioctl(1, TIOCFLUSH, (char *)&out);
        for (;;) {
                if (ioctl(rem, SIOCATMARK, &mark) < 0) {
        ioctl(1, TIOCFLUSH, (char *)&out);
        for (;;) {
                if (ioctl(rem, SIOCATMARK, &mark) < 0) {
@@ -79,7 +95,10 @@ oob()
                        break;
                (void) read(rem, waste, sizeof (waste));
        }
                        break;
                (void) read(rem, waste, sizeof (waste));
        }
-       recv(rem, &mark, 1, SOF_OOB);
+       if (recv(rem, &mark, 1, MSG_OOB) < 0) {
+               perror("recv");
+               ...
+       }
        ...
 }
 .DE
        ...
 }
 .DE
@@ -88,18 +107,109 @@ Figure 5.  Flushing terminal i/o on receipt of out of band data.
 .sp
 .KE
 .NH 2
 .sp
 .KE
 .NH 2
+Interrupt driven socket i/o
+.PP
+The SIGIO signal allows a process to be notified
+via a signal when a socket (or more generally, a file
+descriptor) has data waiting to be read.  Use of
+the SIGIO facility requires three steps:  First,
+the process must set up a SIGIO signal handler
+by use of the \fIsignal\fP call.  Second,
+it must set the process id or process group id which is to receive
+notification of pending input to its own process id,
+or the process group id of its process group (note that
+the default process group of a socket is group zero).
+This is accomplished by use of a \fIfcntl\fP call.
+Third, it must turn on notification of pending i/o requests
+with another \fIfcntl\fP call.  Sample code to
+allow a given process to receive information on
+pending i/o requests as they occur for a socket \fIs\fP
+is given in Figure 6.  With slight change, this code can also
+be used to prepare for receipt of SIGURG signals.
+.KF
+.DS
+#include <fcntl.h>
+ ...
+int    io_handler();
+ ...
+signal(SIGIO, io_handler);
+
+/* Set the process receiving SIGIO/SIGURG signals to us */
+
+if (fcntl(s, F_SETOWN, getpid()) < 0) {
+       perror("fcntl F_SETOWN");
+       exit(1);
+}
+
+/* Allow receipt of asynchronous i/o signals */
+
+if (fcntl(s, F_SETFL, FASYNC) < 0) {
+       perror("fcntl F_SETFL, FASYNC");
+       exit(1);
+}
+.DE
+.ce
+Figure 6.  Use of asynchronous notification of i/o requests.
+.sp
+.KE
+.NH 2
 Signals and process groups
 .PP
 Due to the existence of the SIGURG and SIGIO signals each socket has an
 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:
+associated process number, just as is done for terminals.
+This value is initialized to zero,
+but may be redefined at a later time with the F_SETOWN
+\fIfcntl\fP, such as was done in the code above for SIGIO.
+To set the socket's process id for signals, positive arguments
+should be given to the \fIfcntl\fP call.  To set the socket's
+process group for signals, negative arguments should be 
+passed to \fIfcntl\fP.  Note that the process number indicates
+either the associated process id or the associated process
+group; it is impossible to specify both at the same time.
+A similar \fIfcntl\fP, F_GETOWN, is available for determining the
+current process number of a socket.
+.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 shown in Figure 7.
+.KF
 .DS
 .DS
-ioctl(s, SIOCSPGRP, &pgrp);
+int reaper();
+ ...
+signal(SIGCHLD, reaper);
+listen(f, 5);
+for (;;) {
+       int g, len = sizeof (from);
+
+       g = accept(f, (struct sockaddr *)&from, &len,);
+       if (g < 0) {
+               if (errno != EINTR)
+                       syslog(LOG_ERR, "rlogind: accept: %m");
+               continue;
+       }
+       ...
+}
+ ...
+#include <wait.h>
+reaper()
+{
+       union wait status;
+
+       while (wait3(&status, WNOHANG, 0) > 0)
+               ;
+}
 .DE
 .DE
-A similar ioctl, SIOCGPGRP, is available for determining the
-current process group of a socket.
+.sp
+.ce
+Figure 7.  Use of the SIGCHLD signal.
+.sp
+.KE
+.PP
+If the parent server process fails to reap its children,
+a large number of \*(lqzombie\*(rq processes may be created.
 .NH 2
 Pseudo terminals
 .PP
 .NH 2
 Pseudo terminals
 .PP
@@ -111,10 +221,16 @@ 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
 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
+from the master side, while data written on the master side is
+given to the slave as input.  In this way, the process manipulating
 the master side of the pseudo terminal has control over the
 the master side of the pseudo terminal has control over the
-information read and written on the slave side.  The remote
+information read and written on the slave side.
+The purpose of this abstraction is to
+preserve terminal semantics over a network connection \(em
+that is, the slave side looks like a normal terminal to
+any process reading from or writing to it.
+.PP
+For example, 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,
 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,
@@ -126,31 +242,151 @@ 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.  
 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.  
+.PP
+Under 4.3BSD, the slave side of a pseudo terminal is
+\fI/dev/ttyxy\fP, where \fIx\fP is a single letter
+starting at `p' and perhaps continuing as far down
+as `t'.  \fIy\fP is a hexidecimal ``digit'' (i.e., a single
+character in the range 0 through 9 or `a' through `f').
+The master side of a pseudo terminal is \fI/dev/ptyxy\fP,
+where \fIx\fP and \fIy\fP correspond to the same letters
+in the slave side of the pseudo terminal.
+.PP
+In general, the method of obtaining a pair of master and
+slave pseudo terminals is made up of three components.
+First, the process must find a pseudo terminal which
+is not currently in use.  Having done so,
+it then opens both the master and the slave side of
+the device, taking care to open the master side of the device first.
+The process then \fIfork\fPs; the child closes
+the master side of the pseudo terminal, and \fIexec\fPs the
+appropriate program.  Meanwhile, the parent closes the
+slave side of the pseudo terminal and begins reading and
+writing from the master side.  Sample code making use of
+pseudo terminals is given in Figure 8; this code assumes
+that a connection on a socket \fIs\fP exists, connected
+to a peer who wants a service of some kind, and that the
+process has disassociated itself from a controlling terminal.
+.KF
+.DS
+gotpty = 0;
+for (c = 'p'; !gotpty && c <= 's'; c++) {
+       line = "/dev/ptyXX";
+       line[sizeof("/dev/pty")-1] = c;
+       line[sizeof("/dev/ptyp")-1] = '0';
+       if (stat(line, &statbuf) < 0)
+               break;
+       for (i = 0; i < 16; i++) {
+               line[sizeof("/dev/ptyp")-1] = "0123456789abcdef"[i];
+               master = open(line, O_RDWR);
+               if (master > 0) {
+                       gotpty = 1;
+                       break;
+               }
+       }
+}
+if (!gotpty) {
+       syslog(LOG_ERR, "All network ports in use");
+       exit(1);
+}
+
+line[sizeof("/dev/")-1] = 't';
+slave = open(line, O_RDWR);    /* \fIslave\fP is now slave side */
+if (slave < 0) {
+       syslog(LOG_ERR, "Cannot open slave pty %s", line);
+       exit(1);
+}
+
+ioctl(slave, TIOCGETP, &b);    /* Set slave tty modes */
+b.sg_flags = CRMOD|XTABS|ANYP;
+ioctl(slave, TIOCSETP, &b);
+
+i = fork();
+if (i < 0) {
+       syslog(LOG_ERR, "fork: %m");
+       exit(1);
+} else if (i) {                /* Parent */
+       close(slave);
+       ...
+} else {                /* Child */
+       (void) close(s);
+       (void) close(master);
+       dup2(slave, 0);
+       dup2(slave, 1);
+       dup2(slave, 2);
+       if (slave > 2)
+               (void) close(slave);
+       ...
+}
+.DE
+.ce
+Figure 8.  Creation and use of a pseudo terminal
+.sp
+.KE
 .NH 2
 .NH 2
-Internet address binding
+Selecting specific protocols
 .PP
 .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
+If the third argument to the \fIsocket\fP call is 0,
+\fIsocket\fP will select a default protocol to use with
+the returned socket of the type requested.  This
+protocol should be correct for almost every situation.
+Still, it is conceivable that the user may wish to specify
+a particular protocol for use with a given socket.
+.PP
+To obtain a particular protocol one selects the protocol number,
+as defined within the communication domain.  For the Internet
+domain the available protocols are defined in <\fInetinet/in.h\fP>
+or, better yet, one may use one of the library routines
+discussed in section 3, such as \fIgetprotobyname\fP:
+.DS
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+ ...
+pp = getprotobyname("newtcp");
+s = socket(AF_INET, SOCK_STREAM, pp->p_proto);
+.DE
+This would result in a socket \fIs\fP using a stream
+based connection, but with protocol type of ``newtcp''
+instead of the default ``tcp.''
+.PP
+In the NS domain, the available socket protocols are defined in
+<\fInetns/ns.h\fP>.  To create a raw socket for Xerox Error Protocol
+messages, one might use:
+.DS
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netns/ns.h>
+ ...
+s = socket(AF_NS, SOCK_RAW, NSPROTO_ERROR);
+.DE
+.NH 2
+Address binding
+.PP
+As was mentioned in section 2, 
+binding addresses to sockets in the Internet and NS domains can be
+fairly complex.  As a brief reminder, these associations
+are composed of local and foreign
 addresses, and local and foreign ports.  Port numbers are
 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.
+allocated out of separate spaces, one for each system and one
+for each domain on that system.
+Through the \fIbind\fP system call, a
+process may specify half of an association, the
+<local address, local port> part, while the
+\fIconnect\fP
+and \fIaccept\fP
+primitives are used to complete a socket's association by
+specifying the <foreign address, foreign port> part.
 Since the association is created in two steps the association
 Since the association is created in two steps the association
-uniqueness requirement indicated above could be violated unless
+uniqueness requirement indicated previously 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
 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
+To simplify local address binding in the Internet domain 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 
 \*(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 
@@ -165,56 +401,76 @@ struct sockaddr_in sin;
  ...
 s = socket(AF_INET, SOCK_STREAM, 0);
 sin.sin_family = AF_INET;
  ...
 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));
+sin.sin_addr.s_addr = htonl(INADDR_ANY);
+sin.sin_port = htons(MYPORT);
+bind(s, (struct sockaddr *) &sin, sizeof (sin));
 .DE
 Sockets with wildcarded local addresses may receive messages
 directed to the specified port number, and addressed to any
 .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
+of the possible addresses assigned to a host.  For example,
+if a host is on a networks 128.32 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
 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.
+network 128.32 or network 10.
+If a server process wished to only allow hosts on a
+given network connect to it, it would bind
+the address of the host on the appropriate network.  Such
+an address could perhaps be determined by a routine
+such as \fIgethostbynameandnet\fP, as mentioned in section 3.
 .PP
 In a similar fashion, a local port may be left unspecified
 (specified as zero), in which case the system will select an
 .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:
+appropriate port number for it.  This shortcut will work
+both in the Internet and NS domains.  For example, to
+bind a specific local address to a socket, but to leave the
+local port number unspecified:
 .DS
 .DS
-sin.sin_addr.s_addr = MYADDRESS;
-sin.sin_port = 0;
-bind(s, (char *)&sin, sizeof (sin));
+hp = gethostbyname(hostname);
+if (hp == NULL) {
+       ...
+}
+bcopy(hp->h_addr, (char *) sin.sin_addr, hp->h_length);
+sin.sin_port = htons(0);
+bind(s, (struct sockaddr *) &sin, sizeof (sin));
 .DE
 .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
+The system selects the local port number based on two criteria.
+The first is that on 4BSD systems,
+local ports numbered 0 through 1023 (for the Xerox domain,
+0 through 3000) are reserved
+for privileged users (i.e., the super user).  The second is
 that the port number is not currently bound to some other
 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:
+socket.  In order to find a free Internet port number in the privileged
+range the \fIrresvport\fP library routine may be used as follows
+to return a stream socket in with a privileged port number:
 .DS
 .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;
-       }
+int lport = IPPORT_RESERVED \- 1;
+int s;
+...
+s = rresvport(&lport);
+if (s < 0) {
+       if (errno == EAGAIN)
+               fprintf(stderr, "socket: all ports in use\en");
+       else
+               perror("rresvport: socket");
+       ...
 }
 .DE
 The restriction on allocating ports was done to allow processes
 executing in a \*(lqsecure\*(rq environment to perform authentication
 }
 .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.
+based on the originating address and port number.  For example,
+the \fIrlogin\fP(1) command allows users to log in across a network
+without being asked for a password, if two conditions hold:
+First, the name of the system the user
+is logging in from is in the file
+\fI/etc/hosts.equiv\fP on the system he is logging
+in to (or the system name and the user name are in
+the user's \fI.rhosts\fP file in the user's home
+directory), and second, that the user's rlogin
+process is coming from a privileged port on the machine he is
+logging in from.  The port number and network address of the
+machine the user is logging in from can be determined either
+by the \fIfrom\fP value-result parameter to the \fIaccept\fP call, or
+from the \fIgetpeername\fP call.
 .PP
 In certain cases the algorithm used by the system in selecting
 port numbers is unsuitable for an application.  This is due to
 .PP
 In certain cases the algorithm used by the system in selecting
 port numbers is unsuitable for an application.  This is due to
@@ -228,8 +484,11 @@ connection's socket were around.  To override the default port
 selection algorithm then an option call must be performed prior
 to address binding:
 .DS
 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));
+ ...
+int    on = 1;
+ ...
+setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+bind(s, (struct sockaddr *) &sin, sizeof (sin));
 .DE
 With the above call, local addresses may be bound which
 are already in use.  This does not violate the uniqueness
 .DE
 With the above call, local addresses may be bound which
 are already in use.  This does not violate the uniqueness
@@ -237,29 +496,6 @@ 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).
 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
 .NH 2
 Broadcasting and datagram sockets
 .PP
@@ -269,80 +505,603 @@ 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,
 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.
+the ability to send broadcast packets has been limited
+to sockets which are explicitly marked as allowing broadcasting.
 .PP
 .PP
-To send a broadcast message, an Internet datagram socket 
+To send a broadcast message, a datagram socket 
 should be created:
 .DS
 s = socket(AF_INET, SOCK_DGRAM, 0);
 .DE
 should be created:
 .DS
 s = socket(AF_INET, SOCK_DGRAM, 0);
 .DE
+or
+.DS
+s = socket(AF_NS, SOCK_DGRAM, 0);
+.DE
+The socket is marked as allowing broadcasting,
+.DS
+int    on = 1;
+
+setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on));
+.DE
 and at least a port number should be bound to the socket:
 .DS
 sin.sin_family = AF_INET;
 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));
+sin.sin_addr.s_addr = htonl(INADDR_ANY);
+sin.sin_port = htons(MYPORT);
+bind(s, (struct sockaddr *) &sin, sizeof (sin));
+.DE
+or, for the NS domain,
+.DS
+sns.sns_family = AF_NS;
+netnum = htonl(net);
+sns.sns_addr.x_net = *(union ns_net *) &netnum; /* insert net number */
+sns.sns_addr.x_port = htons(MYPORT);
+bind(s, (struct sockaddr *) &sns, sizeof (sns));
+.DE
+The destination address of the message to be broadcast
+depends on the network the message is to be broadcast
+on, and therefore requires some knowledge of the networks
+to which the host is connected.  Since this information should
+be obtained in a host-independent fashion, 4.3BSD provides a method of
+retrieving this information from the system data structures.
+The SIOCGIFCONF \fIioctl\fP call returns the interface
+configuration of a host in the form of a
+single \fIifconf\fP structure; this structure contains
+a ``data area'' which is made up of an array of
+of \fIifreq\fP structures, one for each network interface
+to which the host is connected.
+These structures are defined in
+\fI<net/if.h>\fP as follows:
+.DS
+.if t .ta .5i 1.0i 1.5i 3.5i
+.if n .ta .7i 1.4i 2.1i 3.4i
+struct ifconf {
+       int     ifc_len;                /* size of associated buffer */
+       union {
+               caddr_t ifcu_buf;
+               struct  ifreq *ifcu_req;
+       } ifc_ifcu;
+};
+
+#define        ifc_buf ifc_ifcu.ifcu_buf               /* buffer address */
+#define        ifc_req ifc_ifcu.ifcu_req               /* array of structures returned */
+
+#define        IFNAMSIZ        16
+
+struct ifreq {
+       char    ifr_name[IFNAMSIZ];             /* if name, e.g. "en0" */
+       union {
+               struct  sockaddr ifru_addr;
+               struct  sockaddr ifru_dstaddr;
+               struct  sockaddr ifru_broadaddr;
+               short   ifru_flags;
+               caddr_t ifru_data;
+       } ifr_ifru;
+};
+
+.if t .ta \w'  #define'u +\w'  ifr_broadaddr'u +\w'  ifr_ifru.ifru_broadaddr'u
+#define        ifr_addr        ifr_ifru.ifru_addr      /* address */
+#define        ifr_dstaddr     ifr_ifru.ifru_dstaddr   /* other end of p-to-p link */
+#define        ifr_broadaddr   ifr_ifru.ifru_broadaddr /* broadcast address */
+#define        ifr_flags       ifr_ifru.ifru_flags     /* flags */
+#define        ifr_data        ifr_ifru.ifru_data      /* for use by interface */
+.DE
+The actual call which obtains the
+interface configuration is
+.DS
+struct ifconf ifc;
+char buf[BUFSIZ];
+
+ifc.ifc_len = sizeof (buf);
+ifc.ifc_buf = buf;
+if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) {
+       ...
+}
 .DE
 .DE
-Then the message should be addressed as:
+After this call \fIbuf\fP will contain one \fIifreq\fP structure for
+each network to which the host is connected, and
+\fIifc.ifc_len\fP will have been modified to reflect the number
+of bytes used by the \fIifreq\fP structures.
+.PP
+For each structure
+there exists a set of ``interface flags'' which tell
+whether the network corresponding to that interface is
+up or down, point to point or broadcast, etc.  The
+SIOCGIFFLAGS \fIioctl\fP retrieves these
+flags for an interface specified by an \fIifreq\fP
+structure as follows:
 .DS
 .DS
-dst.sin_family = AF_INET;
-dst.sin_addr.s_addr = INADDR_ANY;
-dst.sin_port = DESTPORT;
+struct ifreq *ifr;
+
+ifr = ifc.ifc_req;
+
+for (n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++) {
+       /*
+        * We must be careful that we don't use an interface
+        * devoted to an address family other than our own;
+        * if we were interested in NS interfaces, the
+        * AF_INET would be AF_NS.
+        */
+       if (ifr->ifr_addr.sa_family != AF_INET)
+               continue;
+       if (ioctl(s, SIOCGIFFLAGS, (char *) ifr) < 0) {
+               ...
+       }
+       if ((ifr->ifr_flags & IFF_UP) == 0 ||   /* Skip boring cases */
+           (ifr->ifr_flags & (IFF_BROADCAST | IFF_POINTTOPOINT)) == 0)
+               continue;
 .DE
 .DE
-and, finally, a sendto call may be used:
+.PP
+Once the flags have been obtained, the broadcast address 
+must be obtained.  In the case of broadcast networks this is
+done via the SIOCGIFBRDADDR \fIioctl\fP, while for point-to-point networks
+the address of the destination host is obtained with SIOCGIFDSTADDR.
+.DS
+struct sockaddr dst;
+
+if (ifr->ifr_flags & IFF_POINTTOPOINT) {
+       if (ioctl(s, SIOCGIFDSTADDR, (char *) ifr) < 0) {
+               ...
+       }
+       bcopy((char *) ifr->ifr_dstaddr, (char *) &dst, sizeof (ifr->ifr_dstaddr));
+} else if (ifr->ifr_flags & IFF_BROADCAST) {
+       if (ioctl(s, SIOCGIFBRDADDR, (char *) ifr) < 0) {
+               ...
+       }
+       bcopy((char *) ifr->ifr_broadaddr, (char *) &dst, sizeof (ifr->ifr_broadaddr));
+}
+.DE
+.PP
+After the appropriate \fIioctl\fP's have obtained the broadcast
+or destination address (now in \fIdst\fP), the \fIsendto\fP call may be
+used:
 .DS
 .DS
-sendto(s, buf, buflen, 0, &dst, sizeof (dst));
+       sendto(s, buf, buflen, 0, (struct sockaddr *)&dst, sizeof (dst));
+}
 .DE
 .DE
+In the above loop one \fIsendto\fP occurs for every
+interface the host is connected to which supports the notion of
+broadcast or point-to-point addressing.
+If a process only wished to send broadcast
+messages on a given network, code similar to that outlined above
+would be used, but the loop would need to find the
+correct destination address.
 .PP
 Received broadcast messages contain the senders address
 .PP
 Received broadcast messages contain the senders address
-and port (datagram sockets are anchored before
-a message is allowed to go out).  
+and port, as datagram sockets are bound before
+a message is allowed to go out.
 .NH 2
 .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.
+Socket Options
 .PP
 .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:
+It is possible to set and get a number of options on sockets
+via the \fIsetsockopt\fP and \fIgetsockopt\fP system calls.
+These options include such things as marking a socket for
+broadcasting, not to route, to linger on close, etc.
+The general forms of the calls are:
 .DS
 .DS
-int reaper();
- ...
-sigset(SIGCHLD, reaper);
-listen(f, 10);
-for (;;) {
-       int g, len = sizeof (from);
+setsockopt(s, level, optname, optval, optlen);
+.DE
+and
+.DS
+getsockopt(s, level, optname, optval, optlen);
+.DE
+.PP
+The parameters to the calls are as follows: \fIs\fP
+is the socket on which the option is to be applied.
+\fILevel\fP specifies the protocol layer on which the
+option is to be applied; in most cases this is
+the ``socket level'', indicated by the symbolic constant
+SOL_SOCKET, defined in \fI<sys/socket.h>.\fP
+The actual option is specified in \fIoptname\fP, and is
+a symbolic constant also defined in \fI<sys/socket.h>\fP.
+\fIOptval\fP and \fIOptlen\fP point to the value of the
+option (in most cases, whether the option is to be turned
+on or off), and the length of the value of the option,
+respectively.
+For \fIgetsockopt\fP, \fIoptlen\fP is
+a value-result parameter, initially set to the size of
+the storage area pointed to by \fIoptval\fP, and modified
+upon return to indicate the actual amount of storage used.
+.PP
+An example should help clarify things.  It is sometimes
+useful to determine the type (e.g., stream, datagram, etc.)
+of an existing socket; programs
+under \fIinetd\fP (described below) may need to perform this
+task.  This can be accomplished as follows via the
+SO_TYPE socket option and the \fIgetsockopt\fP call:
+.DS
+#include <sys/types.h>
+#include <sys/socket.h>
 
 
-       g = accept(f, &from, &len, 0);
-       if (g < 0) {
-               if (errno != EINTR)
-                       perror("rlogind: accept");
-               continue;
-       }
+int type, size;
+
+size = sizeof (int);
+
+if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &type, &size) < 0) {
        ...
 }
        ...
 }
+.DE
+After the \fIgetsockopt\fP call, \fItype\fP will be set
+to the value of the socket type, as defined in
+\fI<sys/socket.h>\fP.  If, for example, the socket were
+a datagram socket, \fItype\fP would have the value
+corresponding to SOCK_DGRAM.
+.NH 2
+NS Packet Sequences
+.PP
+The semantics of NS connections demand that
+the user both be able to look inside the network header associated
+with any incoming packet and be able to specify what should go
+in certain fields of an outgoing packet.  The header of an
+IDP-level packet looks like:
+.DS
+.if t .ta \w'struct  'u +\w"  struct ns_addr"u +2.0i
+struct idp {
+       u_short idp_sum;        /* Checksum */
+       u_short idp_len;        /* Length, in bytes, including header */
+       u_char  idp_tc;         /* Transport Control (i.e., hop count) */
+       u_char  idp_pt;         /* Packet Type (i.e., level 2 protocol) */
+       struct ns_addr  idp_dna;        /* Destination Network Address */
+       struct ns_addr  idp_sna;        /* Source Network Address */
+};
+.DE
+Most of the fields are filled in automatically; the only
+field that the user should be concerned with is the 
+\fIpacket type\fP field.  The standard values for this
+field are (as defined in <\fInetns/ns.h\fP>):
+.DS
+.if t .ta \w"  #define"u +\w"  NSPROTO_ERROR"u +1.0i
+#define NSPROTO_RI     1               /* Routing Information */
+#define NSPROTO_ECHO   2               /* Echo Protocol */
+#define NSPROTO_ERROR  3               /* Error Protocol */
+#define NSPROTO_PE     4               /* Packet Exchange */
+#define NSPROTO_SPP    5               /* Sequenced Packet */
+.DE
+For SPP connections, the contents of this field are
+automatically set to NSPROTO_SPP; for IDP packets,
+this value defaults to zero, which means ``unknown''.
+.PP
+The contents of a SPP header (minus the IDP header) are:
+.DS
+.if t .ta \w"  #define"u +\w"  u_short"u +2.0i
+struct sphdr {
+       u_char  sp_cc;          /* connection control */
+#define        SP_SP   0x80            /* system packet */
+#define        SP_SA   0x40            /* send acknowledgement */
+#define        SP_OB   0x20            /* attention (out of band data) */
+#define        SP_EM   0x10            /* end of message */
+       u_char  sp_dt;          /* datastream type */
+       u_short sp_sid;         /* source connection identifier */
+       u_short sp_did;         /* destination connection identifier */
+       u_short sp_seq;         /* sequence number */
+       u_short sp_ack;         /* acknowledge number */
+       u_short sp_alo;         /* allocation number */
+};
+.DE
+Here, the items of interest are the \fIdatastream type\fP and
+the \fIconnection control\fP fields.  The semantics of the
+datastream type are defined by the application(s) in question;
+the value of this field is, by default, zero, but it can be
+used to indicate things such as Xerox's Bulk Data Transfer
+Protocol (in which case it is set to one).  The connection control
+field is a mask of the flags defined above.  The user may
+set or clear the end-of-message bit to indicate
+that a given message is the last of a given substream type,
+or may set/clear the attention bit as an alternate way to
+indicate that a packet should be sent out-of-band.
+.PP
+Using different calls to \fIsetsockopt\fP, is it possible
+to indicate whether prototype headers will be associated by
+the user with each outgoing packet (SO_HEADERS_ON_OUTPUT),
+to indicate whether the headers received by the system should be
+delivered to the user (SO_HEADERS_ON_INPUT), or to indicate
+default information that should be associated with all
+outgoing packets on a given socket (SO_DEFAULT_HEADERS).
+For example, to associate prototype headers with outgoing
+SPP packets, one might use:
+.DS
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netns/ns.h>
+#include <netns/sp.h>
  ...
  ...
-#include <wait.h>
-reaper()
-{
-       union wait status;
-
-       while (wait3(&status, WNOHANG, 0) > 0)
-               ;
+struct sockaddr_ns sns, to;
+int s, on = 1;
+struct databuf {
+       struct sphdr proto_spp; /* prototype header */
+       char buf[534];          /* max. possible data by Xerox std. */
+} buf;
+ ...
+s = socket(AF_NS, SOCK_SEQPACKET, 0);
+ ...
+bind(s, (struct sockaddr *) &sns, sizeof (sns));
+setsockopt(s, NSPROTO_SPP, SO_HEADERS_ON_OUTPUT, &on, sizeof(on));
+ ...
+buf.proto_spp.sp_dt = 1;       /* bulk data */
+buf.proto_spp.sp_cc = SP_EM;   /* end-of-message */
+strcpy(buf.buf, "hello world\en");
+sendto(s, (char *) &buf, sizeof(struct sphdr) + strlen("hello world\en"),
+    (struct sockaddr *) &to, sizeof(to));
+ ...
+.DE
+Note that one must be careful when writing headers; if the prototype
+header is not written with the data with which it is to be associated,
+the kernel will treat the first few bytes of the data as the
+header, with unpredictable results.
+To turn off the above association, and to indicate that packet
+headers received by the system should be passed up to the user,
+one might use:
+.DS
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netns/ns.h>
+#include <netns/sp.h>
+ ...
+struct sockaddr sns;
+int s, on = 1, off = 0;
+ ...
+s = socket(AF_NS, SOCK_SEQPACKET, 0);
+ ...
+bind(s, (struct sockaddr *) &sns, sizeof (sns));
+setsockopt(s, NSPROTO_SPP, SO_HEADERS_ON_OUTPUT, &off, sizeof(off));
+setsockopt(s, NSPROTO_SPP, SO_HEADERS_ON_INPUT, &on, sizeof(on));
+ ...
+.DE
+To indicate a default prototype header to be associated with
+the outgoing packets on an IDP datagram socket, one would use:
+.DS
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netns/ns.h>
+#include <netns/idp.h>
+ ...
+struct sockaddr sns;
+struct idp proto_idp;          /* prototype header */
+int s, on = 1;
+ ...
+s = socket(AF_NS, SOCK_DGRAM, 0);
+ ...
+bind(s, (struct sockaddr *) &sns, sizeof (sns));
+proto_idp.idp_pt = NSPROTO_PE; /* packet exchange */
+setsockopt(s, NSPROTO_IDP, SO_DEFAULT_HEADERS, (char *) &proto_idp,
+    sizeof(proto_idp));
+ ...
+.DE
+.NH 2
+Three-way Handshake
+.PP
+The semantics of SPP connections indicates that a three-way
+handshake, involving changes in the datastream type, should \(em
+but is not absolutely required to \(em take place before a SPP
+connection is closed.  Almost all SPP connections are
+``well-behaved'' in this manner; when communicating with
+any process, it is best to assume that the three-way handshake
+is required unless it is known for certain that it is not
+required.  In a three-way close, the closing process
+indicates that it wishes to close the connection by sending
+a zero-length packet with end-of-message set and with
+datastream type 254.  The other side of the connection
+indicates that it is OK to close by sending a zero-length
+packet with end-of-message set and datastream type 255.  Finally,
+the closing process replies with a zero-length packet with 
+substream type 255; at this point, the connection is considered
+closed.  The following code fragments are simplified examples
+of how one might handle this three-way handshake at the user
+level; in the future, support for this type of close will
+probably be provided as part of the C library or as part of
+the kernel.  The first code fragment below illustrates how a process
+might handle three-way handshake if it sees that the process it
+is communicating with wants to close the connection:
+.DS
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netns/ns.h>
+#include <netns/sp.h>
+ ...
+#ifndef SPPSST_END
+#define SPPSST_END 254
+#define SPPSST_ENDREPLY 255
+#endif
+struct sphdr proto_sp;
+int s;
+ ...
+read(s, buf, BUFSIZE);
+if (((struct sphdr *)buf)->sp_dt == SPPSST_END) {
+       /*
+        * SPPSST_END indicates that the other side wants to
+        * close.
+        */
+       proto_sp.sp_dt = SPPSST_ENDREPLY;
+       proto_sp.sp_cc = SP_EM;
+       setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, (char *)&proto_sp,
+           sizeof(proto_sp));
+       write(s, buf, 0);
+       /*
+        * Write a zero-length packet with datastream type = SPPSST_ENDREPLY
+        * to indicate that the close is OK with us.  The packet that we
+        * don't see (because we don't look for it) is another packet
+        * from the other side of the connection, with SPPSST_ENDREPLY
+        * on it it, too.  Once that packet is sent, the connection is
+        * considered closed; note that we really ought to retransmit
+        * the close for some time if we do not get a reply.
+        */
+       close(s);
+}
+ ...
+.DE
+To indicate to another process that we would like to close the
+connection, the following code would suffice:
+.DS
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netns/ns.h>
+#include <netns/sp.h>
+ ...
+#ifndef SPPSST_END
+#define SPPSST_END 254
+#define SPPSST_ENDREPLY 255
+#endif
+struct sphdr proto_sp;
+int s;
+ ...
+proto_sp.sp_dt = SPPSST_END;
+proto_sp.sp_cc = SP_EM;
+setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, (char *)&proto_sp,
+    sizeof(proto_sp));
+write(s, buf, 0);      /* send the end request */
+proto_sp.sp_dt = SPPSST_ENDREPLY;
+setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, (char *)&proto_sp,
+    sizeof(proto_sp));
+/*
+ * We assume (perhaps unwisely)
+ * that the other side will send the
+ * ENDREPLY, so we'll just send our final ENDREPLY
+ * as if we'd seen theirs already.
+ */
+write(s, buf, 0);
+close(s);
+ ...
+.DE
+.NH 2
+Packet Exchange
+.PP
+The Xerox standard protocols include a protocol that is both
+reliable and datagram-oriented.  This protocol is known as
+Packet Exchange (PEX or PE) and, like SPP, is layered on top
+of IDP.  PEX is important for a number of things: Courier
+remote procedure calls may be expedited through the use
+of PEX, and many Xerox servers are located by doing a PEX
+``BroadcastForServers'' operation.  Although there is no
+implementation of PEX in the kernel,
+it may be simulated at the user level with some clever coding
+and the use of one peculiar \fIgetsockopt\fP.  A PEX packet
+looks like:
+.DS
+.if t .ta \w'struct  'u +\w"  struct idp"u +2.0i
+/*
+ * The packet-exchange header shown here is not defined
+ * as part of any of the system include files.
+ */
+struct pex {
+       struct idp      p_idp;  /* idp header */
+       u_short ph_id[2];       /* unique transaction ID for pex */
+       u_short ph_client;      /* client type field for pex */
+};
+.DE
+The \fIph_id\fP field is used to hold a ``unique id'' that
+is used in duplicate suppression; the \fIph_client\fP
+field indicates the PEX client type (similar to the packet
+type field in the IDP header).  PEX reliability stems from the
+fact that it is an idempotent (``I send a packet to you, you
+send a packet to me'') protocol.  Processes on each side of
+the connection may use the unique id to determine if they have
+seen a given packet before (the unique id field differs on each
+packet sent) so that duplicates may be detected, and to indicate
+which message a given packet is in response to.  If a packet with
+a given unique id is sent and no response is received in a given
+amount of time, the packet is retransmitted until it is decided
+that no response will ever be received.  To simulate PEX, one
+must be able to generate unique ids -- something that is hard to
+do at the user level with any real guarantee that the id is really
+unique.  Therefore, a means (via \fIgetsockopt\fP) has been provided
+for getting unique ids from the kernel.  The following code fragment
+indicates how to get a unique id:
+.DS
+long uniqueid;
+int s, idsize = sizeof(uniqueid);
+ ...
+s = socket(AF_NS, SOCK_DGRAM, 0);
+ ...
+/* get id from the kernel -- only on IDP sockets */
+getsockopt(s, NSPROTO_PE, SO_SEQNO, (char *)&uniqueid, &idsize);
+ ...
+.DE
+The retransmission and duplicate suppression code required to
+simulate PEX fully is left as an exercise for the reader.
+.NH 2
+Non-Blocking Sockets
+.PP
+It is occasionally convenient to make use of sockets
+which do not block; that is, i/o requests which
+would take time and
+would cause the process to wait for their completion are
+not executed, and an error code is returned.
+Once a socket has been created via
+the \fIsocket\fP call, it may be marked as non-blocking
+by \fIfcntl\fP as follows:
+.DS
+#include <fcntl.h>
+ ...
+int    s;
+ ...
+s = socket(AF_INET, SOCK_STREAM, 0);
+ ...
+if (fcntl(s, F_SETFL, FNDELAY) < 0)
+       perror("fcntl F_SETFL, FNDELAY");
+       exit(1);
 }
 }
+ ...
 .DE
 .PP
 .DE
 .PP
-If the parent server process fails to reap its children,
-a large number of \*(lqzombie\*(rq processes may be created.
+When performing non-blocking i/o on sockets, one must be
+careful to check for the error EWOULDBLOCK (stored in the
+global variable \fIerrno\fP), which occurs when
+an operation would normally block, but the socket it
+was performed on is marked as non-blocking.
+In particular, \fIaccept\fP, \fIconnect\fP, \fIsend\fP, \fIrecv\fP,
+\fIread\fP, and \fIwrite\fP can
+all return EWOULDBLOCK, and processes should be prepared
+to deal with such return codes.
+.NH 2
+Inetd
+.PP
+One of the daemons provided with 4.3BSD is \fIinetd\fP, the
+so called ``internet super-server.''  \fIInetd\fP is invoked at boot
+time, and determines from the file \fI/etc/inetd.conf\fP the
+servers for which it is to listen.  Once this information has been
+read and a pristine environment created, \fIinetd\fP proceeds
+to create one socket for each service it is to listen for,
+binding the appropriate port number to each socket.
+.PP
+\fIInetd\fP then performs a \fIselect\fP on all these
+sockets for read availability, waiting for somebody wishing
+a connection to the service corresponding to
+that socket.  \fIInetd\fP then performs an \fIaccept\fP on
+the socket in question, \fIfork\fPs, \fIdup\fPs the new
+socket to file descriptors 0 and 1 (stdin and
+stdout), closes other open file
+descriptors, and \fIexec\fPs the appropriate server.
+.PP
+Servers making use of \fIinetd\fP are considerably simplified,
+as \fIinetd\fP takes care of the majority of the IPC work
+required in establishing a connection.  The server invoked
+by \fIinetd\fP expects the socket connected to its client
+on file descriptors 0 and 1, and may immediately perform
+any operations such as \fIread\fP, \fIwrite\fP, \fIsend\fP,
+or \fIrecv\fP.  Indeed, servers may use
+buffered i/o as provided by the ``stdio'' conventions, as
+long as as they remember to use \fIfflush\fP when appropriate.
+.PP
+One call which may be of interest to individuals writing
+servers under \fIinetd\fP is the \fIgetpeername\fP call,
+which returns the address of the peer (process) connected
+on the other end of the socket.  For example, to log the
+Internet address in ``dot notation'' (e.g., ``128.32.0.4'')
+of a client connected to a server under
+\fIinetd\fP, the following code might be used:
+.DS
+struct sockaddr_in name;
+int namelen = sizeof (name);
+ ...
+if (getpeername(0, (struct sockaddr *)&name, &namelen) < 0) {
+       syslog(LOG_ERR, "getpeername: %m");
+       exit(1);
+} else
+       syslog(LOG_INFO, "Connection from %s", inet_ntoa(name.sin_addr));
+ ...
+.DE
+While the \fIgetpeername\fP call is especially useful when
+writing programs to run with \fIinetd\fP, it can be used
+at any time.  Be warned, however, that \fIgetpeername\fP will
+fail on UNIX domain sockets, as their addresses (i.e., pathnames)
+are inaccessible.