From b2618e5cbc184491e4691bcb383b9669d82a725c Mon Sep 17 00:00:00 2001 From: DRC Date: Mon, 21 Feb 2011 13:43:44 +0000 Subject: Using a fixed port range with -via can cause a race condition between multiple vncviewer instances, whereby one instance calls bind() and finds the port to be free, then another instance calls bind() and finds the same port to be free, because the first instance hasn't started the SSH tunnel on it yet. This patch works around the issue by using ephemeral ports. All known modern O/S's increment the ephemeral port number by 1 after bind(), so the port is effectively "reserved" after bind(), and this prevents another vncviewer instance from trying to reserve the same port. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4303 3789f03b-4d11-0410-bbf8-ca57d06f2519 --- common/network/TcpSocket.cxx | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'common') diff --git a/common/network/TcpSocket.cxx b/common/network/TcpSocket.cxx index 8bd817c4..04e08950 100644 --- a/common/network/TcpSocket.cxx +++ b/common/network/TcpSocket.cxx @@ -71,7 +71,7 @@ static rfb::LogWriter vlog("TcpSocket"); /* Tunnelling support. */ int network::findFreeTcpPort (void) { - int sock, port; + int sock; struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; @@ -80,15 +80,16 @@ int network::findFreeTcpPort (void) if ((sock = socket (AF_INET, SOCK_STREAM, 0)) < 0) throw SocketException ("unable to create socket", errorNumber); - for (port = TUNNEL_PORT_OFFSET + 99; port > TUNNEL_PORT_OFFSET; port--) { - addr.sin_port = htons ((unsigned short) port); - if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) == 0) { - closesocket (sock); - return port; - } - } - throw SocketException ("no free port in range", 0); - return 0; + addr.sin_port = 0; + if (bind (sock, (struct sockaddr *)&addr, sizeof (addr)) < 0) + throw SocketException ("unable to find free port", errorNumber); + + socklen_t n = sizeof(addr); + if (getsockname (sock, (struct sockaddr *)&addr, &n) < 0) + throw SocketException ("unable to get port number", errorNumber); + + closesocket (sock); + return ntohs(addr.sin_port); } -- cgit v1.2.3