Annotation of 43BSDReno/share/doc/ps1/08.ipc/5.t, revision 1.1

1.1     ! root        1: .\" Copyright (c) 1986 The Regents of the University of California.
        !             2: .\" All rights reserved.
        !             3: .\"
        !             4: .\" Redistribution and use in source and binary forms are permitted
        !             5: .\" provided that the above copyright notice and this paragraph are
        !             6: .\" duplicated in all such forms and that any documentation,
        !             7: .\" advertising materials, and other materials related to such
        !             8: .\" distribution and use acknowledge that the software was developed
        !             9: .\" by the University of California, Berkeley.  The name of the
        !            10: .\" University may not be used to endorse or promote products derived
        !            11: .\" from this software without specific prior written permission.
        !            12: .\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
        !            13: .\" IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
        !            14: .\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            15: .\"
        !            16: .\"    @(#)5.t 1.6 (Berkeley) 3/7/89
        !            17: .\"
        !            18: .\".ds RH "Advanced Topics
        !            19: .bp
        !            20: .nr H1 5
        !            21: .nr H2 0
        !            22: .LG
        !            23: .B
        !            24: .ce
        !            25: 5. ADVANCED TOPICS
        !            26: .sp 2
        !            27: .R
        !            28: .NL
        !            29: .PP
        !            30: A number of facilities have yet to be discussed.  For most users
        !            31: of the IPC the mechanisms already
        !            32: described will suffice in constructing distributed
        !            33: applications.  However, others will find the need to utilize some
        !            34: of the features which we consider in this section.
        !            35: .NH 2
        !            36: Out of band data
        !            37: .PP
        !            38: The stream socket abstraction includes the notion of \*(lqout
        !            39: of band\*(rq data.  Out of band data is a logically independent 
        !            40: transmission channel associated with each pair of connected
        !            41: stream sockets.  Out of band data is delivered to the user
        !            42: independently of normal data.
        !            43: The abstraction defines that the out of band data facilities
        !            44: must support the reliable delivery of at least one
        !            45: out of band message at a time.  This message may contain at least one
        !            46: byte of data, and at least one message may be pending delivery
        !            47: to the user at any one time.  For communications protocols which
        !            48: support only in-band signaling (i.e. the urgent data is
        !            49: delivered in sequence with the normal data), the system normally extracts
        !            50: the data from the normal data stream and stores it separately.
        !            51: This allows users to choose between receiving the urgent data
        !            52: in order and receiving it out of sequence without having to
        !            53: buffer all the intervening data.  It is possible
        !            54: to ``peek'' (via MSG_PEEK) at out of band data.
        !            55: If the socket has a process group, a SIGURG signal is generated
        !            56: when the protocol is notified of its existence.
        !            57: A process can set the process group
        !            58: or process id to be informed by the SIGURG signal via the
        !            59: appropriate \fIfcntl\fP call, as described below for
        !            60: SIGIO.
        !            61: If multiple sockets may have out of band data awaiting
        !            62: delivery, a \fIselect\fP call for exceptional conditions
        !            63: may be used to determine those sockets with such data pending.
        !            64: Neither the signal nor the select indicate the actual arrival
        !            65: of the out-of-band data, but only notification that it is pending.
        !            66: .PP
        !            67: In addition to the information passed, a logical mark is placed in
        !            68: the data stream to indicate the point at which the out
        !            69: of band data was sent.  The remote login and remote shell
        !            70: applications use this facility to propagate signals between
        !            71: client and server processes.  When a signal
        !            72: flushs any pending output from the remote process(es), all
        !            73: data up to the mark in the data stream is discarded.
        !            74: .PP
        !            75: To send an out of band message the MSG_OOB flag is supplied to
        !            76: a \fIsend\fP or \fIsendto\fP calls,
        !            77: while to receive out of band data MSG_OOB should be indicated
        !            78: when performing a \fIrecvfrom\fP or \fIrecv\fP call.
        !            79: To find out if the read pointer is currently pointing at
        !            80: the mark in the data stream, the SIOCATMARK ioctl is provided:
        !            81: .DS
        !            82: ioctl(s, SIOCATMARK, &yes);
        !            83: .DE
        !            84: If \fIyes\fP is a 1 on return, the next read will return data
        !            85: after the mark.  Otherwise (assuming out of band data has arrived), 
        !            86: the next read will provide data sent by the client prior
        !            87: to transmission of the out of band signal.  The routine used
        !            88: in the remote login process to flush output on receipt of an
        !            89: interrupt or quit signal is shown in Figure 5.
        !            90: It reads the normal data up to the mark (to discard it),
        !            91: then reads the out-of-band byte.
        !            92: .KF
        !            93: .DS
        !            94: #include <sys/ioctl.h>
        !            95: #include <sys/file.h>
        !            96:  ...
        !            97: oob()
        !            98: {
        !            99:        int out = FWRITE, mark;
        !           100:        char waste[BUFSIZ];
        !           101: 
        !           102:        /* flush local terminal output */
        !           103:        ioctl(1, TIOCFLUSH, (char *)&out);
        !           104:        for (;;) {
        !           105:                if (ioctl(rem, SIOCATMARK, &mark) < 0) {
        !           106:                        perror("ioctl");
        !           107:                        break;
        !           108:                }
        !           109:                if (mark)
        !           110:                        break;
        !           111:                (void) read(rem, waste, sizeof (waste));
        !           112:        }
        !           113:        if (recv(rem, &mark, 1, MSG_OOB) < 0) {
        !           114:                perror("recv");
        !           115:                ...
        !           116:        }
        !           117:        ...
        !           118: }
        !           119: .DE
        !           120: .ce
        !           121: Figure 5.  Flushing terminal I/O on receipt of out of band data.
        !           122: .sp
        !           123: .KE
        !           124: .PP
        !           125: A process may also read or peek at the out-of-band data
        !           126: without first reading up to the mark.
        !           127: This is more difficult when the underlying protocol delivers
        !           128: the urgent data in-band with the normal data, and only sends
        !           129: notification of its presence ahead of time (e.g., the TCP protocol
        !           130: used to implement streams in the Internet domain).
        !           131: With such protocols, the out-of-band byte may not yet have arrived
        !           132: when a \fIrecv\fP is done with the MSG_OOB flag.
        !           133: In that case, the call will return an error of EWOULDBLOCK.
        !           134: Worse, there may be enough in-band data in the input buffer
        !           135: that normal flow control prevents the peer from sending the urgent data
        !           136: until the buffer is cleared.
        !           137: The process must then read enough of the queued data
        !           138: that the urgent data may be delivered.
        !           139: .PP
        !           140: Certain programs that use multiple bytes of urgent data and must
        !           141: handle multiple urgent signals (e.g., \fItelnet\fP\|(1C))
        !           142: need to retain the position of urgent data within the stream.
        !           143: This treatment is available as a socket-level option, SO_OOBINLINE;
        !           144: see \fIsetsockopt\fP\|(2) for usage.
        !           145: With this option, the position of urgent data (the \*(lqmark\*(rq)
        !           146: is retained, but the urgent data immediately follows the mark
        !           147: within the normal data stream returned without the MSG_OOB flag.
        !           148: Reception of multiple urgent indications causes the mark to move,
        !           149: but no out-of-band data are lost.
        !           150: .NH 2
        !           151: Non-Blocking Sockets
        !           152: .PP
        !           153: It is occasionally convenient to make use of sockets
        !           154: which do not block; that is, I/O requests which
        !           155: cannot complete immediately and
        !           156: would therefore cause the process to be suspended awaiting completion are
        !           157: not executed, and an error code is returned.
        !           158: Once a socket has been created via
        !           159: the \fIsocket\fP call, it may be marked as non-blocking
        !           160: by \fIfcntl\fP as follows:
        !           161: .DS
        !           162: #include <fcntl.h>
        !           163:  ...
        !           164: int    s;
        !           165:  ...
        !           166: s = socket(AF_INET, SOCK_STREAM, 0);
        !           167:  ...
        !           168: if (fcntl(s, F_SETFL, FNDELAY) < 0)
        !           169:        perror("fcntl F_SETFL, FNDELAY");
        !           170:        exit(1);
        !           171: }
        !           172:  ...
        !           173: .DE
        !           174: .PP
        !           175: When performing non-blocking I/O on sockets, one must be
        !           176: careful to check for the error EWOULDBLOCK (stored in the
        !           177: global variable \fIerrno\fP), which occurs when
        !           178: an operation would normally block, but the socket it
        !           179: was performed on is marked as non-blocking.
        !           180: In particular, \fIaccept\fP, \fIconnect\fP, \fIsend\fP, \fIrecv\fP,
        !           181: \fIread\fP, and \fIwrite\fP can
        !           182: all return EWOULDBLOCK, and processes should be prepared
        !           183: to deal with such return codes.
        !           184: If an operation such as a \fIsend\fP cannot be done in its entirety,
        !           185: but partial writes are sensible (for example, when using a stream socket),
        !           186: the data that can be sent immediately will be processed,
        !           187: and the return value will indicate the amount actually sent.
        !           188: .NH 2
        !           189: Interrupt driven socket I/O
        !           190: .PP
        !           191: The SIGIO signal allows a process to be notified
        !           192: via a signal when a socket (or more generally, a file
        !           193: descriptor) has data waiting to be read.  Use of
        !           194: the SIGIO facility requires three steps:  First,
        !           195: the process must set up a SIGIO signal handler
        !           196: by use of the \fIsignal\fP or \fIsigvec\fP calls.  Second,
        !           197: it must set the process id or process group id which is to receive
        !           198: notification of pending input to its own process id,
        !           199: or the process group id of its process group (note that
        !           200: the default process group of a socket is group zero).
        !           201: This is accomplished by use of an \fIfcntl\fP call.
        !           202: Third, it must enable asynchronous notification of pending I/O requests
        !           203: with another \fIfcntl\fP call.  Sample code to
        !           204: allow a given process to receive information on
        !           205: pending I/O requests as they occur for a socket \fIs\fP
        !           206: is given in Figure 6.  With the addition of a handler for SIGURG,
        !           207: this code can also be used to prepare for receipt of SIGURG signals.
        !           208: .KF
        !           209: .DS
        !           210: #include <fcntl.h>
        !           211:  ...
        !           212: int    io_handler();
        !           213:  ...
        !           214: signal(SIGIO, io_handler);
        !           215: 
        !           216: /* Set the process receiving SIGIO/SIGURG signals to us */
        !           217: 
        !           218: if (fcntl(s, F_SETOWN, getpid()) < 0) {
        !           219:        perror("fcntl F_SETOWN");
        !           220:        exit(1);
        !           221: }
        !           222: 
        !           223: /* Allow receipt of asynchronous I/O signals */
        !           224: 
        !           225: if (fcntl(s, F_SETFL, FASYNC) < 0) {
        !           226:        perror("fcntl F_SETFL, FASYNC");
        !           227:        exit(1);
        !           228: }
        !           229: .DE
        !           230: .ce
        !           231: Figure 6.  Use of asynchronous notification of I/O requests.
        !           232: .sp
        !           233: .KE
        !           234: .NH 2
        !           235: Signals and process groups
        !           236: .PP
        !           237: Due to the existence of the SIGURG and SIGIO signals each socket has an
        !           238: associated process number, just as is done for terminals.
        !           239: This value is initialized to zero,
        !           240: but may be redefined at a later time with the F_SETOWN
        !           241: \fIfcntl\fP, such as was done in the code above for SIGIO.
        !           242: To set the socket's process id for signals, positive arguments
        !           243: should be given to the \fIfcntl\fP call.  To set the socket's
        !           244: process group for signals, negative arguments should be 
        !           245: passed to \fIfcntl\fP.  Note that the process number indicates
        !           246: either the associated process id or the associated process
        !           247: group; it is impossible to specify both at the same time.
        !           248: A similar \fIfcntl\fP, F_GETOWN, is available for determining the
        !           249: current process number of a socket.
        !           250: .PP
        !           251: Another signal which is useful when constructing server processes
        !           252: is SIGCHLD.  This signal is delivered to a process when any
        !           253: child processes have changed state.  Normally servers use
        !           254: the signal to \*(lqreap\*(rq child processes that have exited
        !           255: without explicitly awaiting their termination
        !           256: or periodic polling for exit status.
        !           257: For example, the remote login server loop shown in Figure 2
        !           258: may be augmented as shown in Figure 7.
        !           259: .KF
        !           260: .DS
        !           261: int reaper();
        !           262:  ...
        !           263: signal(SIGCHLD, reaper);
        !           264: listen(f, 5);
        !           265: for (;;) {
        !           266:        int g, len = sizeof (from);
        !           267: 
        !           268:        g = accept(f, (struct sockaddr *)&from, &len,);
        !           269:        if (g < 0) {
        !           270:                if (errno != EINTR)
        !           271:                        syslog(LOG_ERR, "rlogind: accept: %m");
        !           272:                continue;
        !           273:        }
        !           274:        ...
        !           275: }
        !           276:  ...
        !           277: #include <wait.h>
        !           278: reaper()
        !           279: {
        !           280:        union wait status;
        !           281: 
        !           282:        while (wait3(&status, WNOHANG, 0) > 0)
        !           283:                ;
        !           284: }
        !           285: .DE
        !           286: .sp
        !           287: .ce
        !           288: Figure 7.  Use of the SIGCHLD signal.
        !           289: .sp
        !           290: .KE
        !           291: .PP
        !           292: If the parent server process fails to reap its children,
        !           293: a large number of \*(lqzombie\*(rq processes may be created.
        !           294: .NH 2
        !           295: Pseudo terminals
        !           296: .PP
        !           297: Many programs will not function properly without a terminal
        !           298: for standard input and output.  Since sockets do not provide
        !           299: the semantics of terminals,
        !           300: it is often necessary to have a process communicating over
        !           301: the network do so through a \fIpseudo-terminal\fP.  A pseudo-
        !           302: terminal is actually a pair of devices, master and slave,
        !           303: which allow a process to serve as an active agent in communication
        !           304: between processes and users.  Data written on the slave side
        !           305: of a pseudo-terminal is supplied as input to a process reading
        !           306: from the master side, while data written on the master side are
        !           307: processed as terminal input for the slave.
        !           308: In this way, the process manipulating
        !           309: the master side of the pseudo-terminal has control over the
        !           310: information read and written on the slave side
        !           311: as if it were manipulating the keyboard and reading the screen
        !           312: on a real terminal.
        !           313: The purpose of this abstraction is to
        !           314: preserve terminal semantics over a network connection\(em
        !           315: that is, the slave side appears as a normal terminal to
        !           316: any process reading from or writing to it.
        !           317: .PP
        !           318: For example, the remote
        !           319: login server uses pseudo-terminals for remote login sessions.
        !           320: A user logging in to a machine across the network is provided
        !           321: a shell with a slave pseudo-terminal as standard input, output,
        !           322: and error.  The server process then handles the communication
        !           323: between the programs invoked by the remote shell and the user's
        !           324: local client process.
        !           325: When a user sends a character that generates an interrupt
        !           326: on the remote machine that flushes terminal output,
        !           327: the pseudo-terminal generates a control message for the server process.
        !           328: The server then sends an out of band message
        !           329: to the client process to signal a flush of data at the real terminal
        !           330: and on the intervening data buffered in the network.
        !           331: .PP
        !           332: Under 4.3BSD, the name of the slave side of a pseudo-terminal is of the form
        !           333: \fI/dev/ttyxy\fP, where \fIx\fP is a single letter
        !           334: starting at `p' and continuing to `t'.
        !           335: \fIy\fP is a hexadecimal digit (i.e., a single
        !           336: character in the range 0 through 9 or `a' through `f').
        !           337: The master side of a pseudo-terminal is \fI/dev/ptyxy\fP,
        !           338: where \fIx\fP and \fIy\fP correspond to the
        !           339: slave side of the pseudo-terminal.
        !           340: .PP
        !           341: In general, the method of obtaining a pair of master and
        !           342: slave pseudo-terminals is to
        !           343: find a pseudo-terminal which
        !           344: is not currently in use.
        !           345: The master half of a pseudo-terminal is a single-open device;
        !           346: thus, each master may be opened in turn until an open succeeds.
        !           347: The slave side of the pseudo-terminal is then opened,
        !           348: and is set to the proper terminal modes if necessary.
        !           349: The process then \fIfork\fPs; the child closes
        !           350: the master side of the pseudo-terminal, and \fIexec\fPs the
        !           351: appropriate program.  Meanwhile, the parent closes the
        !           352: slave side of the pseudo-terminal and begins reading and
        !           353: writing from the master side.  Sample code making use of
        !           354: pseudo-terminals is given in Figure 8; this code assumes
        !           355: that a connection on a socket \fIs\fP exists, connected
        !           356: to a peer who wants a service of some kind, and that the
        !           357: process has disassociated itself from any previous controlling terminal.
        !           358: .KF
        !           359: .DS
        !           360: gotpty = 0;
        !           361: for (c = 'p'; !gotpty && c <= 's'; c++) {
        !           362:        line = "/dev/ptyXX";
        !           363:        line[sizeof("/dev/pty")-1] = c;
        !           364:        line[sizeof("/dev/ptyp")-1] = '0';
        !           365:        if (stat(line, &statbuf) < 0)
        !           366:                break;
        !           367:        for (i = 0; i < 16; i++) {
        !           368:                line[sizeof("/dev/ptyp")-1] = "0123456789abcdef"[i];
        !           369:                master = open(line, O_RDWR);
        !           370:                if (master > 0) {
        !           371:                        gotpty = 1;
        !           372:                        break;
        !           373:                }
        !           374:        }
        !           375: }
        !           376: if (!gotpty) {
        !           377:        syslog(LOG_ERR, "All network ports in use");
        !           378:        exit(1);
        !           379: }
        !           380: 
        !           381: line[sizeof("/dev/")-1] = 't';
        !           382: slave = open(line, O_RDWR);    /* \fIslave\fP is now slave side */
        !           383: if (slave < 0) {
        !           384:        syslog(LOG_ERR, "Cannot open slave pty %s", line);
        !           385:        exit(1);
        !           386: }
        !           387: 
        !           388: ioctl(slave, TIOCGETP, &b);    /* Set slave tty modes */
        !           389: b.sg_flags = CRMOD|XTABS|ANYP;
        !           390: ioctl(slave, TIOCSETP, &b);
        !           391: 
        !           392: i = fork();
        !           393: if (i < 0) {
        !           394:        syslog(LOG_ERR, "fork: %m");
        !           395:        exit(1);
        !           396: } else if (i) {                /* Parent */
        !           397:        close(slave);
        !           398:        ...
        !           399: } else {                /* Child */
        !           400:        (void) close(s);
        !           401:        (void) close(master);
        !           402:        dup2(slave, 0);
        !           403:        dup2(slave, 1);
        !           404:        dup2(slave, 2);
        !           405:        if (slave > 2)
        !           406:                (void) close(slave);
        !           407:        ...
        !           408: }
        !           409: .DE
        !           410: .ce
        !           411: Figure 8.  Creation and use of a pseudo terminal
        !           412: .sp
        !           413: .KE
        !           414: .NH 2
        !           415: Selecting specific protocols
        !           416: .PP
        !           417: If the third argument to the \fIsocket\fP call is 0,
        !           418: \fIsocket\fP will select a default protocol to use with
        !           419: the returned socket of the type requested.
        !           420: The default protocol is usually correct, and alternate choices are not
        !           421: usually available.
        !           422: However, when using ``raw'' sockets to communicate directly with
        !           423: lower-level protocols or hardware interfaces,
        !           424: the protocol argument may be important for setting up demultiplexing.
        !           425: For example, raw sockets in the Internet family may be used to implement
        !           426: a new protocol above IP, and the socket will receive packets
        !           427: only for the protocol specified.
        !           428: To obtain a particular protocol one determines the protocol number
        !           429: as defined within the communication domain.  For the Internet
        !           430: domain one may use one of the library routines
        !           431: discussed in section 3, such as \fIgetprotobyname\fP:
        !           432: .DS
        !           433: #include <sys/types.h>
        !           434: #include <sys/socket.h>
        !           435: #include <netinet/in.h>
        !           436: #include <netdb.h>
        !           437:  ...
        !           438: pp = getprotobyname("newtcp");
        !           439: s = socket(AF_INET, SOCK_STREAM, pp->p_proto);
        !           440: .DE
        !           441: This would result in a socket \fIs\fP using a stream
        !           442: based connection, but with protocol type of ``newtcp''
        !           443: instead of the default ``tcp.''
        !           444: .PP
        !           445: In the NS domain, the available socket protocols are defined in
        !           446: <\fInetns/ns.h\fP>.  To create a raw socket for Xerox Error Protocol
        !           447: messages, one might use:
        !           448: .DS
        !           449: #include <sys/types.h>
        !           450: #include <sys/socket.h>
        !           451: #include <netns/ns.h>
        !           452:  ...
        !           453: s = socket(AF_NS, SOCK_RAW, NSPROTO_ERROR);
        !           454: .DE
        !           455: .NH 2
        !           456: Address binding
        !           457: .PP
        !           458: As was mentioned in section 2, 
        !           459: binding addresses to sockets in the Internet and NS domains can be
        !           460: fairly complex.  As a brief reminder, these associations
        !           461: are composed of local and foreign
        !           462: addresses, and local and foreign ports.  Port numbers are
        !           463: allocated out of separate spaces, one for each system and one
        !           464: for each domain on that system.
        !           465: Through the \fIbind\fP system call, a
        !           466: process may specify half of an association, the
        !           467: <local address, local port> part, while the
        !           468: \fIconnect\fP
        !           469: and \fIaccept\fP
        !           470: primitives are used to complete a socket's association by
        !           471: specifying the <foreign address, foreign port> part.
        !           472: Since the association is created in two steps the association
        !           473: uniqueness requirement indicated previously could be violated unless
        !           474: care is taken.  Further, it is unrealistic to expect user
        !           475: programs to always know proper values to use for the local address
        !           476: and local port since a host may reside on multiple networks and
        !           477: the set of allocated port numbers is not directly accessible
        !           478: to a user.
        !           479: .PP
        !           480: To simplify local address binding in the Internet domain the notion of a
        !           481: \*(lqwildcard\*(rq address has been provided.  When an address
        !           482: is specified as INADDR_ANY (a manifest constant defined in
        !           483: <netinet/in.h>), the system interprets the address as 
        !           484: \*(lqany valid address\*(rq.  For example, to bind a specific
        !           485: port number to a socket, but leave the local address unspecified,
        !           486: the following code might be used:
        !           487: .DS
        !           488: #include <sys/types.h>
        !           489: #include <netinet/in.h>
        !           490:  ...
        !           491: struct sockaddr_in sin;
        !           492:  ...
        !           493: s = socket(AF_INET, SOCK_STREAM, 0);
        !           494: sin.sin_family = AF_INET;
        !           495: sin.sin_addr.s_addr = htonl(INADDR_ANY);
        !           496: sin.sin_port = htons(MYPORT);
        !           497: bind(s, (struct sockaddr *) &sin, sizeof (sin));
        !           498: .DE
        !           499: Sockets with wildcarded local addresses may receive messages
        !           500: directed to the specified port number, and sent to any
        !           501: of the possible addresses assigned to a host.  For example,
        !           502: if a host has addresses 128.32.0.4 and 10.0.0.78, and a socket is bound as
        !           503: above, the process will be
        !           504: able to accept connection requests which are addressed to
        !           505: 128.32.0.4 or 10.0.0.78.
        !           506: If a server process wished to only allow hosts on a
        !           507: given network connect to it, it would bind
        !           508: the address of the host on the appropriate network.
        !           509: .PP
        !           510: In a similar fashion, a local port may be left unspecified
        !           511: (specified as zero), in which case the system will select an
        !           512: appropriate port number for it.  This shortcut will work
        !           513: both in the Internet and NS domains.  For example, to
        !           514: bind a specific local address to a socket, but to leave the
        !           515: local port number unspecified:
        !           516: .DS
        !           517: hp = gethostbyname(hostname);
        !           518: if (hp == NULL) {
        !           519:        ...
        !           520: }
        !           521: bcopy(hp->h_addr, (char *) sin.sin_addr, hp->h_length);
        !           522: sin.sin_port = htons(0);
        !           523: bind(s, (struct sockaddr *) &sin, sizeof (sin));
        !           524: .DE
        !           525: The system selects the local port number based on two criteria.
        !           526: The first is that on 4BSD systems,
        !           527: Internet ports below IPPORT_RESERVED (1024) (for the Xerox domain,
        !           528: 0 through 3000) are reserved
        !           529: for privileged users (i.e., the super user);
        !           530: Internet ports above IPPORT_USERRESERVED (50000) are reserved
        !           531: for non-privileged servers.  The second is
        !           532: that the port number is not currently bound to some other
        !           533: socket.  In order to find a free Internet port number in the privileged
        !           534: range the \fIrresvport\fP library routine may be used as follows
        !           535: to return a stream socket in with a privileged port number:
        !           536: .DS
        !           537: int lport = IPPORT_RESERVED \- 1;
        !           538: int s;
        !           539: ...
        !           540: s = rresvport(&lport);
        !           541: if (s < 0) {
        !           542:        if (errno == EAGAIN)
        !           543:                fprintf(stderr, "socket: all ports in use\en");
        !           544:        else
        !           545:                perror("rresvport: socket");
        !           546:        ...
        !           547: }
        !           548: .DE
        !           549: The restriction on allocating ports was done to allow processes
        !           550: executing in a \*(lqsecure\*(rq environment to perform authentication
        !           551: based on the originating address and port number.  For example,
        !           552: the \fIrlogin\fP(1) command allows users to log in across a network
        !           553: without being asked for a password, if two conditions hold:
        !           554: First, the name of the system the user
        !           555: is logging in from is in the file
        !           556: \fI/etc/hosts.equiv\fP on the system he is logging
        !           557: in to (or the system name and the user name are in
        !           558: the user's \fI.rhosts\fP file in the user's home
        !           559: directory), and second, that the user's rlogin
        !           560: process is coming from a privileged port on the machine from which he is
        !           561: logging.  The port number and network address of the
        !           562: machine from which the user is logging in can be determined either
        !           563: by the \fIfrom\fP result of the \fIaccept\fP call, or
        !           564: from the \fIgetpeername\fP call.
        !           565: .PP
        !           566: In certain cases the algorithm used by the system in selecting
        !           567: port numbers is unsuitable for an application.  This is because
        !           568: associations are created in a two step process.  For example,
        !           569: the Internet file transfer protocol, FTP, specifies that data
        !           570: connections must always originate from the same local port.  However,
        !           571: duplicate associations are avoided by connecting to different foreign
        !           572: ports.  In this situation the system would disallow binding the
        !           573: same local address and port number to a socket if a previous data
        !           574: connection's socket still existed.  To override the default port
        !           575: selection algorithm, an option call must be performed prior
        !           576: to address binding:
        !           577: .DS
        !           578:  ...
        !           579: int    on = 1;
        !           580:  ...
        !           581: setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
        !           582: bind(s, (struct sockaddr *) &sin, sizeof (sin));
        !           583: .DE
        !           584: With the above call, local addresses may be bound which
        !           585: are already in use.  This does not violate the uniqueness
        !           586: requirement as the system still checks at connect time to
        !           587: be sure any other sockets with the same local address and
        !           588: port do not have the same foreign address and port.
        !           589: If the association already exists, the error EADDRINUSE is returned.
        !           590: .NH 2
        !           591: Broadcasting and determining network configuration
        !           592: .PP
        !           593: By using a datagram socket, it is possible to send broadcast
        !           594: packets on many networks supported by the system.
        !           595: The network itself must support broadcast; the system
        !           596: provides no simulation of broadcast in software.
        !           597: Broadcast messages can place a high load on a network since they force
        !           598: every host on the network to service them.  Consequently,
        !           599: the ability to send broadcast packets has been limited
        !           600: to sockets which are explicitly marked as allowing broadcasting.
        !           601: Broadcast is typically used for one of two reasons:
        !           602: it is desired to find a resource on a local network without prior
        !           603: knowledge of its address,
        !           604: or important functions such as routing require that information
        !           605: be sent to all accessible neighbors.
        !           606: .PP
        !           607: To send a broadcast message, a datagram socket 
        !           608: should be created:
        !           609: .DS
        !           610: s = socket(AF_INET, SOCK_DGRAM, 0);
        !           611: .DE
        !           612: or
        !           613: .DS
        !           614: s = socket(AF_NS, SOCK_DGRAM, 0);
        !           615: .DE
        !           616: The socket is marked as allowing broadcasting,
        !           617: .DS
        !           618: int    on = 1;
        !           619: 
        !           620: setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on));
        !           621: .DE
        !           622: and at least a port number should be bound to the socket:
        !           623: .DS
        !           624: sin.sin_family = AF_INET;
        !           625: sin.sin_addr.s_addr = htonl(INADDR_ANY);
        !           626: sin.sin_port = htons(MYPORT);
        !           627: bind(s, (struct sockaddr *) &sin, sizeof (sin));
        !           628: .DE
        !           629: or, for the NS domain,
        !           630: .DS
        !           631: sns.sns_family = AF_NS;
        !           632: netnum = htonl(net);
        !           633: sns.sns_addr.x_net = *(union ns_net *) &netnum; /* insert net number */
        !           634: sns.sns_addr.x_port = htons(MYPORT);
        !           635: bind(s, (struct sockaddr *) &sns, sizeof (sns));
        !           636: .DE
        !           637: The destination address of the message to be broadcast
        !           638: depends on the network(s) on which the message is to be broadcast.
        !           639: The Internet domain supports a shorthand notation for broadcast
        !           640: on the local network, the address INADDR_BROADCAST (defined in
        !           641: <\fInetinet/in.h\fP>.
        !           642: To determine the list of addresses for all reachable neighbors
        !           643: requires knowledge of the networks to which the host is connected.
        !           644: Since this information should
        !           645: be obtained in a host-independent fashion and may be impossible
        !           646: to derive, 4.3BSD provides a method of
        !           647: retrieving this information from the system data structures.
        !           648: The SIOCGIFCONF \fIioctl\fP call returns the interface
        !           649: configuration of a host in the form of a
        !           650: single \fIifconf\fP structure; this structure contains
        !           651: a ``data area'' which is made up of an array of
        !           652: of \fIifreq\fP structures, one for each network interface
        !           653: to which the host is connected.
        !           654: These structures are defined in
        !           655: \fI<net/if.h>\fP as follows:
        !           656: .DS
        !           657: .if t .ta .5i 1.0i 1.5i 3.5i
        !           658: .if n .ta .7i 1.4i 2.1i 3.4i
        !           659: struct ifconf {
        !           660:        int     ifc_len;                /* size of associated buffer */
        !           661:        union {
        !           662:                caddr_t ifcu_buf;
        !           663:                struct  ifreq *ifcu_req;
        !           664:        } ifc_ifcu;
        !           665: };
        !           666: 
        !           667: #define        ifc_buf ifc_ifcu.ifcu_buf               /* buffer address */
        !           668: #define        ifc_req ifc_ifcu.ifcu_req               /* array of structures returned */
        !           669: 
        !           670: #define        IFNAMSIZ        16
        !           671: 
        !           672: struct ifreq {
        !           673:        char    ifr_name[IFNAMSIZ];             /* if name, e.g. "en0" */
        !           674:        union {
        !           675:                struct  sockaddr ifru_addr;
        !           676:                struct  sockaddr ifru_dstaddr;
        !           677:                struct  sockaddr ifru_broadaddr;
        !           678:                short   ifru_flags;
        !           679:                caddr_t ifru_data;
        !           680:        } ifr_ifru;
        !           681: };
        !           682: 
        !           683: .if t .ta \w'  #define'u +\w'  ifr_broadaddr'u +\w'  ifr_ifru.ifru_broadaddr'u
        !           684: #define        ifr_addr        ifr_ifru.ifru_addr      /* address */
        !           685: #define        ifr_dstaddr     ifr_ifru.ifru_dstaddr   /* other end of p-to-p link */
        !           686: #define        ifr_broadaddr   ifr_ifru.ifru_broadaddr /* broadcast address */
        !           687: #define        ifr_flags       ifr_ifru.ifru_flags     /* flags */
        !           688: #define        ifr_data        ifr_ifru.ifru_data      /* for use by interface */
        !           689: .DE
        !           690: The actual call which obtains the
        !           691: interface configuration is
        !           692: .DS
        !           693: struct ifconf ifc;
        !           694: char buf[BUFSIZ];
        !           695: 
        !           696: ifc.ifc_len = sizeof (buf);
        !           697: ifc.ifc_buf = buf;
        !           698: if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0) {
        !           699:        ...
        !           700: }
        !           701: .DE
        !           702: After this call \fIbuf\fP will contain one \fIifreq\fP structure for
        !           703: each network to which the host is connected, and
        !           704: \fIifc.ifc_len\fP will have been modified to reflect the number
        !           705: of bytes used by the \fIifreq\fP structures.
        !           706: .PP
        !           707: For each structure
        !           708: there exists a set of ``interface flags'' which tell
        !           709: whether the network corresponding to that interface is
        !           710: up or down, point to point or broadcast, etc.  The
        !           711: SIOCGIFFLAGS \fIioctl\fP retrieves these
        !           712: flags for an interface specified by an \fIifreq\fP
        !           713: structure as follows:
        !           714: .DS
        !           715: struct ifreq *ifr;
        !           716: 
        !           717: ifr = ifc.ifc_req;
        !           718: 
        !           719: for (n = ifc.ifc_len / sizeof (struct ifreq); --n >= 0; ifr++) {
        !           720:        /*
        !           721:         * We must be careful that we don't use an interface
        !           722:         * devoted to an address family other than those intended;
        !           723:         * if we were interested in NS interfaces, the
        !           724:         * AF_INET would be AF_NS.
        !           725:         */
        !           726:        if (ifr->ifr_addr.sa_family != AF_INET)
        !           727:                continue;
        !           728:        if (ioctl(s, SIOCGIFFLAGS, (char *) ifr) < 0) {
        !           729:                ...
        !           730:        }
        !           731:        /*
        !           732:         * Skip boring cases.
        !           733:         */
        !           734:        if ((ifr->ifr_flags & IFF_UP) == 0 ||
        !           735:            (ifr->ifr_flags & IFF_LOOPBACK) ||
        !           736:            (ifr->ifr_flags & (IFF_BROADCAST | IFF_POINTTOPOINT)) == 0)
        !           737:                continue;
        !           738: .DE
        !           739: .PP
        !           740: Once the flags have been obtained, the broadcast address 
        !           741: must be obtained.  In the case of broadcast networks this is
        !           742: done via the SIOCGIFBRDADDR \fIioctl\fP, while for point-to-point networks
        !           743: the address of the destination host is obtained with SIOCGIFDSTADDR.
        !           744: .DS
        !           745: struct sockaddr dst;
        !           746: 
        !           747: if (ifr->ifr_flags & IFF_POINTTOPOINT) {
        !           748:        if (ioctl(s, SIOCGIFDSTADDR, (char *) ifr) < 0) {
        !           749:                ...
        !           750:        }
        !           751:        bcopy((char *) ifr->ifr_dstaddr, (char *) &dst, sizeof (ifr->ifr_dstaddr));
        !           752: } else if (ifr->ifr_flags & IFF_BROADCAST) {
        !           753:        if (ioctl(s, SIOCGIFBRDADDR, (char *) ifr) < 0) {
        !           754:                ...
        !           755:        }
        !           756:        bcopy((char *) ifr->ifr_broadaddr, (char *) &dst, sizeof (ifr->ifr_broadaddr));
        !           757: }
        !           758: .DE
        !           759: .PP
        !           760: After the appropriate \fIioctl\fP's have obtained the broadcast
        !           761: or destination address (now in \fIdst\fP), the \fIsendto\fP call may be
        !           762: used:
        !           763: .DS
        !           764:        sendto(s, buf, buflen, 0, (struct sockaddr *)&dst, sizeof (dst));
        !           765: }
        !           766: .DE
        !           767: In the above loop one \fIsendto\fP occurs for every
        !           768: interface to which the host is connected that supports the notion of
        !           769: broadcast or point-to-point addressing.
        !           770: If a process only wished to send broadcast
        !           771: messages on a given network, code similar to that outlined above
        !           772: would be used, but the loop would need to find the
        !           773: correct destination address.
        !           774: .PP
        !           775: Received broadcast messages contain the senders address
        !           776: and port, as datagram sockets are bound before
        !           777: a message is allowed to go out.
        !           778: .NH 2
        !           779: Socket Options
        !           780: .PP
        !           781: It is possible to set and get a number of options on sockets
        !           782: via the \fIsetsockopt\fP and \fIgetsockopt\fP system calls.
        !           783: These options include such things as marking a socket for
        !           784: broadcasting, not to route, to linger on close, etc.
        !           785: The general forms of the calls are:
        !           786: .DS
        !           787: setsockopt(s, level, optname, optval, optlen);
        !           788: .DE
        !           789: and
        !           790: .DS
        !           791: getsockopt(s, level, optname, optval, optlen);
        !           792: .DE
        !           793: .PP
        !           794: The parameters to the calls are as follows: \fIs\fP
        !           795: is the socket on which the option is to be applied.
        !           796: \fILevel\fP specifies the protocol layer on which the
        !           797: option is to be applied; in most cases this is
        !           798: the ``socket level'', indicated by the symbolic constant
        !           799: SOL_SOCKET, defined in \fI<sys/socket.h>.\fP
        !           800: The actual option is specified in \fIoptname\fP, and is
        !           801: a symbolic constant also defined in \fI<sys/socket.h>\fP.
        !           802: \fIOptval\fP and \fIOptlen\fP point to the value of the
        !           803: option (in most cases, whether the option is to be turned
        !           804: on or off), and the length of the value of the option,
        !           805: respectively.
        !           806: For \fIgetsockopt\fP, \fIoptlen\fP is
        !           807: a value-result parameter, initially set to the size of
        !           808: the storage area pointed to by \fIoptval\fP, and modified
        !           809: upon return to indicate the actual amount of storage used.
        !           810: .PP
        !           811: An example should help clarify things.  It is sometimes
        !           812: useful to determine the type (e.g., stream, datagram, etc.)
        !           813: of an existing socket; programs
        !           814: under \fIinetd\fP (described below) may need to perform this
        !           815: task.  This can be accomplished as follows via the
        !           816: SO_TYPE socket option and the \fIgetsockopt\fP call:
        !           817: .DS
        !           818: #include <sys/types.h>
        !           819: #include <sys/socket.h>
        !           820: 
        !           821: int type, size;
        !           822: 
        !           823: size = sizeof (int);
        !           824: 
        !           825: if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &type, &size) < 0) {
        !           826:        ...
        !           827: }
        !           828: .DE
        !           829: After the \fIgetsockopt\fP call, \fItype\fP will be set
        !           830: to the value of the socket type, as defined in
        !           831: \fI<sys/socket.h>\fP.  If, for example, the socket were
        !           832: a datagram socket, \fItype\fP would have the value
        !           833: corresponding to SOCK_DGRAM.
        !           834: .NH 2
        !           835: NS Packet Sequences
        !           836: .PP
        !           837: The semantics of NS connections demand that
        !           838: the user both be able to look inside the network header associated
        !           839: with any incoming packet and be able to specify what should go
        !           840: in certain fields of an outgoing packet.
        !           841: Using different calls to \fIsetsockopt\fP, it is possible
        !           842: to indicate whether prototype headers will be associated by
        !           843: the user with each outgoing packet (SO_HEADERS_ON_OUTPUT),
        !           844: to indicate whether the headers received by the system should be
        !           845: delivered to the user (SO_HEADERS_ON_INPUT), or to indicate
        !           846: default information that should be associated with all
        !           847: outgoing packets on a given socket (SO_DEFAULT_HEADERS).
        !           848: .PP
        !           849: The contents of a SPP header (minus the IDP header) are:
        !           850: .DS
        !           851: .if t .ta \w"  #define"u +\w"  u_short"u +2.0i
        !           852: struct sphdr {
        !           853:        u_char  sp_cc;          /* connection control */
        !           854: #define        SP_SP   0x80            /* system packet */
        !           855: #define        SP_SA   0x40            /* send acknowledgement */
        !           856: #define        SP_OB   0x20            /* attention (out of band data) */
        !           857: #define        SP_EM   0x10            /* end of message */
        !           858:        u_char  sp_dt;          /* datastream type */
        !           859:        u_short sp_sid;         /* source connection identifier */
        !           860:        u_short sp_did;         /* destination connection identifier */
        !           861:        u_short sp_seq;         /* sequence number */
        !           862:        u_short sp_ack;         /* acknowledge number */
        !           863:        u_short sp_alo;         /* allocation number */
        !           864: };
        !           865: .DE
        !           866: Here, the items of interest are the \fIdatastream type\fP and
        !           867: the \fIconnection control\fP fields.  The semantics of the
        !           868: datastream type are defined by the application(s) in question;
        !           869: the value of this field is, by default, zero, but it can be
        !           870: used to indicate things such as Xerox's Bulk Data Transfer
        !           871: Protocol (in which case it is set to one).  The connection control
        !           872: field is a mask of the flags defined just below it.  The user may
        !           873: set or clear the end-of-message bit to indicate
        !           874: that a given message is the last of a given substream type,
        !           875: or may set/clear the attention bit as an alternate way to
        !           876: indicate that a packet should be sent out-of-band.
        !           877: As an example, to associate prototype headers with outgoing
        !           878: SPP packets, consider:
        !           879: .DS
        !           880: #include <sys/types.h>
        !           881: #include <sys/socket.h>
        !           882: #include <netns/ns.h>
        !           883: #include <netns/sp.h>
        !           884:  ...
        !           885: struct sockaddr_ns sns, to;
        !           886: int s, on = 1;
        !           887: struct databuf {
        !           888:        struct sphdr proto_spp; /* prototype header */
        !           889:        char buf[534];          /* max. possible data by Xerox std. */
        !           890: } buf;
        !           891:  ...
        !           892: s = socket(AF_NS, SOCK_SEQPACKET, 0);
        !           893:  ...
        !           894: bind(s, (struct sockaddr *) &sns, sizeof (sns));
        !           895: setsockopt(s, NSPROTO_SPP, SO_HEADERS_ON_OUTPUT, &on, sizeof(on));
        !           896:  ...
        !           897: buf.proto_spp.sp_dt = 1;       /* bulk data */
        !           898: buf.proto_spp.sp_cc = SP_EM;   /* end-of-message */
        !           899: strcpy(buf.buf, "hello world\en");
        !           900: sendto(s, (char *) &buf, sizeof(struct sphdr) + strlen("hello world\en"),
        !           901:     (struct sockaddr *) &to, sizeof(to));
        !           902:  ...
        !           903: .DE
        !           904: Note that one must be careful when writing headers; if the prototype
        !           905: header is not written with the data with which it is to be associated,
        !           906: the kernel will treat the first few bytes of the data as the
        !           907: header, with unpredictable results.
        !           908: To turn off the above association, and to indicate that packet
        !           909: headers received by the system should be passed up to the user,
        !           910: one might use:
        !           911: .DS
        !           912: #include <sys/types.h>
        !           913: #include <sys/socket.h>
        !           914: #include <netns/ns.h>
        !           915: #include <netns/sp.h>
        !           916:  ...
        !           917: struct sockaddr sns;
        !           918: int s, on = 1, off = 0;
        !           919:  ...
        !           920: s = socket(AF_NS, SOCK_SEQPACKET, 0);
        !           921:  ...
        !           922: bind(s, (struct sockaddr *) &sns, sizeof (sns));
        !           923: setsockopt(s, NSPROTO_SPP, SO_HEADERS_ON_OUTPUT, &off, sizeof(off));
        !           924: setsockopt(s, NSPROTO_SPP, SO_HEADERS_ON_INPUT, &on, sizeof(on));
        !           925:  ...
        !           926: .DE
        !           927: .PP
        !           928: Output is handled somewhat differently in the IDP world.
        !           929: The header of an IDP-level packet looks like:
        !           930: .DS
        !           931: .if t .ta \w'struct  'u +\w"  struct ns_addr"u +2.0i
        !           932: struct idp {
        !           933:        u_short idp_sum;        /* Checksum */
        !           934:        u_short idp_len;        /* Length, in bytes, including header */
        !           935:        u_char  idp_tc;         /* Transport Control (i.e., hop count) */
        !           936:        u_char  idp_pt;         /* Packet Type (i.e., level 2 protocol) */
        !           937:        struct ns_addr  idp_dna;        /* Destination Network Address */
        !           938:        struct ns_addr  idp_sna;        /* Source Network Address */
        !           939: };
        !           940: .DE
        !           941: The primary field of interest in an IDP header is the \fIpacket type\fP
        !           942: field.  The standard values for this field are (as defined
        !           943: in <\fInetns/ns.h\fP>):
        !           944: .DS
        !           945: .if t .ta \w"  #define"u +\w"  NSPROTO_ERROR"u +1.0i
        !           946: #define NSPROTO_RI     1               /* Routing Information */
        !           947: #define NSPROTO_ECHO   2               /* Echo Protocol */
        !           948: #define NSPROTO_ERROR  3               /* Error Protocol */
        !           949: #define NSPROTO_PE     4               /* Packet Exchange */
        !           950: #define NSPROTO_SPP    5               /* Sequenced Packet */
        !           951: .DE
        !           952: For SPP connections, the contents of this field are
        !           953: automatically set to NSPROTO_SPP; for IDP packets,
        !           954: this value defaults to zero, which means ``unknown''.
        !           955: .PP
        !           956: Setting the value of that field with SO_DEFAULT_HEADERS is
        !           957: easy:
        !           958: .DS
        !           959: #include <sys/types.h>
        !           960: #include <sys/socket.h>
        !           961: #include <netns/ns.h>
        !           962: #include <netns/idp.h>
        !           963:  ...
        !           964: struct sockaddr sns;
        !           965: struct idp proto_idp;          /* prototype header */
        !           966: int s, on = 1;
        !           967:  ...
        !           968: s = socket(AF_NS, SOCK_DGRAM, 0);
        !           969:  ...
        !           970: bind(s, (struct sockaddr *) &sns, sizeof (sns));
        !           971: proto_idp.idp_pt = NSPROTO_PE; /* packet exchange */
        !           972: setsockopt(s, NSPROTO_IDP, SO_DEFAULT_HEADERS, (char *) &proto_idp,
        !           973:     sizeof(proto_idp));
        !           974:  ...
        !           975: .DE
        !           976: .PP
        !           977: Using SO_HEADERS_ON_OUTPUT is somewhat more difficult.  When
        !           978: SO_HEADERS_ON_OUTPUT is turned on for an IDP socket, the socket
        !           979: becomes (for all intents and purposes) a raw socket.  In this
        !           980: case, all the fields of the prototype header (except the 
        !           981: length and checksum fields, which are computed by the kernel)
        !           982: must be filled in correctly in order for the socket to send and
        !           983: receive data in a sensible manner.  To be more specific, the
        !           984: source address must be set to that of the host sending the
        !           985: data; the destination address must be set to that of the
        !           986: host for whom the data is intended; the packet type must be
        !           987: set to whatever value is desired; and the hopcount must be
        !           988: set to some reasonable value (almost always zero).  It should
        !           989: also be noted that simply sending data using \fIwrite\fP
        !           990: will not work unless a \fIconnect\fP or \fIsendto\fP call
        !           991: is used, in spite of the fact that it is the destination
        !           992: address in the prototype header that is used, not the one
        !           993: given in either of those calls.  For almost
        !           994: all IDP applications , using SO_DEFAULT_HEADERS is easier and
        !           995: more desirable than writing headers.
        !           996: .NH 2
        !           997: Three-way Handshake
        !           998: .PP
        !           999: The semantics of SPP connections indicates that a three-way
        !          1000: handshake, involving changes in the datastream type, should \(em
        !          1001: but is not absolutely required to \(em take place before a SPP
        !          1002: connection is closed.  Almost all SPP connections are
        !          1003: ``well-behaved'' in this manner; when communicating with
        !          1004: any process, it is best to assume that the three-way handshake
        !          1005: is required unless it is known for certain that it is not
        !          1006: required.  In a three-way close, the closing process
        !          1007: indicates that it wishes to close the connection by sending
        !          1008: a zero-length packet with end-of-message set and with
        !          1009: datastream type 254.  The other side of the connection
        !          1010: indicates that it is OK to close by sending a zero-length
        !          1011: packet with end-of-message set and datastream type 255.  Finally,
        !          1012: the closing process replies with a zero-length packet with 
        !          1013: substream type 255; at this point, the connection is considered
        !          1014: closed.  The following code fragments are simplified examples
        !          1015: of how one might handle this three-way handshake at the user
        !          1016: level; in the future, support for this type of close will
        !          1017: probably be provided as part of the C library or as part of
        !          1018: the kernel.  The first code fragment below illustrates how a process
        !          1019: might handle three-way handshake if it sees that the process it
        !          1020: is communicating with wants to close the connection:
        !          1021: .DS
        !          1022: #include <sys/types.h>
        !          1023: #include <sys/socket.h>
        !          1024: #include <netns/ns.h>
        !          1025: #include <netns/sp.h>
        !          1026:  ...
        !          1027: #ifndef SPPSST_END
        !          1028: #define SPPSST_END 254
        !          1029: #define SPPSST_ENDREPLY 255
        !          1030: #endif
        !          1031: struct sphdr proto_sp;
        !          1032: int s;
        !          1033:  ...
        !          1034: read(s, buf, BUFSIZE);
        !          1035: if (((struct sphdr *)buf)->sp_dt == SPPSST_END) {
        !          1036:        /*
        !          1037:         * SPPSST_END indicates that the other side wants to
        !          1038:         * close.
        !          1039:         */
        !          1040:        proto_sp.sp_dt = SPPSST_ENDREPLY;
        !          1041:        proto_sp.sp_cc = SP_EM;
        !          1042:        setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, (char *)&proto_sp,
        !          1043:            sizeof(proto_sp));
        !          1044:        write(s, buf, 0);
        !          1045:        /*
        !          1046:         * Write a zero-length packet with datastream type = SPPSST_ENDREPLY
        !          1047:         * to indicate that the close is OK with us.  The packet that we
        !          1048:         * don't see (because we don't look for it) is another packet
        !          1049:         * from the other side of the connection, with SPPSST_ENDREPLY
        !          1050:         * on it it, too.  Once that packet is sent, the connection is
        !          1051:         * considered closed; note that we really ought to retransmit
        !          1052:         * the close for some time if we do not get a reply.
        !          1053:         */
        !          1054:        close(s);
        !          1055: }
        !          1056:  ...
        !          1057: .DE
        !          1058: To indicate to another process that we would like to close the
        !          1059: connection, the following code would suffice:
        !          1060: .DS
        !          1061: #include <sys/types.h>
        !          1062: #include <sys/socket.h>
        !          1063: #include <netns/ns.h>
        !          1064: #include <netns/sp.h>
        !          1065:  ...
        !          1066: #ifndef SPPSST_END
        !          1067: #define SPPSST_END 254
        !          1068: #define SPPSST_ENDREPLY 255
        !          1069: #endif
        !          1070: struct sphdr proto_sp;
        !          1071: int s;
        !          1072:  ...
        !          1073: proto_sp.sp_dt = SPPSST_END;
        !          1074: proto_sp.sp_cc = SP_EM;
        !          1075: setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, (char *)&proto_sp,
        !          1076:     sizeof(proto_sp));
        !          1077: write(s, buf, 0);      /* send the end request */
        !          1078: proto_sp.sp_dt = SPPSST_ENDREPLY;
        !          1079: setsockopt(s, NSPROTO_SPP, SO_DEFAULT_HEADERS, (char *)&proto_sp,
        !          1080:     sizeof(proto_sp));
        !          1081: /*
        !          1082:  * We assume (perhaps unwisely)
        !          1083:  * that the other side will send the
        !          1084:  * ENDREPLY, so we'll just send our final ENDREPLY
        !          1085:  * as if we'd seen theirs already.
        !          1086:  */
        !          1087: write(s, buf, 0);
        !          1088: close(s);
        !          1089:  ...
        !          1090: .DE
        !          1091: .NH 2
        !          1092: Packet Exchange
        !          1093: .PP
        !          1094: The Xerox standard protocols include a protocol that is both
        !          1095: reliable and datagram-oriented.  This protocol is known as
        !          1096: Packet Exchange (PEX or PE) and, like SPP, is layered on top
        !          1097: of IDP.  PEX is important for a number of things: Courier
        !          1098: remote procedure calls may be expedited through the use
        !          1099: of PEX, and many Xerox servers are located by doing a PEX
        !          1100: ``BroadcastForServers'' operation.  Although there is no
        !          1101: implementation of PEX in the kernel,
        !          1102: it may be simulated at the user level with some clever coding
        !          1103: and the use of one peculiar \fIgetsockopt\fP.  A PEX packet
        !          1104: looks like:
        !          1105: .DS
        !          1106: .if t .ta \w'struct  'u +\w"  struct idp"u +2.0i
        !          1107: /*
        !          1108:  * The packet-exchange header shown here is not defined
        !          1109:  * as part of any of the system include files.
        !          1110:  */
        !          1111: struct pex {
        !          1112:        struct idp      p_idp;  /* idp header */
        !          1113:        u_short ph_id[2];       /* unique transaction ID for pex */
        !          1114:        u_short ph_client;      /* client type field for pex */
        !          1115: };
        !          1116: .DE
        !          1117: The \fIph_id\fP field is used to hold a ``unique id'' that
        !          1118: is used in duplicate suppression; the \fIph_client\fP
        !          1119: field indicates the PEX client type (similar to the packet
        !          1120: type field in the IDP header).  PEX reliability stems from the
        !          1121: fact that it is an idempotent (``I send a packet to you, you
        !          1122: send a packet to me'') protocol.  Processes on each side of
        !          1123: the connection may use the unique id to determine if they have
        !          1124: seen a given packet before (the unique id field differs on each
        !          1125: packet sent) so that duplicates may be detected, and to indicate
        !          1126: which message a given packet is in response to.  If a packet with
        !          1127: a given unique id is sent and no response is received in a given
        !          1128: amount of time, the packet is retransmitted until it is decided
        !          1129: that no response will ever be received.  To simulate PEX, one
        !          1130: must be able to generate unique ids -- something that is hard to
        !          1131: do at the user level with any real guarantee that the id is really
        !          1132: unique.  Therefore, a means (via \fIgetsockopt\fP) has been provided
        !          1133: for getting unique ids from the kernel.  The following code fragment
        !          1134: indicates how to get a unique id:
        !          1135: .DS
        !          1136: long uniqueid;
        !          1137: int s, idsize = sizeof(uniqueid);
        !          1138:  ...
        !          1139: s = socket(AF_NS, SOCK_DGRAM, 0);
        !          1140:  ...
        !          1141: /* get id from the kernel -- only on IDP sockets */
        !          1142: getsockopt(s, NSPROTO_PE, SO_SEQNO, (char *)&uniqueid, &idsize);
        !          1143:  ...
        !          1144: .DE
        !          1145: The retransmission and duplicate suppression code required to
        !          1146: simulate PEX fully is left as an exercise for the reader.
        !          1147: .NH 2
        !          1148: Inetd
        !          1149: .PP
        !          1150: One of the daemons provided with 4.3BSD is \fIinetd\fP, the
        !          1151: so called ``internet super-server.''  \fIInetd\fP is invoked at boot
        !          1152: time, and determines from the file \fI/etc/inetd.conf\fP the
        !          1153: servers for which it is to listen.  Once this information has been
        !          1154: read and a pristine environment created, \fIinetd\fP proceeds
        !          1155: to create one socket for each service it is to listen for,
        !          1156: binding the appropriate port number to each socket.
        !          1157: .PP
        !          1158: \fIInetd\fP then performs a \fIselect\fP on all these
        !          1159: sockets for read availability, waiting for somebody wishing
        !          1160: a connection to the service corresponding to
        !          1161: that socket.  \fIInetd\fP then performs an \fIaccept\fP on
        !          1162: the socket in question, \fIfork\fPs, \fIdup\fPs the new
        !          1163: socket to file descriptors 0 and 1 (stdin and
        !          1164: stdout), closes other open file
        !          1165: descriptors, and \fIexec\fPs the appropriate server.
        !          1166: .PP
        !          1167: Servers making use of \fIinetd\fP are considerably simplified,
        !          1168: as \fIinetd\fP takes care of the majority of the IPC work
        !          1169: required in establishing a connection.  The server invoked
        !          1170: by \fIinetd\fP expects the socket connected to its client
        !          1171: on file descriptors 0 and 1, and may immediately perform
        !          1172: any operations such as \fIread\fP, \fIwrite\fP, \fIsend\fP,
        !          1173: or \fIrecv\fP.  Indeed, servers may use
        !          1174: buffered I/O as provided by the ``stdio'' conventions, as
        !          1175: long as as they remember to use \fIfflush\fP when appropriate.
        !          1176: .PP
        !          1177: One call which may be of interest to individuals writing
        !          1178: servers under \fIinetd\fP is the \fIgetpeername\fP call,
        !          1179: which returns the address of the peer (process) connected
        !          1180: on the other end of the socket.  For example, to log the
        !          1181: Internet address in ``dot notation'' (e.g., ``128.32.0.4'')
        !          1182: of a client connected to a server under
        !          1183: \fIinetd\fP, the following code might be used:
        !          1184: .DS
        !          1185: struct sockaddr_in name;
        !          1186: int namelen = sizeof (name);
        !          1187:  ...
        !          1188: if (getpeername(0, (struct sockaddr *)&name, &namelen) < 0) {
        !          1189:        syslog(LOG_ERR, "getpeername: %m");
        !          1190:        exit(1);
        !          1191: } else
        !          1192:        syslog(LOG_INFO, "Connection from %s", inet_ntoa(name.sin_addr));
        !          1193:  ...
        !          1194: .DE
        !          1195: While the \fIgetpeername\fP call is especially useful when
        !          1196: writing programs to run with \fIinetd\fP, it can be used
        !          1197: under other circumstances.  Be warned, however, that \fIgetpeername\fP will
        !          1198: fail on UNIX domain sockets.

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.