The Scheme Shell provides a BSD-style sockets interface. There is not an official standard for a network interface for scsh to adopt (this is the subject of the forthcoming Posix.8 standard). However, Berkeley sockets are a de facto standard, being found on most Unix workstations and PC operating systems.
It is fairly straightforward to add higher-level network protocols such as smtp, telnet, or http on top of the the basic socket-level support scsh provides. The Scheme Underground has also released a network library with many of these protocols as a companion to the current release of scsh. See this code for examples showing the use of the sockets interface.
For convenience, and to avoid some of the messy details of the socket interface, we provide a high level socket interface. These routines attempt to make it easy to write simple clients and servers without having to think of many of the details of initiating socket connections. We welcome suggested improvements to this interface, including better names, which right now are solely descriptions of the procedure's action. This might be fine for people who already understand sockets, but does not help the new networking programmer.
socket-connect is intended for creating client applications. protocol-family is specified as either the protocol-family/internet or protocol-family/unix. socket-type is specified as either socket-type/stream or socket-type/datagram. See socket for a more complete description of these terms.
The variable args list is meant to specify protocol family specific information. For Internet sockets, this consists of two arguments: a host name and a port number. For Unix sockets, this consists of a pathname.
socket-connect returns a socket which can be used for input and output from a remote server. See socket for a description of the socket record.
bind-listen-accept-loop is intended for creating server applications. protocol-family is specified as either the protocol-family/internet or protocol-family/unix. proc is a procedure of two arguments: a socket and a socket-address. arg specifies a port number for Internet sockets or a pathname for Unix sockets. See socket for a more complete description of these terms.
proc is called with a socket and a socket address each time there is a connection from a client application. The socket allows communications with the client. The socket address specifies the address of the remote client.
This procedure does not return, but loops indefinitely accepting connections from client programs.
Same as bind-listen-accept-loop but runs the thunk prepare after binding the address and before entering the loop. The typical task of the prepare procedure is to change the user id from the superuser to some unprivileged id once the address has been bound.
A socket is one end of a network connection. Three specific properties of sockets are specified at creation time: the protocol-family, type, and protocol.
The protocol-family specifies the protocol family to be used with the socket. This also determines the address family of socket addresses, which are described in more detail below. Scsh currently supports the Unix internal protocols and the Internet protocols using the following constants:
The type specifies the style of communication. Examples that your operating system probably provides are stream and datagram sockets. Others maybe available depending on your system. Typical values are:
The protocol specifies a particular protocol to use within a protocol family and type. Usually only one choice exists, but it's probably safest to set this explicitly. See the protocol database routines for information on looking up protocol constants.
New sockets are typically created with create-socket. However, create-socket-pair can also be used to create a pair of connected sockets in the protocol-family/unix protocol-family. The value of a returned socket is a socket record, defined to have the following structure:
family ; protocol family
inport ; input-port
outport) ; output-port
The family specifies the protocol family of the socket. The inport and outport fields are ports that can be used for input and output, respectively. For a stream socket, they are only usable after a connection has been established via connect-socket or accept-connection. For a datagram socket, outport can be immediately using send-message, and inport can be used after bind has created a local address.
close-socket provides a convenient way to close a socket's port. It is preferred to explicitly closing the inport and outport because using close on sockets is not currently portable across operating systems.
This procedure turns port into a socket object. The port's underlying file descriptor must be a socket with protocol family protocol-family. port->socket applies dup->inport and dup->outport to port to create the ports of the socket object.
port->socket comes in handy for writing servers which run as children of inetd: after receiving a connection inetd creates a socket and passes it as standard input to its child.
The format of a socket-address depends on the address family of the socket. Address-family-specific routines are provided to convert protocol-specific addresses to socket addresses. The value returned by these routines is a socket-address record, defined to have the following visible structure:
family) ; address family
The family is one of the following constants:
unix-address->socket-address returns a socket-address based on the string pathname. There is a system dependent limit on the length of pathname.
internet-address->socket-address returns a socket-address based on an integer host-address and an integer service-port. Besides being a 32-bit host address, an Internet host address can also be one of the following constants:
The use of internet-address/any is described below in bind-socket. internet-address/loopback is an address that always specifies the local machine. internet-address/broadcast is used for network broadcast communications.
For information on obtaining a host's address, see the host-info function.
The routines socket-address->internet-address and socket-address->unix-address return the address-family-specific addresses. Be aware that most implementations don't correctly return anything more than an empty string for addresses in the Unix address-family.
The procedures in this section are presented in the order in which a typical program will use them. Consult a text on network systems programming for more information on sockets.12 The last two tutorials are freely available as part of BSD. In the absence of these, your Unix manual pages for socket might be a good starting point for information.
connect-socket sets up a connection from a socket to a remote socket-address. A connection has different meanings depending on the socket type. A stream socket must be connected before use. A datagram socket can be connected multiple times, but need not be connected at all if the remote address is specified with each send-message, described below. Also, datagram sockets may be disassociated from a remote address by connecting to a null remote address.
Just like connect-socket, connect-socket-no-wait sets up a connection from a socket to a remote socket-address. Unlike connect-socket, connect-socket-no-wait does not block if it cannot establish the connection immediately. Instead it will return #f at once. In this case a subsequent select on the output port of the socket will report the output port as ready as soon as the operation system has established the connection or as soon as setting up the connection led to an error. Afterwards, the procedure connect-socket-successful? can be used to test whether the connection has been established successfully or not.
bind-socket assigns a certain local socket-address to a socket. Binding a socket reserves the local address. To receive connections after binding the socket, use listen-socket for stream sockets and receive-message for datagram sockets.
Binding an Internet socket with a host address of internet-address/any indicates that the caller does not care to specify from which local network interface connections are received. Binding an Internet socket with a service port number of zero indicates that the caller has no preference as to the port number assigned.
Binding a socket in the Unix address family creates a socket special file in the file system that must be deleted before the address can be reused. See delete-file.
listen-socket allows a stream socket to start receiving connections, allowing a queue of up to backlog connection requests. Queued connections may be accepted by accept-connection.
accept-connection receives a connection on a socket, returning a new socket that can be used for this connection and the remote socket address associated with the connection.
Sockets can be associated with a local address or a remote address or both. socket-local-address returns the local socket-address record associated with socket. socket-remote-address returns the remote socket-address record associated with socket.
shutdown-socket shuts down part of a full-duplex socket. The method of shutting done is specified by the how-to argument, one of:
For most uses, standard input and output routines such as read-string and write-string should suffice. However, in some cases an extended interface is required. The receive-message and send-message calls parallel the read-string and write-string calls with a similar naming scheme.
One additional feature of these routines is that receive-message returns the remote socket-address and send-message takes an optional remote socket-address. This allows a program to know the source of input from a datagram socket and to use a datagram socket for output without first connecting it.
All of these procedures take an optional flags field. This argument is an integer bit-mask, composed by or'ing together the following constants:
See read-string and write-string for a more detailed description of the arguments and return values.
socket-option and set-socket-option allow the inspection and modification, respectively, of several options available on sockets. The level argument specifies what protocol level is to be examined or affected. A level of level/socket specifies the highest possible level that is available on all socket types. A specific protocol number can also be used as provided by protocol-info, described below.
There are several different classes of socket options. The first class consists of boolean options which can be either true or false. Examples of this option type are:
Value options are another category of socket options. Options of this type are an integer value. Examples of this option type are:
A third option type specifies how long for data to linger after a socket has been closed. There is only one option of this type: socket/linger. It is set with either #fto disable it or an integer number of seconds to linger and returns a value of the same type upon inspection.
The fourth and final option type of this time is a timeout option. There are two examples of this option type: socket/send-timeout and socket/receive-timeout. These are set with a real number of microseconds resolution and returns a value of the same type upon inspection.
host-info allows a program to look up a host entry based on either its string name or socket-address. The value returned by this routine is a host-info record, defined to have the following structure:
name ; Host name
aliases ; Alternative names
addresses) ; Host addresses
host-info could fail and raise an error for one of the following reasons:
network-info allows a program to look up a network entry based on either its string name or socket-address. The value returned by this routine is a network-info record, defined to have the following structure:
name ; Network name
aliases ; Alternative names
net) ; Network number
service-info allows a program to look up a service entry based on either its string name or integer port. The value returned by this routine is a service-info record, defined to have the following structure:
name ; Service name
aliases ; Alternative names
port ; Port number
protocol) ; Protocol name
protocol-info allows a program to look up a protocol entry based on either its string name or integer number. The value returned by this routine is a protocol-info record, defined to have the following structure:
name ; Protocol name
aliases ; Alternative names
number) ; Protocol number)
network-info, service-info and protocol-info return #fif the specified entity was not found.
12 Some recommended ones are:
``Unix Network Programming'' by W. Richard Stevens
``An Introductory 4.3BSD Interprocess Communication Tutorial.'' (reprinted in UNIX Programmer's Supplementary Documents Volume 1, PS1:7)
``An Advanced 4.3BSD Interprocess Communication Tutorial.'' (reprinted in UNIX Programmer's Supplementary Documents Volume 1, PS1:8)