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