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 "platform/globals.h" |
6 | #if defined(HOST_OS_WINDOWS) |
7 | |
8 | #include "bin/socket_base.h" |
9 | |
10 | #include "bin/builtin.h" |
11 | #include "bin/eventhandler.h" |
12 | #include "bin/file.h" |
13 | #include "bin/lockers.h" |
14 | #include "bin/socket_base_win.h" |
15 | #include "bin/thread.h" |
16 | #include "bin/utils.h" |
17 | #include "bin/utils_win.h" |
18 | #include "platform/syslog.h" |
19 | |
20 | namespace dart { |
21 | namespace bin { |
22 | |
23 | SocketAddress::SocketAddress(struct sockaddr* sockaddr, |
24 | bool unnamed_unix_socket) { |
25 | // Unix domain sockets not supported on Win. Remove this assert if enabled. |
26 | ASSERT(!unnamed_unix_socket); |
27 | ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN); |
28 | RawAddr* raw = reinterpret_cast<RawAddr*>(sockaddr); |
29 | |
30 | // Clear the port before calling WSAAddressToString as WSAAddressToString |
31 | // includes the port in the formatted string. |
32 | int err = |
33 | SocketBase::FormatNumericAddress(*raw, as_string_, INET6_ADDRSTRLEN); |
34 | |
35 | if (err != 0) { |
36 | as_string_[0] = 0; |
37 | } |
38 | memmove(reinterpret_cast<void*>(&addr_), sockaddr, |
39 | SocketAddress::GetAddrLength(*raw)); |
40 | } |
41 | |
42 | static Mutex* init_mutex = new Mutex(); |
43 | static bool socket_initialized = false; |
44 | |
45 | bool SocketBase::Initialize() { |
46 | MutexLocker lock(init_mutex); |
47 | if (socket_initialized) { |
48 | return true; |
49 | } |
50 | int err; |
51 | WSADATA winsock_data; |
52 | WORD version_requested = MAKEWORD(2, 2); |
53 | err = WSAStartup(version_requested, &winsock_data); |
54 | if (err == 0) { |
55 | socket_initialized = true; |
56 | } else { |
57 | Syslog::PrintErr("Unable to initialize Winsock: %d\n" , WSAGetLastError()); |
58 | } |
59 | return (err == 0); |
60 | } |
61 | |
62 | bool SocketBase::FormatNumericAddress(const RawAddr& addr, |
63 | char* address, |
64 | int len) { |
65 | socklen_t salen = SocketAddress::GetAddrLength(addr); |
66 | DWORD l = len; |
67 | RawAddr& raw = const_cast<RawAddr&>(addr); |
68 | wchar_t* waddress = reinterpret_cast<wchar_t*>( |
69 | Dart_ScopeAllocate((salen + 1) * sizeof(wchar_t))); |
70 | intptr_t result = WSAAddressToStringW(&raw.addr, salen, NULL, waddress, &l); |
71 | if (result != 0) { |
72 | return true; |
73 | } |
74 | WideToUtf8Scope wide_name(waddress); |
75 | strncpy(address, wide_name.utf8(), l); |
76 | return false; |
77 | } |
78 | |
79 | intptr_t SocketBase::Available(intptr_t fd) { |
80 | ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(fd); |
81 | return client_socket->Available(); |
82 | } |
83 | |
84 | intptr_t SocketBase::Read(intptr_t fd, |
85 | void* buffer, |
86 | intptr_t num_bytes, |
87 | SocketOpKind sync) { |
88 | Handle* handle = reinterpret_cast<Handle*>(fd); |
89 | return handle->Read(buffer, num_bytes); |
90 | } |
91 | |
92 | intptr_t SocketBase::RecvFrom(intptr_t fd, |
93 | void* buffer, |
94 | intptr_t num_bytes, |
95 | RawAddr* addr, |
96 | SocketOpKind sync) { |
97 | Handle* handle = reinterpret_cast<Handle*>(fd); |
98 | socklen_t addr_len = sizeof(addr->ss); |
99 | return handle->RecvFrom(buffer, num_bytes, &addr->addr, addr_len); |
100 | } |
101 | |
102 | bool SocketBase::AvailableDatagram(intptr_t fd, |
103 | void* buffer, |
104 | intptr_t num_bytes) { |
105 | ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(fd); |
106 | return client_socket->DataReady(); |
107 | } |
108 | |
109 | intptr_t SocketBase::Write(intptr_t fd, |
110 | const void* buffer, |
111 | intptr_t num_bytes, |
112 | SocketOpKind sync) { |
113 | Handle* handle = reinterpret_cast<Handle*>(fd); |
114 | return handle->Write(buffer, num_bytes); |
115 | } |
116 | |
117 | intptr_t SocketBase::SendTo(intptr_t fd, |
118 | const void* buffer, |
119 | intptr_t num_bytes, |
120 | const RawAddr& addr, |
121 | SocketOpKind sync) { |
122 | Handle* handle = reinterpret_cast<Handle*>(fd); |
123 | RawAddr& raw = const_cast<RawAddr&>(addr); |
124 | return handle->SendTo(buffer, num_bytes, &raw.addr, |
125 | SocketAddress::GetAddrLength(addr)); |
126 | } |
127 | |
128 | intptr_t SocketBase::GetPort(intptr_t fd) { |
129 | ASSERT(reinterpret_cast<Handle*>(fd)->is_socket()); |
130 | SocketHandle* socket_handle = reinterpret_cast<SocketHandle*>(fd); |
131 | RawAddr raw; |
132 | socklen_t size = sizeof(raw); |
133 | if (getsockname(socket_handle->socket(), &raw.addr, &size) == SOCKET_ERROR) { |
134 | return 0; |
135 | } |
136 | return SocketAddress::GetAddrPort(raw); |
137 | } |
138 | |
139 | SocketAddress* SocketBase::GetRemotePeer(intptr_t fd, intptr_t* port) { |
140 | ASSERT(reinterpret_cast<Handle*>(fd)->is_socket()); |
141 | SocketHandle* socket_handle = reinterpret_cast<SocketHandle*>(fd); |
142 | RawAddr raw; |
143 | socklen_t size = sizeof(raw); |
144 | if (getpeername(socket_handle->socket(), &raw.addr, &size)) { |
145 | return NULL; |
146 | } |
147 | *port = SocketAddress::GetAddrPort(raw); |
148 | // Clear the port before calling WSAAddressToString as WSAAddressToString |
149 | // includes the port in the formatted string. |
150 | SocketAddress::SetAddrPort(&raw, 0); |
151 | return new SocketAddress(&raw.addr); |
152 | } |
153 | |
154 | bool SocketBase::IsBindError(intptr_t error_number) { |
155 | return error_number == WSAEADDRINUSE || error_number == WSAEADDRNOTAVAIL || |
156 | error_number == WSAEINVAL; |
157 | } |
158 | |
159 | void SocketBase::GetError(intptr_t fd, OSError* os_error) { |
160 | Handle* handle = reinterpret_cast<Handle*>(fd); |
161 | os_error->SetCodeAndMessage(OSError::kSystem, handle->last_error()); |
162 | } |
163 | |
164 | int SocketBase::GetType(intptr_t fd) { |
165 | Handle* handle = reinterpret_cast<Handle*>(fd); |
166 | switch (GetFileType(handle->handle())) { |
167 | case FILE_TYPE_CHAR: |
168 | return File::kTerminal; |
169 | case FILE_TYPE_PIPE: |
170 | return File::kPipe; |
171 | case FILE_TYPE_DISK: |
172 | return File::kFile; |
173 | default: |
174 | return GetLastError() == NO_ERROR ? File::kOther : -1; |
175 | } |
176 | } |
177 | |
178 | intptr_t SocketBase::GetStdioHandle(intptr_t num) { |
179 | if (num != 0) { |
180 | return -1; |
181 | } |
182 | HANDLE handle = GetStdHandle(STD_INPUT_HANDLE); |
183 | if (handle == INVALID_HANDLE_VALUE) { |
184 | return -1; |
185 | } |
186 | StdHandle* std_handle = StdHandle::Stdin(handle); |
187 | std_handle->Retain(); |
188 | std_handle->MarkDoesNotSupportOverlappedIO(); |
189 | std_handle->EnsureInitialized(EventHandler::delegate()); |
190 | return reinterpret_cast<intptr_t>(std_handle); |
191 | } |
192 | |
193 | AddressList<SocketAddress>* SocketBase::LookupAddress(const char* host, |
194 | int type, |
195 | OSError** os_error) { |
196 | Initialize(); |
197 | |
198 | // Perform a name lookup for a host name. |
199 | struct addrinfo hints; |
200 | memset(&hints, 0, sizeof(hints)); |
201 | hints.ai_family = SocketAddress::FromType(type); |
202 | hints.ai_socktype = SOCK_STREAM; |
203 | hints.ai_flags = AI_ADDRCONFIG; |
204 | hints.ai_protocol = IPPROTO_TCP; |
205 | struct addrinfo* info = NULL; |
206 | int status = getaddrinfo(host, 0, &hints, &info); |
207 | if (status != 0) { |
208 | // We failed, try without AI_ADDRCONFIG. This can happen when looking up |
209 | // e.g. '::1', when there are no global IPv6 addresses. |
210 | hints.ai_flags = 0; |
211 | status = getaddrinfo(host, 0, &hints, &info); |
212 | } |
213 | if (status != 0) { |
214 | ASSERT(*os_error == NULL); |
215 | DWORD error_code = WSAGetLastError(); |
216 | SetLastError(error_code); |
217 | *os_error = new OSError(); |
218 | return NULL; |
219 | } |
220 | intptr_t count = 0; |
221 | for (struct addrinfo* c = info; c != NULL; c = c->ai_next) { |
222 | if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) { |
223 | count++; |
224 | } |
225 | } |
226 | AddressList<SocketAddress>* addresses = new AddressList<SocketAddress>(count); |
227 | intptr_t i = 0; |
228 | for (struct addrinfo* c = info; c != NULL; c = c->ai_next) { |
229 | if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) { |
230 | addresses->SetAt(i, new SocketAddress(c->ai_addr)); |
231 | i++; |
232 | } |
233 | } |
234 | freeaddrinfo(info); |
235 | return addresses; |
236 | } |
237 | |
238 | bool SocketBase::ReverseLookup(const RawAddr& addr, |
239 | char* host, |
240 | intptr_t host_len, |
241 | OSError** os_error) { |
242 | ASSERT(host_len >= NI_MAXHOST); |
243 | int status = getnameinfo(&addr.addr, SocketAddress::GetAddrLength(addr), host, |
244 | host_len, NULL, 0, NI_NAMEREQD); |
245 | if (status != 0) { |
246 | ASSERT(*os_error == NULL); |
247 | DWORD error_code = WSAGetLastError(); |
248 | SetLastError(error_code); |
249 | *os_error = new OSError(); |
250 | return false; |
251 | } |
252 | return true; |
253 | } |
254 | |
255 | bool SocketBase::ParseAddress(int type, const char* address, RawAddr* addr) { |
256 | int result; |
257 | Utf8ToWideScope system_address(address); |
258 | if (type == SocketAddress::TYPE_IPV4) { |
259 | result = InetPton(AF_INET, system_address.wide(), &addr->in.sin_addr); |
260 | } else { |
261 | ASSERT(type == SocketAddress::TYPE_IPV6); |
262 | result = InetPton(AF_INET6, system_address.wide(), &addr->in6.sin6_addr); |
263 | } |
264 | return result == 1; |
265 | } |
266 | |
267 | bool SocketBase::RawAddrToString(RawAddr* addr, char* str) { |
268 | // According to InetNtopW(), buffer should be large enough for at least 46 |
269 | // characters for IPv6 and 16 for IPv4. |
270 | COMPILE_ASSERT(INET6_ADDRSTRLEN >= 46); |
271 | wchar_t tmp_buffer[INET6_ADDRSTRLEN]; |
272 | if (addr->addr.sa_family == AF_INET) { |
273 | if (InetNtop(AF_INET, &addr->in.sin_addr, tmp_buffer, INET_ADDRSTRLEN) == |
274 | NULL) { |
275 | return false; |
276 | } |
277 | } else { |
278 | ASSERT(addr->addr.sa_family == AF_INET6); |
279 | if (InetNtop(AF_INET6, &addr->in6.sin6_addr, tmp_buffer, |
280 | INET6_ADDRSTRLEN) == NULL) { |
281 | return false; |
282 | } |
283 | } |
284 | WideToUtf8Scope wide_to_utf8_scope(tmp_buffer); |
285 | if (wide_to_utf8_scope.length() <= INET6_ADDRSTRLEN) { |
286 | strncpy(str, wide_to_utf8_scope.utf8(), INET6_ADDRSTRLEN); |
287 | return true; |
288 | } |
289 | return false; |
290 | } |
291 | |
292 | bool SocketBase::ListInterfacesSupported() { |
293 | return true; |
294 | } |
295 | |
296 | AddressList<InterfaceSocketAddress>* SocketBase::ListInterfaces( |
297 | int type, |
298 | OSError** os_error) { |
299 | Initialize(); |
300 | |
301 | ULONG size = 0; |
302 | DWORD flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | |
303 | GAA_FLAG_SKIP_DNS_SERVER; |
304 | // Query the size needed. |
305 | int status = GetAdaptersAddresses(SocketAddress::FromType(type), flags, NULL, |
306 | NULL, &size); |
307 | IP_ADAPTER_ADDRESSES* addrs = NULL; |
308 | if (status == ERROR_BUFFER_OVERFLOW) { |
309 | addrs = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(malloc(size)); |
310 | // Get the addresses now we have the right buffer. |
311 | status = GetAdaptersAddresses(SocketAddress::FromType(type), flags, NULL, |
312 | addrs, &size); |
313 | } |
314 | if (status != NO_ERROR) { |
315 | ASSERT(*os_error == NULL); |
316 | DWORD error_code = WSAGetLastError(); |
317 | SetLastError(error_code); |
318 | *os_error = new OSError(); |
319 | return NULL; |
320 | } |
321 | intptr_t count = 0; |
322 | for (IP_ADAPTER_ADDRESSES* a = addrs; a != NULL; a = a->Next) { |
323 | for (IP_ADAPTER_UNICAST_ADDRESS* u = a->FirstUnicastAddress; u != NULL; |
324 | u = u->Next) { |
325 | count++; |
326 | } |
327 | } |
328 | AddressList<InterfaceSocketAddress>* addresses = |
329 | new AddressList<InterfaceSocketAddress>(count); |
330 | intptr_t i = 0; |
331 | for (IP_ADAPTER_ADDRESSES* a = addrs; a != NULL; a = a->Next) { |
332 | for (IP_ADAPTER_UNICAST_ADDRESS* u = a->FirstUnicastAddress; u != NULL; |
333 | u = u->Next) { |
334 | addresses->SetAt( |
335 | i, new InterfaceSocketAddress( |
336 | u->Address.lpSockaddr, |
337 | StringUtilsWin::WideToUtf8(a->FriendlyName), a->Ipv6IfIndex)); |
338 | i++; |
339 | } |
340 | } |
341 | free(addrs); |
342 | return addresses; |
343 | } |
344 | |
345 | void SocketBase::Close(intptr_t fd) { |
346 | ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(fd); |
347 | client_socket->Close(); |
348 | } |
349 | |
350 | bool SocketBase::GetNoDelay(intptr_t fd, bool* enabled) { |
351 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
352 | int on; |
353 | socklen_t len = sizeof(on); |
354 | int err = getsockopt(handle->socket(), IPPROTO_TCP, TCP_NODELAY, |
355 | reinterpret_cast<char*>(&on), &len); |
356 | if (err == 0) { |
357 | *enabled = (on == 1); |
358 | } |
359 | return (err == 0); |
360 | } |
361 | |
362 | bool SocketBase::SetNoDelay(intptr_t fd, bool enabled) { |
363 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
364 | int on = enabled ? 1 : 0; |
365 | return setsockopt(handle->socket(), IPPROTO_TCP, TCP_NODELAY, |
366 | reinterpret_cast<char*>(&on), sizeof(on)) == 0; |
367 | } |
368 | |
369 | bool SocketBase::GetMulticastLoop(intptr_t fd, |
370 | intptr_t protocol, |
371 | bool* enabled) { |
372 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
373 | uint8_t on; |
374 | socklen_t len = sizeof(on); |
375 | int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; |
376 | int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_LOOP |
377 | : IPV6_MULTICAST_LOOP; |
378 | if (getsockopt(handle->socket(), level, optname, reinterpret_cast<char*>(&on), |
379 | &len) == 0) { |
380 | *enabled = (on == 1); |
381 | return true; |
382 | } |
383 | return false; |
384 | } |
385 | |
386 | bool SocketBase::SetMulticastLoop(intptr_t fd, |
387 | intptr_t protocol, |
388 | bool enabled) { |
389 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
390 | int on = enabled ? 1 : 0; |
391 | int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; |
392 | int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_LOOP |
393 | : IPV6_MULTICAST_LOOP; |
394 | return setsockopt(handle->socket(), level, optname, |
395 | reinterpret_cast<char*>(&on), sizeof(on)) == 0; |
396 | } |
397 | |
398 | bool SocketBase::GetMulticastHops(intptr_t fd, intptr_t protocol, int* value) { |
399 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
400 | uint8_t v; |
401 | socklen_t len = sizeof(v); |
402 | int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; |
403 | int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_TTL |
404 | : IPV6_MULTICAST_HOPS; |
405 | if (getsockopt(handle->socket(), level, optname, reinterpret_cast<char*>(&v), |
406 | &len) == 0) { |
407 | *value = v; |
408 | return true; |
409 | } |
410 | return false; |
411 | } |
412 | |
413 | bool SocketBase::SetMulticastHops(intptr_t fd, intptr_t protocol, int value) { |
414 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
415 | int v = value; |
416 | int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; |
417 | int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_TTL |
418 | : IPV6_MULTICAST_HOPS; |
419 | return setsockopt(handle->socket(), level, optname, |
420 | reinterpret_cast<char*>(&v), sizeof(v)) == 0; |
421 | } |
422 | |
423 | bool SocketBase::GetBroadcast(intptr_t fd, bool* enabled) { |
424 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
425 | int on; |
426 | socklen_t len = sizeof(on); |
427 | int err = getsockopt(handle->socket(), SOL_SOCKET, SO_BROADCAST, |
428 | reinterpret_cast<char*>(&on), &len); |
429 | if (err == 0) { |
430 | *enabled = (on == 1); |
431 | } |
432 | return (err == 0); |
433 | } |
434 | |
435 | bool SocketBase::SetBroadcast(intptr_t fd, bool enabled) { |
436 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
437 | int on = enabled ? 1 : 0; |
438 | return setsockopt(handle->socket(), SOL_SOCKET, SO_BROADCAST, |
439 | reinterpret_cast<char*>(&on), sizeof(on)) == 0; |
440 | } |
441 | |
442 | bool SocketBase::SetOption(intptr_t fd, |
443 | int level, |
444 | int option, |
445 | const char* data, |
446 | int length) { |
447 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
448 | return setsockopt(handle->socket(), level, option, data, length) == 0; |
449 | } |
450 | |
451 | bool SocketBase::GetOption(intptr_t fd, |
452 | int level, |
453 | int option, |
454 | char* data, |
455 | unsigned int* length) { |
456 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
457 | int optlen = static_cast<int>(*length); |
458 | auto result = getsockopt(handle->socket(), level, option, data, &optlen); |
459 | *length = static_cast<unsigned int>(optlen); |
460 | return result == 0; |
461 | } |
462 | |
463 | bool SocketBase::JoinMulticast(intptr_t fd, |
464 | const RawAddr& addr, |
465 | const RawAddr&, |
466 | int interfaceIndex) { |
467 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
468 | int proto = addr.addr.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; |
469 | struct group_req mreq; |
470 | mreq.gr_interface = interfaceIndex; |
471 | memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr)); |
472 | return setsockopt(handle->socket(), proto, MCAST_JOIN_GROUP, |
473 | reinterpret_cast<char*>(&mreq), sizeof(mreq)) == 0; |
474 | } |
475 | |
476 | bool SocketBase::LeaveMulticast(intptr_t fd, |
477 | const RawAddr& addr, |
478 | const RawAddr&, |
479 | int interfaceIndex) { |
480 | SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd); |
481 | int proto = addr.addr.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; |
482 | struct group_req mreq; |
483 | mreq.gr_interface = interfaceIndex; |
484 | memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr)); |
485 | return setsockopt(handle->socket(), proto, MCAST_LEAVE_GROUP, |
486 | reinterpret_cast<char*>(&mreq), sizeof(mreq)) == 0; |
487 | } |
488 | |
489 | } // namespace bin |
490 | } // namespace dart |
491 | |
492 | #endif // defined(HOST_OS_WINDOWS) |
493 | |