Timelessness

Proxy support for Java SocketChannel

Mon, May 18, 2015

Java, as early as version 1.4, added non-blocking IO (or NIO for short). A core component for non-blocking IO is the SocketChannel. This is the replacement for the Socket in the earlier blocking IO implementation. Unlike Socket, however, SocketChannel has never been given support for establishing connections that go through a (SOCKS) proxy. With NIO it is currently impossible to set up SocketChannel connections via a proxy server. This is possible with the “good old” Socket: Socket has a constructor that accepts a Proxy instance. This instance contains all the connection information for setting up a client connection to a proxy server.

As I was looking into supporting connections via proxy server in irc-api, a Java IRC client library, I discovered that this is not supported. I was actually quite surprised that proxy (client) support has never been added to SocketChannel and from what I could gather from other websites, there is no real solution other than to fall back to a plain Socket. Falling back to Socket is possible, but that also means regressing to the older, blocking IO framework. This would likely lead to significant changes in the way the library is implemented and basically a regression in technical capabilities. (That is assuming one considers non-blocking IO an improvement over blocking IO, of course.)

I have rolled out my own implementation of a SocketChannel that does support proxy connections. This alternative SocketChannel implementation is backed by a Socket and builds on top of that in order to provide the features that SocketChannel specifies. All available connection options have been implemented and the backing socket’s timeout is preconfigured to be ‘0’, i.e. no timeout, since there is no connection option for this. SocketChannel operates on infinite timeout, i.e. it never times out, by default.

For now the implementation only supports blocking connections, which is the default mode in which SocketChannel operates anyway. Making the switch to the non-blocking mode of operation is currently not supported and will throw an UnsupportedOperationException if called. I am looking into supporting this with minimal overhead.