Index: runtime/bin/socket.cc |
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc |
index b0e384c8b18487f67f2b0664b0f63c785e6d1306..d5205723cc8c52d9831b09efafc93658ce30c9ad 100644 |
--- a/runtime/bin/socket.cc |
+++ b/runtime/bin/socket.cc |
@@ -101,44 +101,48 @@ Dart_Handle ListeningSocketRegistry::CreateBindListen(Dart_Handle socket_object, |
intptr_t backlog, |
bool v6_only, |
bool shared) { |
- MutexLocker ml(ListeningSocketRegistry::mutex_); |
+ MutexLocker ml(mutex_); |
+ OSSocket* first_os_socket = NULL; |
intptr_t port = SocketAddress::GetAddrPort(addr); |
- OSSocket* first_os_socket = LookupByPort(port); |
- if (first_os_socket != NULL) { |
- // There is already a socket listening on this port. We need to ensure |
- // that if there is one also listening on the same address, it was created |
- // with `shared = true`, ... |
- OSSocket* os_socket = first_os_socket; |
- OSSocket* os_socket_same_addr = findOSSocketWithAddress(os_socket, addr); |
- |
- if (os_socket_same_addr != NULL) { |
- if (!os_socket_same_addr->shared || !shared) { |
- OSError os_error(-1, |
- "The shared flag to bind() needs to be `true` if " |
- "binding multiple times on the same (address, port) " |
- "combination.", |
- OSError::kUnknown); |
- return DartUtils::NewDartOSError(&os_error); |
- } |
- if (os_socket_same_addr->v6_only != v6_only) { |
- OSError os_error(-1, |
- "The v6Only flag to bind() needs to be the same if " |
- "binding multiple times on the same (address, port) " |
- "combination.", |
- OSError::kUnknown); |
- return DartUtils::NewDartOSError(&os_error); |
+ if (port > 0) { |
+ first_os_socket = LookupByPort(port); |
+ if (first_os_socket != NULL) { |
+ // There is already a socket listening on this port. We need to ensure |
+ // that if there is one also listening on the same address, it was created |
+ // with `shared = true`, ... |
+ OSSocket* os_socket = first_os_socket; |
+ OSSocket* os_socket_same_addr = findOSSocketWithAddress(os_socket, addr); |
+ |
+ if (os_socket_same_addr != NULL) { |
+ if (!os_socket_same_addr->shared || !shared) { |
+ OSError os_error(-1, |
+ "The shared flag to bind() needs to be `true` if " |
+ "binding multiple times on the same (address, port) " |
+ "combination.", |
+ OSError::kUnknown); |
+ return DartUtils::NewDartOSError(&os_error); |
+ } |
+ if (os_socket_same_addr->v6_only != v6_only) { |
+ OSError os_error(-1, |
+ "The v6Only flag to bind() needs to be the same if " |
+ "binding multiple times on the same (address, port) " |
+ "combination.", |
+ OSError::kUnknown); |
+ return DartUtils::NewDartOSError(&os_error); |
+ } |
+ |
+ // This socket creation is the exact same as the one which originally |
+ // created the socket. We therefore increment the refcount and reuse |
+ // the file descriptor. |
+ os_socket->ref_count++; |
+ |
+ // We set as a side-effect the file descriptor on the dart |
+ // socket_object. |
+ Socket::SetSocketIdNativeField(socket_object, os_socket->socketfd); |
+ |
+ return Dart_True(); |
} |
- |
- // This socket creation is the exact same as the one which originally |
- // created the socket. We therefore increment the refcount and reuse |
- // the file descriptor. |
- os_socket->ref_count++; |
- |
- // We set as a side-effect the file descriptor on the dart socket_object. |
- Socket::SetSocketIdNativeField(socket_object, os_socket->socketfd); |
- |
- return Dart_True(); |
} |
} |
@@ -159,6 +163,24 @@ Dart_Handle ListeningSocketRegistry::CreateBindListen(Dart_Handle socket_object, |
intptr_t allocated_port = Socket::GetPort(socketfd); |
ASSERT(allocated_port > 0); |
+ if (allocated_port != port) { |
+ // There are two cases to consider: |
+ // |
+ // a) The user requested (address, port) where port != 0 which means |
+ // we re-use an existing socket if available (and it is shared) or we |
+ // create a new one. The new socket is guaranteed to have that |
+ // selected port. |
+ // |
+ // b) The user requested (address, 0). This will make us *always* create a |
+ // new socket. The OS will assign it a new `allocated_port` and we will |
+ // insert into our data structures. *BUT* There might already be an |
+ // existing (address2, `allocated_port`) where address != address2. So |
+ // we need to do another `LookupByPort(allocated_port)` and link them |
+ // via `OSSocket->next`. |
+ ASSERT(port == 0); |
+ first_os_socket = LookupByPort(allocated_port); |
+ } |
+ |
OSSocket* os_socket = |
new OSSocket(addr, allocated_port, v6_only, shared, socketfd); |
os_socket->ref_count = 1; |