| 1 | // Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file | 
|---|
| 2 | // for details. All rights reserved. Use of this source code is governed by a | 
|---|
| 3 | // BSD-style license that can be found in the LICENSE file. | 
|---|
| 4 |  | 
|---|
| 5 | #include "bin/socket_base.h" | 
|---|
| 6 |  | 
|---|
| 7 | #include "bin/dartutils.h" | 
|---|
| 8 | #include "bin/io_buffer.h" | 
|---|
| 9 | #include "bin/isolate_data.h" | 
|---|
| 10 | #include "bin/lockers.h" | 
|---|
| 11 | #include "bin/thread.h" | 
|---|
| 12 | #include "bin/typed_data_utils.h" | 
|---|
| 13 | #include "bin/utils.h" | 
|---|
| 14 |  | 
|---|
| 15 | #include "include/dart_api.h" | 
|---|
| 16 |  | 
|---|
| 17 | #include "platform/globals.h" | 
|---|
| 18 | #include "platform/utils.h" | 
|---|
| 19 |  | 
|---|
| 20 | namespace dart { | 
|---|
| 21 | namespace bin { | 
|---|
| 22 |  | 
|---|
| 23 | int SocketAddress::GetType() { | 
|---|
| 24 | switch (addr_.ss.ss_family) { | 
|---|
| 25 | case AF_INET6: | 
|---|
| 26 | return TYPE_IPV6; | 
|---|
| 27 | case AF_INET: | 
|---|
| 28 | return TYPE_IPV4; | 
|---|
| 29 | case AF_UNIX: | 
|---|
| 30 | return TYPE_UNIX; | 
|---|
| 31 | default: | 
|---|
| 32 | UNREACHABLE(); | 
|---|
| 33 | return TYPE_ANY; | 
|---|
| 34 | } | 
|---|
| 35 | } | 
|---|
| 36 |  | 
|---|
| 37 | intptr_t SocketAddress::GetAddrLength(const RawAddr& addr) { | 
|---|
| 38 | ASSERT((addr.ss.ss_family == AF_INET) || (addr.ss.ss_family == AF_INET6) || | 
|---|
| 39 | (addr.ss.ss_family == AF_UNIX)); | 
|---|
| 40 | switch (addr.ss.ss_family) { | 
|---|
| 41 | case AF_INET6: | 
|---|
| 42 | return sizeof(struct sockaddr_in6); | 
|---|
| 43 | case AF_INET: | 
|---|
| 44 | return sizeof(struct sockaddr_in); | 
|---|
| 45 | case AF_UNIX: | 
|---|
| 46 | return sizeof(struct sockaddr_un); | 
|---|
| 47 | default: | 
|---|
| 48 | UNREACHABLE(); | 
|---|
| 49 | return 0; | 
|---|
| 50 | } | 
|---|
| 51 | } | 
|---|
| 52 |  | 
|---|
| 53 | intptr_t SocketAddress::GetInAddrLength(const RawAddr& addr) { | 
|---|
| 54 | ASSERT((addr.ss.ss_family == AF_INET) || (addr.ss.ss_family == AF_INET6)); | 
|---|
| 55 | return (addr.ss.ss_family == AF_INET6) ? sizeof(struct in6_addr) | 
|---|
| 56 | : sizeof(struct in_addr); | 
|---|
| 57 | } | 
|---|
| 58 |  | 
|---|
| 59 | bool SocketAddress::AreAddressesEqual(const RawAddr& a, const RawAddr& b) { | 
|---|
| 60 | if (a.ss.ss_family != b.ss.ss_family) { | 
|---|
| 61 | return false; | 
|---|
| 62 | } | 
|---|
| 63 | if (a.ss.ss_family == AF_INET) { | 
|---|
| 64 | return memcmp(&a.in.sin_addr, &b.in.sin_addr, sizeof(a.in.sin_addr)) == 0; | 
|---|
| 65 | } else if (a.ss.ss_family == AF_INET6) { | 
|---|
| 66 | return memcmp(&a.in6.sin6_addr, &b.in6.sin6_addr, | 
|---|
| 67 | sizeof(a.in6.sin6_addr)) == 0 && | 
|---|
| 68 | a.in6.sin6_scope_id == b.in6.sin6_scope_id; | 
|---|
| 69 | } else if (a.ss.ss_family == AF_UNIX) { | 
|---|
| 70 | // This is not used anywhere. The comparison of file path is done via | 
|---|
| 71 | // File::AreIdentical(). | 
|---|
| 72 | int len = sizeof(a.un.sun_path); | 
|---|
| 73 | for (int i = 0; i < len; i++) { | 
|---|
| 74 | if (a.un.sun_path[i] != b.un.sun_path[i]) return false; | 
|---|
| 75 | if (a.un.sun_path[i] == '\0') return true; | 
|---|
| 76 | } | 
|---|
| 77 | return true; | 
|---|
| 78 | } else { | 
|---|
| 79 | UNREACHABLE(); | 
|---|
| 80 | return false; | 
|---|
| 81 | } | 
|---|
| 82 | } | 
|---|
| 83 |  | 
|---|
| 84 | void SocketAddress::GetSockAddr(Dart_Handle obj, RawAddr* addr) { | 
|---|
| 85 | Dart_TypedData_Type data_type; | 
|---|
| 86 | uint8_t* data = NULL; | 
|---|
| 87 | intptr_t len; | 
|---|
| 88 | Dart_Handle result = Dart_TypedDataAcquireData( | 
|---|
| 89 | obj, &data_type, reinterpret_cast<void**>(&data), &len); | 
|---|
| 90 | if (Dart_IsError(result)) { | 
|---|
| 91 | Dart_PropagateError(result); | 
|---|
| 92 | } | 
|---|
| 93 | if ((data_type != Dart_TypedData_kUint8) || | 
|---|
| 94 | ((len != sizeof(in_addr)) && (len != sizeof(in6_addr)))) { | 
|---|
| 95 | Dart_PropagateError(Dart_NewApiError( "Unexpected type for socket address")); | 
|---|
| 96 | } | 
|---|
| 97 | memset(reinterpret_cast<void*>(addr), 0, sizeof(RawAddr)); | 
|---|
| 98 | if (len == sizeof(in_addr)) { | 
|---|
| 99 | addr->in.sin_family = AF_INET; | 
|---|
| 100 | memmove(reinterpret_cast<void*>(&addr->in.sin_addr), data, len); | 
|---|
| 101 | } else { | 
|---|
| 102 | ASSERT(len == sizeof(in6_addr)); | 
|---|
| 103 | addr->in6.sin6_family = AF_INET6; | 
|---|
| 104 | memmove(reinterpret_cast<void*>(&addr->in6.sin6_addr), data, len); | 
|---|
| 105 | } | 
|---|
| 106 | Dart_TypedDataReleaseData(obj); | 
|---|
| 107 | } | 
|---|
| 108 |  | 
|---|
| 109 | Dart_Handle SocketAddress::GetUnixDomainSockAddr(const char* path, | 
|---|
| 110 | Namespace* namespc, | 
|---|
| 111 | RawAddr* addr) { | 
|---|
| 112 | #if defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID) | 
|---|
| 113 | NamespaceScope ns(namespc, path); | 
|---|
| 114 | path = ns.path(); | 
|---|
| 115 | bool is_abstract = (path[0] == '@'); | 
|---|
| 116 | if (is_abstract) { | 
|---|
| 117 | // The following 107 bytes after the leading null byte represents the name | 
|---|
| 118 | // of unix domain socket. Without reseting, even users provide the same path | 
|---|
| 119 | // for bind and connect, they actually represent two different address and | 
|---|
| 120 | // connection will be rejected. | 
|---|
| 121 | bzero(addr->un.sun_path, sizeof(addr->un.sun_path)); | 
|---|
| 122 | } | 
|---|
| 123 | #endif  // defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID) | 
|---|
| 124 | if (sizeof(path) > sizeof(addr->un.sun_path)) { | 
|---|
| 125 | OSError os_error(-1, | 
|---|
| 126 | "The length of path exceeds the limit. " | 
|---|
| 127 | "Check out man 7 unix page", | 
|---|
| 128 | OSError::kUnknown); | 
|---|
| 129 | return DartUtils::NewDartOSError(&os_error); | 
|---|
| 130 | } | 
|---|
| 131 | addr->un.sun_family = AF_UNIX; | 
|---|
| 132 | Utils::SNPrint(addr->un.sun_path, sizeof(addr->un.sun_path), "%s", path); | 
|---|
| 133 | #if defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID) | 
|---|
| 134 | // In case of abstract namespace, transfer the leading '@' into a null byte. | 
|---|
| 135 | if (is_abstract) { | 
|---|
| 136 | addr->un.sun_path[0] = '\0'; | 
|---|
| 137 | } | 
|---|
| 138 | #endif  // defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID) | 
|---|
| 139 | return Dart_Null(); | 
|---|
| 140 | } | 
|---|
| 141 |  | 
|---|
| 142 | int16_t SocketAddress::FromType(int type) { | 
|---|
| 143 | if (type == TYPE_ANY) { | 
|---|
| 144 | return AF_UNSPEC; | 
|---|
| 145 | } | 
|---|
| 146 | if (type == TYPE_IPV4) { | 
|---|
| 147 | return AF_INET; | 
|---|
| 148 | } | 
|---|
| 149 | if (type == TYPE_UNIX) { | 
|---|
| 150 | return AF_UNIX; | 
|---|
| 151 | } | 
|---|
| 152 | ASSERT((type == TYPE_IPV6) && "Invalid type"); | 
|---|
| 153 | return AF_INET6; | 
|---|
| 154 | } | 
|---|
| 155 |  | 
|---|
| 156 | void SocketAddress::SetAddrPort(RawAddr* addr, intptr_t port) { | 
|---|
| 157 | if (addr->ss.ss_family == AF_INET) { | 
|---|
| 158 | addr->in.sin_port = htons(port); | 
|---|
| 159 | } else if (addr->ss.ss_family == AF_INET6) { | 
|---|
| 160 | addr->in6.sin6_port = htons(port); | 
|---|
| 161 | } else { | 
|---|
| 162 | UNREACHABLE(); | 
|---|
| 163 | } | 
|---|
| 164 | } | 
|---|
| 165 |  | 
|---|
| 166 | intptr_t SocketAddress::GetAddrPort(const RawAddr& addr) { | 
|---|
| 167 | if (addr.ss.ss_family == AF_INET) { | 
|---|
| 168 | return ntohs(addr.in.sin_port); | 
|---|
| 169 | } else if (addr.ss.ss_family == AF_INET6) { | 
|---|
| 170 | return ntohs(addr.in6.sin6_port); | 
|---|
| 171 | } else if (addr.ss.ss_family == AF_UNIX) { | 
|---|
| 172 | return 0; | 
|---|
| 173 | } else { | 
|---|
| 174 | UNREACHABLE(); | 
|---|
| 175 | return -1; | 
|---|
| 176 | } | 
|---|
| 177 | } | 
|---|
| 178 |  | 
|---|
| 179 | Dart_Handle SocketAddress::ToTypedData(const RawAddr& addr) { | 
|---|
| 180 | int len = GetInAddrLength(addr); | 
|---|
| 181 | Dart_Handle result = Dart_NewTypedData(Dart_TypedData_kUint8, len); | 
|---|
| 182 | if (Dart_IsError(result)) { | 
|---|
| 183 | Dart_PropagateError(result); | 
|---|
| 184 | } | 
|---|
| 185 | Dart_Handle err; | 
|---|
| 186 | if (addr.addr.sa_family == AF_INET6) { | 
|---|
| 187 | err = Dart_ListSetAsBytes( | 
|---|
| 188 | result, 0, reinterpret_cast<const uint8_t*>(&addr.in6.sin6_addr), len); | 
|---|
| 189 | } else { | 
|---|
| 190 | err = Dart_ListSetAsBytes( | 
|---|
| 191 | result, 0, reinterpret_cast<const uint8_t*>(&addr.in.sin_addr), len); | 
|---|
| 192 | } | 
|---|
| 193 | if (Dart_IsError(err)) { | 
|---|
| 194 | Dart_PropagateError(err); | 
|---|
| 195 | } | 
|---|
| 196 | return result; | 
|---|
| 197 | } | 
|---|
| 198 |  | 
|---|
| 199 | CObjectUint8Array* SocketAddress::ToCObject(const RawAddr& addr) { | 
|---|
| 200 | int in_addr_len = SocketAddress::GetInAddrLength(addr); | 
|---|
| 201 | const void* in_addr; | 
|---|
| 202 | CObjectUint8Array* data = | 
|---|
| 203 | new CObjectUint8Array(CObject::NewUint8Array(in_addr_len)); | 
|---|
| 204 | if (addr.addr.sa_family == AF_INET6) { | 
|---|
| 205 | in_addr = reinterpret_cast<const void*>(&addr.in6.sin6_addr); | 
|---|
| 206 | } else { | 
|---|
| 207 | in_addr = reinterpret_cast<const void*>(&addr.in.sin_addr); | 
|---|
| 208 | } | 
|---|
| 209 | memmove(data->Buffer(), in_addr, in_addr_len); | 
|---|
| 210 | return data; | 
|---|
| 211 | } | 
|---|
| 212 | void SocketAddress::SetAddrScope(RawAddr* addr, intptr_t scope_id) { | 
|---|
| 213 | if (addr->addr.sa_family != AF_INET6) return; | 
|---|
| 214 | addr->in6.sin6_scope_id = scope_id; | 
|---|
| 215 | } | 
|---|
| 216 |  | 
|---|
| 217 | intptr_t SocketAddress::GetAddrScope(const RawAddr& addr) { | 
|---|
| 218 | if (addr.addr.sa_family == AF_INET6) { | 
|---|
| 219 | return addr.in6.sin6_scope_id; | 
|---|
| 220 | } else { | 
|---|
| 221 | return 0; | 
|---|
| 222 | } | 
|---|
| 223 | } | 
|---|
| 224 |  | 
|---|
| 225 | void FUNCTION_NAME(InternetAddress_Parse)(Dart_NativeArguments args) { | 
|---|
| 226 | const char* address = | 
|---|
| 227 | DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); | 
|---|
| 228 | ASSERT(address != NULL); | 
|---|
| 229 | RawAddr raw; | 
|---|
| 230 | memset(&raw, 0, sizeof(raw)); | 
|---|
| 231 | int type = strchr(address, ':') == NULL ? SocketAddress::TYPE_IPV4 | 
|---|
| 232 | : SocketAddress::TYPE_IPV6; | 
|---|
| 233 | if (type == SocketAddress::TYPE_IPV4) { | 
|---|
| 234 | raw.addr.sa_family = AF_INET; | 
|---|
| 235 | } else { | 
|---|
| 236 | raw.addr.sa_family = AF_INET6; | 
|---|
| 237 | } | 
|---|
| 238 | bool ok = SocketBase::ParseAddress(type, address, &raw); | 
|---|
| 239 | if (!ok) { | 
|---|
| 240 | Dart_SetReturnValue(args, Dart_Null()); | 
|---|
| 241 | } else { | 
|---|
| 242 | Dart_SetReturnValue(args, SocketAddress::ToTypedData(raw)); | 
|---|
| 243 | } | 
|---|
| 244 | } | 
|---|
| 245 |  | 
|---|
| 246 | void FUNCTION_NAME(InternetAddress_ParseScopedLinkLocalAddress)( | 
|---|
| 247 | Dart_NativeArguments args) { | 
|---|
| 248 | const char* address = | 
|---|
| 249 | DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0)); | 
|---|
| 250 | // This must be an IPv6 address. | 
|---|
| 251 | intptr_t type = 1; | 
|---|
| 252 | ASSERT(address != NULL); | 
|---|
| 253 | OSError* os_error = NULL; | 
|---|
| 254 | AddressList<SocketAddress>* addresses = | 
|---|
| 255 | SocketBase::LookupAddress(address, type, &os_error); | 
|---|
| 256 | if (addresses != NULL) { | 
|---|
| 257 | Dart_Handle list = Dart_NewList(addresses->count()); | 
|---|
| 258 | for (intptr_t i = 0; i < addresses->count(); i++) { | 
|---|
| 259 | SocketAddress* addr = addresses->GetAt(i); | 
|---|
| 260 | Dart_ListSetAt( | 
|---|
| 261 | list, i, Dart_NewInteger(SocketAddress::GetAddrScope(addr->addr()))); | 
|---|
| 262 | } | 
|---|
| 263 | delete addresses; | 
|---|
| 264 | Dart_SetReturnValue(args, list); | 
|---|
| 265 | } else { | 
|---|
| 266 | Dart_SetReturnValue(args, DartUtils::NewDartOSError(os_error)); | 
|---|
| 267 | delete os_error; | 
|---|
| 268 | } | 
|---|
| 269 | } | 
|---|
| 270 |  | 
|---|
| 271 | void FUNCTION_NAME(InternetAddress_RawAddrToString)(Dart_NativeArguments args) { | 
|---|
| 272 | RawAddr addr; | 
|---|
| 273 | SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 0), &addr); | 
|---|
| 274 | // INET6_ADDRSTRLEN is larger than INET_ADDRSTRLEN | 
|---|
| 275 | char str[INET6_ADDRSTRLEN]; | 
|---|
| 276 | bool ok = SocketBase::RawAddrToString(&addr, str); | 
|---|
| 277 | if (!ok) { | 
|---|
| 278 | str[0] = '\0'; | 
|---|
| 279 | } | 
|---|
| 280 | Dart_SetReturnValue(args, ThrowIfError(DartUtils::NewString(str))); | 
|---|
| 281 | } | 
|---|
| 282 |  | 
|---|
| 283 | void FUNCTION_NAME(NetworkInterface_ListSupported)(Dart_NativeArguments args) { | 
|---|
| 284 | Dart_SetBooleanReturnValue(args, SocketBase::ListInterfacesSupported()); | 
|---|
| 285 | } | 
|---|
| 286 |  | 
|---|
| 287 | void FUNCTION_NAME(SocketBase_IsBindError)(Dart_NativeArguments args) { | 
|---|
| 288 | intptr_t error_number = | 
|---|
| 289 | DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1)); | 
|---|
| 290 | bool is_bind_error = SocketBase::IsBindError(error_number); | 
|---|
| 291 | Dart_SetBooleanReturnValue(args, is_bind_error ? true : false); | 
|---|
| 292 | } | 
|---|
| 293 |  | 
|---|
| 294 | }  // namespace bin | 
|---|
| 295 | }  // namespace dart | 
|---|
| 296 |  | 
|---|