REF SOCKETS John Gibson Jun 1995 COPYRIGHT University of Sussex 1995. All Rights Reserved. >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< UNIX SOCKET >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< INTERFACE >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<< >>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CONTENTS - (Use <ENTER> g to access required sections) 1 Introduction 1.1 Socket Devices 2 Socket Names 2.1 Unix 2.2 Internet ... host-spec ... port-spec 3 Types of Socket 3.1 Stream Sockets 3.2 Datagram Sockets 4 Socket Creation 5 Accessing & Assigning Socket Names 6 Sending and Receiving Messages 7 Miscellaneous --------------- 1 Introduction --------------- LIB * UNIX_SOCKETS is a set of procedures for creating and operating on Unix sockets. Before using any procedures, the library must be loaded with uses unix_sockets; The include file INCLUDE * UNIX_SOCKETS defines various integer constants for use with these procedures. This file describes only the Poplog interface to the socket facilities; it does not attempt to provide a tutorial on sockets in general (for which, see the Unix documentation). 1.1 Socket Devices ------------------- In Poplog, sockets are represented by system devices. As with other procedures that create system devices (i.e. sysopen, syscreate and syspipe), all procedures that create a new socket take an argument org to specify certain aspects of sysread and syswrite's behaviour when applied to it. See Opening System Devices in REF * SYSIO for further details. Note that the procedure * sys_device_wait implements the UNIX * select system call, and can be used to multiplex I/O on sockets and other devices. (Alternatively, asynchronous processing can be effected with * sys_async_io.) --------------- 2 Socket Names --------------- Socket address families are defined by the integer AF_ constants in INCLUDE * UNIX_SOCKETS. Most Unix systems support only two, the Unix (AF_UNIX) and Internet (AF_INET) families. By default, the procedures in LIB * UNIX_SOCKETS also only support Pop socket name representations for these two. However, all name translation is effected through the property * sys_socket_name_trans, which could be extended to provide name translation for other domains if required. 2.1 Unix --------- AF_UNIX socket names are just ordinary Unix filenames (i.e. strings). As usual in Poplog, input filenames are run through * sysfileok to perform any environment variable translation, etc. 2.2 Internet ------------- AF_INET socket names consist of a host-spec, which specifies the host address, and an optional port-spec, specifying the port number at that host (port-spec defaults to 0 when omitted). An Internet socket name is therefore a host-spec alone, or a 2-element list: [ host-spec port-spec ] ... host-spec -------------- host-spec may be one of the following: ¤ A host name string, e.g. 'rsuna.crn.cogs.susx.ac.uk' The given name is translated to an address using UNIX * gethostbyname ¤ A string giving a numeric Internet address in dot notation, e.g. '192.33.16.1' The string is given to UNIX * inet_addr to produce an address. (Note that inet_addr is tried first on any string beginning with a digit; if this returns an error, gethostbyname is tried.) ¤ The word "*", meaning the wildcard address INADDR_ANY. (Used with a port-spec to set a local socket name, where any local host address will do.) ¤ An integer Internet address directly (in host byte order). ¤ A 2-element vector of the form { network local-network-address } where network is an integer or a network name string, and local-network-address is an integer. A network name string is translated to a network number using UNIX * getnetbyname. In either case, the integer network number is then combined with the local-network-address part using UNIX * inet_makeaddr ... port-spec -------------- When present, port-spec takes the following values: ¤ An integer port number. ¤ An Internet service name. This is either a string, or a 2-element vector { service-name protocol-name } where service-name is a string and protocol-name is a word. The given service is translated to a port number using UNIX * getservbyname (qualified by the optional protocol-name if present). For example, [ 'mc.site.ac.uk' 'nntp' ] [ 'rsuna.crn.cogs.susx.ac.uk' {'daytime' udp} ] (A protocol-name vector can also have an explicit port number instead of service-name. This is useful for specifying the protocol to sys_socket_to_service when a non-standard port is being used.) Note that those procedures below which return a socket name always return the host address part of an AF_INET name as a string in Internet dot notation. ------------------ 3 Types of Socket ------------------ The type argument to sys_socket specifies the communication semantics of the socket being created, and is one of the integer SOCK_ constants defined in INCLUDE * UNIX_SOCKETS (or an equivalent ASCII character, see below). Most Unix systems support only stream (SOCK_STREAM) and datagram (SOCK_DGRAM) types: 3.1 Stream Sockets ------------------- SOCK_STREAM sockets are connection-based 2-way byte streams (like 2-way pipes). Connections are established asymmetrically, with one party acting as server, and the other as client. The server process must execute code such as the following: ;;; Create a control socket (n.b. ASCII `S` = SOCK_STREAM) lvars control_sock = sys_socket(af, `S`, false); ;;; Assign a known name local_server_name to the local name of the ;;; control socket, and start listening for connections. (For ;;; Internet, local_server_name is often [* port], meaning any ;;; local hostname at port port.) local_server_name -> sys_socket_name(control_sock, 5); ;;; Then repeatedly accept connections on the control socket. ;;; Each connection creates a new socket for actually communicating ;;; with the client. repeat lvars comm_sock = sys_socket_accept(control_sock, org); ;;; process each comm_sock, e.g. add it to a list of connections endrepeat; To make a connection, each client process creates a socket, and assigns remote_server_name to its sys_socket_peername: lvars comm_sock = sys_socket(af, `S`, org); remote_server_name -> sys_socket_peername(comm_sock); sysread and syswrite are then used to read and write data on each communications socket. 3.2 Datagram Sockets --------------------- SOCK_DGRAM sockets implement datagrams, i.e. connectionless messages of a fixed maximum length: ;;; Create a datagram socket (n.b. ASCII `D` = SOCK_DGRAM) lvars sock = sys_socket(af, `D`, org); ;;; Optionally establish a local name for it. local_name -> sys_socket_name(sock); Messages may then be sent using syswrite or sys_socket_send: ;;; Send a message to remote_name -- this can be done with either ;;; sys_socket_send ... sys_socket_send(sock, message, datalength(message), 0, remote_name); ;;; ... or with syswrite after assigning a remote_name to ;;; sys_socket_peername. remote_name -> sys_socket_peername(sock); syswrite(sock, message, datalength(message)); Messages are received with sysread or sys_socket_recv. In both cases, if a remote_name has been assigned to sys_socket_peername, only messages from there will be accepted (otherwise, they will be received from any sender): ;;; Receive a message -- this can be done with either ;;; sys_socket_recv if the sender's name is required ... sys_socket_recv(sock, buff, datalength(buff), 0, true) -> (nread, remote_name) ;;; ... or with sysread otherwise. sysread(sock, buff, datalength(buff)) -> nread; See Sending and Receiving Messages below for more details. ------------------ 4 Socket Creation ------------------ sys_socket(af, type, org) -> sock [procedure] sys_socket(af, type, protocol, org) -> sock Creates a socket sock (a system device). See Opening System Devices in REF * SYSIO for a description of the org argument. af is the address/protocol family, and must be one of the integer AF_ constants defined in INCLUDE * UNIX_SOCKETS. Most Unix systems support only the AF_UNIX and AF_INET domains; the af argument for these may also be given as the ASCII character constants `u` and `i` respectively. type specifies the communication semantics of the socket, and must be one of the integer SOCK_ constants defined in INCLUDE * UNIX_SOCKETS. Most Unix systems support only SOCK_STREAM (connection-based 2-way byte streams), and SOCK_DGRAM (datagrams, i.e. connectionless, unreliable messages of a fixed maximum length). These two may also be specified as the ASCII character constants `S` and `D` respectively. The optional protocol argument may specify a particular transmission protocol to be used. (That is, where possible -- normally, only a single protocol exists to support a particular socket type within a given family, and this will be used by default.) If supplied, protocol must be a word. This can be either a protocol name, in which case UNIX * getprotobyname will be called to translate it to a protocol number, or it may be a protocol number directly (but again, as a word, e.g. "'123'"). For example, vars sock = sys_socket(`i`, `S`, false); creates an Internet stream socket (default protocol "tcp"). See also UNIX * socket sys_socket_pair(af, type, org) -> (sock1, sock2) [procedure] sys_socket_pair(af, type, protocol, org) -> (sock1, sock2) Creates a pair of unnamed sockets sock1 and sock2, each of which is already connected to the other. The two sockets are indistinguishable. The arguments are the same as for sys_socket above. However, Unix only implements this call for the AF_UNIX address family (where if type is SOCK_STREAM, sock1 and sock2 are just the same as two-way pipes). See also UNIX * socketpair sys_socket_accept(sock, org) -> conn_sock [procedure] Accepts server-side connections on a stream socket sock. sock must have a local name assigned and be listening for connections, i.e. the call local_name -> sys_socket_name(sock, qlen); must previously have been made. The connection is made on a new socket conn_sock, which is returned. conn_sock inherits its address family, type and protocol (and option settings) from sock, and uses the given org argument. sys_socket_peername may be applied to conn_sock to determine the name of the connected peer. See also UNIX * accept sys_socket_to_service(serv_name, org) -> sock [procedure] A convenience routine for connecting to an Internet service at a given host. serv_name must be an AF_INET socket name containing an Internet service name for the port spec (or an explicit port number with a protocol -- see Socket Names: Internet above). sys_socket is then called (with last argument org) to create a socket sock for address family AF_INET. sock is created with type SOCK_STREAM or SOCK_DGRAM, according to whether the protocol used by the service is "tcp" or "udp" respectively. (Note that providing it supplies a service name, serv_name need not specify an explicit protocol name, since UNIX * getservbyname returns this information along with the port number. However, it must specify a protocol name if a port number is given.) The socket is then connected by assigning serv_name to sys_socket_peername for sock. For example vars nntp_sock = sys_socket_to_service(['mc.site.ac.uk' 'nntp'], false); would connect to the 'nntp' news server at host 'mc.site.ac.uk'. ------------------------------------- 5 Accessing & Assigning Socket Names ------------------------------------- sys_socket_name(sock) -> name_or_false [procedure] name -> sys_socket_name(sock) name -> sys_socket_name(sock, qlen) Returns or assigns the local name of the socket sock. For SOCK_STREAM sockets, the updater optionally starts listening for server-side connections. The base procedure returns the local name of sock (as supplied by UNIX * getsockname), or false if the socket is unnamed. The updater assigns name to be the local name of sock (by calling UNIX * bind). The socket must not have a name assigned already. For stream sockets, the optional integer argument qlen may be supplied. After assigning the name, the updater will then call UNIX * listen on sock to start listening for client connections (allowing for a maximum of qlen connection requests to be queued). Connections on sock may then be accepted with * sys_socket_accept. (Note that queued but not-yet-accepted connections on sock behave as 'input' in respect of * sys_input_waiting and * sys_device_wait. * sys_async_io with condition argument 0 can also be used to provide asynchronous notification of connections on sock.) sys_socket_peername(sock) -> name_or_false [procedure] name -> sys_socket_peername(sock) name -> sys_socket_peername(sock, changes_p) name -> sys_socket_peername(sock, retries) name -> sys_socket_peername(sock, changes_p, retries) Returns or assigns the peername of the socket sock. The base procedure returns the peername of sock (as supplied by UNIX * getpeername), or false if the socket has no associated peer. The updater assigns name to be the peername of sock (by calling UNIX * connect). The effect of this depends on the type of socket, as follows: Datagram Sockets For SOCK_DGRAM sockets, peername assignment sets the address to which datagrams will be sent (with syswrite, or sys_socket_send with no destination specified). It constrains datagrams received (with sysread or sys_socket_recv) to come from that address. You can change the peername at any time (or assign false to dissolve any association). Stream Sockets For SOCK_STREAM sockets, assigning a peername makes a ('client') connection to the designated address; this can be done only once. For a connection to be established, the peer (i.e. 'server') must be listening for connections at the designated address (see sys_socket_name above), and must then accept the connection (see sys_socket_accept). However, a connection may be temporarily refused, for example if the server's queue of pending (not yet accepted) connections is full. For this reason, the updater of sys_socket_peername will retry upto retries times to make the connection (where the optional integer retries argument defaults to 5 if omitted). The procedure waits one second before each retry. For Unix-related reasons, each connect failure (i.e. Unix ECONNREFUSED error), causes the Unix file descriptor associated with sock to become unusable for further operations. The updater of sys_socket_peername is therefore obliged to open a new socket before trying again, and to replace the sock device's file descriptor with the new one. As a result, any assignments previously made to sock with sys_socket_option will be lost. To surmount this problem, the optional changes_p argument may be supplied: this is applied to sock before each connection attempt (including the first). Hence any sys_socket_option assignments that need doing before connection should be put into a changes_p procedure. Note that for all types of socket, assigning to sys_socket_peername also causes the local name (i.e. sys_socket_name) of the socket to be assigned a value if it does not already have one (the value is chosen by Unix). Client-side SOCK_STREAM sockets do not usually bother assigning an explicit local name, but if this has been done, sys_socket_peername will preserve the assignment across any new socket descriptors created during connection retries. --------------------------------- 6 Sending and Receiving Messages --------------------------------- For most purposes, sysread and syswrite are sufficient for reading and writing sockets. However, these cannot be used ¤ For out-of-band data on stream sockets. ¤ When receiving datagrams on a datagram socket with no associated peername (and which can therefore receive from any sender), and where the sender address of each message is required (e.g. so a reply can be sent). Although sysread will read such messages, it will not provide the sender addresses. (Note that syswrite can be used to send messages to multiple destinations by assigning different peernames to sys_socket_peername. syswrite cannot be used on a datagram socket with no associated peername.) The procedures sys_socket_recv and sys_socket_send are provided to cope with the above cases. Unlike sysread and syswrite, they provide no internal Poplog buffering of data. sys_socket_recv(sock, buff, nbytes, flags, false) [procedure] -> nread sys_socket_recv(sock, buff, nbytes, flags, true) -> (nread, from_name) Provides an interface to UNIX * recv and * recvfrom for reading messages from the socket sock. buff is a string into which at most nbytes bytes of data will be read (starting at subscript 1). The flags argument is either 0 or one or more of the integer MSG_ constants defined in INCLUDE * UNIX_SOCKETS or'ed together. The number of bytes nread that were actually read is returned. If the last argument is false, this is the only result; otherwise the sender's address from_name is returned as well. sys_socket_send(sock, buff, nbytes, flags, to_name) [procedure] Provides an interface to UNIX * send and * sendto for writing messages to the socket sock. buff is a string from which nbytes bytes of data will be written (starting from subscript 1). The flags argument is either 0 or one or more of the integer MSG_ constants defined in INCLUDE * UNIX_SOCKETS or'ed together. The to_name argument is either the name of the destination to which the message should be sent, or false; in the latter case, the socket must have had a destination assigned with sys_socket_peername. ---------------- 7 Miscellaneous ---------------- sys_socket_option(sock, option) -> bool_or_int [procedure] bool_or_int -> sys_socket_option(sock, option) Provides an interface to UNIX * getsockopt and * setsockopt for accessing and updating socket-level and Internet TCP options on a socket sock. option must be one of the integer SO_ or (for Internet stream sockets) TCP_ contants defined in INCLUDE * UNIX_SOCKETS. With the exception of SO_LINGER, all supported options have either a boolean or an integer value, e.g. sys_socket_option(sock, SO_REUSEADDR) => ** <false> true -> sys_socket_option(sock, SO_REUSEADDR); sys_socket_option(sock, TCP_MAXSEG) => ** 536 For SO_LINGER, the value is false if the linger option is disabled, and an integer timeout value in seconds otherwise: sys_socket_option(sock, SO_LINGER) => ** <false> 1 -> sys_socket_option(sock, SO_LINGER); Options for other protocol levels are not supported. sys_socket_shutdown(sock, how) [procedure] Shuts down all or part of a full-duplex connection on the socket sock. Allowed values for how are how Meaning --- ------- 0 Disallow further reads or receives. 1 Disallow further writes or sends. 2 Disallow both reads and writes. See also UNIX * shutdown sys_socket_name_trans(af) -> trans_p [procedure] trans_p -> sys_socket_name_trans(af) This is a property which maps a given address family af to a procedure-with-updater trans_p for translating between Pop socket names and Unix addresses for that family. By default, only procedures for the AF_UNIX and AF_INET domains are defined. A new procedure trans_p for some other address family must have the form trans_p(name) -> (namebuff, namesize) (namebuff, namesize) -> trans_p() -> name i.e. the base procedure takes a name name and returns namebuff, namesize, while the updater takes namebuff, namesize and returns name. name is whatever Pop object(s) are being used to represent names in the given domain. namebuff and namesize are the external representation (i.e. appropriate sockaddr struct) of the name as supplied to Unix routines such as bind, connect. namebuff should be an "exptr_mem" structure (as produced by * initexptr_mem), and namesize the size in bytes as expected by the Unix routines. See LIB * UNIX_SOCKETS for the corresponding AF_UNIX and AF_INET procedures. +-+ C.unix/ref/sockets +-+ Copyright University of Sussex 1995. All rights reserved.