1// Copyright (c) 2013, 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.h"
6
7#include "bin/dartutils.h"
8#include "bin/eventhandler.h"
9#include "bin/file.h"
10#include "bin/io_buffer.h"
11#include "bin/isolate_data.h"
12#include "bin/lockers.h"
13#include "bin/process.h"
14#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
25static const int kSocketIdNativeField = 0;
26
27ListeningSocketRegistry* globalTcpListeningSocketRegistry = nullptr;
28
29bool Socket::short_socket_read_ = false;
30bool Socket::short_socket_write_ = false;
31
32void ListeningSocketRegistry::Initialize() {
33 ASSERT(globalTcpListeningSocketRegistry == nullptr);
34 globalTcpListeningSocketRegistry = new ListeningSocketRegistry();
35}
36
37ListeningSocketRegistry* ListeningSocketRegistry::Instance() {
38 return globalTcpListeningSocketRegistry;
39}
40
41void ListeningSocketRegistry::Cleanup() {
42 delete globalTcpListeningSocketRegistry;
43 globalTcpListeningSocketRegistry = nullptr;
44}
45
46ListeningSocketRegistry::OSSocket* ListeningSocketRegistry::LookupByPort(
47 intptr_t port) {
48 SimpleHashMap::Entry* entry = sockets_by_port_.Lookup(
49 GetHashmapKeyFromIntptr(port), GetHashmapHashFromIntptr(port), false);
50 if (entry == nullptr) {
51 return nullptr;
52 }
53 return reinterpret_cast<OSSocket*>(entry->value);
54}
55
56void ListeningSocketRegistry::InsertByPort(intptr_t port, OSSocket* socket) {
57 SimpleHashMap::Entry* entry = sockets_by_port_.Lookup(
58 GetHashmapKeyFromIntptr(port), GetHashmapHashFromIntptr(port), true);
59 ASSERT(entry != nullptr);
60 entry->value = reinterpret_cast<void*>(socket);
61}
62
63void ListeningSocketRegistry::RemoveByPort(intptr_t port) {
64 sockets_by_port_.Remove(GetHashmapKeyFromIntptr(port),
65 GetHashmapHashFromIntptr(port));
66}
67
68ListeningSocketRegistry::OSSocket* ListeningSocketRegistry::LookupByFd(
69 Socket* fd) {
70 SimpleHashMap::Entry* entry = sockets_by_fd_.Lookup(
71 GetHashmapKeyFromIntptr(reinterpret_cast<intptr_t>(fd)),
72 GetHashmapHashFromIntptr(reinterpret_cast<intptr_t>(fd)), false);
73 if (entry == nullptr) {
74 return nullptr;
75 }
76 return reinterpret_cast<OSSocket*>(entry->value);
77}
78
79void ListeningSocketRegistry::InsertByFd(Socket* fd, OSSocket* socket) {
80 SimpleHashMap::Entry* entry = sockets_by_fd_.Lookup(
81 GetHashmapKeyFromIntptr(reinterpret_cast<intptr_t>(fd)),
82 GetHashmapHashFromIntptr(reinterpret_cast<intptr_t>(fd)), true);
83 ASSERT(entry != nullptr);
84 entry->value = reinterpret_cast<void*>(socket);
85}
86
87void ListeningSocketRegistry::RemoveByFd(Socket* fd) {
88 sockets_by_fd_.Remove(
89 GetHashmapKeyFromIntptr(reinterpret_cast<intptr_t>(fd)),
90 GetHashmapHashFromIntptr(reinterpret_cast<intptr_t>(fd)));
91}
92
93Dart_Handle ListeningSocketRegistry::CreateBindListen(Dart_Handle socket_object,
94 RawAddr addr,
95 intptr_t backlog,
96 bool v6_only,
97 bool shared) {
98 MutexLocker ml(&mutex_);
99
100 OSSocket* first_os_socket = nullptr;
101 intptr_t port = SocketAddress::GetAddrPort(addr);
102 if (port > 0) {
103 first_os_socket = LookupByPort(port);
104 if (first_os_socket != nullptr) {
105 // There is already a socket listening on this port. We need to ensure
106 // that if there is one also listening on the same address, it was created
107 // with `shared = true`, ...
108 OSSocket* os_socket = first_os_socket;
109 OSSocket* os_socket_same_addr = FindOSSocketWithAddress(os_socket, addr);
110
111 if (os_socket_same_addr != nullptr) {
112 if (!os_socket_same_addr->shared || !shared) {
113 OSError os_error(-1,
114 "The shared flag to bind() needs to be `true` if "
115 "binding multiple times on the same (address, port) "
116 "combination.",
117 OSError::kUnknown);
118 return DartUtils::NewDartOSError(&os_error);
119 }
120 if (os_socket_same_addr->v6_only != v6_only) {
121 OSError os_error(-1,
122 "The v6Only flag to bind() needs to be the same if "
123 "binding multiple times on the same (address, port) "
124 "combination.",
125 OSError::kUnknown);
126 return DartUtils::NewDartOSError(&os_error);
127 }
128
129 // This socket creation is the exact same as the one which originally
130 // created the socket. Feed same fd and store it into native field
131 // of dart socket_object. Sockets here will share same fd but contain a
132 // different port() through EventHandler_SendData.
133 Socket* socketfd = new Socket(os_socket->fd);
134 os_socket->ref_count++;
135 // We set as a side-effect the file descriptor on the dart
136 // socket_object.
137 Socket::ReuseSocketIdNativeField(socket_object, socketfd,
138 Socket::kFinalizerListening);
139 InsertByFd(socketfd, os_socket);
140 return Dart_True();
141 }
142 }
143 }
144
145 // There is no socket listening on that (address, port), so we create new one.
146 intptr_t fd = ServerSocket::CreateBindListen(addr, backlog, v6_only);
147 if (fd == -5) {
148 OSError os_error(-1, "Invalid host", OSError::kUnknown);
149 return DartUtils::NewDartOSError(&os_error);
150 }
151 if (fd < 0) {
152 OSError error;
153 return DartUtils::NewDartOSError(&error);
154 }
155 if (!ServerSocket::StartAccept(fd)) {
156 OSError os_error(-1, "Failed to start accept", OSError::kUnknown);
157 return DartUtils::NewDartOSError(&os_error);
158 }
159 intptr_t allocated_port = SocketBase::GetPort(fd);
160 ASSERT(allocated_port > 0);
161
162 if (allocated_port != port) {
163 // There are two cases to consider:
164 //
165 // a) The user requested (address, port) where port != 0 which means
166 // we re-use an existing socket if available (and it is shared) or we
167 // create a new one. The new socket is guaranteed to have that
168 // selected port.
169 //
170 // b) The user requested (address, 0). This will make us *always* create a
171 // new socket. The OS will assign it a new `allocated_port` and we will
172 // insert into our data structures. *BUT* There might already be an
173 // existing (address2, `allocated_port`) where address != address2. So
174 // we need to do another `LookupByPort(allocated_port)` and link them
175 // via `OSSocket->next`.
176 ASSERT(port == 0);
177 first_os_socket = LookupByPort(allocated_port);
178 }
179
180 Socket* socketfd = new Socket(fd);
181 OSSocket* os_socket =
182 new OSSocket(addr, allocated_port, v6_only, shared, socketfd, nullptr);
183 os_socket->ref_count = 1;
184 os_socket->next = first_os_socket;
185
186 InsertByPort(allocated_port, os_socket);
187 InsertByFd(socketfd, os_socket);
188
189 // We set as a side-effect the port on the dart socket_object.
190 Socket::ReuseSocketIdNativeField(socket_object, socketfd,
191 Socket::kFinalizerListening);
192
193 return Dart_True();
194}
195
196Dart_Handle ListeningSocketRegistry::CreateUnixDomainBindListen(
197 Dart_Handle socket_object,
198 Namespace* namespc,
199 const char* path,
200 intptr_t backlog,
201 bool shared) {
202 MutexLocker ml(&mutex_);
203
204 RawAddr addr;
205 Dart_Handle result =
206 SocketAddress::GetUnixDomainSockAddr(path, namespc, &addr);
207 if (!Dart_IsNull(result)) {
208 return result;
209 }
210
211#if defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)
212 // Abstract unix domain socket doesn't exist in file system.
213 if (File::Exists(namespc, addr.un.sun_path) && path[0] != '@') {
214#else
215 if (File::Exists(namespc, addr.un.sun_path)) {
216#endif // defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)
217 if (unix_domain_sockets_ != nullptr) {
218 // If there is a socket listening on this file. Ensure
219 // that it was created with `shared` mode and current `shared`
220 // is also true.
221 OSSocket* os_socket = unix_domain_sockets_;
222 OSSocket* os_socket_same_addr =
223 FindOSSocketWithPath(os_socket, namespc, addr.un.sun_path);
224 if (os_socket_same_addr != nullptr) {
225 if (!os_socket_same_addr->shared || !shared) {
226 OSError os_error(-1,
227 "The shared flag to bind() needs to be `true` if "
228 "binding multiple times on the same path.",
229 OSError::kUnknown);
230 return DartUtils::NewDartOSError(&os_error);
231 }
232
233 // This socket creation is the exact same as the one which originally
234 // created the socket. Feed the same fd and store it into the native
235 // field of dart socket_object. Sockets here will share same fd but
236 // contain a different port() through EventHandler_SendData.
237 Socket* socketfd = new Socket(os_socket->fd);
238 os_socket->ref_count++;
239 // We set as a side-effect the file descriptor on the dart
240 // socket_object.
241 Socket::ReuseSocketIdNativeField(socket_object, socketfd,
242 Socket::kFinalizerListening);
243 InsertByFd(socketfd, os_socket);
244 return Dart_True();
245 }
246 }
247 // Unix domain socket by default doesn't allow binding to an existing file.
248 // An error (EADDRINUSE) will be returned back. However, hanging is noticed
249 // on Android so we throw an exception for all platforms.
250 OSError os_error(-1, "File exists with given unix domain address",
251 OSError::kUnknown);
252 return DartUtils::NewDartOSError(&os_error);
253 }
254
255 // There is no socket listening on that path, so we create new one.
256 intptr_t fd = ServerSocket::CreateUnixDomainBindListen(addr, backlog);
257
258 if (fd < 0) {
259 return DartUtils::NewDartOSError();
260 }
261
262 Socket* socketfd = new Socket(fd);
263 OSSocket* os_socket =
264 new OSSocket(addr, -1, false, shared, socketfd, namespc);
265 os_socket->ref_count = 1;
266 os_socket->next = unix_domain_sockets_;
267 unix_domain_sockets_ = os_socket;
268 InsertByFd(socketfd, os_socket);
269
270 Socket::ReuseSocketIdNativeField(socket_object, socketfd,
271 Socket::kFinalizerListening);
272
273 return Dart_True();
274}
275
276bool ListeningSocketRegistry::CloseOneSafe(OSSocket* os_socket,
277 Socket* socket) {
278 ASSERT(!mutex_.TryLock());
279 ASSERT(os_socket != nullptr);
280 ASSERT(os_socket->ref_count > 0);
281 os_socket->ref_count--;
282 RemoveByFd(socket);
283 if (os_socket->ref_count > 0) {
284 return false;
285 }
286 // Unlink the socket file, if os_socket contains unix domain sockets.
287 if (os_socket->address.addr.sa_family == AF_UNIX) {
288#if defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)
289 // If the socket is abstract, which has a path starting with a null byte,
290 // unlink() is not necessary because the file doesn't exist.
291 if (os_socket->address.un.sun_path[0] != '\0') {
292 Utils::Unlink(os_socket->address.un.sun_path);
293 }
294#else
295 Utils::Unlink(os_socket->address.un.sun_path);
296#endif // defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)
297 // Remove os_socket from unix_domain_sockets_ list.
298 OSSocket* prev = nullptr;
299 OSSocket* current = unix_domain_sockets_;
300 while (current != nullptr) {
301 if (current == os_socket) {
302 if (prev == nullptr) {
303 unix_domain_sockets_ = unix_domain_sockets_->next;
304 } else {
305 prev->next = current->next;
306 }
307 break;
308 }
309 prev = current;
310 current = current->next;
311 }
312 delete os_socket;
313 return true;
314 }
315 OSSocket* prev = nullptr;
316 OSSocket* current = LookupByPort(os_socket->port);
317 while (current != os_socket) {
318 ASSERT(current != nullptr);
319 prev = current;
320 current = current->next;
321 }
322
323 if ((prev == nullptr) && (current->next == nullptr)) {
324 // Remove last element from the list.
325 RemoveByPort(os_socket->port);
326 } else if (prev == nullptr) {
327 // Remove first element of the list.
328 InsertByPort(os_socket->port, current->next);
329 } else {
330 // Remove element from the list which is not the first one.
331 prev->next = os_socket->next;
332 }
333
334 ASSERT(os_socket->ref_count == 0);
335 delete os_socket;
336 return true;
337}
338
339void ListeningSocketRegistry::CloseAllSafe() {
340 MutexLocker ml(&mutex_);
341 for (SimpleHashMap::Entry* cursor = sockets_by_fd_.Start(); cursor != nullptr;
342 cursor = sockets_by_fd_.Next(cursor)) {
343 OSSocket* os_socket = reinterpret_cast<OSSocket*>(cursor->value);
344 ASSERT(os_socket != nullptr);
345 delete os_socket;
346 }
347}
348
349bool ListeningSocketRegistry::CloseSafe(Socket* socketfd) {
350 ASSERT(!mutex_.TryLock());
351 OSSocket* os_socket = LookupByFd(socketfd);
352 if (os_socket != nullptr) {
353 return CloseOneSafe(os_socket, socketfd);
354 } else {
355 // A finalizer may direct the event handler to close a listening socket
356 // that it has never seen before. In this case, we return true to direct
357 // the eventhandler to clean up the socket.
358 return true;
359 }
360}
361
362void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) {
363 RawAddr addr;
364 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
365 Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
366 int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
367 SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port));
368 if (addr.addr.sa_family == AF_INET6) {
369 Dart_Handle scope_id_arg = Dart_GetNativeArgument(args, 3);
370 int64_t scope_id =
371 DartUtils::GetInt64ValueCheckRange(scope_id_arg, 0, 65535);
372 SocketAddress::SetAddrScope(&addr, scope_id);
373 }
374 intptr_t socket = Socket::CreateConnect(addr);
375 OSError error;
376 if (socket >= 0) {
377 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
378 Socket::kFinalizerNormal);
379 Dart_SetReturnValue(args, Dart_True());
380 } else {
381 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error));
382 }
383}
384
385void FUNCTION_NAME(Socket_CreateBindConnect)(Dart_NativeArguments args) {
386 RawAddr addr;
387 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
388 Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
389 int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
390 SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port));
391 RawAddr sourceAddr;
392 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 3), &sourceAddr);
393 if (addr.addr.sa_family == AF_INET6) {
394 Dart_Handle scope_id_arg = Dart_GetNativeArgument(args, 4);
395 int64_t scope_id =
396 DartUtils::GetInt64ValueCheckRange(scope_id_arg, 0, 65535);
397 SocketAddress::SetAddrScope(&addr, scope_id);
398 }
399 intptr_t socket = Socket::CreateBindConnect(addr, sourceAddr);
400 OSError error;
401 if (socket >= 0) {
402 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
403 Socket::kFinalizerNormal);
404 Dart_SetReturnValue(args, Dart_True());
405 } else {
406 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error));
407 }
408}
409
410void FUNCTION_NAME(Socket_CreateUnixDomainBindConnect)(
411 Dart_NativeArguments args) {
412#if defined(HOST_OS_WINDOWS) || defined(HOST_OS_FUCHSIA)
413 OSError os_error(
414 -1, "Unix domain sockets are not available on this operating system.",
415 OSError::kUnknown);
416 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
417#else
418 RawAddr addr;
419 Dart_Handle address = Dart_GetNativeArgument(args, 1);
420 if (Dart_IsNull(address)) {
421 Dart_SetReturnValue(args,
422 DartUtils::NewDartArgumentError("expect address to be of type String"));
423 }
424 Dart_Handle result = SocketAddress::GetUnixDomainSockAddr(
425 DartUtils::GetStringValue(address), Namespace::GetNamespace(args, 3),
426 &addr);
427 if (!Dart_IsNull(result)) {
428 return Dart_SetReturnValue(args, result);
429 }
430
431 RawAddr sourceAddr;
432 address = Dart_GetNativeArgument(args, 2);
433 if (Dart_IsNull(address)) {
434 Dart_SetReturnValue(args,
435 DartUtils::NewDartArgumentError("expect address to be of type String"));
436 }
437 result = SocketAddress::GetUnixDomainSockAddr(
438 DartUtils::GetStringValue(address), Namespace::GetNamespace(args, 3),
439 &sourceAddr);
440 if (!Dart_IsNull(result)) {
441 return Dart_SetReturnValue(args, result);
442 }
443
444 intptr_t socket = Socket::CreateUnixDomainBindConnect(addr, sourceAddr);
445 if (socket >= 0) {
446 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
447 Socket::kFinalizerNormal);
448 Dart_SetReturnValue(args, Dart_True());
449 } else {
450 Dart_SetReturnValue(args, DartUtils::NewDartOSError());
451 }
452#endif // defined(HOST_OS_WINDOWS) || defined(HOST_OS_FUCHSIA)
453}
454
455void FUNCTION_NAME(Socket_CreateUnixDomainConnect)(Dart_NativeArguments args) {
456#if defined(HOST_OS_WINDOWS) || defined(HOST_OS_FUCHSIA)
457 OSError os_error(
458 -1, "Unix domain sockets are not available on this operating system.",
459 OSError::kUnknown);
460 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
461#else
462 RawAddr addr;
463 Dart_Handle address = Dart_GetNativeArgument(args, 1);
464 if (Dart_IsNull(address)) {
465 Dart_SetReturnValue(args,
466 DartUtils::NewDartArgumentError("expect address to be of type String"));
467 }
468 Dart_Handle result = SocketAddress::GetUnixDomainSockAddr(
469 DartUtils::GetStringValue(address), Namespace::GetNamespace(args, 2),
470 &addr);
471 if (!Dart_IsNull(result)) {
472 return Dart_SetReturnValue(args, result);
473 }
474 intptr_t socket = Socket::CreateUnixDomainConnect(addr);
475 if (socket >= 0) {
476 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
477 Socket::kFinalizerNormal);
478 Dart_SetReturnValue(args, Dart_True());
479 } else {
480 Dart_SetReturnValue(args, DartUtils::NewDartOSError());
481 }
482#endif // defined(HOST_OS_WINDOWS) || defined(HOST_OS_FUCHSIA)
483}
484
485void FUNCTION_NAME(Socket_CreateBindDatagram)(Dart_NativeArguments args) {
486 RawAddr addr;
487 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
488 Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
489 int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
490 SocketAddress::SetAddrPort(&addr, port);
491 bool reuse_addr = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
492 bool reuse_port = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
493 int ttl = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 5));
494 intptr_t socket =
495 Socket::CreateBindDatagram(addr, reuse_addr, reuse_port, ttl);
496 if (socket >= 0) {
497 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
498 Socket::kFinalizerNormal);
499 Dart_SetReturnValue(args, Dart_True());
500 } else {
501 OSError error;
502 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error));
503 }
504}
505
506void FUNCTION_NAME(Socket_Available)(Dart_NativeArguments args) {
507 Socket* socket =
508 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
509 intptr_t available = SocketBase::Available(socket->fd());
510 if (available >= 0) {
511 Dart_SetIntegerReturnValue(args, available);
512 } else {
513 // Available failed. Mark socket as having data, to trigger a future read
514 // event where the actual error can be reported.
515 Dart_SetIntegerReturnValue(args, 1);
516 }
517}
518
519void FUNCTION_NAME(Socket_Read)(Dart_NativeArguments args) {
520 Socket* socket =
521 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
522 int64_t length = 0;
523 if (DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 1), &length) &&
524 (length >= 0)) {
525 if (Socket::short_socket_read()) {
526 length = (length + 1) / 2;
527 }
528 uint8_t* buffer = nullptr;
529 Dart_Handle result = IOBuffer::Allocate(length, &buffer);
530 if (Dart_IsNull(result)) {
531 Dart_ThrowException(DartUtils::NewDartOSError());
532 }
533 if (Dart_IsError(result)) {
534 Dart_PropagateError(result);
535 }
536 ASSERT(buffer != nullptr);
537 intptr_t bytes_read =
538 SocketBase::Read(socket->fd(), buffer, length, SocketBase::kAsync);
539 if (bytes_read == length) {
540 Dart_SetReturnValue(args, result);
541 } else if (bytes_read > 0) {
542 uint8_t* new_buffer = nullptr;
543 Dart_Handle new_result = IOBuffer::Allocate(bytes_read, &new_buffer);
544 if (Dart_IsNull(new_result)) {
545 Dart_ThrowException(DartUtils::NewDartOSError());
546 }
547 if (Dart_IsError(new_result)) {
548 Dart_PropagateError(new_result);
549 }
550 ASSERT(new_buffer != nullptr);
551 memmove(new_buffer, buffer, bytes_read);
552 Dart_SetReturnValue(args, new_result);
553 } else if (bytes_read == 0) {
554 // On MacOS when reading from a tty Ctrl-D will result in reading one
555 // less byte then reported as available.
556 Dart_SetReturnValue(args, Dart_Null());
557 } else {
558 ASSERT(bytes_read == -1);
559 Dart_ThrowException(DartUtils::NewDartOSError());
560 }
561 } else {
562 OSError os_error(-1, "Invalid argument", OSError::kUnknown);
563 Dart_ThrowException(DartUtils::NewDartOSError(&os_error));
564 }
565}
566
567void FUNCTION_NAME(Socket_RecvFrom)(Dart_NativeArguments args) {
568 // TODO(sgjesse): Use a MTU value here. Only the loopback adapter can
569 // handle 64k datagrams.
570 const int kReceiveBufferLen = 65536;
571 Socket* socket =
572 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
573
574 // Ensure that a receive buffer for the UDP socket exists.
575 ASSERT(socket != nullptr);
576 uint8_t* recv_buffer = socket->udp_receive_buffer();
577 if (recv_buffer == nullptr) {
578 recv_buffer = reinterpret_cast<uint8_t*>(malloc(kReceiveBufferLen));
579 socket->set_udp_receive_buffer(recv_buffer);
580 }
581
582 // Read data into the buffer.
583 RawAddr addr;
584 const intptr_t bytes_read = SocketBase::RecvFrom(
585 socket->fd(), recv_buffer, kReceiveBufferLen, &addr, SocketBase::kAsync);
586 if (bytes_read == 0) {
587 Dart_SetReturnValue(args, Dart_Null());
588 return;
589 }
590 if (bytes_read < 0) {
591 ASSERT(bytes_read == -1);
592 Dart_ThrowException(DartUtils::NewDartOSError());
593 }
594
595 // Datagram data read. Copy into buffer of the exact size,
596 ASSERT(bytes_read >= 0);
597 uint8_t* data_buffer = nullptr;
598 Dart_Handle data = IOBuffer::Allocate(bytes_read, &data_buffer);
599 if (Dart_IsNull(data)) {
600 Dart_ThrowException(DartUtils::NewDartOSError());
601 }
602 if (Dart_IsError(data)) {
603 Dart_PropagateError(data);
604 }
605 ASSERT(data_buffer != nullptr);
606 memmove(data_buffer, recv_buffer, bytes_read);
607
608 // Memory Sanitizer complains addr not being initialized, which is done
609 // through RecvFrom().
610 // Issue: https://github.com/google/sanitizers/issues/1201
611 MSAN_UNPOISON(&addr, sizeof(RawAddr));
612
613 // Get the port and clear it in the sockaddr structure.
614 int port = SocketAddress::GetAddrPort(addr);
615 // TODO(21403): Add checks for AF_UNIX, if unix domain sockets
616 // are used in SOCK_DGRAM.
617 enum internet_type { IPv4, IPv6 };
618 internet_type type;
619 if (addr.addr.sa_family == AF_INET) {
620 addr.in.sin_port = 0;
621 type = IPv4;
622 } else {
623 ASSERT(addr.addr.sa_family == AF_INET6);
624 addr.in6.sin6_port = 0;
625 type = IPv6;
626 }
627 // Format the address to a string using the numeric format.
628 char numeric_address[INET6_ADDRSTRLEN];
629 SocketBase::FormatNumericAddress(addr, numeric_address, INET6_ADDRSTRLEN);
630
631 // Create a Datagram object with the data and sender address and port.
632 const int kNumArgs = 5;
633 Dart_Handle dart_args[kNumArgs];
634 dart_args[0] = data;
635 dart_args[1] = Dart_NewStringFromCString(numeric_address);
636 if (Dart_IsError(dart_args[1])) {
637 Dart_PropagateError(dart_args[1]);
638 }
639 dart_args[2] = SocketAddress::ToTypedData(addr);
640 dart_args[3] = Dart_NewInteger(port);
641 dart_args[4] = Dart_NewInteger(type);
642 if (Dart_IsError(dart_args[3])) {
643 Dart_PropagateError(dart_args[3]);
644 }
645 // TODO(sgjesse): Cache the _makeDatagram function somewhere.
646 Dart_Handle io_lib = Dart_LookupLibrary(DartUtils::NewString("dart:io"));
647 if (Dart_IsError(io_lib)) {
648 Dart_PropagateError(io_lib);
649 }
650 Dart_Handle result = Dart_Invoke(
651 io_lib, DartUtils::NewString("_makeDatagram"), kNumArgs, dart_args);
652 Dart_SetReturnValue(args, result);
653}
654
655void FUNCTION_NAME(Socket_WriteList)(Dart_NativeArguments args) {
656 Socket* socket =
657 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
658 Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
659 ASSERT(Dart_IsList(buffer_obj));
660 intptr_t offset = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 2));
661 intptr_t length = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 3));
662 bool short_write = false;
663 if (Socket::short_socket_write()) {
664 if (length > 1) {
665 short_write = true;
666 }
667 length = (length + 1) / 2;
668 }
669 Dart_TypedData_Type type;
670 uint8_t* buffer = nullptr;
671 intptr_t len;
672 Dart_Handle result = Dart_TypedDataAcquireData(
673 buffer_obj, &type, reinterpret_cast<void**>(&buffer), &len);
674 if (Dart_IsError(result)) {
675 Dart_PropagateError(result);
676 }
677 ASSERT((offset + length) <= len);
678 buffer += offset;
679 intptr_t bytes_written =
680 SocketBase::Write(socket->fd(), buffer, length, SocketBase::kAsync);
681 if (bytes_written >= 0) {
682 Dart_TypedDataReleaseData(buffer_obj);
683 if (short_write) {
684 // If the write was forced 'short', indicate by returning the negative
685 // number of bytes. A forced short write may not trigger a write event.
686 Dart_SetIntegerReturnValue(args, -bytes_written);
687 } else {
688 Dart_SetIntegerReturnValue(args, bytes_written);
689 }
690 } else {
691 // Extract OSError before we release data, as it may override the error.
692 Dart_Handle error;
693 {
694 OSError os_error;
695 Dart_TypedDataReleaseData(buffer_obj);
696 error = DartUtils::NewDartOSError(&os_error);
697 }
698 Dart_ThrowException(error);
699 }
700}
701
702void FUNCTION_NAME(Socket_SendTo)(Dart_NativeArguments args) {
703 Socket* socket =
704 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
705 Dart_Handle buffer_obj = Dart_GetNativeArgument(args, 1);
706 intptr_t offset = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 2));
707 intptr_t length = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 3));
708 Dart_Handle address_obj = Dart_GetNativeArgument(args, 4);
709 ASSERT(Dart_IsList(address_obj));
710 RawAddr addr;
711 SocketAddress::GetSockAddr(address_obj, &addr);
712 int64_t port = DartUtils::GetInt64ValueCheckRange(
713 Dart_GetNativeArgument(args, 5), 0, 65535);
714 SocketAddress::SetAddrPort(&addr, port);
715 Dart_TypedData_Type type;
716 uint8_t* buffer = nullptr;
717 intptr_t len;
718 Dart_Handle result = Dart_TypedDataAcquireData(
719 buffer_obj, &type, reinterpret_cast<void**>(&buffer), &len);
720 if (Dart_IsError(result)) {
721 Dart_PropagateError(result);
722 }
723 ASSERT((offset + length) <= len);
724 buffer += offset;
725 intptr_t bytes_written = SocketBase::SendTo(socket->fd(), buffer, length,
726 addr, SocketBase::kAsync);
727 if (bytes_written >= 0) {
728 Dart_TypedDataReleaseData(buffer_obj);
729 Dart_SetIntegerReturnValue(args, bytes_written);
730 } else {
731 // Extract OSError before we release data, as it may override the error.
732 Dart_Handle error;
733 {
734 OSError os_error;
735 Dart_TypedDataReleaseData(buffer_obj);
736 error = DartUtils::NewDartOSError(&os_error);
737 }
738 Dart_ThrowException(error);
739 }
740}
741
742void FUNCTION_NAME(Socket_GetPort)(Dart_NativeArguments args) {
743 Socket* socket =
744 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
745 intptr_t port = SocketBase::GetPort(socket->fd());
746 if (port > 0) {
747 Dart_SetIntegerReturnValue(args, port);
748 } else {
749 Dart_SetReturnValue(args, DartUtils::NewDartOSError());
750 }
751}
752
753void FUNCTION_NAME(Socket_GetRemotePeer)(Dart_NativeArguments args) {
754 Socket* socket =
755 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
756 intptr_t port = 0;
757 SocketAddress* addr = SocketBase::GetRemotePeer(socket->fd(), &port);
758 if (addr != nullptr) {
759 Dart_Handle list = Dart_NewList(2);
760 int type = addr->GetType();
761 Dart_Handle entry;
762 if (type == SocketAddress::TYPE_UNIX) {
763 entry = Dart_NewList(2);
764 } else {
765 entry = Dart_NewList(3);
766 RawAddr raw = addr->addr();
767 Dart_ListSetAt(entry, 2, SocketAddress::ToTypedData(raw));
768 }
769 Dart_ListSetAt(entry, 0, Dart_NewInteger(type));
770 Dart_ListSetAt(entry, 1, Dart_NewStringFromCString(addr->as_string()));
771
772 Dart_ListSetAt(list, 0, entry);
773 Dart_ListSetAt(list, 1, Dart_NewInteger(port));
774 Dart_SetReturnValue(args, list);
775 delete addr;
776 } else {
777 Dart_ThrowException(DartUtils::NewDartOSError());
778 }
779}
780
781void FUNCTION_NAME(Socket_GetError)(Dart_NativeArguments args) {
782 Socket* socket =
783 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
784 OSError os_error;
785 SocketBase::GetError(socket->fd(), &os_error);
786 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
787}
788
789void FUNCTION_NAME(Socket_GetType)(Dart_NativeArguments args) {
790 Socket* socket =
791 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
792 OSError os_error;
793 intptr_t type = SocketBase::GetType(socket->fd());
794 if (type >= 0) {
795 Dart_SetIntegerReturnValue(args, type);
796 } else {
797 Dart_SetReturnValue(args, DartUtils::NewDartOSError());
798 }
799}
800
801void FUNCTION_NAME(Socket_GetStdioHandle)(Dart_NativeArguments args) {
802 int64_t num =
803 DartUtils::GetInt64ValueCheckRange(Dart_GetNativeArgument(args, 1), 0, 2);
804 intptr_t socket = SocketBase::GetStdioHandle(num);
805 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
806 Socket::kFinalizerStdio);
807 Dart_SetReturnValue(args, Dart_NewBoolean(socket >= 0));
808}
809
810void FUNCTION_NAME(Socket_GetSocketId)(Dart_NativeArguments args) {
811 Socket* socket =
812 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
813 intptr_t id = reinterpret_cast<intptr_t>(socket);
814 Dart_SetIntegerReturnValue(args, id);
815}
816
817void FUNCTION_NAME(Socket_SetSocketId)(Dart_NativeArguments args) {
818 intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
819 intptr_t type_flag =
820 DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 2));
821 Socket::SocketFinalizer finalizer;
822 if (Socket::IsSignalSocketFlag(type_flag)) {
823 finalizer = Socket::kFinalizerSignal;
824 } else {
825 finalizer = Socket::kFinalizerNormal;
826 }
827 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), id,
828 finalizer);
829}
830
831void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) {
832 RawAddr addr;
833 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
834 int64_t port = DartUtils::GetInt64ValueCheckRange(
835 Dart_GetNativeArgument(args, 2), 0, 65535);
836 SocketAddress::SetAddrPort(&addr, port);
837 int64_t backlog = DartUtils::GetInt64ValueCheckRange(
838 Dart_GetNativeArgument(args, 3), 0, 65535);
839 bool v6_only = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
840 bool shared = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
841 if (addr.addr.sa_family == AF_INET6) {
842 Dart_Handle scope_id_arg = Dart_GetNativeArgument(args, 6);
843 int64_t scope_id =
844 DartUtils::GetInt64ValueCheckRange(scope_id_arg, 0, 65535);
845 SocketAddress::SetAddrScope(&addr, scope_id);
846 }
847
848 Dart_Handle socket_object = Dart_GetNativeArgument(args, 0);
849 Dart_Handle result = ListeningSocketRegistry::Instance()->CreateBindListen(
850 socket_object, addr, backlog, v6_only, shared);
851 Dart_SetReturnValue(args, result);
852}
853
854void FUNCTION_NAME(ServerSocket_CreateUnixDomainBindListen)(
855 Dart_NativeArguments args) {
856#if defined(HOST_OS_WINDOWS)
857 OSError os_error(
858 -1, "Unix domain sockets are not available on this operating system.",
859 OSError::kUnknown);
860 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
861#else
862 Dart_Handle address = Dart_GetNativeArgument(args, 1);
863 if (Dart_IsNull(address)) {
864 Dart_SetReturnValue(args,
865 DartUtils::NewDartArgumentError("expect address to be of type String"));
866 }
867 const char* path = DartUtils::GetStringValue(address);
868 int64_t backlog = DartUtils::GetInt64ValueCheckRange(
869 Dart_GetNativeArgument(args, 2), 0, 65535);
870 bool shared = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
871 Namespace* namespc = Namespace::GetNamespace(args, 4);
872 Dart_Handle socket_object = Dart_GetNativeArgument(args, 0);
873 Dart_Handle result =
874 ListeningSocketRegistry::Instance()->CreateUnixDomainBindListen(
875 socket_object, namespc, path, backlog, shared);
876 Dart_SetReturnValue(args, result);
877#endif // defined(HOST_OS_WINDOWS)
878}
879
880void FUNCTION_NAME(ServerSocket_Accept)(Dart_NativeArguments args) {
881 Socket* socket =
882 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
883 intptr_t new_socket = ServerSocket::Accept(socket->fd());
884 if (new_socket >= 0) {
885 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 1), new_socket,
886 Socket::kFinalizerNormal);
887 Dart_SetReturnValue(args, Dart_True());
888 } else {
889 Dart_SetReturnValue(args, Dart_False());
890 }
891}
892
893CObject* Socket::LookupRequest(const CObjectArray& request) {
894 if ((request.Length() == 2) && request[0]->IsString() &&
895 request[1]->IsInt32()) {
896 CObjectString host(request[0]);
897 CObjectInt32 type(request[1]);
898 CObject* result = nullptr;
899 OSError* os_error = nullptr;
900 AddressList<SocketAddress>* addresses =
901 SocketBase::LookupAddress(host.CString(), type.Value(), &os_error);
902 if (addresses != nullptr) {
903 CObjectArray* array =
904 new CObjectArray(CObject::NewArray(addresses->count() + 1));
905 array->SetAt(0, new CObjectInt32(CObject::NewInt32(0)));
906 for (intptr_t i = 0; i < addresses->count(); i++) {
907 SocketAddress* addr = addresses->GetAt(i);
908 CObjectArray* entry = new CObjectArray(CObject::NewArray(4));
909
910 CObjectInt32* type =
911 new CObjectInt32(CObject::NewInt32(addr->GetType()));
912 entry->SetAt(0, type);
913
914 CObjectString* as_string =
915 new CObjectString(CObject::NewString(addr->as_string()));
916 entry->SetAt(1, as_string);
917
918 RawAddr raw = addr->addr();
919 CObjectUint8Array* data = SocketAddress::ToCObject(raw);
920 entry->SetAt(2, data);
921
922 CObjectInt64* scope_id = new CObjectInt64(
923 CObject::NewInt64(SocketAddress::GetAddrScope(raw)));
924 entry->SetAt(3, scope_id);
925
926 array->SetAt(i + 1, entry);
927 }
928 result = array;
929 delete addresses;
930 } else {
931 result = CObject::NewOSError(os_error);
932 delete os_error;
933 }
934 return result;
935 }
936 return CObject::IllegalArgumentError();
937}
938
939CObject* Socket::ReverseLookupRequest(const CObjectArray& request) {
940 if ((request.Length() == 1) && request[0]->IsTypedData()) {
941 CObjectUint8Array addr_object(request[0]);
942 RawAddr addr;
943 int len = addr_object.Length();
944 memset(reinterpret_cast<void*>(&addr), 0, sizeof(RawAddr));
945 if (len == sizeof(in_addr)) {
946 addr.in.sin_family = AF_INET;
947 memmove(reinterpret_cast<void*>(&addr.in.sin_addr), addr_object.Buffer(),
948 len);
949 } else {
950 ASSERT(len == sizeof(in6_addr));
951 addr.in6.sin6_family = AF_INET6;
952 memmove(reinterpret_cast<void*>(&addr.in6.sin6_addr),
953 addr_object.Buffer(), len);
954 }
955
956 OSError* os_error = nullptr;
957 const intptr_t kMaxHostLength = 1025;
958 char host[kMaxHostLength];
959 if (SocketBase::ReverseLookup(addr, host, kMaxHostLength, &os_error)) {
960 return new CObjectString(CObject::NewString(host));
961 } else {
962 CObject* result = CObject::NewOSError(os_error);
963 delete os_error;
964 return result;
965 }
966 }
967 return CObject::IllegalArgumentError();
968}
969
970CObject* Socket::ListInterfacesRequest(const CObjectArray& request) {
971 if ((request.Length() == 1) && request[0]->IsInt32()) {
972 CObjectInt32 type(request[0]);
973 CObject* result = nullptr;
974 OSError* os_error = nullptr;
975 AddressList<InterfaceSocketAddress>* addresses =
976 SocketBase::ListInterfaces(type.Value(), &os_error);
977 if (addresses != nullptr) {
978 CObjectArray* array =
979 new CObjectArray(CObject::NewArray(addresses->count() + 1));
980 array->SetAt(0, new CObjectInt32(CObject::NewInt32(0)));
981 for (intptr_t i = 0; i < addresses->count(); i++) {
982 InterfaceSocketAddress* interface = addresses->GetAt(i);
983 SocketAddress* addr = interface->socket_address();
984 CObjectArray* entry = new CObjectArray(CObject::NewArray(5));
985
986 CObjectInt32* type =
987 new CObjectInt32(CObject::NewInt32(addr->GetType()));
988 entry->SetAt(0, type);
989
990 CObjectString* as_string =
991 new CObjectString(CObject::NewString(addr->as_string()));
992 entry->SetAt(1, as_string);
993
994 RawAddr raw = addr->addr();
995 CObjectUint8Array* data = SocketAddress::ToCObject(raw);
996 entry->SetAt(2, data);
997
998 CObjectString* interface_name =
999 new CObjectString(CObject::NewString(interface->interface_name()));
1000 entry->SetAt(3, interface_name);
1001
1002 CObjectInt64* interface_index =
1003 new CObjectInt64(CObject::NewInt64(interface->interface_index()));
1004 entry->SetAt(4, interface_index);
1005
1006 array->SetAt(i + 1, entry);
1007 }
1008 result = array;
1009 delete addresses;
1010 } else {
1011 result = CObject::NewOSError(os_error);
1012 delete os_error;
1013 }
1014 return result;
1015 }
1016 return CObject::IllegalArgumentError();
1017}
1018
1019void FUNCTION_NAME(Socket_GetOption)(Dart_NativeArguments args) {
1020 Socket* socket =
1021 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
1022 int64_t option = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
1023 intptr_t protocol = static_cast<intptr_t>(
1024 DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2)));
1025 bool ok = false;
1026 switch (option) {
1027 case 0: { // TCP_NODELAY.
1028 bool enabled;
1029 ok = SocketBase::GetNoDelay(socket->fd(), &enabled);
1030 if (ok) {
1031 Dart_SetBooleanReturnValue(args, enabled);
1032 }
1033 break;
1034 }
1035 case 1: { // IP_MULTICAST_LOOP.
1036 bool enabled;
1037 ok = SocketBase::GetMulticastLoop(socket->fd(), protocol, &enabled);
1038 if (ok) {
1039 Dart_SetBooleanReturnValue(args, enabled);
1040 }
1041 break;
1042 }
1043 case 2: { // IP_MULTICAST_TTL.
1044 int value;
1045 ok = SocketBase::GetMulticastHops(socket->fd(), protocol, &value);
1046 if (ok) {
1047 Dart_SetIntegerReturnValue(args, value);
1048 }
1049 break;
1050 }
1051 case 3: { // IP_MULTICAST_IF.
1052 UNIMPLEMENTED();
1053 break;
1054 }
1055 case 4: { // IP_BROADCAST.
1056 bool enabled;
1057 ok = SocketBase::GetBroadcast(socket->fd(), &enabled);
1058 if (ok) {
1059 Dart_SetBooleanReturnValue(args, enabled);
1060 }
1061 break;
1062 }
1063 default:
1064 UNREACHABLE();
1065 break;
1066 }
1067 // In case of failure the return value is not set above.
1068 if (!ok) {
1069 Dart_ThrowException(DartUtils::NewDartOSError());
1070 }
1071}
1072
1073void FUNCTION_NAME(Socket_SetOption)(Dart_NativeArguments args) {
1074 bool result = false;
1075 Socket* socket =
1076 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
1077 int64_t option = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
1078 int64_t protocol = DartUtils::GetInt64ValueCheckRange(
1079 Dart_GetNativeArgument(args, 2), SocketAddress::TYPE_IPV4,
1080 SocketAddress::TYPE_IPV6);
1081 switch (option) {
1082 case 0: // TCP_NODELAY.
1083 result = SocketBase::SetNoDelay(
1084 socket->fd(),
1085 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3)));
1086 break;
1087 case 1: // IP_MULTICAST_LOOP.
1088 result = SocketBase::SetMulticastLoop(
1089 socket->fd(), protocol,
1090 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3)));
1091 break;
1092 case 2: // IP_MULTICAST_TTL.
1093 result = SocketBase::SetMulticastHops(
1094 socket->fd(), protocol,
1095 DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3)));
1096 break;
1097 case 3: { // IP_MULTICAST_IF.
1098 UNIMPLEMENTED();
1099 break;
1100 }
1101 case 4: // IP_BROADCAST.
1102 result = SocketBase::SetBroadcast(
1103 socket->fd(),
1104 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3)));
1105 break;
1106 default:
1107 Dart_PropagateError(
1108 Dart_NewApiError("option to setOption() is outside expected range"));
1109 break;
1110 }
1111 if (!result) {
1112 Dart_ThrowException(DartUtils::NewDartOSError());
1113 }
1114}
1115
1116void FUNCTION_NAME(Socket_SetRawOption)(Dart_NativeArguments args) {
1117 Socket* socket =
1118 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
1119 int64_t level = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
1120 int64_t option = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
1121 Dart_Handle data_obj = Dart_GetNativeArgument(args, 3);
1122 ASSERT(Dart_IsList(data_obj));
1123 char* data = nullptr;
1124 intptr_t length;
1125 Dart_TypedData_Type type;
1126 Dart_Handle data_result = Dart_TypedDataAcquireData(
1127 data_obj, &type, reinterpret_cast<void**>(&data), &length);
1128 if (Dart_IsError(data_result)) {
1129 Dart_PropagateError(data_result);
1130 }
1131
1132 bool result = SocketBase::SetOption(socket->fd(), static_cast<int>(level),
1133 static_cast<int>(option), data,
1134 static_cast<int>(length));
1135
1136 Dart_TypedDataReleaseData(data_obj);
1137
1138 if (!result) {
1139 Dart_ThrowException(DartUtils::NewDartOSError());
1140 }
1141}
1142
1143void FUNCTION_NAME(Socket_GetRawOption)(Dart_NativeArguments args) {
1144 Socket* socket =
1145 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
1146 int64_t level = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 1));
1147 int64_t option = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
1148 Dart_Handle data_obj = Dart_GetNativeArgument(args, 3);
1149 ASSERT(Dart_IsList(data_obj));
1150 char* data = nullptr;
1151 intptr_t length;
1152 Dart_TypedData_Type type;
1153 Dart_Handle data_result = Dart_TypedDataAcquireData(
1154 data_obj, &type, reinterpret_cast<void**>(&data), &length);
1155 if (Dart_IsError(data_result)) {
1156 Dart_PropagateError(data_result);
1157 }
1158 unsigned int int_length = static_cast<unsigned int>(length);
1159 bool result =
1160 SocketBase::GetOption(socket->fd(), static_cast<int>(level),
1161 static_cast<int>(option), data, &int_length);
1162
1163 Dart_TypedDataReleaseData(data_obj);
1164 if (!result) {
1165 Dart_ThrowException(DartUtils::NewDartOSError());
1166 }
1167}
1168
1169// Keep in sync with _RawSocketOptions in socket.dart
1170enum _RawSocketOptions : int64_t {
1171 DART_SOL_SOCKET = 0,
1172 DART_IPPROTO_IP = 1,
1173 DART_IP_MULTICAST_IF = 2,
1174 DART_IPPROTO_IPV6 = 3,
1175 DART_IPV6_MULTICAST_IF = 4,
1176 DART_IPPROTO_TCP = 5,
1177 DART_IPPROTO_UDP = 6
1178};
1179
1180void FUNCTION_NAME(RawSocketOption_GetOptionValue)(Dart_NativeArguments args) {
1181 _RawSocketOptions key = static_cast<_RawSocketOptions>(
1182 DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 0)));
1183 switch (key) {
1184 case DART_SOL_SOCKET:
1185 Dart_SetIntegerReturnValue(args, SOL_SOCKET);
1186 break;
1187 case DART_IPPROTO_IP:
1188 Dart_SetIntegerReturnValue(args, IPPROTO_IP);
1189 break;
1190 case DART_IP_MULTICAST_IF:
1191 Dart_SetIntegerReturnValue(args, IP_MULTICAST_IF);
1192 break;
1193 case DART_IPPROTO_IPV6:
1194 Dart_SetIntegerReturnValue(args, IPPROTO_IPV6);
1195 break;
1196 case DART_IPV6_MULTICAST_IF:
1197 Dart_SetIntegerReturnValue(args, IPV6_MULTICAST_IF);
1198 break;
1199 case DART_IPPROTO_TCP:
1200 Dart_SetIntegerReturnValue(args, IPPROTO_TCP);
1201 break;
1202 case DART_IPPROTO_UDP:
1203 Dart_SetIntegerReturnValue(args, IPPROTO_UDP);
1204 break;
1205 default:
1206 Dart_PropagateError(Dart_NewApiError(
1207 "option to getOptionValue() is outside expected range"));
1208 break;
1209 }
1210}
1211
1212void FUNCTION_NAME(Socket_JoinMulticast)(Dart_NativeArguments args) {
1213 Socket* socket =
1214 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
1215 RawAddr addr;
1216 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
1217 RawAddr interface;
1218 if (Dart_GetNativeArgument(args, 2) != Dart_Null()) {
1219 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 2), &interface);
1220 }
1221 int interfaceIndex =
1222 DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
1223 if (!SocketBase::JoinMulticast(socket->fd(), addr, interface,
1224 interfaceIndex)) {
1225 Dart_ThrowException(DartUtils::NewDartOSError());
1226 }
1227}
1228
1229void FUNCTION_NAME(Socket_LeaveMulticast)(Dart_NativeArguments args) {
1230 Socket* socket =
1231 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
1232 RawAddr addr;
1233 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
1234 RawAddr interface;
1235 if (Dart_GetNativeArgument(args, 2) != Dart_Null()) {
1236 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 2), &interface);
1237 }
1238 int interfaceIndex =
1239 DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
1240 if (!SocketBase::LeaveMulticast(socket->fd(), addr, interface,
1241 interfaceIndex)) {
1242 Dart_ThrowException(DartUtils::NewDartOSError());
1243 }
1244}
1245
1246void FUNCTION_NAME(Socket_AvailableDatagram)(Dart_NativeArguments args) {
1247 const int kReceiveBufferLen = 1;
1248 Socket* socket =
1249 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
1250 ASSERT(socket != nullptr);
1251 // Ensure that a receive buffer for peeking the UDP socket exists.
1252 uint8_t recv_buffer[kReceiveBufferLen];
1253 bool available = SocketBase::AvailableDatagram(socket->fd(), recv_buffer,
1254 kReceiveBufferLen);
1255 Dart_SetBooleanReturnValue(args, available);
1256}
1257
1258static void NormalSocketFinalizer(void* isolate_data, void* data) {
1259 Socket* socket = reinterpret_cast<Socket*>(data);
1260 if (socket->fd() >= 0) {
1261 const int64_t flags = 1 << kCloseCommand;
1262 socket->Retain();
1263 EventHandler::SendFromNative(reinterpret_cast<intptr_t>(socket),
1264 socket->port(), flags);
1265 }
1266 socket->Release();
1267}
1268
1269static void ListeningSocketFinalizer(void* isolate_data, void* data) {
1270 Socket* socket = reinterpret_cast<Socket*>(data);
1271 if (socket->fd() >= 0) {
1272 const int64_t flags = (1 << kListeningSocket) | (1 << kCloseCommand);
1273 socket->Retain();
1274 EventHandler::SendFromNative(reinterpret_cast<intptr_t>(socket),
1275 socket->port(), flags);
1276 }
1277 socket->Release();
1278}
1279
1280static void StdioSocketFinalizer(void* isolate_data, void* data) {
1281 Socket* socket = reinterpret_cast<Socket*>(data);
1282 if (socket->fd() >= 0) {
1283 socket->CloseFd();
1284 }
1285 socket->Release();
1286}
1287
1288static void SignalSocketFinalizer(void* isolate_data, void* data) {
1289 Socket* socket = reinterpret_cast<Socket*>(data);
1290 if (socket->fd() >= 0) {
1291 Process::ClearSignalHandlerByFd(socket->fd(), socket->isolate_port());
1292 const int64_t flags = 1 << kCloseCommand;
1293 socket->Retain();
1294 EventHandler::SendFromNative(reinterpret_cast<intptr_t>(socket),
1295 socket->port(), flags);
1296 }
1297
1298 socket->Release();
1299}
1300
1301void Socket::ReuseSocketIdNativeField(Dart_Handle handle,
1302 Socket* socket,
1303 SocketFinalizer finalizer) {
1304 Dart_Handle err = Dart_SetNativeInstanceField(
1305 handle, kSocketIdNativeField, reinterpret_cast<intptr_t>(socket));
1306 if (Dart_IsError(err)) {
1307 Dart_PropagateError(err);
1308 }
1309 Dart_HandleFinalizer callback;
1310 switch (finalizer) {
1311 case kFinalizerNormal:
1312 callback = NormalSocketFinalizer;
1313 break;
1314 case kFinalizerListening:
1315 callback = ListeningSocketFinalizer;
1316 break;
1317 case kFinalizerStdio:
1318 callback = StdioSocketFinalizer;
1319 break;
1320 case kFinalizerSignal:
1321 callback = SignalSocketFinalizer;
1322 break;
1323 default:
1324 callback = NULL;
1325 UNREACHABLE();
1326 break;
1327 }
1328 if (callback != NULL) {
1329 Dart_NewFinalizableHandle(handle, reinterpret_cast<void*>(socket),
1330 sizeof(Socket), callback);
1331 }
1332}
1333
1334void Socket::SetSocketIdNativeField(Dart_Handle handle,
1335 intptr_t id,
1336 SocketFinalizer finalizer) {
1337 Socket* socket = new Socket(id);
1338 ReuseSocketIdNativeField(handle, socket, finalizer);
1339}
1340
1341Socket* Socket::GetSocketIdNativeField(Dart_Handle socket_obj) {
1342 intptr_t id;
1343 Dart_Handle err =
1344 Dart_GetNativeInstanceField(socket_obj, kSocketIdNativeField, &id);
1345 if (Dart_IsError(err)) {
1346 Dart_PropagateError(err);
1347 }
1348 Socket* socket = reinterpret_cast<Socket*>(id);
1349 if (socket == nullptr) {
1350 Dart_PropagateError(Dart_NewUnhandledExceptionError(
1351 DartUtils::NewInternalError("No native peer")));
1352 }
1353 return socket;
1354}
1355
1356} // namespace bin
1357} // namespace dart
1358