Support for IPv6 and Unix domain sockets
Saturday, July 21, 2007
Some very new code, not completely tested.
The <client>
and <server>
words used to take a host/port pair, and a
port number, respectively. This was too limiting. Now both words take
address specifiers, of which are there four types:
"/path/to/socket" <local>
- an IPC socket with the given path (Unix domain sockets on Unix)"dotted.quad" 123 <inet4>
- an IPv4 address"ipv6.addr" 1234 <inet6>
- an IPv6 address"hostname" "http" <inet>
- Internet host named by DNS entry; will be either IPv4 or IPv6
Note that in most cases, <client>
will be called with an instance of
inet
; this invokes the domain name resolver, which may produce a list
of multiple IPv4 and IPv6 addresses. Factor tries each one in turn until
a connection succeeds. This is the expected behavior for client sockets,
since users generally input host names and not IP addresses, and don’t
care if the connection is made over IPv4 or IPv6.
The <server>
word requires an instance of the more specific inet4
and inet6
classes. Since in most cases, a server interested in
connections on, say, port 8080 wants to receive connections over both
IPv4 and IPv6, the with-server
combinator should be used instead of
calling <server>
directly. Here’s a usage example which waits for
connections on port 8080 and sends “Hello, client” to each one:
8080 internet-server [ "Hello, client." print ] with-server
If your system is configured for IPv6, this example will spawn two threads, for IPv4 and IPv6 connections.
Server sockets can now be restricted to the loopback network interface
by passing 8080 local-server
instead of 8080 internet-server
. Before
this was provided by the Unix-only loopback-server
module; this module
is now obsolete.
The domain name resolver can now be invoked directly with the
resolve-host
word. Given a host name and port name or number, it
returns a list of address specifiers.
UDP/IP works as before; words which used to take host/port pairs now
take address specifiers. Note that the inet
address specifier is not
supported for UDP/IP; clients must first resolve the destination host
name, and pick the appropriate address specifier, whether it be an IPv4
or IPv6 address, from the result.
Unix domain sockets are accessed with the local
address specifier.
Stream Unix domain sockets are very commonly used, but a little-known fact is that datagram Unix domain sockets are supported too. Here is some proof.
Enter this in one listener:
"/tmp/dgram-dst" <local> <datagram>
dup receive
stream-close
Then this in another:
"/tmp/dgram-src" <local> <datagram>
B{ 1 2 3 4 5 } "/tmp/dgram-dst" <local> pick send
stream-close
The first machine should now have the following two objects on the stack:
B{ 1 2 3 4 }
T{ local f "/tmp/dgram-src" }
I still have to fix assorted bugs in this code. Also Windows network support is lagging; not only does it have to be updated to support address specifiers, but it is also missing UDP hooks at this stage.
I won’t be adding more features to networking for a little while, but the next thing I will do is probably raw sockets.