Flutter Engine
The Flutter Engine
socket_base.cc
Go to the documentation of this file.
1// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "bin/socket_base.h"
6
7#include <errno.h> // NOLINT
8
9#include "bin/dartutils.h"
10#include "bin/io_buffer.h"
11#include "bin/isolate_data.h"
12#include "bin/lockers.h"
13#include "bin/thread.h"
15#include "bin/utils.h"
16
17#include "include/dart_api.h"
18
19#include "platform/globals.h"
20#include "platform/utils.h"
21
22namespace dart {
23namespace bin {
24
26 switch (addr_.ss.ss_family) {
27 case AF_INET6:
28 return TYPE_IPV6;
29 case AF_INET:
30 return TYPE_IPV4;
31 case AF_UNIX:
32 return TYPE_UNIX;
33 default:
35 return TYPE_ANY;
36 }
37}
38
40 bool unnamed_unix_socket) {
41 ASSERT((addr.ss.ss_family == AF_INET) || (addr.ss.ss_family == AF_INET6) ||
42 (addr.ss.ss_family == AF_UNIX));
43 switch (addr.ss.ss_family) {
44 case AF_INET6:
45 return sizeof(struct sockaddr_in6);
46 case AF_INET:
47 return sizeof(struct sockaddr_in);
48 case AF_UNIX: {
49 // For an abstract UNIX socket, trailing null bytes in the name are
50 // meaningful. That is, the bytes '\0/tmp/dbus-xxxx' are a different name
51 // than '\0/tmp/dbus-xxxx\0\0\0...'. The length of the address structure
52 // passed to connect() etc. tells those calls how many bytes of the name
53 // to look at. Therefore, when computing the length of the address in
54 // this case, any trailing null bytes are trimmed.
55 // TODO(dart:io): Support abstract UNIX socket addresses that have
56 // trailing null bytes on purpose.
57 // https://github.com/dart-lang/sdk/issues/46158
58 intptr_t nulls = 0;
59 if (!unnamed_unix_socket && addr.un.sun_path[0] == '\0') {
60 intptr_t i = sizeof(addr.un.sun_path) - 1;
61 while (addr.un.sun_path[i] == '\0') {
62 nulls++;
63 i--;
64 }
65 }
66 return sizeof(struct sockaddr_un) - nulls;
67 }
68 default:
70 return 0;
71 }
72}
73
75 ASSERT((addr.ss.ss_family == AF_INET) || (addr.ss.ss_family == AF_INET6));
76 return (addr.ss.ss_family == AF_INET6) ? sizeof(struct in6_addr)
77 : sizeof(struct in_addr);
78}
79
80bool SocketAddress::AreAddressesEqual(const RawAddr& a, const RawAddr& b) {
81 if (a.ss.ss_family != b.ss.ss_family) {
82 return false;
83 }
84 if (a.ss.ss_family == AF_INET) {
85 return memcmp(&a.in.sin_addr, &b.in.sin_addr, sizeof(a.in.sin_addr)) == 0;
86 } else if (a.ss.ss_family == AF_INET6) {
87 return memcmp(&a.in6.sin6_addr, &b.in6.sin6_addr,
88 sizeof(a.in6.sin6_addr)) == 0 &&
89 a.in6.sin6_scope_id == b.in6.sin6_scope_id;
90 } else if (a.ss.ss_family == AF_UNIX) {
91 // This is not used anywhere. The comparison of file path is done via
92 // File::AreIdentical().
93 int len = sizeof(a.un.sun_path);
94 for (int i = 0; i < len; i++) {
95 if (a.un.sun_path[i] != b.un.sun_path[i]) return false;
96 if (a.un.sun_path[i] == '\0') return true;
97 }
98 return true;
99 } else {
100 UNREACHABLE();
101 return false;
102 }
103}
104
106 Dart_TypedData_Type data_type;
107 uint8_t* data = nullptr;
108 intptr_t len;
110 obj, &data_type, reinterpret_cast<void**>(&data), &len);
111 if (Dart_IsError(result)) {
113 }
114 if ((data_type != Dart_TypedData_kUint8) ||
115 ((len != sizeof(in_addr)) && (len != sizeof(in6_addr)))) {
116 Dart_PropagateError(Dart_NewApiError("Unexpected type for socket address"));
117 }
118 memset(reinterpret_cast<void*>(addr), 0, sizeof(RawAddr));
119 if (len == sizeof(in_addr)) {
120 addr->in.sin_family = AF_INET;
121 memmove(reinterpret_cast<void*>(&addr->in.sin_addr), data, len);
122 } else {
123 ASSERT(len == sizeof(in6_addr));
124 addr->in6.sin6_family = AF_INET6;
125 memmove(reinterpret_cast<void*>(&addr->in6.sin6_addr), data, len);
126 }
128}
129
131 Namespace* namespc,
132 RawAddr* addr) {
133#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
134 NamespaceScope ns(namespc, path);
135 path = ns.path();
136 bool is_abstract = (path[0] == '@');
137 if (is_abstract) {
138 // The following 107 bytes after the leading null byte represents the name
139 // of unix domain socket. Without reseting, even users provide the same path
140 // for bind and connect, they actually represent two different address and
141 // connection will be rejected.
142 bzero(addr->un.sun_path, sizeof(addr->un.sun_path));
143 }
144#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
145 if (sizeof(path) > sizeof(addr->un.sun_path)) {
146 OSError os_error(-1,
147 "The length of path exceeds the limit. "
148 "Check out man 7 unix page",
150 return DartUtils::NewDartOSError(&os_error);
151 }
152 addr->un.sun_family = AF_UNIX;
153 Utils::SNPrint(addr->un.sun_path, sizeof(addr->un.sun_path), "%s", path);
154#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
155 // In case of abstract namespace, transfer the leading '@' into a null byte.
156 if (is_abstract) {
157 addr->un.sun_path[0] = '\0';
158 }
159#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
160 return Dart_Null();
161}
162
164 if (type == TYPE_ANY) {
165 return AF_UNSPEC;
166 }
167 if (type == TYPE_IPV4) {
168 return AF_INET;
169 }
170 if (type == TYPE_UNIX) {
171 return AF_UNIX;
172 }
173 ASSERT((type == TYPE_IPV6) && "Invalid type");
174 return AF_INET6;
175}
176
178 if (addr->ss.ss_family == AF_INET) {
179 addr->in.sin_port = htons(port);
180 } else if (addr->ss.ss_family == AF_INET6) {
181 addr->in6.sin6_port = htons(port);
182 } else {
183 UNREACHABLE();
184 }
185}
186
188 if (addr.ss.ss_family == AF_INET) {
189 return ntohs(addr.in.sin_port);
190 } else if (addr.ss.ss_family == AF_INET6) {
191 return ntohs(addr.in6.sin6_port);
192 } else if (addr.ss.ss_family == AF_UNIX) {
193 return 0;
194 } else {
195 UNREACHABLE();
196 return -1;
197 }
198}
199
201 int len = GetInAddrLength(addr);
203 if (Dart_IsError(result)) {
205 }
206 Dart_Handle err;
207 if (addr.addr.sa_family == AF_INET6) {
209 result, 0, reinterpret_cast<const uint8_t*>(&addr.in6.sin6_addr), len);
210 } else {
212 result, 0, reinterpret_cast<const uint8_t*>(&addr.in.sin_addr), len);
213 }
214 if (Dart_IsError(err)) {
216 }
217 return result;
218}
219
221 int in_addr_len = SocketAddress::GetInAddrLength(addr);
222 const void* in_addr;
223 if (addr.addr.sa_family == AF_INET6) {
224 in_addr = reinterpret_cast<const void*>(&addr.in6.sin6_addr);
225 } else {
226 in_addr = reinterpret_cast<const void*>(&addr.in.sin_addr);
227 }
229 new CObjectUint8Array(CObject::NewUint8Array(in_addr, in_addr_len));
230 return data;
231}
232void SocketAddress::SetAddrScope(RawAddr* addr, intptr_t scope_id) {
233 if (addr->addr.sa_family != AF_INET6) return;
234 addr->in6.sin6_scope_id = scope_id;
235}
236
238 if (addr.addr.sa_family == AF_INET6) {
239 return addr.in6.sin6_scope_id;
240 } else {
241 return 0;
242 }
243}
244
246 const char* address =
248 ASSERT(address != nullptr);
249 RawAddr raw;
250 memset(&raw, 0, sizeof(raw));
251 int type = strchr(address, ':') == nullptr ? SocketAddress::TYPE_IPV4
254 raw.addr.sa_family = AF_INET;
255 } else {
256 raw.addr.sa_family = AF_INET6;
257 }
258 bool ok = SocketBase::ParseAddress(type, address, &raw);
259 if (!ok) {
261 } else {
263 }
264}
265
268 const char* address =
270 // This must be an IPv6 address.
271 intptr_t type = 1;
272 ASSERT(address != nullptr);
273 OSError* os_error = nullptr;
274 AddressList<SocketAddress>* addresses =
275 SocketBase::LookupAddress(address, type, &os_error);
276 if (addresses != nullptr) {
277 SocketAddress* addr = addresses->GetAt(0);
280 delete addresses;
281 } else {
283 delete os_error;
284 }
285}
286
290 // INET6_ADDRSTRLEN is larger than INET_ADDRSTRLEN
291 char str[INET6_ADDRSTRLEN];
292 bool ok = SocketBase::RawAddrToString(&addr, str);
293 if (!ok) {
294 str[0] = '\0';
295 }
297}
298
300 intptr_t error_number =
302 bool is_bind_error = SocketBase::IsBindError(error_number);
303 Dart_SetBooleanReturnValue(args, is_bind_error ? true : false);
304}
305
306bool SocketBase::IsValidAddress(const char* address) {
307 ASSERT(address != nullptr);
308 RawAddr raw;
309 memset(&raw, 0, sizeof(raw));
310 int type = strchr(address, ':') == nullptr ? SocketAddress::TYPE_IPV4
313 raw.addr.sa_family = AF_INET;
314 } else {
315 raw.addr.sa_family = AF_INET6;
316 }
317 return SocketBase::ParseAddress(type, address, &raw);
318}
319
320#if !defined(DART_HOST_OS_WINDOWS)
321intptr_t SocketBase::Write(intptr_t fd,
322 const void* buffer,
323 intptr_t num_bytes,
324 SocketOpKind sync) {
325 // For non-blocking sockets we must write as many bytes as possible into
326 // the output to trigger EAGAIN otherwise we are not guaranteed to
327 // receive an event from epoll which we are using in edge-triggering
328 // (EPOLLET) mode. See man epoll for more information and guidelines.
329 ssize_t num_bytes_left = num_bytes;
330 while (num_bytes_left > 0) {
331 ssize_t written_bytes = WriteImpl(fd, buffer, num_bytes_left, sync);
332 static_assert(EAGAIN == EWOULDBLOCK);
333 if (written_bytes == -1) {
334 if ((sync == kAsync) && (errno == EWOULDBLOCK)) {
335 break;
336 }
337
338 return -1; // Error occurred.
339 }
340
341 num_bytes_left -= written_bytes;
342 buffer = static_cast<const char*>(buffer) + written_bytes;
343 }
344
345 return num_bytes - num_bytes_left;
346}
347#endif
348
349} // namespace bin
350} // namespace dart
static bool ok(int result)
#define UNREACHABLE()
Definition: assert.h:248
GLenum type
#define FUNCTION_NAME(name)
Definition: builtin.h:19
static int SNPrint(char *str, size_t size, const char *format,...) PRINTF_ATTRIBUTE(3
T * GetAt(intptr_t i) const
Definition: socket_base.h:141
static Dart_CObject * NewUint8Array(const void *data, intptr_t length)
Definition: dartutils.cc:945
static Dart_Handle NewDartOSError()
Definition: dartutils.cc:702
static const char * GetStringValue(Dart_Handle str_obj)
Definition: dartutils.cc:128
static Dart_Handle NewString(const char *str)
Definition: dartutils.h:214
static intptr_t GetIntptrValue(Dart_Handle value_obj)
Definition: dartutils.cc:100
const char * path() const
Definition: namespace.h:83
static void SetAddrScope(RawAddr *addr, intptr_t scope_id)
Definition: socket_base.cc:232
static void GetSockAddr(Dart_Handle obj, RawAddr *addr)
Definition: socket_base.cc:105
static int16_t FromType(int type)
Definition: socket_base.cc:163
static intptr_t GetAddrScope(const RawAddr &addr)
Definition: socket_base.cc:237
static void SetAddrPort(RawAddr *addr, intptr_t port)
Definition: socket_base.cc:177
static CObjectUint8Array * ToCObject(const RawAddr &addr)
Definition: socket_base.cc:220
static bool AreAddressesEqual(const RawAddr &a, const RawAddr &b)
Definition: socket_base.cc:80
static intptr_t GetAddrLength(const RawAddr &addr, bool unnamed_unix_socket=false)
Definition: socket_base.cc:39
static Dart_Handle GetUnixDomainSockAddr(const char *path, Namespace *namespc, RawAddr *addr)
Definition: socket_base.cc:130
static Dart_Handle ToTypedData(const RawAddr &addr)
Definition: socket_base.cc:200
static intptr_t GetAddrPort(const RawAddr &addr)
Definition: socket_base.cc:187
static intptr_t GetInAddrLength(const RawAddr &addr)
Definition: socket_base.cc:74
const RawAddr & addr() const
Definition: socket_base.h:68
static AddressList< SocketAddress > * LookupAddress(const char *host, int type, OSError **os_error)
static bool ParseAddress(int type, const char *address, RawAddr *addr)
static bool IsBindError(intptr_t error_number)
static bool IsValidAddress(const char *address)
Definition: socket_base.cc:306
static bool RawAddrToString(RawAddr *addr, char *str)
static intptr_t Write(intptr_t fd, const void *buffer, intptr_t num_bytes, SocketOpKind sync)
Definition: socket_base.cc:321
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
struct _Dart_NativeArguments * Dart_NativeArguments
Definition: dart_api.h:3019
Dart_TypedData_Type
Definition: dart_api.h:2612
@ Dart_TypedData_kUint8
Definition: dart_api.h:2615
#define ASSERT(E)
static bool b
struct MyStruct a[10]
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
GAsyncResult * result
static Dart_Handle ThrowIfError(Dart_Handle handle)
Definition: dartutils.h:31
void FUNCTION_NAME() InternetAddress_RawAddrToString(Dart_NativeArguments args)
Definition: socket_base.cc:287
void FUNCTION_NAME() SocketBase_IsBindError(Dart_NativeArguments args)
Definition: socket_base.cc:299
void FUNCTION_NAME() InternetAddress_ParseScopedLinkLocalAddress(Dart_NativeArguments args)
Definition: socket_base.cc:266
void FUNCTION_NAME() InternetAddress_Parse(Dart_NativeArguments args)
Definition: socket_base.cc:245
Definition: dart_vm.cc:33
DART_EXPORT void Dart_SetBooleanReturnValue(Dart_NativeArguments args, bool retval)
DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value)
DART_EXPORT void Dart_PropagateError(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type, intptr_t length)
DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args, Dart_Handle retval)
DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object, Dart_TypedData_Type *type, void **data, intptr_t *len)
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_ListSetAsBytes(Dart_Handle list, intptr_t offset, const uint8_t *native_array, intptr_t length)
DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args, int index)
DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_NewApiError(const char *error)
DART_EXPORT Dart_Handle Dart_Null()
static int8_t data[kExtLength]
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service port
Definition: switches.h:87
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
struct sockaddr_storage ss
Definition: socket_base.h:37
struct sockaddr addr
Definition: socket_base.h:38
struct sockaddr_un un
Definition: socket_base.h:36
struct sockaddr_in in
Definition: socket_base.h:34
struct sockaddr_in6 in6
Definition: socket_base.h:35