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