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