hargettp/courier — pull request #7 by carletes (2014-07-06 15:21:12+00:00)
Title: Socket-based transports: Addresses as URIs

The IPv6 loopback address in my Linux box is usable:
```
$ /sbin/ifconfig lo
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:689459 errors:0 dropped:0 overruns:0 frame:0
TX packets:689459 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:43568922 (43.5 MB) TX bytes:43568922 (43.5 MB)

$ ping6 ::1
PING ::1(::1) 56 data bytes
64 bytes from ::1: icmp_seq=1 ttl=64 time=0.012 ms
64 bytes from ::1: icmp_seq=2 ttl=64 time=0.011 ms
^C
--- ::1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev =0.011/0.011/0.012/0.003 ms
$
```

My `/etc/hosts` file, however, does not resolve `localhost` to an IPv6 address:

```
127.0.0.1 localhost
127.0.1.1 marcelino

# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
```

In this setup the current implementation of `whenIPv6` fails to activate the IPv6 tests, because it assumes that `localhost` must resolve to an IPv6 address in order for IPv6 to be supported:

```haskell
whenIPv6 assn = do
addresses <- lookupAddresses NS.AF_INET6 NS.Stream "localhost:1"
```

My initial workaround was to pass `::1` to `lookupAddresses`, which would resolve to an IPv6 address, regardless of what `localhost` resolves to:

```haskell
whenIPv6 assn = do
addresses <- lookupAddresses NS.AF_INET6 NS.Stream "[::1]:1"
```

Unfortunately the current implementation of `parseSocketAddress` in `Network.Transport.Sockets` assumes a single colon (if any at all) separating the host name from the port, so the snippet above does not work.

Instead of rewriting the address parsing code in `parseSocketAddress`, I've sketched this pull requests, which assumes that `Address` values are URIs, instead of `host:port` pairs. The version of `parseSocketAddress` delegates all the parsing work to `Network.URI.parseURI`.

In this branch I can now run both IPv4 and IPv6 tests:

```
$ sudo sysctl net.ipv6.conf.all.disable_ipv6=0
net.ipv6.conf.all.disable_ipv6 = 0
$

$ cabal build && ./dist/build/test-courier/test-courier
Building courier-0.1.0.15...
Preprocessing library courier-0.1.0.15...
In-place registering courier-0.1.0.15...
Preprocessing test suite 'test-courier' for courier-0.1.0.15...
hunit: [OK]
endpoints: [OK]
mbox-creation: [OK]
mbox-simple-write: [OK]
mbox-write-read: [OK]
mbox-match: [OK]
mbox-find: [OK]
mem-endpoints+transport: [OK]
mem-bind: [OK]
mem-unbind: [OK]
mem-sendReceive: [OK]
mem-transport: [OK]
tcp-endpoints+transport: [OK]
tcp-bind-unbind: [OK]
tcp-send-receive: [OK]
tcp-double-send-receive: [OK]
tcp-send-receive-reply: [OK]
tcp-multiple-send-receive-reply: [OK]
tcp-local-send-receive-reply: [OK]
tcp6-endpoints+transport: [OK]
tcp6-bind-unbind: [OK]
tcp6-send-receive: [OK]
tcp6-double-send-receive: [OK]
tcp6-send-receive-reply: [OK]
tcp6-multiple-send-receive-reply: [OK]
tcp6-local-send-receive-reply: [OK]
udp-endpoints+transport: [OK]
udp-bind-unbind: [OK]
udp-send-receive: [OK]
udp-double-send-receive: [OK]
udp-send-receive-reply: [OK]
udp-multiple-send-receive-reply: [OK]
udp-local-send-receive-reply: [OK]
udp6-endpoints+transport: [OK]
udp6-bind-unbind: [OK]
udp6-send-receive: [OK]
udp6-double-send-receive: [OK]
udp6-send-receive-reply: [OK]
udp6-multiple-send-receive-reply: [OK]
udp6-local-send-receive-reply: [OK]
call-one-hear-call: [OK]
call-one-call-hear: [OK]
call-concurrent-call-hear: [OK]
call-one-handler: [OK]
call-two-handlers: [OK]
gcall-three-handlers: [OK]
call-one-with-timeout: [OK]
gcall-three-handlers-with-timeout: [OK]

Test Cases Total
Passed 48 48
Failed 0 0
Total 48 48
$
```

IPv4-only tests seems to work, too:

```
$ sudo sysctl net.ipv6.conf.all.disable_ipv6=1
net.ipv6.conf.all.disable_ipv6 = 1
$

$ cabal build && ./dist/build/test-courier/test-courier
Building courier-0.1.0.15...
Preprocessing library courier-0.1.0.15...
In-place registering courier-0.1.0.15...
Preprocessing test suite 'test-courier' for courier-0.1.0.15...
hunit: [OK]
endpoints: [OK]
mbox-creation: [OK]
mbox-simple-write: [OK]
mbox-write-read: [OK]
mbox-match: [OK]
mbox-find: [OK]
mem-endpoints+transport: [OK]
mem-bind: [OK]
mem-unbind: [OK]
mem-sendReceive: [OK]
mem-transport: [OK]
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
tcp-endpoints+transport: [OK]
2014-07-06 16:16:46 BST [WARNING] - IPv6 not available
tcp-bind-unbind: [OK]
tcp-send-receive: [OK]
tcp-double-send-receive: [OK]
tcp-send-receive-reply: [OK]
tcp-multiple-send-receive-reply: [OK]
tcp-local-send-receive-reply: [OK]
tcp6-endpoints+transport: [OK]
tcp6-bind-unbind: [OK]
tcp6-send-receive: [OK]
tcp6-double-send-receive: [OK]
tcp6-send-receive-reply: [OK]
tcp6-multiple-send-receive-reply: [OK]
tcp6-local-send-receive-reply: [OK]
udp-endpoints+transport: [OK]
udp-bind-unbind: [OK]
udp-send-receive: [OK]
udp-double-send-receive: [OK]
udp-send-receive-reply: [OK]
udp-multiple-send-receive-reply: [OK]
udp-local-send-receive-reply: [OK]
udp6-endpoints+transport: [OK]
udp6-bind-unbind: [OK]
udp6-send-receive: [OK]
udp6-double-send-receive: [OK]
udp6-send-receive-reply: [OK]
udp6-multiple-send-receive-reply: [OK]
udp6-local-send-receive-reply: [OK]
call-one-hear-call: [OK]
call-one-call-hear: [OK]
call-concurrent-call-hear: [OK]
call-one-handler: [OK]
call-two-handlers: [OK]
gcall-three-handlers: [OK]
call-one-with-timeout: [OK]
gcall-three-handlers-with-timeout: [OK]

Test Cases Total
Passed 48 48
Failed 0 0
Total 48 48
$