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