Index: runtime/bin/socket.cc |
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc |
index 175d07e6a5f7a9e4608a4e177d39a3251f7c2718..7665d5ef1d5cbe55accf2afb9fa4d28672b937c1 100644 |
--- a/runtime/bin/socket.cc |
+++ b/runtime/bin/socket.cc |
@@ -25,6 +25,8 @@ int Socket::service_ports_size_ = 0; |
Dart_Port* Socket::service_ports_ = NULL; |
int Socket::service_ports_index_ = 0; |
+// TODO(sgjesse): Make this thread local. |
+unsigned int rand_r_state = 0; |
static void GetSockAddr(Dart_Handle obj, RawAddr* addr) { |
Dart_TypedData_Type data_type; |
@@ -33,6 +35,9 @@ static void GetSockAddr(Dart_Handle obj, RawAddr* addr) { |
Dart_Handle result = Dart_TypedDataAcquireData( |
obj, &data_type, reinterpret_cast<void**>(&data), &len); |
if (Dart_IsError(result)) Dart_PropagateError(result); |
+ if (data_type != Dart_TypedData_kUint8) { |
+ Dart_PropagateError(Dart_NewApiError("Unexpected type for socket address")); |
+ } |
memmove(reinterpret_cast<void *>(addr), data, len); |
Dart_TypedDataReleaseData(obj); |
} |
@@ -117,6 +122,27 @@ void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) { |
} |
} |
+void FUNCTION_NAME(Socket_CreateBindDatagram)(Dart_NativeArguments args) { |
+ RawAddr addr; |
+ GetSockAddr(Dart_GetNativeArgument(args, 1), &addr); |
+ int64_t port = DartUtils::GetInt64ValueCheckRange( |
+ Dart_GetNativeArgument(args, 2), |
+ 0, |
+ 65535); |
+ intptr_t socket = Socket::CreateBindDatagram( |
+ &addr, |
+ port, |
+ DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3))); |
+ OSError error; |
Anders Johnsen
2013/11/29 12:36:54
Unused?
Søren Gjesse
2013/12/12 11:38:46
Yes, removed.
|
+ if (socket >= 0) { |
+ Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket); |
+ Dart_SetReturnValue(args, Dart_True()); |
+ } else { |
+ OSError error; |
+ Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error)); |
+ } |
+} |
+ |
void FUNCTION_NAME(Socket_Available)(Dart_NativeArguments args) { |
intptr_t socket = |
@@ -182,6 +208,79 @@ void FUNCTION_NAME(Socket_Read)(Dart_NativeArguments args) { |
} |
+void FUNCTION_NAME(Socket_RecvFrom)(Dart_NativeArguments args) { |
+ static bool drop_datagrams = Dart_IsVMFlagSet("drop_datagrams"); |
+ intptr_t socket = |
+ Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0)); |
+ |
+ // TODO(sgjesse): This needs to be 64k as that is the max UDP packet size. |
+ uint8_t buffer[4096]; |
+ RawAddr addr; |
+ intptr_t bytes_read = Socket::RecvFrom(socket, buffer, 4096, &addr); |
+ Dart_Handle err; |
+ if (bytes_read > 0) { |
+ uint8_t* data_buffer = NULL; |
+ Dart_Handle data = IOBuffer::Allocate(bytes_read, &data_buffer); |
+ if (Dart_IsError(data)) Dart_PropagateError(data); |
+ ASSERT(data_buffer != NULL); |
+ memmove(data_buffer, buffer, bytes_read); |
+ |
+ // Get the port and clear it in the sockaddr structure. |
+ int port = SocketAddress::GetAddrPort(&addr); |
+ if (addr.addr.sa_family == AF_INET) { |
+ addr.in.sin_port = 0; |
+ } else { |
+ ASSERT(addr.addr.sa_family == AF_INET6); |
+ addr.in6.sin6_port = 0; |
+ } |
+ // Format the address to a string using the numeric format. |
+ char numeric_address[INET6_ADDRSTRLEN]; |
+ Socket::FormatNumericAddress(&addr, numeric_address, INET6_ADDRSTRLEN); |
+ |
+ // Create a Datagram object with the data and sender address and port. |
+ const int kNumArgs = 5; |
+ Dart_Handle dart_args[kNumArgs]; |
+ dart_args[0] = data; |
+ dart_args[1] = Dart_NewBoolean(addr.addr.sa_family == AF_INET6); |
+ dart_args[2] = Dart_NewStringFromCString(numeric_address); |
+ if (Dart_IsError(dart_args[2])) Dart_PropagateError(dart_args[2]); |
+ int len = SocketAddress::GetAddrLength(&addr); |
+ dart_args[3] = Dart_NewTypedData(Dart_TypedData_kUint8, len); |
+ if (Dart_IsError(dart_args[3])) Dart_PropagateError(dart_args[3]); |
+ err = Dart_ListSetAsBytes( |
+ dart_args[3], 0, reinterpret_cast<uint8_t *>(&addr), len); |
+ if (Dart_IsError(err)) Dart_PropagateError(err); |
+ dart_args[4] = Dart_NewInteger(port); |
+ if (Dart_IsError(dart_args[4])) Dart_PropagateError(dart_args[4]); |
+ // TODO(sgjesse): Cache the _makeDatagram function somewhere. |
+ Dart_Handle io_lib = |
+ Dart_LookupLibrary(DartUtils::NewString("dart:io")); |
+ if (Dart_IsError(io_lib)) Dart_PropagateError(io_lib); |
+ Dart_Handle result = |
+ Dart_Invoke(io_lib, |
+ DartUtils::NewString("_makeDatagram"), |
+ kNumArgs, |
+ dart_args); |
+ if (Dart_IsError(result)) Dart_PropagateError(result); |
+ if (drop_datagrams) { |
Anders Johnsen
2013/11/29 12:36:54
Drop earlier?
Søren Gjesse
2013/12/12 11:38:46
Done.
|
+ int random = rand_r(&rand_r_state); |
+ if (random > (RAND_MAX / 2)) { |
+ Dart_SetReturnValue(args, result); |
+ } else { |
+ Dart_SetReturnValue(args, Dart_Null()); |
+ } |
+ } else { |
+ Dart_SetReturnValue(args, result); |
+ } |
+ } else if (bytes_read == 0) { |
+ Dart_SetReturnValue(args, Dart_Null()); |
+ } else { |
+ ASSERT(bytes_read == -1); |
+ Dart_SetReturnValue(args, DartUtils::NewDartOSError()); |
+ } |
+} |
+ |
+ |
void FUNCTION_NAME(Socket_WriteList)(Dart_NativeArguments args) { |
static bool short_socket_writes = Dart_IsVMFlagSet("short_socket_write"); |
intptr_t socket = |
@@ -216,6 +315,44 @@ void FUNCTION_NAME(Socket_WriteList)(Dart_NativeArguments args) { |
} |
+void FUNCTION_NAME(Socket_SendTo)(Dart_NativeArguments args) { |
+ intptr_t socket = |
+ Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0)); |
+ Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1); |
+ intptr_t offset = |
+ DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 2)); |
+ intptr_t length = |
+ DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 3)); |
+ Dart_Handle address_obj = Dart_GetNativeArgument(args, 4); |
+ ASSERT(Dart_IsList(address_obj)); |
+ RawAddr addr; |
+ GetSockAddr(address_obj, &addr); |
+ int64_t port = DartUtils::GetInt64ValueCheckRange( |
+ Dart_GetNativeArgument(args, 5), |
+ 0, |
+ 65535); |
+ SocketAddress::SetAddrPort(&addr, port); |
+ Dart_TypedData_Type type; |
+ uint8_t* buffer = NULL; |
+ intptr_t len; |
+ Dart_Handle result = Dart_TypedDataAcquireData( |
+ buffer_obj, &type, reinterpret_cast<void**>(&buffer), &len); |
+ if (Dart_IsError(result)) Dart_PropagateError(result); |
+ ASSERT((offset + length) <= len); |
+ buffer += offset; |
+ intptr_t bytes_written = Socket::SendTo(socket, buffer, length, addr); |
+ if (bytes_written >= 0) { |
+ Dart_TypedDataReleaseData(buffer_obj); |
+ Dart_SetReturnValue(args, Dart_NewInteger(bytes_written)); |
+ } else { |
+ // Extract OSError before we release data, as it may override the error. |
+ OSError os_error; |
+ Dart_TypedDataReleaseData(buffer_obj); |
+ Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error)); |
+ } |
+} |
+ |
+ |
void FUNCTION_NAME(Socket_GetPort)(Dart_NativeArguments args) { |
intptr_t socket = |
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0)); |
@@ -463,26 +600,131 @@ CObject* Socket::ListInterfacesRequest(const CObjectArray& request) { |
} |
+void FUNCTION_NAME(Socket_GetOption)(Dart_NativeArguments args) { |
+ intptr_t socket = |
+ Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0)); |
+ int64_t option = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1)); |
+ intptr_t protocol = |
+ static_cast<intptr_t>( |
+ DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2))); |
+ bool ok; |
+ switch (option) { |
+ case 0: { // TCP_NODELAY. |
+ bool enabled; |
+ ok = Socket::GetNoDelay(socket, &enabled); |
+ if (ok) { |
+ Dart_SetReturnValue(args, enabled ? Dart_True() : Dart_False()); |
+ } |
+ break; |
+ } |
+ case 1: { // IP_MULTICAST_LOOP. |
+ bool enabled; |
+ ok = Socket::GetMulticastLoop(socket, protocol, &enabled); |
+ if (ok) { |
+ Dart_SetReturnValue(args, enabled ? Dart_True() : Dart_False()); |
+ } |
+ break; |
+ } |
+ case 2: { // IP_MULTICAST_TTL. |
+ int value; |
+ ok = Socket::GetMulticastHops(socket, protocol, &value); |
+ if (ok) { |
+ Dart_SetReturnValue(args, Dart_NewInteger(value)); |
+ } |
+ break; |
+ } |
+ case 3: { // IP_MULTICAST_IF. |
+ UNIMPLEMENTED(); |
+ break; |
+ } |
+ case 4: { // IP_BROADCAST. |
+ bool enabled; |
+ ok = Socket::GetBroadcast(socket, &enabled); |
+ if (ok) { |
+ Dart_SetReturnValue(args, enabled ? Dart_True() : Dart_False()); |
+ } |
+ break; |
+ } |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ // In case of failure the return value is not set above. |
+ if (!ok) { |
+ Dart_SetReturnValue(args, DartUtils::NewDartOSError()); |
+ } |
+} |
+ |
+ |
void FUNCTION_NAME(Socket_SetOption)(Dart_NativeArguments args) { |
bool result = false; |
intptr_t socket = |
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0)); |
- Dart_Handle option_obj = Dart_GetNativeArgument(args, 1); |
- int64_t option; |
- Dart_Handle err = Dart_IntegerToInt64(option_obj, &option); |
- if (Dart_IsError(err)) Dart_PropagateError(err); |
- Dart_Handle enabled_obj = Dart_GetNativeArgument(args, 2); |
- bool enabled; |
- err = Dart_BooleanValue(enabled_obj, &enabled); |
- if (Dart_IsError(err)) Dart_PropagateError(err); |
+ int64_t option = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1)); |
+ int64_t protocol = DartUtils::GetInt64ValueCheckRange( |
+ Dart_GetNativeArgument(args, 2), |
+ SocketAddress::TYPE_IPV4, |
+ SocketAddress::TYPE_IPV6); |
switch (option) { |
case 0: // TCP_NODELAY. |
- result = Socket::SetNoDelay(socket, enabled); |
+ result = Socket::SetNoDelay( |
+ socket, DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3))); |
+ break; |
+ case 1: // IP_MULTICAST_LOOP. |
+ result = Socket::SetMulticastLoop( |
+ socket, |
+ protocol, |
+ DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3))); |
+ break; |
+ case 2: // IP_MULTICAST_TTL. |
+ result = Socket::SetMulticastHops( |
+ socket, |
+ protocol, |
+ DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3))); |
+ break; |
+ case 3: { // IP_MULTICAST_IF. |
+ UNIMPLEMENTED(); |
+ break; |
+ } |
+ case 4: // IP_BROADCAST. |
+ result = Socket::SetBroadcast( |
+ socket, DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3))); |
break; |
default: |
+ Dart_PropagateError(Dart_NewApiError("Value outside expected range")); |
break; |
} |
- Dart_SetReturnValue(args, Dart_NewBoolean(result)); |
+ if (result) { |
+ Dart_SetReturnValue(args, Dart_Null()); |
+ } else { |
+ Dart_SetReturnValue(args, DartUtils::NewDartOSError()); |
+ } |
+} |
+ |
+ |
+void FUNCTION_NAME(Socket_JoinMulticast)(Dart_NativeArguments args) { |
+ intptr_t socket = |
+ Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0)); |
+ RawAddr addr; |
+ GetSockAddr(Dart_GetNativeArgument(args, 1), &addr); |
+ if (Socket::JoinMulticast(socket, &addr, 0)) { |
+ Dart_SetReturnValue(args, Dart_Null()); |
+ } else { |
+ Dart_SetReturnValue(args, DartUtils::NewDartOSError()); |
+ } |
+} |
+ |
+ |
+void FUNCTION_NAME(Socket_LeaveMulticast)(Dart_NativeArguments args) { |
+ intptr_t socket = |
+ Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0)); |
+ RawAddr addr; |
+ GetSockAddr(Dart_GetNativeArgument(args, 1), &addr); |
+ if (Socket::LeaveMulticast(socket, &addr, 0)) { |
+ Dart_SetReturnValue(args, Dart_Null()); |
+ } else { |
+ Dart_SetReturnValue(args, DartUtils::NewDartOSError()); |
+ } |
} |