Networking

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.

4.1  High-level 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 protocol-family socket-type . args)     --->     socket         (procedure) 
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 protocol-family proc arg)     --->     does-not-return         (procedure) 
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.

(bind-prepare-listen-accept-loop protocol-family prepare proc arg)     --->     does-not-return         (procedure) 
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.

4.2  Sockets

(create-socket protocol-family type [protocol])     --->     socket         (procedure) 
(create-socket-pair type)     --->     [socket1 socket2]         (procedure) 
(close-socket socket)     --->     undefined         (procedure) 

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:


protocol-family/unspecified
protocol-family/unix
protocol-family/internet

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:


socket-type/stream
socket-type/datagram
socket-type/raw

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:


(define-record socket
  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.

(port->socket port protocol-family)     --->     socket         (procedure) 
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.

4.3  Socket addresses

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:


(define-record socket-address
  family)                               ; address family

The family is one of the following constants:


address-family/unspecified
address-family/unix
address-family/internet

(unix-address->socket-address pathname)     --->     socket-address         (procedure) 
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 host-address service-port)     --->     socket-address         (procedure) 
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:

internet-address/any
internet-address/loopback
internet-address/broadcast

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.

(socket-address->unix-address socket-address)     --->     pathname         (procedure) 
(socket-address->internet-address socket-address)     --->     [host-address service-port]         (procedure) 

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.

4.4  Socket primitives

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 socket socket-address)     --->     undefined         (procedure) 
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.

(connect-socket-no-wait socket socket-address)     --->     boolean         (procedure) 
(connect-socket-successful? socket)     --->     boolean         (procedure) 
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 socket socket-address)     --->     undefined         (procedure) 
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 socket backlog)     --->     undefined         (procedure) 
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 socket)     --->     [new-socket socket-address]         (procedure) 
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.

(socket-local-address socket)     --->     socket-address         (procedure) 
(socket-remote-address socket)     --->     socket-address         (procedure) 
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 socket how-to)     --->     undefined         (procedure) 

shutdown-socket shuts down part of a full-duplex socket. The method of shutting done is specified by the how-to argument, one of:


shutdown/receives
shutdown/sends
shutdown/sends+receives

4.5  Performing input and output on sockets

(receive-message socket length [flags])     --->     [string-or-#f socket-address]         (procedure) 
(receive-message! socket string [start] [end] [flags])     --->     [count-or-#f socket-address]         (procedure) 
(receive-message/partial socket length [flags])     --->     [string-or-#f socket-address]         (procedure) 
(receive-message!/partial socket string [start] [end] [flags])     --->     [count-or-#f socket-address]         (procedure) 

(send-message socket string [start] [end] [flags] [socket-address])     --->     undefined         (procedure) 
(send-message/partial socket string [start] [end] [flags] [socket-address])     --->     count         (procedure) 

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:


message/out-of-band
message/peek
message/dont-route

See read-string and write-string for a more detailed description of the arguments and return values.

4.6  Socket options

(socket-option socket level option)     --->     value         (procedure) 
(set-socket-option socket level option value)     --->     undefined         (procedure) 

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:


socket/debug
socket/accept-connect
socket/reuse-address
socket/keep-alive
socket/dont-route
socket/broadcast
socket/use-loop-back
socket/oob-inline
socket/use-privileged
socket/cant-signal
tcp/no-delay

Value options are another category of socket options. Options of this type are an integer value. Examples of this option type are:


socket/send-buffer
socket/receive-buffer
socket/send-low-water
socket/receive-low-water
socket/error
socket/type
ip/time-to-live
tcp/max-segment

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.

4.7  Database-information entries

(host-info name-or-socket-address)     --->     host-info         (procedure) 
(network-info name-or-socket-address)     --->     network-info or #f         (procedure) 
(service-info name-or-number [protocol-name])     --->     service-info or #f         (procedure) 
(protocol-info name-or-number)     --->     protocol-info or #f         (procedure) 

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:


(define-record host-info
  name                                  ; Host name
  aliases                               ; Alternative names
  addresses)                            ; Host addresses

host-info could fail and raise an error for one of the following reasons:


herror/host-not-found
herror/try-again
herror/no-recovery
herror/no-data
herror/no-address

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:


(define-record network-info
  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:


(define-record service-info
  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:


(define-record protocol-info
  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: