Saturday, July 21, 2007

Support for IPv6 and Unix domain sockets

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.

1 comment:

Anonymous said...

very cool!