// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #if !defined(DART_IO_DISABLED) #include "platform/globals.h" #if defined(TARGET_OS_WINDOWS) #include "bin/socket.h" #include "bin/socket_win.h" #include "bin/builtin.h" #include "bin/eventhandler.h" #include "bin/file.h" #include "bin/lockers.h" #include "bin/log.h" #include "bin/thread.h" #include "bin/utils.h" #include "bin/utils_win.h" namespace dart { namespace bin { SocketAddress::SocketAddress(struct sockaddr* sockaddr) { ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN); RawAddr* raw = reinterpret_cast(sockaddr); // Clear the port before calling WSAAddressToString as WSAAddressToString // includes the port in the formatted string. int err = Socket::FormatNumericAddress(*raw, as_string_, INET6_ADDRSTRLEN); if (err != 0) { as_string_[0] = 0; } memmove(reinterpret_cast(&addr_), sockaddr, SocketAddress::GetAddrLength(*raw)); } bool Socket::FormatNumericAddress(const RawAddr& addr, char* address, int len) { socklen_t salen = SocketAddress::GetAddrLength(addr); DWORD l = len; RawAddr& raw = const_cast(addr); return WSAAddressToStringA(&raw.addr, salen, NULL, address, &l) != 0; } static Mutex* init_mutex = new Mutex(); static bool socket_initialized = false; bool Socket::Initialize() { MutexLocker lock(init_mutex); if (socket_initialized) { return true; } int err; WSADATA winsock_data; WORD version_requested = MAKEWORD(2, 2); err = WSAStartup(version_requested, &winsock_data); if (err == 0) { socket_initialized = true; } else { Log::PrintErr("Unable to initialize Winsock: %d\n", WSAGetLastError()); } return (err == 0); } intptr_t Socket::Available(intptr_t fd) { ClientSocket* client_socket = reinterpret_cast(fd); return client_socket->Available(); } intptr_t Socket::Read(intptr_t fd, void* buffer, intptr_t num_bytes) { Handle* handle = reinterpret_cast(fd); return handle->Read(buffer, num_bytes); } intptr_t Socket::RecvFrom( intptr_t fd, void* buffer, intptr_t num_bytes, RawAddr* addr) { Handle* handle = reinterpret_cast(fd); socklen_t addr_len = sizeof(addr->ss); return handle->RecvFrom(buffer, num_bytes, &addr->addr, addr_len); } intptr_t Socket::Write(intptr_t fd, const void* buffer, intptr_t num_bytes) { Handle* handle = reinterpret_cast(fd); return handle->Write(buffer, num_bytes); } intptr_t Socket::SendTo( intptr_t fd, const void* buffer, intptr_t num_bytes, const RawAddr& addr) { Handle* handle = reinterpret_cast(fd); RawAddr& raw = const_cast(addr); return handle->SendTo( buffer, num_bytes, &raw.addr, SocketAddress::GetAddrLength(addr)); } intptr_t Socket::GetPort(intptr_t fd) { ASSERT(reinterpret_cast(fd)->is_socket()); SocketHandle* socket_handle = reinterpret_cast(fd); RawAddr raw; socklen_t size = sizeof(raw); if (getsockname(socket_handle->socket(), &raw.addr, &size) == SOCKET_ERROR) { return 0; } return SocketAddress::GetAddrPort(raw); } SocketAddress* Socket::GetRemotePeer(intptr_t fd, intptr_t* port) { ASSERT(reinterpret_cast(fd)->is_socket()); SocketHandle* socket_handle = reinterpret_cast(fd); RawAddr raw; socklen_t size = sizeof(raw); if (getpeername(socket_handle->socket(), &raw.addr, &size)) { return NULL; } *port = SocketAddress::GetAddrPort(raw); // Clear the port before calling WSAAddressToString as WSAAddressToString // includes the port in the formatted string. SocketAddress::SetAddrPort(&raw, 0); return new SocketAddress(&raw.addr); } static intptr_t Create(const RawAddr& addr) { SOCKET s = socket(addr.ss.ss_family, SOCK_STREAM, 0); if (s == INVALID_SOCKET) { return -1; } linger l; l.l_onoff = 1; l.l_linger = 10; int status = setsockopt(s, SOL_SOCKET, SO_LINGER, reinterpret_cast(&l), sizeof(l)); if (status != NO_ERROR) { FATAL("Failed setting SO_LINGER on socket"); } ClientSocket* client_socket = new ClientSocket(s); return reinterpret_cast(client_socket); } static intptr_t Connect( intptr_t fd, const RawAddr& addr, const RawAddr& bind_addr) { ASSERT(reinterpret_cast(fd)->is_client_socket()); ClientSocket* handle = reinterpret_cast(fd); SOCKET s = handle->socket(); int status = bind( s, &bind_addr.addr, SocketAddress::GetAddrLength(bind_addr)); if (status != NO_ERROR) { int rc = WSAGetLastError(); handle->mark_closed(); // Destructor asserts that socket is marked closed. delete handle; closesocket(s); SetLastError(rc); return -1; } LPFN_CONNECTEX connectEx = NULL; GUID guid_connect_ex = WSAID_CONNECTEX; DWORD bytes; status = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid_connect_ex, sizeof(guid_connect_ex), &connectEx, sizeof(connectEx), &bytes, NULL, NULL); DWORD rc; if (status != SOCKET_ERROR) { handle->EnsureInitialized(EventHandler::delegate()); OverlappedBuffer* overlapped = OverlappedBuffer::AllocateConnectBuffer(); status = connectEx(s, &addr.addr, SocketAddress::GetAddrLength(addr), NULL, 0, NULL, overlapped->GetCleanOverlapped()); if (status == TRUE) { handle->ConnectComplete(overlapped); return fd; } else if (WSAGetLastError() == ERROR_IO_PENDING) { return fd; } rc = WSAGetLastError(); // Cleanup in case of error. OverlappedBuffer::DisposeBuffer(overlapped); } else { rc = WSAGetLastError(); } handle->Close(); delete handle; SetLastError(rc); return -1; } intptr_t Socket::CreateConnect(const RawAddr& addr) { intptr_t fd = Create(addr); if (fd < 0) { return fd; } RawAddr bind_addr; memset(&bind_addr, 0, sizeof(bind_addr)); bind_addr.ss.ss_family = addr.ss.ss_family; if (addr.ss.ss_family == AF_INET) { bind_addr.in.sin_addr.s_addr = INADDR_ANY; } else { bind_addr.in6.sin6_addr = in6addr_any; } return Connect(fd, addr, bind_addr); } intptr_t Socket::CreateBindConnect(const RawAddr& addr, const RawAddr& source_addr) { intptr_t fd = Create(addr); if (fd < 0) { return fd; } return Connect(fd, addr, source_addr); } bool Socket::IsBindError(intptr_t error_number) { return error_number == WSAEADDRINUSE || error_number == WSAEADDRNOTAVAIL || error_number == WSAEINVAL; } void Socket::GetError(intptr_t fd, OSError* os_error) { Handle* handle = reinterpret_cast(fd); os_error->SetCodeAndMessage(OSError::kSystem, handle->last_error()); } int Socket::GetType(intptr_t fd) { Handle* handle = reinterpret_cast(fd); switch (GetFileType(handle->handle())) { case FILE_TYPE_CHAR: return File::kTerminal; case FILE_TYPE_PIPE: return File::kPipe; case FILE_TYPE_DISK: return File::kFile; default: return GetLastError == NO_ERROR ? File::kOther : -1; } } intptr_t Socket::GetStdioHandle(intptr_t num) { if (num != 0) { return -1; } HANDLE handle = GetStdHandle(STD_INPUT_HANDLE); if (handle == INVALID_HANDLE_VALUE) { return -1; } StdHandle* std_handle = new StdHandle(handle); std_handle->MarkDoesNotSupportOverlappedIO(); std_handle->EnsureInitialized(EventHandler::delegate()); return reinterpret_cast(std_handle); } intptr_t ServerSocket::Accept(intptr_t fd) { ListenSocket* listen_socket = reinterpret_cast(fd); ClientSocket* client_socket = listen_socket->Accept(); if (client_socket != NULL) { return reinterpret_cast(client_socket); } else { return -1; } } AddressList* Socket::LookupAddress(const char* host, int type, OSError** os_error) { Initialize(); // Perform a name lookup for a host name. struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = SocketAddress::FromType(type); hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; hints.ai_protocol = IPPROTO_TCP; struct addrinfo* info = NULL; int status = getaddrinfo(host, 0, &hints, &info); if (status != 0) { // We failed, try without AI_ADDRCONFIG. This can happen when looking up // e.g. '::1', when there are no global IPv6 addresses. hints.ai_flags = 0; status = getaddrinfo(host, 0, &hints, &info); } if (status != 0) { ASSERT(*os_error == NULL); DWORD error_code = WSAGetLastError(); SetLastError(error_code); *os_error = new OSError(); return NULL; } intptr_t count = 0; for (struct addrinfo* c = info; c != NULL; c = c->ai_next) { if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) { count++; } } AddressList* addresses = new AddressList(count); intptr_t i = 0; for (struct addrinfo* c = info; c != NULL; c = c->ai_next) { if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) { addresses->SetAt(i, new SocketAddress(c->ai_addr)); i++; } } freeaddrinfo(info); return addresses; } bool Socket::ReverseLookup(const RawAddr& addr, char* host, intptr_t host_len, OSError** os_error) { ASSERT(host_len >= NI_MAXHOST); int status = getnameinfo(&addr.addr, SocketAddress::GetAddrLength(addr), host, host_len, NULL, 0, NI_NAMEREQD); if (status != 0) { ASSERT(*os_error == NULL); DWORD error_code = WSAGetLastError(); SetLastError(error_code); *os_error = new OSError(); return false; } return true; } bool Socket::ParseAddress(int type, const char* address, RawAddr* addr) { int result; const wchar_t* system_address = StringUtilsWin::Utf8ToWide(address); if (type == SocketAddress::TYPE_IPV4) { result = InetPton(AF_INET, system_address, &addr->in.sin_addr); } else { ASSERT(type == SocketAddress::TYPE_IPV6); result = InetPton(AF_INET6, system_address, &addr->in6.sin6_addr); } return result == 1; } intptr_t Socket::CreateBindDatagram(const RawAddr& addr, bool reuseAddress) { SOCKET s = socket(addr.ss.ss_family, SOCK_DGRAM, IPPROTO_UDP); if (s == INVALID_SOCKET) { return -1; } int status; if (reuseAddress) { BOOL optval = true; status = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&optval), sizeof(optval)); if (status == SOCKET_ERROR) { DWORD rc = WSAGetLastError(); closesocket(s); SetLastError(rc); return -1; } } status = bind(s, &addr.addr, SocketAddress::GetAddrLength(addr)); if (status == SOCKET_ERROR) { DWORD rc = WSAGetLastError(); closesocket(s); SetLastError(rc); return -1; } DatagramSocket* datagram_socket = new DatagramSocket(s); datagram_socket->EnsureInitialized(EventHandler::delegate()); return reinterpret_cast(datagram_socket); } bool Socket::ListInterfacesSupported() { return true; } AddressList* Socket::ListInterfaces( int type, OSError** os_error) { Initialize(); ULONG size = 0; DWORD flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER; // Query the size needed. int status = GetAdaptersAddresses(SocketAddress::FromType(type), flags, NULL, NULL, &size); IP_ADAPTER_ADDRESSES* addrs = NULL; if (status == ERROR_BUFFER_OVERFLOW) { addrs = reinterpret_cast(malloc(size)); // Get the addresses now we have the right buffer. status = GetAdaptersAddresses(SocketAddress::FromType(type), flags, NULL, addrs, &size); } if (status != NO_ERROR) { ASSERT(*os_error == NULL); DWORD error_code = WSAGetLastError(); SetLastError(error_code); *os_error = new OSError(); return NULL; } intptr_t count = 0; for (IP_ADAPTER_ADDRESSES* a = addrs; a != NULL; a = a->Next) { for (IP_ADAPTER_UNICAST_ADDRESS* u = a->FirstUnicastAddress; u != NULL; u = u->Next) { count++; } } AddressList* addresses = new AddressList(count); intptr_t i = 0; for (IP_ADAPTER_ADDRESSES* a = addrs; a != NULL; a = a->Next) { for (IP_ADAPTER_UNICAST_ADDRESS* u = a->FirstUnicastAddress; u != NULL; u = u->Next) { addresses->SetAt(i, new InterfaceSocketAddress( u->Address.lpSockaddr, StringUtilsWin::WideToUtf8(a->FriendlyName), a->Ipv6IfIndex)); i++; } } free(addrs); return addresses; } intptr_t ServerSocket::CreateBindListen(const RawAddr& addr, intptr_t backlog, bool v6_only) { SOCKET s = socket(addr.ss.ss_family, SOCK_STREAM, IPPROTO_TCP); if (s == INVALID_SOCKET) { return -1; } BOOL optval = true; int status = setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, reinterpret_cast(&optval), sizeof(optval)); if (status == SOCKET_ERROR) { DWORD rc = WSAGetLastError(); closesocket(s); SetLastError(rc); return -1; } if (addr.ss.ss_family == AF_INET6) { optval = v6_only; setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&optval), sizeof(optval)); } status = bind(s, &addr.addr, SocketAddress::GetAddrLength(addr)); if (status == SOCKET_ERROR) { DWORD rc = WSAGetLastError(); closesocket(s); SetLastError(rc); return -1; } ListenSocket* listen_socket = new ListenSocket(s); // Test for invalid socket port 65535 (some browsers disallow it). if ((SocketAddress::GetAddrPort(addr) == 0) && (Socket::GetPort(reinterpret_cast(listen_socket)) == 65535)) { // Don't close fd until we have created new. By doing that we ensure another // port. intptr_t new_s = CreateBindListen(addr, backlog, v6_only); DWORD rc = WSAGetLastError(); closesocket(s); delete listen_socket; SetLastError(rc); return new_s; } status = listen(s, backlog > 0 ? backlog : SOMAXCONN); if (status == SOCKET_ERROR) { DWORD rc = WSAGetLastError(); closesocket(s); delete listen_socket; SetLastError(rc); return -1; } return reinterpret_cast(listen_socket); } bool ServerSocket::StartAccept(intptr_t fd) { ListenSocket* listen_socket = reinterpret_cast(fd); listen_socket->EnsureInitialized(EventHandler::delegate()); // Always keep 5 outstanding accepts going, to enhance performance. for (int i = 0; i < 5; i++) { if (!listen_socket->IssueAccept()) { DWORD rc = WSAGetLastError(); listen_socket->Close(); if (!listen_socket->HasPendingAccept()) { // Delete socket now, if there are no pending accepts. Otherwise, // the event-handler will take care of deleting it. delete listen_socket; } SetLastError(rc); return false; } } return true; } void Socket::Close(intptr_t fd) { ClientSocket* client_socket = reinterpret_cast(fd); client_socket->Close(); } bool Socket::GetNoDelay(intptr_t fd, bool* enabled) { SocketHandle* handle = reinterpret_cast(fd); int on; socklen_t len = sizeof(on); int err = getsockopt(handle->socket(), IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&on), &len); if (err == 0) { *enabled = (on == 1); } return (err == 0); } bool Socket::SetNoDelay(intptr_t fd, bool enabled) { SocketHandle* handle = reinterpret_cast(fd); int on = enabled ? 1 : 0; return setsockopt(handle->socket(), IPPROTO_TCP, TCP_NODELAY, reinterpret_cast(&on), sizeof(on)) == 0; } bool Socket::GetMulticastLoop(intptr_t fd, intptr_t protocol, bool* enabled) { SocketHandle* handle = reinterpret_cast(fd); uint8_t on; socklen_t len = sizeof(on); int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_LOOP : IPV6_MULTICAST_LOOP; if (getsockopt(handle->socket(), level, optname, reinterpret_cast(&on), &len) == 0) { *enabled = (on == 1); return true; } return false; } bool Socket::SetMulticastLoop(intptr_t fd, intptr_t protocol, bool enabled) { SocketHandle* handle = reinterpret_cast(fd); int on = enabled ? 1 : 0; int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_LOOP : IPV6_MULTICAST_LOOP; return setsockopt(handle->socket(), level, optname, reinterpret_cast(&on), sizeof(on)) == 0; } bool Socket::GetMulticastHops(intptr_t fd, intptr_t protocol, int* value) { SocketHandle* handle = reinterpret_cast(fd); uint8_t v; socklen_t len = sizeof(v); int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS; if (getsockopt(handle->socket(), level, optname, reinterpret_cast(&v), &len) == 0) { *value = v; return true; } return false; } bool Socket::SetMulticastHops(intptr_t fd, intptr_t protocol, int value) { SocketHandle* handle = reinterpret_cast(fd); int v = value; int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; int optname = protocol == SocketAddress::TYPE_IPV4 ? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS; return setsockopt(handle->socket(), level, optname, reinterpret_cast(&v), sizeof(v)) == 0; } bool Socket::GetBroadcast(intptr_t fd, bool* enabled) { SocketHandle* handle = reinterpret_cast(fd); int on; socklen_t len = sizeof(on); int err = getsockopt(handle->socket(), SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&on), &len); if (err == 0) { *enabled = (on == 1); } return (err == 0); } bool Socket::SetBroadcast(intptr_t fd, bool enabled) { SocketHandle* handle = reinterpret_cast(fd); int on = enabled ? 1 : 0; return setsockopt(handle->socket(), SOL_SOCKET, SO_BROADCAST, reinterpret_cast(&on), sizeof(on)) == 0; } bool Socket::JoinMulticast( intptr_t fd, const RawAddr& addr, const RawAddr&, int interfaceIndex) { SocketHandle* handle = reinterpret_cast(fd); int proto = addr.addr.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; struct group_req mreq; mreq.gr_interface = interfaceIndex; memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr)); return setsockopt(handle->socket(), proto, MCAST_JOIN_GROUP, reinterpret_cast(&mreq), sizeof(mreq)) == 0; } bool Socket::LeaveMulticast( intptr_t fd, const RawAddr& addr, const RawAddr&, int interfaceIndex) { SocketHandle* handle = reinterpret_cast(fd); int proto = addr.addr.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; struct group_req mreq; mreq.gr_interface = interfaceIndex; memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr)); return setsockopt(handle->socket(), proto, MCAST_LEAVE_GROUP, reinterpret_cast(&mreq), sizeof(mreq)) == 0; } } // namespace bin } // namespace dart #endif // defined(TARGET_OS_WINDOWS) #endif // !defined(DART_IO_DISABLED)