Friday, April 30, 2010

ICE becomes RFC 5245

Interactive Connectivity Establishment (ICE) is a protocol for Network Address Translator (NAT) traversal for offer/answer protocols. The Internet Engineering Task Force (IETF) recently approved it as RFC 5245.

Saturday, April 10, 2010

Reusing TCP Connections: "address already in use"

The socket option SO_REUSEADDR is useful for binding a socket to a port that is already in use by another socket. But even if you are successful in binding the socket, it does not mean you will not get the "address already in use" error later with that socket.

Consider a case where you want to connect from a fixed source port (srcport) and IP (srcip) to a fixed destination port (dstport) and IP (dstip) using TCP. A TCP connection is basically a 5-tuple (srcip, srcport, dstip, dstport, protocol).
The first attempt with connect() succeeds and the connection is established.
But, depending on your OS configuration, you may not be able to establish the same connection again for a while, even if you close the first connection. Even though you may succeed with SO_REUSEADDR binding the (srcip, srcport, TCP) 3-tuple, your connect() call will fail to establish the 5-tuple.

This is a very unlikely use-case because usually, clients do not need to use the same srcport in a subsequent connection. But I encountered this problem when I was developing an ICE-TCP library for a client who wanted to specify a fixed port to be used in the SDP generated by the library. In this case, there is a chance that the same fixed port will be specified for a call after the previous call ends.

This problem arises from the TIME_WAIT state of TCP.

To get around this problem, you need to "hard close" the first connection (as opposed to "graceful shutdown"). For this, set the option SO_LINGER to the socket of the first connection, with a linger timeout of zero. Then when you want to close the connection, DO NOT call shutdown(). Call only closesocket(). If you call shutdown(), a graceful shutdown is initiated with the [FIN, ACK, FIN, ACK] sequence, which ultimately leads to the stuck TIME_WAIT state.

So, in summary, if you desparately need to reuse a TCP connection 5-tuple and want to avoid the "address already in use" problem, use SO_REUSEADDR, SO_LINGER and closesocket(), and avoid shutdown().

To know more about the TIME_WAIT state and other details, check out the following links:
http://www.developerweb.net/forum/showthread.php?t=2941
http://hea-www.harvard.edu/~fine/Tech/addrinuse.html

Sunday, April 4, 2010

Reusing Ports: Socket Option SO_REUSEADDR

Recently, I came across a situation where I had to bind the same port to multiple sockets. I am just going to write some brief notes about this.

Is it possible to bind multiple sockets to the same port?
Yes, it is possible.

How?
There is a socket option for this, called SO_REUSEADDR.

Why would someone want to reuse a port?
This option is sometimes needed. For example,
  1. Suppose you have restriction on the number of ports you can use. Then you may want to use the same port for connecting to different destinations.
  2. The original use case for this option occurs when a socket is closed. It may "linger" for a while, because there is still unsent data in the buffer. So you cannot use (bind to) that port right away after the socket is closed. So you can set SO_REUSEADDR on that socket, if you think the port needs to be usable right away after closing a previously bound socket.

Can I prevent a port from being reused or hijacked?
Yes, you can.
In Linux, if you do not set SO_REUSEADDR on a socket, the port bound to that socket cannot be rebound by another socket.
But in Windows, even if you do not set SO_REUSEADDR, that port can be bound to another socket if the second socket sets SO_REUSEADDR before bind!
In order to prevent this, Windows provides another option called SO_EXCLUSIVEADDRUSE. When this option is set on a socket, the port bound to that socket cannot be reused by another socket.

Example problem
I would like to bind any free port to socket S1. Then I would like to bind that specific port to socket S2 as well.

Solution
  1. Bind any free port to S1 (specifying zero for port does this).
  2. Set socket option SO_REUSEADDR to S1 (Do not set this before binding, so that an unused port is guaranteed to be bound to S1 in step 1).
  3. Find out the port number P that is bound to S1 (getsockname can be used for this).
  4. Set socket option SO_REUSEADDR to S2 (Some OS may not need this step. But it does not do any harm to do it anyway).
  5. Bind the specific port P to socket S2.