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 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
     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 
    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
    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:
    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 
    180 void Win32Socket::EventSink::Dispose() {
    181   parent_ = NULL;
    182   if (::IsWindow(handle())) {
    183     ::DestroyWindow(handle());
    184   } else {
    185     delete this;
    186   }
    187 }
    188 
    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 
    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 
    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 
    229 void Win32Socket::EventSink::OnFinalMessage(HWND hWnd) {
    230   delete this;
    231 }
    232 
    233 /////////////////////////////////////////////////////////////////////////////
    234 // Win32Socket
    235 /////////////////////////////////////////////////////////////////////////////
    236 
    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 
    242 Win32Socket::~Win32Socket() {
    243   Close();
    244 }
    245 
    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 
    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 
    278 void Win32Socket::SetTimeout(int ms) {
    279   if (sink_)
    280     ::SetTimer(sink_->handle(), 1, ms, 0);
    281 }
    282 
    283 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 
    299 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 
    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 
    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 
    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 
    383 int Win32Socket::GetError() const {
    384   return error_;
    385 }
    386 
    387 void Win32Socket::SetError(int error) {
    388   error_ = error;
    389 }
    390 
    391 Socket::ConnState Win32Socket::GetState() const {
    392   return state_;
    393 }
    394 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    568 void Win32Socket::UpdateLastError() {
    569   error_ = WSAGetLastError();
    570 }
    571 
    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 
    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 
    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 
    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 
    703 Win32SocketServer::~Win32SocketServer() {
    704   if (wnd_.handle() != NULL) {
    705     KillTimer(wnd_.handle(), 1);
    706     wnd_.Destroy();
    707   }
    708 }
    709 
    710 Socket* Win32SocketServer::CreateSocket(int type) {
    711   return CreateAsyncSocket(type);
    712 }
    713 
    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 
    723 void Win32SocketServer::SetMessageQueue(MessageQueue* queue) {
    724   message_queue_ = queue;
    725 }
    726 
    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 
    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 
    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 
    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