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/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 | |
19 | namespace dart { |
20 | namespace bin { |
21 | |
22 | Socket::Socket(intptr_t fd) |
23 | : ReferenceCounted(), |
24 | fd_(fd), |
25 | isolate_port_(Dart_GetMainPortId()), |
26 | port_(ILLEGAL_PORT), |
27 | udp_receive_buffer_(NULL) { |
28 | ASSERT(fd_ != kClosedFd); |
29 | Handle* handle = reinterpret_cast<Handle*>(fd_); |
30 | ASSERT(handle != NULL); |
31 | } |
32 | |
33 | void Socket::CloseFd() { |
34 | ASSERT(fd_ != kClosedFd); |
35 | Handle* handle = reinterpret_cast<Handle*>(fd_); |
36 | ASSERT(handle != NULL); |
37 | handle->Release(); |
38 | SetClosedFd(); |
39 | } |
40 | |
41 | void Socket::SetClosedFd() { |
42 | fd_ = kClosedFd; |
43 | } |
44 | |
45 | static 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 | |
64 | static 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); |
78 | SetLastError(rc); |
79 | return -1; |
80 | } |
81 | |
82 | LPFN_CONNECTEX connectEx = NULL; |
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, NULL, NULL); |
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), NULL, |
95 | 0, NULL, 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(); |
112 | SetLastError(rc); |
113 | return -1; |
114 | } |
115 | |
116 | intptr_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 | |
134 | intptr_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 | |
141 | intptr_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 | |
151 | intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr, |
152 | const RawAddr& source_addr) { |
153 | SetLastError(ERROR_NOT_SUPPORTED); |
154 | return -1; |
155 | } |
156 | |
157 | intptr_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 != NULL) { |
161 | return reinterpret_cast<intptr_t>(client_socket); |
162 | } else { |
163 | return -1; |
164 | } |
165 | } |
166 | |
167 | intptr_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); |
184 | SetLastError(rc); |
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); |
208 | SetLastError(rc); |
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); |
216 | SetLastError(rc); |
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 | |
226 | intptr_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); |
241 | SetLastError(rc); |
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); |
255 | SetLastError(rc); |
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(); |
271 | SetLastError(rc); |
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(); |
280 | SetLastError(rc); |
281 | return -1; |
282 | } |
283 | |
284 | return reinterpret_cast<intptr_t>(listen_socket); |
285 | } |
286 | |
287 | intptr_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 | |
295 | bool 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 | } |
308 | SetLastError(rc); |
309 | return false; |
310 | } |
311 | } |
312 | return true; |
313 | } |
314 | |
315 | } // namespace bin |
316 | } // namespace dart |
317 | |
318 | #endif // defined(HOST_OS_WINDOWS) |
319 | |