text: /*
   *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
   *
   *  Use of this source code is governed by a BSD-style license
   *  that can be found in the LICENSE file in the root of the source
   *  tree. An additional intellectual property rights grant can be found
   *  in the file PATENTS.  All contributing project authors may
   *  be found in the AUTHORS file in the root of the source tree.
   */
  
  #include BOSS_WEBRTC_U_rtc_base__win32socketserver_h //original-code:"rtc_base/win32socketserver.h"
  
  #include <algorithm>
  #include BOSS_FAKEWIN_V_ws2tcpip_h //original-code:<ws2tcpip.h>  // NOLINT
  
  #include BOSS_WEBRTC_U_rtc_base__byteorder_h //original-code:"rtc_base/byteorder.h"
  #include BOSS_WEBRTC_U_rtc_base__checks_h //original-code:"rtc_base/checks.h"
  #include BOSS_WEBRTC_U_rtc_base__logging_h //original-code:"rtc_base/logging.h"
  #include BOSS_WEBRTC_U_rtc_base__win32window_h //original-code:"rtc_base/win32window.h"
  
  namespace rtc {
  
  ///////////////////////////////////////////////////////////////////////////////
  // Win32Socket
  ///////////////////////////////////////////////////////////////////////////////
  
  // TODO: Move this to a common place where PhysicalSocketServer can
  // share it.
  // Standard MTUs
  static const uint16_t PACKET_MAXIMUMS[] = {
      65535,  // Theoretical maximum, Hyperchannel
      32000,  // Nothing
      17914,  // 16Mb IBM Token Ring
      8166,   // IEEE 802.4
      // 4464   // IEEE 802.5 (4Mb max)
      4352,   // FDDI
      // 2048,  // Wideband Network
      2002,   // IEEE 802.5 (4Mb recommended)
      // 1536,  // Expermental Ethernet Networks
      // 1500,  // Ethernet, Point-to-Point (default)
      1492,   // IEEE 802.3
      1006,   // SLIP, ARPANET
      // 576,   // X.25 Networks
      // 544,   // DEC IP Portal
      // 512,   // NETBIOS
      508,    // IEEE 802/Source-Rt Bridge, ARCNET
      296,    // Point-to-Point (low delay)
      68,     // Official minimum
      0,      // End of list marker
  };
  
  static const int IP_HEADER_SIZE = 20u;
  static const int ICMP_HEADER_SIZE = 8u;
  static const int ICMP_PING_TIMEOUT_MILLIS = 10000u;
  
  // TODO: Enable for production builds also? Use FormatMessage?
  #if !defined(NDEBUG)
  LPCSTR WSAErrorToString(int error, LPCSTR *description_result) {
    LPCSTR string = "Unspecified";
    LPCSTR description = "Unspecified description";
    switch (error) {
      case ERROR_SUCCESS:
        string = "SUCCESS";
        description = "Operation succeeded";
        break;
      case WSAEWOULDBLOCK:
        string = "WSAEWOULDBLOCK";
        description = "Using a non-blocking socket, will notify later";
        break;
      case WSAEACCES:
        string = "WSAEACCES";
        description = "Access denied, or sharing violation";
        break;
      case WSAEADDRNOTAVAIL:
        string = "WSAEADDRNOTAVAIL";
        description = "Address is not valid in this context";
        break;
      case WSAENETDOWN:
        string = "WSAENETDOWN";
        description = "Network is down";
        break;
      case WSAENETUNREACH:
        string = "WSAENETUNREACH";
        description = "Network is up, but unreachable";
        break;
      case WSAENETRESET:
        string = "WSANETRESET";
        description = "Connection has been reset due to keep-alive activity";
        break;
      case WSAECONNABORTED:
        string = "WSAECONNABORTED";
        description = "Aborted by host";
        break;
      case WSAECONNRESET:
        string = "WSAECONNRESET";
        description = "Connection reset by host";
        break;
      case WSAETIMEDOUT:
        string = "WSAETIMEDOUT";
        description = "Timed out, host failed to respond";
        break;
      case WSAECONNREFUSED:
        string = "WSAECONNREFUSED";
        description = "Host actively refused connection";
        break;
      case WSAEHOSTDOWN:
        string = "WSAEHOSTDOWN";
        description = "Host is down";
        break;
      case WSAEHOSTUNREACH:
        string = "WSAEHOSTUNREACH";
        description = "Host is unreachable";
        break;
      case WSAHOST_NOT_FOUND:
        string = "WSAHOST_NOT_FOUND";
        description = "No such host is known";
        break;
    }
    if (description_result) {
      *description_result = description;
    }
    return string;
  }
  
  void ReportWSAError(LPCSTR context, int error, const SocketAddress& address) {
    LPCSTR description_string;
    LPCSTR error_string = WSAErrorToString(error, &description_string);
    RTC_LOG(LS_INFO) << context << " = " << error << " (" << error_string << ":"
                     << description_string << ") [" << address.ToString() << "]";
  }
  #else
  void ReportWSAError(LPCSTR context, int error, const SocketAddress& address) {}
  #endif
  
  /////////////////////////////////////////////////////////////////////////////
  // Win32Socket::EventSink
  /////////////////////////////////////////////////////////////////////////////
  
  #define WM_SOCKETNOTIFY  (WM_USER + 50)
  #define WM_DNSNOTIFY     (WM_USER + 51)
  
  struct Win32Socket::DnsLookup {
    HANDLE handle;
    uint16_t port;
    char buffer[MAXGETHOSTSTRUCT];
  };
  
  class Win32Socket::EventSink : public Win32Window {
   public:
    explicit EventSink(Win32Socket * parent) : parent_(parent) { }
  
    void Dispose();
  
    bool OnMessage(UINT uMsg,
                   WPARAM wParam,
                   LPARAM lParam,
                   LRESULT& result) override;
    void OnNcDestroy() override;
  
   private:
    bool OnSocketNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& result);
    bool OnDnsNotify(WPARAM wParam, LPARAM lParam, LRESULT& result);
  
    Win32Socket * parent_;
  };
  
  void Win32Socket::EventSink::Dispose() {
    parent_ = nullptr;
    if (::IsWindow(handle())) {
      ::DestroyWindow(handle());
    } else {
      delete this;
    }
  }
  
  bool Win32Socket::EventSink::OnMessage(UINT uMsg, WPARAM wParam,
                                         LPARAM lParam, LRESULT& result) {
    switch (uMsg) {
    case WM_SOCKETNOTIFY:
    case WM_TIMER:
      return OnSocketNotify(uMsg, wParam, lParam, result);
    case WM_DNSNOTIFY:
      return OnDnsNotify(wParam, lParam, result);
    }
    return false;
  }
  
  bool Win32Socket::EventSink::OnSocketNotify(UINT uMsg, WPARAM wParam,
                                              LPARAM lParam, LRESULT& result) {
    result = 0;
  
    int wsa_event = WSAGETSELECTEVENT(lParam);
    int wsa_error = WSAGETSELECTERROR(lParam);
  
    // Treat connect timeouts as close notifications
    if (uMsg == WM_TIMER) {
      wsa_event = FD_CLOSE;
      wsa_error = WSAETIMEDOUT;
    }
  
    if (parent_)
      parent_->OnSocketNotify(static_cast<SOCKET>(wParam), wsa_event, wsa_error);
    return true;
  }
  
  bool Win32Socket::EventSink::OnDnsNotify(WPARAM wParam, LPARAM lParam,
                                           LRESULT& result) {
    result = 0;
  
    int error = WSAGETASYNCERROR(lParam);
    if (parent_)
      parent_->OnDnsNotify(reinterpret_cast<HANDLE>(wParam), error);
    return true;
  }
  
  void Win32Socket::EventSink::OnNcDestroy() {
    if (parent_) {
      RTC_LOG(LS_ERROR) << "EventSink hwnd is being destroyed, but the event sink"
                           " hasn't yet been disposed.";
    } else {
      delete this;
    }
  }
  
  /////////////////////////////////////////////////////////////////////////////
  // Win32Socket
  /////////////////////////////////////////////////////////////////////////////
  
  Win32Socket::Win32Socket()
      : socket_(INVALID_SOCKET),
        error_(0),
        state_(CS_CLOSED),
        connect_time_(0),
        closing_(false),
        close_error_(0),
        sink_(nullptr),
        dns_(nullptr) {}
  
  Win32Socket::~Win32Socket() {
    Close();
  }
  
  bool Win32Socket::CreateT(int family, int type) {
    Close();
    int proto = (SOCK_DGRAM == type) ? IPPROTO_UDP : IPPROTO_TCP;
    socket_ = ::WSASocket(family, type, proto, nullptr, 0, 0);
    if (socket_ == INVALID_SOCKET) {
      UpdateLastError();
      return false;
    }
    if ((SOCK_DGRAM == type) && !SetAsync(FD_READ | FD_WRITE)) {
      return false;
    }
    return true;
  }
  
  int Win32Socket::Attach(SOCKET s) {
    RTC_DCHECK(socket_ == INVALID_SOCKET);
    if (socket_ != INVALID_SOCKET)
      return SOCKET_ERROR;
  
    RTC_DCHECK(s != INVALID_SOCKET);
    if (s == INVALID_SOCKET)
      return SOCKET_ERROR;
  
    socket_ = s;
    state_ = CS_CONNECTED;
  
    if (!SetAsync(FD_READ | FD_WRITE | FD_CLOSE))
      return SOCKET_ERROR;
  
    return 0;
  }
  
  void Win32Socket::SetTimeout(int ms) {
    if (sink_)
      ::SetTimer(sink_->handle(), 1, ms, 0);
  }
  
  SocketAddress Win32Socket::GetLocalAddress() const {
    sockaddr_storage addr = {0};
    socklen_t addrlen = sizeof(addr);
    int result = ::getsockname(socket_, reinterpret_cast<sockaddr*>(&addr),
                               &addrlen);
    SocketAddress address;
    if (result >= 0) {
      SocketAddressFromSockAddrStorage(addr, &address);
    } else {
      RTC_LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket="
                          << socket_;
    }
    return address;
  }
  
  SocketAddress Win32Socket::GetRemoteAddress() const {
    sockaddr_storage addr = {0};
    socklen_t addrlen = sizeof(addr);
    int result = ::getpeername(socket_, reinterpret_cast<sockaddr*>(&addr),
                               &addrlen);
    SocketAddress address;
    if (result >= 0) {
      SocketAddressFromSockAddrStorage(addr, &address);
    } else {
      RTC_LOG(LS_WARNING)
          << "GetRemoteAddress: unable to get remote addr, socket=" << socket_;
    }
    return address;
  }
  
  int Win32Socket::Bind(const SocketAddress& addr) {
    RTC_DCHECK(socket_ != INVALID_SOCKET);
    if (socket_ == INVALID_SOCKET)
      return SOCKET_ERROR;
  
    sockaddr_storage saddr;
    size_t len = addr.ToSockAddrStorage(&saddr);
    int err = ::bind(socket_,
                     reinterpret_cast<sockaddr*>(&saddr),
                     static_cast<int>(len));
    UpdateLastError();
    return err;
  }
  
  int Win32Socket::Connect(const SocketAddress& addr) {
    if (state_ != CS_CLOSED) {
      SetError(EALREADY);
      return SOCKET_ERROR;
    }
  
    if (!addr.IsUnresolvedIP()) {
      return DoConnect(addr);
    }
  
    RTC_LOG_F(LS_INFO) << "async dns lookup (" << addr.hostname() << ")";
    DnsLookup * dns = new DnsLookup;
    if (!sink_) {
      // Explicitly create the sink ourselves here; we can't rely on SetAsync
      // because we don't have a socket_ yet.
      CreateSink();
    }
    // TODO: Replace with IPv6 compatible lookup.
    dns->handle = WSAAsyncGetHostByName(sink_->handle(), WM_DNSNOTIFY,
                                        addr.hostname().c_str(), dns->buffer,
                                        sizeof(dns->buffer));
  
    if (!dns->handle) {
      RTC_LOG_F(LS_ERROR) << "WSAAsyncGetHostByName error: " << WSAGetLastError();
      delete dns;
      UpdateLastError();
      Close();
      return SOCKET_ERROR;
    }
  
    dns->port = addr.port();
    dns_ = dns;
    state_ = CS_CONNECTING;
    return 0;
  }
  
  int Win32Socket::DoConnect(const SocketAddress& addr) {
    if ((socket_ == INVALID_SOCKET) && !CreateT(addr.family(), SOCK_STREAM)) {
      return SOCKET_ERROR;
    }
    if (!SetAsync(FD_READ | FD_WRITE | FD_CONNECT | FD_CLOSE)) {
      return SOCKET_ERROR;
    }
  
    sockaddr_storage saddr = {0};
    size_t len = addr.ToSockAddrStorage(&saddr);
    connect_time_ = Time();
    int result = connect(socket_,
                         reinterpret_cast<SOCKADDR*>(&saddr),
                         static_cast<int>(len));
    if (result != SOCKET_ERROR) {
      state_ = CS_CONNECTED;
    } else {
      int code = WSAGetLastError();
      if (code == WSAEWOULDBLOCK) {
        state_ = CS_CONNECTING;
      } else {
        ReportWSAError("WSAAsync:connect", code, addr);
        error_ = code;
        Close();
        return SOCKET_ERROR;
      }
    }
    addr_ = addr;
  
    return 0;
  }
  
  int Win32Socket::GetError() const {
    return error_;
  }
  
  void Win32Socket::SetError(int error) {
    error_ = error;
  }
  
  Socket::ConnState Win32Socket::GetState() const {
    return state_;
  }
  
  int Win32Socket::GetOption(Option opt, int* value) {
    int slevel;
    int sopt;
    if (TranslateOption(opt, &slevel, &sopt) == -1)
      return -1;
  
    char* p = reinterpret_cast<char*>(value);
    int optlen = sizeof(value);
    return ::getsockopt(socket_, slevel, sopt, p, &optlen);
  }
  
  int Win32Socket::SetOption(Option opt, int value) {
    int slevel;
    int sopt;
    if (TranslateOption(opt, &slevel, &sopt) == -1)
      return -1;
  
    const char* p = reinterpret_cast<const char*>(&value);
    return ::setsockopt(socket_, slevel, sopt, p, sizeof(value));
  }
  
  int Win32Socket::Send(const void* buffer, size_t length) {
    int sent = ::send(socket_,
                      reinterpret_cast<const char*>(buffer),
                      static_cast<int>(length),
                      0);
    UpdateLastError();
    return sent;
  }
  
  int Win32Socket::SendTo(const void* buffer, size_t length,
                          const SocketAddress& addr) {
    sockaddr_storage saddr;
    size_t addr_len = addr.ToSockAddrStorage(&saddr);
    int sent = ::sendto(socket_, reinterpret_cast<const char*>(buffer),
                        static_cast<int>(length), 0,
                        reinterpret_cast<sockaddr*>(&saddr),
                        static_cast<int>(addr_len));
    UpdateLastError();
    return sent;
  }
  
  int Win32Socket::Recv(void* buffer, size_t length, int64_t* timestamp) {
    if (timestamp) {
      *timestamp = -1;
    }
    int received = ::recv(socket_, static_cast<char*>(buffer),
                          static_cast<int>(length), 0);
    UpdateLastError();
    if (closing_ && received <= static_cast<int>(length))
      PostClosed();
    return received;
  }
  
  int Win32Socket::RecvFrom(void* buffer,
                            size_t length,
                            SocketAddress* out_addr,
                            int64_t* timestamp) {
    if (timestamp) {
      *timestamp = -1;
    }
    sockaddr_storage saddr;
    socklen_t addr_len = sizeof(saddr);
    int received = ::recvfrom(socket_, static_cast<char*>(buffer),
                              static_cast<int>(length), 0,
                              reinterpret_cast<sockaddr*>(&saddr), &addr_len);
    UpdateLastError();
    if (received != SOCKET_ERROR)
      SocketAddressFromSockAddrStorage(saddr, out_addr);
    if (closing_ && received <= static_cast<int>(length))
      PostClosed();
    return received;
  }
  
  int Win32Socket::Listen(int backlog) {
    int err = ::listen(socket_, backlog);
    if (!SetAsync(FD_ACCEPT))
      return SOCKET_ERROR;
  
    UpdateLastError();
    if (err == 0)
      state_ = CS_CONNECTING;
    return err;
  }
  
  Win32Socket* Win32Socket::Accept(SocketAddress* out_addr) {
    sockaddr_storage saddr;
    socklen_t addr_len = sizeof(saddr);
    SOCKET s = ::accept(socket_, reinterpret_cast<sockaddr*>(&saddr), &addr_len);
    UpdateLastError();
    if (s == INVALID_SOCKET)
      return nullptr;
    if (out_addr)
      SocketAddressFromSockAddrStorage(saddr, out_addr);
    Win32Socket* socket = new Win32Socket;
    if (0 == socket->Attach(s))
      return socket;
    delete socket;
    return nullptr;
  }
  
  int Win32Socket::Close() {
    int err = 0;
    if (socket_ != INVALID_SOCKET) {
      err = ::closesocket(socket_);
      socket_ = INVALID_SOCKET;
      closing_ = false;
      close_error_ = 0;
      UpdateLastError();
    }
    if (dns_) {
      WSACancelAsyncRequest(dns_->handle);
      delete dns_;
      dns_ = nullptr;
    }
    if (sink_) {
      sink_->Dispose();
      sink_ = nullptr;
    }
    addr_.Clear();
    state_ = CS_CLOSED;
    return err;
  }
  
  void Win32Socket::CreateSink() {
    RTC_DCHECK(nullptr == sink_);
  
    // Create window
    sink_ = new EventSink(this);
    sink_->Create(nullptr, L"EventSink", 0, 0, 0, 0, 10, 10);
  }
  
  bool Win32Socket::SetAsync(int events) {
    if (nullptr == sink_) {
      CreateSink();
      RTC_DCHECK(nullptr != sink_);
    }
  
    // start the async select
    if (WSAAsyncSelect(socket_, sink_->handle(), WM_SOCKETNOTIFY, events)
        == SOCKET_ERROR) {
      UpdateLastError();
      Close();
      return false;
    }
  
    return true;
  }
  
  bool Win32Socket::HandleClosed(int close_error) {
    // WM_CLOSE will be received before all data has been read, so we need to
    // hold on to it until the read buffer has been drained.
    char ch;
    closing_ = true;
    close_error_ = close_error;
    return (::recv(socket_, &ch, 1, MSG_PEEK) <= 0);
  }
  
  void Win32Socket::PostClosed() {
    // If we see that the buffer is indeed drained, then send the close.
    closing_ = false;
    ::PostMessage(sink_->handle(), WM_SOCKETNOTIFY,
                  socket_, WSAMAKESELECTREPLY(FD_CLOSE, close_error_));
  }
  
  void Win32Socket::UpdateLastError() {
    error_ = WSAGetLastError();
  }
  
  int Win32Socket::TranslateOption(Option opt, int* slevel, int* sopt) {
    switch (opt) {
      case OPT_DONTFRAGMENT:
        *slevel = IPPROTO_IP;
        *sopt = IP_DONTFRAGMENT;
        break;
      case OPT_RCVBUF:
        *slevel = SOL_SOCKET;
        *sopt = SO_RCVBUF;
        break;
      case OPT_SNDBUF:
        *slevel = SOL_SOCKET;
        *sopt = SO_SNDBUF;
        break;
      case OPT_NODELAY:
        *slevel = IPPROTO_TCP;
        *sopt = TCP_NODELAY;
        break;
      case OPT_DSCP:
        RTC_LOG(LS_WARNING) << "Socket::OPT_DSCP not supported.";
        return -1;
      default:
        RTC_NOTREACHED();
        return -1;
    }
    return 0;
  }
  
  void Win32Socket::OnSocketNotify(SOCKET socket, int event, int error) {
    // Ignore events if we're already closed.
    if (socket != socket_)
      return;
  
    error_ = error;
    switch (event) {
      case FD_CONNECT:
        if (error != ERROR_SUCCESS) {
          ReportWSAError("WSAAsync:connect notify", error, addr_);
  #if !defined(NDEBUG)
          int64_t duration = TimeSince(connect_time_);
          RTC_LOG(LS_INFO) << "WSAAsync:connect error (" << duration
                           << " ms), faking close";
  #endif
          state_ = CS_CLOSED;
          // If you get an error connecting, close doesn't really do anything
          // and it certainly doesn't send back any close notification, but
          // we really only maintain a few states, so it is easiest to get
          // back into a known state by pretending that a close happened, even
          // though the connect event never did occur.
          SignalCloseEvent(this, error);
        } else {
  #if !defined(NDEBUG)
          int64_t duration = TimeSince(connect_time_);
          RTC_LOG(LS_INFO) << "WSAAsync:connect (" << duration << " ms)";
  #endif
          state_ = CS_CONNECTED;
          SignalConnectEvent(this);
        }
        break;
  
      case FD_ACCEPT:
      case FD_READ:
        if (error != ERROR_SUCCESS) {
          ReportWSAError("WSAAsync:read notify", error, addr_);
        } else {
          SignalReadEvent(this);
        }
        break;
  
      case FD_WRITE:
        if (error != ERROR_SUCCESS) {
          ReportWSAError("WSAAsync:write notify", error, addr_);
        } else {
          SignalWriteEvent(this);
        }
        break;
  
      case FD_CLOSE:
        if (HandleClosed(error)) {
          ReportWSAError("WSAAsync:close notify", error, addr_);
          state_ = CS_CLOSED;
          SignalCloseEvent(this, error);
        }
        break;
    }
  }
  
  void Win32Socket::OnDnsNotify(HANDLE task, int error) {
    if (!dns_ || dns_->handle != task)
      return;
  
    uint32_t ip = 0;
    if (error == 0) {
      hostent* pHost = reinterpret_cast<hostent*>(dns_->buffer);
      uint32_t net_ip = *reinterpret_cast<uint32_t*>(pHost->h_addr_list[0]);
      ip = NetworkToHost32(net_ip);
    }
  
    RTC_LOG_F(LS_INFO) << "(" << IPAddress(ip).ToSensitiveString() << ", "
                       << error << ")";
  
    if (error == 0) {
      SocketAddress address(ip, dns_->port);
      error = DoConnect(address);
    } else {
      Close();
    }
  
    if (error) {
      error_ = error;
      SignalCloseEvent(this, error_);
    } else {
      delete dns_;
      dns_ = nullptr;
    }
  }
  
  ///////////////////////////////////////////////////////////////////////////////
  // Win32SocketServer
  // Provides cricket base services on top of a win32 gui thread
  ///////////////////////////////////////////////////////////////////////////////
  
  static UINT s_wm_wakeup_id = 0;
  const TCHAR Win32SocketServer::kWindowName[] = L"libjingle Message Window";
  
  Win32SocketServer::Win32SocketServer()
      : wnd_(this),
        posted_(false),
        hdlg_(nullptr) {
    if (s_wm_wakeup_id == 0)
      s_wm_wakeup_id = RegisterWindowMessage(L"WM_WAKEUP");
    if (!wnd_.Create(nullptr, kWindowName, 0, 0, 0, 0, 0, 0)) {
      RTC_LOG_GLE(LS_ERROR) << "Failed to create message window.";
    }
  }
  
  Win32SocketServer::~Win32SocketServer() {
    if (wnd_.handle() != nullptr) {
      KillTimer(wnd_.handle(), 1);
      wnd_.Destroy();
    }
  }
  
  Socket* Win32SocketServer::CreateSocket(int type) {
    return CreateSocket(AF_INET, type);
  }
  
  Socket* Win32SocketServer::CreateSocket(int family, int type) {
    return CreateAsyncSocket(family, type);
  }
  
  AsyncSocket* Win32SocketServer::CreateAsyncSocket(int type) {
    return CreateAsyncSocket(AF_INET, type);
  }
  
  AsyncSocket* Win32SocketServer::CreateAsyncSocket(int family, int type) {
    Win32Socket* socket = new Win32Socket;
    if (socket->CreateT(family, type)) {
      return socket;
    }
    delete socket;
    return nullptr;
  }
  
  void Win32SocketServer::SetMessageQueue(MessageQueue* queue) {
    message_queue_ = queue;
  }
  
  bool Win32SocketServer::Wait(int cms, bool process_io) {
    BOOL b;
    if (process_io) {
      // Spin the Win32 message pump at least once, and as long as requested.
      // This is the Thread::ProcessMessages case.
      uint32_t start = Time();
      do {
        MSG msg;
        SetTimer(wnd_.handle(), 0, cms, nullptr);
        // Get the next available message. If we have a modeless dialog, give
        // give the message to IsDialogMessage, which will return true if it
        // was a message for the dialog that it handled internally.
        // Otherwise, dispatch as usual via Translate/DispatchMessage.
        b = GetMessage(&msg, nullptr, 0, 0);
        if (b == -1) {
          RTC_LOG_GLE(LS_ERROR) << "GetMessage failed.";
          return false;
        } else if(b) {
          if (!hdlg_ || !IsDialogMessage(hdlg_, &msg)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
          }
        }
        KillTimer(wnd_.handle(), 0);
      } while (b && TimeSince(start) < cms);
    } else if (cms != 0) {
      // Sit and wait forever for a WakeUp. This is the Thread::Send case.
      RTC_DCHECK(cms == -1);
      MSG msg;
      b = GetMessage(&msg, nullptr, s_wm_wakeup_id, s_wm_wakeup_id);
      {
        CritScope scope(&cs_);
        posted_ = false;
      }
    } else {
      // No-op (cms == 0 && !process_io). This is the Pump case.
      b = TRUE;
    }
    return (b != FALSE);
  }
  
  void Win32SocketServer::WakeUp() {
    if (wnd_.handle()) {
      // Set the "message pending" flag, if not already set.
      {
        CritScope scope(&cs_);
        if (posted_)
          return;
        posted_ = true;
      }
  
      PostMessage(wnd_.handle(), s_wm_wakeup_id, 0, 0);
    }
  }
  
  void Win32SocketServer::Pump() {
    // Clear the "message pending" flag.
    {
      CritScope scope(&cs_);
      posted_ = false;
    }
  
    // Dispatch all the messages that are currently in our queue. If new messages
    // are posted during the dispatch, they will be handled in the next Pump.
    // We use max(1, ...) to make sure we try to dispatch at least once, since
    // this allow us to process "sent" messages, not included in the size() count.
    Message msg;
    for (size_t max_messages_to_process =
             std::max<size_t>(1, message_queue_->size());
         max_messages_to_process > 0 && message_queue_->Get(&msg, 0, false);
         --max_messages_to_process) {
      message_queue_->Dispatch(&msg);
    }
  
    // Anything remaining?
    int delay = message_queue_->GetDelay();
    if (delay == -1) {
      KillTimer(wnd_.handle(), 1);
    } else {
      SetTimer(wnd_.handle(), 1, delay, nullptr);
    }
  }
  
  bool Win32SocketServer::MessageWindow::OnMessage(UINT wm, WPARAM wp,
                                                   LPARAM lp, LRESULT& lr) {
    bool handled = false;
    if (wm == s_wm_wakeup_id || (wm == WM_TIMER && wp == 1)) {
      ss_->Pump();
      lr = 0;
      handled = true;
    }
    return handled;
  }
  
  Win32Thread::Win32Thread(SocketServer* ss) : Thread(ss), id_(0) {}
  
  Win32Thread::~Win32Thread() {
    Stop();
  }
  
  void Win32Thread::Run() {
    id_ = GetCurrentThreadId();
    Thread::Run();
    id_ = 0;
  }
  
  void Win32Thread::Quit() {
    PostThreadMessage(id_, WM_QUIT, 0, 0);
  }
  
  }  // namespace rtc
  