Index: dart/runtime/bin/socket.cc |
diff --git a/dart/runtime/bin/socket.cc b/dart/runtime/bin/socket.cc |
index dcacf6ac34b1bb42783b03a8e1978a324dbdf84a..a17a678a171fa9ba8583aba907367eb1b1040589 100644 |
--- a/dart/runtime/bin/socket.cc |
+++ b/dart/runtime/bin/socket.cc |
@@ -7,6 +7,7 @@ |
#include "bin/dartutils.h" |
#include "bin/socket.h" |
#include "bin/thread.h" |
+#include "bin/lockers.h" |
#include "bin/utils.h" |
#include "platform/globals.h" |
@@ -17,6 +18,158 @@ |
namespace dart { |
namespace bin { |
+Dart_Handle ListeningSocketRegistry::CreateBindListen(Dart_Handle socket_object, |
+ RawAddr addr, |
+ intptr_t port, |
+ intptr_t backlog, |
+ bool v6_only, |
+ bool shared) { |
+ MutexLocker ml(ListeningSocketRegistry::mutex_); |
+ |
+ SocketsIterator it = sockets_by_port_.find(port); |
+ OSSocket *first_os_socket = NULL; |
+ if (it != sockets_by_port_.end()) { |
+ first_os_socket = it->second; |
+ } |
+ |
+ 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 = it->second; |
+ 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 created the |
Søren Gjesse
2015/01/29 09:05:51
add "originally" after "which"
kustermann
2015/01/29 11:14:05
Done.
|
+ // socket. We therefore increment the refcount and return the file |
+ // descriptor. |
+ os_socket->ref_count++; |
+ |
+ // We set as a side-effect the port on the dart socket_object. |
Søren Gjesse
2015/01/29 09:05:51
port -> file descriptor
kustermann
2015/01/29 11:14:05
Done.
|
+ Socket::SetSocketIdNativeField(socket_object, os_socket->socketfd); |
+ |
+ return Dart_True(); |
+ } |
+ } |
+ |
+ // There is no socket listening on that (address, port), so we create new one. |
+ intptr_t socketfd = ServerSocket::CreateBindListen( |
+ addr, port, backlog, v6_only); |
+ if (socketfd == -5) { |
+ OSError os_error(-1, "Invalid host", OSError::kUnknown); |
+ return DartUtils::NewDartOSError(&os_error); |
+ } |
+ if (socketfd < 0) { |
+ OSError error; |
+ return DartUtils::NewDartOSError(&error); |
+ } |
+ if (!ServerSocket::StartAccept(socketfd)) { |
+ OSError os_error(-1, "Failed to start accept", OSError::kUnknown); |
+ return DartUtils::NewDartOSError(&os_error); |
+ } |
+ intptr_t allocated_port = Socket::GetPort(socketfd); |
+ ASSERT(allocated_port >= 0); |
Søren Gjesse
2015/01/29 09:05:51
'>=' -> '>'
kustermann
2015/01/29 11:14:05
Done.
|
+ |
+ OSSocket *os_socket = |
+ new OSSocket(addr, allocated_port, v6_only, shared, socketfd); |
+ os_socket->ref_count = 1; |
+ os_socket->next = first_os_socket; |
+ sockets_by_port_[allocated_port] = os_socket; |
+ sockets_by_fd_[socketfd] = os_socket; |
+ |
+ // We set as a side-effect the port on the dart socket_object. |
+ Socket::SetSocketIdNativeField(socket_object, socketfd); |
+ |
+ return Dart_True(); |
+} |
+ |
+bool ListeningSocketRegistry::CloseSafe(int socketfd) { |
Søren Gjesse
2015/01/29 09:05:51
Maybe assert that the mutex is actually locked. As
kustermann
2015/01/29 11:14:05
Done.
|
+ SocketsIterator it = sockets_by_fd_.find(socketfd); |
+ if (it != sockets_by_fd_.end()) { |
+ OSSocket *os_socket = it->second; |
+ |
+ ASSERT(os_socket->ref_count > 0); |
+ os_socket->ref_count--; |
+ if (os_socket->ref_count == 0) { |
+ // We free the OS socket by removing it from two datastructures. |
+ sockets_by_fd_.erase(socketfd); |
+ |
+ OSSocket *last = NULL; |
Søren Gjesse
2015/01/29 09:05:51
Rename last to prev?
kustermann
2015/01/29 11:14:05
Done.
|
+ OSSocket *current = sockets_by_port_[os_socket->port]; |
+ while (current != os_socket) { |
+ ASSERT(current != NULL); |
+ last = current; |
+ current = current->next; |
+ } |
+ |
+ if (last == NULL && current->next == NULL) { |
+ sockets_by_port_.erase(os_socket->port); |
+ } else if (last == NULL) { |
+ sockets_by_port_[os_socket->port] = current->next; |
+ } else { |
+ last->next = os_socket->next; |
+ } |
+ |
+ delete os_socket; |
+ return true; |
+ } |
+ return false; |
+ } else { |
+ // It should be impossible for the event handler to close something that |
+ // hasn't been created before. |
+ UNREACHABLE(); |
+ return false; |
+ } |
+} |
+ |
+Dart_Handle ListeningSocketRegistry::MarkSocketFdAsSharableHack(int socketfd) { |
+ MutexLocker ml(ListeningSocketRegistry::mutex_); |
+ |
+ SocketsIterator it = sockets_by_fd_.find(socketfd); |
+ if (it != sockets_by_fd_.end()) { |
+ it->second->shared = true; |
+ return Dart_True(); |
+ } else { |
+ return Dart_False(); |
+ } |
+} |
+ |
+bool ListeningSocketRegistry::addressesAreEqual(const RawAddr& a, |
Søren Gjesse
2015/01/29 09:05:51
Move this as a static on SocketAddress where we ha
|
+ const RawAddr& b) { |
+ if (a.ss.ss_family == AF_INET) { |
+ if (b.ss.ss_family != AF_INET) return false; |
+ return memcmp(&a.in.sin_addr, &b.in.sin_addr, sizeof(a.in.sin_addr)) == 0; |
+ } else if (a.ss.ss_family == AF_INET6) { |
+ if (b.ss.ss_family != AF_INET6) return false; |
+ return memcmp(&a.in6.sin6_addr, |
+ &b.in6.sin6_addr, |
+ sizeof(a.in6.sin6_addr)) == 0; |
+ } else { |
+ UNREACHABLE(); |
+ return false; |
+ } |
+} |
+ |
+ListeningSocketRegistry globalTcpListeningSocketRegistry; |
+ |
static const int kSocketIdNativeField = 0; |
void FUNCTION_NAME(InternetAddress_Parse)(Dart_NativeArguments args) { |
@@ -376,20 +529,12 @@ void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) { |
0, |
65535); |
bool v6_only = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); |
- intptr_t socket = ServerSocket::CreateBindListen( |
- addr, port, backlog, v6_only); |
- OSError error; |
- if (socket >= 0 && ServerSocket::StartAccept(socket)) { |
- Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket); |
- Dart_SetReturnValue(args, Dart_True()); |
- } else { |
- if (socket == -5) { |
- OSError os_error(-1, "Invalid host", OSError::kUnknown); |
- Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error)); |
- } else { |
- Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error)); |
- } |
- } |
+ bool shared = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5)); |
+ |
+ Dart_Handle socket_object = Dart_GetNativeArgument(args, 0); |
+ Dart_Handle result = globalTcpListeningSocketRegistry.CreateBindListen( |
+ socket_object, addr, port, backlog, v6_only, shared); |
+ Dart_SetReturnValue(args, result); |
} |
@@ -678,6 +823,15 @@ void FUNCTION_NAME(Socket_LeaveMulticast)(Dart_NativeArguments args) { |
} |
+void FUNCTION_NAME(Socket_MarkSocketAsSharedHack)(Dart_NativeArguments args) { |
+ intptr_t socketfd = |
+ Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0)); |
+ |
+ Dart_SetReturnValue(args, |
+ globalTcpListeningSocketRegistry.MarkSocketFdAsSharableHack(socketfd)); |
+} |
+ |
+ |
void Socket::SetSocketIdNativeField(Dart_Handle socket, intptr_t id) { |
Dart_Handle err = |
Dart_SetNativeInstanceField(socket, kSocketIdNativeField, id); |