Flutter Engine
The Flutter Engine
socket_base_fuchsia.cc
Go to the documentation of this file.
1// Copyright (c) 2016, 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 "platform/globals.h"
6#if defined(DART_HOST_OS_FUCHSIA)
7
8#include "bin/socket_base.h"
9
10#include <errno.h>
11#include <ifaddrs.h>
12#include <net/if.h>
13#include <netinet/tcp.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17#include <sys/stat.h>
18#include <unistd.h>
19#include <vector>
20
21#include "bin/eventhandler.h"
22#include "bin/fdutils.h"
23#include "bin/file.h"
26
27// #define SOCKET_LOG_INFO 1
28// #define SOCKET_LOG_ERROR 1
29
30// define SOCKET_LOG_ERROR to get log messages only for errors.
31// define SOCKET_LOG_INFO to get log messages for both information and errors.
32#if defined(SOCKET_LOG_INFO) || defined(SOCKET_LOG_ERROR)
33#define LOG_ERR(msg, ...) \
34 { \
35 int err = errno; \
36 Syslog::PrintErr("Dart Socket ERROR: %s:%d: " msg, __FILE__, __LINE__, \
37 ##__VA_ARGS__); \
38 errno = err; \
39 }
40#if defined(SOCKET_LOG_INFO)
41#define LOG_INFO(msg, ...) \
42 Syslog::Print("Dart Socket INFO: %s:%d: " msg, __FILE__, __LINE__, \
43 ##__VA_ARGS__)
44#else
45#define LOG_INFO(msg, ...)
46#endif // defined(SOCKET_LOG_INFO)
47#else
48#define LOG_ERR(msg, ...)
49#define LOG_INFO(msg, ...)
50#endif // defined(SOCKET_LOG_INFO) || defined(SOCKET_LOG_ERROR)
51
52namespace dart {
53namespace bin {
54
55SocketAddress::SocketAddress(struct sockaddr* sa, bool unnamed_unix_socket) {
56 // Fuchsia does not support unix domain sockets.
57 if (unnamed_unix_socket) {
58 FATAL("Fuchsia does not support unix domain sockets.");
59 }
60 ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
61 if (!SocketBase::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa),
62 as_string_, INET6_ADDRSTRLEN)) {
63 as_string_[0] = 0;
64 }
65 socklen_t salen = GetAddrLength(*reinterpret_cast<RawAddr*>(sa));
66 memmove(reinterpret_cast<void*>(&addr_), sa, salen);
67}
68
70 // Nothing to do on Fuchsia.
71 return true;
72}
73
74bool SocketBase::FormatNumericAddress(const RawAddr& addr,
75 char* address,
76 int len) {
77 socklen_t salen = SocketAddress::GetAddrLength(addr);
78 LOG_INFO("SocketBase::FormatNumericAddress: calling getnameinfo\n");
79 return (NO_RETRY_EXPECTED(getnameinfo(&addr.addr, salen, address, len,
80 nullptr, 0, NI_NUMERICHOST) == 0));
81}
82
83bool SocketBase::IsBindError(intptr_t error_number) {
84 return error_number == EADDRINUSE || error_number == EADDRNOTAVAIL ||
85 error_number == EINVAL;
86}
87
88intptr_t SocketBase::Available(intptr_t fd) {
89 IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
90 return handle->AvailableBytes();
91}
92
93intptr_t SocketBase::Read(intptr_t fd,
94 void* buffer,
95 intptr_t num_bytes,
96 SocketOpKind sync) {
97 IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
98 ASSERT(handle->fd() >= 0);
99 LOG_INFO("SocketBase::Read: calling read(%ld, %p, %ld)\n", handle->fd(),
100 buffer, num_bytes);
101 intptr_t read_bytes = handle->Read(buffer, num_bytes);
102 ASSERT(EAGAIN == EWOULDBLOCK);
103 if ((sync == kAsync) && (read_bytes == -1) && (errno == EWOULDBLOCK)) {
104 // If the read would block we need to retry and therefore return 0
105 // as the number of bytes written.
106 read_bytes = 0;
107 } else if (read_bytes == -1) {
108 LOG_ERR("SocketBase::Read: read(%ld, %p, %ld) failed\n", handle->fd(),
109 buffer, num_bytes);
110 } else {
111 LOG_INFO("SocketBase::Read: read(%ld, %p, %ld) succeeded\n", handle->fd(),
112 buffer, num_bytes);
113 }
114 return read_bytes;
115}
116
117intptr_t SocketBase::RecvFrom(intptr_t fd,
118 void* buffer,
119 intptr_t num_bytes,
120 RawAddr* addr,
121 SocketOpKind sync) {
122 errno = ENOSYS;
123 return -1;
124}
125
127 return false;
128}
129
130intptr_t SocketBase::ReceiveMessage(intptr_t fd,
131 void* buffer,
132 int64_t* p_buffer_num_bytes,
133 SocketControlMessage** p_messages,
134 SocketOpKind sync,
135 OSError* p_oserror) {
136 errno = ENOSYS;
137 return -1;
138}
139
140bool SocketBase::AvailableDatagram(intptr_t fd,
141 void* buffer,
142 intptr_t num_bytes) {
143 return false;
144}
145
146intptr_t SocketBase::WriteImpl(intptr_t fd,
147 const void* buffer,
148 intptr_t num_bytes,
149 SocketOpKind sync) {
150 IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
151 ASSERT(handle->fd() >= 0);
152 LOG_INFO("SocketBase::WriteImpl: calling write(%ld, %p, %ld)\n", handle->fd(),
153 buffer, num_bytes);
154 intptr_t written_bytes = handle->Write(buffer, num_bytes);
155 if (written_bytes == -1 && !(sync == kAsync && errno == EWOULDBLOCK)) {
156 LOG_ERR("SocketBase::WriteImpl: write(%ld, %p, %ld) failed\n", handle->fd(),
157 buffer, num_bytes);
158 } else {
159 LOG_INFO("SocketBase::WriteImpl: write(%ld, %p, %ld) succeeded\n",
160 handle->fd(), buffer, num_bytes);
161 }
162 return written_bytes;
163}
164
165intptr_t SocketBase::SendTo(intptr_t fd,
166 const void* buffer,
167 intptr_t num_bytes,
168 const RawAddr& addr,
169 SocketOpKind sync) {
170 errno = ENOSYS;
171 return -1;
172}
173
174intptr_t SocketBase::SendMessage(intptr_t fd,
175 void* buffer,
176 size_t num_bytes,
177 SocketControlMessage* messages,
178 intptr_t num_messages,
179 SocketOpKind sync,
180 OSError* p_oserror) {
181 errno = ENOSYS;
182 return -1;
183}
184
185bool SocketBase::GetSocketName(intptr_t fd, SocketAddress* p_sa) {
186 ASSERT(fd >= 0);
187 ASSERT(p_sa != nullptr);
188 RawAddr raw;
189 socklen_t size = sizeof(raw);
190 if (NO_RETRY_EXPECTED(getsockname(fd, &raw.addr, &size))) {
191 return false;
192 }
193
194 // sockaddr_un contains sa_family_t sun_family and char[] sun_path.
195 // If size is the size of sa_family_t, this is an unnamed socket and
196 // sun_path contains garbage.
197 new (p_sa) SocketAddress(&raw.addr,
198 /*unnamed_unix_socket=*/size == sizeof(sa_family_t));
199 return true;
200}
201
202intptr_t SocketBase::GetPort(intptr_t fd) {
203 IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
204 ASSERT(handle->fd() >= 0);
205 RawAddr raw;
206 socklen_t size = sizeof(raw);
207 LOG_INFO("SocketBase::GetPort: calling getsockname(%ld)\n", handle->fd());
208 if (NO_RETRY_EXPECTED(getsockname(handle->fd(), &raw.addr, &size))) {
209 return 0;
210 }
211 return SocketAddress::GetAddrPort(raw);
212}
213
214SocketAddress* SocketBase::GetRemotePeer(intptr_t fd, intptr_t* port) {
215 IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
216 ASSERT(handle->fd() >= 0);
217 RawAddr raw;
218 socklen_t size = sizeof(raw);
219 if (NO_RETRY_EXPECTED(getpeername(handle->fd(), &raw.addr, &size))) {
220 return nullptr;
221 }
223 return new SocketAddress(&raw.addr);
224}
225
226void SocketBase::GetError(intptr_t fd, OSError* os_error) {
227 IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
228 ASSERT(handle->fd() >= 0);
229 int len = sizeof(errno);
230 int err = 0;
231 VOID_NO_RETRY_EXPECTED(getsockopt(handle->fd(), SOL_SOCKET, SO_ERROR, &err,
232 reinterpret_cast<socklen_t*>(&len)));
233 errno = err;
234 os_error->SetCodeAndMessage(OSError::kSystem, errno);
235}
236
237int SocketBase::GetType(intptr_t fd) {
238 errno = ENOSYS;
239 return -1;
240}
241
242intptr_t SocketBase::GetStdioHandle(intptr_t num) {
243 return num;
244}
245
246AddressList<SocketAddress>* SocketBase::LookupAddress(const char* host,
247 int type,
248 OSError** os_error) {
249 // Perform a name lookup for a host name.
250 struct addrinfo hints;
251 memset(&hints, 0, sizeof(hints));
252 hints.ai_family = SocketAddress::FromType(type);
253 hints.ai_socktype = SOCK_STREAM;
254 hints.ai_flags = AI_ADDRCONFIG;
255 hints.ai_protocol = IPPROTO_TCP;
256 struct addrinfo* info = nullptr;
257 LOG_INFO("SocketBase::LookupAddress: calling getaddrinfo\n");
258 int status = NO_RETRY_EXPECTED(getaddrinfo(host, nullptr, &hints, &info));
259 if (status != 0) {
260 // We failed, try without AI_ADDRCONFIG. This can happen when looking up
261 // e.g. '::1', when there are no global IPv6 addresses.
262 hints.ai_flags = 0;
263 LOG_INFO("SocketBase::LookupAddress: calling getaddrinfo again\n");
264 status = NO_RETRY_EXPECTED(getaddrinfo(host, nullptr, &hints, &info));
265 if (status != 0) {
266 ASSERT(*os_error == nullptr);
267 *os_error =
268 new OSError(status, gai_strerror(status), OSError::kGetAddressInfo);
269 return nullptr;
270 }
271 }
272 intptr_t count = 0;
273 for (struct addrinfo* c = info; c != nullptr; c = c->ai_next) {
274 if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) {
275 count++;
276 }
277 }
278 intptr_t i = 0;
279 AddressList<SocketAddress>* addresses = new AddressList<SocketAddress>(count);
280 for (struct addrinfo* c = info; c != nullptr; c = c->ai_next) {
281 if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) {
282 addresses->SetAt(i, new SocketAddress(c->ai_addr));
283 i++;
284 }
285 }
286 freeaddrinfo(info);
287 return addresses;
288}
289
290bool SocketBase::ReverseLookup(const RawAddr& addr,
291 char* host,
292 intptr_t host_len,
293 OSError** os_error) {
294 errno = ENOSYS;
295 return false;
296}
297
298bool SocketBase::ParseAddress(int type, const char* address, RawAddr* addr) {
299 int result;
301 result = NO_RETRY_EXPECTED(inet_pton(AF_INET, address, &addr->in.sin_addr));
302 } else {
304 result =
305 NO_RETRY_EXPECTED(inet_pton(AF_INET6, address, &addr->in6.sin6_addr));
306 }
307 return (result == 1);
308}
309
310bool SocketBase::RawAddrToString(RawAddr* addr, char* str) {
311 if (addr->addr.sa_family == AF_INET) {
312 return inet_ntop(AF_INET, &addr->in.sin_addr, str, INET_ADDRSTRLEN) !=
313 nullptr;
314 } else {
315 ASSERT(addr->addr.sa_family == AF_INET6);
316 return inet_ntop(AF_INET6, &addr->in6.sin6_addr, str, INET6_ADDRSTRLEN) !=
317 nullptr;
318 }
319}
320
321static bool ShouldIncludeIfaAddrs(struct ifaddrs* ifa, int lookup_family) {
322 if (ifa->ifa_addr == nullptr) {
323 // OpenVPN's virtual device tun0.
324 return false;
325 }
326 int family = ifa->ifa_addr->sa_family;
327 return ((lookup_family == family) ||
328 (((lookup_family == AF_UNSPEC) &&
329 ((family == AF_INET) || (family == AF_INET6)))));
330}
331
332AddressList<InterfaceSocketAddress>* SocketBase::ListInterfaces(
333 int type,
334 OSError** os_error) {
335 struct ifaddrs* ifaddr;
336
337 int status = NO_RETRY_EXPECTED(getifaddrs(&ifaddr));
338 if (status != 0) {
339 ASSERT(*os_error == nullptr);
340 *os_error =
341 new OSError(status, gai_strerror(status), OSError::kGetAddressInfo);
342 return nullptr;
343 }
344
345 int lookup_family = SocketAddress::FromType(type);
346
347 intptr_t count = 0;
348 for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
349 if (ShouldIncludeIfaAddrs(ifa, lookup_family)) {
350 count++;
351 }
352 }
353
354 AddressList<InterfaceSocketAddress>* addresses =
355 new AddressList<InterfaceSocketAddress>(count);
356 int i = 0;
357 for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
358 if (ShouldIncludeIfaAddrs(ifa, lookup_family)) {
359 char* ifa_name = DartUtils::ScopedCopyCString(ifa->ifa_name);
360 addresses->SetAt(
361 i, new InterfaceSocketAddress(ifa->ifa_addr, ifa_name,
362 if_nametoindex(ifa->ifa_name)));
363 i++;
364 }
365 }
366 freeifaddrs(ifaddr);
367 return addresses;
368}
369
370void SocketBase::Close(intptr_t fd) {
371 IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
372 ASSERT(handle->fd() >= 0);
373 NO_RETRY_EXPECTED(close(handle->fd()));
374}
375
376bool SocketBase::GetNoDelay(intptr_t fd, bool* enabled) {
377 errno = ENOSYS;
378 return false;
379}
380
381bool SocketBase::SetNoDelay(intptr_t fd, bool enabled) {
382 IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
383 int on = enabled ? 1 : 0;
384 return NO_RETRY_EXPECTED(setsockopt(handle->fd(), IPPROTO_TCP, TCP_NODELAY,
385 reinterpret_cast<char*>(&on),
386 sizeof(on))) == 0;
387}
388
389bool SocketBase::GetMulticastLoop(intptr_t fd,
390 intptr_t protocol,
391 bool* enabled) {
392 errno = ENOSYS;
393 return false;
394}
395
396bool SocketBase::SetMulticastLoop(intptr_t fd,
397 intptr_t protocol,
398 bool enabled) {
399 errno = ENOSYS;
400 return false;
401}
402
403bool SocketBase::GetMulticastHops(intptr_t fd, intptr_t protocol, int* value) {
404 errno = ENOSYS;
405 return false;
406}
407
408bool SocketBase::SetMulticastHops(intptr_t fd, intptr_t protocol, int value) {
409 errno = ENOSYS;
410 return false;
411}
412
413bool SocketBase::GetBroadcast(intptr_t fd, bool* enabled) {
414 errno = ENOSYS;
415 return false;
416}
417
418bool SocketBase::SetBroadcast(intptr_t fd, bool enabled) {
419 errno = ENOSYS;
420 return false;
421}
422
423bool SocketBase::SetOption(intptr_t fd,
424 int level,
425 int option,
426 const char* data,
427 int length) {
428 IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
429 return NO_RETRY_EXPECTED(
430 setsockopt(handle->fd(), level, option, data, length)) == 0;
431}
432
433bool SocketBase::GetOption(intptr_t fd,
434 int level,
435 int option,
436 char* data,
437 unsigned int* length) {
438 IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
439 socklen_t optlen = static_cast<socklen_t>(*length);
440 auto result =
441 NO_RETRY_EXPECTED(getsockopt(handle->fd(), level, option, data, &optlen));
442 *length = static_cast<unsigned int>(optlen);
443 return result == 0;
444}
445
446bool SocketBase::JoinMulticast(intptr_t fd,
447 const RawAddr& addr,
448 const RawAddr&,
449 int interfaceIndex) {
450 errno = ENOSYS;
451 return false;
452}
453
454bool SocketBase::LeaveMulticast(intptr_t fd,
455 const RawAddr& addr,
456 const RawAddr&,
457 int interfaceIndex) {
458 errno = ENOSYS;
459 return false;
460}
461
462} // namespace bin
463} // namespace dart
464
465#endif // defined(DART_HOST_OS_FUCHSIA)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
int count
Definition: FontMgrTest.cpp:50
#define LOG_INFO(...)
GLenum type
static char * ScopedCopyCString(const char *str)
Definition: dartutils.h:232
static int16_t FromType(int type)
Definition: socket_base.cc:163
static intptr_t GetAddrLength(const RawAddr &addr, bool unnamed_unix_socket=false)
Definition: socket_base.cc:39
SocketAddress(struct sockaddr *sa, bool unnamed_unix_socket=false)
static intptr_t GetAddrPort(const RawAddr &addr)
Definition: socket_base.cc:187
static bool LeaveMulticast(intptr_t fd, const RawAddr &addr, const RawAddr &interface, int interfaceIndex)
static bool AvailableDatagram(intptr_t fd, void *buffer, intptr_t num_bytes)
static int GetType(intptr_t fd)
static AddressList< SocketAddress > * LookupAddress(const char *host, int type, OSError **os_error)
static bool SetMulticastHops(intptr_t fd, intptr_t protocol, int value)
static intptr_t GetStdioHandle(intptr_t num)
static intptr_t ReceiveMessage(intptr_t fd, void *buffer, int64_t *p_buffer_num_bytes, SocketControlMessage **p_messages, SocketOpKind sync, OSError *p_oserror)
static bool SetOption(intptr_t fd, int level, int option, const char *data, int length)
static SocketAddress * GetRemotePeer(intptr_t fd, intptr_t *port)
static bool FormatNumericAddress(const RawAddr &addr, char *address, int len)
static bool SetNoDelay(intptr_t fd, bool enabled)
static bool GetSocketName(intptr_t fd, SocketAddress *p_sa)
static bool ParseAddress(int type, const char *address, RawAddr *addr)
static intptr_t Available(intptr_t fd)
static void Close(intptr_t fd)
static void GetError(intptr_t fd, OSError *os_error)
static intptr_t RecvFrom(intptr_t fd, void *buffer, intptr_t num_bytes, RawAddr *addr, SocketOpKind sync)
static bool IsBindError(intptr_t error_number)
static intptr_t Read(intptr_t fd, void *buffer, intptr_t num_bytes, SocketOpKind sync)
static bool SetBroadcast(intptr_t fd, bool value)
static bool GetNoDelay(intptr_t fd, bool *enabled)
static bool SetMulticastLoop(intptr_t fd, intptr_t protocol, bool enabled)
static bool GetOption(intptr_t fd, int level, int option, char *data, unsigned int *length)
static bool ReverseLookup(const RawAddr &addr, char *host, intptr_t host_len, OSError **os_error)
static bool Initialize()
static bool RawAddrToString(RawAddr *addr, char *str)
static intptr_t SendTo(intptr_t fd, const void *buffer, intptr_t num_bytes, const RawAddr &addr, SocketOpKind sync)
static bool GetMulticastHops(intptr_t fd, intptr_t protocol, int *value)
static bool GetMulticastLoop(intptr_t fd, intptr_t protocol, bool *enabled)
static bool JoinMulticast(intptr_t fd, const RawAddr &addr, const RawAddr &interface, int interfaceIndex)
static intptr_t SendMessage(intptr_t fd, void *buffer, size_t buffer_num_bytes, SocketControlMessage *messages, intptr_t num_messages, SocketOpKind sync, OSError *p_oserror)
static AddressList< InterfaceSocketAddress > * ListInterfaces(int type, OSError **os_error)
static bool GetBroadcast(intptr_t fd, bool *value)
static intptr_t GetPort(intptr_t fd)
#define ASSERT(E)
#define FATAL(error)
uint8_t value
GAsyncResult * result
size_t length
Definition: dart_vm.cc:33
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 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 host
Definition: switches.h:74
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
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
#define NO_RETRY_EXPECTED(expression)
#define VOID_NO_RETRY_EXPECTED(expression)