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 | |
22 | namespace dart { |
23 | namespace bin { |
24 | |
25 | static const int kSocketIdNativeField = 0; |
26 | |
27 | ListeningSocketRegistry* globalTcpListeningSocketRegistry = nullptr; |
28 | |
29 | bool Socket::short_socket_read_ = false; |
30 | bool Socket::short_socket_write_ = false; |
31 | |
32 | void ListeningSocketRegistry::Initialize() { |
33 | ASSERT(globalTcpListeningSocketRegistry == nullptr); |
34 | globalTcpListeningSocketRegistry = new ListeningSocketRegistry(); |
35 | } |
36 | |
37 | ListeningSocketRegistry* ListeningSocketRegistry::Instance() { |
38 | return globalTcpListeningSocketRegistry; |
39 | } |
40 | |
41 | void ListeningSocketRegistry::Cleanup() { |
42 | delete globalTcpListeningSocketRegistry; |
43 | globalTcpListeningSocketRegistry = nullptr; |
44 | } |
45 | |
46 | ListeningSocketRegistry::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 | |
56 | void 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 | |
63 | void ListeningSocketRegistry::RemoveByPort(intptr_t port) { |
64 | sockets_by_port_.Remove(GetHashmapKeyFromIntptr(port), |
65 | GetHashmapHashFromIntptr(port)); |
66 | } |
67 | |
68 | ListeningSocketRegistry::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 | |
79 | void 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 | |
87 | void 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 | |
93 | Dart_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 | |
196 | Dart_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 | |
276 | bool 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 | |
339 | void 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 | |
349 | bool 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 | |
362 | void 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 | |
385 | void 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 | |
410 | void 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 | |
455 | void 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 | |
485 | void 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 | |
506 | void 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 | |
519 | void 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 | |
567 | void 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 | |
655 | void 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 | |
702 | void 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 | |
742 | void 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 | |
753 | void 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 | |
781 | void 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 | |
789 | void 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 | |
801 | void 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 | |
810 | void 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 | |
817 | void 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 | |
831 | void 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 | |
854 | void 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 | |
880 | void 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 | |
893 | CObject* 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 | |
939 | CObject* 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 | |
970 | CObject* 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 | |
1019 | void 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 | |
1073 | void 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 | |
1116 | void 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 | |
1143 | void 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 |
1170 | enum _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 | |
1180 | void 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 | |
1212 | void 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 | |
1229 | void 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 | |
1246 | void 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 | |
1258 | static 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 | |
1269 | static 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 | |
1280 | static 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 | |
1288 | static 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 | |
1301 | void 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 | |
1334 | void 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 | |
1341 | Socket* 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 | |