Chapter 3 Programmer's Manual This chapter provides an in depth description of the AmiTCP/IP application programming interface. Following sectionsintroduce the socket model of communication (3.1) andthe bsdsocket.library function calls implementing the socket abstraction. Some useful supporting routines are described in section 3.2. The client/server model is introduced in section 3.3. Some more advanced topics are discussed in section 3.4. Section 3.5 summarizes the small differences between AmiTCP/IP and 4.3BSD socket APIs. The full function reference of the AmiTCP/IP API functions is in appendix Bstarting from page 128. The textin sections 3.1 -- 3.4 is based on the [Leffler et al 1991a ]. 3.1 Socket Concepts The basic building block for communication is the socket. A socket is an endpoint of communication to which a name may be bound. Each socket in use has a type and one or more associated processes. Sockets exist within communication domains. A communication domain is an abstraction introduced to bundle common properties of processes communicating through sockets. One such property is the scheme used to name sockets. Sockets normally exchange data only with socketsin the same domain1. The AmiTCP/IP system supports currently onlyone communication domain: the Internet domain, which is used by processes which communicate using the the DARPA standard communication protocols. The underlying communication facilities provided by the domains havea significant influence on the internal system implementation as well as the interface to socket facilities available to a user. 3.1.1 Socket Types Sockets are typed according to the communication properties visible to a user. Processes are presumed to communicate only between sockets of the same type, although there is nothing that prevents communication between ________________________________ 1It may be possible to cross domain boundaries, but only if some translation process is performed. 27 28 Section 3.1 AmiTCP/IP System Manual sockets of different types should the underlying communication protocols support this. Three types of sockets currently are available to a user. A stream socket provides for the bidirectional, reliable, sequenced, and unduplicated flow of data without recordboundaries. Aside from the bidirectionality of data flow, a pair ofconnected stream sockets provides an interface nearly identical to that of pipes.2 A datagram socket supports bidirectional flow of data which is not promised to be sequenced, reliable, or unduplicated. That is, a process receiving messages on a datagram socketmay find messages duplicated, and, possibly, in an order different from the order in which it was sent. An important characteristic of a datagram socket is that record boundaries in data are preserved. Datagram sockets closely model the facilities found in many contemporary packet switched networks such as the Ethernet. A raw socket provides users access to the underlying communication protocols which support socket abstractions. These sockets are normally datagram oriented, though their exact characteristics are dependent on the interface provided by the protocol. Raw sockets are not intended for the general user; they have been provided mainly for those interested in developing new 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 3.4. Another potential socket type which has interesting properties is the reliably delivered message socket. The reliably delivered message socket has similar properties to a datagram socket, but with 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 3.4. 3.1.2 Using The Socket Library As any other Amiga shared library the bsdsocket.library must be opened to be able to access the functions in the library. Thiscan be done with Exec's OpenLibrary() call. The call returns a librarybase pointer which is task specfic, which means that each separate task (or process) must open the library itself. This is because the AmiTCP/IPstores task specific information to the library basestructure. The library base pointer returned by the OpenLibrary() must be stored in to a variable accessable from the program (usually global) named SocketBase. Example of opening the library follows: #include ... struct Library *SocketBase = NULL; ... if ((SocketBase = OpenLibrary("bsdsocket.library", 2)) == NULL) - ________________________________ 2In the UNIX systems pipes havebeen implemented internally as simply a pair of connected stream sockets. System Manual AmiTCP/IP Section 3.1 29 /* couldnot open the library */ ... " else - /* SocketBase now points to socket base of this task */ ... " Note thatthe library version argument of the OpenLibrary() call is given as 2, which means that at least version 2 is needed. This is the minimum version which should be requested, since the version 1 is incompatible with the version 2 and up. If the application uses features defined for some specific version (and up), a later version number should be specified. After theapplication is done with sockets the library must be closed. This is done with CloseLibrary() as follows: if (SocketBase) - CloseLibrary(SocketBase); SocketBase = NULL; " Note thatif the application in question is multithreaded, each task (or process) need to open/close its ownlibrary base. The base opened by the net.lib may be used by the originaltask only! Many programs expect the error values of the socket calls to be placed in a global variable named errno. By default a sharedlibrary cannot know the address (nor size) of the applications variables, however. There are two remedies to this: 1. Use function Errno() to retrieve the error value, or 2. Tell the address and the size of the errno variable to the AmiTCP/IP by using the SetErrnoPtr() call. The latter method requires only one additional function call to the startup of the application, and is thusthe preferred method. The call may look like: #include #include ... SetErrnoPtr(&errno, sizeof(errno)); All thisis done automatically for the application if it is linked with the net.lib3. See section 3.1.3 for more information about the net.lib and about compiling and linking the applications. ________________________________ 3The net.lib is compiler dependent and is currently defined for SASC 6 only. The actual name of the library varies and depends on the compiler options used. 30 Section 3.1 AmiTCP/IP System Manual 3.1.3 Compiling and Linking The Applications AmiTCP/IP provides standard BSD Unix header files to be used by the applications. Normally they are installed to a directory which is assigned to a name NETINCLUDE: (see section 1.1). This means that you should add the NETINCLUDE: to the compilers search path for include files. The include files are decribed briefly in the following subsection: The NETINCLUDE Header Files bsdsocket.h This file includes compiler specific prototypes and inline functions for bsdsocket.library. Currently supported compilers are GCC and SAS C version 6. The prototypes for the library functions are automatically included by the include files when appropriate, i.e. when the prototypes where declared in the original BSD includes. Thus the bsdsocket.h is included by sys/socket.h, netdb.h and arpa/inet.h. For other compilers only C prototypes are included, so stub routines should be used to call the functions. errno.h Replacement for the errno.h included in the standard C-compiler headers. This includes the file sys/errno.h, which defines symbolic constants for the error values returned by socket library calls. This file is BSD compatible and may well replace file provided by the SAS/C 6. netdb.h Contains definitions and prototypes for the network database functions, such as the gethostbyname(). Standard BSD System Headers sys/errno.h Error code definitions for system functions. sys/ioctl.h Definitions for socket IO control. sys/param.h General machine independent parameter definitions. sys/socket.h Definitions related to sockets: types, address families, options and prototypes. sys/syslog.h Definations for system logging facilities. sys/time.h Definition of structure timeval. sys/types.h Common C type definitions and file descriptorset macros for select(). Internet Related Headers arpa/inet.h Inet library function prototypes (inet_addr() etc.). Included for compatibility and only includes other include files. netinet/in.h Protocol numbers, port conventions, inet address definitions. netinet/in_systm.h Some network byte order type definitions. netinet/ip.h IP packet header, packet options, timestamp. System Manual AmiTCP/IP Section 3.1 31 netinet/ip_icmp.h ICMP packet structure. netinet/ip_var.h Defines IP statistics, external IP packet header, reassemble queues structures. netinet/tcp.h Defines the TCP packet structure. netinet/udp.h Defines the UDP packet structure. Network Related Headers net/if.h Defines the interface for network adapter drivers. net/if_arp.h General protocol independent ARP structures. net/route.h Routing ioctl definitions. net/sana2errno.h Sana-II related error definitions. net/sana2tags.h Tag definitions for configuring the Sana-II software network interface. Inetd Support inetd.h Internet daemon interface definitions. inetdlib.h Internet daemon library definitions. Prototypes clib/socket_inlines.h Inline function definitions for those BSD socket API functions, which are not implemented strictly like originals by bsdsocket.library. clib/socket_protos.h bsdsocket.library function call prototypes. SAS/C Pragmas pragmas/socket_pragmas.h SAS/C pragma library calls for bsdsocket.library. SAS/C Proto -file proto/socket.h Include file normally included by the SAS/C programs. Defines the socket base variable and includes the files clib/socket_protos.h and pragmas/socket_pragmas.h. GCC Inline Functions inline/socket.h GCC inline functions for the bsdsocket.library functions. Function Description File fd/socket_lib.fd Standard fd-file which specifies in which registers the arguments to the bsdsocket.library functions are passed. This file can be used to obtain information needed to call the bsdsocket.library functions by the assembler programs. Sana-II Header Files devices/sana2.h Definitions for the Sana-II network device driver interface. 32 Section 3.1 AmiTCP/IP System Manual devices/sana2specialstats.h Special statistics definitions for the Sana-II. Miscellaneous charread.h Macro package to do buffered byte-by-byte reading from a socket. lineread.h Definitions for buffered line orientedreading from a socket. Linking With net.lib AmiTCP/IP distribution includes a link library named net.lib to be used by the applications. It is normally located in the directory which has an assigned name NETLIB:. The library contains compiler dependent code which makes the library itself compiler dependent. Currently only SASC version6 is supported4. net.lib features automatic initialization and termination functions which open and close the bsdsocket.library for the application. Using this feature it is possible to compile some typical BSD Unix socket based applications with AmiTCP/IP without anymodifications to the original source code. Note that this base may be used by the process starting the program, i.e. the one that executes themain(). This applies to the included utility functions which call the socket library, too. The library also defines new array of error names to be used by perror() library function. This is done because the error name array normally used by Amiga C compilers doesnot contain enough error entries, resulting perror() to print "Unknown error code" if some socket error is passed. Note that for perror() to work the error valuemust be placed into the global errno variable. This is accomplished by the SetErrnoPrt() call made in the automaticinitialization function. For the library functions to take effect, the library must be specified before the C compiler own libraries in the link command line. 3.1.4 Socket Creation To create a socket the socket() system call is used: s = socket(domain, type, protocol); This call requests that the system create a socket in the specified domain and of the specified type. A particular protocol may also be requested. If the protocol is left unspecified (a value of 0), the system will select an appropriate protocol from those protocols which comprise the communication domain and which may be used to support the requested socket type. The user is returned a descriptor (a small integer number) which may be used in later system calls which operate on sockets. The domain is specified as one of the manifest constants ________________________________ 4But since the source for the library is provided, it can be used with any C compiler. System Manual AmiTCP/IP Section 3.1 33 defined in the file sys/socket.h. For the Internet domain the constant is AF_INET5. The socket types are also defined in this file and one of SOCK_STREAM, SOCK_DGRAM or SOCK_RAW mustbe specified. To create a stream socket in the Internet domain the following call might be used: s = socket(AF_INET, SOCK_STREAM, 0); This call would result in a stream socket being created with the TCP protocol providing the underlying communication support. To create a datagram socket the call might be: s = socket(AF_INET, SOCK_DGRAM, 0); The default protocol (used when the protocol argument to the socket() 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 3.4. There areseveral reasons a socket() call may fail. Aside from the rare occurrence of lack of memory (ENOBUFS), a socket request may fail due to a request for an unknown protocol(EPROTONOSUPPORT), or a request for a type of socket for which there isno supporting protocol (EPROTOTYPE). 3.1.5 Binding Local Names 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. Communicating processes are bound by an association. In the Internet domain, an association is composed of local and foreign addresses, and local and foreign ports,In most domains, associations must be unique. In the Internet domain there may neverbe duplicate tuples. The bind() system call allows a process to specify half of an association, , while the connect() and accept() calls are used to complete a socket's association. In the Internet domain, binding names to sockets can be fairly complex. Fortunately, it is usually not necessaryto specifically bind an address and port number to a socket, because theconnect() and send() calls will automatically bind an appropriate address if they are used with an unbound socket. The bind() system call is used as follows: bind(s, name, namelen); The bound name is a variable length bytestring 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 domain). As mentioned, in the Internet domain names contain an Internet addressand port number. In binding an Internet address things are a little complicated: ________________________________ 5The manifest constants are named AF _whatever as they indicate the ``address format'' to use in interpreting names. 34 Section 3.1 AmiTCP/IP System Manual #include #include ... struct sockaddr_in sin; ... bind(s, (struct sockaddr *) &sin, sizeof (sin)); The selection of what to place in the address sin requires some discussion. We will come back to the problem of formulating Internet addresses in section 3.2 when the library routines used in name resolution are discussed. 3.1.6 Connection Establishment Connection establishment is asymmetric,with one process a ``client'' and the other a ``server''. The server, when willing to offer its advertised services, binds a socket to a well--known address associated with the service and then passively ``listens'' on its socket. It is then possible for an unrelated process to rendezvous with the server. The client requests services from the serverby initiating a ``connection'' to the server's socket. On the client side the connect() call is used to initiate a connection. Using the Internet domain, thismight apper as: struct sockaddr_in server; ... connect(s, (struct sockaddr *)&server, sizeof (server)); where server in the example above would contain Internet 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 if necessary. This is the usual way that local addresses are bound to a socket. An erroris returned if the connection was unsuccessful (any name automatically bound by the system, however, remains). Otherwise, the socket is associated with the server anddata transfer may begin. Some of the more common errors returned whena connection attempt fails are: ETIMEDOUT After failing to establish a connection for a period of time, the system decided there was no point in retrying the connection attempt any more. This usually occurs because the destination host is down, or because problems in the network resulted in transmissions being lost. ECONNREFUSED The host refusedservice for some reason. This is usually due to a server process not being present at the requested name. ENETDOWN or EHOSTDOWN These operational errors are returned based on status information delivered to the client host by the underlying communication services. ENETUNREACH or EHOSTUNREACH These operational errors can occur either because the network or host is unknown (no route to the network or System Manual AmiTCP/IP Section 3.1 35 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 host being down, in which case the system indicates the entire network is unreachable. For the server to receive a client's connection it must perform two steps after binding its socket. The first is to indicate a willingness to listen for incoming connection requests: listen(s, 5); The second parameter to the listen() call specifies the maximum number of outstanding connections which may be queued awaiting acceptance by the server process; this number may be limited by the system. Should a connection be requested while the queueis 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 make room in its pending connection queue while the client 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 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 systemresources by setting an infinite backlog, then ignoring all connection requests. With a socket marked as listening, a server may accept a connection: struct sockaddr_in from; ... fromlen = sizeof (from); newsock = accept(s, (struct sockaddr *)&from, &fromlen); A new descriptor is returned on receiptof 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'sname. The value--result parameter fromlen is initialized by theserver to indicate how much space is associated with from, 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 a NULL pointer. accept()normally blocks. That is, accept() will not return until a connection is available or the system call is interrupted by a signal6 to the process. Further, there is no way for a process toindicate it will accept connections from only a specificindividual, or individuals. It is up to the user process to consider who the connection is from and close down the connection if it does notwish to speak to the process. If the server process wants to accept connections on more than one socket, or wants to avoid blocking on the accept call, there are alternatives; they will be considered insection 3.4. ________________________________ 6By default, the CTRL-C signalinterrupts the system calls, but the application may change this, however. 36 Section 3.1 AmiTCP/IP System Manual 3.1.7 Data Transfer With a connection established, data maybegin to flow. To send and receive data there are a number of possible calls. With the peer entity at each end of a connection anchored, auser can send or receive a message without specifying the peer. The calls send()and recv() may be used: send(s, buf, sizeof (buf), flags); recv(s, buf, sizeof (buf), flags); While send() and recv() are virtually identical to the standard I/O routines, the extra flags argument is important. Theflags, defined in sys/socket.h, may be specified as a non--zero value if one or more of the following is required: MSG_OOB Send/receive out of band data. MSG_PEEK Lookat data without reading. MSG_DONTROUTESend data without routing packets. Out of band data is a notion specific to stream sockets, and one which we will not immediately consider. The option to have data sent without routing applied to the outgoing packetsis currently used only by the routing table management process, and isunlikely to be of interest to the casual user. The ability to preview data is, however, of interest. When MSG_PEEK is specified with a recv() call, any data present is returned to the user, but treated as still ``unread''. That is, the next recv() call applied to the socket will return the data previously previewed. 3.1.8 Discarding Sockets Once a socket is no longer of interest,it may be discarded by applying a CloseSocket() to the descriptor, CloseSocket(s); If data is associated with a socket which promises reliable delivery (e.g. a stream socket) when a close takes place, the system will continue to attempt to transfer the data. However, after a fairly long period of time, if the data is still undelivered, it will be discarded. Should a user have no use for any pending data, it may perform a shutdown() on the socket prior to closing it. This call is of the form: shutdown(s, how); where how is 0 if the user is no longerinterested in reading data, 1 if no more data will be sent, or 2 if no data is to be sent or received. System Manual AmiTCP/IP Section 3.1 37 3.1.9 Connectionless Sockets To this point we have been concerned mostly with sockets which follow a connection oriented model. However, there is also support for connectionless interactions typical of the datagram facilities found in contemporary packet switched networks. A datagram socket provides a symmetric interface to data exchange. While processesare still likely to be client and server, there is no requirement for connection establishment. Instead, each message includes the destination address. Datagramsockets are created as before. If a particular local address is needed, the bind operation must precede the first data transmission. Otherwise, the system will set the localaddress and/or port when data is first sent. To send data, the sendto() call is used, sendto(s, buf, buflen, flags, (struct sockaddr *)&to, tolen); The s, buf, buflen, and flags parametersare used as before. The to and tolen values are used to indicate the address of the intended recipient of the message. When using an unreliable datagram interface, it is unlikely that any errors will be reported to the sender. When information is present locally to recognize a message that can not be delivered (for instance when a network is unreachable), the call will return -1 and the global value errno will contain an error number (See section 3.1.2 for discussion about errno). To receive messages on an unconnected datagram socket, the recvfrom() call is provided: recvfrom(s, buf, buflen, flags, (struct sockaddr *)&from, &fromlen); Once again, the fromlen parameter is handled in a value--result fashion, initially containing the size of the from buffer, and modified on return to indicate the actual size of the address from which the datagram was received. In addition to the two calls mentioned above, datagram sockets may also use the connect() call to associate 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 address is permitted for each socket at one time; a second connect() will change the destination address, and a connect() toa null address (family AF_UNSPEC) will disconnect. Connect requests on datagram socketsreturn 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 endconnection). accept() and listen() are not used with datagram sockets. While a datagram socket is connected, errors from recent send() calls may be returned asynchronously. These errors may be reported on subsequent operations on the socket, ora special socket option used with getsockopt(), SO_ERROR,may be used to interrogate the error status. A select() for reading or writing will return true when an error indication has been received. The next operation will return theerror, and the error status is cleared. Other of the less important details of datagram sockets are described in section 3.4. 38 Section 3.1 AmiTCP/IP System Manual 3.1.10 Input/Output Multiplexing One last facility often used in developing applications is the ability to multiplex i/o requests among multiple sockets. This is done using the select() call. The select() call provided by AmiTCP/IPis actually a compile time inline function (or normalstub with compilers without inline facility) which calls the WaitSelect(). The WaitSelect() call is similar to the normal select() call, buthas one extra argument specifying a pointer to a signal mask for the signals which should break the selection (in addition to the timeouts and the break signal). This makes possible to use WaitSelect() instead of normal Wait() as a driver for the applications event loop. If the pointer is given as NULL the functionality is as with BSD select(). The inline (orstub) function for select* *() actually just calls the WaitSelect() with last argument as NULL. Here is abrief example of the usage of the WaitSelect(): #include #include ... fd_set readmask, writemask, exceptmask; struct timeval timeout; ULONG signalmask; ... WaitSelect(nfds, &readmask, &writemask, &exceptmask, &timeout, &signalmask); WaitSelect() takes as arguments pointersto three sets, one for the set of file descriptors for which the callerwishes 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; out-of-band data is the only exceptional condition currently implemented. If the user is not interested in certain conditions (i.e.,read, write, or exceptions), the corresponding argument to the select() should be a NULL pointer. Each setis actually a structure containing an array of long integer bit masks; the size of the array is setby the definition FD_SETSIZE. The array is long enough to hold one bit foreach of FD_SETSIZE file descriptors. The macros FD_SET(fd, &mask) and FD_CLR(fd, &mask) have been provided for adding and removing file descriptorfd in the set mask. The set should be zeroed before use, and the macro FD_ZERO(&mask) has been provided to clear the set mask. The parameter nfds inthe select() call specifies the range of file descriptors(i.e. one plusthe value of the largest descriptor) to be examined in aset. A timeoutvalue may be specified if the selection is not to last more than a predetermined period of time. If the fields intimeout are set to 0, the selection takes the form of a poll, returning immediately. If the last parameter is a NULL pointer, the selection will block indefinitely7. ________________________________ 7To be more specific, a returntakes place only when a descriptor is selectable, or when a signal is receivedby the caller, interrupting the system call. System Manual AmiTCP/IP Section 3.1 39 The lastargument is a pointer to the mask specifying signals for which the WaitSelect() should break. WaitSelect() normally returns the number of file descriptors selected; if the WaitSelect() call returns due to the timeout expiring, then the value 0 is returned. If the WaitSelect() terminates because of an error or interruption, a -1 is returned with the error number in errno, and with the filedescriptor masks unchanged. The signal mask is altered on return to holdthe bits for the signals which caused the break. Assuminga 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 ina select mask may be tested with the FD_ISSET(fd, &mask) macro, which returns a non-zero value if fd is a member of the set mask,and 0 if it is not. To determine if there are connections waiting on a socket to be used with an accept() call, select() can be used, followed by a FD_ISSET(fd, &mask) macro to check for read readiness on the appropriate socket. If FD_ISSET() returns a non-zero value, indicating permission to read, then a connection is pending on the socket. As an example, to read data from two sockets, s1 and s2 as it is available from each and with a one--second timeout, the following code might be used: #include #include #include ... fd_set read_template; struct timeval wait; int nb; int s1,s2; int maxfd; ... maxfd = s1 > s2 ? s1 : s2; for (;;) - wait.tv_sec = 1; /* onesecond */ wait.tv_usec = 0; FD_ZERO(&read_template); FD_SET(s1, &read_template); FD_SET(s2, &read_template); nb = select(maxfd, &read_template, NULL, NULL, &wait); if (nb <=0) - /* An error occurred during the select, or the select timed out. */ " if (FD_ISSET(s1, &read_template)) - /* Socket #1 is ready to be readfrom. */ " if (FD_ISSET(s2, &read_template)) - /* Socket #2 is ready to be readfrom. */ 40 Section 3.2 AmiTCP/IP System Manual " " Note theusage of the select(), which calls WaitSelect() with NULL signal mask pointer. In 4.2BSD, the arguments to select() were pointers to integers instead of pointers to fd_sets. This type ofcall 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. select()provides a synchronous multiplexing scheme. Asynchronous notification of output completion, inputavailability, and exceptional conditions is possible through use of the SigIO and SigURG signals described in section 3.4. 3.2 Network Library Routines The discussion in section 3.1 indicatedthe possible need to locate and construct network addresses when using the interprocess communication facilities in a distributed environment. To aid in this task a number of routines have been added to the Amiga shared socket library. In this section we will consider the routines provided to manipulate network addresses. Locatinga service on a remote host requires many levels of mapping before client and server may communicate. A service is assigned a name which is intended for human consumption;e.g. ``the login server on host monet''. This name, and the name of the peer host, must then be translated into network addresses whichare not necessarily suitable for human consumption. Finally, the address must then usedin locating a physical location and route to the service. The specifics of these three mappings are likely to vary between network architectures. For instance, it is desirable for a network 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 host wishes tocommunicate. This ability to have hosts named in a location independent manner may induce overhead in connection establishment, as a discovery process must take place, but allows a host to be physically mobile without requiring it to notify its clientele of its current location. Standardroutines are provided for: mapping host names to network addresses, network names to network numbers, protocol names to protocol numbers, and service names to port numbers and the appropriate protocol to use in communicating with the serverprocess. The file netdb.h must be included when using any of these routines. 3.2.1 Host Names An Internet host name to address mappingis represented by the hostent structure: System Manual AmiTCP/IP Section 3.2 41 struct hostent - char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* host address type (e.g., AF_INET) */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses, nullterminated */ "; #define h_addr h_addr_list[0] /* first address, network byte order */ The routine gethostbyname() takes an Internet host name and returns a hostent structure, while the routine gethostbyaddr() maps Internet host addresses into a hostent structure. 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 addresses. This list of addresses is required because it is possible for a host to have many addresses, all having the same name. The h_addr definition is provided for backward compatibility, and is defined to be thefirst address in the list of addresses in the hostent structure. The database for these calls is provided either by the configuration file or by use of a name server. Because of the differences in these databases and their access protocols, the information returned may differ. When using the host table version of gethostbyname(), only one address will be returned, but all listedaliases will be included. The name server version may return alternateaddresses, but will not provide any aliases other than one given as argument. 3.2.2 Network Names As for host names, routines for mappingnetwork names to numbers, and back, are provided. These routines return a netent structure: /* * Assumption here is that a network number * fits in 32 bits -- probably a poor one. */ struct netent - char *n_name; /* official name of net */ char **n_aliases; /* alias list */ int n_addrtype; /* net address type */ int n_net; /* networknumber, host byte order */ "; The routines getnetbyname(), andgetnetbynumber() are the network counterparts to the host routines described above. The routines uses data read from AmiTCP/IP configuration file. 3.2.3 Protocol Names For protocols, the protoent structure defines the protocol--name mapping used with the routines getprotobyname()and getprotobynumber(): 42 Section 3.2 AmiTCP/IP System Manual struct protoent - char *p_name; /* official protocol name */ char **p_aliases; /* alias list */ int p_proto; /* protocol number */ "; 3.2.4 Service Names Information regarding services is a bitmore complicated. A service is expected to reside at a specific ``port'' 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. If this occurs,the higher level library routines will have to be bypassed or extended. A service mapping is described by the servent structure: struct servent - char *s_name; /* official service name */ char **s_aliases; /* alias list */ int s_port; /*port number, network byte order */ char *s_proto; /* protocol to use */ "; The routine getservbyname() maps service names to a servent structure by specifying a service name and, optionally, a qualifying protocol. Thus the call sp = getservbyname("telnet", NULL); returns the service specification for atelnet server using any protocol, while the call sp = getservbyname("telnet", "tcp"); returns only that telnet server which uses the TCP protocol. The routine getservbyport() is also provided. The getservbyport()routine has an interface similar to that provided by getservbyname(); an optional protocol name may be specified to qualify lookups. 3.2.5 Miscellaneous 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 fashion. It is clear, however, that purging all network dependencies is very difficult. So long as the user is required to supply network addresses when naming services and sockets there will always some network dependency in a program. For example, the normal codeincluded in client programs, such as the remote login program, is as follows: System Manual AmiTCP/IP Section 3.2 43 Remote Login Client Code #include #include #include #include #include ... int main(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"n"); exit(1); " hp = gethostbyname(argv[1]); if (hp == NULL) - fprintf(stderr, "rlogin: %s: unknown host"n",argv[1]); exit(2); " bzero((char *)&server, sizeof (server)); server.sin_port = sp->s_port; bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length); server.sin_family = hp->h_addrtype; s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) - perror("rlogin: socket"); exit(3); " ... /* Connect does the bind()for us */ if (connect(s, (struct sockaddr *)&server, sizeof (server)) < 0) - perror("rlogin: connect"); exit(5); " ... " (This example will be considered in more detail in section 3.3.) If we wanted to make the remote login program independent of the Internet protocols and addressing schemewe 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. Aside from the address-related data base routines, there are several other routines available in the run-timelibrary which are of interest to 44 Section 3.3 AmiTCP/IP System Manual users. These are intended mostly to simplify manipulation of names and addresses. The routines for manipulating variable length byte strings and handling byte swapping of network addresses and values are summarized below:8. bcmp(s1, s2, n) Compare byte-strings; 0 if same, not 0 otherwise. bcopy(s1, s2, n) Copy n bytes from s1 to s2. bzero(base, n) Zero-fill n bytes starting at base. htonl(val) Convert 32-bit quantity from host to network byte order. htons(val) Convert 16-bit quantity from host to network byte order. ntohl(val) Convert 32-bit quantity from network to host byte order. ntohs(val) Convert 16-bit quantity from network to host byte order. The byteswapping routines are provided because the operating system expects addresses to be supplied in network order. Onsome 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 orderso that they may simply be copied into the structures provided to the system. This implies users should encounter the byte swapping problem onlywhen interpreting network addresses. For example, if an Internet port is to be printed out the following code would be required: printf("port number %d"n", ntohs(sp->s_port)); On machines where unneeded (as on Amiga)these routines are defined as null macros. 3.3 Client/Server Model The most commonly used paradigm in constructing distributed applications is the client/server model. In this scheme client applications request services from a server process. This implies an asymmetry in establishing communication between the client and server which has been ________________________________ 8The byte string functions areprovided by the C-compiler. The byte order functions are provided as preprocessor macros. System Manual AmiTCP/IP Section 3.3 45 examined in section 3.1. In this section we will lookmore closely at the interactions between client and server, and consider some of the problems in developing client and serverapplications. 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 immutably recognized as the master, with the other as the slave. An example of a symmetric protocol is the TELNET protocol used inthe Internet for remote terminal emulation. An example of an asymmetric protocol is theInternet file transfer protocol, FTP. No matter whether the specific protocol used in obtaining a service is symmetric or asymmetric, when accessing a service there is a ``client process'' and a ``server process''. Wewill first consider the properties of server processes, then client processes. A serverprocess normally listens at a well known address for service requests. That is, the server process remains dormantuntil a connection is requested by a client's connection tothe server's address. At such a time the server process ``wakes up'' andservices the client, performing whatever appropriate actions the clientrequests of it. Alternative schemes which use a service server may be used to eliminate a flock of server processes clogging thesystem while remaining dormant most of the time. For Internet servers in 4.3BSD, thisscheme has been implemented via inetd, the so called ``internet super-server.'' Inetd listens at a variety of ports, determined at start-up by reading a configuration file. When a connection is requested toa port on which inetd is listening, inetd executes the appropriate server program to handle the client. Inetd will be described in more detail in section 3.4. 3.3.1 Servers 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 below (AmiTCP/IP way): main(int argc, char *argv) - int f; struct sockaddr_in from; struct servent *sp; sp = getservbyname("login", "tcp"); if (sp ==NULL) - fprintf(stderr, "rlogind: tcp/login: unknown service"n"); exit(1); " ... sin.sin_port = sp->s_port; /* Restricted port */ ... 46 Section 3.3 AmiTCP/IP System Manual f = socket(AF_INET, SOCK_STREAM, 0); ... if (bind(f, (struct sockaddr *) &sin, sizeof (sin)) < 0) - ... " ... 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: %s", errors[errno]); continue; " /* * AmiTCP code follows... */ id = ReleaseSocket(g, UNIQUE_ID); startit(id, &from); " " The firststep taken by the server is look up its service definition: sp = getservbyname("login", "tcp"); if (sp == NULL) - fprintf(stderr, "rlogind: tcp/login: unknown service"n"); exit(1); " The result of the getservbyname call isused in later portions of the code to define the Internet port at which it listens for service requests (indicated by a connection). Once a server has established a pristine environment, it creates a socket and begins accepting service requests. The bind() call is required to insure the server listens atits expected location. The mainbody of the loop is fairly simple: for (;;) - int g, len = sizeof (from); g = accept(f, (struct sockaddr *)&from, &len); if (g < 0) - if (errno != EINTR) syslog(LOG_ERR, "rlogind: accept: %s", errors[errno]); continue; " /* * AmiTCP code follows... */ id = ReleaseSocket(g, UNIQUE_ID); startit(id, &from); " System Manual AmiTCP/IP Section 3.3 47 An accept() call blocks the server until a client requests service. This call could return a failure statusif the call is interrupted by a signal such as CTRL-C (to be discussed in section 3.4). Therefore, the return value from accept() is checked toinsure a connection has actually been established. With a connection in hand, servers using AmiTCP/IP socket library, this new socket is released to an external list inside AmiTCP/IP process via ReleaseSocket() call. ReleaseSocket() returns an id (unique if requested). startit() starts a new AmigaOS task and informs the id for it. This new task then uses ObtainSocket() with id asargument to receive the socket. The address of the client is alsohandled the new task because it requires it in authenticating clients. 3.3.2 Clients The client side of the remote login service was shown earlier in section 3.2. One can see the separate, asymmetric roles of theclient and server clearly in the code. The server is a passive entity, listening for client connections, while the client process is an active entity, initiating a connection when invoked. Let us consider more closely the steps taken by the client remote login process. As in the server process, the first step is to locate the service definition for a remote login: sp = getservbyname("login", "tcp"); if (sp == NULL) - fprintf(stderr, "rlogin: tcp/login: unknown service"n"); exit(1); " Next thedestination host is looked up with a gethostbyname() call: hp = gethostbyname(argv[1]); if (hp == NULL) - fprintf(stderr, "rlogin: %s: unknown host"n", argv[1]); exit(2); " With this accomplished, all that is required is to establish a connection to the server at the requested host andstart up the remote login protocol. The address buffer is filled in with the Internet address and rlogin port number of the foreign host. bzero((char *)&server, sizeof (server)); server.sin_port = sp->s_port; bcopy(hp->h_addr, (char *) &server.sin_addr, hp->h_length); server.sin_family = hp->h_addrtype; A socket is created, and a connection initiated. Notethat connect() implicitly performs a bind() call, because s is unbound. s = socket(hp->h_addrtype, SOCK_STREAM, 0); if (s < 0) - 48 Section 3.3 AmiTCP/IP System Manual perror("rlogin: socket"); exit(3); " ... if (connect(s, (struct sockaddr *) &server, sizeof (server)) < 0) - perror("rlogin: connect"); exit(4); " The details of the remote login protocolwill not be considered here. 3.3.3 Connectionless Servers While connection-based services are thenorm, some services are based on the use of datagram sockets. One, in particular, is the ``rwho'' service which provides users with status information for hosts connected to a local area network. This service, while predicated onthe ability to broadcast information to all hosts connected to a particular network, is of interest as an example usage of datagram sockets. A user onany machine running the rwho server may find out the current status of a machine with the ruptime program. The output generated is illustrated below. Ruptime Output arpa up 9:45, 5 users, load 1.15, 1.39, 1.31 cad up 2+12:04, 8 users, load 4.67, 5.13, 4.59 calder up 10:10, 0 users,load 0.27, 0.15, 0.14 dali up 2+06:28, 9 users, load 1.04, 1.20, 1.65 degas up 25+09:48, 0 users, load 1.49, 1.43, 1.41 ear up 5+00:05, 0 users, load 1.51, 1.54, 1.56 ernie down 0:24 esvax down 17:04 ingres down 0:26 kim up 3+09:16, 8 users, load 2.03, 2.46, 3.11 matisse up 3+06:18, 0 users, load 0.03, 0.03, 0.05 medea up 3+09:39, 2 users,load 0.35, 0.37, 0.50 merlin down 19+15:37 miro up 1+07:20, 7 users, load 4.59, 3.28, 2.12 monet up 1+00:43, 2 users,load 0.22, 0.09, 0.07 oz down 16:09 statvax up 2+15:57, 3 users, load 1.52, 1.81, 1.86 ucbvax up 9:34, 2 users, load 6.08, 5.16, 3.28 Status information for each host is periodically broadcast by rwho server processes on each machine. The same server process also receives the status information and uses it to update a database. This database is then interpreted to generate the status information for each host. Servers operate autonomously, coupled only by the local network and its broadcast capabilities. Note thatthe use of broadcast for such a task is fairly inefficient, as all hosts must process each message,whether or not using an rwho System Manual AmiTCP/IP Section 3.3 49 server. Unless such a service is sufficiently universal and is frequently used, the expense of periodicbroadcasts outweighs the simplicity. The rwhoserver, in a simplified form, is pictured next9: BYTE alrmsig; main() - long on; fd_set readfds; ... sp = getservbyname("who", "udp"); sin.sin_port = sp->s_port; net = getnetbyname("localnet"); sin.sin_addr = inet_makeaddr(INADDR_ANY, net); ... s = socket(AF_INET, SOCK_DGRAM, 0); ... on = 1; if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) - syslog(LOG_ERR, "rwhod: setsockopt SO_BROADCAST: %s", strerror(errno)); exit(1); " bind(s, (struct sockaddr *) &sin, sizeof (sin)); ... alrmsig =AllocSignal(-1); onalrm();/* activate and handle periodic alarm system */ FD_ZERO(&readfds); FD_SET(s, &readfds); for (;;)- struct whod wd; struct sockaddr_in from; int n, cc, whod, len = sizeof (from); ULONG alrmmask; alrmmask = 1 << alrmsig; n = WaitSelect(s, &readfds, NULL,NULL, NULL, &alrmmask); if (n < 0) - syslog(LOG_ERR, "rwhod: WaitSelect: %s", strerror(errno)); exit(1); " if (alrmmask) onalrm(); /* handles the alarm */ if (n > 0) - cc = recvfrom(s, (char *)&wd, sizeof (wd), 0, (struct sockaddr *)&from, &len); if (cc <= 0) - ________________________________ 9A real code must always test the return values of various services against errors. Thes e tests are partly omitted from this code to show the matters important to this section. 50 Section 3.3 AmiTCP/IP System Manual if (cc < 0) syslog(LOG_ERR, "rwhod: recv: %s", strerror(errno)); continue; " if (from.sin_port != sin.sin_port) - syslog(LOG_ERR, "rwhod: %ld: bad from port", ntohs(from.sin_port)); continue; " ... if (!verify(wd.wd_hostname)) - syslog(LOG_ERR, "rwhod: malformed host name from %lx", ntohl(from.sin_addr.s_addr)); continue; " (void) sprintf(path, "%s/whod.%s", RWHODIR, wd.wd_hostname); whod = open(path, O_WRONLY _ O_CREAT _ O_TRUNC, 0666); ... (void) time(&wd.wd_recvtime); (void) write(whod, (char *)&wd, cc); (void) close(whod); " " " There aretwo separate tasks performed by the server. The first task is to act as a receiver of status information broadcast by other hosts on the network. This job is carried out in the main loopof the program. Packets received at the rwho port are interrogated to insure they've been sent by another rwho server process, then are time stamped with their arrival time and used to update a file indicating the status of the host. When a host has not been heard from foran extended period of time, the database interpretation routines assumethe host is down and indicate such on the status reports. This algorithm is prone toerror as a server may be down while a host is actually up,but serves our current needs. The second task performed by the server is to supply information regarding the status of its host. This involves periodically acquiring system status information, packaging itup in a message 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 where to transmit the resultantpacket is somewhat problematical, however. Status information must be broadcast on the local network. For networks which do not support the notionof broadcast another scheme must be used to simulate or replace broadcasting. One possibility is to enumerate the known neighbors (based onthe 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, nomachine 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 System Manual AmiTCP/IP Section 3.4 51 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 theyalways communicate with these neighbors. Ifeach server has at least one neighbor supplied 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 those which do not, then networks with an arbitrary topology may share status information10 It is important that software operating in a distributed environment not have any site-dependent informationcompiled into it. This would require a separate copy of the server ateach host and make maintenance a severe headache. 4.3BSD attempts to isolate host-specific information from applications by providing system calls which return the necessary information11. A mechanism exists, in the form of an IoctlSocket() 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 asite independent manner. This allows 4.3BSD to solve the problem of decidinghow to propagate status information in the case of rwho, 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 ioctl calls. The specifics of such broadcastings are complex, however, and will be covered in section 3.4. 3.4 Advanced Topics A number of facilities have yet to be discussed. Formost users of the AmiTCP/IP the mechanisms already described will suffice in constructing distributed applications. However, others will find the need to utilize some of the features which we consider in this section. 3.4.1 OutOf Band Data The stream socket abstraction includes the notion of ``out of band'' 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. The abstraction defines that the out of band data facilities must support the reliable delivery of at least one out of band message at a time. This message may contain at least one byte of data, and at least one message may be pending delivery to the user at any onetime. For communications protocols which support only in-band signaling (i.e. the urgent data is ________________________________ 10One must, however, be concerned about loops. That is, if a host is connected to multiple networks, it willreceive status information from itself. This can lead to an endless, wasteful, exchange of information. 11An example of such a system call is the gethostname() call which returns the host's official name. 52 Section 3.4 AmiTCP/IP System Manual delivered in sequence with the normal data), the system normally extracts the data from the normal data stream andstores it separately. This allows users to choose between receiving the urgent data in order and receiving it out of sequence without having to bufferall the intervening data. It is possib* *le to ``peek'' (via MSG_PEEK) at out of band data. If the socket has an owner, a signal is generated when the protocolis notified of its existence. A process can set the task to be informed by a signal via the appropriate IoctlSocket() and SetSocketSignals() calls, as described below in section 3.4.3. If multiple sockets may have out of band data awaiting delivery, a select() call for except* *ional conditions may be used to determine those sockets with such data pending. Neit* *her the signal nor the select() indicate theactual arrival of the out-of-band data, but only notification that it is pending. 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 sent12. The remote login and remote shell applications use this facility to propagate signals between client andserver processes. When a signal flushs any pending output from the remote process(es), all data up to the mark in the data stream is discarded. To send an out of band message the MSG_OOB flag is supplied to a send() or sendto() calls, while to receive outof band data MSG_OOB should be indicated when performing a recvfrom() or recv() call. To find out if the read pointer is currently pointing at the mark in the data stream, the SIOCATMARK ioctl is provided: IoctlSocket(s, SIOCATMARK, &yes); If yes is a 1 on return, the next read will return data after the mark. Otherwise (assuming out of band data hasarrived), the next read will provide data sent by the client prior totransmission of the out of band signal. The routine used in the remote login process to flush output on receipt of an interrupt or quit signal is shown below: #include #include ... oob() - int mark; char waste[BUFSIZ]; /* flushterminal I/O on receipt of out of band data */ for (;;)- if (IoctlSocket(rem, SIOCATMARK,&mark) < 0) - perror("IoctlSocket"); break; " if (mark) break; recv(rem, waste, sizeof (waste),0); ________________________________ 12AmiTCP/IP follows the BSD interpretation of the RFC 793 in which the concept of out-of-band data is introduced. The BSD interpretation is in conflict with (later) defined Host Requirements laid down in RFC 1122. System Manual AmiTCP/IP Section 3.4 53 " if (recv(rem, &mark, 1, MSG_OOB) < 0) - perror("recv"); ... " ... " The normal data up to the mark if first read (discarding it), then the out-of-band byte is read. A processmay also read or peek at the out-of-band data without first reading up to the mark. This is more difficult when the underlying protocol delivers the urgent data in-band with the normal data, and only sends notification of its presence aheadof time (e.g., the TCP protocol used to implement streams in the Internet domain). With such protocols, the out-of-band byte may not yet have arrived when a recv() is done with the MSG_OOB flag. In that case, the call will return an error of EWOULDBLOCK. Worse, there may be enoughin-band data in the input buffer that normal flow control prevents the peer from sending the urgent data until the buffer is cleared. The process must then read enough of the queued data that the urgent data may bedelivered. Certain programs that use multiple bytes of urgent data and must handle multiple urgent signals (e.g., telnet) need to retain the position of urgent data within the stream. This treatment is available as a socket-level option, SO_OOBINLINE; see function reference for setsockopt() for usage. With this option, the positionof urgent data (the ``mark'') is retained, but the urgent data immediately follows the mark within the normal data stream returned without the MSG_OOB flag. Reception of multiple urgent indicationscauses the mark to move, but no out-of-band data are lost. 3.4.2 Non-Blocking Sockets It is occasionally convenient to make use of sockets which do not block; that is, I/O requests which cannot complete immediately and would therefore cause the process to be suspended awaiting completion are not executed, and an error code is returned. Once a sockethas been created via the socket() call, it may be markedas non-blocking by IoctlSocket() as follows: #include ... int s; long yes = TRUE; ... s = socket(AF_INET, SOCK_STREAM, 0); ... if (IoctlSocket(s, FIONBIO, &yes) < 0) perror("IoctlSocket FIONBIO"); exit(1); " ... When performing non-blocking I/O on sockets, one must be careful to check for the error EWOULDBLOCK (storedin the global variable errno), 54 Section 3.4 AmiTCP/IP System Manual which occurs when an operation would normally block, but the socket it was performed on is marked as non-blocking. In particular, accept(), connect(), send(), sendto(), recv() andrecvto() can all return EWOULDBLOCK, and processes should be prepared to deal with such return codes. If an operation such as a send() cannot be donein its entirety, but partial writes are sensible (for example, when using a stream socket), the data that can be sent immediately will be processed, and the return value will indicate the amount actually sent. 3.4.3 Signal Driven Socket I/O The AmiTCP/IP allows a task to be notified via a signal when a socket has either normal or out-of-band data waiting to be read. Use of this facility requres four steps: 1. The signals to be used must be allocated with Exec AllocSignal() call. 2. The allocated signal(s) must be registered to the AmiTCP/IP with the SetSocketSignals() call. The signals registered with SetSocketSignals() affect all sockets of the calling task, so this is usually done only after OpenLibrary() call. 3. The owner of the socket must be set to the task itself (note that the owner of a socket is unspecified by default). This is accomplished by the use of an IoctlSocket() call. 4. Asynchronous notification for the socket must be enabled with another IoctlSocket() call Note that it is application's responsibility to react on received signals. Sample code to allow a given process to receive information on pending I/O requests as they occur for a sockets is given below: #include #include ... BYTE SIGIO = -1, SIGURG = -1; ... struct Task *thisTask = FindTask(NULL); /* our task pointer */ long yes = TRUE; /* Allocate signals for asynchronous notification */ if ((SIGIO = AllocSignal(-1)) == -1) - fprintf(stderr, "allocSignal failed."n"); exit(1); " atexit(freeSignals); /* free allocated signals on exit */ if ((SIGURG = AllocSignal(-1)) == -1) - fprintf(stderr, "allocSignal failed."n"); exit(1); " System Manual AmiTCP/IP Section 3.4 55 /* Set socket signals for this task */ SetSocketSignals(SIGBREAKF_CTRL_C, 1 << SIGIO, 1 << SIGURG); /* Set the process receiving SIGIO/SIGURG signals to us */ if (IoctlSocket(s, FIOSETOWN, &thisTask) < 0) - perror("IoctlSocket FIOSETOWN"); exit(1); " /* Allow receipt of asynchronous I/O signals */ if (IoctlSocket(s, FIOASYNC, &yes) < 0) - perror("IoctlSocket FIOASYNC"); exit(1); " 3.4.4 Selecting Specific Protocols If the third argument to the socket() call is 0, socket will select a default protocol to use with the returned socket of the type requested. The default protocol is usually correct,and alternate choices are not usually available. However, when using ``raw'' socketsto communicate directly with lower-level protocols or hardware interfaces, the protocol argument may be important for setting updemultiplexing. For example, raw sockets in the Internet family may be used to implement a new protocol above IP, and the socket will receive packets only for the protocol specified. To obtain a particular protocol one determines the protocol number as defined within the communication domain. For the Internet domain one may use one of the library routines discussed in section 3.2, such as getprotobyname(): #include #include #include #include ... pp = getprotobyname("newtcp"); s = socket(AF_INET, SOCK_STREAM, pp->p_proto); This would result in a socket s using astream based connection, but with protocol type of ``newtcp'' instead of the default ``tcp.'' 3.4.5 Address Binding As was mentioned in section 3.1, bindingaddresses to sockets in the Internet 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 allocated out of separate spaces, one for each system and one for each domainon that system. Through the bind() call, a process may specify halfof an association, the part, while the connect() and accept() calls are 56 Section 3.4 AmiTCP/IP System Manual used to complete a socket's associationby specifying the part. Since the association iscreated in two steps the association uniqueness requirement indicated previously could be violated unless care is taken. Further, it is unrealistic to expect user programs to always know proper values touse for the local address and local port since a host may reside on multiplenetworks and the set of allocated port numbers is not directly accessibleto a user. To simplify local address binding in the Internet domain the notion of a ``wildcard'' address has been provided. When an address is specified as INADDR_ANY (a manifest constant defined in file netinet/in.h), the system interprets the address as ``any valid address''. For example, to bind a specific port number to a socket,but leave the local address unspecified, the following code might beused: #include #include ... struct sockaddr_in sin; ... s = socket(AF_INET, SOCK_STREAM, 0); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(MYPORT); bzero(sin.sin_zero, sizeof(sin.sin_zero)); bind(s, (struct sockaddr *) &sin, sizeof (sin)); Sockets with wildcarded local addressesmay receive messages directed to the specified port number, and sent to any of the possible addresses assigned to a host. For example, if a host has addresses 128.32.0.4 and 10.0.0.78, and a socket is bound as above, the process will be able to accept connection requests which are addressed to 128.32.0.4 or 10.0.0.78. If a server process wished to only allow hosts on a given network connect to it, it would bind theaddress of the host on the appropriate network. In a similar fashion, a local port may be left unspecified (specified as zero), in which case the system willselect an appropriate port number for it. For example, to bind a specific local addressto a socket, but to leave the local port number unspecified: hp = gethostbyname(hostname); if (hp == NULL) - ... " bzero(&sin, sizeof(sin)); bcopy(hp->h_addr, (char *) sin.sin_addr, hp->h_length); sin.sin_port = htons(0); bind(s, (struct sockaddr *) &sin, sizeof (sin)); The system selects the local port numberbased on two criteria. The first is that on 4BSD systems, Internetports below IPPORT_RESERVED (1024) are reserved for privileged processes13 ; Internet ports above ________________________________ 13All processes in AmigaOS are considered as privileged. System Manual AmiTCP/IP Section 3.4 57 IPPORT_USERRESERVED (5000) are reserved for non-privileged servers. The second is that the port number is not currently bound to some other socket. In order to find a free Internet port number in the privileged range the rresvport() library routine may be used as follows to return a stream socket in with a privileged portnumber: int lport = IPPORT_RESERVED - 1; int s; s = rresvport(&lport); if (s < 0) - if (errno== EAGAIN) fprintf(stderr, "socket: all ports in use"n"); else perror("rresvport: socket"); ... " The restriction on allocating ports wasdone to allow processes executing in a secure environment to perform authentication based on the originating address and port number. For example, therlogin command allows users to log in across a networkwithout 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 AmiTCP:db/hosts.equiv14 on the system he is logging into (or the system name and the user name are in the user's .rhosts file in the user's home directory), and second, that the user's rlogin process is coming from a privileged port on the machine from which he is logging. The port number and networkaddress of the machine from which the user is logging in can be determined either by the from result of the accept() call, or from thegetpeername() call. In certain cases the algorithm used by the system in selecting port numbers is unsuitable for an application. This is because associations are created in a two step process. For example, the Internet file transfer protocol, FTP, specifies that data connections must always originate from the same local port. However, duplicateassociations are avoided by connecting to different foreign ports. Inthis situation the system would disallow binding the same local address and port number to a socket if a previous data connection's socket still existed. To override the default port selection algorithm, anoption call must be performed prior to address binding: ... long on = 1; ... setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); bind(s, (struct sockaddr *) &sin, sizeof (sin)); With the above call, local addresses maybe bound which are already in use. This does not violate the uniqueness requirementas the system still checks at connect time to be sureany other sockets with the same local address and port do not have the same foreign address and port. If the association already exists, the error EADDRINUSE is returned. ________________________________ 14In UNIX /etc/hosts.equiv 58 Section 3.4 AmiTCP/IP System Manual 3.4.6 Broadcasting And Determining Network Configuration By using a datagram socket, it is possible to send broadcast packets on many networks supported by the system. The network itself must support broadcast; the system provides no simulation of broadcast in software. Broadcast messages can place a high loadon a network since they force every host on the network to service them. Consequently, the ability to send broadcast packets has been limitedto sockets which are explicitly marked as allowing broadcasting. Broadcast is typically used for one of two reasons: it is desired to find a resource on a local network without prior knowledge of its address, or important functions such as routing require that information be sent to allaccessible neighbors. To send abroadcast message, a datagram socket should be created: s = socket(AF_INET, SOCK_DGRAM, 0); The socket is marked as allowing broadcasting, long on = 1; setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)); and at least a port number should be bound to the socket: sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(MYPORT); bzero(sin.sin_zero, sizeof(sin.sin_zero)); bind(s, (struct sockaddr *) &sin, sizeof (sin)); The destination address of the message to be broadcast depends on the network(s) on which the message is to bebroadcast. The Internet domain supports a shorthand notation for broadcast on the local network, the address INADDR_BROADCAST (defined in netinet/in.h). To determine the list of addresses for all reachable neighbors requires knowledge of the networks to which the host is connected. Since this information should be obtained in a host independent fashion and may be impossible to derive, 4.3BSD provides a method of retrieving this information from the system data structures. The SIOCGIFCONF IoctlSocket()call returns the interface configuration of a host in theform of a single ifconf structure; this structure contains a ``data area'' which is made up of an array of of ifreq structures, one for each network interface to which the host is connected. These structures are defined in net/if.h asfollows: 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 64 System Manual AmiTCP/IP Section 3.4 59 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; "; #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 */ The actual call which obtains the interface configuration is struct ifconf ifc; char buf[BUFSIZ]; ifc.ifc_len = sizeof (buf); ifc.ifc_buf = buf; if (IoctlSocket(s, SIOCGIFCONF, (char *) &ifc) < 0) - ... " After this call buf will contain one ifreq structure for each network to which the host is connected, and ifc.ifc_len will have been modified to reflect the number of bytes used by theifreq structures. For eachstructure 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 IoctlSocket() retrieves these flags for an interface specified by an ifreq structure as follows: 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 anaddress family other than those intended; * if we were interested in NS interfaces, the * AF_INET wouldbe AF_NS. */ if (ifr->ifr_addr.sa_family != AF_INET) continue; if (IoctlSocket(s, SIOCGIFFLAGS, (char *) ifr) < 0) - ... " /* 60 Section 3.4 AmiTCP/IP System Manual * Skip boring cases. */ if ((ifr->ifr_flags & IFF_UP) == 0 __ (ifr->ifr_flags & IFF_LOOPBACK) __ (ifr->ifr_flags & (IFF_BROADCAST_ IFF_POINTTOPOINT)) == 0) continue; Once the flags have been obtained, the broadcast address must be obtained. In the case of broadcast networks this is done via the SIOCGIFBRDADDR IoctlSocket(), while forpoint-to-point networks the address of the destination host is obtained with SIOCGIFDSTADDR. struct sockaddr dst; if (ifr->ifr_flags & IFF_POINTTOPOINT) - if (IoctlSocket(s, SIOCGIFDSTADDR, (char *) ifr) < 0) - ... " bcopy((char *) ifr->ifr_dstaddr, (char *) &dst, sizeof (ifr->ifr_dstaddr)); " else if (ifr->ifr_flags & IFF_BROADCAST) - if (IoctlSocket(s, SIOCGIFBRDADDR, (char *) ifr) < 0) - ... " bcopy((char *) ifr->ifr_broadaddr, (char *) &dst, sizeof (ifr->ifr_broadaddr)); " After the appropriate ioctl's have obtained the broadcast or destination address (now in dst), the sendto() callmay be used: sendto(s,buf, buflen, 0, (struct sockaddr *)&dst, sizeof (dst)); " In the above loop one sendto() occurs for every interface to which the host is connected that supports the notion of broadcast or point-to-point addressing. If a process only wished to send broadcastmessages on a given network, code similar to that outlined above would be used, but the loop would need to find the correct destination address. Receivedbroadcast messages contain the senders address and port, as datagram sockets are bound before a message is allowed to go out. AmiTCP/IP specific extensions Extensions to interface ioctls The following ioctls are used to configure protocol and hardware specific properties of a sana_softc interface. They are used in the AmiTCP/IP only. SIOCSSANATAGS Set SANA-II specific properties with a tag list. SIOCGSANATAGS Get SANA-II specific properties into the wiretype_parameters structure and a user tag list. These ioctls use the following structure as a argument: System Manual AmiTCP/IP Section 3.4 61 struct wiretype_parameters - ULONG wiretype; /* the wiretype of the interface */ WORD flags; /* iff_flags */ struct TagItem *tags; /* tag list user provides */ "; SIOCGARPT Getthe contents of an ARP mapping cache into a struct arpreq table. This ioctl takes the following arptabreq structure as an argument: /* * An AmiTCP/IP specific ARP table ioctl request */ struct arptabreq - struct arpreq atr_arpreq; /* To identify theinterface */ long atr_size; /* # of elementsin atr_table */ long atr_inuse; /* # of elements in use */ struct arpreq *atr_table; "; The atr_arpreq specifies the used interface. The hardware address for the interface is returned in the arp_ha field of atr_arpreq structure. The SIOCGARPT ioctl reads at most atr_size entries from the cache into the user supplied buffer atr_table, if it is not NULL. Actual amount of returned entries is returned in atr_size. The current amount of cached mappings is returned in the atr_inuse. 3.4.7 Socket Options It is possible to set and get a number of options on sockets via the setsockopt() and getsockopt() 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: setsockopt(s, level, optname, optval, optlen); and getsockopt(s, level, optname, optval, optlen); The parameters to the calls are as follows: s is the socket on which the option is to be applied. level 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 sys/socket.h. The actual option is specified in optname, and is a symbolic constant also defined in sys/socket.h. optval and optlen pointto 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 getsockopt(), optlen is a value--resultparameter, initially set to the 62 Section 3.4 AmiTCP/IP System Manual size of the storage area pointed to by optval, and modified upon return to indicate the actual amount of storageused. An example should help clarify things. It is sometimes useful to determine the type (e.g., stream, datagram, etc.) ofan existing socket; programs under inetd (described in section 3.4.8) may need to perform this task. This can be accomplished as follows via theSO _TYPE socket option and the getsockopt() call: #include #include long type, size; size = sizeof (type); if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &type, &size) < 0) - ... " After the getsockopt() call, type will be set to the value of the socket type, as defined in sys/socket.h. If, for example, thesocket were a datagram socket, type would have the value corresponding to SOCK_DGRAM. 3.4.8 Inetd One of the daemons provided with AmiTCP/IP is inetd, the so called ``internet super--server.'' Inetd is invoked at start-up time, and determines the servers, for which it isto listen, from the file AmiTCP:db/inetd.conf15. Once this information has been read and a pristine environment created, inetd proceeds to create one socket for each service it is to listen for, binding the appropriate port number to each socket. Inetd then performs a select() on all these sockets for read availability, waiting for somebody wishing a connection to the service corresponding to that socket. Inetd then performs an accept() on the socket in question, releases the socketwith a ReleaseSocket() call and starts the appropriate server. Servers making use of inetd are considerably simplified, as inetd takes care of the majority of the work required in establishing a connection. The server invoked by inetd expects thesocket connected to its client to be found by calling ObtainSocket(). The client socketID for the server is found in a DaemonMessage structure given to the server process. Usually the netlib:autoinitd.o module takes care of obtaining the client socket into global variable server_socket. For practical purposes the code might assume this socket to be 0. One callwhich may be of interest to individuals writing servers under inetd is the getpeername() call, which returns the address of the peer (process) connected on the other end ofthe socket. For example, to log the Internet address in ``dot notation''(e.g., ``128.32.0.4'') of a ________________________________ 15In UNIX systems /etc/inetd.conf. System Manual AmiTCP/IP Section 3.5 63 client connected to a server under inetd, the following code might be used: 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)); ... While the getpeername() call is especially useful when writing programs to run with inetd, it can be used underother circumstances. Sources for a very simple TCP protocol server is included with AmiTCP/IP as an example. 3.5 Deviation From Berkeley Sockets This section discusses the differences between the API of the AmiTCP/IP and the 4.3BSD. They are not so numerousas it might seem to, but worth taking attention to when porting existing 4.3BSD software to AmiTCP/IP. 3.5.1 Opening and Closing the Shared Library Since the API is provided as a shared library, it must be opened to be able to access the functions it provides. Note that any two tasks may not share a socket library base, since the base contains task specific information. AmiTCP/IPdoes resource tracking based on the information stored in a library base, so it is essential that the library is closed after use, since the resources used by the base aregone if the application exits without closing the base. See section 3.1.2 for examples and more discussion on the subject. 3.5.2 Naming Conventions of the API Functions The API functions which preserve the semantics of the BSD calls are named the same as the original functions. In the name of binary compatibility between different C compilers the functions which either take a structure as an argument or return a structure asa value had to be changed not to do so. These functions are named differently; all words in these function names begin with an upper caseletter. Inlinefunctions16 are provided with the original semantics, however. This makes it possible to keep using the original functions when writing the code and still be binary compatible. The inline functions are mostly trivial; for example the select() call is actually an inlinewhich calls WaitSelect() with last argument as NULL. ________________________________ 16Or linker stubs in compilers with no inline functions. 64 Section 3.5 AmiTCP/IP System Manual This is amatter which should be totally invisible for C users, but assembler programmers should take attention and be sure to pass arguments as described in the function reference for the non-inline versions. 3.5.3 errno Unix libraries return error values in aglobal variable named errno. Since a shared library cannot know the address of any variables of an application, the address of the errno must be explicitly told to the AmiTCP/IP. An alternative is to use Errno() call to fetch the error value, but since the first method needsno modifications to the existing sources (besides calling SetErrnoPtr() once in the beginning), it is the preferred method. Section 3.1.2 contains examples andmore discussion about the matter. 3.5.4 NewField in the sockaddr Structures Since AmiTCP/IP is based on the BSD Net/2 release, it has few differences to the 4.3BSD. Most notableone is that the sockaddr and sockaddr_in structureshave a new field telling the length of the structure. These are named as sa_len and sin_len respectively. These fields are used by the AmiTCP/IP to determine the real length of the address given. In addition the sockaddr_in structure has a field named sin_zero, which should be initialized to zero before passed to the AmiTCP/IP, since any garbage left there will be used by the routing facility (which obviously leads to undesired behaviour). 3.5.5 Linger Time The unit of the linger time of a socketis a second. The Net/2 code seemed to use ticks17. 3.5.6 Transferring Sockets from a Task to Another Since AmigaOS has no fork() call, in which the child process inherits the file descriptors, and hence sockets, a mechanism for transferring sockets from a task to another must be provided. This is accomplished by the calls ReleaseSocket(), ReleaseCopyOfSocket() and ObtainSocket(), which release a socket, a copy of a socket andobtain a released socket, respectively. An id is given to a socket placed in thelist of released sockets. This id can be either unique or be based on aservice number in cases where it is irrelevant which instance of the server process for the service in question obtains the socket. If an unique id is used, the releasing task is responsible of transferring the id to the obtaining task. ________________________________ 17One tick is 1/hz:th of a second, where hz is the frequency of the electricity of the wall socket. System Manual AmiTCP/IP Section 3.5 65 This feature affects the server processes only, since the clients usually create the socket(s) on their own. 3.5.7 Ioctl Differences The Unix ioctl() function is renamed asIoctlSocket() in AmiTCP/IP to avoid name clashes with some C runtime libraries. Followingsummarizes other differences in the ioctl calls: 1. FIOCLEX and FIONCLEX are silently ignored, that is, they are accepted, but have no effect. Whether sockets should be closed on exec() or not is irrelevant, since AmigaOS has no such feature (see discussion about fork() above). 2. FIOSETOWN and SIOCSPGRP take a pointer to a struct Task * as an argument instead of a pointer to a process (or group) id. Note that if the task in question has not opened the bsdsocket.library the owner of the precess is set to NULL (disabled). The task pointer is used as the receiver of the asynchronous notification signals if asynchronous notification is enabled. 3. FIOGETOWN and SIOCGPGRP take a pointer to a struct Task * as an argument in which the current task pointer of the owner of the socket in question is placed on return. 3.5.8 Signal Handling There is a fundamental difference between BSD Unix and Amiga signal handling and the system call interface. In the Unix systems a received signal may interrupt a process executinga system call. If there is a signal handler installed, it can be executed before the system call returns to the main execution branch with an error code. However,there are some system calls which may not be interrupted. If a Unix process has a negative priority,tsleep() does not wake up until the specified condition is met. The interrupted system call does not have any unrecoverable effects, the execution of the program may continue after the errno is checked against other errors than EINTR. In the AmigaOS, Exec, there are no specific system calls. All OS functions are provided by shared libraries. There areeither no separate kernel and user memory spaces, the one common memory space is shared by all processes. The IO system is based on messages, which are implemented as shared memory areas. When a program receives a message to a port, it is delivered a signal associated with the port. While itis possible to use signal handlers with Exec, they are even more dangerous to use and restricted than in Unix systems. This is not recommended, since the exception handlermust behave like any real interrupt handler. Calls provided by AmiTCP/IP are notcallable from interrupts. Further, it is not possible to interrupt asystem call implemented as a shared library function. The application must itself react on receipt of the signals. The recommended way of handling these signals is by the normal Wait() of by 66 Section 3.5 AmiTCP/IP System Manual AmiTCP/IP call WaitSelect(), which allows an application to specify a signal mask which should abort the selection. The application then checks the received signals and calls appropriate handler for the signal. 3.5.9 Asynchronous I/O AmigaOS does not have any reserved signals for networking, such as SIGIO or SIGURG in Unix systems, and so the scheme used in asynchronous notification must be changed a little. The application can set a group of signal masks, with function named SetSocketSignals(), to be used by the AmiTCP/IP. First argument specifies the signal mask which should break the blocking of the blocking socket calls. It is by default set to the signal for CTRL-C. Second argument specifies the signal(s) to be sent when asynchronous notification for readiness to read is necessary. Thismask lets the application define which signal should be used as replacement for SIGIO signal of the Unix systems. Third and last argument specifies the corresponding mask for the asynchronousnotification of urgent (out-of-band) data (SIGURG). These lasttwo masks are zero by default. Note thatthere is no way to query the current settings of these signals form the AmiTCP/IP, so the application must store the signal numbers (or masks) for later use. Also note that the break mask must be explicitly given if SetSocketSignals() is called, since the values supplied override the default settings. 3.5.10 Constructing an Event Loop Amiga programs are often constructed around an event loop, in which Wait() function is used to wait for somesubset of given signals to arrive. When a signal is received, some actions are taken and if IO is performed, it is usually asynchronous. Many Unixprograms use to do synchronous IO and let the signal handlers to handle special events (window size changes, timeouts, etc.). This can be emulated to some extent with AmigaOS,since it is possible to specify an exeption function to handle receptionof given signals. This is very limited, though, since the exeption codeis executed at true interrupt level, and may thus pre-empt the main process in an arbitrary location. Also note that a very limited set of shared library functions can be called while in interrupt, especially note that any AmiTCP/IP function may NOT be called from interrupt code. AmiTCP/IPoffers remedy for this, however. The application can use WaitSelect() to handle both Amiga signals and socket IO multiplexing. Selecting assures that the following socket calls will not block18. Another possiblility is to use signal driven socket IO (see section 3.4.3). Yet another possibility is to specify a special break mask with SetSocketSignals() function. The signals in the mask cause any blocking socket IO routine to return with the error code EINTR. Note that the ________________________________ 18See NOTES section of the reference for the WaitSelect(). System Manual AmiTCP/IP Section 3.5 67 signals are not cleared in this procedure. The Wait()with the same signal mask can be used to determine (and clear) the received signals. This allows the usage of synchronous socket IO, but the EINTR error code must be checked after each failing call. 3.5.11 ''Killing'' the Processes In AmigaOS the applications must co-operate with the OS for the user to be able to stop them. This is why the blocking operations of the AmiTCP/IP can be aborted. By default the reception ofCTRL-C signal aborts any blocking call. The call returns an error value (in errno) of EINTR when aborted. In addition the signal which caused the break will remain set for the application to be able to react on it in its normal event processing. This means that the application neednot specially check for EINTR after every socket callas long as they eventually check for the break signal. All sockets left open by the application are closed by the CloseLibrary() call. You may left the sockets open when aborting the program, because the socket library is closed automatically during the exit process if either autotermination function (specific to SAS C) or ANSI atexit() function is installed before the exit is done. . The signals which cause the abort can be set with the SetSocketSignals() call. The break signal mask is given as the first argument. Calling this function discards the previousvalues of the sockets signal masks. Aborting can be disabled by giving the mask as 0L. See section 3.5.9 for more discussion about the SetSocketSignals() call. 3.5.12 WaitSelect() In AmiTCP/IP no other than socket I/O can be multiplexed with the select() call. This may be a major pain as I/O is normally multiplexed with an Wait() loop, waiting for given signals to arrive. This is the motivation for the WaitSelect() call. It combines theselection and waiting in a single call19. The WaitSelect() takes one argument in addition to the normal select() call. It is a pointerto signal mask to wait for in addition to the signals thatthe AmiTCP/IP uses internally. If any of these signals is received, they are returned as a result in the same signal mask. Signals specified in the given signal mask override the signals of the break mask (see previous section). If the same signal is specified in both the SIGINTR mask and the mask given to the WaitSelect(), the reception of the signal causes it tobe cleared and returned in the mask as the result. WaitSelect() can be used as replacement for the Wait() in applications which require to multiplex both socket related and other Amiga I/O. ________________________________ 19This feature was really easy to implement, since AmiTCP/IP uses a Wait() to wait for I/O events itself. 68 Section 3.5 AmiTCP/IP System Manual Appendix B API Function Reference This appendix is a complete reference tothe functions and concepts provided by the AmiTCP/IP system. Table of Contents Standard BSD Style Socket Functions accept : : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : 130 bind : : : : : : : : : : : : : : : : : : : : : :: : : : : : : : : : : :* * : : : : : : : : : 132 CloseSocket : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : 133 connect : : : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : 134 Dup2Socket : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : 136 getpeername : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : 137 getsockname : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : 138 getsockopt : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : 139 IoctlSocket : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : 142 listen : : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : 144 recv : : : : : : : : : : : : : : : : : : : : : :: : : : : : : : : : : :* * : : : : : : : : : 145 recvfrom : : : : : : : : : : : : : : : : : : : : :: : : : : : : : : : :* * : : : : : : : : 145 select : : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : 147 send : : : : : : : : : : : : : : : : : : : : : :: : : : : : : : : : : :* * : : : : : : : : : 150 sendto : : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : 150 setsockopt : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : 139 shutdown : : : : : : : : : : : : : : : : : : : : :: : : : : : : : : : :* * : : : : : : : : 152 socket : : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : 153 WaitSelect : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : 147 Other BSD Functions Related to Sockets getdtablesize : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : 156 Syslog : : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : 157 Network Data and Address Manipulation inet_addr : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : : : : :: 159 Inet_LnaOf: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : : 159 inet_lnaof: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : : 159 128 System Manual AmiTCP/IP Section B.0 129 inet_MakeAddr : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : : : : :159 inet_makeaddr : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : : : : :159 Inet_NetOf: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : : 159 inet_netof: : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : : 159 inet_network : : : : : : : : : : : : : : : : : : : : : : :: : : : : : :* * : : : : : : : 159 Inet_NtoA : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : : : : :: 159 inet_ntoa : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : : : : :: 159 Network, Protocol and Service Queries gethostbyaddr : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : 162 gethostbyname : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : 162 getnetbyaddr : : : : : : : : : : : : : : : : : : :: : : : : : : : : : :* * : : : : : : : 164 getnetbyname : : : : : : : : : : : : : : : : : : :: : : : : : : : : : :* * : : : : : : : 164 getprotobyname : : : : : : :: : : : : : : : : : : : : : : : : : : : : * *: : : : : : : 166 getprotobynumber : : : : : : : : : : : : : : : : : :: : : : : : : : : :* * : : : : : : 166 getservbyname : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : 167 getservbyport : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : 167 AmiTCP/IP Specific Extensions Errno : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : :: : : : : : 169 ObtainSocket : : : : : : : : : : : : : : : : : : :: : : : : : : : : : :* * : : : : : : : 170 ReleaseCopyOfSocket : :: : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : 171 ReleaseSocket : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : 172 SetDTableSize : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : 173 SetErrnoPtr : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : 174 SetSocketSignals : : : : : : : : : : : : : : : : : :: : : : : : : : : :* * : : : : : : 175 130 Section B.1 AmiTCP/IP System Manual B.1 Standard BSD Style Socket Functions B.1.1 accept() NAME accept -accept a connection on a socket SYNOPSIS #include #include ns = accept(s, addr, addrlen) D0 D0 A0 A1 long accept(long, struct sockaddr *, long *); FUNCTION The argument s is a socket that has been created with socket(),bound to an address with bind(), and is listen- ing for connections after a listen(). accept() extracts the first connection on the queue of pending connections, creates anew socket with the same properties of s and allo- cates a new socket descriptor for the socket. If no pending connections are present on the queue, and the socket is not marked as non-blocking, accept() blocks the caller until a connection is present. If the socket is marked non-blocking and no pending connections are present on the queue, accept()returns an error as described below. The accepted socket isused to read and write data to and from the socket which connected to this one; it is not used to accept more connections. The original socket s remains open for accept- ing further connections. The argument addr is a result parameter that is filled in with the address of the connecting entity, as known to the communications layer. The exact format of the addr parame- ter is determined by the domain in which the communication is occurring. The addrlen is a value-result parameter; it should initially contain the amount of space pointed to by addr; onreturn it will contain the actual length (in bytes) of the address returned. This call is used with connection-based socket types, currently with SOCK_STREAM. It is possible to select() a socket for the purposes of doing anaccept() by selecting it for read. RETURN VALUES accept()returns a non-negative descriptor for the accepted socket onsuccess. Onfailure, it returns -1 and sets errno to indicate the error. System Manual AmiTCP/IP Section B.1 131 ERRORS EBADF - The descriptoris invalid. EINTR - The operation was interrupted by a break signal. EOPNOTSUPP - The referencedsocket is not of type SOCK_STREAM. EWOULDBLOCK - The socket is marked non-blocking and no con- nections are present to be accepted. SEE ALSO bind(), connect(), listen(), select(), SetSocketSignals(), socket() 132 Section B.1 AmiTCP/IP System Manual B.1.2 bind() NAME bind - bind a name to a socket SYNOPSIS #include #include success =bind(s, name, namelen) D0 D0 A0 D1 long bind(long, struct sockaddr *, long); FUNCTION bind() assigns a name to an unnamed socket. When a socket is created with socket(2) it exists in a name space (address family) but has no name assigned. bind() requests that the name pointed to by name be assigned to the socket. RETURN VALUES 0 - on success. -1 - on failure and sets errno to indicate the error. ERRORS EACCES - The requested address is protected, and the current user has inadequate permis- sion to access it. EADDRINUSE - The specified address is already in use. EADDRNOTAVAIL - The specified address is not available from the local machine. EBADF -s is not a valid descriptor. EINVAL - namelen is not the size of a valid address for the specified address fam- ily. The socket is already bound to an address. SEE ALSO connect(), getsockname(), listen(), socket() NOTES The rulesused in name binding vary between communication domains. System Manual AmiTCP/IP Section B.1 133 B.1.3 CloseSocket() NAME CloseSocket - delete a socket descriptor SYNOPSIS success =CloseSocket(s) D0 D0 long CloseSocket(long); FUNCTION CloseSocket() deletes a descriptor from the library base socket reference table. Ifs is the last reference to the underlying object, then the object will be deactivated and socket (see socket()), associated naming information and queued data are discarded. All sockets are automatically closed when the socket library is closed, but closing sockets as soon as possible is recommended to save system resources. RETURN VALUES 0 on success. -1 on failure and sets errnoto indicate the error. ERRORS EBADF -s is not an active socket descriptor. EINTR -linger on close was interrupted. The socket is closed, however. SEE ALSO accept(),SetSocketSignals(), shutdown(), socket(), exec.library/CloseLibrary() 134 Section B.1 AmiTCP/IP System Manual B.1.4 connect() NAME connect -initiate a connection on a socket SYNOPSIS #include #include success =connect(s, name, namelen) D0 D0 A0 D1 long connect(long, struct sockaddr *, long); FUNCTION The parameter s is a socket. If it is of type SOCK_DGRAM, then this call specifies the peer with which the socket is to be associated; this address is that to which datagrams are to be sent, and the only address from which datagrams are to bereceived. Ifit is of type SOCK_STREAM, then this call attempts to make a connection to another socket. The other socket is specified by name which is an address in the communications space of the socket. Each communications space interprets the name parameter in its own way. Gen- erally, stream sockets may successfully connect() only once; datagramsockets may use connect() multiple times to change their association. Datagram sockets may dissolve the asso- ciation by connecting to an invalid address, such as a null address. RETURN VALUES 0 on success. -1 on failure and sets errnoto indicate the error. ERRORS EADDRINUSE - The address is already in use. EADDRNOTAVAIL - The specified address is not available on the remote machine. EAFNOSUPPORT - Addresses in the specified address fam- ily cannot be used with this socket. EALREADY - The socket is non-blocking and a previ- ous connection attempt has not yet been completed. EBADF -s is not a valid descriptor. ECONNREFUSED - The attempt to connect was forcefully System Manual AmiTCP/IP Section B.1 135 rejected. The calling program should CloseSocket() the socket descriptor, and issue another socket() call to obtain a new descriptor before attempting another connect() call. EINPROGRESS - The socket is non-blocking and the con- nection cannot be completed immediately. It is possible to select() for comple- tion by selecting the socket for writ- ing. EINTR -The operation was interrupted by a break signal. EINVAL - namelen is not the size of a valid address for the specified address fam- ily. EISCONN The socket is already connected. ENETUNREACH - The network is not reachable from this host. ETIMEDOUT - Connection establishment timed out without establishing a connection. SEE ALSO accept(),CloseSocket(), connect(), getsockname(), select(), socket() 136 Section B.1 AmiTCP/IP System Manual B.1.5 Dup2Socket() NAME Dup2Socket - duplicate a socket descriptor SYNOPSIS newfd = Dup2Socket(fd1, fd2) D0 D0 D1 long Dup2Socket(long, long); DESCRIPTION Dup2Socket() duplicates an existing socket descriptor. theargument fd1 is small non-negative value that indexes thesocket on SocketBase descriptor table. The value must beless than the size of the table, which is returned by getdtablesize(). fd2 specifies the desired value of the new descriptor. If descriptor fd2 is already in use, it is first deallocated as if it were closed by CloseSocket(). If thevalue if fd2 is -1, the new descriptor used and returned isthe lowest numbered descriptor that is not currently in useby the SocketBase. RETURN VALUES Dup2Socket() returns a new descriptor on success. On failure -1is returned and errno is set to indicate the error. ERRORS EBADF fd1 or fd2 is not a valid active descriptor. EMFILE Too many descriptors are active. SEE ALSO accept(), CloseSocket(), getdtablesize(), SetDtableSize(), socket() System Manual AmiTCP/IP Section B.1 137 B.1.6 getpeername() NAME getpeername - get name of connected peer SYNOPSIS success = getpeername(s, name, namelen) D0 D0 A0 A1 long getpeername(long, struct sockaddr *, long *); FUNCTION getpeername() returns the name of the peer connected to socket s. The long pointed to by the namelen parameter should be initialized to indicate the amount of space pointed to by name. On return it contains the actual size of the name returned (in bytes). The name is truncated if the buffer provided is too small. RETURN VALUE A 0 is returned if the call succeeds, -1 if it fails. ERRORS EBADF - The argument sis not a valid descriptor. ENOBUFS - Insufficient resources were available in the system to perform the operation. ENOTCONN - The socket is not connected. SEE ALSO accept(),bind(), getsockname(), socket() 138 Section B.1 AmiTCP/IP System Manual B.1.7 getsockname() NAME getsockname - get socket name SYNOPSIS success =getsockname(s, name, namelen) D0 D0 A0 A1 long getsockname(long, struct sockaddr *, long *); FUNCTION getsockname() returns the current name for the specified socket. The namelen parameter should be initialized to indicatethe amount of space pointed to by name. On return it contains the actual size of the name returned (in bytes). DIAGNOSTICS A 0 is returned if the call succeeds, -1 if it fails. ERRORS The callsucceeds unless: EBADF s is not a valid descriptor. ENOBUFS Insufficient resources were available in the system to perform the operation. SEE ALSO bind(), getpeername(), socket() System Manual AmiTCP/IP Section B.1 139 B.1.8 getsockopt() NAME getsockopt, setsockopt - get and set options on sockets SYNOPSIS #include #include success = getsockopt(s, level, optname, optval, optlen) D0 D0 D1 D2 A0 A1 long getsockopt(long, long, long, caddr_t, long *); success = setsockopt(s, level, optname, optval, optlen) D0 D0 D1 D2 A0 D3 long setsockopt(long, long, long, caddr_t, long); FUNCTION getsockopt() and setsockopt() manipulate options associated with a socket. Options may exist at multiple protocol lev- els; theyare always present at the uppermost ``socket'' level. When manipulating socket options the level at which the option resides and the name of the option must be specified. To manipulate options at the ``socket'' level, level is specifiedas SOL_SOCKET. To manipulate options at any other level theprotocol number of the appropriate protocol con- trolling the option is supplied. For example, to indicate that an option is to be interpreted by the TCP protocol, level should be set to the protocol number of TCP. The parameters optval and optlen are used to access option values for setsockopt(). For getsockopt() they identify a buffer inwhich the value for the requested option(s) are to be returned. For getsockopt(), optlen is a value-result parameter, initially containing the size of the buffer pointed to by optval, and modified on return to indicate the actual size of the value returned. If no option value is to be supplied or returned, optval may be supplied as 0. optname and any specified options are passed uninterpreted to the appropriate protocol module for interpretation. The include file contains definitions for ``socket'' level options, described below. Options at other protocol levels vary in format and name. Most socket-level options take an int parameter for optval. For setsockopt(), the parameter should be non-zero to enable 140 Section B.1 AmiTCP/IP System Manual a booleanoption, or zero if the option is to be disabled. SO_LINGER uses a struct linger parameter, defined in , which specifies the desired state of the option and the linger interval (see below). The following options are recognized at the socket level. Except as noted, eachmay be examined with getsockopt() and set withsetsockopt(). SO_DEBUG - toggle recording of debugging information SO_REUSEADDR - toggle local address reuse SO_KEEPALIVE - toggle keep connections alive SO_DONTROUTE - toggle routing bypass for outgoing messages SO_LINGER - linger on close if data present SO_BROADCAST - toggle permission to transmit broadcast messages SO_OOBINLINE - toggle reception of out-of-band data in band SO_SNDBUF - set buffer size for output SO_RCVBUF - set buffer size for input SO_TYPE - get the type of the socket (get only) SO_ERROR - get and clear error on the socket (get only) SO_DEBUG enables debugging in the underlying protocol modules. SO_REUSEADDR indicates that the rules used in validating addresses supplied in a bind() call should allow reuse oflocal addresses. SO_KEEPALIVE enables the periodic transmission of messages on a connected socket. Should the connected party fail to respond to these messages, the con- nection is considered broken. If the process is waiting in select() when the connection is broken, select() returns true for any read or write events selected for the socket. SO_DONTROUTE indicates that outgoing messages should bypass the standard routing facilities. Instead, messages are directed to the appropriate network interface accordingto the network portion of the destination address. SO_LINGERcontrols the action taken when unsent messags are queued on socket and a CloseSocket() is performed. If the socket promises reliable delivery of data and SO_LINGER is set, the system will block the process on the close attempt until it is able to transmit the data or until it decides it is unable to deliver the information (a timeout period, in seconds, termed the linger interval, is specified in the set- sockopt() call when SO_LINGER is requested). If SO_LINGER is disabled and a CloseSocket() is issued, the System Manual AmiTCP/IP Section B.1 141 system will process the close in a manner that allows the process to continue as quickly as possible. The option SO_BROADCAST requests permission to send broad- cast datagrams on the socket. Broadcast was a privileged operationin earlier versions of the system. With protocols that support out-of-band data, the SO_OOBINLINE option requeststhat out-of-band data be placed in the normal data input queue as received; it will then be accessible with recv() orread() calls without the MSG_OOB flag. SO_SNDBUF and SO_RCVBUF are options to adjust the normal buffer sizes allocatedfor output and input buffers, respectively. The buffer size may be increased for high-volume connections, or may be decreased to limit the possible backlog of incoming data. The system places an absolute limit on these values. Finally,SO_TYPE and SO_ERROR are options used only with getsockopt(). SO_TYPE returns the type of the socket, such as SOCK_STREAM; it is useful for servers that inherit sock- ets on startup. SO_ERROR returns any pending error on the socket and clears the error status. It may be used to check for asynchronous errors on connected datagram sockets or for other asynchronous errors. RETURN VALUES 0 - on success. -1 - on failure and set errno to indicate the error. ERRORS EBADF -s is not a valid descriptor. ENOPROTOOPT - The option is unknown at the level indi- cated. SEE ALSO IoctlSocket(), socket() BUGS Several of the socket options should be handled at lower levels ofthe system. 142 Section B.1 AmiTCP/IP System Manual B.1.9 IoctlSocket() NAME IoctlSocket - control sockets SYNOPSIS #include #include value = IoctlSocket(fd, request, arg) D0 D0 D1 A0 long IoctlSocket(long, long, caddr_t); FUNCTION IoctlSocket() performs a special function on the object referred to by theopen socketdescriptor fd. Note: the setsockopt() call (seegetsockopt()) is the primary method for operating on sockets as such, rather than on the underlying protocol or network interface. For mostIoctlSocket() functions, arg is a pointer to data to be used by the function or to be filled in by the function. Other functions may ignore arg or may treat it directly as a data item; they may, for example, be passed an int value. The following requests are supported: FIOASYNC The argument is a pointer to a long. Set or clear asynchronous I/O. If the value of that long is a 1 (one) the descriptor is set for asynchronous I/O. If the value of that long is a 0 (zero) the descriptor is cleared for asynchro- nous I/O. FIOCLEX FIONCLEX Ignored, no use for close-on-exec flag in Amiga. FIOGETOWN SIOCGPGRP The argument is pointer to struct Task*. Set the value of that pointer to the Task that is receiving SIGIO or SIGURG signals for the socket referred to by the descriptor passed to IoctlSocket(). FIONBIO The argument is a pointer to a long. Set or clear non-blocking I/O. If the System Manual AmiTCP/IP Section B.1 143 value of that long is a 1 (one) the descriptor is set for non-blocking I/O. If the value of that long is a 0 (zero) the descriptor is cleared for non- blocking I/O. FIONREAD The argument is a pointer to a long. Set the value of that long to the number of immediately readable characters from the socket fd. FIOSETOWN SIOCSPGRP The argument is pointer to struct Task*, pointer to the task that will subseq- uently receive SIGIO or SIGURG signals for the socket referred to by the descriptor passed. SIOCCATMARK The argument is a pointer to a long. Set the value of that long to 1 if the read pointer for the socket referred to by the descriptor passed to IoctlSocket() points to a mark in the data stream for an out-of-band message, and to 0 if it does not point to a mark. RETURN VALUES IoctlSocket() returns 0 on success for most requests. Some specialized requests may return non-zero values on success; On failure, IoctlSocket()returns -1 and sets errno to indicate the error. ERRORS EBADF fd is not a valid descriptor. EINVAL request or arg is not valid. IoctlSocket() will also fail if the object on which the function is being performed detects an error. In this case, an error code specific to the object and the function will be returned. SEE ALSO getsockopt(), SetSocketSignals(), setsockopt() 144 Section B.1 AmiTCP/IP System Manual B.1.10 listen() NAME listen -listen for connections on a socket SYNOPSIS success =listen(s, backlog) D0 D0 D1 long listen(long, long); FUNCTION To accept connections, a socket is first created with socket(), a backlog for incoming connections is specified with listen() and then the connections are accepted with accept(). The listen() call applies only to socket of type SOCK_STREAM. The backlog parameter defines the maximum length the queue of pending connections may grow to. If a connection request arrives with the queue full the client will receive an error with an indication of ECONNREFUSED. RETURN VALUES 0 on success. -1 on failure and sets errno to indicate the error. ERRORS EBADF -s is not a valid descriptor. EOPNOTSUPP - The socketis not of a type that sup- ports listen(). SEE ALSO accept(),connect(), socket() BUGS The backlog is currently limited (silently) to 5. System Manual AmiTCP/IP Section B.1 145 B.1.11 recv() NAME recv, recvfrom, - receive a message from a socket SYNOPSIS #include #include nbytes = recv(s, buf, len, flags) D0 D0 A0 D1 D2 long recv(long, char *, long, long); nbytes = recvfrom(s, buf, len, flags, from, fromlen) D0 D0 A0 D1 D2 A1 A2 long recvfrom(long, char *, long, long, struct sockaddr *, long *); FUNCTION s is a socket created with socket(). recv() and recvfrom(), are used to receive messages from another socket. recv() may be used only on a connected socket (see connect()), while recvfrom() may be used to receive data on a socket whether it is in a connected state or not. If from is not a NULL pointer, the source address of the message is filled in. fromlen is a value-result parameter, initialized to the size of the buffer associated with from, and modified on return to indicate the actual size of the address stored there. The length of the message is returned. If a message is too long to fitin the supplied buffer, excess bytes may be discarded depending on the type of socketthe message is received from (see socket()). If no messages are available at the socket, the receive call waits for a message to arrive, unless the socket is non- blocking(see IoctlSocket()) in which case -1 is returned with theexternal variable errno set to EWOULDBLOCK. The select() call may be used to determine when more data arrive. The flagsparameter is formed by ORing one or more of the following: MSG_OOB - Read any "out-of-band" data present on the socket, rather than the regular "in-band" data. 146 Section B.1 AmiTCP/IP System Manual MSG_PEEK - "Peek" at the data present onthe socket; the data are returned, but not consumed, so that a subsequent receive operation will see the same data. RETURN VALUES These calls return the number of bytes received, or -1 if an error occurred. ERRORS EBADF -s is an invalid descriptor. EINTR -The operation was interrupted by a break signal. EWOULDBLOCK - The socket is marked non-blocking and the requested operation would block. SEE ALSO connect(), getsockopt(), IoctlSocket(), select(), send(), SetSocketSignals(), socket() System Manual AmiTCP/IP Section B.1 147 B.1.12 select() NAME select --synchronous I/O multiplexing (stub/inline function) WaitSelect -- select() with Amiga Wait() function. SYNOPSIS #include #include n = select (nfds, readfds, writefds, exceptfds, timeout) long select(long, fd_set *, fd_set *, fd_set *, struct timeval *); n = WaitSelect (nfds, readfds, writefds, exceptfds, timeout, D0 D0 A0 A1 A2 A3 sigmp) D1 long WaitSelect(long, fd_set *, fd_set *, fd_set *, struct timeval *, long *); FD_SET (fd, &fdset) FD_CLR (fd, &fdset) FD_ISSET(fd, &fdset) FD_ZERO (&fdset) long fd; fd_set fdset; DESCRIPTION select()examines the socket descriptor sets whose addresses are passed in readfds, writefds, and exceptfds to see if some of their descriptors are ready for reading, ready for writing, or have an exceptional condition pending. nfds is the number of bits to be checked in each bit mask that representa file descriptor; the descriptors from 0 through (nfds - 1) in the descriptor sets are examined. On return, select() replaces the given descriptor sets with subsets consisting of those descriptors that are ready for the requestedoperation. The total number of ready descriptors in all the sets is returned. WaitSelect() also takes a signal mask which is waited during normal select() operation. If one of these singals is recei- ved, WaitSelect() returns and has re-set the signal mask to returnthose signals that have arrived. Normal select() return values are returned. The descriptor sets are stored as bit fields in arrays of integers. The following macros are provided for manipulat- 148 Section B.1 AmiTCP/IP System Manual ing suchdescriptor sets: FD_ZERO (&fdset) initializes a descriptor set fdset to the null set. FD_SET(fd, &fdset ) includesa particular descriptor fd in fdset. FD_CLR(fd, &fdset) removes fd from fdset. FD_ISSET(fd, &fdset) is nonzero if fd is a member of fdset, zero otherwise. The behavior of these macros is undefined if a descriptor value is less than zero or greater than or equal to FD_SETSIZE, which is normally at least equal to the maximum number of descriptors supported by the system. If timeout is not a NULL pointer, it specifies a maximum interval to wait for the selection to complete. If timeout is a NULL pointer, the select blocks indefinitely. To effect a poll, the timeout argument should be a non-NULL pointer,pointing to a zero-valued timeval structure. Any of readfds, writefds, and exceptfds may be given as NULL pointersif no descriptors are of interest. Selectingtrue for reading on a socket descriptor upon which a listen() call has been performed indicates that a subse- quent accept() call on that descriptor will not block. RETURN VALUES select()returns a non-negative value on success. A positive value indicates the number of ready descriptors in the descriptor sets. 0 indicates that the time limit referred to by timeout expired or that the operation was interrupted either bya break signal or by arrival of a signal specified in *sigmp. On failure, select() returns -1, sets errno to indicatethe error, and the descriptor sets are not changed. ERRORS EBADF - One of the descriptor sets specified an invalid descriptor. EINTR - one of the signals in SIGINTR mask (see Set- SocketSignals()) is set and it was not requested in WaitSelect() call. EINVAL - A component of the pointed-to time limit is outside the acceptable range: t_sec must be between 0 and 10^8,inclusive. t_usec must be greater than or equal to 0, and less than 10^6. SEE ALSO accept(), connect(), getdtablesize(), listen(), recv(), send(), SetDTableSize(), SetSocketSignals() NOTES System Manual AmiTCP/IP Section B.1 149 Under rare circumstances, select() may indicate that a descriptor is ready for writing when in fact an attempt to write would block. This can happen if system resources necessary for a write are exhausted or otherwise unavail- able. Ifan application deems it critical that writes to a file descriptor not block, it should set the descriptor for non-blocking I/O using the FIOASYNC request to IoctlSocket(). Default system limit for open socket descriptors is currently 64. However, in order to accommodate programs which might potentially use a larger number of open files with select, it is possible to increase this size within a program by providing a larger definition of FD_SETSIZE before the inclusion of and use SetDTableSize(FD_SETSIZE) call directly after OpenLibrary(). BUGS select()should probably return the time remaining from the original timeout, if any, by modifying the time value in place. This may be implemented in future versions of the system. Thus, it is unwise to assume that the timeout pointer will be unmodified by the select() call. 150 Section B.1 AmiTCP/IP System Manual B.1.13 send() NAME send, sendto - send a message from a socket SYNOPSIS #include #include nbytes =send(s, msg, len, flags) D0 D0 A0 D1 D2 int send(int, char *, int, int); nbytes =sendto(s, msg, len, flags, to, tolen) D0 D0 A0 D1 D2 A1 D3 int send(int, char *, int, int, struct sockaddr *, int); FUNCTION s is a socket created with socket(). send() and sendto() are used totransmit a message to another socket. send() may be used only when the socket is in a connected state, while sendto()may be used at any time. The address of the target is given by to with tolen specify- ing its size. The length of the message is given by len. If the message is too long to pass atomically through the underlying protocol, then the error EMSGSIZE is returned, and the message is not transmitted. No indication of failure to deliver is implicit in a send(). Return values of -1 indicate some locally detected errors. If no buffer space is available at the socket to hold the message to be transmitted, then send() normally blocks, unless the socket has been placed in non-blocking I/O mode. The select() call may be used to determine when it is pos- sible tosend more data. The flagsparameter is formed by ORing one or more of the following: MSG_OOB - Send ``out-of-band'' data on sockets that support this notion. The underly- ing protocol must also support ``out- of-band'' data. Currently, only SOCK_STREAM sockets created in the AF_INET address family support out-of- band data. System Manual AmiTCP/IP Section B.1 151 MSG_DONTROUTE - The SO_DONTROUTE optionis turned on for the duration of the operation. This is usually used only by diagnostic or rout- ing programs. RETURN VALUES On success, these functions return the number of bytes sent. On failure, they return -1 and set errno to indicate the error. ERRORS EBADF -s is an invalid descriptor. EINTR -The operation was interrupted by a break signal. EINVAL - len is not the size of a valid address for the specified address family. EMSGSIZE - The socket requires that message be sent atomically, and the size of the message to be sent made this impossible. ENOBUFS - The system was unable to allocate an internal buffer. The operation may succeed when buffers become available. ENOBUFS - The output queue for a network interface was full. This generally indicates that the interface has stopped sending, but may be caused by transient congestion. EWOULDBLOCK - The socket is marked non-blocking and the requested operation would block. SEE ALSO connect(), getsockopt(), recv(), select(), socket() 152 Section B.1 AmiTCP/IP System Manual B.1.14 shutdown() NAME shutdown- shut down part of a full-duplex connection SYNOPSIS success =shutdown(s, how) D0 D0 D1 long shutdown(long, long); DESCRIPTION The shutdown() call causes all or part of a full-duplex con- nection on the socket associated with s to be shut down. If how is 0,then further receives will be disallowed. If how is 1, then further sends will be disallowed. If how is 2, then further sends and receives will be disallowed. RETURN VALUES 0 - on success. -1 - on failure and sets errno to indicate the error. ERRORS EBADF - s is not a valid descriptor. ENOTCONN - The specified socket is not connected. SEE ALSO connect(), socket() BUGS The how values should be defined constants. System Manual AmiTCP/IP Section B.1 153 B.1.15 socket() NAME socket -create an endpoint for communication SYNOPSIS #include #include s = socket(domain, type, protocol) D0 D0 D1 D2 long socket(long, long, long); FUNCTION socket()creates an endpoint for communication and returns a descriptor. The domain parameter specifies a communications domain within which communication will take place; this selects the protocol family which should be used. The protocol family generally is the same as the address family for the addressessupplied in later operations on the socket. These families are defined in the include file . The currently understood formats are PF_INET - (ARPA Internet protocols) The socket has the indicated type, which specifies the semanticsof communication. Currently defined types are: SOCK_STREAM SOCK_DGRAM SOCK_RAW A SOCK_STREAM type provides sequenced, reliable, two-way connection based byte streams. An out-of-band data transmission mechanism may be supported. A SOCK_DGRAM socket supports datagrams (connectionless, unreliable mes- sages of a fixed (typically small) maximum length). SOCK_RAW sockets provide access to internal network interfaces. The protocol specifies a particular protocol to be used with the socket. Normally only a single protocol exists to sup- port a particular socket type within a given protocol fam- ily. However, it is possible that many protocols may exist, in whichcase a particular protocol must be specified in this manner. The protocol number to use is particular to the "communication domain" in which communication is to take place. 154 Section B.1 AmiTCP/IP System Manual Sockets of type SOCK_STREAM are full-duplex byte streams, similar to pipes. A streamsocket must be in a connected state before any data may be sent or received on it. A con- nection to another socket is created with a connect() call. Once connected, data may be transferred using send() and recv() or their variant calls. When a session has been completeda CloseSocket() may be performed. Out-of-band data mayalso be transmitted as described in send() and receivedas described in recv(). The communications protocols used to implement a SOCK_STREAM insure that data is not lost or duplicated. If a piece of data for which the peer protocol has buffer space cannot be successfully transmitted within a reasonable length of time, then the connection is considered broken and calls will indicatean error with -1 returns and with ETIMEDOUT as the specificerror code (see Errno()). The protocols optionally keep sockets "warm" by forcing transmissions roughly every minute inthe absence of other activity. SOCK_DGRAM and SOCK_RAW sockets allow sending of datagrams to correspondents named in send() calls. Datagrams are generally received with recv(), which returns the next datagramwith its return address. The operation of sockets is controlled by socket level options. These options aredefined in the file socket.h. getsockopt() and setsockopt() are used to get and set options, respectively. RETURN VALUES socket()returns a non-negative descriptor on success. On failure,it returns -1 and sets errno to indicate the error. ERRORS EACCES - Permission to create a socket of the specified type and/or protocol is denied. EMFILE - The per-process descriptor table is full. ENOBUFS - Insufficient buffer space is available. The socket cannot be created until suf- ficient resources are freed. EPROTONOSUPPORT - The protocol type or the specified pro- tocol is not supported within this domain. System Manual AmiTCP/IP Section B.1 155 EPROTOTYPE - The protocol is the wrong type for the socket. SEE ALSO accept(),bind(), CloseSocket(), connect(), getsockname(), getsockopt(), IoctlSocket(), listen(), recv(), select(), send(), shutdown(), WaitSelect() 156 Section B.2 AmiTCP/IP System Manual B.2 Other BSD Functions Related to Sockets B.2.1 getdtablesize() NAME getdtablesize - get socket descriptor table size SYNOPSIS nfds = getdtablesize() D0 long getdtablesize(void); FUNCTION Return value of maximum number of open socket descriptors. Larger socket descriptor table can be allocated with SetDTableSize() call. SEE ALSO SetDTableSize() System Manual AmiTCP/IP Section B.2 157 B.2.2 Syslog() NAME syslog -write message to AmiTCP/IP log. SYNOPSIS #include void syslog(unsigned long level, char * format, ...); Syslog(level, format, ap) D0 A0 A1 VOID Syslog(unsigned long, const char *, va_list); FUNCTION Writes the message given as format string and arguments (printf-style) both to the log file and to the console, execpt ifthe level is LOG_EMERG, which is used by panic(), in whichcase only the log file is used since panic() generatesa User Request. The levelis selected from an ordered list: LOG_EMERG A panic condition. LOG_ALERT A condition thatshould be corrected immediately, such as a corrupted system database. LOG_CRIT Critical conditions, such as hard device errors. LOG_ERR Errors. LOG_WARNING Warning messages. LOG_NOTICE Conditions that are not error con- ditions, butthat may require spe- cial handling. LOG_INFO Informational messages. LOG_DEBUG Messages that contain information normally of use only when debugging a program. INPUTS Level - indicates the type of the message. The levels are defined in sys/syslog.h and listed above. 158 Section B.2 AmiTCP/IP System Manual format - This is a printf-style format string as defined in exec.library/RawDoFmt(). arguments- as in printf(). ap - pointer to an array of arguments. RESULT Returns no value. EXAMPLES To log a message at priority LOG_INFO, it would make the followingcall to syslog: syslog(LOG_INFO, "Connection from host %s", CallingHost); NOTES As Exec RawDoFmt() used to do formatting expects by default short (16bit long) integers you should use the `l'-modifier when appopriate. See your compiler documentation about how it passesarguments on a vararg list. This function is callable from interrupts. BUGS Because there is a limited number of internal messages used by the logging system, some log messages may get lost if a high priority task or interrupt handler sends many messages in succession. If this happens, the next log message tells the fact. SEE ALSO exec.library/RawDoFmt() System Manual AmiTCP/IP Section B.3 159 B.3 Network Data and Address Manipulation B.3.1 inet _addr() NAME inet_addr, inet_network, Inet_MakeAddr, Inet_LnaOf, Inet_NetOf, Inet_NtoA - Internet address manipulation inet_makeaddr, inet_lnaof, inet_netof, inet_ntoa-- inline/stub functions to handle structure arguments SYNOPSIS #include addr = inet_addr(cp) D0 A0 unsignedlong inet_addr(char *); net = inet_network(cp) D0 A0 unsignedlong inet_network(char *); in_addr =Inet_MakeAddr(net, lna) D0 D0 D1 unsignedlong Inet_MakeAddr(long, long); lna = Inet_LnaOf(in) D0 D0 long Inet_LnaOf(unsigned long); net = Inet_NetOf(in) D0 D0 long Inet_NetOf(unsigned long); addr = Inet_NtoA(in) DO D0 char * Inet_NtoA(unsigned long); in_addr =inet_makeaddr(net, lna) struct in_addr inet_makeaddr(long, long); lna = inet_lnaof(in) 160 Section B.3 AmiTCP/IP System Manual int inet_lnaof(struct in_addr); net = inet_netof(in) int inet_netof(struct in_addr); addr = inet_ntoa(in) char * inet_ntoa(struct in_addr); IMPLEMENTATION NOTE Return value of Inet_MakeAddr() and argument types of Inet_LnaOf(), Inet_NetOf() and Inet_NtoA() are longs instead of struct in_addr. The original behaviour is achieved by using included stub functions (lower case function names) which handle structure arguments. DESCRIPTION The routines inet_addr() and inet_network() each interpret character strings representing numbers expressed in the Internetstandard `.' notation, returning numbers suitable for use as Internet addresses and Internet network numbers, respectively. The routine inet_makeaddr() takes an Internet network number and a local network address and constructs an Internetaddress from it. The routines inet_netof() and inet_lnaof() break apart Internet host addresses, returning the network number and local network address part, respec- tively. The routine inet_ntoa() returns a pointer to a string in the base 256notation ``d.d.d.d'' described below. All Internet address are returned in network order (bytes ordered from left to right). All network numbers and local address parts are returned as machine format integer values. INTERNET ADDRESSES Values specified using the `.' notation take one of the following forms: a.b.c.d a.b.c a.b a When fourparts are specified, each is interpreted as a byte of data and assigned, from left to right, to the four bytes of an Internet address. Note: when an Internet address is viewed as a 32-bit integer quantity on little endian systems, the bytes referred to above appear as d.c.b.a. System Manual AmiTCP/IP Section B.3 161 bytes areordered from right to left. When a three part address is specified, the last part is interpreted as a 16-bit quantity and placed in the right most twobytes of the network address. This makes the three part address format convenient for specifying Class B net- work addresses as "128.net.host". When a two part address is supplied, the last part is inter- preted as a 24-bit quantity and placed in the right most three bytes of the network address. This makes the two part address format convenient for specifying Class A network addressesas "net.host". When onlyone part is given, the value is stored directly in the network address without any byte rearrangement. All numbers supplied as ``parts'' in a `.' notation may be decimal, octal, or hexadecimal, as specified in the C language(that is, a leading 0x or 0X implies hexadecimal; otherwise, a leading0 implies octal; otherwise, the number is interpreted as decimal). RETURN VALUE The value-1 is returned by inet_addr() and inet_network() for malformed requests. BUGS The problem of host byte ordering versus network byte order- ing is confusing. A simple way to specify Class C network addressesin a manner similar to that for Class B and Class A is needed. The return value from inet_ntoa() points to static buffer which is overwritten in each inet_ntoa() call. 162 Section B.4 AmiTCP/IP System Manual B.4 Network, Protocol and Service Queries B.4.1 gethostbyname() NAME gethostbyname, gethostbyaddr - get network host entry SYNOPSIS #include #include #include hostent =gethostbyname(name) D0 A0 struct hostent *gethostbyname(char *); hostent =gethostbyaddr(addr, len, type) D0 A0 D0 D1 struct hostent *gethostbyaddr(caddr_t, LONG, LONG); DESCRIPTION gethostbyname() and gethostbyaddr() both return a pointer to an object with the following structure containing the data received from a name server or the broken-out fields of a linein netdb configuration file. In the case of gethostbyaddr(), addr is a pointer to the binary format address of length len (not a character string) and type is an address family as defined in . struct hostent - char *h_name; /* official name of host */ char **h_aliases; /* alias list */ int h_addrtype; /* address type */ int h_length; /* length of address */ char **h_addr_list; /* list of addresses from name server */ "; The members of this structure are: h_name Official name of the host. h_aliases A zero terminated array of alternate names for the host. h_addrtype The type of address being returned; currently always AF_INET. h_length The length, in bytes, of the address. System Manual AmiTCP/IP Section B.4 163 h_addr_list A pointer to a list of network addresses for the named host. Host addresses are returned in network byte order. DIAGNOSTICS A NULL pointer is returned if no matching entry was found or error occured. BUGS All information is contained in a static area so it must be copied ifit is to be saved. Only the Internet address for- mat is currently understood. SEE ALSO AmiTCP/IP configuration 164 Section B.4 AmiTCP/IP System Manual B.4.2 getnetbyname() NAME getnetbyname, getnetbyaddr - get network entry SYNOPSIS #include netent =getnetbyname(name) D0 A0 struct netent *getnetbyname(char *); netent =getnetbyaddr(net, type) D0 D0 D1 struct netent *getnetbyaddr(long, long); DESCRIPTION getnetbyname(), and getnetbyaddr() both return a pointer to an object with the following structure containing the broken-out fields of a line in netdb configuration file. struct netent - char *n_name; /* official name of net */ char **n_aliases; /* alias list */ int n_addrtype; /* net number type */ long n_net; /* net number */ "; The members of this structure are: n_name The official name of the network. n_aliases A zero terminated list of alternate names for the network. n_addrtype The type of the network number returned; currently only AF_INET. n_net The network number. Network numbers are returned in machine byte order. Network numbers are supplied in host order. Type specifies the address type to use, currently only AF_INET is supported. DIAGNOSTICS A NULL pointer is returned if no matching entry was found or error occured. System Manual AmiTCP/IP Section B.4 165 BUGS All information is contained in a static area so it must be copied ifit is to be saved. Only Internet network numbers are currently understood. SEE ALSO AmiTCP/IP configuration 166 Section B.4 AmiTCP/IP System Manual B.4.3 getprotobyname() NAME getprotobyname, getprotobynumber - get protocol entry SYNOPSIS #include protoent= getprotobyname(name) D0 A0 struct protoent *getprotobyname(char *); protoent= getprotobynumber(proto) D0 D0 struct protoent *getprotobynumber(long); DESCRIPTION getprotobyname() and getprotobynumber() both return a pointer to an object with the following structure containing the broken-out fields of a line in netdb configuration file struct protoent - char *p_name; /* official name of protocol */ char **p_aliases; /* alias list */ int p_proto; /* protocol number */ "; The members of this structure are: p_name The official name of the protocol. p_aliases A zero terminated list of alternate names for the protocol. p_proto The protocol number. DIAGNOSTICS A NULL pointer is returned if no matching entry was found or error occured. BUGS All information is contained in a static area so it must be copied if it is to be saved. Only the Internet protocols are currently understood. SEE ALSO AmiTCP/IP configuration System Manual AmiTCP/IP Section B.4 167 B.4.4 getservbyname() NAME getservbyname, getservbyport - get service entry SYNOPSIS #include servent =getservbyname(name, proto) D0 A0 A1 struct servent *getservbyname(char *, char *) servent =getservbyport(port, proto) D0 D0 A0 struct servent *getservbyport(long, char *); DESCRIPTION getservbyname() and getservbyport() both return a pointer to an object with the following structure containing the broken-out fields of a line in netdb configuration file. struct servent - char *s_name; /* official name of service */ char **s_aliases; /* alias list */ int s_port; /*port service resides at */ char *s_proto; /* protocol to use */ "; The members of this structure are: s_name The official name of the service. s_aliases A zero terminated list of alternate names for the service. s_port The port number at which the ser- vice resides. Port numbers are returned in network short byte order. s_proto The name of the protocol to use when contacting the service. The protoargument specifies the protocol for which to the sercive is to use. It is a normal C string, e.g. "tcp" or "udp". DIAGNOSTICS A NULL pointer is returned if no matching entry was found or error occured. BUGS All information is contained in a static area so it must be 168 Section B.4 AmiTCP/IP System Manual copied if it is to be saved. Expecting port numbers to fit in a 32 bit quantity is probably naive. SEE ALSO AmiTCP/IP configuration System Manual AmiTCP/IP Section B.5 169 B.5 AmiTCP/IP Specific Extensions B.5.1 Errno() NAME Errno - get error value after unsuccessful function call SYNOPSIS errno = Errno() D0 LONG Errno(VOID); FUNCTION When some function in socket library return an error conditionvalue, they also set a specific error value. This error value can be extracted by this function. RESULT Error value indicating the error on last failure of some socket function call. NOTES Return value of Errno() is not changed after successful functionso so it cannot be used to determine success of any functioncall of this library. Also, another function call to this library may change the return value of Errno() so use it right after error occurred. SEE ALSO SetErrnoPtr() 170 Section B.5 AmiTCP/IP System Manual B.5.2 ObtainSocket() NAME ObtainSocket - get a socket from AmiTCP/IP socket list SYNOPSIS s = ObtainSocket(id, domain, type, protocol) D0 D0 D1 D2 D3 LONG ObtainSocket(LONG, LONG, LONG, LONG); FUNCTION When onetask wants to give a socket to an another one, it releasesit (with a key value) to a special socket list held by AmiTCP/IP. This function requests that socket and receivesit if id and other parameters match. INPUTS id - a key value given by the socket donator. domain - see documentation of socket(). type - see documentation of socket(). protocol- see documentation of socket(). RESULT Non negative socket descriptor on success. On failure, -1 is returnedand the errno is set to indicate the error. ERRORS EMFILE - The per-process descriptor table is full. EPROTONOSUPPORT - The protocol type or the specified pro- tocol is not supported within this domain. EPROTOTYPE - The protocol is the wrong type for the socket. EWOULDBLOCK - Matching socket is not found. SEE ALSO ReleaseCopyOfSocket(), ReleaseSocket(), socket() System Manual AmiTCP/IP Section B.5 171 B.5.3 ReleaseCopyOfSocket() NAME ReleaseCopyOfSocket - copy given socket to AmiTCP/IP socket list. SYNOPSIS id = ReleaseCopyOfSocket(fd, id) D0 D0 D1 LONG ReleaseCopyOfSocket(LONG, LONG); FUNCTION Make a new reference to a given socket (pointed by its descriptor) and release it to the socket list held by AmiTCP/IP. INPUTS fd - descriptor of the socket to release. id - thekey value to identify use of this socket. It can be unique or not, depending on its value. If id value is between 0 and 65535, inclusively, it is considered nonunique and it can be used as a port number, for example. If id is greater than 65535 and less than 2^31) it must be unique in currently held sockets in AmiTCP/IP socket list, Otherwise an error will be returned and socket is not released. If id == UNIQUE_ID (defined in ) an unique id will be generated. RESULT id - -1 in case of error and the key value of the socket put in the list. Most useful when an uniqueid is generated by this routine. ERRORS EINVAL -Requested unique id is already used. ENOMEM -Needed memory couldn't be allocated. NOTE The socket descriptor is not deallocated. SEE ALSO ObtainSocket(), ReleaseSocket() 172 Section B.5 AmiTCP/IP System Manual B.5.4 ReleaseSocket() NAME ReleaseSocket - release given socket to AmiTCP/IP socket list. SYNOPSIS id = ReleaseSocket(fd, id) D0 D0 D1 LONG ReleaseSocket(LONG, LONG); FUNCTION Release the reference of given socket (via its descriptor) and movethe socket to the socket list held by AmiTCP/IP. The socket descriptor is deallocated in this procedure. INPUTS fd - descriptor of the socket to release. id - thekey value to identify use of this socket. It can be unique or not, depending on its value. If id value is between 0 and 65535, inclusively, it is considered nonunique and it can be used as a port number, for example. If id is greater than 65535 and less than 2^31) it must be unique in currently held sockets in AmiTCP/IP socket list, Otherwise an error will be returned and socket is not released. If id == UNIQUE_ID (defined in ) an unique id will be generated. RESULT id - -1 in case of error and the key value of the socket put in the list. Most useful when an uniqueid is generated by this routine. ERRORS EINVAL -Requested unique id is already used. ENOMEM -Needed memory couldn't be allocated. SEE ALSO ObtainSocket(), ReleaseCopyOfSocket() System Manual AmiTCP/IP Section B.5 173 B.5.5 SetDTableSize() NAME SetDTableSize - set socket descriptor table size of the base SYNOPSIS newsize =SetDTableSize(size) D0 D0 LONG SetDTableSize(UWORD); FUNCTION This function increases the descriptor table size inside library base so more sockets can be open at the same time. INPUT size - the new size of the desctiptor table. RESULT newsize -the new size of the descriptor table. Note that this canbe less than requested if an error occured. WARNING If the size of fd_set is not adjusted to store the increased space needed for new socket descriptors some other memory will bespilled. Change the value of FD_SETSIZE before including any socket include files and don't increase descriptor table to greater than the new value of FD_SETSIZE. SEE ALSO getdtablesize(), select() 174 Section B.5 AmiTCP/IP System Manual B.5.6 SetErrnoPtr() NAME SetErrnoPtr - set new place where the error value will be written SYNOPSIS SetErrnoPtr(ptr, size) A0 D0 VOID SetErrnoPtr(VOID *, UBYTE); FUNCTION This functions allows caller to redirect error variable inside scope of caller task. Usually this is used to make task's global variable errno as error variable. INPUTS ptr - pointer to error variable that isto be modified on every error condition on this library function. size - size of the error variable. EXAMPLE #include struct Library; struct Library * SocketBase = NULL; int main(void) - ... if ((SocketBase = OpenLibrary("bsdsocket.library", 2)) != NULL) - SetErrnoPtr(&errno, sizeof(errno)); ... " " NOTES Be sure that this new error variable exists until library base is finally closed or SetErrnoPtr() is called again for another variable. SEE ALSO Errno() System Manual AmiTCP/IP Section B.5 175 B.5.7 SetSocketSignals() NAME SetSocketSignals - inform AmiTCP/IP of INTR, IO and URG signals SYNOPSIS SetSocketSignals(sigintrmask, sigiomask, sigurgmask) D0 D1 D2 VOID SetSocketSignals(ULONG, ULONG, ULONG); FUNCTION SetSocketSignals() tells the AmiTCP/IP which signal masks corresponds UNIX SIGINT, SIGIO and SIGURG signals to be used in this implementation. sigintrmask mask is used to determine which Amiga signals interrupt blocking library calls. sigio- and sigurgmasks are sent when asynchronous notification of socket events is done and when out-of-band data arrives, respectively. Note that the supplied values write over old ones. If this functionis used and CTRL-C is still wanted to interrupt the calls (the default behaviour), the value BREAKF_CTRL_C must be explicitly given. SEE ALSO IoctlSocket(), recv(), send(), WaitSelect() Appendix C AmiTCP/IP Network Link Library This appendix describes the functions located in the net.lib. Table of Contents autoinit : : : : : : : : : : : : : : : : : : : : :: : : : : : : : : : :* * : : : : : : : : 177 autoinitd : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :* * : : : :: : : : 178 charRead : : : : : : : : : : : : : : : : : : : : :: : : : : : : : : : :* * : : : : : : : : 179 gethostname : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : 181 lineRead : : : : : : : : : : : : : : : : : : : : :: : : : : : : : : : :* * : : : : : : : : 182 176 System Manual AmiTCP/IP Section C.1 177 C.1 net.lib Functions C.1.1 autoinit NAME autoinit - SAS C Autoinitialization Functions SYNOPSIS _STIopenSockets() void _STIopenSockets(void) _STDcloseSockets() void _STDcloseSockets(void) FUNCTION These functions open and close the bsdsocket.library at the startup and exit of the program, respectively. For a program to use these functions, it must be linked with netlib:net.lib. Ifthe library can be opened, the _STIopenSockets() calls bsdsocket.library function SetErrnoPtr() to tell the library the address and the size of the errno variable of thecalling program. NOTES _STIopenSockets() also checks that the system version is at least 37. It puts up a requester if the bsdsocket.library isnot found or is of wrong version. Theautoinitialization and autotermination functions are features specific to the SAS C6. However, these functions canbe used with other (ANSI) C compilers, too. Example follows: "*at start of main() *" atexit(_STDcloseSockets); _STDopenSockets(); BUGS SEE ALSO bsdsocket.library/SetErrnoPtr(), SAS/C 6 User's Guide p. 145 for details of autoinitialization and autotermination functions. 178 Section C.1 AmiTCP/IP System Manual C.1.2 autoinitd NAME autoinitd - SAS C Autoinitialization Functions for Daemons SYNOPSIS void _STIopenSockets(void); void _STDcloseSockets(void); long server_socket; DESCRIPTION These are SASC autoinitialization functions for internet daemons started by inetd, Internet super-server. Upon startup, the server socket is obtained with ObtainSocket() library call. If successful, thesocket id is stored to the global variable server_socket. If the socket is not obtainable, the server_socket contains value -1. Ifthe server_socket is not valid, the server may try to accept() a newconnection and act as a stand-alone server. RESULT server_socket - positive socket id for success or -1 for failure. NOTES _STIopenSockets() also checks that the system version is at least 37. It puts up a requester if the bsdsocket.library isnot found or is of wrong version. Theautoinitialization and autotermination functions are features specific to the SAS C6. However, these functions canbe used with other (ANSI) C compilers, too. Example follows: "*at start of main() *" atexit(_STDcloseSockets); _STDopenSockets(); AUTHOR Jarno Rajahalme, Pekka Pessi, theAmiTCP/IP Group , Helsinki University of Technology, Finland. SEE ALSO serveraccept(), netutil/inetd System Manual AmiTCP/IP Section C.1 179 C.1.3 charRead NAME charRead -- read characters from socket one by one. SYNOPSIS initCharRead(rc, fd) void initCharRead(struct CharRead *, int); character = charRead(rc) intcharRead(struct CharRead *); DESCRIPTION charRead is a macro package which return characters one by one from given socket input stream. The socket where data is to be read isset by calling initCharRead(): rc is the pointer to charread structure previously allocated. fd is the (socket) descriptor where reading is to be done. charRead() returns the next character from input stream or one of the following: RC_DO_SELECT (-3) - read input buffer is returned. Do select before next call if you don't want charread to block. RC_EOF (-2) - end-of-file condition has occurred. RC_ERROR (-1) - there has been an error while filling new charread buffer. Check the value of Errno() NOTE Always use variable of type int to store return value from charRead() since the numeric value of characters returned may vary between 0 -255 (or even greater). As you may know, -3 equals 253 if of type unsigned char. EXAMPLE /* * This piece of code shows how to use charread with select() */ #include #include #include main_loop(int sock) - struct CharReadrc; fd_set readfds; int c; initCharRead(&rc, sock); 180 Section C.1 AmiTCP/IP System Manual FD_ZERO(&readfds); while(1) - FD_SET(sock, &readfds); if (select(sock + 1. &readfds, NULL, NULL, NULL)) < 0) - perror("select"); break; " if (FD_ISSET(sock, &readfds)) - while((c = charRead(&rc)) >= 0) handle_next_input_character(c); if (c == RC_EOF) break; if (c == RC_ERROR) - perror("charRead"); break; " " " " PORTABILITY Thesource file charread.h should be able to be used in UNIX programs as is. AUTHORS Tomi Ollila, theAmiTCP/IP Group , SEE ALSO lineRead(), bsdsocket.library/recv() System Manual AmiTCP/IP Section C.1 181 C.1.4 gethostname NAME gethostname -- get the name of the host SYNOPSIS error = gethostname(name, namelen); intgethostname(char *, int); FUNCTION Getthe name of the host to the buffer name of length namelen. Thename is taken from the environment variable "HOSTNAME" where it SHOULD reside. INPUTS name - Pointer to the buffer where the name should be stored. namelen - Length of the buffer name. RESULT error - 0 on success,-1 in case of an error. The global variable errno will be set to indicate the error as follows: ENOENT - The environment variable "HOSTNAME" is not found. EXAMPLE char hostname[MAXHOSTNAMELEN]; int error; error = gethostname(hostname, sizeof(hostname)); if(error < 0) exit(10); printf("My name is ""%s""."n", hostname); NOTES This function is included for source compatibility with Unix systems. TheENOENT errno value is AmiTCP/IP addition. BUGS Unlike the Unix version, this version assures that the resulting string is always NULL-terminated. SEE ALSO getenv() 182 Section C.1 AmiTCP/IP System Manual C.1.5 lineRead NAME lineRead -- read newline terminated strings from socket SYNOPSIS initLineRead(rl, fd, lftype, bufsize) void initLineRead(struct LineRead *, int, int, int); length = lineRead(rl) intlineread(struct LineRead *); DESCRIPTION lineRead() reads newline terminated strings from given descriptor very efficiently. All the options needed are set by calling initLineRead(): rl is the pointer to lineread structure previously allocated. fd is the (socket) descriptor where reading is to be done. lftype can have following 3 values: RL_LFNOTREQ - Newline terminated strings are returned unless there is no newlines left in currently buffered input. In this case remaining buffer is returned. RL_LFREQLF - If there is no newlines left in currently buffered input the remaining input datais copied at the start of buffer. Caller is informed that next call will fill the buffer (andit may block). Lines are always returned withnewline at the end unless the string is longer than whole buffer. RL_LFREQNUL - Like LF_REQLF, but remaining newline is removed. Note here that lenght is one longer that actual string length since line that has only one newline at the end would returnlength as 0 which indigate string incomplete condition. bufsize is used to tell lineread how big the receive buffer is. always put RL_BUFSIZE here since that value is used to determine thememory allocated for the buffer. This option is given to you soyou may decide to use different buffer size than the default 1024. lineRead() returns the newline terminated string in rl_line field oflineread structure. Return values of lineRead() are: 1 - RL_BUFSIZE - normal length of returned string. 0 - If zero is returned just after select(), end-of-file condition has occurred. Otherwise string is not completed yet. Make sure you call select() (or use non- blocking IO) if you don't want next call System Manual AmiTCP/IP Section C.1 183 to block. -1 - if rl_Line field of lineread structure is NULL, it indicates error condition. If rl_Line points to start of string buffer, input string has been longer than buffer. In this case rl_Line points to zero terminated string of length RL_BUFSIZE. Youmay modify the zero terminated string returned by lineRead() in anyway, but memory around the string is private lineread memory. EXAMPLE /* * The following code shows how to use lineread with select() */ #ifdef USE_LOW_MEMORY_BUFFER #define RL_BUFSIZE 256 #endif #include #ifdef AMIGA #include #endif #include #define NULL 0 ... main_loop(int sock) - struct LineRead* rl; int length; fd_set reafdfs; if (rl = (struct LineRead *)AllocMem(sizeof (*rl), 0)) - initLineRead(rl, sock, LF_REQLF, RL_BUFSIZE); FD_ZERO(&readfds); while(1) - FD_SET(sock, &readfds); if (select(sock + 1, &readfds, NULL, NULL, NULL)) < 0) - perror("select"); break; " if (FD_ISSET(sock, &readfds)) if ((length = lineRead(rl)) == 0) /* EOF */ break; do - if (length > 0) 184 Section C.1 AmiTCP/IP System Manual write(1, rl->rl_Line, length); /* stdout. write() for */ /* speed demonstration*/ else - /* length == -1 */ if (rl->rl_Line == NULL); - perror("lineRead"); break; " else - fprintf(stderr, "lineread input buffer overflow!"n"); write(1, rl->rl_Line, RL_BUFSIZE); write(1, ""n", 1); " " " while ((length = lineRead(rl)) != 0); /* 0 -> doselect() */ " FreeMem(rl, sizeof (*rl); " else fprintf("AllocMem: Out Of memory"n"); " PORTABILITY Thesource modules lineread.c and lineread.h should compile inUNIX machines as is. AUTHORS Tomi Ollila, theAmiTCP/IP Group , SEE ALSO readChar(), bsdsocket.library/recv() Appendix D Protocols and Network Interfaces The AutoDoc file protocol.doc contains on-line manual pages for protocols and network interfaces. Table of Contents arp : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : : 186 icmp : : : : : : : : : : : : : : : : : : : : : :: : : : : : : : : : : :* * : : : : : : : : : 189 if : : : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : : 190 inet : : : : : : : : : : : : : : : : : : : : : :: : : : : : : : : : : :* * : : : : : : : : : 193 ip : : : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : : 196 lo : : : : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : : 198 routing : : : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : 199 tcp : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : : 201 udp : : : : : : : :: : : : : : : : : : : : : : : : : : : : : : : : : : * *: : : : : : : : : : 203 185 186 Section D.1 AmiTCP/IP System Manual D.1 Protocols and Network Interfaces D.1.1 arp NAME arp- Address Resolution Protocol CONFIG AnySANA-II device driver using ARP SYNOPSIS #include #include #include s =socket(AF_INET, SOCK_DGRAM, 0); DESCRIPTION ARPis a protocol used to dynamically map between Internet Protocol (IP) and hardware addresses. It can be used by most theSANA-II network interface drivers. The current implementation supports only Internet Protocol (and is tested only with Ethernet). However, ARP is not limited to only that combination. ARPcaches IP-to-hardware address mappings. When an interface requests a mapping for an address not in the cache, ARP queues themessage which requires the mapping and broadcasts a message on the associated network requesting the address mapping. If a response is provided, the new mapping is cached andany pending message is transmitted. ARP will queue at most onepacket while waiting for a mapping request to be responded to;only the most recently transmitted packet is kept. Theaddress mapping caches are separate for each interface. The amount of mappings in the cache may be specified with an IoctlSocket() request. Tofacilitate communications with systems which do not use ARP, IoctlSocket() requests are provided to enter and delete entries inthe IP-to-Ethernet tables. USAGE #include #include #include #include struct arpreq arpreq; IoctlSocket(s, SIOCSARP, (caddr_t)&arpreq); IoctlSocket(s, SIOCGARP, (caddr_t)&arpreq); IoctlSocket(s, SIOCDARP, (caddr_t)&arpreq); These three IoctlSocket()s take the same structure as an argument. System Manual AmiTCP/IP Section D.1 187 SIOCSARP sets an ARP entry, SIOCGARP gets an ARP entry, and SIOCDARP deletes an ARP entry. These IoctlSocket() requests may be applied to anysocket descriptor (s). The arpreq structure contains: /*Maximum number of octets in protocol/hw address */ #define MAXADDRARP 16 /* * ARP ioctl request. */ struct arpreq - struct sockaddr arp_pa; /* protocol address */ struct - /* hardware address */ u_char sa_len; /* actual length + 2 */ u_char sa_family; char sa_data[MAXADDRARP]; " arp_ha; int arp_flags; /* flags */ "; /* arp_flags andat_flags field values */ #define ATF_INUSE 0x01 /* entry in use */ #define ATF_COM 0x02 /* completed entry */ #define ATF_PERM 0x04 /* permanent entry */ #define ATF_PUBL 0x08 /* publish entry */ Theinterface whose ARP table is manipulated is specified by arp_pa sockaddr. The address family for the arp_pa sockaddr must be AF_INET; for the arp_ha sockaddr it must be AF_UNSPEC. Thelength of arp_ha must match the length of used hardware address. Maximum length for the hardware address is MAXADDRARP bytes. The only flag bits which may be written are ATF_PERM andATF_PUBL. ATF_PERM makes the entry permanent if the IoctlSocket() call succeeds. ATF_PUBL specifies that the ARP code should respond to ARP requests for the indicated host coming from other machines. This allows a host to act as an ARPserver which may be useful in convincing an ARP-only machine to talk to a non-ARP machine. UNSUPPORTED IN AmiTCP/IP AmiTCP/IP EXTENSIONS There is an extension to the standard BSD4.4 ARP ioctl interface to access the contents of the whole ARP mapping cache. (In the BSD4.4 thestatic ARP table is accessed via the /dev/kmem.) The SIOCGARPT ioctl takes the following arptabreq structure as an argument: /* * An AmiTCP/IP specific ARP table ioctl request */ struct arptabreq - struct arpreq atr_arpreq; /* To identify the interface */ long atr_size; /* # of elements in atr_table */ long atr_inuse; /* # of elements in use */ 188 Section D.1 AmiTCP/IP System Manual struct arpreq *atr_table; "; Theatr_arpreq specifies the used interface. The hardware address forthe interface is returned in the arp_ha field of atr_arpreq structure. TheSIOCGARPT ioctl reads at most atr_size entries from the cache into the user supplied buffer atr_table, if it is not NULL. Actual amount of returned entries is returned in atr_size. The current amount of cached mappings is returned in the atr_inuse. TheSIOCGARPT ioctl has following usage: struct arpreq cache[N]; struct arptabreq arptab = - N, 0, cache "; IoctlSocket(s, SIOCGARPT, (caddr_t)&arptabreq); DIAGNOSTICS ARPwatches passively for hosts impersonating the local host (that is, a host which responds to an ARP mapping request forthe local host's address). "duplicate IP address a.b.c.d!!" "sent from hardware address: %x:%x:...:%x:%x" ARP has discovered another host on the local network which responds to mapping requests for its own Internet address. BUGS TheARP is tested only with Ethernet. Other network hardware may require special ifconfig configuration. SEE ALSO inet, netutil/arp, netutil/ifconfig, Plummer, Dave, ``An Ethernet Address Resolution Protocol -or- ConvertingNetwork Protocol Addresses to 48.bit Ether- netAddresses for Transmission on Ethernet Hardware,'' RFC 826, Network Information Center, SRI International, Menlo Park, Calif., November 1982. (Sun 800-1059-10) System Manual AmiTCP/IP Section D.1 189 D.1.2 icmp NAME icmp - Internet Control Message Protocol SYNOPSIS #include #include int socket(AF_INET, SOCK_RAW, proto) DESCRIPTION ICMP is the error and control message protocol used by IP and the Internet protocol family. It may be accessed through a ``raw socket'' for network monitoring and diagnostic functions. The proto parameter to the socket call to create an ICMP socket is obtained from getprotobyname(). ICMP sockets are connectionless, and are normally used with the sendto() and recvfrom() calls, though the connect() call may also be used to fix the destination for future packets (in which case the recv() and send() socket library calls maybe used). Outgoing packets automatically have an IP header prepended to them (based on the destination address). Incoming packets are received with the IP header and options intact. DIAGNOSTICS A socket operation may fail with one of the following errors returned: [EISCONN] when trying to establish a connection ona socket which already has one, orwhen trying to send a datagram with the destination address specified and the socket is already connected; [ENOTCONN] when trying tosend a datagram, but no destination address is specified, andthe socket hasn't been connected; [ENOBUFS] when the system runs out of memory for aninternal data structure; [EADDRNOTAVAIL] when an attempt is made to create a socket with a network address for whichno network interface exists. SEE ALSO bsdsocket.library/send(), bsdsocket.library/recv(), inet, ip HISTORY Theicmp protocol is originally from 4.3BSD. 190 Section D.1 AmiTCP/IP System Manual D.1.3 if NAME if- Network Interface to SANA-II devices DESCRIPTION Each network interface in the AmiTCP/IP corresponds to a path through which messages may be sent and received. A network interface usually has a SANA-II device driver associated with it, though the loopback interface, "lo", do not. The network interface inthe AmiTCP/IP (sana_softc) is superset of the BSD Unix network interface. When the network interface is first time referenced, AmiTCP/IP tries toopen the corresponding SANA-II device driver. If successful, a software interface to the SANA-II device is created. The "network/" prefix is added to the SANA-II device name, if needed. Once the interface has acquired its address, it is expected to install a routing table entry so that messages can be routed through it. TheSANA-II interfaces must be configured before they will allow traffic to flow through them. It is done after the interface is assigned a protocol address with a SIOCSIFADDR ioctl. Some interfaces may use the protocol address or a part of it as their hardware address. On interfaces where the network-link layer address mapping is static, only the network number is taken from the ioctl; theremainder is found in a hardware specific manner. On interfaces which provide dynamic network-link layer address mapping facilities (for example, Ethernets or Arcnets using ARP), the entire address specified in the ioctl is used. Thefollowing ioctl calls may be used to manipulate network interfaces. Unless specified otherwise, the request takes an ifreq structure as its parameter. This structure has the form struct ifreq - char ifr_name[IFNAMSIZ]; /* interface name (eg. "slip.device/0")*/ union - struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; short ifru_flags; " ifr_ifru; #define ifr_addr ifr_ifru.ifru_addr /* address */ #define ifr_dstaddr ifr_ifru.ifru_dstaddr /* end of p-to-p link */ #define ifr_flags ifr_ifru.ifru_flags /* flags */ "; SIOCSIFADDR Set interface address. Following the address assignment, the ``initialization'' routine for the interface is called. SIOCGIFADDR Get interface address. SIOCSIFDSTADDR Set point to point address for interface. SIOCGIFDSTADDR Get point to point address for interface. System Manual AmiTCP/IP Section D.1 191 SIOCSIFFLAGS Set interface flagsfield. If the interface is marked down, any processes currently routing packets through the interface are notified. SIOCGIFFLAGS Get interface flags. SIOCGIFCONF Get interface configurationlist. This request takes an ifconf structure(see below) as a value-result parameter. The ifc_len field should be initially set to the sizeof the buffer pointed to by ifc_buf. On return itwill contain the length, in bytes, of the configuration list. /* * Structure used in SIOCGIFCONF request. * Used toretrieve interface configuration * for machine (useful for programs which * must know all networks accessible). */ 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 */ "; UNSUPPORTED IN AmiTCP/IP These standard BSD ioctl codes are not currently supported: SIOCADDMULTI Enable a multicast address for the interface. SIOCDELMULTI Disable a previouslyset multicast address. SIOCSPROMISC Toggle promiscuous mode. AmiTCP/IP EXTENSIONS Thefollowing ioctls are used to configure protocol and hardware specific properties of a sana_softc interface. They are used in the AmiTCP/IP only. SIOCSSANATAGS Set SANA-II specific properties with a tag list. SIOCGSANATAGS Get SANA-II specific properties into a wiretype_parameters structure and a user tag list. struct wiretype_parameters - ULONG wiretype; /* the wiretype of theinterface */ WORD flags; /* iff_flags*/ struct TagItem*tags; /* tag list userprovides */ 192 Section D.1 AmiTCP/IP System Manual "; SEE ALSO arp, lo, netutil/arp, netutil/ifconfig, , , System Manual AmiTCP/IP Section D.1 193 D.1.4 inet NAME inet - Internet protocol family SYNOPSIS #include #include DESCRIPTION TheInternet protocol family implements a collection of protocols which are centered around the Internet Protocol (IP) and which share a common address format. The Internet family provides protocol support for the SOCK_STREAM, SOCK_DGRAM, and SOCK_RAW socket types. PROTOCOLS TheInternet protocol family is comprised of the Internet Protocol (IP), the Address Resolution Protocol (ARP), the Internet Control Message Protocol (ICMP), the Transmission Control Protocol (TCP), andthe User Datagram Protocol (UDP). TCPis used to support the SOCK_STREAM abstraction while UDP is used tosupport the SOCK_DGRAM abstraction; (SEE ALSO tcp, SEE ALSO udp). A raw interface to IP is available by creating an Internet socket of type SOCK_RAW; (SEE ALSO ip). ICMP is used by the kernel to handle andreport errors in protocol processing. It is also accessible to user programs; (SEE ALSO icmp). ARP is used to translate 32-bit IP addresses into varying length hardware addresses; (SEE ALSO arp). The32-bit IP address is divided into network number and host number parts. It is frequency-encoded; the most significant bit is zero in Class A addresses, in which the high-order 8 bits are the network number. Class Baddresses have their high order two bits set to 10 anduse the highorder 16 bits as the network number field. Class C addresses have a 24-bit network number part of which the high order three bits are 110. Sites with a cluster of local networks may chose to use a single network number for the cluster; this is done byusing subnet addressing. The local (host) portion of the address isfurther subdivided into subnet number and host number parts. Within a subnet, each subnet appears to be an individual network; externally, the entire cluster appears to be a single, uniform network requiring only a single routing entry. Subnet addressing is enabled and examined by the following ioctl commands on a datagram socket in the Internet domain; they have the same form as the SIOCIFADDR (SEE ALSO if) command. SIOCSIFNETMASK Set interface network mask. The network mask defines the network part of the address; ifit contains more of the address than the address type would indicate, then subnets are in use. SIOCGIFNETMASK Get interface network mask. ADDRESSING IPaddresses are four byte quantities, stored in network byte order (the native Amiga byte order) 194 Section D.1 AmiTCP/IP System Manual Sockets in the Internet protocol family use the following addressing structure: struct sockaddr_in - short sin_family; u_short sin_port; struct in_addr sin_addr; char sin_zero[8]; "; Functions in bsdsocket.library are provided to manipulate structures ofthis form. Thesin_addr field of the sockaddr_in structure specifies a local or remote IP address. Each network interface has its own unique IP address. The special value INADDR_ANY may be used in this field to effect "wildcard" matching. Given in a bind() call, this value leaves the local IP address of the socket unspecified, so that the socket will receive connections or messages directed at any of the valid IP addresses of the system. This can prove useful when a process neither knows nor cares what the local IP address is or when a process wishes to receive requests using all of its network interfaces. Thesockaddr_in structure given in the bind() call must specify an in_addr value of either IPADDR_ANY or one of the system's valid IP addresses. Requests to bind any other address will elicit theerror EADDRNOTAVAIL. When a connect() call is made for a socket that has a wildcard local address, the system sets the sin_addr field of the socket to the IP address of the network interface that thepackets for that connection are routed via. Thesin_port field of the sockaddr_in structure specifies a port number used by TCP or UDP. The local port address specified in a bind() call is restricted to be greater than IPPORT_RESERVED (defined in ) unless the creating process is running asthe super-user, providing a space of protected port numbers. In addition, the local port address must not be in use by any socket of same address family and type. Requests to bind sockets to port numbers being used by other sockets return the error EADDRINUSE. If thelocal port address is specified as 0, then the system picks a unique port address greater than IPPORT_RESERVED. A unique local port address is also picked when a socket which is not bound is used ina connect() or send() call. This allows programs which do not care which local port number is used to set up TCP connections by sim- ply calling socket() and then connect(), and to send UDP datagrams with a socket() call followed by a send() call. Although this implementation restricts sockets to unique local port numbers, TCP allows multiple simultaneous connections involving the same local port number so long as the remote IP addresses or port numbers are different for each connection. Programs may explicitly override the socket restriction by setting the SO_REUSEADDR socket option with setsockopt (see getsockopt()). SEE ALSO bsdsocket.library/bind(), bsdsocket.library/connect(), System Manual AmiTCP/IP Section D.1 195 bsdsocket.library/getsockopt(), bsdsocket.library/IoctlSocket(), bsdsocket.library/send(), bsdsocket.library/socket(), bsdsocket.library/gethostent(), bsdsocket.library/getnetent(), bsdsocket.library/getprotoent(), bsdsocket.library/getservent(), bsdsocket.library/inet_addr(), arp, icmp, ip, tcp, udp Network Information Center, DDN Protocol Handbook (3 vols.), Network Information Center, SRI International, Menlo Park, Calif., 1985. A AmiTCP/IP Interprocess Communication Primer WARNING TheInternet protocol support is subject to change as the Internet protocols develop. Users should not depend on details of the current implementation, but rather the services exported. 196 Section D.1 AmiTCP/IP System Manual D.1.5 ip NAME ip- Internet Protocol SYNOPSIS #include #include int socket(AF_INET, SOCK_RAW, proto) DESCRIPTION IPis the transport layer protocol used by the Internet protocol family. Optionsmay be set at the IP level when using higher-level protocols that are based on IP (such as TCP and UDP). It may also be accessed through a ``raw socket'' when developing new protocols, or special purpose applica- tions. A single generic option is supported at the IP level, IP_OPTIONS, that may be used to provide IP options to be transmitted in the IP header of each outgoing packet. Options are set with setsockopt() andexamined with getsockopt(). The format of IP options to be sent isthat specified by the IP protocol specification, with one exception: the list of addresses for Source Route options must include the first-hop gateway at the beginning of the list of gateways. The first-hop gateway address will be extracted from the option list and the size adjusted accordingly before use. IP options may be used with any socket type in the Internet family. RawIP sockets are connectionless, and are normally used with the sendto and recvfrom calls, though the connect() call may also be used to fix the destination for future packets (in which case the recv() and send() system calls may be used). Ifproto is 0, the default protocol IPPROTO_RAW is used for outgoing packets, and only incoming packets destined for that protocol are received. If proto is non-zero, that protocol number will be used onoutgoing packets and to filter incoming packets. Outgoing packets automatically have an IP header prepended to them (based on the destination address and the protocol number the socket iscreated with). Incoming packets are received with IP header and options intact. DIAGNOSTICS A socket operation may fail with one of the following errors returned: [EISCONN] when trying to establish a connection ona socket which already has one, orwhen trying to send a datagram with the destination address specified and the socket is already connected; [ENOTCONN] when trying tosend a datagram, but no destination address is specified, andthe socket hasn't been System Manual AmiTCP/IP Section D.1 197 connected; [ENOBUFS] when the system runs out of memory for aninternal data structure; [EADDRNOTAVAIL] when an attempt is made to create a socket with a network address for whichno network interface exists. Thefollowing errors specific to IP may occur when setting or getting IP options: [EINVAL] An unknown socket option name was given. [EINVAL] The IP option field was improperly formed; an option field was shorterthan the minimum value or longer than the option buffer provided. SEE ALSO bsdsocket.library/getsockopt(), bsdsocket.library/send(), bsdsocket.library/recv(), icmp, inet HISTORY Theip protocol appeared in 4.2BSD. 198 Section D.1 AmiTCP/IP System Manual D.1.6 lo NAME lo- Software Loopback Network Interface SYNOPSIS pseudo-device loop DESCRIPTION Theloop interface is a software loopback mechanism which may be used for performance analysis, software testing, and/or local communication. There is no SANA-II interface associated with lo. Aswith other network interfaces, the loopback interface must have network addresses assigned for each address family with which it is tobe used. These addresses may be set or changed with the SIOCSIFADDR ioctl. The loopback interface should be the last interface configured, as protocols may use the order of configuration as an indication of priority. The loopback should never be configured first unless no hardware interfaces exist. DIAGNOSTICS "lo%d: can't handle af%d." Theinterface was handed a message with ad- dresses formatted in an unsuitable address family; the packet was dropped. SEE ALSO inet, if, netutil/ifconfig BUGS Older BSD Unix systems enabled the loopback interface automatically, using a nonstandard Internet address (127.1). Use ofthat address is now discouraged; a reserved host address for the local network should be used instead. System Manual AmiTCP/IP Section D.1 199 D.1.7 routing NAME routing - system supporting for local network packet routing DESCRIPTION Thenetwork facilities provided general packet routing, leaving routing table maintenance to applications processes. A simple set of data structures comprise a ``routing table'' used in selecting the appropriate network interface when transmitting packets. This table contains a single entry for each route to a specific network or host. A user process, the routing daemon, maintains this data base with the aid of two socket specific ioctl commands, SIOCADDRT and SIOCDELRT. Thecommands allow the addition and deletion of a single routing table entry, respectively. Routing table manipulations may only be carried out by super-user. A routing table entry has the following form, as defined in : struct rtentry - u_long rt_hash; struct sockaddr rt_dst; struct sockaddr rt_gateway; short rt_flags; short rt_refcnt; u_long rt_use; struct ifnet *rt_ifp; "; with rt_flags defined from: #define RTF_UP 0x1 /* route usable */ #define RTF_GATEWAY 0x2 /* destination is a gateway */ #define RTF_HOST 0x4 /* host entry (net otherwise) */ Routing table entries come in three flavors: for a specific host, for all hosts on a specific network, for any destination notmatched by entries of the first two types (a wildcard route). When the system is booted, each network interface autoconfigured installs a routing table entry when it wishes tohave packets sent through it. Normally the interface specifies the route through it is a ``direct'' connection to thedestination host or network. If the route is direct, the transport layer of a protocol family usually requests the packet be sent to the same host specified in the packet. Otherwise, the interface may be requested to address the packet to an entity different from the eventual recipient (that is, the packet is forwarded). Routing table entries installed by a user process may not specify the hash, reference count, use, or interface fields; these are filled in by the routing routines. If a route is in usewhen it is deleted (rt_refcnt is non-zero), the resources associated with it will not be reclaimed until all references toit are removed. 200 Section D.1 AmiTCP/IP System Manual Therouting code returns EEXIST if requested to duplicate an existing entry, ESRCH if requested to delete a non-existent entry, or ENOBUFS if insufficient resources were available to install a new route. Thert_use field contains the number of packets sent along the route. This value is used to select among multiple routes to thesame destination. When multiple routes to the same destination exist, the least used route is selected. A wildcard routing entry is specified with a zero destination address value. Wildcard routes are used only when the system fails to find a route to the destination host and network. Thecombination of wildcard routes and routing redirects can provide an economical mechanism for routing traffic. SEE ALSO bsdsocket.library/IoctlSocket(), netutil/route System Manual AmiTCP/IP Section D.1 201 D.1.8 tcp NAME tcp- Internet Transmission Control Protocol SYNOPSIS #include #include int socket(AF_INET, SOCK_STREAM, 0) DESCRIPTION TheTCP protocol provides reliable, flow-controlled, two-way transmission of data. It is a byte-stream protocol used to support theSOCK_STREAM abstraction. TCP uses the standard Internet address format and, in addition, provides a per-host collection of ``port addresses''. Thus, each address is composed of an Internet address specifying the host and network, with a specific TCP port on the host identifying the peer entity. Sockets utilizing the tcp protocol are either ``active'' or ``passive''. Active sockets initiate connections to passive sockets. By default TCP sockets are created active; to create a passive socket the listen() bsdsocket.library function call must be used after binding the socket with the bind() bsdsocket.library function call. Only passive sockets may use the accept() call to accept incoming connections. Only active sockets may use the connect() call to initiate connections. Passive sockets may ``underspecify'' their location to match incoming connection requests from multiple networks. This technique, termed ``wildcard addressing'', allows a single server to provide service to clients on multiple networks. To create a socket which listens on all networks, the Internet address INADDR_ANY must bebound. The TCP port may still be specified at this time; if the port is not specified the bsdsocket.library function will assign one. Once a connection has been established the socket's address is fixed by the peer entity's location. The address assigned the socket is the address associated with the network interface through which packets are being transmitted and received. Normally this address corresponds to the peer entity's network. TCPsupports one socket option which is set with setsockopt() and tested with getsockopt(). Under most circumstances, TCP sends data when it is presented; when outstanding data has not yet been acknowledged, it gathers small amounts of output to be sent in a single packet once an acknowledgement is received. For a small number of clients, such as X Window System functions that send a stream of mouse events which receive no replies, this packetization may cause significant delays. Therefore, TCP provides a boolean option, TCP_NODELAY (from , to defeat this algorithm. Theoption level for the setsockopt call is the protocol number for TCP, available from getprotobyname(). Options at the IP transport level may be used with TCP; SEE ALSO ip. 202 Section D.1 AmiTCP/IP System Manual Incoming connection requests that are source-routed are noted, and thereverse source route is used in responding. DIAGNOSTICS A socket operation may fail with one of the following errors returned: [EISCONN] when trying to establish a connection ona socket which already has one; [ENOBUFS] when the AmiTCP/IP runs out of memory foran internal data structure; [ETIMEDOUT] when a connection was dropped due to excessive retransmissions; [ECONNRESET] when the remote peerforces the connection to be closed; [ECONNREFUSED] when the remote peer actively refuses connection establishment (usually because no process is listening to the port); [EADDRINUSE] when an attempt is made to create a socket with a port which has already been allocated; [EADDRNOTAVAIL] when an attempt is made to create a socket with a network address for whichno network interface exists. SEE ALSO bsdsocket.library/getsockopt(), bsdsocket.library/socket(), bsdsocket.library/bind(), bsdsocket.library/listen(), bsdsocket.library/accept(), bsdsocket.library/connect(), inet, ip,, , HISTORY Thetcp protocol stack appeared in 4.2BSD. System Manual AmiTCP/IP Section D.1 203 D.1.9 udp NAME udp- Internet User Datagram Protocol SYNOPSIS #include #include int socket(AF_INET, SOCK_DGRAM, 0) DESCRIPTION UDPis a simple, unreliable datagram protocol which is used to support the SOCK_DGRAM abstraction for the Internet protocol family. UDPsockets are connectionless, and are normally used with the sendto() and recvfrom() calls, though the connect() call may also be used to fix the destination for future packets (in which case the recv() and send() function calls may be used). UDPaddress formats are identical to those used by TCP. In particular UDP provides a port identifier in addition to the normal Internet address format. Note that the UDP port space is separate from the TCP port space (i.e. a UDP port may not be ``connected'' to a TCP port). In addition broadcast packets may be sent (assuming the underlying network supports this) by using a reserved ``broadcast address''; this address is network interface dependent. Options at the IP transport level may be used with UDP; SEE ALSO ip. DIAGNOSTICS A socket operation may fail with one of the following errors returned: [EISCONN] when trying to establish a connection ona socket which already has one, orwhen trying to send a datagram with the destination address specified and the socket is already connected; [ENOTCONN] when trying tosend a datagram, but no destination address is specified, andthe socket hasn't been connected; [ENOBUFS] when the system runs out of memory for an internal data structure; [EADDRINUSE] when an attempt is made to create a socket with a port which has already been allocated; [EADDRNOTAVAIL] when an attempt is made to create a socket with a network address for whichno network interface exists. SEE ALSO bsdsocket.library/getsockopt(), bsdsocket.library/recv(), bsdsocket.library/send(), bsdsocket.library/socket(), inet, ip 204 Section D.1 AmiTCP/IP System Manual HISTORY Theudp protocol appeared in 4.2BSD.