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
36namespace 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
45static 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
67static const uint32 IP_HEADER_SIZE = 20;
68static const uint32 ICMP_HEADER_SIZE = 8;
69
70// TODO: Enable for production builds also? Use FormatMessage?
71#ifdef _DEBUG
72LPCSTR 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
139void 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
147void 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
157struct Win32Socket::DnsLookup {
158  HANDLE handle;
159  uint16 port;
160  char buffer[MAXGETHOSTSTRUCT];
161};
162
163class Win32Socket::EventSink : public Win32Window {
164 public:
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
180void Win32Socket::EventSink::Dispose() {
181  parent_ = NULL;
182  if (::IsWindow(handle())) {
183    ::DestroyWindow(handle());
184  } else {
185    delete this;
186  }
187}
188
189bool 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
201bool 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
219bool 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
229void Win32Socket::EventSink::OnFinalMessage(HWND hWnd) {
230  delete this;
231}
232
233/////////////////////////////////////////////////////////////////////////////
234// Win32Socket
235/////////////////////////////////////////////////////////////////////////////
236
237Win32Socket::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
242Win32Socket::~Win32Socket() {
243  Close();
244}
245
246bool 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
260int 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
278void Win32Socket::SetTimeout(int ms) {
279  if (sink_)
280    ::SetTimer(sink_->handle(), 1, ms, 0);
281}
282
283SocketAddress 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
299SocketAddress 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
316int 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
328int 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
359int 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
383int Win32Socket::GetError() const {
384  return error_;
385}
386
387void Win32Socket::SetError(int error) {
388  error_ = error;
389}
390
391Socket::ConnState Win32Socket::GetState() const {
392  return state_;
393}
394
395int 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
406int 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
416int 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
422int 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
432int 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
440int 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
454int 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
465Win32Socket* 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
481int 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
504int 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
534bool 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
552bool 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
561void 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
568void Win32Socket::UpdateLastError() {
569  error_ = WSAGetLastError();
570}
571
572int 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
597void 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
656void 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
691static UINT s_wm_wakeup_id = 0;
692const TCHAR Win32SocketServer::kWindowName[] = L"libjingle Message Window";
693
694Win32SocketServer::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
703Win32SocketServer::~Win32SocketServer() {
704  if (wnd_.handle() != NULL) {
705    KillTimer(wnd_.handle(), 1);
706    wnd_.Destroy();
707  }
708}
709
710Socket* Win32SocketServer::CreateSocket(int type) {
711  return CreateAsyncSocket(type);
712}
713
714AsyncSocket* 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
723void Win32SocketServer::SetMessageQueue(MessageQueue* queue) {
724  message_queue_ = queue;
725}
726
727bool 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
759void 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
773void 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
800bool 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