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
20namespace dart {
21namespace bin {
22
23int 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
37intptr_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
53intptr_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
59bool 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
84void 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
109Dart_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
142int16_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
156void 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
166intptr_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
179Dart_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
199CObjectUint8Array* 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}
212void 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
217intptr_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
225void 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
246void 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
271void 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
283void FUNCTION_NAME(NetworkInterface_ListSupported)(Dart_NativeArguments args) {
284 Dart_SetBooleanReturnValue(args, SocketBase::ListInterfacesSupported());
285}
286
287void 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