Posts Tagged ‘ Address already in use exception ’

Socket bind exception on Red5 restart

This one is a gem. We’re using Red5 as flash server for several of our projects and one annoying problem that we encountered were thrown exceptions on Red5 restart. Specifically, Address already in use exception which signals that a socket is still being used. The culprit is socket bound to 1935 port which is used for rtmp traffic between flash clients and Red5. That socket remained in TIME_WAIT state even after Red5 was shutdown.

Now, it is important to note that tcp connections should be closed properly in order to avoid this sort of problems, but this is not always possible (unexpected server shutdown, bug which makes server unresponsive, etc.). Brief discussion about proper tcp handling is here. I know from experience that other servers (for example Tomcat) don’t have this problem with socket binding (at least not in the last ~5 years) and I was curious why Red5 developers haven’t solved this. The thing to do to avoid this is to set SO_REUSEADDR flag on the socket. This means that other processes can bind to this socket if it is in TIME_WAIT state. Fortunately, Red5 is open source, so I browsed a bit and found this in RTMPMinaTransport class :

acceptor = new NioSocketAcceptor(ioThreads);
acceptor.setHandler(ioHandler);
acceptor.setBacklog(100);

log.info(“TCP No Delay: {}”, tcpNoDelay);
log.info(“Receive Buffer Size: {}”, receiveBufferSize);
log.info(“Send Buffer Size: {}”, sendBufferSize);

SocketSessionConfig sessionConf = (SocketSessionConfig) acceptor.getSessionConfig();
sessionConf.setReuseAddress(true);
sessionConf.setTcpNoDelay(tcpNoDelay);
sessionConf.setReceiveBufferSize(receiveBufferSize);
sessionConf.setSendBufferSize(sendBufferSize);

Interesting enough, they do set this flag as I’ve shown with the bolded line. So I’ve tried debugging the code and after some time I’ve found out, that SocketSessionConfig is never read, never used. I will repeat this : SocketSessionConfig is never accessed. That part of the code could as well be removed. The solution is simple, flag must be set directly on NioSocketAcceptor and then the socket can be bound on restart without a problem:

acceptor = new NioSocketAcceptor(ioThreads);
acceptor.setHandler(ioHandler);
acceptor.setBacklog(100);
acceptor.setReuseAddress(true);

I’ve added the bolded line and compiled the source. With new red5.jar, restarting works like a charm.