Flutter Engine
The Flutter Engine
socket_win.cc
Go to the documentation of this file.
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(DART_HOST_OS_WINDOWS)
7
8#include "bin/builtin.h"
9#include "bin/eventhandler.h"
10#include "bin/file.h"
11#include "bin/lockers.h"
12#include "bin/socket.h"
13#include "bin/socket_base_win.h"
14#include "bin/thread.h"
15#include "bin/utils.h"
16#include "bin/utils_win.h"
17#include "platform/syslog.h"
18
19namespace dart {
20namespace bin {
21
22Socket::Socket(intptr_t fd)
23 : ReferenceCounted(),
24 fd_(fd),
25 isolate_port_(Dart_GetMainPortId()),
26 port_(ILLEGAL_PORT),
27 udp_receive_buffer_(nullptr) {
28 ASSERT(fd_ != kClosedFd);
29 Handle* handle = reinterpret_cast<Handle*>(fd_);
30 ASSERT(handle != nullptr);
31}
32
33void Socket::CloseFd() {
34 ASSERT(fd_ != kClosedFd);
35 Handle* handle = reinterpret_cast<Handle*>(fd_);
36 ASSERT(handle != nullptr);
37 handle->Release();
38 SetClosedFd();
39}
40
41void Socket::SetClosedFd() {
42 fd_ = kClosedFd;
43}
44
45static intptr_t Create(const RawAddr& addr) {
46 SOCKET s = socket(addr.ss.ss_family, SOCK_STREAM, 0);
47 if (s == INVALID_SOCKET) {
48 return -1;
49 }
50
51 linger l;
52 l.l_onoff = 1;
53 l.l_linger = 10;
54 int status = setsockopt(s, SOL_SOCKET, SO_LINGER, reinterpret_cast<char*>(&l),
55 sizeof(l));
56 if (status != NO_ERROR) {
57 FATAL("Failed setting SO_LINGER on socket");
58 }
59
60 ClientSocket* client_socket = new ClientSocket(s);
61 return reinterpret_cast<intptr_t>(client_socket);
62}
63
64static intptr_t Connect(intptr_t fd,
65 const RawAddr& addr,
66 const RawAddr& bind_addr) {
67 ASSERT(reinterpret_cast<Handle*>(fd)->is_client_socket());
68 ClientSocket* handle = reinterpret_cast<ClientSocket*>(fd);
69 SOCKET s = handle->socket();
70
71 int status =
72 bind(s, &bind_addr.addr, SocketAddress::GetAddrLength(bind_addr));
73 if (status != NO_ERROR) {
74 int rc = WSAGetLastError();
75 handle->mark_closed(); // Destructor asserts that socket is marked closed.
76 handle->Release();
77 closesocket(s);
79 return -1;
80 }
81
82 LPFN_CONNECTEX connectEx = nullptr;
83 GUID guid_connect_ex = WSAID_CONNECTEX;
84 DWORD bytes;
85 status = WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid_connect_ex,
86 sizeof(guid_connect_ex), &connectEx, sizeof(connectEx),
87 &bytes, nullptr, nullptr);
88 DWORD rc;
89 if (status != SOCKET_ERROR) {
90 handle->EnsureInitialized(EventHandler::delegate());
91
92 OverlappedBuffer* overlapped = OverlappedBuffer::AllocateConnectBuffer();
93
94 status = connectEx(s, &addr.addr, SocketAddress::GetAddrLength(addr),
95 nullptr, 0, nullptr, overlapped->GetCleanOverlapped());
96
97 if (status == TRUE) {
98 handle->ConnectComplete(overlapped);
99 return fd;
100 } else if (WSAGetLastError() == ERROR_IO_PENDING) {
101 return fd;
102 }
103 rc = WSAGetLastError();
104 // Cleanup in case of error.
105 OverlappedBuffer::DisposeBuffer(overlapped);
106 handle->Release();
107 } else {
108 rc = WSAGetLastError();
109 }
110 handle->Close();
111 handle->Release();
113 return -1;
114}
115
116intptr_t Socket::CreateConnect(const RawAddr& addr) {
117 intptr_t fd = Create(addr);
118 if (fd < 0) {
119 return fd;
120 }
121
122 RawAddr bind_addr;
123 memset(&bind_addr, 0, sizeof(bind_addr));
124 bind_addr.ss.ss_family = addr.ss.ss_family;
125 if (addr.ss.ss_family == AF_INET) {
126 bind_addr.in.sin_addr.s_addr = INADDR_ANY;
127 } else {
128 bind_addr.in6.sin6_addr = in6addr_any;
129 }
130
131 return Connect(fd, addr, bind_addr);
132}
133
134intptr_t Socket::CreateUnixDomainConnect(const RawAddr& addr) {
135 // TODO(21403): Support unix domain socket on Windows
136 // https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
137 SetLastError(ERROR_NOT_SUPPORTED);
138 return -1;
139}
140
141intptr_t Socket::CreateBindConnect(const RawAddr& addr,
142 const RawAddr& source_addr) {
143 intptr_t fd = Create(addr);
144 if (fd < 0) {
145 return fd;
146 }
147
148 return Connect(fd, addr, source_addr);
149}
150
151intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr,
152 const RawAddr& source_addr) {
153 SetLastError(ERROR_NOT_SUPPORTED);
154 return -1;
155}
156
157intptr_t ServerSocket::Accept(intptr_t fd) {
158 ListenSocket* listen_socket = reinterpret_cast<ListenSocket*>(fd);
159 ClientSocket* client_socket = listen_socket->Accept();
160 if (client_socket != nullptr) {
161 return reinterpret_cast<intptr_t>(client_socket);
162 } else {
163 return -1;
164 }
165}
166
167intptr_t Socket::CreateBindDatagram(const RawAddr& addr,
168 bool reuseAddress,
169 bool reusePort,
170 int ttl) {
171 SOCKET s = socket(addr.ss.ss_family, SOCK_DGRAM, IPPROTO_UDP);
172 if (s == INVALID_SOCKET) {
173 return -1;
174 }
175
176 int status;
177 if (reuseAddress) {
178 BOOL optval = true;
179 status = setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
180 reinterpret_cast<const char*>(&optval), sizeof(optval));
181 if (status == SOCKET_ERROR) {
182 DWORD rc = WSAGetLastError();
183 closesocket(s);
185 return -1;
186 }
187 }
188
189 if (reusePort) {
190 // ignore reusePort - not supported on this platform.
191 Syslog::PrintErr(
192 "Dart Socket ERROR: %s:%d: `reusePort` not supported for "
193 "Windows.",
194 __FILE__, __LINE__);
195 }
196
197 // Can't use SocketBase::SetMulticastHops here - we'd need to create
198 // the DatagramSocket object and reinterpret_cast it here, just for that
199 // method to reinterpret_cast it again.
200 int ttlValue = ttl;
201 int ttlLevel = addr.addr.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
202 int ttlOptname =
203 addr.addr.sa_family == AF_INET ? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS;
204 if (setsockopt(s, ttlLevel, ttlOptname, reinterpret_cast<char*>(&ttlValue),
205 sizeof(ttlValue)) != 0) {
206 DWORD rc = WSAGetLastError();
207 closesocket(s);
209 return -1;
210 }
211
212 status = bind(s, &addr.addr, SocketAddress::GetAddrLength(addr));
213 if (status == SOCKET_ERROR) {
214 DWORD rc = WSAGetLastError();
215 closesocket(s);
217 return -1;
218 }
219
220 DatagramSocket* datagram_socket = new DatagramSocket(s);
221 datagram_socket->EnsureInitialized(EventHandler::delegate());
222
223 return reinterpret_cast<intptr_t>(datagram_socket);
224}
225
226intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
227 intptr_t backlog,
228 bool v6_only) {
229 SOCKET s = socket(addr.ss.ss_family, SOCK_STREAM, IPPROTO_TCP);
230 if (s == INVALID_SOCKET) {
231 return -1;
232 }
233
234 BOOL optval = true;
235 int status =
236 setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
237 reinterpret_cast<const char*>(&optval), sizeof(optval));
238 if (status == SOCKET_ERROR) {
239 DWORD rc = WSAGetLastError();
240 closesocket(s);
242 return -1;
243 }
244
245 if (addr.ss.ss_family == AF_INET6) {
246 optval = v6_only;
247 setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
248 reinterpret_cast<const char*>(&optval), sizeof(optval));
249 }
250
251 status = bind(s, &addr.addr, SocketAddress::GetAddrLength(addr));
252 if (status == SOCKET_ERROR) {
253 DWORD rc = WSAGetLastError();
254 closesocket(s);
256 return -1;
257 }
258
259 ListenSocket* listen_socket = new ListenSocket(s);
260
261 // Test for invalid socket port 65535 (some browsers disallow it).
262 if ((SocketAddress::GetAddrPort(addr) == 0) &&
263 (SocketBase::GetPort(reinterpret_cast<intptr_t>(listen_socket)) ==
264 65535)) {
265 // Don't close fd until we have created new. By doing that we ensure another
266 // port.
267 intptr_t new_s = CreateBindListen(addr, backlog, v6_only);
268 DWORD rc = WSAGetLastError();
269 closesocket(s);
270 listen_socket->Release();
272 return new_s;
273 }
274
275 status = listen(s, backlog > 0 ? backlog : SOMAXCONN);
276 if (status == SOCKET_ERROR) {
277 DWORD rc = WSAGetLastError();
278 closesocket(s);
279 listen_socket->Release();
281 return -1;
282 }
283
284 return reinterpret_cast<intptr_t>(listen_socket);
285}
286
287intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
288 intptr_t backlog) {
289 // TODO(21403): Support unix domain socket on Windows
290 // https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
291 SetLastError(ERROR_NOT_SUPPORTED);
292 return -1;
293}
294
295bool ServerSocket::StartAccept(intptr_t fd) {
296 ListenSocket* listen_socket = reinterpret_cast<ListenSocket*>(fd);
297 listen_socket->EnsureInitialized(EventHandler::delegate());
298 // Always keep 5 outstanding accepts going, to enhance performance.
299 for (int i = 0; i < 5; i++) {
300 if (!listen_socket->IssueAccept()) {
301 DWORD rc = WSAGetLastError();
302 listen_socket->Close();
303 if (!listen_socket->HasPendingAccept()) {
304 // Delete socket now, if there are no pending accepts. Otherwise,
305 // the event-handler will take care of deleting it.
306 listen_socket->Release();
307 }
309 return false;
310 }
311 }
312 return true;
313}
314
315} // namespace bin
316} // namespace dart
317
318#endif // defined(DART_HOST_OS_WINDOWS)
static sk_sp< Effect > Create()
Definition: RefCntTest.cpp:117
Socket(intptr_t fd)
#define ILLEGAL_PORT
Definition: dart_api.h:1535
#define ASSERT(E)
struct MyStruct s
#define FATAL(error)
Definition: dart_vm.cc:33
DART_EXPORT Dart_Port Dart_GetMainPortId()
int BOOL
Definition: windows_types.h:37
WINBASEAPI VOID WINAPI SetLastError(_In_ DWORD dwErrCode)
unsigned long DWORD
Definition: windows_types.h:22
struct _GUID GUID