• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
11 #include "webrtc/base/win32socketserver.h"
12 
13 #include <algorithm>
14 #include <ws2tcpip.h>  // NOLINT
15 
16 #include "webrtc/base/byteorder.h"
17 #include "webrtc/base/common.h"
18 #include "webrtc/base/logging.h"
19 #include "webrtc/base/win32window.h"
20 #include "webrtc/base/winping.h"
21 
22 namespace rtc {
23 
24 ///////////////////////////////////////////////////////////////////////////////
25 // Win32Socket
26 ///////////////////////////////////////////////////////////////////////////////
27 
28 // TODO: Move this to a common place where PhysicalSocketServer can
29 // share it.
30 // Standard MTUs
31 static const uint16_t PACKET_MAXIMUMS[] = {
32     65535,  // Theoretical maximum, Hyperchannel
33     32000,  // Nothing
34     17914,  // 16Mb IBM Token Ring
35     8166,   // IEEE 802.4
36     // 4464   // IEEE 802.5 (4Mb max)
37     4352,   // FDDI
38     // 2048,  // Wideband Network
39     2002,   // IEEE 802.5 (4Mb recommended)
40     // 1536,  // Expermental Ethernet Networks
41     // 1500,  // Ethernet, Point-to-Point (default)
42     1492,   // IEEE 802.3
43     1006,   // SLIP, ARPANET
44     // 576,   // X.25 Networks
45     // 544,   // DEC IP Portal
46     // 512,   // NETBIOS
47     508,    // IEEE 802/Source-Rt Bridge, ARCNET
48     296,    // Point-to-Point (low delay)
49     68,     // Official minimum
50     0,      // End of list marker
51 };
52 
53 static const int IP_HEADER_SIZE = 20u;
54 static const int ICMP_HEADER_SIZE = 8u;
55 static const int ICMP_PING_TIMEOUT_MILLIS = 10000u;
56 
57 // TODO: Enable for production builds also? Use FormatMessage?
58 #if !defined(NDEBUG)
WSAErrorToString(int error,LPCSTR * description_result)59 LPCSTR WSAErrorToString(int error, LPCSTR *description_result) {
60   LPCSTR string = "Unspecified";
61   LPCSTR description = "Unspecified description";
62   switch (error) {
63     case ERROR_SUCCESS:
64       string = "SUCCESS";
65       description = "Operation succeeded";
66       break;
67     case WSAEWOULDBLOCK:
68       string = "WSAEWOULDBLOCK";
69       description = "Using a non-blocking socket, will notify later";
70       break;
71     case WSAEACCES:
72       string = "WSAEACCES";
73       description = "Access denied, or sharing violation";
74       break;
75     case WSAEADDRNOTAVAIL:
76       string = "WSAEADDRNOTAVAIL";
77       description = "Address is not valid in this context";
78       break;
79     case WSAENETDOWN:
80       string = "WSAENETDOWN";
81       description = "Network is down";
82       break;
83     case WSAENETUNREACH:
84       string = "WSAENETUNREACH";
85       description = "Network is up, but unreachable";
86       break;
87     case WSAENETRESET:
88       string = "WSANETRESET";
89       description = "Connection has been reset due to keep-alive activity";
90       break;
91     case WSAECONNABORTED:
92       string = "WSAECONNABORTED";
93       description = "Aborted by host";
94       break;
95     case WSAECONNRESET:
96       string = "WSAECONNRESET";
97       description = "Connection reset by host";
98       break;
99     case WSAETIMEDOUT:
100       string = "WSAETIMEDOUT";
101       description = "Timed out, host failed to respond";
102       break;
103     case WSAECONNREFUSED:
104       string = "WSAECONNREFUSED";
105       description = "Host actively refused connection";
106       break;
107     case WSAEHOSTDOWN:
108       string = "WSAEHOSTDOWN";
109       description = "Host is down";
110       break;
111     case WSAEHOSTUNREACH:
112       string = "WSAEHOSTUNREACH";
113       description = "Host is unreachable";
114       break;
115     case WSAHOST_NOT_FOUND:
116       string = "WSAHOST_NOT_FOUND";
117       description = "No such host is known";
118       break;
119   }
120   if (description_result) {
121     *description_result = description;
122   }
123   return string;
124 }
125 
ReportWSAError(LPCSTR context,int error,const SocketAddress & address)126 void ReportWSAError(LPCSTR context, int error, const SocketAddress& address) {
127   LPCSTR description_string;
128   LPCSTR error_string = WSAErrorToString(error, &description_string);
129   LOG(LS_INFO) << context << " = " << error
130     << " (" << error_string << ":" << description_string << ") ["
131     << address.ToString() << "]";
132 }
133 #else
ReportWSAError(LPCSTR context,int error,const SocketAddress & address)134 void ReportWSAError(LPCSTR context, int error, const SocketAddress& address) {}
135 #endif
136 
137 /////////////////////////////////////////////////////////////////////////////
138 // Win32Socket::EventSink
139 /////////////////////////////////////////////////////////////////////////////
140 
141 #define WM_SOCKETNOTIFY  (WM_USER + 50)
142 #define WM_DNSNOTIFY     (WM_USER + 51)
143 
144 struct Win32Socket::DnsLookup {
145   HANDLE handle;
146   uint16_t port;
147   char buffer[MAXGETHOSTSTRUCT];
148 };
149 
150 class Win32Socket::EventSink : public Win32Window {
151  public:
EventSink(Win32Socket * parent)152   explicit EventSink(Win32Socket * parent) : parent_(parent) { }
153 
154   void Dispose();
155 
156   virtual bool OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam,
157                          LRESULT& result);
158   virtual void OnNcDestroy();
159 
160  private:
161   bool OnSocketNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& result);
162   bool OnDnsNotify(WPARAM wParam, LPARAM lParam, LRESULT& result);
163 
164   Win32Socket * parent_;
165 };
166 
Dispose()167 void Win32Socket::EventSink::Dispose() {
168   parent_ = NULL;
169   if (::IsWindow(handle())) {
170     ::DestroyWindow(handle());
171   } else {
172     delete this;
173   }
174 }
175 
OnMessage(UINT uMsg,WPARAM wParam,LPARAM lParam,LRESULT & result)176 bool Win32Socket::EventSink::OnMessage(UINT uMsg, WPARAM wParam,
177                                        LPARAM lParam, LRESULT& result) {
178   switch (uMsg) {
179   case WM_SOCKETNOTIFY:
180   case WM_TIMER:
181     return OnSocketNotify(uMsg, wParam, lParam, result);
182   case WM_DNSNOTIFY:
183     return OnDnsNotify(wParam, lParam, result);
184   }
185   return false;
186 }
187 
OnSocketNotify(UINT uMsg,WPARAM wParam,LPARAM lParam,LRESULT & result)188 bool Win32Socket::EventSink::OnSocketNotify(UINT uMsg, WPARAM wParam,
189                                             LPARAM lParam, LRESULT& result) {
190   result = 0;
191 
192   int wsa_event = WSAGETSELECTEVENT(lParam);
193   int wsa_error = WSAGETSELECTERROR(lParam);
194 
195   // Treat connect timeouts as close notifications
196   if (uMsg == WM_TIMER) {
197     wsa_event = FD_CLOSE;
198     wsa_error = WSAETIMEDOUT;
199   }
200 
201   if (parent_)
202     parent_->OnSocketNotify(static_cast<SOCKET>(wParam), wsa_event, wsa_error);
203   return true;
204 }
205 
OnDnsNotify(WPARAM wParam,LPARAM lParam,LRESULT & result)206 bool Win32Socket::EventSink::OnDnsNotify(WPARAM wParam, LPARAM lParam,
207                                          LRESULT& result) {
208   result = 0;
209 
210   int error = WSAGETASYNCERROR(lParam);
211   if (parent_)
212     parent_->OnDnsNotify(reinterpret_cast<HANDLE>(wParam), error);
213   return true;
214 }
215 
OnNcDestroy()216 void Win32Socket::EventSink::OnNcDestroy() {
217   if (parent_) {
218     LOG(LS_ERROR) << "EventSink hwnd is being destroyed, but the event sink"
219                      " hasn't yet been disposed.";
220   } else {
221     delete this;
222   }
223 }
224 
225 /////////////////////////////////////////////////////////////////////////////
226 // Win32Socket
227 /////////////////////////////////////////////////////////////////////////////
228 
Win32Socket()229 Win32Socket::Win32Socket()
230     : socket_(INVALID_SOCKET), error_(0), state_(CS_CLOSED), connect_time_(0),
231       closing_(false), close_error_(0), sink_(NULL), dns_(NULL) {
232 }
233 
~Win32Socket()234 Win32Socket::~Win32Socket() {
235   Close();
236 }
237 
CreateT(int family,int type)238 bool Win32Socket::CreateT(int family, int type) {
239   Close();
240   int proto = (SOCK_DGRAM == type) ? IPPROTO_UDP : IPPROTO_TCP;
241   socket_ = ::WSASocket(family, type, proto, NULL, NULL, 0);
242   if (socket_ == INVALID_SOCKET) {
243     UpdateLastError();
244     return false;
245   }
246   if ((SOCK_DGRAM == type) && !SetAsync(FD_READ | FD_WRITE)) {
247     return false;
248   }
249   return true;
250 }
251 
Attach(SOCKET s)252 int Win32Socket::Attach(SOCKET s) {
253   ASSERT(socket_ == INVALID_SOCKET);
254   if (socket_ != INVALID_SOCKET)
255     return SOCKET_ERROR;
256 
257   ASSERT(s != INVALID_SOCKET);
258   if (s == INVALID_SOCKET)
259     return SOCKET_ERROR;
260 
261   socket_ = s;
262   state_ = CS_CONNECTED;
263 
264   if (!SetAsync(FD_READ | FD_WRITE | FD_CLOSE))
265     return SOCKET_ERROR;
266 
267   return 0;
268 }
269 
SetTimeout(int ms)270 void Win32Socket::SetTimeout(int ms) {
271   if (sink_)
272     ::SetTimer(sink_->handle(), 1, ms, 0);
273 }
274 
GetLocalAddress() const275 SocketAddress Win32Socket::GetLocalAddress() const {
276   sockaddr_storage addr = {0};
277   socklen_t addrlen = sizeof(addr);
278   int result = ::getsockname(socket_, reinterpret_cast<sockaddr*>(&addr),
279                              &addrlen);
280   SocketAddress address;
281   if (result >= 0) {
282     SocketAddressFromSockAddrStorage(addr, &address);
283   } else {
284     LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket="
285                     << socket_;
286   }
287   return address;
288 }
289 
GetRemoteAddress() const290 SocketAddress Win32Socket::GetRemoteAddress() const {
291   sockaddr_storage addr = {0};
292   socklen_t addrlen = sizeof(addr);
293   int result = ::getpeername(socket_, reinterpret_cast<sockaddr*>(&addr),
294                              &addrlen);
295   SocketAddress address;
296   if (result >= 0) {
297     SocketAddressFromSockAddrStorage(addr, &address);
298   } else {
299     LOG(LS_WARNING) << "GetRemoteAddress: unable to get remote addr, socket="
300                     << socket_;
301   }
302   return address;
303 }
304 
Bind(const SocketAddress & addr)305 int Win32Socket::Bind(const SocketAddress& addr) {
306   ASSERT(socket_ != INVALID_SOCKET);
307   if (socket_ == INVALID_SOCKET)
308     return SOCKET_ERROR;
309 
310   sockaddr_storage saddr;
311   size_t len = addr.ToSockAddrStorage(&saddr);
312   int err = ::bind(socket_,
313                    reinterpret_cast<sockaddr*>(&saddr),
314                    static_cast<int>(len));
315   UpdateLastError();
316   return err;
317 }
318 
Connect(const SocketAddress & addr)319 int Win32Socket::Connect(const SocketAddress& addr) {
320   if (state_ != CS_CLOSED) {
321     SetError(EALREADY);
322     return SOCKET_ERROR;
323   }
324 
325   if (!addr.IsUnresolvedIP()) {
326     return DoConnect(addr);
327   }
328 
329   LOG_F(LS_INFO) << "async dns lookup (" << addr.hostname() << ")";
330   DnsLookup * dns = new DnsLookup;
331   if (!sink_) {
332     // Explicitly create the sink ourselves here; we can't rely on SetAsync
333     // because we don't have a socket_ yet.
334     CreateSink();
335   }
336   // TODO: Replace with IPv6 compatible lookup.
337   dns->handle = WSAAsyncGetHostByName(sink_->handle(), WM_DNSNOTIFY,
338                                       addr.hostname().c_str(), dns->buffer,
339                                       sizeof(dns->buffer));
340 
341   if (!dns->handle) {
342     LOG_F(LS_ERROR) << "WSAAsyncGetHostByName error: " << WSAGetLastError();
343     delete dns;
344     UpdateLastError();
345     Close();
346     return SOCKET_ERROR;
347   }
348 
349   dns->port = addr.port();
350   dns_ = dns;
351   state_ = CS_CONNECTING;
352   return 0;
353 }
354 
DoConnect(const SocketAddress & addr)355 int Win32Socket::DoConnect(const SocketAddress& addr) {
356   if ((socket_ == INVALID_SOCKET) && !CreateT(addr.family(), SOCK_STREAM)) {
357     return SOCKET_ERROR;
358   }
359   if (!SetAsync(FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE)) {
360     return SOCKET_ERROR;
361   }
362 
363   sockaddr_storage saddr = {0};
364   size_t len = addr.ToSockAddrStorage(&saddr);
365   connect_time_ = Time();
366   int result = connect(socket_,
367                        reinterpret_cast<SOCKADDR*>(&saddr),
368                        static_cast<int>(len));
369   if (result != SOCKET_ERROR) {
370     state_ = CS_CONNECTED;
371   } else {
372     int code = WSAGetLastError();
373     if (code == WSAEWOULDBLOCK) {
374       state_ = CS_CONNECTING;
375     } else {
376       ReportWSAError("WSAAsync:connect", code, addr);
377       error_ = code;
378       Close();
379       return SOCKET_ERROR;
380     }
381   }
382   addr_ = addr;
383 
384   return 0;
385 }
386 
GetError() const387 int Win32Socket::GetError() const {
388   return error_;
389 }
390 
SetError(int error)391 void Win32Socket::SetError(int error) {
392   error_ = error;
393 }
394 
GetState() const395 Socket::ConnState Win32Socket::GetState() const {
396   return state_;
397 }
398 
GetOption(Option opt,int * value)399 int Win32Socket::GetOption(Option opt, int* value) {
400   int slevel;
401   int sopt;
402   if (TranslateOption(opt, &slevel, &sopt) == -1)
403     return -1;
404 
405   char* p = reinterpret_cast<char*>(value);
406   int optlen = sizeof(value);
407   return ::getsockopt(socket_, slevel, sopt, p, &optlen);
408 }
409 
SetOption(Option opt,int value)410 int Win32Socket::SetOption(Option opt, int value) {
411   int slevel;
412   int sopt;
413   if (TranslateOption(opt, &slevel, &sopt) == -1)
414     return -1;
415 
416   const char* p = reinterpret_cast<const char*>(&value);
417   return ::setsockopt(socket_, slevel, sopt, p, sizeof(value));
418 }
419 
Send(const void * buffer,size_t length)420 int Win32Socket::Send(const void* buffer, size_t length) {
421   int sent = ::send(socket_,
422                     reinterpret_cast<const char*>(buffer),
423                     static_cast<int>(length),
424                     0);
425   UpdateLastError();
426   return sent;
427 }
428 
SendTo(const void * buffer,size_t length,const SocketAddress & addr)429 int Win32Socket::SendTo(const void* buffer, size_t length,
430                         const SocketAddress& addr) {
431   sockaddr_storage saddr;
432   size_t addr_len = addr.ToSockAddrStorage(&saddr);
433   int sent = ::sendto(socket_, reinterpret_cast<const char*>(buffer),
434                       static_cast<int>(length), 0,
435                       reinterpret_cast<sockaddr*>(&saddr),
436                       static_cast<int>(addr_len));
437   UpdateLastError();
438   return sent;
439 }
440 
Recv(void * buffer,size_t length)441 int Win32Socket::Recv(void* buffer, size_t length) {
442   int received = ::recv(socket_, static_cast<char*>(buffer),
443                         static_cast<int>(length), 0);
444   UpdateLastError();
445   if (closing_ && received <= static_cast<int>(length))
446     PostClosed();
447   return received;
448 }
449 
RecvFrom(void * buffer,size_t length,SocketAddress * out_addr)450 int Win32Socket::RecvFrom(void* buffer, size_t length,
451                           SocketAddress* out_addr) {
452   sockaddr_storage saddr;
453   socklen_t addr_len = sizeof(saddr);
454   int received = ::recvfrom(socket_, static_cast<char*>(buffer),
455                             static_cast<int>(length), 0,
456                             reinterpret_cast<sockaddr*>(&saddr), &addr_len);
457   UpdateLastError();
458   if (received != SOCKET_ERROR)
459     SocketAddressFromSockAddrStorage(saddr, out_addr);
460   if (closing_ && received <= static_cast<int>(length))
461     PostClosed();
462   return received;
463 }
464 
Listen(int backlog)465 int Win32Socket::Listen(int backlog) {
466   int err = ::listen(socket_, backlog);
467   if (!SetAsync(FD_ACCEPT))
468     return SOCKET_ERROR;
469 
470   UpdateLastError();
471   if (err == 0)
472     state_ = CS_CONNECTING;
473   return err;
474 }
475 
Accept(SocketAddress * out_addr)476 Win32Socket* Win32Socket::Accept(SocketAddress* out_addr) {
477   sockaddr_storage saddr;
478   socklen_t addr_len = sizeof(saddr);
479   SOCKET s = ::accept(socket_, reinterpret_cast<sockaddr*>(&saddr), &addr_len);
480   UpdateLastError();
481   if (s == INVALID_SOCKET)
482     return NULL;
483   if (out_addr)
484     SocketAddressFromSockAddrStorage(saddr, out_addr);
485   Win32Socket* socket = new Win32Socket;
486   if (0 == socket->Attach(s))
487     return socket;
488   delete socket;
489   return NULL;
490 }
491 
Close()492 int Win32Socket::Close() {
493   int err = 0;
494   if (socket_ != INVALID_SOCKET) {
495     err = ::closesocket(socket_);
496     socket_ = INVALID_SOCKET;
497     closing_ = false;
498     close_error_ = 0;
499     UpdateLastError();
500   }
501   if (dns_) {
502     WSACancelAsyncRequest(dns_->handle);
503     delete dns_;
504     dns_ = NULL;
505   }
506   if (sink_) {
507     sink_->Dispose();
508     sink_ = NULL;
509   }
510   addr_.Clear();
511   state_ = CS_CLOSED;
512   return err;
513 }
514 
EstimateMTU(uint16_t * mtu)515 int Win32Socket::EstimateMTU(uint16_t* mtu) {
516   SocketAddress addr = GetRemoteAddress();
517   if (addr.IsAnyIP()) {
518     error_ = ENOTCONN;
519     return -1;
520   }
521 
522   WinPing ping;
523   if (!ping.IsValid()) {
524     error_ = EINVAL;  // can't think of a better error ID
525     return -1;
526   }
527 
528   for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) {
529     int32_t size = PACKET_MAXIMUMS[level] - IP_HEADER_SIZE - ICMP_HEADER_SIZE;
530     WinPing::PingResult result = ping.Ping(addr.ipaddr(), size,
531                                            ICMP_PING_TIMEOUT_MILLIS, 1, false);
532     if (result == WinPing::PING_FAIL) {
533       error_ = EINVAL;  // can't think of a better error ID
534       return -1;
535     }
536     if (result != WinPing::PING_TOO_LARGE) {
537       *mtu = PACKET_MAXIMUMS[level];
538       return 0;
539     }
540   }
541 
542   ASSERT(false);
543   return 0;
544 }
545 
CreateSink()546 void Win32Socket::CreateSink() {
547   ASSERT(NULL == sink_);
548 
549   // Create window
550   sink_ = new EventSink(this);
551   sink_->Create(NULL, L"EventSink", 0, 0, 0, 0, 10, 10);
552 }
553 
SetAsync(int events)554 bool Win32Socket::SetAsync(int events) {
555   if (NULL == sink_) {
556     CreateSink();
557     ASSERT(NULL != sink_);
558   }
559 
560   // start the async select
561   if (WSAAsyncSelect(socket_, sink_->handle(), WM_SOCKETNOTIFY, events)
562       == SOCKET_ERROR) {
563     UpdateLastError();
564     Close();
565     return false;
566   }
567 
568   return true;
569 }
570 
HandleClosed(int close_error)571 bool Win32Socket::HandleClosed(int close_error) {
572   // WM_CLOSE will be received before all data has been read, so we need to
573   // hold on to it until the read buffer has been drained.
574   char ch;
575   closing_ = true;
576   close_error_ = close_error;
577   return (::recv(socket_, &ch, 1, MSG_PEEK) <= 0);
578 }
579 
PostClosed()580 void Win32Socket::PostClosed() {
581   // If we see that the buffer is indeed drained, then send the close.
582   closing_ = false;
583   ::PostMessage(sink_->handle(), WM_SOCKETNOTIFY,
584                 socket_, WSAMAKESELECTREPLY(FD_CLOSE, close_error_));
585 }
586 
UpdateLastError()587 void Win32Socket::UpdateLastError() {
588   error_ = WSAGetLastError();
589 }
590 
TranslateOption(Option opt,int * slevel,int * sopt)591 int Win32Socket::TranslateOption(Option opt, int* slevel, int* sopt) {
592   switch (opt) {
593     case OPT_DONTFRAGMENT:
594       *slevel = IPPROTO_IP;
595       *sopt = IP_DONTFRAGMENT;
596       break;
597     case OPT_RCVBUF:
598       *slevel = SOL_SOCKET;
599       *sopt = SO_RCVBUF;
600       break;
601     case OPT_SNDBUF:
602       *slevel = SOL_SOCKET;
603       *sopt = SO_SNDBUF;
604       break;
605     case OPT_NODELAY:
606       *slevel = IPPROTO_TCP;
607       *sopt = TCP_NODELAY;
608       break;
609     case OPT_DSCP:
610       LOG(LS_WARNING) << "Socket::OPT_DSCP not supported.";
611       return -1;
612     default:
613       ASSERT(false);
614       return -1;
615   }
616   return 0;
617 }
618 
OnSocketNotify(SOCKET socket,int event,int error)619 void Win32Socket::OnSocketNotify(SOCKET socket, int event, int error) {
620   // Ignore events if we're already closed.
621   if (socket != socket_)
622     return;
623 
624   error_ = error;
625   switch (event) {
626     case FD_CONNECT:
627       if (error != ERROR_SUCCESS) {
628         ReportWSAError("WSAAsync:connect notify", error, addr_);
629 #if !defined(NDEBUG)
630         int32_t duration = TimeSince(connect_time_);
631         LOG(LS_INFO) << "WSAAsync:connect error (" << duration
632                      << " ms), faking close";
633 #endif
634         state_ = CS_CLOSED;
635         // If you get an error connecting, close doesn't really do anything
636         // and it certainly doesn't send back any close notification, but
637         // we really only maintain a few states, so it is easiest to get
638         // back into a known state by pretending that a close happened, even
639         // though the connect event never did occur.
640         SignalCloseEvent(this, error);
641       } else {
642 #if !defined(NDEBUG)
643         int32_t duration = TimeSince(connect_time_);
644         LOG(LS_INFO) << "WSAAsync:connect (" << duration << " ms)";
645 #endif
646         state_ = CS_CONNECTED;
647         SignalConnectEvent(this);
648       }
649       break;
650 
651     case FD_ACCEPT:
652     case FD_READ:
653       if (error != ERROR_SUCCESS) {
654         ReportWSAError("WSAAsync:read notify", error, addr_);
655       } else {
656         SignalReadEvent(this);
657       }
658       break;
659 
660     case FD_WRITE:
661       if (error != ERROR_SUCCESS) {
662         ReportWSAError("WSAAsync:write notify", error, addr_);
663       } else {
664         SignalWriteEvent(this);
665       }
666       break;
667 
668     case FD_CLOSE:
669       if (HandleClosed(error)) {
670         ReportWSAError("WSAAsync:close notify", error, addr_);
671         state_ = CS_CLOSED;
672         SignalCloseEvent(this, error);
673       }
674       break;
675   }
676 }
677 
OnDnsNotify(HANDLE task,int error)678 void Win32Socket::OnDnsNotify(HANDLE task, int error) {
679   if (!dns_ || dns_->handle != task)
680     return;
681 
682   uint32_t ip = 0;
683   if (error == 0) {
684     hostent* pHost = reinterpret_cast<hostent*>(dns_->buffer);
685     uint32_t net_ip = *reinterpret_cast<uint32_t*>(pHost->h_addr_list[0]);
686     ip = NetworkToHost32(net_ip);
687   }
688 
689   LOG_F(LS_INFO) << "(" << IPAddress(ip).ToSensitiveString()
690                  << ", " << error << ")";
691 
692   if (error == 0) {
693     SocketAddress address(ip, dns_->port);
694     error = DoConnect(address);
695   } else {
696     Close();
697   }
698 
699   if (error) {
700     error_ = error;
701     SignalCloseEvent(this, error_);
702   } else {
703     delete dns_;
704     dns_ = NULL;
705   }
706 }
707 
708 ///////////////////////////////////////////////////////////////////////////////
709 // Win32SocketServer
710 // Provides cricket base services on top of a win32 gui thread
711 ///////////////////////////////////////////////////////////////////////////////
712 
713 static UINT s_wm_wakeup_id = 0;
714 const TCHAR Win32SocketServer::kWindowName[] = L"libjingle Message Window";
715 
Win32SocketServer(MessageQueue * message_queue)716 Win32SocketServer::Win32SocketServer(MessageQueue* message_queue)
717     : message_queue_(message_queue),
718       wnd_(this),
719       posted_(false),
720       hdlg_(NULL) {
721   if (s_wm_wakeup_id == 0)
722     s_wm_wakeup_id = RegisterWindowMessage(L"WM_WAKEUP");
723   if (!wnd_.Create(NULL, kWindowName, 0, 0, 0, 0, 0, 0)) {
724     LOG_GLE(LS_ERROR) << "Failed to create message window.";
725   }
726 }
727 
~Win32SocketServer()728 Win32SocketServer::~Win32SocketServer() {
729   if (wnd_.handle() != NULL) {
730     KillTimer(wnd_.handle(), 1);
731     wnd_.Destroy();
732   }
733 }
734 
CreateSocket(int type)735 Socket* Win32SocketServer::CreateSocket(int type) {
736   return CreateSocket(AF_INET, type);
737 }
738 
CreateSocket(int family,int type)739 Socket* Win32SocketServer::CreateSocket(int family, int type) {
740   return CreateAsyncSocket(family, type);
741 }
742 
CreateAsyncSocket(int type)743 AsyncSocket* Win32SocketServer::CreateAsyncSocket(int type) {
744   return CreateAsyncSocket(AF_INET, type);
745 }
746 
CreateAsyncSocket(int family,int type)747 AsyncSocket* Win32SocketServer::CreateAsyncSocket(int family, int type) {
748   Win32Socket* socket = new Win32Socket;
749   if (socket->CreateT(family, type)) {
750     return socket;
751   }
752   delete socket;
753   return NULL;
754 }
755 
SetMessageQueue(MessageQueue * queue)756 void Win32SocketServer::SetMessageQueue(MessageQueue* queue) {
757   message_queue_ = queue;
758 }
759 
Wait(int cms,bool process_io)760 bool Win32SocketServer::Wait(int cms, bool process_io) {
761   BOOL b;
762   if (process_io) {
763     // Spin the Win32 message pump at least once, and as long as requested.
764     // This is the Thread::ProcessMessages case.
765     uint32_t start = Time();
766     do {
767       MSG msg;
768       SetTimer(wnd_.handle(), 0, cms, NULL);
769       // Get the next available message. If we have a modeless dialog, give
770       // give the message to IsDialogMessage, which will return true if it
771       // was a message for the dialog that it handled internally.
772       // Otherwise, dispatch as usual via Translate/DispatchMessage.
773       b = GetMessage(&msg, NULL, 0, 0);
774       if (b == -1) {
775         LOG_GLE(LS_ERROR) << "GetMessage failed.";
776         return false;
777       } else if(b) {
778         if (!hdlg_ || !IsDialogMessage(hdlg_, &msg)) {
779           TranslateMessage(&msg);
780           DispatchMessage(&msg);
781         }
782       }
783       KillTimer(wnd_.handle(), 0);
784     } while (b && TimeSince(start) < cms);
785   } else if (cms != 0) {
786     // Sit and wait forever for a WakeUp. This is the Thread::Send case.
787     ASSERT(cms == -1);
788     MSG msg;
789     b = GetMessage(&msg, NULL, s_wm_wakeup_id, s_wm_wakeup_id);
790     {
791       CritScope scope(&cs_);
792       posted_ = false;
793     }
794   } else {
795     // No-op (cms == 0 && !process_io). This is the Pump case.
796     b = TRUE;
797   }
798   return (b != FALSE);
799 }
800 
WakeUp()801 void Win32SocketServer::WakeUp() {
802   if (wnd_.handle()) {
803     // Set the "message pending" flag, if not already set.
804     {
805       CritScope scope(&cs_);
806       if (posted_)
807         return;
808       posted_ = true;
809     }
810 
811     PostMessage(wnd_.handle(), s_wm_wakeup_id, 0, 0);
812   }
813 }
814 
Pump()815 void Win32SocketServer::Pump() {
816   // Clear the "message pending" flag.
817   {
818     CritScope scope(&cs_);
819     posted_ = false;
820   }
821 
822   // Dispatch all the messages that are currently in our queue. If new messages
823   // are posted during the dispatch, they will be handled in the next Pump.
824   // We use max(1, ...) to make sure we try to dispatch at least once, since
825   // this allow us to process "sent" messages, not included in the size() count.
826   Message msg;
827   for (size_t max_messages_to_process =
828            std::max<size_t>(1, message_queue_->size());
829        max_messages_to_process > 0 && message_queue_->Get(&msg, 0, false);
830        --max_messages_to_process) {
831     message_queue_->Dispatch(&msg);
832   }
833 
834   // Anything remaining?
835   int delay = message_queue_->GetDelay();
836   if (delay == -1) {
837     KillTimer(wnd_.handle(), 1);
838   } else {
839     SetTimer(wnd_.handle(), 1, delay, NULL);
840   }
841 }
842 
OnMessage(UINT wm,WPARAM wp,LPARAM lp,LRESULT & lr)843 bool Win32SocketServer::MessageWindow::OnMessage(UINT wm, WPARAM wp,
844                                                  LPARAM lp, LRESULT& lr) {
845   bool handled = false;
846   if (wm == s_wm_wakeup_id || (wm == WM_TIMER && wp == 1)) {
847     ss_->Pump();
848     lr = 0;
849     handled = true;
850   }
851   return handled;
852 }
853 
854 }  // namespace rtc
855