Files
sdk/runtime/bin/socket.cc
T
Zachary Anderson ba550f1c43 Fixes NetworkInterface.list crash on Android
Previously, Socket::ListInterfaces failed to set the os_error out
parameter causing a crash in the caller. This change sets an error here.

I've also added NetworkInterface.listSupported, which returns false on
Android, and true everywhere else. ifaddrs.h continues not to exist in
the NDK, so in order to support NetworkInterface.list, we'd have to
reimplement it, or find a suitable reimplementation somewhere.

related #26329

R=johnmccutchan@google.com

Review URL: https://codereview.chromium.org/1916223003 .
2016-04-26 07:48:58 -07:00

887 lines
29 KiB
C++

// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#if !defined(DART_IO_DISABLED)
#include "bin/socket.h"
#include "bin/dartutils.h"
#include "bin/io_buffer.h"
#include "bin/isolate_data.h"
#include "bin/lockers.h"
#include "bin/thread.h"
#include "bin/utils.h"
#include "include/dart_api.h"
#include "platform/globals.h"
#include "platform/utils.h"
namespace dart {
namespace bin {
static const int kSocketIdNativeField = 0;
ListeningSocketRegistry *globalTcpListeningSocketRegistry = NULL;
void ListeningSocketRegistry::Initialize() {
ASSERT(globalTcpListeningSocketRegistry == NULL);
globalTcpListeningSocketRegistry = new ListeningSocketRegistry();
}
ListeningSocketRegistry *ListeningSocketRegistry::Instance() {
return globalTcpListeningSocketRegistry;
}
void ListeningSocketRegistry::Cleanup() {
delete globalTcpListeningSocketRegistry;
globalTcpListeningSocketRegistry = NULL;
}
Dart_Handle ListeningSocketRegistry::CreateBindListen(Dart_Handle socket_object,
RawAddr addr,
intptr_t backlog,
bool v6_only,
bool shared) {
MutexLocker ml(ListeningSocketRegistry::mutex_);
intptr_t port = SocketAddress::GetAddrPort(addr);
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 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();
}
}
// There is no socket listening on that (address, port), so we create new one.
intptr_t socketfd = ServerSocket::CreateBindListen(addr, 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);
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(intptr_t socketfd) {
ASSERT(!mutex_->TryLock());
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 *prev = NULL;
OSSocket *current = sockets_by_port_[os_socket->port];
while (current != os_socket) {
ASSERT(current != NULL);
prev = current;
current = current->next;
}
if ((prev == NULL) && (current->next == NULL)) {
// Remove last element from the list.
sockets_by_port_.erase(os_socket->port);
} else if (prev == NULL) {
// Remove first element of the list.
sockets_by_port_[os_socket->port] = current->next;
} else {
// Remove element from the list which is not the first one.
prev->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;
}
}
void FUNCTION_NAME(InternetAddress_Parse)(Dart_NativeArguments args) {
const char* address =
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
ASSERT(address != NULL);
RawAddr raw;
memset(&raw, 0, sizeof(raw));
int type = strchr(address, ':') == NULL ? SocketAddress::TYPE_IPV4
: SocketAddress::TYPE_IPV6;
if (type == SocketAddress::TYPE_IPV4) {
raw.addr.sa_family = AF_INET;
} else {
raw.addr.sa_family = AF_INET6;
}
bool ok = Socket::ParseAddress(type, address, &raw);
if (!ok) {
Dart_SetReturnValue(args, Dart_Null());
} else {
Dart_SetReturnValue(args, SocketAddress::ToTypedData(raw));
}
}
void FUNCTION_NAME(NetworkInterface_ListSupported)(Dart_NativeArguments args) {
Dart_SetReturnValue(args, Dart_NewBoolean(Socket::ListInterfacesSupported()));
}
void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) {
RawAddr addr;
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port));
intptr_t socket = Socket::CreateConnect(addr);
OSError error;
if (socket >= 0) {
Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket);
Dart_SetReturnValue(args, Dart_True());
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error));
}
}
void FUNCTION_NAME(Socket_CreateBindConnect)(Dart_NativeArguments args) {
RawAddr addr;
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port));
RawAddr sourceAddr;
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 3), &sourceAddr);
intptr_t socket = Socket::CreateBindConnect(addr, sourceAddr);
OSError error;
if (socket >= 0) {
Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket);
Dart_SetReturnValue(args, Dart_True());
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error));
}
}
void FUNCTION_NAME(Socket_CreateBindDatagram)(Dart_NativeArguments args) {
RawAddr addr;
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
SocketAddress::SetAddrPort(&addr, port);
bool reuse_addr = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
intptr_t socket = Socket::CreateBindDatagram(addr, reuse_addr);
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 =
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
intptr_t available = Socket::Available(socket);
if (available >= 0) {
Dart_SetReturnValue(args, Dart_NewInteger(available));
} else {
// Available failed. Mark socket as having data, to trigger a future read
// event where the actual error can be reported.
Dart_SetReturnValue(args, Dart_NewInteger(1));
}
}
void FUNCTION_NAME(Socket_Read)(Dart_NativeArguments args) {
static bool short_socket_reads = Dart_IsVMFlagSet("short_socket_read");
intptr_t socket =
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
int64_t length = 0;
if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &length)) {
if (short_socket_reads) {
length = (length + 1) / 2;
}
uint8_t* buffer = NULL;
Dart_Handle result = IOBuffer::Allocate(length, &buffer);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
ASSERT(buffer != NULL);
intptr_t bytes_read = Socket::Read(socket, buffer, length);
if (bytes_read == length) {
Dart_SetReturnValue(args, result);
} else if (bytes_read > 0) {
uint8_t* new_buffer = NULL;
Dart_Handle new_result = IOBuffer::Allocate(bytes_read, &new_buffer);
if (Dart_IsError(new_result)) {
Dart_PropagateError(new_result);
}
ASSERT(new_buffer != NULL);
memmove(new_buffer, buffer, bytes_read);
Dart_SetReturnValue(args, new_result);
} else if (bytes_read == 0) {
// On MacOS when reading from a tty Ctrl-D will result in reading one
// less byte then reported as available.
Dart_SetReturnValue(args, Dart_Null());
} else {
ASSERT(bytes_read == -1);
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
} else {
OSError os_error(-1, "Invalid argument", OSError::kUnknown);
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
}
}
void FUNCTION_NAME(Socket_RecvFrom)(Dart_NativeArguments args) {
intptr_t socket =
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
// TODO(sgjesse): Use a MTU value here. Only the loopback adapter can
// handle 64k datagrams.
IsolateData* isolate_data =
reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
if (isolate_data->udp_receive_buffer == NULL) {
isolate_data->udp_receive_buffer =
reinterpret_cast<uint8_t*>(malloc(65536));
}
RawAddr addr;
intptr_t bytes_read =
Socket::RecvFrom(socket, isolate_data->udp_receive_buffer, 65536, &addr);
if (bytes_read == 0) {
Dart_SetReturnValue(args, Dart_Null());
return;
}
if (bytes_read < 0) {
ASSERT(bytes_read == -1);
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
return;
}
// Datagram data read. Copy into buffer of the exact size,
ASSERT(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, isolate_data->udp_receive_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 = 4;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = data;
dart_args[1] = Dart_NewStringFromCString(numeric_address);
if (Dart_IsError(dart_args[1])) {
Dart_PropagateError(dart_args[1]);
}
dart_args[2] = SocketAddress::ToTypedData(addr);
dart_args[3] = Dart_NewInteger(port);
if (Dart_IsError(dart_args[3])) {
Dart_PropagateError(dart_args[3]);
}
// 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);
Dart_SetReturnValue(args, result);
}
void FUNCTION_NAME(Socket_WriteList)(Dart_NativeArguments args) {
static bool short_socket_writes = Dart_IsVMFlagSet("short_socket_write");
intptr_t socket =
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
ASSERT(Dart_IsList(buffer_obj));
intptr_t offset =
DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 2));
intptr_t length =
DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 3));
bool short_write = false;
if (short_socket_writes) {
if (length > 1) {
short_write = true;
}
length = (length + 1) / 2;
}
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::Write(socket, buffer, length);
if (bytes_written >= 0) {
Dart_TypedDataReleaseData(buffer_obj);
if (short_write) {
// If the write was forced 'short', indicate by returning the negative
// number of bytes. A forced short write may not trigger a write event.
Dart_SetReturnValue(args, Dart_NewInteger(-bytes_written));
} else {
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_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;
SocketAddress::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));
OSError os_error;
intptr_t port = Socket::GetPort(socket);
if (port > 0) {
Dart_SetReturnValue(args, Dart_NewInteger(port));
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
}
void FUNCTION_NAME(Socket_GetRemotePeer)(Dart_NativeArguments args) {
intptr_t socket =
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
OSError os_error;
intptr_t port = 0;
SocketAddress* addr = Socket::GetRemotePeer(socket, &port);
if (addr != NULL) {
Dart_Handle list = Dart_NewList(2);
Dart_Handle entry = Dart_NewList(3);
Dart_ListSetAt(entry, 0, Dart_NewInteger(addr->GetType()));
Dart_ListSetAt(entry, 1, Dart_NewStringFromCString(addr->as_string()));
RawAddr raw = addr->addr();
intptr_t data_length = SocketAddress::GetAddrLength(raw);
Dart_Handle data = Dart_NewTypedData(Dart_TypedData_kUint8, data_length);
Dart_ListSetAsBytes(data, 0, reinterpret_cast<uint8_t*>(&raw), data_length);
Dart_ListSetAt(entry, 2, data);
Dart_ListSetAt(list, 0, entry);
Dart_ListSetAt(list, 1, Dart_NewInteger(port));
Dart_SetReturnValue(args, list);
delete addr;
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
}
void FUNCTION_NAME(Socket_GetError)(Dart_NativeArguments args) {
intptr_t socket =
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
OSError os_error;
Socket::GetError(socket, &os_error);
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
}
void FUNCTION_NAME(Socket_GetType)(Dart_NativeArguments args) {
intptr_t socket =
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
OSError os_error;
intptr_t type = Socket::GetType(socket);
if (type >= 0) {
Dart_SetReturnValue(args, Dart_NewInteger(type));
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
}
void FUNCTION_NAME(Socket_GetStdioHandle)(Dart_NativeArguments args) {
int64_t num = DartUtils::GetInt64ValueCheckRange(
Dart_GetNativeArgument(args, 1), 0, 2);
intptr_t socket = Socket::GetStdioHandle(num);
Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket);
Dart_SetReturnValue(args, Dart_NewBoolean(socket >= 0));
}
void FUNCTION_NAME(Socket_GetSocketId)(Dart_NativeArguments args) {
intptr_t id = Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
Dart_SetReturnValue(args, Dart_NewInteger(id));
}
void FUNCTION_NAME(Socket_SetSocketId)(Dart_NativeArguments args) {
intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), id);
}
void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) {
RawAddr addr;
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
int64_t port = DartUtils::GetInt64ValueCheckRange(
Dart_GetNativeArgument(args, 2),
0,
65535);
SocketAddress::SetAddrPort(&addr, port);
int64_t backlog = DartUtils::GetInt64ValueCheckRange(
Dart_GetNativeArgument(args, 3),
0,
65535);
bool v6_only = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
bool shared = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
Dart_Handle socket_object = Dart_GetNativeArgument(args, 0);
Dart_Handle result = ListeningSocketRegistry::Instance()->CreateBindListen(
socket_object, addr, backlog, v6_only, shared);
Dart_SetReturnValue(args, result);
}
void FUNCTION_NAME(ServerSocket_Accept)(Dart_NativeArguments args) {
intptr_t socket =
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
intptr_t new_socket = ServerSocket::Accept(socket);
if (new_socket >= 0) {
Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 1), new_socket);
Dart_SetReturnValue(args, Dart_True());
} else if (new_socket == ServerSocket::kTemporaryFailure) {
Dart_SetReturnValue(args, Dart_False());
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
}
CObject* Socket::LookupRequest(const CObjectArray& request) {
if ((request.Length() == 2) &&
request[0]->IsString() &&
request[1]->IsInt32()) {
CObjectString host(request[0]);
CObjectInt32 type(request[1]);
CObject* result = NULL;
OSError* os_error = NULL;
AddressList<SocketAddress>* addresses =
Socket::LookupAddress(host.CString(), type.Value(), &os_error);
if (addresses != NULL) {
CObjectArray* array = new CObjectArray(
CObject::NewArray(addresses->count() + 1));
array->SetAt(0, new CObjectInt32(CObject::NewInt32(0)));
for (intptr_t i = 0; i < addresses->count(); i++) {
SocketAddress* addr = addresses->GetAt(i);
CObjectArray* entry = new CObjectArray(CObject::NewArray(3));
CObjectInt32* type = new CObjectInt32(
CObject::NewInt32(addr->GetType()));
entry->SetAt(0, type);
CObjectString* as_string = new CObjectString(CObject::NewString(
addr->as_string()));
entry->SetAt(1, as_string);
RawAddr raw = addr->addr();
CObjectUint8Array* data = SocketAddress::ToCObject(raw);
entry->SetAt(2, data);
array->SetAt(i + 1, entry);
}
result = array;
delete addresses;
} else {
result = CObject::NewOSError(os_error);
delete os_error;
}
return result;
}
return CObject::IllegalArgumentError();
}
CObject* Socket::ReverseLookupRequest(const CObjectArray& request) {
if ((request.Length() == 1) &&
request[0]->IsTypedData()) {
CObjectUint8Array addr_object(request[0]);
RawAddr addr;
int len = addr_object.Length();
memset(reinterpret_cast<void*>(&addr), 0, sizeof(RawAddr));
if (len == sizeof(in_addr)) {
addr.in.sin_family = AF_INET;
memmove(reinterpret_cast<void*>(&addr.in.sin_addr),
addr_object.Buffer(),
len);
} else {
ASSERT(len == sizeof(in6_addr));
addr.in6.sin6_family = AF_INET6;
memmove(reinterpret_cast<void*>(&addr.in6.sin6_addr),
addr_object.Buffer(),
len);
}
OSError* os_error = NULL;
const intptr_t kMaxHostLength = 1025;
char host[kMaxHostLength];
if (Socket::ReverseLookup(addr, host, kMaxHostLength, &os_error)) {
return new CObjectString(CObject::NewString(host));
} else {
CObject* result = CObject::NewOSError(os_error);
delete os_error;
return result;
}
}
return CObject::IllegalArgumentError();
}
CObject* Socket::ListInterfacesRequest(const CObjectArray& request) {
if ((request.Length() == 1) &&
request[0]->IsInt32()) {
CObjectInt32 type(request[0]);
CObject* result = NULL;
OSError* os_error = NULL;
AddressList<InterfaceSocketAddress>* addresses = Socket::ListInterfaces(
type.Value(), &os_error);
if (addresses != NULL) {
CObjectArray* array = new CObjectArray(
CObject::NewArray(addresses->count() + 1));
array->SetAt(0, new CObjectInt32(CObject::NewInt32(0)));
for (intptr_t i = 0; i < addresses->count(); i++) {
InterfaceSocketAddress* interface = addresses->GetAt(i);
SocketAddress* addr = interface->socket_address();
CObjectArray* entry = new CObjectArray(CObject::NewArray(5));
CObjectInt32* type = new CObjectInt32(
CObject::NewInt32(addr->GetType()));
entry->SetAt(0, type);
CObjectString* as_string = new CObjectString(CObject::NewString(
addr->as_string()));
entry->SetAt(1, as_string);
RawAddr raw = addr->addr();
CObjectUint8Array* data = SocketAddress::ToCObject(raw);
entry->SetAt(2, data);
CObjectString* interface_name = new CObjectString(CObject::NewString(
interface->interface_name()));
entry->SetAt(3, interface_name);
CObjectInt64* interface_index = new CObjectInt64(CObject::NewInt64(
interface->interface_index()));
entry->SetAt(4, interface_index);
array->SetAt(i + 1, entry);
}
result = array;
delete addresses;
} else {
result = CObject::NewOSError(os_error);
delete os_error;
}
return result;
}
return CObject::IllegalArgumentError();
}
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 = false;
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));
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, 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;
}
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;
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
RawAddr interface;
if (Dart_GetNativeArgument(args, 2) != Dart_Null()) {
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 2), &interface);
}
int interfaceIndex =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
if (Socket::JoinMulticast(socket, addr, interface, interfaceIndex)) {
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;
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
RawAddr interface;
if (Dart_GetNativeArgument(args, 2) != Dart_Null()) {
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 2), &interface);
}
int interfaceIndex =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
if (Socket::LeaveMulticast(socket, addr, interface, interfaceIndex)) {
Dart_SetReturnValue(args, Dart_Null());
} else {
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
}
}
void Socket::SetSocketIdNativeField(Dart_Handle socket, intptr_t id) {
Dart_Handle err =
Dart_SetNativeInstanceField(socket, kSocketIdNativeField, id);
if (Dart_IsError(err)) {
Dart_PropagateError(err);
}
}
intptr_t Socket::GetSocketIdNativeField(Dart_Handle socket_obj) {
intptr_t socket = 0;
Dart_Handle err =
Dart_GetNativeInstanceField(socket_obj, kSocketIdNativeField, &socket);
if (Dart_IsError(err)) {
Dart_PropagateError(err);
}
return socket;
}
} // namespace bin
} // namespace dart
#endif // !defined(DART_IO_DISABLED)