| 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 | |