[dart:io] support Unix domain communications
Support Unix domain sockets communication on Linux, MacOS and Android.
Changes:
1. Add a field for InternetAddressType named unix.
2. Constructor of InternetAddress gains one more optional field: type. InternetAddress(String address, {InternetAddressType type});
3. Add another constructor to InternetAddress which taks raw address/path for ip/unix addresses as an argument. InternetAddress.fromRawAddress(Uint8List rawAddress, {InternetAddressType type});
The operation for unix domain sockets communication is basically the same as normal sockets except an InternetAddress with type unix should be passed.
Change-Id: I6a1135bbdd7f4e4fc745ccf8f95dec5272b6839b
Bug: https://github.com/dart-lang/sdk/issues/21403
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/125932
Commit-Queue: Zichang Guo <zichangguo@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
cbd67124d1
commit
ed83a28d3e
@@ -115,6 +115,23 @@ used (see Issue [39627][]).
|
||||
|
||||
now gives `v;a=A;b="(B)";c="";d="ø";e="\\\""`.
|
||||
|
||||
* [Unix domain sockets](https://en.wikipedia.org/wiki/Unix_domain_socket) are
|
||||
now supported on Linux, Android and MacOS, which can be used by passing a
|
||||
`InternetAddress` of `InternetAddressType.Unix` into `connect`, `startConnect`
|
||||
and `bind` methods. `port` argument in those methods will be ignored. Getter
|
||||
of `port` will always return 0 for Unix domain sockets.
|
||||
|
||||
* Class `InternetAddressType` gains one more option `Unix`, which represents a
|
||||
Unix domain address.
|
||||
|
||||
* Class `InternetAddress`:
|
||||
* `InternetAddress` constructor gains an optional `type` parameter. To create
|
||||
a Unix domain address, `type` is set to `InternetAddressType.Unix` and
|
||||
`address` is a file path.
|
||||
* `InternetAddress` gains a new constructor `fromRawAddress` that takes an
|
||||
address in byte format for Internet addresses or raw file path for Unix
|
||||
domain addresses.
|
||||
|
||||
#### `dart:mirrors`
|
||||
|
||||
* Added `MirrorSystem.neverType`.
|
||||
|
||||
+2
-2
@@ -763,7 +763,7 @@ void FUNCTION_NAME(File_AreIdentical)(Dart_NativeArguments args) {
|
||||
Namespace* namespc = Namespace::GetNamespace(args, 0);
|
||||
const char* path_1 = DartUtils::GetNativeStringArgument(args, 1);
|
||||
const char* path_2 = DartUtils::GetNativeStringArgument(args, 2);
|
||||
File::Identical result = File::AreIdentical(namespc, path_1, path_2);
|
||||
File::Identical result = File::AreIdentical(namespc, path_1, namespc, path_2);
|
||||
if (result == File::kError) {
|
||||
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
|
||||
} else {
|
||||
@@ -1455,7 +1455,7 @@ CObject* File::IdenticalRequest(const CObjectArray& request) {
|
||||
CObjectString path1(request[1]);
|
||||
CObjectString path2(request[2]);
|
||||
File::Identical result =
|
||||
File::AreIdentical(namespc, path1.CString(), path2.CString());
|
||||
File::AreIdentical(namespc, path1.CString(), namespc, path2.CString());
|
||||
if (result == File::kError) {
|
||||
return CObject::NewOSError();
|
||||
}
|
||||
|
||||
+2
-1
@@ -250,8 +250,9 @@ class File : public ReferenceCounted<File> {
|
||||
static const char* PathSeparator();
|
||||
static const char* StringEscapedPathSeparator();
|
||||
static Type GetType(Namespace* namespc, const char* path, bool follow_links);
|
||||
static Identical AreIdentical(Namespace* namespc,
|
||||
static Identical AreIdentical(Namespace* namespc_1,
|
||||
const char* file_1,
|
||||
Namespace* namespc_2,
|
||||
const char* file_2);
|
||||
static StdioHandleType GetStdioHandleType(int fd);
|
||||
|
||||
|
||||
+17
-11
@@ -702,22 +702,28 @@ File::StdioHandleType File::GetStdioHandleType(int fd) {
|
||||
return kOther;
|
||||
}
|
||||
|
||||
File::Identical File::AreIdentical(Namespace* namespc,
|
||||
File::Identical File::AreIdentical(Namespace* namespc_1,
|
||||
const char* file_1,
|
||||
Namespace* namespc_2,
|
||||
const char* file_2) {
|
||||
NamespaceScope ns1(namespc, file_1);
|
||||
NamespaceScope ns2(namespc, file_2);
|
||||
struct stat file_1_info;
|
||||
struct stat file_2_info;
|
||||
int status = TEMP_FAILURE_RETRY(
|
||||
fstatat(ns1.fd(), ns1.path(), &file_1_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
int status;
|
||||
{
|
||||
NamespaceScope ns1(namespc_1, file_1);
|
||||
status = TEMP_FAILURE_RETRY(
|
||||
fstatat(ns1.fd(), ns1.path(), &file_1_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
}
|
||||
}
|
||||
status = TEMP_FAILURE_RETRY(
|
||||
fstatat(ns2.fd(), ns2.path(), &file_2_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
{
|
||||
NamespaceScope ns2(namespc_2, file_2);
|
||||
status = TEMP_FAILURE_RETRY(
|
||||
fstatat(ns2.fd(), ns2.path(), &file_2_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
}
|
||||
}
|
||||
return ((file_1_info.st_ino == file_2_info.st_ino) &&
|
||||
(file_1_info.st_dev == file_2_info.st_dev))
|
||||
|
||||
+17
-11
@@ -655,22 +655,28 @@ File::StdioHandleType File::GetStdioHandleType(int fd) {
|
||||
return kOther;
|
||||
}
|
||||
|
||||
File::Identical File::AreIdentical(Namespace* namespc,
|
||||
File::Identical File::AreIdentical(Namespace* namespc_1,
|
||||
const char* file_1,
|
||||
Namespace* namespc_2,
|
||||
const char* file_2) {
|
||||
NamespaceScope ns1(namespc, file_1);
|
||||
NamespaceScope ns2(namespc, file_2);
|
||||
struct stat file_1_info;
|
||||
struct stat file_2_info;
|
||||
int status = TEMP_FAILURE_RETRY(
|
||||
fstatat(ns1.fd(), ns1.path(), &file_1_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
int status;
|
||||
{
|
||||
NamespaceScope ns1(namespc_1, file_1);
|
||||
status = TEMP_FAILURE_RETRY(
|
||||
fstatat(ns1.fd(), ns1.path(), &file_1_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
}
|
||||
}
|
||||
status = TEMP_FAILURE_RETRY(
|
||||
fstatat(ns2.fd(), ns2.path(), &file_2_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
{
|
||||
NamespaceScope ns2(namespc_2, file_2);
|
||||
status = TEMP_FAILURE_RETRY(
|
||||
fstatat(ns2.fd(), ns2.path(), &file_2_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
}
|
||||
}
|
||||
return ((file_1_info.st_ino == file_2_info.st_ino) &&
|
||||
(file_1_info.st_dev == file_2_info.st_dev))
|
||||
|
||||
+17
-11
@@ -699,22 +699,28 @@ File::StdioHandleType File::GetStdioHandleType(int fd) {
|
||||
return kOther;
|
||||
}
|
||||
|
||||
File::Identical File::AreIdentical(Namespace* namespc,
|
||||
File::Identical File::AreIdentical(Namespace* namespc_1,
|
||||
const char* file_1,
|
||||
Namespace* namespc_2,
|
||||
const char* file_2) {
|
||||
NamespaceScope ns1(namespc, file_1);
|
||||
NamespaceScope ns2(namespc, file_2);
|
||||
struct stat64 file_1_info;
|
||||
struct stat64 file_2_info;
|
||||
int status = TEMP_FAILURE_RETRY(
|
||||
fstatat64(ns1.fd(), ns1.path(), &file_1_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
int status;
|
||||
{
|
||||
NamespaceScope ns1(namespc_1, file_1);
|
||||
status = TEMP_FAILURE_RETRY(
|
||||
fstatat64(ns1.fd(), ns1.path(), &file_1_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
}
|
||||
}
|
||||
status = TEMP_FAILURE_RETRY(
|
||||
fstatat64(ns2.fd(), ns2.path(), &file_2_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
{
|
||||
NamespaceScope ns2(namespc_2, file_2);
|
||||
status = TEMP_FAILURE_RETRY(
|
||||
fstatat64(ns2.fd(), ns2.path(), &file_2_info, AT_SYMLINK_NOFOLLOW));
|
||||
if (status == -1) {
|
||||
return File::kError;
|
||||
}
|
||||
}
|
||||
return ((file_1_info.st_ino == file_2_info.st_ino) &&
|
||||
(file_1_info.st_dev == file_2_info.st_dev))
|
||||
|
||||
@@ -619,9 +619,12 @@ File::StdioHandleType File::GetStdioHandleType(int fd) {
|
||||
return kOther;
|
||||
}
|
||||
|
||||
File::Identical File::AreIdentical(Namespace* namespc,
|
||||
File::Identical File::AreIdentical(Namespace* namespc_1,
|
||||
const char* file_1,
|
||||
Namespace* namespc_2,
|
||||
const char* file_2) {
|
||||
USE(namespc_1);
|
||||
USE(namespc_2);
|
||||
struct stat file_1_info;
|
||||
struct stat file_2_info;
|
||||
if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) ||
|
||||
|
||||
@@ -760,9 +760,12 @@ File::Type File::GetType(Namespace* namespc,
|
||||
return result;
|
||||
}
|
||||
|
||||
File::Identical File::AreIdentical(Namespace* namespc,
|
||||
File::Identical File::AreIdentical(Namespace* namespc_1,
|
||||
const char* file_1,
|
||||
Namespace* namespc_2,
|
||||
const char* file_2) {
|
||||
USE(namespc_1);
|
||||
USE(namespc_2);
|
||||
BY_HANDLE_FILE_INFORMATION file_info[2];
|
||||
const char* file_names[2] = {file_1, file_2};
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
|
||||
@@ -82,6 +82,7 @@ namespace bin {
|
||||
V(Filter_Process, 4) \
|
||||
V(Filter_Processed, 3) \
|
||||
V(InternetAddress_Parse, 1) \
|
||||
V(InternetAddress_RawAddrToString, 1) \
|
||||
V(IOService_NewServicePort, 0) \
|
||||
V(Namespace_Create, 2) \
|
||||
V(Namespace_GetDefault, 0) \
|
||||
@@ -130,11 +131,14 @@ namespace bin {
|
||||
V(SecurityContext_UseCertificateChainBytes, 3) \
|
||||
V(ServerSocket_Accept, 2) \
|
||||
V(ServerSocket_CreateBindListen, 7) \
|
||||
V(ServerSocket_CreateUnixDomainBindListen, 5) \
|
||||
V(SocketBase_IsBindError, 2) \
|
||||
V(Socket_Available, 1) \
|
||||
V(Socket_CreateBindConnect, 5) \
|
||||
V(Socket_CreateUnixDomainBindConnect, 4) \
|
||||
V(Socket_CreateBindDatagram, 6) \
|
||||
V(Socket_CreateConnect, 4) \
|
||||
V(Socket_CreateUnixDomainConnect, 3) \
|
||||
V(Socket_GetPort, 1) \
|
||||
V(Socket_GetRemotePeer, 1) \
|
||||
V(Socket_GetError, 1) \
|
||||
|
||||
+183
-10
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "bin/dartutils.h"
|
||||
#include "bin/eventhandler.h"
|
||||
#include "bin/file.h"
|
||||
#include "bin/io_buffer.h"
|
||||
#include "bin/isolate_data.h"
|
||||
#include "bin/lockers.h"
|
||||
@@ -178,7 +179,7 @@ Dart_Handle ListeningSocketRegistry::CreateBindListen(Dart_Handle socket_object,
|
||||
|
||||
Socket* socketfd = new Socket(fd);
|
||||
OSSocket* os_socket =
|
||||
new OSSocket(addr, allocated_port, v6_only, shared, socketfd);
|
||||
new OSSocket(addr, allocated_port, v6_only, shared, socketfd, NULL);
|
||||
os_socket->ref_count = 1;
|
||||
os_socket->next = first_os_socket;
|
||||
|
||||
@@ -192,6 +193,73 @@ Dart_Handle ListeningSocketRegistry::CreateBindListen(Dart_Handle socket_object,
|
||||
return Dart_True();
|
||||
}
|
||||
|
||||
Dart_Handle ListeningSocketRegistry::CreateUnixDomainBindListen(
|
||||
Dart_Handle socket_object,
|
||||
Namespace* namespc,
|
||||
const char* path,
|
||||
intptr_t backlog,
|
||||
bool shared) {
|
||||
MutexLocker ml(&mutex_);
|
||||
|
||||
if (unix_domain_sockets_ != NULL && File::Exists(namespc, path)) {
|
||||
// If there is a socket listening on this file. Ensure
|
||||
// that it was created with `shared` mode and current `shared`
|
||||
// is also true.
|
||||
OSSocket* os_socket = unix_domain_sockets_;
|
||||
OSSocket* os_socket_same_addr =
|
||||
FindOSSocketWithPath(os_socket, namespc, path);
|
||||
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 path.",
|
||||
OSError::kUnknown);
|
||||
return DartUtils::NewDartOSError(&os_error);
|
||||
}
|
||||
|
||||
// This socket creation is the exact same as the one which originally
|
||||
// created the socket. Feed the same fd and store it into the native field
|
||||
// of dart socket_object. Sockets here will share same fd but contain a
|
||||
// different port() through EventHandler_SendData.
|
||||
Socket* socketfd = new Socket(os_socket->fd);
|
||||
os_socket->ref_count++;
|
||||
// We set as a side-effect the file descriptor on the dart
|
||||
// socket_object.
|
||||
Socket::ReuseSocketIdNativeField(socket_object, socketfd,
|
||||
Socket::kFinalizerListening);
|
||||
InsertByFd(socketfd, os_socket);
|
||||
return Dart_True();
|
||||
}
|
||||
}
|
||||
|
||||
RawAddr addr;
|
||||
Dart_Handle result =
|
||||
SocketAddress::GetUnixDomainSockAddr(path, namespc, &addr);
|
||||
if (!Dart_IsNull(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// There is no socket listening on that path, so we create new one.
|
||||
intptr_t fd = ServerSocket::CreateUnixDomainBindListen(addr, backlog);
|
||||
|
||||
if (fd < 0) {
|
||||
return DartUtils::NewDartOSError();
|
||||
}
|
||||
|
||||
Socket* socketfd = new Socket(fd);
|
||||
OSSocket* os_socket =
|
||||
new OSSocket(addr, -1, false, shared, socketfd, namespc);
|
||||
os_socket->ref_count = 1;
|
||||
os_socket->next = unix_domain_sockets_;
|
||||
unix_domain_sockets_ = os_socket;
|
||||
InsertByFd(socketfd, os_socket);
|
||||
|
||||
Socket::ReuseSocketIdNativeField(socket_object, socketfd,
|
||||
Socket::kFinalizerListening);
|
||||
|
||||
return Dart_True();
|
||||
}
|
||||
|
||||
bool ListeningSocketRegistry::CloseOneSafe(OSSocket* os_socket,
|
||||
Socket* socket) {
|
||||
ASSERT(!mutex_.TryLock());
|
||||
@@ -202,7 +270,12 @@ bool ListeningSocketRegistry::CloseOneSafe(OSSocket* os_socket,
|
||||
if (os_socket->ref_count > 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unlink the socket file, if os_socket contains unix domain sockets.
|
||||
if (os_socket->address.addr.sa_family == AF_UNIX) {
|
||||
unlink(os_socket->address.un.sun_path);
|
||||
delete os_socket;
|
||||
return true;
|
||||
}
|
||||
OSSocket* prev = NULL;
|
||||
OSSocket* current = LookupByPort(os_socket->port);
|
||||
while (current != os_socket) {
|
||||
@@ -298,6 +371,72 @@ void FUNCTION_NAME(Socket_CreateBindConnect)(Dart_NativeArguments args) {
|
||||
}
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(Socket_CreateUnixDomainBindConnect)(
|
||||
Dart_NativeArguments args) {
|
||||
#if defined(HOST_OS_WINDOWS) || defined(HOST_OS_FUCHSIA)
|
||||
OSError os_error(
|
||||
-1, "Unix domain sockets are not available on this operating system.",
|
||||
OSError::kUnknown);
|
||||
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
|
||||
#else
|
||||
RawAddr addr;
|
||||
Dart_Handle address = Dart_GetNativeArgument(args, 1);
|
||||
ASSERT(Dart_IsString(address));
|
||||
Dart_Handle result = SocketAddress::GetUnixDomainSockAddr(
|
||||
DartUtils::GetStringValue(address), Namespace::GetNamespace(args, 3),
|
||||
&addr);
|
||||
if (!Dart_IsNull(result)) {
|
||||
return Dart_SetReturnValue(args, result);
|
||||
}
|
||||
|
||||
RawAddr sourceAddr;
|
||||
address = Dart_GetNativeArgument(args, 2);
|
||||
ASSERT(Dart_IsString(address));
|
||||
result = SocketAddress::GetUnixDomainSockAddr(
|
||||
DartUtils::GetStringValue(address), Namespace::GetNamespace(args, 3),
|
||||
&sourceAddr);
|
||||
if (!Dart_IsNull(result)) {
|
||||
return Dart_SetReturnValue(args, result);
|
||||
}
|
||||
|
||||
intptr_t socket = Socket::CreateUnixDomainBindConnect(addr, sourceAddr);
|
||||
if (socket >= 0) {
|
||||
Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
|
||||
Socket::kFinalizerNormal);
|
||||
Dart_SetReturnValue(args, Dart_True());
|
||||
} else {
|
||||
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
|
||||
}
|
||||
#endif // defined(HOST_OS_WINDOWS) || defined(HOST_OS_FUCHSIA)
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(Socket_CreateUnixDomainConnect)(Dart_NativeArguments args) {
|
||||
#if defined(HOST_OS_WINDOWS) || defined(HOST_OS_FUCHSIA)
|
||||
OSError os_error(
|
||||
-1, "Unix domain sockets are only available on linux, android and macos.",
|
||||
OSError::kUnknown);
|
||||
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
|
||||
#else
|
||||
RawAddr addr;
|
||||
Dart_Handle address = Dart_GetNativeArgument(args, 1);
|
||||
ASSERT(Dart_IsString(address));
|
||||
Dart_Handle result = SocketAddress::GetUnixDomainSockAddr(
|
||||
DartUtils::GetStringValue(address), Namespace::GetNamespace(args, 2),
|
||||
&addr);
|
||||
if (!Dart_IsNull(result)) {
|
||||
return Dart_SetReturnValue(args, result);
|
||||
}
|
||||
intptr_t socket = Socket::CreateUnixDomainConnect(addr);
|
||||
if (socket >= 0) {
|
||||
Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
|
||||
Socket::kFinalizerNormal);
|
||||
Dart_SetReturnValue(args, Dart_True());
|
||||
} else {
|
||||
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
|
||||
}
|
||||
#endif // defined(HOST_OS_WINDOWS) || defined(HOST_OS_FUCHSIA)
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(Socket_CreateBindDatagram)(Dart_NativeArguments args) {
|
||||
RawAddr addr;
|
||||
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
|
||||
@@ -423,18 +562,24 @@ void FUNCTION_NAME(Socket_RecvFrom)(Dart_NativeArguments args) {
|
||||
|
||||
// Get the port and clear it in the sockaddr structure.
|
||||
int port = SocketAddress::GetAddrPort(addr);
|
||||
// TODO(21403): Add checks for AF_UNIX, if unix domain sockets
|
||||
// are used in SOCK_DGRAM.
|
||||
enum internet_type { IPv4, IPv6 };
|
||||
internet_type type;
|
||||
if (addr.addr.sa_family == AF_INET) {
|
||||
addr.in.sin_port = 0;
|
||||
type = IPv4;
|
||||
} else {
|
||||
ASSERT(addr.addr.sa_family == AF_INET6);
|
||||
addr.in6.sin6_port = 0;
|
||||
type = IPv6;
|
||||
}
|
||||
// Format the address to a string using the numeric format.
|
||||
char numeric_address[INET6_ADDRSTRLEN];
|
||||
SocketBase::FormatNumericAddress(addr, numeric_address, INET6_ADDRSTRLEN);
|
||||
|
||||
// Create a Datagram object with the data and sender address and port.
|
||||
const int kNumArgs = 4;
|
||||
const int kNumArgs = 5;
|
||||
Dart_Handle dart_args[kNumArgs];
|
||||
dart_args[0] = data;
|
||||
dart_args[1] = Dart_NewStringFromCString(numeric_address);
|
||||
@@ -443,6 +588,7 @@ void FUNCTION_NAME(Socket_RecvFrom)(Dart_NativeArguments args) {
|
||||
}
|
||||
dart_args[2] = SocketAddress::ToTypedData(addr);
|
||||
dart_args[3] = Dart_NewInteger(port);
|
||||
dart_args[4] = Dart_NewInteger(type);
|
||||
if (Dart_IsError(dart_args[3])) {
|
||||
Dart_PropagateError(dart_args[3]);
|
||||
}
|
||||
@@ -550,7 +696,7 @@ void FUNCTION_NAME(Socket_GetPort)(Dart_NativeArguments args) {
|
||||
if (port > 0) {
|
||||
Dart_SetIntegerReturnValue(args, port);
|
||||
} else {
|
||||
Dart_ThrowException(DartUtils::NewDartOSError());
|
||||
Dart_SetReturnValue(args, DartUtils::NewDartOSError());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -561,14 +707,18 @@ void FUNCTION_NAME(Socket_GetRemotePeer)(Dart_NativeArguments args) {
|
||||
SocketAddress* addr = SocketBase::GetRemotePeer(socket->fd(), &port);
|
||||
if (addr != NULL) {
|
||||
Dart_Handle list = Dart_NewList(2);
|
||||
|
||||
Dart_Handle entry = Dart_NewList(3);
|
||||
Dart_ListSetAt(entry, 0, Dart_NewInteger(addr->GetType()));
|
||||
int type = addr->GetType();
|
||||
Dart_Handle entry;
|
||||
if (type == SocketAddress::TYPE_UNIX) {
|
||||
entry = Dart_NewList(2);
|
||||
} else {
|
||||
entry = Dart_NewList(3);
|
||||
RawAddr raw = addr->addr();
|
||||
Dart_ListSetAt(entry, 2, SocketAddress::ToTypedData(raw));
|
||||
}
|
||||
Dart_ListSetAt(entry, 0, Dart_NewInteger(type));
|
||||
Dart_ListSetAt(entry, 1, Dart_NewStringFromCString(addr->as_string()));
|
||||
|
||||
RawAddr raw = addr->addr();
|
||||
Dart_ListSetAt(entry, 2, SocketAddress::ToTypedData(raw));
|
||||
|
||||
Dart_ListSetAt(list, 0, entry);
|
||||
Dart_ListSetAt(list, 1, Dart_NewInteger(port));
|
||||
Dart_SetReturnValue(args, list);
|
||||
@@ -651,6 +801,29 @@ void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) {
|
||||
Dart_SetReturnValue(args, result);
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(ServerSocket_CreateUnixDomainBindListen)(
|
||||
Dart_NativeArguments args) {
|
||||
#if defined(HOST_OS_WINDOWS)
|
||||
OSError os_error(
|
||||
-1, "Unix domain sockets are only available on linux, android and macos.",
|
||||
OSError::kUnknown);
|
||||
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
|
||||
#else
|
||||
Dart_Handle address = Dart_GetNativeArgument(args, 1);
|
||||
ASSERT(Dart_IsString(address));
|
||||
const char* path = DartUtils::GetStringValue(address);
|
||||
int64_t backlog = DartUtils::GetInt64ValueCheckRange(
|
||||
Dart_GetNativeArgument(args, 2), 0, 65535);
|
||||
bool shared = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
|
||||
Namespace* namespc = Namespace::GetNamespace(args, 4);
|
||||
Dart_Handle socket_object = Dart_GetNativeArgument(args, 0);
|
||||
Dart_Handle result =
|
||||
ListeningSocketRegistry::Instance()->CreateUnixDomainBindListen(
|
||||
socket_object, namespc, path, backlog, shared);
|
||||
Dart_SetReturnValue(args, result);
|
||||
#endif // defined(HOST_OS_WINDOWS)
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(ServerSocket_Accept)(Dart_NativeArguments args) {
|
||||
Socket* socket =
|
||||
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
|
||||
|
||||
+40
-1
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "bin/builtin.h"
|
||||
#include "bin/dartutils.h"
|
||||
#include "bin/file.h"
|
||||
#include "bin/reference_counting.h"
|
||||
#include "bin/socket_base.h"
|
||||
#include "bin/thread.h"
|
||||
@@ -70,10 +71,13 @@ class Socket : public ReferenceCounted<Socket> {
|
||||
// Creates a socket which is bound and connected. The port to connect to is
|
||||
// specified as the port component of the passed RawAddr structure.
|
||||
static intptr_t CreateConnect(const RawAddr& addr);
|
||||
static intptr_t CreateUnixDomainConnect(const RawAddr& addr);
|
||||
// Creates a socket which is bound and connected. The port to connect to is
|
||||
// specified as the port component of the passed RawAddr structure.
|
||||
static intptr_t CreateBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr);
|
||||
static intptr_t CreateUnixDomainBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr);
|
||||
// Creates a datagram socket which is bound. The port to bind
|
||||
// to is specified as the port component of the RawAddr structure.
|
||||
static intptr_t CreateBindDatagram(const RawAddr& addr,
|
||||
@@ -146,6 +150,8 @@ class ServerSocket {
|
||||
static intptr_t CreateBindListen(const RawAddr& addr,
|
||||
intptr_t backlog,
|
||||
bool v6_only = false);
|
||||
static intptr_t CreateUnixDomainBindListen(const RawAddr& addr,
|
||||
intptr_t backlog);
|
||||
|
||||
// Start accepting on a newly created listening socket. If it was unable to
|
||||
// start accepting incoming sockets, the fd is invalidated.
|
||||
@@ -173,6 +179,8 @@ class ListeningSocketRegistry {
|
||||
|
||||
static void Cleanup();
|
||||
|
||||
// Bind `socket_object` to `addr`.
|
||||
// Return Dart_True() if succeed.
|
||||
// This function should be called from a dart runtime call in order to create
|
||||
// a new (potentially shared) socket.
|
||||
Dart_Handle CreateBindListen(Dart_Handle socket_object,
|
||||
@@ -180,6 +188,15 @@ class ListeningSocketRegistry {
|
||||
intptr_t backlog,
|
||||
bool v6_only,
|
||||
bool shared);
|
||||
// Bind unix domain socket`socket_object` to `path`.
|
||||
// Return Dart_True() if succeed.
|
||||
// This function should be called from a dart runtime call in order to create
|
||||
// a new socket.
|
||||
Dart_Handle CreateUnixDomainBindListen(Dart_Handle socket_object,
|
||||
Namespace* namespc,
|
||||
const char* path,
|
||||
intptr_t backlog,
|
||||
bool shared);
|
||||
|
||||
// This should be called from the event handler for every kCloseEvent it gets
|
||||
// on listening sockets.
|
||||
@@ -202,6 +219,10 @@ class ListeningSocketRegistry {
|
||||
int ref_count;
|
||||
intptr_t fd;
|
||||
|
||||
// Only applicable to Unix domain socket, where address.addr.sa_family
|
||||
// == AF_UNIX.
|
||||
Namespace* namespc;
|
||||
|
||||
// Singly linked lists of OSSocket instances which listen on the same port
|
||||
// but on different addresses.
|
||||
OSSocket* next;
|
||||
@@ -210,12 +231,14 @@ class ListeningSocketRegistry {
|
||||
int port,
|
||||
bool v6_only,
|
||||
bool shared,
|
||||
Socket* socketfd)
|
||||
Socket* socketfd,
|
||||
Namespace* namespc)
|
||||
: address(address),
|
||||
port(port),
|
||||
v6_only(v6_only),
|
||||
shared(shared),
|
||||
ref_count(0),
|
||||
namespc(namespc),
|
||||
next(NULL) {
|
||||
fd = socketfd->fd();
|
||||
}
|
||||
@@ -233,6 +256,20 @@ class ListeningSocketRegistry {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OSSocket* FindOSSocketWithPath(OSSocket* current,
|
||||
Namespace* namespc,
|
||||
const char* path) {
|
||||
while (current != NULL) {
|
||||
ASSERT(current->address.addr.sa_family == AF_UNIX);
|
||||
if (File::AreIdentical(current->namespc, current->address.un.sun_path,
|
||||
namespc, path) == File::kIdentical) {
|
||||
return current;
|
||||
}
|
||||
current = current->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool SameIntptrValue(void* key1, void* key2) {
|
||||
return reinterpret_cast<intptr_t>(key1) == reinterpret_cast<intptr_t>(key2);
|
||||
}
|
||||
@@ -259,6 +296,8 @@ class ListeningSocketRegistry {
|
||||
SimpleHashMap sockets_by_port_;
|
||||
SimpleHashMap sockets_by_fd_;
|
||||
|
||||
OSSocket* unix_domain_sockets_;
|
||||
|
||||
Mutex mutex_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ListeningSocketRegistry);
|
||||
|
||||
@@ -37,7 +37,7 @@ static intptr_t Create(const RawAddr& addr) {
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (!FDUtils::SetCloseOnExec(fd)) {
|
||||
if (!FDUtils::SetCloseOnExec(fd) || !FDUtils::SetNonBlocking(fd)) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -60,13 +60,23 @@ intptr_t Socket::CreateConnect(const RawAddr& addr) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (!FDUtils::SetNonBlocking(fd)) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
return Connect(fd, addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateUnixDomainConnect(const RawAddr& addr) {
|
||||
intptr_t fd = Create(addr);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
intptr_t result = TEMP_FAILURE_RETRY(connect(
|
||||
fd, (struct sockaddr*)&addr.un, SocketAddress::GetAddrLength(addr)));
|
||||
if (result == 0 || errno == EAGAIN) {
|
||||
return fd;
|
||||
}
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr) {
|
||||
intptr_t fd = Create(addr);
|
||||
@@ -76,7 +86,7 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
if ((result != 0) && (errno != EINPROGRESS)) {
|
||||
if (result != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -84,6 +94,29 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
return Connect(fd, addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr) {
|
||||
intptr_t fd = Create(addr);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
if (result != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = TEMP_FAILURE_RETRY(connect(fd, (struct sockaddr*)&addr.un,
|
||||
SocketAddress::GetAddrLength(addr)));
|
||||
if (result == 0 || errno == EAGAIN) {
|
||||
return fd;
|
||||
}
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateBindDatagram(const RawAddr& addr,
|
||||
bool reuseAddress,
|
||||
bool reusePort,
|
||||
@@ -189,6 +222,21 @@ intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
return fd;
|
||||
}
|
||||
|
||||
intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
|
||||
intptr_t backlog) {
|
||||
intptr_t fd = Create(addr);
|
||||
if (NO_RETRY_EXPECTED(bind(fd, (struct sockaddr*)&addr.un,
|
||||
SocketAddress::GetAddrLength(addr))) < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool ServerSocket::StartAccept(intptr_t fd) {
|
||||
USE(fd);
|
||||
return true;
|
||||
|
||||
+81
-17
@@ -9,6 +9,7 @@
|
||||
#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"
|
||||
@@ -20,16 +21,33 @@ namespace dart {
|
||||
namespace bin {
|
||||
|
||||
int SocketAddress::GetType() {
|
||||
if (addr_.ss.ss_family == AF_INET6) {
|
||||
return TYPE_IPV6;
|
||||
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;
|
||||
}
|
||||
return TYPE_IPV4;
|
||||
}
|
||||
|
||||
intptr_t SocketAddress::GetAddrLength(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 sockaddr_in6)
|
||||
: sizeof(struct sockaddr_in);
|
||||
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:
|
||||
return sizeof(struct sockaddr_un);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t SocketAddress::GetInAddrLength(const RawAddr& addr) {
|
||||
@@ -39,18 +57,24 @@ intptr_t SocketAddress::GetInAddrLength(const RawAddr& 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) {
|
||||
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 &&
|
||||
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;
|
||||
@@ -82,6 +106,25 @@ void SocketAddress::GetSockAddr(Dart_Handle obj, RawAddr* addr) {
|
||||
Dart_TypedDataReleaseData(obj);
|
||||
}
|
||||
|
||||
Dart_Handle SocketAddress::GetUnixDomainSockAddr(const char* path,
|
||||
Namespace* namespc,
|
||||
RawAddr* addr) {
|
||||
#if defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)
|
||||
NamespaceScope ns(namespc, path);
|
||||
path = ns.path();
|
||||
#endif // defined(HOST_OS_LINUX) || defined(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);
|
||||
return Dart_Null();
|
||||
}
|
||||
|
||||
int16_t SocketAddress::FromType(int type) {
|
||||
if (type == TYPE_ANY) {
|
||||
return AF_UNSPEC;
|
||||
@@ -89,6 +132,9 @@ int16_t SocketAddress::FromType(int type) {
|
||||
if (type == TYPE_IPV4) {
|
||||
return AF_INET;
|
||||
}
|
||||
if (type == TYPE_UNIX) {
|
||||
return AF_UNIX;
|
||||
}
|
||||
ASSERT((type == TYPE_IPV6) && "Invalid type");
|
||||
return AF_INET6;
|
||||
}
|
||||
@@ -96,16 +142,23 @@ int16_t SocketAddress::FromType(int type) {
|
||||
void SocketAddress::SetAddrPort(RawAddr* addr, intptr_t port) {
|
||||
if (addr->ss.ss_family == AF_INET) {
|
||||
addr->in.sin_port = htons(port);
|
||||
} else {
|
||||
} 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 {
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,16 +229,27 @@ void FUNCTION_NAME(InternetAddress_Parse)(Dart_NativeArguments args) {
|
||||
}
|
||||
}
|
||||
|
||||
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_SetReturnValue(args,
|
||||
Dart_NewBoolean(SocketBase::ListInterfacesSupported()));
|
||||
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_SetReturnValue(args, is_bind_error ? Dart_True() : Dart_False());
|
||||
Dart_SetBooleanReturnValue(args, is_bind_error ? true : false);
|
||||
}
|
||||
|
||||
} // namespace bin
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "bin/builtin.h"
|
||||
#include "bin/dartutils.h"
|
||||
#include "bin/file.h"
|
||||
#include "bin/thread.h"
|
||||
#include "bin/utils.h"
|
||||
#include "platform/allocation.h"
|
||||
@@ -34,6 +35,7 @@ namespace bin {
|
||||
union RawAddr {
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
struct sockaddr_un un;
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr addr;
|
||||
};
|
||||
@@ -44,6 +46,7 @@ class SocketAddress {
|
||||
TYPE_ANY = -1,
|
||||
TYPE_IPV4,
|
||||
TYPE_IPV6,
|
||||
TYPE_UNIX,
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -55,7 +58,9 @@ class SocketAddress {
|
||||
ADDRESS_LAST = ADDRESS_ANY_IP_V6,
|
||||
};
|
||||
|
||||
explicit SocketAddress(struct sockaddr* sa);
|
||||
// Unix domain socket may be unnamed. In this case addr_.un.sun_path contains
|
||||
// garbage and should not be inspected.
|
||||
explicit SocketAddress(struct sockaddr* sa, bool unnamed_unix_socket = false);
|
||||
|
||||
~SocketAddress() {}
|
||||
|
||||
@@ -68,6 +73,9 @@ class SocketAddress {
|
||||
static intptr_t GetInAddrLength(const RawAddr& addr);
|
||||
static bool AreAddressesEqual(const RawAddr& a, const RawAddr& b);
|
||||
static void GetSockAddr(Dart_Handle obj, RawAddr* addr);
|
||||
static Dart_Handle GetUnixDomainSockAddr(const char* path,
|
||||
Namespace* namespc,
|
||||
RawAddr* addr);
|
||||
static int16_t FromType(int type);
|
||||
static void SetAddrPort(RawAddr* addr, intptr_t port);
|
||||
static intptr_t GetAddrPort(const RawAddr& addr);
|
||||
@@ -77,7 +85,17 @@ class SocketAddress {
|
||||
static intptr_t GetAddrScope(const RawAddr& addr);
|
||||
|
||||
private:
|
||||
#if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || defined(HOST_OS_ANDROID)
|
||||
// Unix domain address is only on Linux, Mac OS and Android now.
|
||||
// unix(7) require sun_path to be 108 bytes on Linux and Android, 104 bytes on
|
||||
// Mac OS.
|
||||
static const intptr_t kMaxUnixPathLength =
|
||||
sizeof(((struct sockaddr_un*)0)->sun_path);
|
||||
char as_string_[kMaxUnixPathLength];
|
||||
#else
|
||||
char as_string_[INET6_ADDRSTRLEN];
|
||||
#endif // defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || \
|
||||
// defined(HOST_OS_ANDROID)
|
||||
RawAddr addr_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SocketAddress);
|
||||
@@ -214,6 +232,9 @@ class SocketBase : public AllStatic {
|
||||
OSError** os_error);
|
||||
|
||||
static bool ParseAddress(int type, const char* address, RawAddr* addr);
|
||||
|
||||
// Convert address from byte representation to human readable string.
|
||||
static bool RawAddrToString(RawAddr* addr, char* str);
|
||||
static bool FormatNumericAddress(const RawAddr& addr, char* address, int len);
|
||||
|
||||
// Whether ListInterfaces is supported.
|
||||
|
||||
@@ -26,11 +26,19 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
SocketAddress::SocketAddress(struct sockaddr* sa) {
|
||||
ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
|
||||
if (!SocketBase::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa),
|
||||
as_string_, INET6_ADDRSTRLEN)) {
|
||||
SocketAddress::SocketAddress(struct sockaddr* sa, bool unnamed_unix_socket) {
|
||||
if (unnamed_unix_socket) {
|
||||
// This is an unnamed unix domain socket.
|
||||
as_string_[0] = 0;
|
||||
} else if (sa->sa_family == AF_UNIX) {
|
||||
struct sockaddr_un* un = ((struct sockaddr_un*)sa);
|
||||
memmove(as_string_, un->sun_path, sizeof(un->sun_path));
|
||||
} else {
|
||||
ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
|
||||
if (!SocketBase::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa),
|
||||
as_string_, INET6_ADDRSTRLEN)) {
|
||||
as_string_[0] = 0;
|
||||
}
|
||||
}
|
||||
socklen_t salen = GetAddrLength(*reinterpret_cast<RawAddr*>(sa));
|
||||
memmove(reinterpret_cast<void*>(&addr_), sa, salen);
|
||||
@@ -140,6 +148,13 @@ SocketAddress* SocketBase::GetRemotePeer(intptr_t fd, intptr_t* port) {
|
||||
if (NO_RETRY_EXPECTED(getpeername(fd, &raw.addr, &size))) {
|
||||
return NULL;
|
||||
}
|
||||
// sockaddr_un contains sa_family_t sun_familty and char[] sun_path.
|
||||
// If size is the size of sa_familty_t, this is an unnamed socket and
|
||||
// sun_path contains garbage.
|
||||
if (size == sizeof(sa_family_t)) {
|
||||
*port = 0;
|
||||
return new SocketAddress(&raw.addr, true);
|
||||
}
|
||||
*port = SocketAddress::GetAddrPort(raw);
|
||||
return new SocketAddress(&raw.addr);
|
||||
}
|
||||
@@ -244,6 +259,16 @@ bool SocketBase::ParseAddress(int type, const char* address, RawAddr* addr) {
|
||||
return (result == 1);
|
||||
}
|
||||
|
||||
bool SocketBase::RawAddrToString(RawAddr* addr, char* str) {
|
||||
if (addr->addr.sa_family == AF_INET) {
|
||||
return inet_ntop(AF_INET, &addr->in.sin_addr, str, INET_ADDRSTRLEN) != NULL;
|
||||
} else {
|
||||
ASSERT(addr->addr.sa_family == AF_INET6);
|
||||
return inet_ntop(AF_INET6, &addr->in6.sin6_addr, str, INET6_ADDRSTRLEN) !=
|
||||
NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ShouldIncludeIfaAddrs(struct ifaddrs* ifa, int lookup_family) {
|
||||
if (ifa->ifa_addr == NULL) {
|
||||
// OpenVPN's virtual device tun0.
|
||||
|
||||
@@ -12,5 +12,6 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#endif // RUNTIME_BIN_SOCKET_BASE_ANDROID_H_
|
||||
|
||||
@@ -54,7 +54,11 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
SocketAddress::SocketAddress(struct sockaddr* sa) {
|
||||
SocketAddress::SocketAddress(struct sockaddr* sa, bool unnamed_unix_socket) {
|
||||
// Fuchsia does not support unix domain sockets.
|
||||
if (unnamed_unix_socket) {
|
||||
FATAL("Fuchsia does not support unix domain sockets.");
|
||||
}
|
||||
ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
|
||||
if (!SocketBase::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa),
|
||||
as_string_, INET6_ADDRSTRLEN)) {
|
||||
@@ -274,6 +278,16 @@ bool SocketBase::ParseAddress(int type, const char* address, RawAddr* addr) {
|
||||
return (result == 1);
|
||||
}
|
||||
|
||||
bool SocketBase::RawAddrToString(RawAddr* addr, char* str) {
|
||||
if (addr->addr.sa_family == AF_INET) {
|
||||
return inet_ntop(AF_INET, &addr->in.sin_addr, str, INET_ADDRSTRLEN) != NULL;
|
||||
} else {
|
||||
ASSERT(addr->addr.sa_family == AF_INET6);
|
||||
return inet_ntop(AF_INET6, &addr->in6.sin6_addr, str, INET6_ADDRSTRLEN) !=
|
||||
NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool SocketBase::ListInterfacesSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -26,11 +26,19 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
SocketAddress::SocketAddress(struct sockaddr* sa) {
|
||||
ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
|
||||
if (!SocketBase::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa),
|
||||
as_string_, INET6_ADDRSTRLEN)) {
|
||||
SocketAddress::SocketAddress(struct sockaddr* sa, bool unnamed_unix_socket) {
|
||||
if (unnamed_unix_socket) {
|
||||
// This is an unnamed unix domain socket.
|
||||
as_string_[0] = 0;
|
||||
} else if (sa->sa_family == AF_UNIX) {
|
||||
struct sockaddr_un* un = ((struct sockaddr_un*)sa);
|
||||
memmove(as_string_, un->sun_path, sizeof(un->sun_path));
|
||||
} else {
|
||||
ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
|
||||
if (!SocketBase::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa),
|
||||
as_string_, INET6_ADDRSTRLEN)) {
|
||||
as_string_[0] = 0;
|
||||
}
|
||||
}
|
||||
socklen_t salen = GetAddrLength(*reinterpret_cast<RawAddr*>(sa));
|
||||
memmove(reinterpret_cast<void*>(&addr_), sa, salen);
|
||||
@@ -140,6 +148,13 @@ SocketAddress* SocketBase::GetRemotePeer(intptr_t fd, intptr_t* port) {
|
||||
if (NO_RETRY_EXPECTED(getpeername(fd, &raw.addr, &size))) {
|
||||
return NULL;
|
||||
}
|
||||
// sockaddr_un contains sa_family_t sun_familty and char[] sun_path.
|
||||
// If size is the size of sa_familty_t, this is an unnamed socket and
|
||||
// sun_path contains garbage.
|
||||
if (size == sizeof(sa_family_t)) {
|
||||
*port = 0;
|
||||
return new SocketAddress(&raw.addr, true);
|
||||
}
|
||||
*port = SocketAddress::GetAddrPort(raw);
|
||||
return new SocketAddress(&raw.addr);
|
||||
}
|
||||
@@ -246,6 +261,16 @@ bool SocketBase::ParseAddress(int type, const char* address, RawAddr* addr) {
|
||||
return (result == 1);
|
||||
}
|
||||
|
||||
bool SocketBase::RawAddrToString(RawAddr* addr, char* str) {
|
||||
if (addr->addr.sa_family == AF_INET) {
|
||||
return inet_ntop(AF_INET, &addr->in.sin_addr, str, INET_ADDRSTRLEN) != NULL;
|
||||
} else {
|
||||
ASSERT(addr->addr.sa_family == AF_INET6);
|
||||
return inet_ntop(AF_INET6, &addr->in6.sin6_addr, str, INET6_ADDRSTRLEN) !=
|
||||
NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ShouldIncludeIfaAddrs(struct ifaddrs* ifa, int lookup_family) {
|
||||
if (ifa->ifa_addr == NULL) {
|
||||
// OpenVPN's virtual device tun0.
|
||||
|
||||
@@ -12,5 +12,6 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#endif // RUNTIME_BIN_SOCKET_BASE_LINUX_H_
|
||||
|
||||
@@ -25,11 +25,19 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
SocketAddress::SocketAddress(struct sockaddr* sa) {
|
||||
ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
|
||||
if (!SocketBase::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa),
|
||||
as_string_, INET6_ADDRSTRLEN)) {
|
||||
SocketAddress::SocketAddress(struct sockaddr* sa, bool unnamed_unix_socket) {
|
||||
if (unnamed_unix_socket) {
|
||||
// This is an unnamed unix domain socket.
|
||||
as_string_[0] = 0;
|
||||
} else if (sa->sa_family == AF_UNIX) {
|
||||
struct sockaddr_un* un = ((struct sockaddr_un*)sa);
|
||||
memmove(as_string_, un->sun_path, sizeof(un->sun_path));
|
||||
} else {
|
||||
ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
|
||||
if (!SocketBase::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa),
|
||||
as_string_, INET6_ADDRSTRLEN)) {
|
||||
as_string_[0] = 0;
|
||||
}
|
||||
}
|
||||
socklen_t salen = GetAddrLength(*reinterpret_cast<RawAddr*>(sa));
|
||||
memmove(reinterpret_cast<void*>(&addr_), sa, salen);
|
||||
@@ -139,6 +147,13 @@ SocketAddress* SocketBase::GetRemotePeer(intptr_t fd, intptr_t* port) {
|
||||
if (NO_RETRY_EXPECTED(getpeername(fd, &raw.addr, &size))) {
|
||||
return NULL;
|
||||
}
|
||||
// sockaddr_un contains sa_family_t sun_familty and char[] sun_path.
|
||||
// If size is the size of sa_familty_t, this is an unnamed socket and
|
||||
// sun_path contains garbage.
|
||||
if (size == sizeof(sa_family_t)) {
|
||||
*port = 0;
|
||||
return new SocketAddress(&raw.addr, true);
|
||||
}
|
||||
*port = SocketAddress::GetAddrPort(raw);
|
||||
return new SocketAddress(&raw.addr);
|
||||
}
|
||||
@@ -236,6 +251,16 @@ bool SocketBase::ParseAddress(int type, const char* address, RawAddr* addr) {
|
||||
return (result == 1);
|
||||
}
|
||||
|
||||
bool SocketBase::RawAddrToString(RawAddr* addr, char* str) {
|
||||
if (addr->addr.sa_family == AF_INET) {
|
||||
return inet_ntop(AF_INET, &addr->in.sin_addr, str, INET_ADDRSTRLEN) != NULL;
|
||||
} else {
|
||||
ASSERT(addr->addr.sa_family == AF_INET6);
|
||||
return inet_ntop(AF_INET6, &addr->in6.sin6_addr, str, INET6_ADDRSTRLEN) !=
|
||||
NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool ShouldIncludeIfaAddrs(struct ifaddrs* ifa, int lookup_family) {
|
||||
if (ifa->ifa_addr == NULL) {
|
||||
// OpenVPN's virtual device tun0.
|
||||
|
||||
@@ -12,5 +12,6 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#endif // RUNTIME_BIN_SOCKET_BASE_MACOS_H_
|
||||
|
||||
@@ -20,7 +20,10 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
SocketAddress::SocketAddress(struct sockaddr* sockaddr) {
|
||||
SocketAddress::SocketAddress(struct sockaddr* sockaddr,
|
||||
bool unnamed_unix_socket) {
|
||||
// Unix domain sockets not supported on Win. Remove this assert if enabled.
|
||||
ASSERT(!unnamed_unix_socket);
|
||||
ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
|
||||
RawAddr* raw = reinterpret_cast<RawAddr*>(sockaddr);
|
||||
|
||||
@@ -246,6 +249,31 @@ bool SocketBase::ParseAddress(int type, const char* address, RawAddr* addr) {
|
||||
return result == 1;
|
||||
}
|
||||
|
||||
bool SocketBase::RawAddrToString(RawAddr* addr, char* str) {
|
||||
// According to InetNtopW(), buffer should be large enough for at least 46
|
||||
// characters for IPv6 and 16 for IPv4.
|
||||
COMPILE_ASSERT(INET6_ADDRSTRLEN >= 46);
|
||||
wchar_t tmp_buffer[INET6_ADDRSTRLEN];
|
||||
if (addr->addr.sa_family == AF_INET) {
|
||||
if (InetNtop(AF_INET, &addr->in.sin_addr, tmp_buffer, INET_ADDRSTRLEN) ==
|
||||
NULL) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ASSERT(addr->addr.sa_family == AF_INET6);
|
||||
if (InetNtop(AF_INET6, &addr->in6.sin6_addr, tmp_buffer,
|
||||
INET6_ADDRSTRLEN) == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
WideToUtf8Scope wide_to_utf8_scope(tmp_buffer);
|
||||
if (wide_to_utf8_scope.length() <= INET6_ADDRSTRLEN) {
|
||||
strncpy(str, wide_to_utf8_scope.utf8(), INET6_ADDRSTRLEN);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SocketBase::ListInterfacesSupported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#error Do not include socket_base_win.h directly. Use socket_base.h.
|
||||
#endif
|
||||
|
||||
#include <afunix.h>
|
||||
#include <iphlpapi.h>
|
||||
#include <mswsock.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
@@ -109,12 +109,25 @@ intptr_t Socket::CreateConnect(const RawAddr& addr) {
|
||||
return Connect(fd, addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateUnixDomainConnect(const RawAddr& addr) {
|
||||
// Fuchsia does not support unix domain socket
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr) {
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr) {
|
||||
// Fuchsia does not support unix domain socket
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateBindDatagram(const RawAddr& addr,
|
||||
bool reuseAddress,
|
||||
bool reusePort,
|
||||
@@ -192,6 +205,13 @@ intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
return reinterpret_cast<intptr_t>(io_handle);
|
||||
}
|
||||
|
||||
intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
|
||||
intptr_t backlog) {
|
||||
// Fuchsia does not support unix domain socket.
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ServerSocket::StartAccept(intptr_t fd) {
|
||||
USE(fd);
|
||||
return true;
|
||||
|
||||
@@ -48,7 +48,7 @@ static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
if ((result == 0) || (errno == EINPROGRESS)) {
|
||||
return fd;
|
||||
}
|
||||
FDUtils::FDUtils::SaveErrorAndClose(fd);
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,20 @@ intptr_t Socket::CreateConnect(const RawAddr& addr) {
|
||||
return Connect(fd, addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateUnixDomainConnect(const RawAddr& addr) {
|
||||
intptr_t fd = Create(addr);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
intptr_t result = TEMP_FAILURE_RETRY(connect(
|
||||
fd, (struct sockaddr*)&addr.un, SocketAddress::GetAddrLength(addr)));
|
||||
if (result == 0 || errno == EAGAIN) {
|
||||
return fd;
|
||||
}
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr) {
|
||||
intptr_t fd = Create(addr);
|
||||
@@ -69,7 +83,7 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
if ((result != 0) && (errno != EINPROGRESS)) {
|
||||
if (result != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -77,6 +91,29 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
return Connect(fd, addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr) {
|
||||
intptr_t fd = Create(addr);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
if (result != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = TEMP_FAILURE_RETRY(connect(fd, (struct sockaddr*)&addr.un,
|
||||
SocketAddress::GetAddrLength(addr)));
|
||||
if (result == 0 || errno == EAGAIN) {
|
||||
return fd;
|
||||
}
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateBindDatagram(const RawAddr& addr,
|
||||
bool reuseAddress,
|
||||
bool reusePort,
|
||||
@@ -182,6 +219,21 @@ intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
return fd;
|
||||
}
|
||||
|
||||
intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
|
||||
intptr_t backlog) {
|
||||
intptr_t fd = Create(addr);
|
||||
if (NO_RETRY_EXPECTED(bind(fd, (struct sockaddr*)&addr.un,
|
||||
sizeof(struct sockaddr_un))) < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool ServerSocket::StartAccept(intptr_t fd) {
|
||||
USE(fd);
|
||||
return true;
|
||||
|
||||
@@ -66,6 +66,14 @@ intptr_t Socket::CreateConnect(const RawAddr& addr) {
|
||||
return Connect(fd, addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateUnixDomainConnect(const RawAddr& addr) {
|
||||
intptr_t fd = Create(addr);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
return Connect(fd, addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr) {
|
||||
intptr_t fd = Create(addr);
|
||||
@@ -75,7 +83,24 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
if ((result != 0) && (errno != EINPROGRESS)) {
|
||||
if (result != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return Connect(fd, addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr) {
|
||||
intptr_t fd = Create(addr);
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
if (result != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -199,6 +224,37 @@ intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
return fd;
|
||||
}
|
||||
|
||||
intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
|
||||
intptr_t backlog) {
|
||||
intptr_t fd;
|
||||
fd = NO_RETRY_EXPECTED(socket(addr.ss.ss_family, SOCK_STREAM, 0));
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!FDUtils::SetCloseOnExec(fd)) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NO_RETRY_EXPECTED(
|
||||
bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NO_RETRY_EXPECTED(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!FDUtils::SetNonBlocking(fd)) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool ServerSocket::StartAccept(intptr_t fd) {
|
||||
USE(fd);
|
||||
return true;
|
||||
|
||||
@@ -131,6 +131,13 @@ intptr_t Socket::CreateConnect(const RawAddr& addr) {
|
||||
return Connect(fd, addr, bind_addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateUnixDomainConnect(const RawAddr& addr) {
|
||||
// TODO(21403): Support unix domain socket on Windows
|
||||
// https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr) {
|
||||
intptr_t fd = Create(addr);
|
||||
@@ -141,6 +148,12 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
return Connect(fd, addr, source_addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr) {
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
intptr_t ServerSocket::Accept(intptr_t fd) {
|
||||
ListenSocket* listen_socket = reinterpret_cast<ListenSocket*>(fd);
|
||||
ClientSocket* client_socket = listen_socket->Accept();
|
||||
@@ -271,6 +284,14 @@ intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
return reinterpret_cast<intptr_t>(listen_socket);
|
||||
}
|
||||
|
||||
intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
|
||||
intptr_t backlog) {
|
||||
// TODO(21403): Support unix domain socket on Windows
|
||||
// https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ServerSocket::StartAccept(intptr_t fd) {
|
||||
ListenSocket* listen_socket = reinterpret_cast<ListenSocket*>(fd);
|
||||
listen_socket->EnsureInitialized(EventHandler::delegate());
|
||||
|
||||
@@ -38,7 +38,7 @@ static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
return fd;
|
||||
}
|
||||
ASSERT(errno != EINPROGRESS);
|
||||
FDUtils::FDUtils::SaveErrorAndClose(fd);
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
return fd;
|
||||
}
|
||||
ASSERT(errno != EINPROGRESS);
|
||||
FDUtils::FDUtils::SaveErrorAndClose(fd);
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
return fd;
|
||||
}
|
||||
ASSERT(errno != EINPROGRESS);
|
||||
FDUtils::FDUtils::SaveErrorAndClose(fd);
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
return fd;
|
||||
}
|
||||
ASSERT(errno != EINPROGRESS);
|
||||
FDUtils::FDUtils::SaveErrorAndClose(fd);
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -406,9 +406,16 @@ class InternetAddress {
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress(String address) {
|
||||
factory InternetAddress(String address, {InternetAddressType type}) {
|
||||
throw UnsupportedError("InternetAddress");
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress.fromRawAddress(Uint8List rawAddress,
|
||||
{InternetAddressType type}) {
|
||||
throw new UnsupportedError("InternetAddress.fromRawAddress");
|
||||
}
|
||||
|
||||
@patch
|
||||
static Future<List<InternetAddress>> lookup(String host,
|
||||
{InternetAddressType type = InternetAddressType.any}) {
|
||||
|
||||
@@ -406,9 +406,16 @@ class InternetAddress {
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress(String address) {
|
||||
factory InternetAddress(String address, {InternetAddressType type}) {
|
||||
throw new UnsupportedError("InternetAddress");
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress.fromRawAddress(Uint8List rawAddress,
|
||||
{InternetAddressType type}) {
|
||||
throw new UnsupportedError("InternetAddress.fromRawAddress");
|
||||
}
|
||||
|
||||
@patch
|
||||
static Future<List<InternetAddress>> lookup(String host,
|
||||
{InternetAddressType type: InternetAddressType.any}) {
|
||||
|
||||
@@ -71,8 +71,14 @@ class InternetAddress {
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress(String address) {
|
||||
return new _InternetAddress.parse(address);
|
||||
factory InternetAddress(String address, {InternetAddressType type}) {
|
||||
return _InternetAddress.fromString(address, type: type);
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress.fromRawAddress(Uint8List rawAddress,
|
||||
{InternetAddressType type}) {
|
||||
return _InternetAddress.fromRawAddress(rawAddress, type: type);
|
||||
}
|
||||
|
||||
@patch
|
||||
@@ -140,10 +146,7 @@ class _InternetAddress implements InternetAddress {
|
||||
final String _host;
|
||||
final Uint8List _in_addr;
|
||||
final int _scope_id;
|
||||
|
||||
InternetAddressType get type => _in_addr.length == _IPv4AddrLength
|
||||
? InternetAddressType.IPv4
|
||||
: InternetAddressType.IPv6;
|
||||
final InternetAddressType type;
|
||||
|
||||
String get host => _host != null ? _host : address;
|
||||
|
||||
@@ -159,6 +162,9 @@ class _InternetAddress implements InternetAddress {
|
||||
if (_in_addr[i] != 0) return false;
|
||||
}
|
||||
return _in_addr[_IPv6AddrLength - 1] == 1;
|
||||
|
||||
case InternetAddressType.unix:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,6 +177,9 @@ class _InternetAddress implements InternetAddress {
|
||||
case InternetAddressType.IPv6:
|
||||
// Checking for fe80::/10.
|
||||
return _in_addr[0] == 0xFE && (_in_addr[1] & 0xB0) == 0x80;
|
||||
|
||||
case InternetAddressType.unix:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,57 +192,103 @@ class _InternetAddress implements InternetAddress {
|
||||
case InternetAddressType.IPv6:
|
||||
// Checking for ff00::/8.
|
||||
return _in_addr[0] == 0xFF;
|
||||
|
||||
case InternetAddressType.unix:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<InternetAddress> reverse() => _NativeSocket.reverseLookup(this);
|
||||
Future<InternetAddress> reverse() {
|
||||
if (type == InternetAddressType.unix) {
|
||||
return Future.value(this);
|
||||
}
|
||||
return _NativeSocket.reverseLookup(this);
|
||||
}
|
||||
|
||||
_InternetAddress(this.address, this._host, this._in_addr,
|
||||
_InternetAddress(this.type, this.address, this._host, this._in_addr,
|
||||
[this._scope_id = 0]);
|
||||
|
||||
factory _InternetAddress.parse(String address) {
|
||||
if (address is! String) {
|
||||
throw new ArgumentError("Invalid internet address $address");
|
||||
factory _InternetAddress.fromString(String address,
|
||||
{InternetAddressType type}) {
|
||||
if (type == InternetAddressType.unix) {
|
||||
ArgumentError.checkNotNull(address, 'address');
|
||||
var rawAddress = FileSystemEntity._toUtf8Array(address);
|
||||
return _InternetAddress(
|
||||
InternetAddressType.unix, address, null, rawAddress);
|
||||
} else {
|
||||
if (address is! String) {
|
||||
throw ArgumentError("Invalid internet address $address");
|
||||
}
|
||||
var in_addr = _parse(address);
|
||||
if (in_addr == null) {
|
||||
throw ArgumentError("Invalid internet address $address");
|
||||
}
|
||||
InternetAddressType type = in_addr.length == _IPv4AddrLength
|
||||
? InternetAddressType.IPv4
|
||||
: InternetAddressType.IPv6;
|
||||
return _InternetAddress(type, address, null, in_addr);
|
||||
}
|
||||
var in_addr = _parse(address);
|
||||
if (in_addr == null) {
|
||||
throw new ArgumentError("Invalid internet address $address");
|
||||
}
|
||||
|
||||
factory _InternetAddress.fromRawAddress(Uint8List rawAddress,
|
||||
{InternetAddressType type}) {
|
||||
if (type == InternetAddressType.unix) {
|
||||
ArgumentError.checkNotNull(rawAddress, 'rawAddress');
|
||||
var rawPath = FileSystemEntity._toNullTerminatedUtf8Array(rawAddress);
|
||||
var address = FileSystemEntity._toStringFromUtf8Array(rawAddress);
|
||||
return _InternetAddress(InternetAddressType.unix, address, null, rawPath);
|
||||
} else {
|
||||
int type = -1;
|
||||
if (rawAddress.length == _IPv4AddrLength) {
|
||||
type = 0;
|
||||
} else {
|
||||
if (rawAddress.length != _IPv6AddrLength) {
|
||||
throw ArgumentError("Invalid internet address ${rawAddress}");
|
||||
}
|
||||
type = 1;
|
||||
}
|
||||
var address = _rawAddrToString(rawAddress);
|
||||
return _InternetAddress(
|
||||
InternetAddressType._from(type), address, null, rawAddress);
|
||||
}
|
||||
return new _InternetAddress(address, null, in_addr);
|
||||
}
|
||||
|
||||
factory _InternetAddress.fixed(int id) {
|
||||
switch (id) {
|
||||
case _addressLoopbackIPv4:
|
||||
var in_addr = new Uint8List(_IPv4AddrLength);
|
||||
var in_addr = Uint8List(_IPv4AddrLength);
|
||||
in_addr[0] = 127;
|
||||
in_addr[_IPv4AddrLength - 1] = 1;
|
||||
return new _InternetAddress("127.0.0.1", null, in_addr);
|
||||
return _InternetAddress(
|
||||
InternetAddressType.IPv4, "127.0.0.1", null, in_addr);
|
||||
case _addressLoopbackIPv6:
|
||||
var in_addr = new Uint8List(_IPv6AddrLength);
|
||||
var in_addr = Uint8List(_IPv6AddrLength);
|
||||
in_addr[_IPv6AddrLength - 1] = 1;
|
||||
return new _InternetAddress("::1", null, in_addr);
|
||||
return _InternetAddress(InternetAddressType.IPv6, "::1", null, in_addr);
|
||||
case _addressAnyIPv4:
|
||||
var in_addr = new Uint8List(_IPv4AddrLength);
|
||||
return new _InternetAddress("0.0.0.0", "0.0.0.0", in_addr);
|
||||
var in_addr = Uint8List(_IPv4AddrLength);
|
||||
return _InternetAddress(
|
||||
InternetAddressType.IPv4, "0.0.0.0", "0.0.0.0", in_addr);
|
||||
case _addressAnyIPv6:
|
||||
var in_addr = new Uint8List(_IPv6AddrLength);
|
||||
return new _InternetAddress("::", "::", in_addr);
|
||||
var in_addr = Uint8List(_IPv6AddrLength);
|
||||
return _InternetAddress(InternetAddressType.IPv6, "::", "::", in_addr);
|
||||
default:
|
||||
assert(false);
|
||||
throw new ArgumentError();
|
||||
throw ArgumentError();
|
||||
}
|
||||
}
|
||||
|
||||
// Create a clone of this _InternetAddress replacing the host.
|
||||
_InternetAddress _cloneWithNewHost(String host) {
|
||||
return new _InternetAddress(
|
||||
address, host, new Uint8List.fromList(_in_addr));
|
||||
return _InternetAddress(type, address, host, Uint8List.fromList(_in_addr));
|
||||
}
|
||||
|
||||
bool operator ==(other) {
|
||||
if (!(other is _InternetAddress)) return false;
|
||||
if (other.type != type) return false;
|
||||
if (type == InternetAddressType.unix) {
|
||||
return address == other.address;
|
||||
}
|
||||
bool equals = true;
|
||||
for (int i = 0; i < _in_addr.length && equals; i++) {
|
||||
equals = other._in_addr[i] == _in_addr[i];
|
||||
@@ -242,6 +297,9 @@ class _InternetAddress implements InternetAddress {
|
||||
}
|
||||
|
||||
int get hashCode {
|
||||
if (type == InternetAddressType.unix) {
|
||||
return address.hashCode;
|
||||
}
|
||||
int result = 1;
|
||||
for (int i = 0; i < _in_addr.length; i++) {
|
||||
result = (result * 31 + _in_addr[i]) & 0x3FFFFFFF;
|
||||
@@ -253,6 +311,9 @@ class _InternetAddress implements InternetAddress {
|
||||
return "InternetAddress('$address', ${type.name})";
|
||||
}
|
||||
|
||||
static String _rawAddrToString(Uint8List address)
|
||||
native "InternetAddress_RawAddrToString";
|
||||
|
||||
static Uint8List _parse(String address) native "InternetAddress_Parse";
|
||||
}
|
||||
|
||||
@@ -394,8 +455,8 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
throw createError(response, "Failed host lookup: '$host'");
|
||||
} else {
|
||||
return response.skip(1).map<InternetAddress>((result) {
|
||||
var type = new InternetAddressType._from(result[0]);
|
||||
return new _InternetAddress(result[1], host, result[2], result[3]);
|
||||
var type = InternetAddressType._from(result[0]);
|
||||
return _InternetAddress(type, result[1], host, result[2], result[3]);
|
||||
}).toList();
|
||||
}
|
||||
});
|
||||
@@ -423,10 +484,10 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
} else {
|
||||
var map = response.skip(1).fold(new Map<String, NetworkInterface>(),
|
||||
(map, result) {
|
||||
var type = new InternetAddressType._from(result[0]);
|
||||
var type = InternetAddressType._from(result[0]);
|
||||
var name = result[3];
|
||||
var index = result[4];
|
||||
var address = new _InternetAddress(result[1], "", result[2]);
|
||||
var address = _InternetAddress(type, result[1], "", result[2]);
|
||||
if (!includeLinkLocal && address.isLinkLocal) return map;
|
||||
if (!includeLoopback && address.isLoopback) return map;
|
||||
map.putIfAbsent(name, () => new _NetworkInterface(name, index));
|
||||
@@ -505,12 +566,23 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
socket.localAddress = address;
|
||||
var result;
|
||||
if (sourceAddress == null) {
|
||||
result = socket.nativeCreateConnect(
|
||||
address._in_addr, port, address._scope_id);
|
||||
if (address.type == InternetAddressType.unix) {
|
||||
result = socket.nativeCreateUnixDomainConnect(
|
||||
address.address, _Namespace._namespace);
|
||||
} else {
|
||||
result = socket.nativeCreateConnect(
|
||||
address._in_addr, port, address._scope_id);
|
||||
}
|
||||
} else {
|
||||
assert(sourceAddress is _InternetAddress);
|
||||
result = socket.nativeCreateBindConnect(address._in_addr, port,
|
||||
sourceAddress._in_addr, address._scope_id);
|
||||
if (address.type == InternetAddressType.unix) {
|
||||
assert(sourceAddress.type == InternetAddressType.unix);
|
||||
result = socket.nativeCreateUnixDomainBindConnect(
|
||||
address.address, sourceAddress.address, _Namespace._namespace);
|
||||
} else {
|
||||
result = socket.nativeCreateBindConnect(address._in_addr, port,
|
||||
sourceAddress._in_addr, address._scope_id);
|
||||
}
|
||||
}
|
||||
if (result is OSError) {
|
||||
// Keep first error, if present.
|
||||
@@ -642,8 +714,18 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
|
||||
var socket = new _NativeSocket.listen();
|
||||
socket.localAddress = address;
|
||||
var result = socket.nativeCreateBindListen(
|
||||
address._in_addr, port, backlog, v6Only, shared, address._scope_id);
|
||||
var result;
|
||||
if (address.type == InternetAddressType.unix) {
|
||||
var path = address.address;
|
||||
if (FileSystemEntity.isLinkSync(path)) {
|
||||
path = Link(path).targetSync();
|
||||
}
|
||||
result = socket.nativeCreateUnixDomainBindListen(
|
||||
path, backlog, shared, _Namespace._namespace);
|
||||
} else {
|
||||
result = socket.nativeCreateBindListen(
|
||||
address._in_addr, port, backlog, v6Only, shared, address._scope_id);
|
||||
}
|
||||
if (result is OSError) {
|
||||
throw new SocketException("Failed to create server socket",
|
||||
osError: result, address: address, port: port);
|
||||
@@ -885,12 +967,14 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
}
|
||||
|
||||
int get port {
|
||||
if (localAddress.type == InternetAddressType.unix) return 0;
|
||||
if (localPort != 0) return localPort;
|
||||
if (isClosing || isClosed) throw const SocketException.closed();
|
||||
return localPort = nativeGetPort();
|
||||
}
|
||||
|
||||
int get remotePort {
|
||||
if (localAddress.type == InternetAddressType.unix) return 0;
|
||||
if (isClosing || isClosed) throw const SocketException.closed();
|
||||
return nativeGetRemotePeer()[1];
|
||||
}
|
||||
@@ -902,7 +986,11 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
var result = nativeGetRemotePeer();
|
||||
var addr = result[0];
|
||||
var type = new InternetAddressType._from(addr[0]);
|
||||
return new _InternetAddress(addr[1], null, addr[2]);
|
||||
if (type == InternetAddressType.unix) {
|
||||
return _InternetAddress.fromString(addr[1],
|
||||
type: InternetAddressType.unix);
|
||||
}
|
||||
return _InternetAddress(type, addr[1], null, addr[2]);
|
||||
}
|
||||
|
||||
void issueReadEvent() {
|
||||
@@ -1247,11 +1335,17 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
int port) native "Socket_SendTo";
|
||||
nativeCreateConnect(Uint8List addr, int port, int scope_id)
|
||||
native "Socket_CreateConnect";
|
||||
nativeCreateUnixDomainConnect(String addr, _Namespace namespace)
|
||||
native "Socket_CreateUnixDomainConnect";
|
||||
nativeCreateBindConnect(Uint8List addr, int port, Uint8List sourceAddr,
|
||||
int scope_id) native "Socket_CreateBindConnect";
|
||||
nativeCreateUnixDomainBindConnect(String addr, String sourceAddr,
|
||||
_Namespace namespace) native "Socket_CreateUnixDomainBindConnect";
|
||||
bool isBindError(int errorNumber) native "SocketBase_IsBindError";
|
||||
nativeCreateBindListen(Uint8List addr, int port, int backlog, bool v6Only,
|
||||
bool shared, int scope_id) native "ServerSocket_CreateBindListen";
|
||||
nativeCreateUnixDomainBindListen(String addr, int backlog, bool shared,
|
||||
_Namespace namespace) native "ServerSocket_CreateUnixDomainBindListen";
|
||||
nativeCreateBindDatagram(Uint8List addr, int port, bool reuseAddress,
|
||||
bool reusePort, int ttl) native "Socket_CreateBindDatagram";
|
||||
bool nativeAccept(_NativeSocket socket) native "ServerSocket_Accept";
|
||||
@@ -2090,6 +2184,9 @@ class _RawDatagramSocket extends Stream<RawSocketEvent>
|
||||
|
||||
@pragma("vm:entry-point", "call")
|
||||
Datagram _makeDatagram(
|
||||
Uint8List data, String address, Uint8List in_addr, int port) {
|
||||
return new Datagram(data, new _InternetAddress(address, null, in_addr), port);
|
||||
Uint8List data, String address, Uint8List in_addr, int port, int type) {
|
||||
return new Datagram(
|
||||
data,
|
||||
_InternetAddress(InternetAddressType._from(type), address, null, in_addr),
|
||||
port);
|
||||
}
|
||||
|
||||
@@ -144,7 +144,12 @@ class _NativeSynchronousSocket extends _NativeSynchronousSocketNativeWrapper {
|
||||
throw result;
|
||||
}
|
||||
var addr = result[0];
|
||||
return new _InternetAddress(addr[1], null, addr[2]);
|
||||
var type = InternetAddressType._from(addr[0]);
|
||||
if (type == InternetAddressType.unix) {
|
||||
return _InternetAddress.fromString(addr[1],
|
||||
type: InternetAddressType.unix);
|
||||
}
|
||||
return _InternetAddress(type, addr[1], null, addr[2]);
|
||||
}
|
||||
|
||||
int get remotePort {
|
||||
@@ -188,7 +193,8 @@ class _NativeSynchronousSocket extends _NativeSynchronousSocketNativeWrapper {
|
||||
new List<_InternetAddress>(response.length);
|
||||
for (int i = 0; i < response.length; ++i) {
|
||||
var result = response[i];
|
||||
addresses[i] = new _InternetAddress(result[1], host, result[2]);
|
||||
var type = InternetAddressType._from(result[0]);
|
||||
addresses[i] = _InternetAddress(type, result[1], host, result[2]);
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
|
||||
+72
-24
@@ -8,11 +8,15 @@ part of dart.io;
|
||||
|
||||
/**
|
||||
* [InternetAddressType] is the type an [InternetAddress]. Currently,
|
||||
* IP version 4 (IPv4) and IP version 6 (IPv6) are supported.
|
||||
* IP version 4 (IPv4), IP version 6 (IPv6) and Unix domain address are
|
||||
* supported. Unix domain sockets are available only on Linux, MacOS and
|
||||
* Android.
|
||||
*/
|
||||
class InternetAddressType {
|
||||
static const InternetAddressType IPv4 = const InternetAddressType._(0);
|
||||
static const InternetAddressType IPv6 = const InternetAddressType._(1);
|
||||
@Since("2.8")
|
||||
static const InternetAddressType unix = const InternetAddressType._(2);
|
||||
static const InternetAddressType any = const InternetAddressType._(-1);
|
||||
|
||||
@Deprecated("Use IPv4 instead")
|
||||
@@ -27,8 +31,9 @@ class InternetAddressType {
|
||||
const InternetAddressType._(this._value);
|
||||
|
||||
factory InternetAddressType._from(int value) {
|
||||
if (value == 0) return IPv4;
|
||||
if (value == 1) return IPv6;
|
||||
if (value == IPv4._value) return IPv4;
|
||||
if (value == IPv6._value) return IPv6;
|
||||
if (value == unix._value) return unix;
|
||||
throw new ArgumentError("Invalid type: $value");
|
||||
}
|
||||
|
||||
@@ -43,6 +48,8 @@ class InternetAddressType {
|
||||
return "IPv4";
|
||||
case 1:
|
||||
return "IPv6";
|
||||
case 2:
|
||||
return "Unix";
|
||||
default:
|
||||
throw new ArgumentError("Invalid InternetAddress");
|
||||
}
|
||||
@@ -52,7 +59,7 @@ class InternetAddressType {
|
||||
}
|
||||
|
||||
/**
|
||||
* An internet address.
|
||||
* An internet address or a Unix domain address.
|
||||
*
|
||||
* This object holds an internet address. If this internet address
|
||||
* is the result of a DNS lookup, the address also holds the hostname
|
||||
@@ -95,27 +102,35 @@ abstract class InternetAddress {
|
||||
external static InternetAddress get ANY_IP_V6;
|
||||
|
||||
/**
|
||||
* The [type] of the [InternetAddress] specified what IP protocol.
|
||||
* The address family of the [InternetAddress].
|
||||
*/
|
||||
InternetAddressType get type;
|
||||
|
||||
/**
|
||||
* The numeric address of the host. For IPv4 addresses this is using
|
||||
* the dotted-decimal notation. For IPv6 it is using the
|
||||
* hexadecimal representation.
|
||||
* The numeric address of the host.
|
||||
*
|
||||
* For IPv4 addresses this is using the dotted-decimal notation.
|
||||
* For IPv6 it is using the hexadecimal representation.
|
||||
* For Unix domain addresses, this is a file path.
|
||||
*/
|
||||
String get address;
|
||||
|
||||
/**
|
||||
* The host used to lookup the address. If there is no host
|
||||
* associated with the address this returns the numeric address.
|
||||
* The host used to lookup the address.
|
||||
*
|
||||
* If there is no host associated with the address this returns the [address].
|
||||
*/
|
||||
String get host;
|
||||
|
||||
/**
|
||||
* Get the raw address of this [InternetAddress]. The result is either a
|
||||
* 4 or 16 byte long list. The returned list is a copy, making it possible
|
||||
* to change the list without modifying the [InternetAddress].
|
||||
* The raw address of this [InternetAddress].
|
||||
*
|
||||
* For an IP address, the result is either a 4 or 16 byte long list.
|
||||
* For a Unix domain address, UTF-8 encoded byte sequences that represents
|
||||
* [address] is returned.
|
||||
*
|
||||
* The returned list is a fresh copy, making it possible to change the list without
|
||||
* modifying the [InternetAddress].
|
||||
*/
|
||||
Uint8List get rawAddress;
|
||||
|
||||
@@ -135,17 +150,48 @@ abstract class InternetAddress {
|
||||
bool get isMulticast;
|
||||
|
||||
/**
|
||||
* Creates a new [InternetAddress] from a numeric address.
|
||||
* Creates a new [InternetAddress] from a numeric address or a file path.
|
||||
*
|
||||
* If the address in [address] is not a numeric IPv4
|
||||
* (dotted-decimal notation) or IPv6 (hexadecimal representation).
|
||||
* address [ArgumentError] is thrown.
|
||||
* If [type] is [InternetAddressType.IPv4], [address] must be a numeric IPv4
|
||||
* address (dotted-decimal notation).
|
||||
* If [type] is [InternetAddressType.IPv6], [address] must be a numeric IPv6
|
||||
* address (hexadecimal notation).
|
||||
* If [type] is [InternetAddressType.unix], [address] must be a a valid file
|
||||
* path.
|
||||
* If [type] is omitted, [address] must be either a numeric IPv4 or IPv6
|
||||
* address and the type is inferred from the format.
|
||||
*
|
||||
* To create a Unix domain address, [type] should be
|
||||
* [InternetAddressType.unix] and [address] should be a string.
|
||||
*/
|
||||
external factory InternetAddress(String address);
|
||||
external factory InternetAddress(String address,
|
||||
{@Since("2.8") InternetAddressType type});
|
||||
|
||||
/**
|
||||
* Perform a reverse dns lookup on the [address], creating a new
|
||||
* [InternetAddress] where the host field set to the result.
|
||||
* Creates a new [InternetAddress] from the provided raw address bytes.
|
||||
*
|
||||
* If the [type] is [InternetAddressType.IPv4], the [rawAddress] must have
|
||||
* length 4.
|
||||
* If the [type] is [InternetAddressType.IPv6], the [rawAddress] must have
|
||||
* length 16.
|
||||
* If the [type] is [InternetAddressType.IPv4], the [rawAddress] must be a
|
||||
* valid UTF-8 encoded file path.
|
||||
*
|
||||
* If [type] is omitted, the [rawAddress] must have a length of either 4 or
|
||||
* 16, in which case the type defaults to [InternetAddress.IPv4] or
|
||||
* [InternetAddress.IPv6] respectively.
|
||||
*/
|
||||
external factory InternetAddress.fromRawAddress(Uint8List rawAddress,
|
||||
{@Since("2.8") InternetAddressType type});
|
||||
|
||||
/**
|
||||
* Perform a reverse DNS lookup on this [address]
|
||||
*
|
||||
* Returns a new [InternetAddress] with the same address, but where the [host]
|
||||
* field set to the result of the lookup.
|
||||
*
|
||||
* If this address is Unix domain addresses, no lookup is performed and this
|
||||
* address is returned directly.
|
||||
*/
|
||||
Future<InternetAddress> reverse();
|
||||
|
||||
@@ -826,28 +872,30 @@ abstract class Socket implements Stream<Uint8List>, IOSink {
|
||||
void setRawOption(RawSocketOption option);
|
||||
|
||||
/**
|
||||
* Returns the port used by this socket.
|
||||
* The port used by this socket.
|
||||
*
|
||||
* Throws a [SocketException] if the socket is closed.
|
||||
* The port is 0 if the socket is a Unix domain socket.
|
||||
*/
|
||||
int get port;
|
||||
|
||||
/**
|
||||
* Returns the remote port connected to by this socket.
|
||||
* The remote port connected to by this socket.
|
||||
*
|
||||
* Throws a [SocketException] if the socket is closed.
|
||||
* The port is 0 if the socket is a Unix domain socket.
|
||||
*/
|
||||
int get remotePort;
|
||||
|
||||
/**
|
||||
* Returns the [InternetAddress] used to connect this socket.
|
||||
* The [InternetAddress] used to connect this socket.
|
||||
*
|
||||
* Throws a [SocketException] if the socket is closed.
|
||||
*/
|
||||
InternetAddress get address;
|
||||
|
||||
/**
|
||||
* Returns the remote [InternetAddress] connected to by this socket.
|
||||
* The remote [InternetAddress] connected to by this socket.
|
||||
*
|
||||
* Throws a [SocketException] if the socket is closed.
|
||||
*/
|
||||
|
||||
@@ -404,9 +404,16 @@ class InternetAddress {
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress(String address) {
|
||||
factory InternetAddress(String address, {InternetAddressType? type}) {
|
||||
throw UnsupportedError("InternetAddress");
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress.fromRawAddress(Uint8List rawAddress,
|
||||
{InternetAddressType? type}) {
|
||||
throw new UnsupportedError("InternetAddress.fromRawAddress");
|
||||
}
|
||||
|
||||
@patch
|
||||
static Future<List<InternetAddress>> lookup(String host,
|
||||
{InternetAddressType type = InternetAddressType.any}) {
|
||||
|
||||
@@ -404,9 +404,16 @@ class InternetAddress {
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress(String address) {
|
||||
factory InternetAddress(String address, {InternetAddressType? type}) {
|
||||
throw new UnsupportedError("InternetAddress");
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress.fromRawAddress(Uint8List rawAddress,
|
||||
{InternetAddressType? type}) {
|
||||
throw new UnsupportedError("InternetAddress.fromRawAddress");
|
||||
}
|
||||
|
||||
@patch
|
||||
static Future<List<InternetAddress>> lookup(String host,
|
||||
{InternetAddressType type: InternetAddressType.any}) {
|
||||
|
||||
@@ -68,8 +68,14 @@ class InternetAddress {
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress(String address) {
|
||||
return new _InternetAddress.parse(address);
|
||||
factory InternetAddress(String address, {InternetAddressType? type}) {
|
||||
return _InternetAddress.fromString(address, type: type);
|
||||
}
|
||||
|
||||
@patch
|
||||
factory InternetAddress.fromRawAddress(Uint8List rawAddress,
|
||||
{InternetAddressType? type}) {
|
||||
return _InternetAddress.fromRawAddress(rawAddress, type: type);
|
||||
}
|
||||
|
||||
@patch
|
||||
@@ -141,10 +147,7 @@ class _InternetAddress implements InternetAddress {
|
||||
final String? _host;
|
||||
final Uint8List _in_addr;
|
||||
final int _scope_id;
|
||||
|
||||
InternetAddressType get type => _in_addr.length == _IPv4AddrLength
|
||||
? InternetAddressType.IPv4
|
||||
: InternetAddressType.IPv6;
|
||||
final InternetAddressType type;
|
||||
|
||||
String get host => _host ?? address;
|
||||
|
||||
@@ -160,6 +163,9 @@ class _InternetAddress implements InternetAddress {
|
||||
if (_in_addr[i] != 0) return false;
|
||||
}
|
||||
return _in_addr[_IPv6AddrLength - 1] == 1;
|
||||
|
||||
case InternetAddressType.unix:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,6 +178,9 @@ class _InternetAddress implements InternetAddress {
|
||||
case InternetAddressType.IPv6:
|
||||
// Checking for fe80::/10.
|
||||
return _in_addr[0] == 0xFE && (_in_addr[1] & 0xB0) == 0x80;
|
||||
|
||||
case InternetAddressType.unix:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,56 +193,101 @@ class _InternetAddress implements InternetAddress {
|
||||
case InternetAddressType.IPv6:
|
||||
// Checking for ff00::/8.
|
||||
return _in_addr[0] == 0xFF;
|
||||
|
||||
case InternetAddressType.unix:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<InternetAddress> reverse() => _NativeSocket.reverseLookup(this);
|
||||
Future<InternetAddress> reverse() {
|
||||
if (type == InternetAddressType.unix) {
|
||||
return Future.value(this);
|
||||
}
|
||||
return _NativeSocket.reverseLookup(this);
|
||||
}
|
||||
|
||||
_InternetAddress(this.address, this._host, this._in_addr,
|
||||
_InternetAddress(this.type, this.address, this._host, this._in_addr,
|
||||
[this._scope_id = 0]);
|
||||
|
||||
factory _InternetAddress.parse(String address) {
|
||||
factory _InternetAddress.fromString(String address,
|
||||
{InternetAddressType? type}) {
|
||||
// TODO: Remove once non-nullability is sound.
|
||||
ArgumentError.checkNotNull(address, "address");
|
||||
var in_addr = _parse(address);
|
||||
if (in_addr == null) {
|
||||
throw new ArgumentError("Invalid internet address $address");
|
||||
ArgumentError.checkNotNull(address, 'address');
|
||||
if (type == InternetAddressType.unix) {
|
||||
var rawAddress = FileSystemEntity._toUtf8Array(address);
|
||||
return _InternetAddress(
|
||||
InternetAddressType.unix, address, null, rawAddress);
|
||||
} else {
|
||||
var in_addr = _parse(address);
|
||||
if (in_addr == null) {
|
||||
throw ArgumentError("Invalid internet address $address");
|
||||
}
|
||||
InternetAddressType type = in_addr.length == _IPv4AddrLength
|
||||
? InternetAddressType.IPv4
|
||||
: InternetAddressType.IPv6;
|
||||
return _InternetAddress(type, address, null, in_addr);
|
||||
}
|
||||
}
|
||||
|
||||
factory _InternetAddress.fromRawAddress(Uint8List rawAddress,
|
||||
{InternetAddressType? type}) {
|
||||
if (type == InternetAddressType.unix) {
|
||||
ArgumentError.checkNotNull(rawAddress, 'rawAddress');
|
||||
var rawPath = FileSystemEntity._toNullTerminatedUtf8Array(rawAddress);
|
||||
var address = FileSystemEntity._toStringFromUtf8Array(rawAddress);
|
||||
return _InternetAddress(InternetAddressType.unix, address, null, rawPath);
|
||||
} else {
|
||||
int type = -1;
|
||||
if (rawAddress.length == _IPv4AddrLength) {
|
||||
type = 0;
|
||||
} else {
|
||||
if (rawAddress.length != _IPv6AddrLength) {
|
||||
throw ArgumentError("Invalid internet address ${rawAddress}");
|
||||
}
|
||||
type = 1;
|
||||
}
|
||||
var address = _rawAddrToString(rawAddress);
|
||||
return _InternetAddress(
|
||||
InternetAddressType._from(type), address, null, rawAddress);
|
||||
}
|
||||
return new _InternetAddress(address, null, in_addr);
|
||||
}
|
||||
|
||||
factory _InternetAddress.fixed(int id) {
|
||||
switch (id) {
|
||||
case _addressLoopbackIPv4:
|
||||
var in_addr = new Uint8List(_IPv4AddrLength);
|
||||
var in_addr = Uint8List(_IPv4AddrLength);
|
||||
in_addr[0] = 127;
|
||||
in_addr[_IPv4AddrLength - 1] = 1;
|
||||
return new _InternetAddress("127.0.0.1", null, in_addr);
|
||||
return _InternetAddress(
|
||||
InternetAddressType.IPv4, "127.0.0.1", null, in_addr);
|
||||
case _addressLoopbackIPv6:
|
||||
var in_addr = new Uint8List(_IPv6AddrLength);
|
||||
var in_addr = Uint8List(_IPv6AddrLength);
|
||||
in_addr[_IPv6AddrLength - 1] = 1;
|
||||
return new _InternetAddress("::1", null, in_addr);
|
||||
return _InternetAddress(InternetAddressType.IPv6, "::1", null, in_addr);
|
||||
case _addressAnyIPv4:
|
||||
var in_addr = new Uint8List(_IPv4AddrLength);
|
||||
return new _InternetAddress("0.0.0.0", "0.0.0.0", in_addr);
|
||||
var in_addr = Uint8List(_IPv4AddrLength);
|
||||
return _InternetAddress(
|
||||
InternetAddressType.IPv4, "0.0.0.0", "0.0.0.0", in_addr);
|
||||
case _addressAnyIPv6:
|
||||
var in_addr = new Uint8List(_IPv6AddrLength);
|
||||
return new _InternetAddress("::", "::", in_addr);
|
||||
var in_addr = Uint8List(_IPv6AddrLength);
|
||||
return _InternetAddress(InternetAddressType.IPv6, "::", "::", in_addr);
|
||||
default:
|
||||
assert(false);
|
||||
throw new ArgumentError();
|
||||
throw ArgumentError();
|
||||
}
|
||||
}
|
||||
|
||||
// Create a clone of this _InternetAddress replacing the host.
|
||||
_InternetAddress _cloneWithNewHost(String host) {
|
||||
return new _InternetAddress(
|
||||
address, host, new Uint8List.fromList(_in_addr));
|
||||
return _InternetAddress(type, address, host, Uint8List.fromList(_in_addr));
|
||||
}
|
||||
|
||||
bool operator ==(other) {
|
||||
if (!(other is _InternetAddress)) return false;
|
||||
if (other.type != type) return false;
|
||||
if (type == InternetAddressType.unix) {
|
||||
return address == other.address;
|
||||
}
|
||||
bool equals = true;
|
||||
for (int i = 0; i < _in_addr.length && equals; i++) {
|
||||
equals = other._in_addr[i] == _in_addr[i];
|
||||
@@ -242,6 +296,9 @@ class _InternetAddress implements InternetAddress {
|
||||
}
|
||||
|
||||
int get hashCode {
|
||||
if (type == InternetAddressType.unix) {
|
||||
return address.hashCode;
|
||||
}
|
||||
int result = 1;
|
||||
for (int i = 0; i < _in_addr.length; i++) {
|
||||
result = (result * 31 + _in_addr[i]) & 0x3FFFFFFF;
|
||||
@@ -253,6 +310,9 @@ class _InternetAddress implements InternetAddress {
|
||||
return "InternetAddress('$address', ${type.name})";
|
||||
}
|
||||
|
||||
static String _rawAddrToString(Uint8List address)
|
||||
native "InternetAddress_RawAddrToString";
|
||||
|
||||
static Uint8List? _parse(String address) native "InternetAddress_Parse";
|
||||
}
|
||||
|
||||
@@ -394,8 +454,8 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
throw createError(response, "Failed host lookup: '$host'");
|
||||
} else {
|
||||
return response.skip(1).map<InternetAddress>((result) {
|
||||
var type = new InternetAddressType._from(result[0]);
|
||||
return new _InternetAddress(result[1], host, result[2], result[3]);
|
||||
var type = InternetAddressType._from(result[0]);
|
||||
return _InternetAddress(type, result[1], host, result[2], result[3]);
|
||||
}).toList();
|
||||
}
|
||||
});
|
||||
@@ -423,10 +483,10 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
} else {
|
||||
var map = response.skip(1).fold(new Map<String, NetworkInterface>(),
|
||||
(map, result) {
|
||||
var type = new InternetAddressType._from(result[0]);
|
||||
var type = InternetAddressType._from(result[0]);
|
||||
var name = result[3];
|
||||
var index = result[4];
|
||||
var address = new _InternetAddress(result[1], "", result[2]);
|
||||
var address = _InternetAddress(type, result[1], "", result[2]);
|
||||
if (!includeLinkLocal && address.isLinkLocal) return map;
|
||||
if (!includeLoopback && address.isLoopback) return map;
|
||||
map.putIfAbsent(name, () => new _NetworkInterface(name, index));
|
||||
@@ -505,12 +565,23 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
socket.localAddress = address;
|
||||
var result;
|
||||
if (sourceAddress == null) {
|
||||
result = socket.nativeCreateConnect(
|
||||
address._in_addr, port, address._scope_id);
|
||||
if (address.type == InternetAddressType.unix) {
|
||||
result = socket.nativeCreateUnixDomainConnect(
|
||||
address.address, _Namespace._namespace);
|
||||
} else {
|
||||
result = socket.nativeCreateConnect(
|
||||
address._in_addr, port, address._scope_id);
|
||||
}
|
||||
} else {
|
||||
assert(sourceAddress is _InternetAddress);
|
||||
result = socket.nativeCreateBindConnect(address._in_addr, port,
|
||||
sourceAddress._in_addr, address._scope_id);
|
||||
if (address.type == InternetAddressType.unix) {
|
||||
assert(sourceAddress.type == InternetAddressType.unix);
|
||||
result = socket.nativeCreateUnixDomainBindConnect(
|
||||
address.address, sourceAddress.address, _Namespace._namespace);
|
||||
} else {
|
||||
result = socket.nativeCreateBindConnect(address._in_addr, port,
|
||||
sourceAddress._in_addr, address._scope_id);
|
||||
}
|
||||
}
|
||||
if (result is OSError) {
|
||||
// Keep first error, if present.
|
||||
@@ -641,8 +712,18 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
|
||||
var socket = new _NativeSocket.listen();
|
||||
socket.localAddress = address;
|
||||
var result = socket.nativeCreateBindListen(
|
||||
address._in_addr, port, backlog, v6Only, shared, address._scope_id);
|
||||
var result;
|
||||
if (address.type == InternetAddressType.unix) {
|
||||
var path = address.address;
|
||||
if (FileSystemEntity.isLinkSync(path)) {
|
||||
path = Link(path).targetSync();
|
||||
}
|
||||
result = socket.nativeCreateUnixDomainBindListen(
|
||||
path, backlog, shared, _Namespace._namespace);
|
||||
} else {
|
||||
result = socket.nativeCreateBindListen(
|
||||
address._in_addr, port, backlog, v6Only, shared, address._scope_id);
|
||||
}
|
||||
if (result is OSError) {
|
||||
throw new SocketException("Failed to create server socket",
|
||||
osError: result, address: address, port: port);
|
||||
@@ -905,12 +986,14 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
}
|
||||
|
||||
int get port {
|
||||
if (localAddress.type == InternetAddressType.unix) return 0;
|
||||
if (localPort != 0) return localPort;
|
||||
if (isClosing || isClosed) throw const SocketException.closed();
|
||||
return localPort = nativeGetPort();
|
||||
}
|
||||
|
||||
int get remotePort {
|
||||
if (localAddress.type == InternetAddressType.unix) return 0;
|
||||
if (isClosing || isClosed) throw const SocketException.closed();
|
||||
return nativeGetRemotePeer()[1];
|
||||
}
|
||||
@@ -922,7 +1005,11 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
var result = nativeGetRemotePeer();
|
||||
var addr = result[0];
|
||||
var type = new InternetAddressType._from(addr[0]);
|
||||
return new _InternetAddress(addr[1], null, addr[2]);
|
||||
if (type == InternetAddressType.unix) {
|
||||
return _InternetAddress.fromString(addr[1],
|
||||
type: InternetAddressType.unix);
|
||||
}
|
||||
return _InternetAddress(type, addr[1], null, addr[2]);
|
||||
}
|
||||
|
||||
void issueReadEvent() {
|
||||
@@ -1274,11 +1361,17 @@ class _NativeSocket extends _NativeSocketNativeWrapper with _ServiceObject {
|
||||
int port) native "Socket_SendTo";
|
||||
nativeCreateConnect(Uint8List addr, int port, int scope_id)
|
||||
native "Socket_CreateConnect";
|
||||
nativeCreateUnixDomainConnect(String addr, _Namespace namespace)
|
||||
native "Socket_CreateUnixDomainConnect";
|
||||
nativeCreateBindConnect(Uint8List addr, int port, Uint8List sourceAddr,
|
||||
int scope_id) native "Socket_CreateBindConnect";
|
||||
nativeCreateUnixDomainBindConnect(String addr, String sourceAddr,
|
||||
_Namespace namespace) native "Socket_CreateUnixDomainBindConnect";
|
||||
bool isBindError(int errorNumber) native "SocketBase_IsBindError";
|
||||
nativeCreateBindListen(Uint8List addr, int port, int backlog, bool v6Only,
|
||||
bool shared, int scope_id) native "ServerSocket_CreateBindListen";
|
||||
nativeCreateUnixDomainBindListen(String addr, int backlog, bool shared,
|
||||
_Namespace namespace) native "ServerSocket_CreateUnixDomainBindListen";
|
||||
nativeCreateBindDatagram(Uint8List addr, int port, bool reuseAddress,
|
||||
bool reusePort, int ttl) native "Socket_CreateBindDatagram";
|
||||
bool nativeAccept(_NativeSocket socket) native "ServerSocket_Accept";
|
||||
@@ -2122,6 +2215,9 @@ class _RawDatagramSocket extends Stream<RawSocketEvent>
|
||||
|
||||
@pragma("vm:entry-point", "call")
|
||||
Datagram _makeDatagram(
|
||||
Uint8List data, String address, Uint8List in_addr, int port) {
|
||||
return new Datagram(data, new _InternetAddress(address, null, in_addr), port);
|
||||
Uint8List data, String address, Uint8List in_addr, int port, int type) {
|
||||
return new Datagram(
|
||||
data,
|
||||
_InternetAddress(InternetAddressType._from(type), address, null, in_addr),
|
||||
port);
|
||||
}
|
||||
|
||||
@@ -142,7 +142,12 @@ class _NativeSynchronousSocket extends _NativeSynchronousSocketNativeWrapper {
|
||||
throw result;
|
||||
}
|
||||
var addr = result[0];
|
||||
return new _InternetAddress(addr[1], null, addr[2]);
|
||||
var type = InternetAddressType._from(addr[0]);
|
||||
if (type == InternetAddressType.unix) {
|
||||
return _InternetAddress.fromString(addr[1],
|
||||
type: InternetAddressType.unix);
|
||||
}
|
||||
return _InternetAddress(type, addr[1], null, addr[2]);
|
||||
}
|
||||
|
||||
int get remotePort {
|
||||
@@ -184,7 +189,8 @@ class _NativeSynchronousSocket extends _NativeSynchronousSocketNativeWrapper {
|
||||
}
|
||||
return <_InternetAddress>[
|
||||
for (int i = 0; i < response.length; ++i)
|
||||
new _InternetAddress(response[i][1], host, response[i][2]),
|
||||
new _InternetAddress(InternetAddressType._from(response[i][0]),
|
||||
response[i][1], host, response[i][2]),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
+72
-24
@@ -6,11 +6,15 @@ part of dart.io;
|
||||
|
||||
/**
|
||||
* [InternetAddressType] is the type an [InternetAddress]. Currently,
|
||||
* IP version 4 (IPv4) and IP version 6 (IPv6) are supported.
|
||||
* IP version 4 (IPv4), IP version 6 (IPv6) and Unix domain address are
|
||||
* supported. Unix domain sockets are available only on Linux, MacOS and
|
||||
* Android.
|
||||
*/
|
||||
class InternetAddressType {
|
||||
static const InternetAddressType IPv4 = const InternetAddressType._(0);
|
||||
static const InternetAddressType IPv6 = const InternetAddressType._(1);
|
||||
@Since("2.8")
|
||||
static const InternetAddressType unix = const InternetAddressType._(2);
|
||||
static const InternetAddressType any = const InternetAddressType._(-1);
|
||||
|
||||
@Deprecated("Use IPv4 instead")
|
||||
@@ -25,8 +29,9 @@ class InternetAddressType {
|
||||
const InternetAddressType._(this._value);
|
||||
|
||||
factory InternetAddressType._from(int value) {
|
||||
if (value == 0) return IPv4;
|
||||
if (value == 1) return IPv6;
|
||||
if (value == IPv4._value) return IPv4;
|
||||
if (value == IPv6._value) return IPv6;
|
||||
if (value == unix._value) return unix;
|
||||
throw new ArgumentError("Invalid type: $value");
|
||||
}
|
||||
|
||||
@@ -41,6 +46,8 @@ class InternetAddressType {
|
||||
return "IPv4";
|
||||
case 1:
|
||||
return "IPv6";
|
||||
case 2:
|
||||
return "Unix";
|
||||
default:
|
||||
throw new ArgumentError("Invalid InternetAddress");
|
||||
}
|
||||
@@ -50,7 +57,7 @@ class InternetAddressType {
|
||||
}
|
||||
|
||||
/**
|
||||
* An internet address.
|
||||
* An internet address or a Unix domain address.
|
||||
*
|
||||
* This object holds an internet address. If this internet address
|
||||
* is the result of a DNS lookup, the address also holds the hostname
|
||||
@@ -93,27 +100,35 @@ abstract class InternetAddress {
|
||||
external static InternetAddress get ANY_IP_V6;
|
||||
|
||||
/**
|
||||
* The [type] of the [InternetAddress] specified what IP protocol.
|
||||
* The address family of the [InternetAddress].
|
||||
*/
|
||||
InternetAddressType get type;
|
||||
|
||||
/**
|
||||
* The numeric address of the host. For IPv4 addresses this is using
|
||||
* the dotted-decimal notation. For IPv6 it is using the
|
||||
* hexadecimal representation.
|
||||
* The numeric address of the host.
|
||||
*
|
||||
* For IPv4 addresses this is using the dotted-decimal notation.
|
||||
* For IPv6 it is using the hexadecimal representation.
|
||||
* For Unix domain addresses, this is a file path.
|
||||
*/
|
||||
String get address;
|
||||
|
||||
/**
|
||||
* The host used to lookup the address. If there is no host
|
||||
* associated with the address this returns the numeric address.
|
||||
* The host used to lookup the address.
|
||||
*
|
||||
* If there is no host associated with the address this returns the [address].
|
||||
*/
|
||||
String get host;
|
||||
|
||||
/**
|
||||
* Get the raw address of this [InternetAddress]. The result is either a
|
||||
* 4 or 16 byte long list. The returned list is a copy, making it possible
|
||||
* to change the list without modifying the [InternetAddress].
|
||||
* The raw address of this [InternetAddress].
|
||||
*
|
||||
* For an IP address, the result is either a 4 or 16 byte long list.
|
||||
* For a Unix domain address, UTF-8 encoded byte sequences that represents
|
||||
* [address] is returned.
|
||||
*
|
||||
* The returned list is a fresh copy, making it possible to change the list without
|
||||
* modifying the [InternetAddress].
|
||||
*/
|
||||
Uint8List get rawAddress;
|
||||
|
||||
@@ -133,17 +148,48 @@ abstract class InternetAddress {
|
||||
bool get isMulticast;
|
||||
|
||||
/**
|
||||
* Creates a new [InternetAddress] from a numeric address.
|
||||
* Creates a new [InternetAddress] from a numeric address or a file path.
|
||||
*
|
||||
* If the address in [address] is not a numeric IPv4
|
||||
* (dotted-decimal notation) or IPv6 (hexadecimal representation).
|
||||
* address [ArgumentError] is thrown.
|
||||
* If [type] is [InternetAddressType.IPv4], [address] must be a numeric IPv4
|
||||
* address (dotted-decimal notation).
|
||||
* If [type] is [InternetAddressType.IPv6], [address] must be a numeric IPv6
|
||||
* address (hexadecimal notation).
|
||||
* If [type] is [InternetAddressType.unix], [address] must be a a valid file
|
||||
* path.
|
||||
* If [type] is omitted, [address] must be either a numeric IPv4 or IPv6
|
||||
* address and the type is inferred from the format.
|
||||
*
|
||||
* To create a Unix domain address, [type] should be
|
||||
* [InternetAddressType.unix] and [address] should be a string.
|
||||
*/
|
||||
external factory InternetAddress(String address);
|
||||
external factory InternetAddress(String address,
|
||||
{@Since("2.8") InternetAddressType? type});
|
||||
|
||||
/**
|
||||
* Perform a reverse dns lookup on the [address], creating a new
|
||||
* [InternetAddress] where the host field set to the result.
|
||||
* Creates a new [InternetAddress] from the provided raw address bytes.
|
||||
*
|
||||
* If the [type] is [InternetAddressType.IPv4], the [rawAddress] must have
|
||||
* length 4.
|
||||
* If the [type] is [InternetAddressType.IPv6], the [rawAddress] must have
|
||||
* length 16.
|
||||
* If the [type] is [InternetAddressType.IPv4], the [rawAddress] must be a
|
||||
* valid UTF-8 encoded file path.
|
||||
*
|
||||
* If [type] is omitted, the [rawAddress] must have a length of either 4 or
|
||||
* 16, in which case the type defaults to [InternetAddress.IPv4] or
|
||||
* [InternetAddress.IPv6] respectively.
|
||||
*/
|
||||
external factory InternetAddress.fromRawAddress(Uint8List rawAddress,
|
||||
{@Since("2.8") InternetAddressType? type});
|
||||
|
||||
/**
|
||||
* Perform a reverse DNS lookup on this [address]
|
||||
*
|
||||
* Returns a new [InternetAddress] with the same address, but where the [host]
|
||||
* field set to the result of the lookup.
|
||||
*
|
||||
* If this address is Unix domain addresses, no lookup is performed and this
|
||||
* address is returned directly.
|
||||
*/
|
||||
Future<InternetAddress> reverse();
|
||||
|
||||
@@ -817,28 +863,30 @@ abstract class Socket implements Stream<Uint8List>, IOSink {
|
||||
void setRawOption(RawSocketOption option);
|
||||
|
||||
/**
|
||||
* Returns the port used by this socket.
|
||||
* The port used by this socket.
|
||||
*
|
||||
* Throws a [SocketException] if the socket is closed.
|
||||
* The port is 0 if the socket is a Unix domain socket.
|
||||
*/
|
||||
int get port;
|
||||
|
||||
/**
|
||||
* Returns the remote port connected to by this socket.
|
||||
* The remote port connected to by this socket.
|
||||
*
|
||||
* Throws a [SocketException] if the socket is closed.
|
||||
* The port is 0 if the socket is a Unix domain socket.
|
||||
*/
|
||||
int get remotePort;
|
||||
|
||||
/**
|
||||
* Returns the [InternetAddress] used to connect this socket.
|
||||
* The [InternetAddress] used to connect this socket.
|
||||
*
|
||||
* Throws a [SocketException] if the socket is closed.
|
||||
*/
|
||||
InternetAddress get address;
|
||||
|
||||
/**
|
||||
* Returns the remote [InternetAddress] connected to by this socket.
|
||||
* The remote [InternetAddress] connected to by this socket.
|
||||
*
|
||||
* Throws a [SocketException] if the socket is closed.
|
||||
*/
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
@@ -131,10 +133,40 @@ void testReverseLookup() {
|
||||
});
|
||||
}
|
||||
|
||||
void testRawAddress() {
|
||||
Uint8List addr = Uint8List.fromList([127, 0, 0, 1]);
|
||||
var address = InternetAddress.fromRawAddress(addr);
|
||||
Expect.equals('127.0.0.1', address.address);
|
||||
Expect.equals(address.address, address.host);
|
||||
Expect.equals(InternetAddressType.IPv4, address.type);
|
||||
}
|
||||
|
||||
void testRawAddressIPv6() {
|
||||
Uint8List addr =
|
||||
Uint8List.fromList([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||
var address = InternetAddress.fromRawAddress(addr);
|
||||
Expect.equals('::1', address.address);
|
||||
Expect.equals(address.address, address.host);
|
||||
Expect.equals(InternetAddressType.IPv6, address.type);
|
||||
}
|
||||
|
||||
void testRawPath() {
|
||||
var name = 'test_raw_path';
|
||||
Uint8List path = Uint8List.fromList(utf8.encode(name));
|
||||
var address =
|
||||
InternetAddress.fromRawAddress(path, type: InternetAddressType.unix);
|
||||
Expect.equals(name, address.address);
|
||||
Expect.equals(address.address, address.host);
|
||||
Expect.equals(InternetAddressType.unix, address.type);
|
||||
}
|
||||
|
||||
void main() {
|
||||
testDefaultAddresses();
|
||||
testConstructor();
|
||||
testEquality();
|
||||
testLookup();
|
||||
testReverseLookup();
|
||||
testRawAddress();
|
||||
testRawAddressIPv6();
|
||||
testRawPath();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2020, 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.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
Future testAddress(Uint8List name, String addr,
|
||||
{InternetAddressType? type}) async {
|
||||
var address = InternetAddress.fromRawAddress(name, type: type);
|
||||
Expect.equals(address.address, addr);
|
||||
var server = await ServerSocket.bind(address, 0);
|
||||
var client = await Socket.connect(address, server.port);
|
||||
var completer = Completer();
|
||||
server.listen((socket) async {
|
||||
Expect.equals(socket.port, server.port);
|
||||
Expect.equals(client.port, socket.remotePort);
|
||||
Expect.equals(client.remotePort, socket.port);
|
||||
|
||||
Expect.equals(client.remoteAddress, address);
|
||||
socket.destroy();
|
||||
client.destroy();
|
||||
await server.close();
|
||||
completer.complete();
|
||||
});
|
||||
await completer.future;
|
||||
}
|
||||
|
||||
Future<void> testUnixAddress() async {
|
||||
Directory dir = Directory.systemTemp.createTempSync();
|
||||
var name = 'raw_path_test';
|
||||
try {
|
||||
final file = File('${dir.path}/$name');
|
||||
Uint8List path = Uint8List.fromList(utf8.encode(file.path));
|
||||
var address =
|
||||
InternetAddress.fromRawAddress(path, type: InternetAddressType.unix);
|
||||
Expect.isTrue(address.address.toString().endsWith(name));
|
||||
|
||||
// Test socket
|
||||
var server = await ServerSocket.bind(address, 0);
|
||||
var client = await Socket.connect(address, server.port);
|
||||
var completer = Completer<void>();
|
||||
server.listen((socket) async {
|
||||
Expect.equals(socket.port, server.port);
|
||||
Expect.equals(client.port, socket.remotePort);
|
||||
Expect.equals(client.remotePort, socket.port);
|
||||
|
||||
Expect.equals(client.remoteAddress, address);
|
||||
socket.destroy();
|
||||
client.destroy();
|
||||
await server.close();
|
||||
completer.complete();
|
||||
});
|
||||
await completer.future;
|
||||
} finally {
|
||||
dir.deleteSync(recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
void main() async {
|
||||
// Test for internet address ipv4 ('127.0.0.1').
|
||||
Uint8List addr = Uint8List.fromList([127, 0, 0, 1]);
|
||||
await testAddress(addr, '127.0.0.1');
|
||||
|
||||
// Test unix socket
|
||||
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
|
||||
await testUnixAddress();
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,11 @@
|
||||
// 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.
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "dart:async";
|
||||
import "dart:io";
|
||||
import "dart:typed_data";
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void testHostAndPort() {
|
||||
ServerSocket.bind("::1", 0).then((server) {
|
||||
@@ -29,6 +32,30 @@ void testHostAndPort() {
|
||||
});
|
||||
}
|
||||
|
||||
void main() {
|
||||
testHostAndPort();
|
||||
Future<void> testRawAddress() async {
|
||||
var list =
|
||||
Uint8List.fromList([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||
var addr = '::1';
|
||||
var address = InternetAddress.fromRawAddress(list);
|
||||
Expect.equals(address.address, addr);
|
||||
var server = await ServerSocket.bind(address, 0);
|
||||
var client = await Socket.connect(address, server.port);
|
||||
var completer = Completer<void>();
|
||||
server.listen((socket) async {
|
||||
Expect.equals(socket.port, server.port);
|
||||
Expect.equals(client.port, socket.remotePort);
|
||||
Expect.equals(client.remotePort, socket.port);
|
||||
|
||||
Expect.equals(client.remoteAddress, address);
|
||||
socket.destroy();
|
||||
client.destroy();
|
||||
await server.close();
|
||||
completer.complete();
|
||||
});
|
||||
await completer.future;
|
||||
}
|
||||
|
||||
void main() async {
|
||||
testHostAndPort();
|
||||
await testRawAddress();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
// Copyright (c) 2020, 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.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
Future testAddress(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var server = await ServerSocket.bind(address, 0);
|
||||
|
||||
var type = FileSystemEntity.typeSync(address.address);
|
||||
|
||||
var client = await Socket.connect(address, server.port);
|
||||
var completer = Completer<void>();
|
||||
server.listen((socket) async {
|
||||
Expect.equals(socket.port, 0);
|
||||
Expect.equals(socket.port, server.port);
|
||||
Expect.equals(client.port, socket.remotePort);
|
||||
Expect.equals(client.remotePort, socket.port);
|
||||
|
||||
// Client has not bound to a path. This is an unnamed socket.
|
||||
Expect.equals(socket.remoteAddress.toString(), "InternetAddress('', Unix)");
|
||||
Expect.equals(client.remoteAddress.toString(), address.toString());
|
||||
socket.destroy();
|
||||
client.destroy();
|
||||
await server.close();
|
||||
completer.complete();
|
||||
});
|
||||
await completer.future;
|
||||
}
|
||||
|
||||
testBindShared(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var socket = await ServerSocket.bind(address, 0, shared: true);
|
||||
Expect.isTrue(socket.port == 0);
|
||||
|
||||
// Same path
|
||||
var socket2 = await ServerSocket.bind(address, 0, shared: true);
|
||||
Expect.equals(socket.address.address, socket2.address.address);
|
||||
Expect.equals(socket.port, socket2.port);
|
||||
|
||||
// Test relative path
|
||||
var path = name.substring(name.lastIndexOf('/') + 1);
|
||||
address = InternetAddress('${name}/../${path}/sock',
|
||||
type: InternetAddressType.unix);
|
||||
|
||||
var socket3 = await ServerSocket.bind(address, 0, shared: true);
|
||||
Expect.isTrue(FileSystemEntity.identicalSync(
|
||||
socket.address.address, socket3.address.address));
|
||||
Expect.equals(socket.port, socket2.port);
|
||||
await socket.close();
|
||||
await socket2.close();
|
||||
await socket3.close();
|
||||
}
|
||||
|
||||
testBind(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var server = await ServerSocket.bind(address, 0, shared: false);
|
||||
Expect.isTrue(server.address.toString().contains(name));
|
||||
// Unix domain socket does not have a valid port number.
|
||||
Expect.equals(server.port, 0);
|
||||
|
||||
var type = FileSystemEntity.typeSync(address.address);
|
||||
|
||||
var sub;
|
||||
sub = server.listen((s) {
|
||||
sub.cancel();
|
||||
server.close();
|
||||
});
|
||||
|
||||
var socket = await Socket.connect(address, server.port);
|
||||
socket.write(" socket content");
|
||||
|
||||
await socket.destroy();
|
||||
await server.close();
|
||||
}
|
||||
|
||||
Future testListenCloseListenClose(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
ServerSocket socket = await ServerSocket.bind(address, 0, shared: true);
|
||||
ServerSocket socket2 =
|
||||
await ServerSocket.bind(address, socket.port, shared: true);
|
||||
|
||||
// The second socket should have kept the OS socket alive. We can therefore
|
||||
// test if it is working correctly.
|
||||
await socket.close();
|
||||
|
||||
var type = FileSystemEntity.typeSync(address.address);
|
||||
|
||||
// For robustness we ignore any clients unrelated to this test.
|
||||
List<int> sendData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
socket2.listen((Socket client) async {
|
||||
client.add(sendData);
|
||||
await Future.wait([client.drain(), client.close()]);
|
||||
});
|
||||
|
||||
final client = await Socket.connect(address, socket2.port);
|
||||
List<int> data = [];
|
||||
var completer = Completer<void>();
|
||||
client.listen(data.addAll, onDone: () {
|
||||
Expect.listEquals(sendData, data);
|
||||
completer.complete();
|
||||
});
|
||||
await completer.future;
|
||||
await client.close();
|
||||
|
||||
// Close the second server socket.
|
||||
await socket2.close();
|
||||
}
|
||||
|
||||
Future testSourceAddressConnect(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
ServerSocket server = await ServerSocket.bind(address, 0);
|
||||
|
||||
var completer = Completer<void>();
|
||||
var localAddress =
|
||||
InternetAddress('$name/local', type: InternetAddressType.unix);
|
||||
server.listen((Socket socket) async {
|
||||
Expect.equals(socket.address.address, address.address);
|
||||
Expect.equals(socket.remoteAddress.address, localAddress.address);
|
||||
socket.drain();
|
||||
socket.close();
|
||||
completer.complete();
|
||||
});
|
||||
|
||||
var type = FileSystemEntity.typeSync(address.address);
|
||||
|
||||
Socket client =
|
||||
await Socket.connect(address, server.port, sourceAddress: localAddress);
|
||||
Expect.equals(client.remoteAddress.address, address.address);
|
||||
await completer.future;
|
||||
await client.close();
|
||||
await client.drain();
|
||||
await server.close();
|
||||
}
|
||||
|
||||
// Create socket in temp directory
|
||||
Future withTempDir(String prefix, void test(Directory dir)) async {
|
||||
var tempDir = Directory.systemTemp.createTempSync(prefix);
|
||||
try {
|
||||
await test(tempDir);
|
||||
} finally {
|
||||
tempDir.deleteSync(recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testAddress('${dir.path}');
|
||||
});
|
||||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testBind('${dir.path}');
|
||||
});
|
||||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testBindShared('${dir.path}');
|
||||
});
|
||||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testListenCloseListenClose('${dir.path}');
|
||||
});
|
||||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testSourceAddressConnect('${dir.path}');
|
||||
});
|
||||
} catch (e) {
|
||||
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
|
||||
Expect.fail("Unexpected exceptions are thrown");
|
||||
} else {
|
||||
Expect.isTrue(e is SocketException);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
@@ -131,10 +133,39 @@ void testReverseLookup() {
|
||||
});
|
||||
}
|
||||
|
||||
void testRawAddress() {
|
||||
Uint8List addr = Uint8List.fromList([127, 0, 0, 1]);
|
||||
var address = InternetAddress.fromRawAddress(addr);
|
||||
Expect.equals('127.0.0.1', address.address);
|
||||
Expect.equals(address.address, address.host);
|
||||
Expect.equals(InternetAddressType.IPv4, address.type);
|
||||
}
|
||||
|
||||
void testRawAddressIPv6() {
|
||||
Uint8List addr =
|
||||
Uint8List.fromList([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||
var address = InternetAddress.fromRawAddress(addr);
|
||||
Expect.equals('::1', address.address);
|
||||
Expect.equals(address.address, address.host);
|
||||
Expect.equals(InternetAddressType.IPv6, address.type);
|
||||
}
|
||||
|
||||
void testRawPath() {
|
||||
var name = 'test_raw_path';
|
||||
var address = InternetAddress.fromRawAddress(utf8.encode(name),
|
||||
type: InternetAddressType.unix);
|
||||
Expect.equals(name, address.address);
|
||||
Expect.equals(address.address, address.host);
|
||||
Expect.equals(InternetAddressType.unix, address.type);
|
||||
}
|
||||
|
||||
void main() {
|
||||
testDefaultAddresses();
|
||||
testConstructor();
|
||||
testEquality();
|
||||
testLookup();
|
||||
testReverseLookup();
|
||||
testRawAddress();
|
||||
testRawAddressIPv6();
|
||||
testRawPath();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2020, 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.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
Future testAddress(Uint8List name, String addr,
|
||||
{InternetAddressType type}) async {
|
||||
var address = InternetAddress.fromRawAddress(name, type: type);
|
||||
Expect.equals(address.address, addr);
|
||||
var server = await ServerSocket.bind(address, 0);
|
||||
var client = await Socket.connect(address, server.port);
|
||||
var completer = Completer();
|
||||
server.listen((socket) async {
|
||||
Expect.equals(socket.port, server.port);
|
||||
Expect.equals(client.port, socket.remotePort);
|
||||
Expect.equals(client.remotePort, socket.port);
|
||||
|
||||
Expect.equals(client.remoteAddress, address);
|
||||
socket.destroy();
|
||||
client.destroy();
|
||||
await server.close();
|
||||
completer.complete();
|
||||
});
|
||||
await completer.future;
|
||||
}
|
||||
|
||||
Future<void> testUnixAddress() async {
|
||||
Directory dir = Directory.systemTemp.createTempSync();
|
||||
var name = 'raw_path_test';
|
||||
try {
|
||||
var file = File('${dir.path}/$name');
|
||||
var address = InternetAddress.fromRawAddress(utf8.encode(file.path),
|
||||
type: InternetAddressType.unix);
|
||||
Expect.isTrue(address.address.toString().endsWith(name));
|
||||
|
||||
// Test socket
|
||||
var server = await ServerSocket.bind(address, 0);
|
||||
var client = await Socket.connect(address, server.port);
|
||||
var completer = Completer<void>();
|
||||
server.listen((socket) async {
|
||||
Expect.equals(socket.port, server.port);
|
||||
Expect.equals(client.port, socket.remotePort);
|
||||
Expect.equals(client.remotePort, socket.port);
|
||||
|
||||
Expect.equals(client.remoteAddress, address);
|
||||
socket.destroy();
|
||||
client.destroy();
|
||||
await server.close();
|
||||
completer.complete();
|
||||
});
|
||||
await completer.future;
|
||||
} finally {
|
||||
dir.deleteSync(recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
void main() async {
|
||||
// Test for internet address ipv4 ('127.0.0.1').
|
||||
Uint8List addr = Uint8List.fromList([127, 0, 0, 1]);
|
||||
await testAddress(addr, '127.0.0.1');
|
||||
|
||||
// Test unix socket
|
||||
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
|
||||
await testUnixAddress();
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,11 @@
|
||||
// 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.
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
import "dart:async";
|
||||
import "dart:io";
|
||||
import "dart:typed_data";
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
void testHostAndPort() {
|
||||
ServerSocket.bind("::1", 0).then((server) {
|
||||
@@ -29,6 +32,30 @@ void testHostAndPort() {
|
||||
});
|
||||
}
|
||||
|
||||
void main() {
|
||||
testHostAndPort();
|
||||
Future<void> testRawAddress() async {
|
||||
var list =
|
||||
Uint8List.fromList([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
|
||||
var addr = '::1';
|
||||
var address = InternetAddress.fromRawAddress(list);
|
||||
Expect.equals(address.address, addr);
|
||||
var server = await ServerSocket.bind(address, 0);
|
||||
var client = await Socket.connect(address, server.port);
|
||||
var completer = Completer<void>();
|
||||
server.listen((socket) async {
|
||||
Expect.equals(socket.port, server.port);
|
||||
Expect.equals(client.port, socket.remotePort);
|
||||
Expect.equals(client.remotePort, socket.port);
|
||||
|
||||
Expect.equals(client.remoteAddress, address);
|
||||
socket.destroy();
|
||||
client.destroy();
|
||||
await server.close();
|
||||
completer.complete();
|
||||
});
|
||||
await completer.future;
|
||||
}
|
||||
|
||||
void main() async {
|
||||
testHostAndPort();
|
||||
await testRawAddress();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
// Copyright (c) 2020, 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.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
Future testAddress(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var server = await ServerSocket.bind(address, 0);
|
||||
|
||||
var type = FileSystemEntity.typeSync(address.address);
|
||||
|
||||
var client = await Socket.connect(address, server.port);
|
||||
var completer = Completer<void>();
|
||||
server.listen((socket) async {
|
||||
Expect.equals(socket.port, 0);
|
||||
Expect.equals(socket.port, server.port);
|
||||
Expect.equals(client.port, socket.remotePort);
|
||||
Expect.equals(client.remotePort, socket.port);
|
||||
|
||||
// Client has not bound to a path. This is an unnamed socket.
|
||||
Expect.equals(socket.remoteAddress.toString(), "InternetAddress('', Unix)");
|
||||
Expect.equals(client.remoteAddress.toString(), address.toString());
|
||||
socket.destroy();
|
||||
client.destroy();
|
||||
await server.close();
|
||||
completer.complete();
|
||||
});
|
||||
await completer.future;
|
||||
}
|
||||
|
||||
testBindShared(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var socket = await ServerSocket.bind(address, 0, shared: true);
|
||||
Expect.isTrue(socket.port == 0);
|
||||
|
||||
// Same path
|
||||
var socket2 = await ServerSocket.bind(address, 0, shared: true);
|
||||
Expect.equals(socket.address.address, socket2.address.address);
|
||||
Expect.equals(socket.port, socket2.port);
|
||||
|
||||
// Test relative path
|
||||
var path = name.substring(name.lastIndexOf('/') + 1);
|
||||
address = InternetAddress('${name}/../${path}/sock',
|
||||
type: InternetAddressType.unix);
|
||||
|
||||
var socket3 = await ServerSocket.bind(address, 0, shared: true);
|
||||
Expect.isTrue(FileSystemEntity.identicalSync(
|
||||
socket.address.address, socket3.address.address));
|
||||
Expect.equals(socket.port, socket2.port);
|
||||
await socket.close();
|
||||
await socket2.close();
|
||||
await socket3.close();
|
||||
}
|
||||
|
||||
testBind(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var server = await ServerSocket.bind(address, 0, shared: false);
|
||||
Expect.isTrue(server.address.toString().contains(name));
|
||||
// Unix domain socket does not have a valid port number.
|
||||
Expect.equals(server.port, 0);
|
||||
|
||||
var type = FileSystemEntity.typeSync(address.address);
|
||||
|
||||
var sub;
|
||||
sub = server.listen((s) {
|
||||
sub.cancel();
|
||||
server.close();
|
||||
});
|
||||
|
||||
var socket = await Socket.connect(address, server.port);
|
||||
socket.write(" socket content");
|
||||
|
||||
await socket.destroy();
|
||||
await server.close();
|
||||
}
|
||||
|
||||
Future testListenCloseListenClose(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
ServerSocket socket = await ServerSocket.bind(address, 0, shared: true);
|
||||
ServerSocket socket2 =
|
||||
await ServerSocket.bind(address, socket.port, shared: true);
|
||||
|
||||
// The second socket should have kept the OS socket alive. We can therefore
|
||||
// test if it is working correctly.
|
||||
await socket.close();
|
||||
|
||||
var type = FileSystemEntity.typeSync(address.address);
|
||||
|
||||
// For robustness we ignore any clients unrelated to this test.
|
||||
List<int> sendData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
||||
socket2.listen((Socket client) async {
|
||||
client.add(sendData);
|
||||
await Future.wait([client.drain(), client.close()]);
|
||||
});
|
||||
|
||||
final client = await Socket.connect(address, socket2.port);
|
||||
List<int> data = [];
|
||||
var completer = Completer<void>();
|
||||
client.listen(data.addAll, onDone: () {
|
||||
Expect.listEquals(sendData, data);
|
||||
completer.complete();
|
||||
});
|
||||
await completer.future;
|
||||
await client.close();
|
||||
|
||||
// Close the second server socket.
|
||||
await socket2.close();
|
||||
}
|
||||
|
||||
Future testSourceAddressConnect(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
ServerSocket server = await ServerSocket.bind(address, 0);
|
||||
|
||||
var completer = Completer<void>();
|
||||
var localAddress =
|
||||
InternetAddress('$name/local', type: InternetAddressType.unix);
|
||||
server.listen((Socket socket) async {
|
||||
Expect.equals(socket.address.address, address.address);
|
||||
Expect.equals(socket.remoteAddress.address, localAddress.address);
|
||||
socket.drain();
|
||||
socket.close();
|
||||
completer.complete();
|
||||
});
|
||||
|
||||
var type = FileSystemEntity.typeSync(address.address);
|
||||
|
||||
Socket client =
|
||||
await Socket.connect(address, server.port, sourceAddress: localAddress);
|
||||
Expect.equals(client.remoteAddress.address, address.address);
|
||||
await completer.future;
|
||||
await client.close();
|
||||
await client.drain();
|
||||
await server.close();
|
||||
}
|
||||
|
||||
// Create socket in temp directory
|
||||
Future withTempDir(String prefix, void test(Directory dir)) async {
|
||||
var tempDir = Directory.systemTemp.createTempSync(prefix);
|
||||
try {
|
||||
await test(tempDir);
|
||||
} finally {
|
||||
tempDir.deleteSync(recursive: true);
|
||||
}
|
||||
}
|
||||
|
||||
void main() async {
|
||||
try {
|
||||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testAddress('${dir.path}');
|
||||
});
|
||||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testBind('${dir.path}');
|
||||
});
|
||||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testBindShared('${dir.path}');
|
||||
});
|
||||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testListenCloseListenClose('${dir.path}');
|
||||
});
|
||||
await withTempDir('unix_socket_test', (Directory dir) async {
|
||||
await testSourceAddressConnect('${dir.path}');
|
||||
});
|
||||
} catch (e) {
|
||||
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
|
||||
Expect.fail("Unexpected exceptions are thrown");
|
||||
} else {
|
||||
Expect.isTrue(e is SocketException);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user