blob: cfe21a3630e568a6434c663ecc8e185707550138 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Steve Anton10542f22019-01-11 17:11:0011#include "rtc_base/win32_socket_server.h"
andresp@webrtc.orgff689be2015-02-12 11:54:2612
andresp@webrtc.orgff689be2015-02-12 11:54:2613#include <ws2tcpip.h> // NOLINT
Jonas Olssona4d87372019-07-05 17:08:3314
Yves Gerey665174f2018-06-19 13:03:0515#include <algorithm>
andresp@webrtc.orgff689be2015-02-12 11:54:2616
Steve Anton10542f22019-01-11 17:11:0017#include "rtc_base/byte_order.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3118#include "rtc_base/checks.h"
19#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 17:11:0020#include "rtc_base/time_utils.h" // For Time, TimeSince
21#include "rtc_base/win32_window.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2622
23namespace rtc {
24
25///////////////////////////////////////////////////////////////////////////////
26// Win32Socket
27///////////////////////////////////////////////////////////////////////////////
28
henrike@webrtc.orgf0488722014-05-13 18:00:2629// TODO: Enable for production builds also? Use FormatMessage?
tfarinaa41ab932015-10-30 23:08:4830#if !defined(NDEBUG)
Yves Gerey665174f2018-06-19 13:03:0531LPCSTR WSAErrorToString(int error, LPCSTR* description_result) {
henrike@webrtc.orgf0488722014-05-13 18:00:2632 LPCSTR string = "Unspecified";
33 LPCSTR description = "Unspecified description";
34 switch (error) {
35 case ERROR_SUCCESS:
36 string = "SUCCESS";
37 description = "Operation succeeded";
38 break;
39 case WSAEWOULDBLOCK:
40 string = "WSAEWOULDBLOCK";
41 description = "Using a non-blocking socket, will notify later";
42 break;
43 case WSAEACCES:
44 string = "WSAEACCES";
45 description = "Access denied, or sharing violation";
46 break;
47 case WSAEADDRNOTAVAIL:
48 string = "WSAEADDRNOTAVAIL";
49 description = "Address is not valid in this context";
50 break;
51 case WSAENETDOWN:
52 string = "WSAENETDOWN";
53 description = "Network is down";
54 break;
55 case WSAENETUNREACH:
56 string = "WSAENETUNREACH";
57 description = "Network is up, but unreachable";
58 break;
59 case WSAENETRESET:
60 string = "WSANETRESET";
61 description = "Connection has been reset due to keep-alive activity";
62 break;
63 case WSAECONNABORTED:
64 string = "WSAECONNABORTED";
65 description = "Aborted by host";
66 break;
67 case WSAECONNRESET:
68 string = "WSAECONNRESET";
69 description = "Connection reset by host";
70 break;
71 case WSAETIMEDOUT:
72 string = "WSAETIMEDOUT";
73 description = "Timed out, host failed to respond";
74 break;
75 case WSAECONNREFUSED:
76 string = "WSAECONNREFUSED";
77 description = "Host actively refused connection";
78 break;
79 case WSAEHOSTDOWN:
80 string = "WSAEHOSTDOWN";
81 description = "Host is down";
82 break;
83 case WSAEHOSTUNREACH:
84 string = "WSAEHOSTUNREACH";
85 description = "Host is unreachable";
86 break;
87 case WSAHOST_NOT_FOUND:
88 string = "WSAHOST_NOT_FOUND";
89 description = "No such host is known";
90 break;
91 }
92 if (description_result) {
93 *description_result = description;
94 }
95 return string;
96}
97
98void ReportWSAError(LPCSTR context, int error, const SocketAddress& address) {
99 LPCSTR description_string;
100 LPCSTR error_string = WSAErrorToString(error, &description_string);
Mirko Bonadei675513b2017-11-09 10:09:25101 RTC_LOG(LS_INFO) << context << " = " << error << " (" << error_string << ":"
102 << description_string << ") [" << address.ToString() << "]";
henrike@webrtc.orgf0488722014-05-13 18:00:26103}
104#else
105void ReportWSAError(LPCSTR context, int error, const SocketAddress& address) {}
106#endif
107
108/////////////////////////////////////////////////////////////////////////////
109// Win32Socket::EventSink
110/////////////////////////////////////////////////////////////////////////////
111
Yves Gerey665174f2018-06-19 13:03:05112#define WM_SOCKETNOTIFY (WM_USER + 50)
113#define WM_DNSNOTIFY (WM_USER + 51)
henrike@webrtc.orgf0488722014-05-13 18:00:26114
115struct Win32Socket::DnsLookup {
116 HANDLE handle;
Peter Boström0c4e06b2015-10-07 10:23:21117 uint16_t port;
henrike@webrtc.orgf0488722014-05-13 18:00:26118 char buffer[MAXGETHOSTSTRUCT];
119};
120
121class Win32Socket::EventSink : public Win32Window {
122 public:
Yves Gerey665174f2018-06-19 13:03:05123 explicit EventSink(Win32Socket* parent) : parent_(parent) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26124
125 void Dispose();
126
Steve Anton9de3aac2017-10-24 17:08:26127 bool OnMessage(UINT uMsg,
128 WPARAM wParam,
129 LPARAM lParam,
130 LRESULT& result) override;
131 void OnNcDestroy() override;
henrike@webrtc.orgf0488722014-05-13 18:00:26132
133 private:
134 bool OnSocketNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& result);
135 bool OnDnsNotify(WPARAM wParam, LPARAM lParam, LRESULT& result);
136
Yves Gerey665174f2018-06-19 13:03:05137 Win32Socket* parent_;
henrike@webrtc.orgf0488722014-05-13 18:00:26138};
139
140void Win32Socket::EventSink::Dispose() {
deadbeef37f5ecf2017-02-27 22:06:41141 parent_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26142 if (::IsWindow(handle())) {
143 ::DestroyWindow(handle());
144 } else {
145 delete this;
146 }
147}
148
Yves Gerey665174f2018-06-19 13:03:05149bool Win32Socket::EventSink::OnMessage(UINT uMsg,
150 WPARAM wParam,
151 LPARAM lParam,
152 LRESULT& result) {
henrike@webrtc.orgf0488722014-05-13 18:00:26153 switch (uMsg) {
Yves Gerey665174f2018-06-19 13:03:05154 case WM_SOCKETNOTIFY:
155 case WM_TIMER:
156 return OnSocketNotify(uMsg, wParam, lParam, result);
157 case WM_DNSNOTIFY:
158 return OnDnsNotify(wParam, lParam, result);
henrike@webrtc.orgf0488722014-05-13 18:00:26159 }
160 return false;
161}
162
Yves Gerey665174f2018-06-19 13:03:05163bool Win32Socket::EventSink::OnSocketNotify(UINT uMsg,
164 WPARAM wParam,
165 LPARAM lParam,
166 LRESULT& result) {
henrike@webrtc.orgf0488722014-05-13 18:00:26167 result = 0;
168
169 int wsa_event = WSAGETSELECTEVENT(lParam);
170 int wsa_error = WSAGETSELECTERROR(lParam);
171
172 // Treat connect timeouts as close notifications
173 if (uMsg == WM_TIMER) {
174 wsa_event = FD_CLOSE;
175 wsa_error = WSAETIMEDOUT;
176 }
177
178 if (parent_)
179 parent_->OnSocketNotify(static_cast<SOCKET>(wParam), wsa_event, wsa_error);
180 return true;
181}
182
Yves Gerey665174f2018-06-19 13:03:05183bool Win32Socket::EventSink::OnDnsNotify(WPARAM wParam,
184 LPARAM lParam,
henrike@webrtc.orgf0488722014-05-13 18:00:26185 LRESULT& result) {
186 result = 0;
187
188 int error = WSAGETASYNCERROR(lParam);
189 if (parent_)
190 parent_->OnDnsNotify(reinterpret_cast<HANDLE>(wParam), error);
191 return true;
192}
193
194void Win32Socket::EventSink::OnNcDestroy() {
195 if (parent_) {
Mirko Bonadei675513b2017-11-09 10:09:25196 RTC_LOG(LS_ERROR) << "EventSink hwnd is being destroyed, but the event sink"
197 " hasn't yet been disposed.";
henrike@webrtc.orgf0488722014-05-13 18:00:26198 } else {
199 delete this;
200 }
201}
202
203/////////////////////////////////////////////////////////////////////////////
204// Win32Socket
205/////////////////////////////////////////////////////////////////////////////
206
207Win32Socket::Win32Socket()
deadbeef37f5ecf2017-02-27 22:06:41208 : socket_(INVALID_SOCKET),
209 error_(0),
210 state_(CS_CLOSED),
211 connect_time_(0),
212 closing_(false),
213 close_error_(0),
214 sink_(nullptr),
215 dns_(nullptr) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26216
217Win32Socket::~Win32Socket() {
218 Close();
219}
220
221bool Win32Socket::CreateT(int family, int type) {
222 Close();
223 int proto = (SOCK_DGRAM == type) ? IPPROTO_UDP : IPPROTO_TCP;
deadbeef37f5ecf2017-02-27 22:06:41224 socket_ = ::WSASocket(family, type, proto, nullptr, 0, 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26225 if (socket_ == INVALID_SOCKET) {
226 UpdateLastError();
227 return false;
228 }
229 if ((SOCK_DGRAM == type) && !SetAsync(FD_READ | FD_WRITE)) {
230 return false;
231 }
232 return true;
233}
234
235int Win32Socket::Attach(SOCKET s) {
nisseede5da42017-01-12 13:15:36236 RTC_DCHECK(socket_ == INVALID_SOCKET);
henrike@webrtc.orgf0488722014-05-13 18:00:26237 if (socket_ != INVALID_SOCKET)
238 return SOCKET_ERROR;
239
nisseede5da42017-01-12 13:15:36240 RTC_DCHECK(s != INVALID_SOCKET);
henrike@webrtc.orgf0488722014-05-13 18:00:26241 if (s == INVALID_SOCKET)
242 return SOCKET_ERROR;
243
244 socket_ = s;
245 state_ = CS_CONNECTED;
246
247 if (!SetAsync(FD_READ | FD_WRITE | FD_CLOSE))
248 return SOCKET_ERROR;
249
250 return 0;
251}
252
253void Win32Socket::SetTimeout(int ms) {
254 if (sink_)
255 ::SetTimer(sink_->handle(), 1, ms, 0);
256}
257
258SocketAddress Win32Socket::GetLocalAddress() const {
259 sockaddr_storage addr = {0};
260 socklen_t addrlen = sizeof(addr);
Yves Gerey665174f2018-06-19 13:03:05261 int result =
262 ::getsockname(socket_, reinterpret_cast<sockaddr*>(&addr), &addrlen);
henrike@webrtc.orgf0488722014-05-13 18:00:26263 SocketAddress address;
264 if (result >= 0) {
265 SocketAddressFromSockAddrStorage(addr, &address);
266 } else {
Mirko Bonadei675513b2017-11-09 10:09:25267 RTC_LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket="
268 << socket_;
henrike@webrtc.orgf0488722014-05-13 18:00:26269 }
270 return address;
271}
272
273SocketAddress Win32Socket::GetRemoteAddress() const {
274 sockaddr_storage addr = {0};
275 socklen_t addrlen = sizeof(addr);
Yves Gerey665174f2018-06-19 13:03:05276 int result =
277 ::getpeername(socket_, reinterpret_cast<sockaddr*>(&addr), &addrlen);
henrike@webrtc.orgf0488722014-05-13 18:00:26278 SocketAddress address;
279 if (result >= 0) {
280 SocketAddressFromSockAddrStorage(addr, &address);
281 } else {
Mirko Bonadei675513b2017-11-09 10:09:25282 RTC_LOG(LS_WARNING)
283 << "GetRemoteAddress: unable to get remote addr, socket=" << socket_;
henrike@webrtc.orgf0488722014-05-13 18:00:26284 }
285 return address;
286}
287
288int Win32Socket::Bind(const SocketAddress& addr) {
nisseede5da42017-01-12 13:15:36289 RTC_DCHECK(socket_ != INVALID_SOCKET);
henrike@webrtc.orgf0488722014-05-13 18:00:26290 if (socket_ == INVALID_SOCKET)
291 return SOCKET_ERROR;
292
293 sockaddr_storage saddr;
294 size_t len = addr.ToSockAddrStorage(&saddr);
Yves Gerey665174f2018-06-19 13:03:05295 int err = ::bind(socket_, reinterpret_cast<sockaddr*>(&saddr),
henrike@webrtc.orgf0488722014-05-13 18:00:26296 static_cast<int>(len));
297 UpdateLastError();
298 return err;
299}
300
301int Win32Socket::Connect(const SocketAddress& addr) {
302 if (state_ != CS_CLOSED) {
303 SetError(EALREADY);
304 return SOCKET_ERROR;
305 }
306
307 if (!addr.IsUnresolvedIP()) {
308 return DoConnect(addr);
309 }
310
Mirko Bonadei675513b2017-11-09 10:09:25311 RTC_LOG_F(LS_INFO) << "async dns lookup (" << addr.hostname() << ")";
Yves Gerey665174f2018-06-19 13:03:05312 DnsLookup* dns = new DnsLookup;
henrike@webrtc.orgf0488722014-05-13 18:00:26313 if (!sink_) {
314 // Explicitly create the sink ourselves here; we can't rely on SetAsync
315 // because we don't have a socket_ yet.
316 CreateSink();
317 }
318 // TODO: Replace with IPv6 compatible lookup.
319 dns->handle = WSAAsyncGetHostByName(sink_->handle(), WM_DNSNOTIFY,
320 addr.hostname().c_str(), dns->buffer,
321 sizeof(dns->buffer));
322
323 if (!dns->handle) {
Mirko Bonadei675513b2017-11-09 10:09:25324 RTC_LOG_F(LS_ERROR) << "WSAAsyncGetHostByName error: " << WSAGetLastError();
henrike@webrtc.orgf0488722014-05-13 18:00:26325 delete dns;
326 UpdateLastError();
327 Close();
328 return SOCKET_ERROR;
329 }
330
331 dns->port = addr.port();
332 dns_ = dns;
333 state_ = CS_CONNECTING;
334 return 0;
335}
336
337int Win32Socket::DoConnect(const SocketAddress& addr) {
338 if ((socket_ == INVALID_SOCKET) && !CreateT(addr.family(), SOCK_STREAM)) {
339 return SOCKET_ERROR;
340 }
341 if (!SetAsync(FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE)) {
342 return SOCKET_ERROR;
343 }
344
345 sockaddr_storage saddr = {0};
346 size_t len = addr.ToSockAddrStorage(&saddr);
347 connect_time_ = Time();
Yves Gerey665174f2018-06-19 13:03:05348 int result = connect(socket_, reinterpret_cast<SOCKADDR*>(&saddr),
henrike@webrtc.orgf0488722014-05-13 18:00:26349 static_cast<int>(len));
350 if (result != SOCKET_ERROR) {
351 state_ = CS_CONNECTED;
352 } else {
353 int code = WSAGetLastError();
354 if (code == WSAEWOULDBLOCK) {
355 state_ = CS_CONNECTING;
356 } else {
357 ReportWSAError("WSAAsync:connect", code, addr);
358 error_ = code;
359 Close();
360 return SOCKET_ERROR;
361 }
362 }
363 addr_ = addr;
364
365 return 0;
366}
367
368int Win32Socket::GetError() const {
369 return error_;
370}
371
372void Win32Socket::SetError(int error) {
373 error_ = error;
374}
375
376Socket::ConnState Win32Socket::GetState() const {
377 return state_;
378}
379
380int Win32Socket::GetOption(Option opt, int* value) {
381 int slevel;
382 int sopt;
383 if (TranslateOption(opt, &slevel, &sopt) == -1)
384 return -1;
385
386 char* p = reinterpret_cast<char*>(value);
387 int optlen = sizeof(value);
388 return ::getsockopt(socket_, slevel, sopt, p, &optlen);
389}
390
391int Win32Socket::SetOption(Option opt, int value) {
392 int slevel;
393 int sopt;
394 if (TranslateOption(opt, &slevel, &sopt) == -1)
395 return -1;
396
397 const char* p = reinterpret_cast<const char*>(&value);
398 return ::setsockopt(socket_, slevel, sopt, p, sizeof(value));
399}
400
401int Win32Socket::Send(const void* buffer, size_t length) {
Yves Gerey665174f2018-06-19 13:03:05402 int sent = ::send(socket_, reinterpret_cast<const char*>(buffer),
403 static_cast<int>(length), 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26404 UpdateLastError();
405 return sent;
406}
407
Yves Gerey665174f2018-06-19 13:03:05408int Win32Socket::SendTo(const void* buffer,
409 size_t length,
henrike@webrtc.orgf0488722014-05-13 18:00:26410 const SocketAddress& addr) {
411 sockaddr_storage saddr;
412 size_t addr_len = addr.ToSockAddrStorage(&saddr);
Yves Gerey665174f2018-06-19 13:03:05413 int sent = ::sendto(
414 socket_, reinterpret_cast<const char*>(buffer), static_cast<int>(length),
415 0, reinterpret_cast<sockaddr*>(&saddr), static_cast<int>(addr_len));
henrike@webrtc.orgf0488722014-05-13 18:00:26416 UpdateLastError();
417 return sent;
418}
419
Stefan Holmer9131efd2016-05-23 16:19:26420int Win32Socket::Recv(void* buffer, size_t length, int64_t* timestamp) {
421 if (timestamp) {
422 *timestamp = -1;
423 }
Yves Gerey665174f2018-06-19 13:03:05424 int received =
425 ::recv(socket_, static_cast<char*>(buffer), static_cast<int>(length), 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26426 UpdateLastError();
427 if (closing_ && received <= static_cast<int>(length))
428 PostClosed();
429 return received;
430}
431
Stefan Holmer9131efd2016-05-23 16:19:26432int Win32Socket::RecvFrom(void* buffer,
433 size_t length,
434 SocketAddress* out_addr,
435 int64_t* timestamp) {
436 if (timestamp) {
437 *timestamp = -1;
438 }
henrike@webrtc.orgf0488722014-05-13 18:00:26439 sockaddr_storage saddr;
440 socklen_t addr_len = sizeof(saddr);
Yves Gerey665174f2018-06-19 13:03:05441 int received =
442 ::recvfrom(socket_, static_cast<char*>(buffer), static_cast<int>(length),
443 0, reinterpret_cast<sockaddr*>(&saddr), &addr_len);
henrike@webrtc.orgf0488722014-05-13 18:00:26444 UpdateLastError();
445 if (received != SOCKET_ERROR)
446 SocketAddressFromSockAddrStorage(saddr, out_addr);
447 if (closing_ && received <= static_cast<int>(length))
448 PostClosed();
449 return received;
450}
451
452int Win32Socket::Listen(int backlog) {
453 int err = ::listen(socket_, backlog);
454 if (!SetAsync(FD_ACCEPT))
455 return SOCKET_ERROR;
456
457 UpdateLastError();
458 if (err == 0)
459 state_ = CS_CONNECTING;
460 return err;
461}
462
463Win32Socket* Win32Socket::Accept(SocketAddress* out_addr) {
464 sockaddr_storage saddr;
465 socklen_t addr_len = sizeof(saddr);
466 SOCKET s = ::accept(socket_, reinterpret_cast<sockaddr*>(&saddr), &addr_len);
467 UpdateLastError();
468 if (s == INVALID_SOCKET)
deadbeef37f5ecf2017-02-27 22:06:41469 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26470 if (out_addr)
471 SocketAddressFromSockAddrStorage(saddr, out_addr);
472 Win32Socket* socket = new Win32Socket;
473 if (0 == socket->Attach(s))
474 return socket;
475 delete socket;
deadbeef37f5ecf2017-02-27 22:06:41476 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26477}
478
479int Win32Socket::Close() {
480 int err = 0;
481 if (socket_ != INVALID_SOCKET) {
482 err = ::closesocket(socket_);
483 socket_ = INVALID_SOCKET;
484 closing_ = false;
485 close_error_ = 0;
486 UpdateLastError();
487 }
488 if (dns_) {
489 WSACancelAsyncRequest(dns_->handle);
490 delete dns_;
deadbeef37f5ecf2017-02-27 22:06:41491 dns_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26492 }
493 if (sink_) {
494 sink_->Dispose();
deadbeef37f5ecf2017-02-27 22:06:41495 sink_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26496 }
497 addr_.Clear();
498 state_ = CS_CLOSED;
499 return err;
500}
501
henrike@webrtc.orgf0488722014-05-13 18:00:26502void Win32Socket::CreateSink() {
deadbeef37f5ecf2017-02-27 22:06:41503 RTC_DCHECK(nullptr == sink_);
henrike@webrtc.orgf0488722014-05-13 18:00:26504
505 // Create window
506 sink_ = new EventSink(this);
deadbeef37f5ecf2017-02-27 22:06:41507 sink_->Create(nullptr, L"EventSink", 0, 0, 0, 0, 10, 10);
henrike@webrtc.orgf0488722014-05-13 18:00:26508}
509
510bool Win32Socket::SetAsync(int events) {
deadbeef37f5ecf2017-02-27 22:06:41511 if (nullptr == sink_) {
henrike@webrtc.orgf0488722014-05-13 18:00:26512 CreateSink();
deadbeef37f5ecf2017-02-27 22:06:41513 RTC_DCHECK(nullptr != sink_);
henrike@webrtc.orgf0488722014-05-13 18:00:26514 }
515
516 // start the async select
Yves Gerey665174f2018-06-19 13:03:05517 if (WSAAsyncSelect(socket_, sink_->handle(), WM_SOCKETNOTIFY, events) ==
518 SOCKET_ERROR) {
henrike@webrtc.orgf0488722014-05-13 18:00:26519 UpdateLastError();
520 Close();
521 return false;
522 }
523
524 return true;
525}
526
527bool Win32Socket::HandleClosed(int close_error) {
528 // WM_CLOSE will be received before all data has been read, so we need to
529 // hold on to it until the read buffer has been drained.
530 char ch;
531 closing_ = true;
532 close_error_ = close_error;
533 return (::recv(socket_, &ch, 1, MSG_PEEK) <= 0);
534}
535
536void Win32Socket::PostClosed() {
537 // If we see that the buffer is indeed drained, then send the close.
538 closing_ = false;
Yves Gerey665174f2018-06-19 13:03:05539 ::PostMessage(sink_->handle(), WM_SOCKETNOTIFY, socket_,
540 WSAMAKESELECTREPLY(FD_CLOSE, close_error_));
henrike@webrtc.orgf0488722014-05-13 18:00:26541}
542
543void Win32Socket::UpdateLastError() {
544 error_ = WSAGetLastError();
545}
546
547int Win32Socket::TranslateOption(Option opt, int* slevel, int* sopt) {
548 switch (opt) {
549 case OPT_DONTFRAGMENT:
550 *slevel = IPPROTO_IP;
551 *sopt = IP_DONTFRAGMENT;
552 break;
553 case OPT_RCVBUF:
554 *slevel = SOL_SOCKET;
555 *sopt = SO_RCVBUF;
556 break;
557 case OPT_SNDBUF:
558 *slevel = SOL_SOCKET;
559 *sopt = SO_SNDBUF;
560 break;
561 case OPT_NODELAY:
562 *slevel = IPPROTO_TCP;
563 *sopt = TCP_NODELAY;
564 break;
565 case OPT_DSCP:
Mirko Bonadei675513b2017-11-09 10:09:25566 RTC_LOG(LS_WARNING) << "Socket::OPT_DSCP not supported.";
henrike@webrtc.orgf0488722014-05-13 18:00:26567 return -1;
568 default:
nissec80e7412017-01-11 13:56:46569 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26570 return -1;
571 }
572 return 0;
573}
574
575void Win32Socket::OnSocketNotify(SOCKET socket, int event, int error) {
576 // Ignore events if we're already closed.
577 if (socket != socket_)
578 return;
579
580 error_ = error;
581 switch (event) {
582 case FD_CONNECT:
583 if (error != ERROR_SUCCESS) {
584 ReportWSAError("WSAAsync:connect notify", error, addr_);
tfarinaa41ab932015-10-30 23:08:48585#if !defined(NDEBUG)
Honghai Zhang82d78622016-05-06 18:29:15586 int64_t duration = TimeSince(connect_time_);
Mirko Bonadei675513b2017-11-09 10:09:25587 RTC_LOG(LS_INFO) << "WSAAsync:connect error (" << duration
588 << " ms), faking close";
henrike@webrtc.orgf0488722014-05-13 18:00:26589#endif
590 state_ = CS_CLOSED;
591 // If you get an error connecting, close doesn't really do anything
592 // and it certainly doesn't send back any close notification, but
593 // we really only maintain a few states, so it is easiest to get
594 // back into a known state by pretending that a close happened, even
595 // though the connect event never did occur.
596 SignalCloseEvent(this, error);
597 } else {
tfarinaa41ab932015-10-30 23:08:48598#if !defined(NDEBUG)
Honghai Zhang82d78622016-05-06 18:29:15599 int64_t duration = TimeSince(connect_time_);
Mirko Bonadei675513b2017-11-09 10:09:25600 RTC_LOG(LS_INFO) << "WSAAsync:connect (" << duration << " ms)";
henrike@webrtc.orgf0488722014-05-13 18:00:26601#endif
602 state_ = CS_CONNECTED;
603 SignalConnectEvent(this);
604 }
605 break;
606
607 case FD_ACCEPT:
608 case FD_READ:
609 if (error != ERROR_SUCCESS) {
610 ReportWSAError("WSAAsync:read notify", error, addr_);
611 } else {
612 SignalReadEvent(this);
613 }
614 break;
615
616 case FD_WRITE:
617 if (error != ERROR_SUCCESS) {
618 ReportWSAError("WSAAsync:write notify", error, addr_);
619 } else {
620 SignalWriteEvent(this);
621 }
622 break;
623
624 case FD_CLOSE:
625 if (HandleClosed(error)) {
626 ReportWSAError("WSAAsync:close notify", error, addr_);
627 state_ = CS_CLOSED;
628 SignalCloseEvent(this, error);
629 }
630 break;
631 }
632}
633
634void Win32Socket::OnDnsNotify(HANDLE task, int error) {
635 if (!dns_ || dns_->handle != task)
636 return;
637
Peter Boström0c4e06b2015-10-07 10:23:21638 uint32_t ip = 0;
henrike@webrtc.orgf0488722014-05-13 18:00:26639 if (error == 0) {
640 hostent* pHost = reinterpret_cast<hostent*>(dns_->buffer);
Peter Boström0c4e06b2015-10-07 10:23:21641 uint32_t net_ip = *reinterpret_cast<uint32_t*>(pHost->h_addr_list[0]);
henrike@webrtc.orgf0488722014-05-13 18:00:26642 ip = NetworkToHost32(net_ip);
643 }
644
Mirko Bonadei675513b2017-11-09 10:09:25645 RTC_LOG_F(LS_INFO) << "(" << IPAddress(ip).ToSensitiveString() << ", "
646 << error << ")";
henrike@webrtc.orgf0488722014-05-13 18:00:26647
648 if (error == 0) {
649 SocketAddress address(ip, dns_->port);
650 error = DoConnect(address);
651 } else {
652 Close();
653 }
654
655 if (error) {
656 error_ = error;
657 SignalCloseEvent(this, error_);
658 } else {
659 delete dns_;
deadbeef37f5ecf2017-02-27 22:06:41660 dns_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26661 }
662}
663
664///////////////////////////////////////////////////////////////////////////////
665// Win32SocketServer
666// Provides cricket base services on top of a win32 gui thread
667///////////////////////////////////////////////////////////////////////////////
668
669static UINT s_wm_wakeup_id = 0;
Mirko Bonadei673f7e52019-03-25 08:01:02670const wchar_t Win32SocketServer::kWindowName[] = L"libjingle Message Window";
henrike@webrtc.orgf0488722014-05-13 18:00:26671
nisse7eaa4ea2017-05-08 12:25:41672Win32SocketServer::Win32SocketServer()
Yves Gerey665174f2018-06-19 13:03:05673 : wnd_(this), posted_(false), hdlg_(nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26674 if (s_wm_wakeup_id == 0)
Mirko Bonadei673f7e52019-03-25 08:01:02675 s_wm_wakeup_id = RegisterWindowMessageW(L"WM_WAKEUP");
deadbeef37f5ecf2017-02-27 22:06:41676 if (!wnd_.Create(nullptr, kWindowName, 0, 0, 0, 0, 0, 0)) {
Mirko Bonadei675513b2017-11-09 10:09:25677 RTC_LOG_GLE(LS_ERROR) << "Failed to create message window.";
henrike@webrtc.orgf0488722014-05-13 18:00:26678 }
679}
680
681Win32SocketServer::~Win32SocketServer() {
deadbeef37f5ecf2017-02-27 22:06:41682 if (wnd_.handle() != nullptr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26683 KillTimer(wnd_.handle(), 1);
684 wnd_.Destroy();
685 }
686}
687
henrike@webrtc.orgf0488722014-05-13 18:00:26688Socket* Win32SocketServer::CreateSocket(int family, int type) {
689 return CreateAsyncSocket(family, type);
690}
691
henrike@webrtc.orgf0488722014-05-13 18:00:26692AsyncSocket* Win32SocketServer::CreateAsyncSocket(int family, int type) {
693 Win32Socket* socket = new Win32Socket;
694 if (socket->CreateT(family, type)) {
695 return socket;
696 }
697 delete socket;
deadbeef37f5ecf2017-02-27 22:06:41698 return nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26699}
700
Sebastian Jansson290de822020-01-09 13:20:23701void Win32SocketServer::SetMessageQueue(Thread* queue) {
henrike@webrtc.orgf0488722014-05-13 18:00:26702 message_queue_ = queue;
703}
704
705bool Win32SocketServer::Wait(int cms, bool process_io) {
706 BOOL b;
707 if (process_io) {
708 // Spin the Win32 message pump at least once, and as long as requested.
709 // This is the Thread::ProcessMessages case.
Peter Boström0c4e06b2015-10-07 10:23:21710 uint32_t start = Time();
henrike@webrtc.orgf0488722014-05-13 18:00:26711 do {
712 MSG msg;
deadbeef37f5ecf2017-02-27 22:06:41713 SetTimer(wnd_.handle(), 0, cms, nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26714 // Get the next available message. If we have a modeless dialog, give
715 // give the message to IsDialogMessage, which will return true if it
716 // was a message for the dialog that it handled internally.
717 // Otherwise, dispatch as usual via Translate/DispatchMessage.
deadbeef37f5ecf2017-02-27 22:06:41718 b = GetMessage(&msg, nullptr, 0, 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26719 if (b == -1) {
Mirko Bonadei675513b2017-11-09 10:09:25720 RTC_LOG_GLE(LS_ERROR) << "GetMessage failed.";
henrike@webrtc.orgf0488722014-05-13 18:00:26721 return false;
Yves Gerey665174f2018-06-19 13:03:05722 } else if (b) {
henrike@webrtc.orgf0488722014-05-13 18:00:26723 if (!hdlg_ || !IsDialogMessage(hdlg_, &msg)) {
724 TranslateMessage(&msg);
725 DispatchMessage(&msg);
726 }
727 }
728 KillTimer(wnd_.handle(), 0);
729 } while (b && TimeSince(start) < cms);
730 } else if (cms != 0) {
731 // Sit and wait forever for a WakeUp. This is the Thread::Send case.
nisseede5da42017-01-12 13:15:36732 RTC_DCHECK(cms == -1);
henrike@webrtc.orgf0488722014-05-13 18:00:26733 MSG msg;
deadbeef37f5ecf2017-02-27 22:06:41734 b = GetMessage(&msg, nullptr, s_wm_wakeup_id, s_wm_wakeup_id);
henrike@webrtc.orgf0488722014-05-13 18:00:26735 {
Markus Handell18523c32020-07-08 15:55:58736 webrtc::MutexLock lock(&mutex_);
henrike@webrtc.orgf0488722014-05-13 18:00:26737 posted_ = false;
738 }
739 } else {
740 // No-op (cms == 0 && !process_io). This is the Pump case.
741 b = TRUE;
742 }
743 return (b != FALSE);
744}
745
746void Win32SocketServer::WakeUp() {
747 if (wnd_.handle()) {
748 // Set the "message pending" flag, if not already set.
749 {
Markus Handell18523c32020-07-08 15:55:58750 webrtc::MutexLock lock(&mutex_);
henrike@webrtc.orgf0488722014-05-13 18:00:26751 if (posted_)
752 return;
753 posted_ = true;
754 }
755
756 PostMessage(wnd_.handle(), s_wm_wakeup_id, 0, 0);
757 }
758}
759
760void Win32SocketServer::Pump() {
761 // Clear the "message pending" flag.
762 {
Markus Handell18523c32020-07-08 15:55:58763 webrtc::MutexLock lock(&mutex_);
henrike@webrtc.orgf0488722014-05-13 18:00:26764 posted_ = false;
765 }
766
767 // Dispatch all the messages that are currently in our queue. If new messages
768 // are posted during the dispatch, they will be handled in the next Pump.
769 // We use max(1, ...) to make sure we try to dispatch at least once, since
770 // this allow us to process "sent" messages, not included in the size() count.
771 Message msg;
andresp@webrtc.orgff689be2015-02-12 11:54:26772 for (size_t max_messages_to_process =
773 std::max<size_t>(1, message_queue_->size());
henrike@webrtc.orgf0488722014-05-13 18:00:26774 max_messages_to_process > 0 && message_queue_->Get(&msg, 0, false);
775 --max_messages_to_process) {
776 message_queue_->Dispatch(&msg);
777 }
778
779 // Anything remaining?
780 int delay = message_queue_->GetDelay();
781 if (delay == -1) {
782 KillTimer(wnd_.handle(), 1);
783 } else {
deadbeef37f5ecf2017-02-27 22:06:41784 SetTimer(wnd_.handle(), 1, delay, nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26785 }
786}
787
Yves Gerey665174f2018-06-19 13:03:05788bool Win32SocketServer::MessageWindow::OnMessage(UINT wm,
789 WPARAM wp,
790 LPARAM lp,
791 LRESULT& lr) {
henrike@webrtc.orgf0488722014-05-13 18:00:26792 bool handled = false;
793 if (wm == s_wm_wakeup_id || (wm == WM_TIMER && wp == 1)) {
794 ss_->Pump();
795 lr = 0;
796 handled = true;
797 }
798 return handled;
799}
800
Steve Anton9de3aac2017-10-24 17:08:26801Win32Thread::Win32Thread(SocketServer* ss) : Thread(ss), id_(0) {}
802
803Win32Thread::~Win32Thread() {
804 Stop();
805}
806
807void Win32Thread::Run() {
808 id_ = GetCurrentThreadId();
809 Thread::Run();
810 id_ = 0;
811}
812
813void Win32Thread::Quit() {
814 PostThreadMessage(id_, WM_QUIT, 0, 0);
815}
816
henrike@webrtc.orgf0488722014-05-13 18:00:26817} // namespace rtc