mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 08:44:27 +00:00
f407419d0a
This relands https://dart-review.googlesource.com/c/sdk/+/205633 but without renaming TARGET_OS_IPHONE to DART_TARGET_OS_IPHONE. It also changes uses of TARGET_OS_IOS to DART_TARGET_OS_MACOS_IOS to be consistent with the rest of the VM. TargetConditionals.h for XCode 13 defines several TARGET_OS_* preprocessor symbols that confuse the Dart build. There is probably a more targeted fix for this, but renaming the symbols that Dart uses will also prevent this problem if more symbols are added to the platform headers in the future. See: https://github.com/dart-lang/sdk/issues/46499 TEST=It builds. Change-Id: Ie775c19dd23cfdf5f65e5ebc6ee4ec3a561676fa Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/205860 Commit-Queue: Zach Anderson <zra@google.com> Reviewed-by: Alexander Aprelev <aam@google.com>
310 lines
10 KiB
C++
310 lines
10 KiB
C++
// Copyright (c) 2017, 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.
|
|
|
|
#include "bin/socket_base.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/typed_data_utils.h"
|
|
#include "bin/utils.h"
|
|
|
|
#include "include/dart_api.h"
|
|
|
|
#include "platform/globals.h"
|
|
#include "platform/utils.h"
|
|
|
|
namespace dart {
|
|
namespace bin {
|
|
|
|
int SocketAddress::GetType() {
|
|
switch (addr_.ss.ss_family) {
|
|
case AF_INET6:
|
|
return TYPE_IPV6;
|
|
case AF_INET:
|
|
return TYPE_IPV4;
|
|
case AF_UNIX:
|
|
return TYPE_UNIX;
|
|
default:
|
|
UNREACHABLE();
|
|
return TYPE_ANY;
|
|
}
|
|
}
|
|
|
|
intptr_t SocketAddress::GetAddrLength(const RawAddr& addr,
|
|
bool unnamed_unix_socket) {
|
|
ASSERT((addr.ss.ss_family == AF_INET) || (addr.ss.ss_family == AF_INET6) ||
|
|
(addr.ss.ss_family == AF_UNIX));
|
|
switch (addr.ss.ss_family) {
|
|
case AF_INET6:
|
|
return sizeof(struct sockaddr_in6);
|
|
case AF_INET:
|
|
return sizeof(struct sockaddr_in);
|
|
case AF_UNIX: {
|
|
// For an abstract UNIX socket, trailing null bytes in the name are
|
|
// meaningful. That is, the bytes '\0/tmp/dbus-xxxx' are a different name
|
|
// than '\0/tmp/dbus-xxxx\0\0\0...'. The length of the address structure
|
|
// passed to connect() etc. tells those calls how many bytes of the name
|
|
// to look at. Therefore, when computing the length of the address in
|
|
// this case, any trailing null bytes are trimmed.
|
|
// TODO(dart:io): Support abstract UNIX socket addresses that have
|
|
// trailing null bytes on purpose.
|
|
// https://github.com/dart-lang/sdk/issues/46158
|
|
intptr_t nulls = 0;
|
|
if (!unnamed_unix_socket && addr.un.sun_path[0] == '\0') {
|
|
intptr_t i = sizeof(addr.un.sun_path) - 1;
|
|
while (addr.un.sun_path[i] == '\0') {
|
|
nulls++;
|
|
i--;
|
|
}
|
|
}
|
|
return sizeof(struct sockaddr_un) - nulls;
|
|
}
|
|
default:
|
|
UNREACHABLE();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
intptr_t SocketAddress::GetInAddrLength(const RawAddr& addr) {
|
|
ASSERT((addr.ss.ss_family == AF_INET) || (addr.ss.ss_family == AF_INET6));
|
|
return (addr.ss.ss_family == AF_INET6) ? sizeof(struct in6_addr)
|
|
: sizeof(struct in_addr);
|
|
}
|
|
|
|
bool SocketAddress::AreAddressesEqual(const RawAddr& a, const RawAddr& b) {
|
|
if (a.ss.ss_family != b.ss.ss_family) {
|
|
return false;
|
|
}
|
|
if (a.ss.ss_family == AF_INET) {
|
|
return memcmp(&a.in.sin_addr, &b.in.sin_addr, sizeof(a.in.sin_addr)) == 0;
|
|
} else if (a.ss.ss_family == AF_INET6) {
|
|
return memcmp(&a.in6.sin6_addr, &b.in6.sin6_addr,
|
|
sizeof(a.in6.sin6_addr)) == 0 &&
|
|
a.in6.sin6_scope_id == b.in6.sin6_scope_id;
|
|
} else if (a.ss.ss_family == AF_UNIX) {
|
|
// This is not used anywhere. The comparison of file path is done via
|
|
// File::AreIdentical().
|
|
int len = sizeof(a.un.sun_path);
|
|
for (int i = 0; i < len; i++) {
|
|
if (a.un.sun_path[i] != b.un.sun_path[i]) return false;
|
|
if (a.un.sun_path[i] == '\0') return true;
|
|
}
|
|
return true;
|
|
} else {
|
|
UNREACHABLE();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void SocketAddress::GetSockAddr(Dart_Handle obj, RawAddr* addr) {
|
|
Dart_TypedData_Type data_type;
|
|
uint8_t* data = NULL;
|
|
intptr_t len;
|
|
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) ||
|
|
((len != sizeof(in_addr)) && (len != sizeof(in6_addr)))) {
|
|
Dart_PropagateError(Dart_NewApiError("Unexpected type for socket address"));
|
|
}
|
|
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), data, len);
|
|
} else {
|
|
ASSERT(len == sizeof(in6_addr));
|
|
addr->in6.sin6_family = AF_INET6;
|
|
memmove(reinterpret_cast<void*>(&addr->in6.sin6_addr), data, len);
|
|
}
|
|
Dart_TypedDataReleaseData(obj);
|
|
}
|
|
|
|
Dart_Handle SocketAddress::GetUnixDomainSockAddr(const char* path,
|
|
Namespace* namespc,
|
|
RawAddr* addr) {
|
|
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
|
NamespaceScope ns(namespc, path);
|
|
path = ns.path();
|
|
bool is_abstract = (path[0] == '@');
|
|
if (is_abstract) {
|
|
// The following 107 bytes after the leading null byte represents the name
|
|
// of unix domain socket. Without reseting, even users provide the same path
|
|
// for bind and connect, they actually represent two different address and
|
|
// connection will be rejected.
|
|
bzero(addr->un.sun_path, sizeof(addr->un.sun_path));
|
|
}
|
|
#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
|
if (sizeof(path) > sizeof(addr->un.sun_path)) {
|
|
OSError os_error(-1,
|
|
"The length of path exceeds the limit. "
|
|
"Check out man 7 unix page",
|
|
OSError::kUnknown);
|
|
return DartUtils::NewDartOSError(&os_error);
|
|
}
|
|
addr->un.sun_family = AF_UNIX;
|
|
Utils::SNPrint(addr->un.sun_path, sizeof(addr->un.sun_path), "%s", path);
|
|
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
|
// In case of abstract namespace, transfer the leading '@' into a null byte.
|
|
if (is_abstract) {
|
|
addr->un.sun_path[0] = '\0';
|
|
}
|
|
#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
|
return Dart_Null();
|
|
}
|
|
|
|
int16_t SocketAddress::FromType(int type) {
|
|
if (type == TYPE_ANY) {
|
|
return AF_UNSPEC;
|
|
}
|
|
if (type == TYPE_IPV4) {
|
|
return AF_INET;
|
|
}
|
|
if (type == TYPE_UNIX) {
|
|
return AF_UNIX;
|
|
}
|
|
ASSERT((type == TYPE_IPV6) && "Invalid type");
|
|
return AF_INET6;
|
|
}
|
|
|
|
void SocketAddress::SetAddrPort(RawAddr* addr, intptr_t port) {
|
|
if (addr->ss.ss_family == AF_INET) {
|
|
addr->in.sin_port = htons(port);
|
|
} else if (addr->ss.ss_family == AF_INET6) {
|
|
addr->in6.sin6_port = htons(port);
|
|
} else {
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
intptr_t SocketAddress::GetAddrPort(const RawAddr& addr) {
|
|
if (addr.ss.ss_family == AF_INET) {
|
|
return ntohs(addr.in.sin_port);
|
|
} else if (addr.ss.ss_family == AF_INET6) {
|
|
return ntohs(addr.in6.sin6_port);
|
|
} else if (addr.ss.ss_family == AF_UNIX) {
|
|
return 0;
|
|
} else {
|
|
UNREACHABLE();
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
Dart_Handle SocketAddress::ToTypedData(const RawAddr& addr) {
|
|
int len = GetInAddrLength(addr);
|
|
Dart_Handle result = Dart_NewTypedData(Dart_TypedData_kUint8, len);
|
|
if (Dart_IsError(result)) {
|
|
Dart_PropagateError(result);
|
|
}
|
|
Dart_Handle err;
|
|
if (addr.addr.sa_family == AF_INET6) {
|
|
err = Dart_ListSetAsBytes(
|
|
result, 0, reinterpret_cast<const uint8_t*>(&addr.in6.sin6_addr), len);
|
|
} else {
|
|
err = Dart_ListSetAsBytes(
|
|
result, 0, reinterpret_cast<const uint8_t*>(&addr.in.sin_addr), len);
|
|
}
|
|
if (Dart_IsError(err)) {
|
|
Dart_PropagateError(err);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
CObjectUint8Array* SocketAddress::ToCObject(const RawAddr& addr) {
|
|
int in_addr_len = SocketAddress::GetInAddrLength(addr);
|
|
const void* in_addr;
|
|
CObjectUint8Array* data =
|
|
new CObjectUint8Array(CObject::NewUint8Array(in_addr_len));
|
|
if (addr.addr.sa_family == AF_INET6) {
|
|
in_addr = reinterpret_cast<const void*>(&addr.in6.sin6_addr);
|
|
} else {
|
|
in_addr = reinterpret_cast<const void*>(&addr.in.sin_addr);
|
|
}
|
|
memmove(data->Buffer(), in_addr, in_addr_len);
|
|
return data;
|
|
}
|
|
void SocketAddress::SetAddrScope(RawAddr* addr, intptr_t scope_id) {
|
|
if (addr->addr.sa_family != AF_INET6) return;
|
|
addr->in6.sin6_scope_id = scope_id;
|
|
}
|
|
|
|
intptr_t SocketAddress::GetAddrScope(const RawAddr& addr) {
|
|
if (addr.addr.sa_family == AF_INET6) {
|
|
return addr.in6.sin6_scope_id;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
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 = SocketBase::ParseAddress(type, address, &raw);
|
|
if (!ok) {
|
|
Dart_SetReturnValue(args, Dart_Null());
|
|
} else {
|
|
Dart_SetReturnValue(args, SocketAddress::ToTypedData(raw));
|
|
}
|
|
}
|
|
|
|
void FUNCTION_NAME(InternetAddress_ParseScopedLinkLocalAddress)(
|
|
Dart_NativeArguments args) {
|
|
const char* address =
|
|
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
|
|
// This must be an IPv6 address.
|
|
intptr_t type = 1;
|
|
ASSERT(address != NULL);
|
|
OSError* os_error = NULL;
|
|
AddressList<SocketAddress>* addresses =
|
|
SocketBase::LookupAddress(address, type, &os_error);
|
|
if (addresses != NULL) {
|
|
SocketAddress* addr = addresses->GetAt(0);
|
|
Dart_SetReturnValue(
|
|
args, Dart_NewInteger(SocketAddress::GetAddrScope(addr->addr())));
|
|
delete addresses;
|
|
} else {
|
|
Dart_SetReturnValue(args, DartUtils::NewDartOSError(os_error));
|
|
delete os_error;
|
|
}
|
|
}
|
|
|
|
void FUNCTION_NAME(InternetAddress_RawAddrToString)(Dart_NativeArguments args) {
|
|
RawAddr addr;
|
|
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 0), &addr);
|
|
// INET6_ADDRSTRLEN is larger than INET_ADDRSTRLEN
|
|
char str[INET6_ADDRSTRLEN];
|
|
bool ok = SocketBase::RawAddrToString(&addr, str);
|
|
if (!ok) {
|
|
str[0] = '\0';
|
|
}
|
|
Dart_SetReturnValue(args, ThrowIfError(DartUtils::NewString(str)));
|
|
}
|
|
|
|
void FUNCTION_NAME(NetworkInterface_ListSupported)(Dart_NativeArguments args) {
|
|
Dart_SetBooleanReturnValue(args, SocketBase::ListInterfacesSupported());
|
|
}
|
|
|
|
void FUNCTION_NAME(SocketBase_IsBindError)(Dart_NativeArguments args) {
|
|
intptr_t error_number =
|
|
DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
|
|
bool is_bind_error = SocketBase::IsBindError(error_number);
|
|
Dart_SetBooleanReturnValue(args, is_bind_error ? true : false);
|
|
}
|
|
|
|
} // namespace bin
|
|
} // namespace dart
|