15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org/*
25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * libjingle
35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Copyright 2004--2005, Google Inc.
45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * Redistribution and use in source and binary forms, with or without
65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * modification, are permitted provided that the following conditions are met:
75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  1. Redistributions of source code must retain the above copyright notice,
95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer.
105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  2. Redistributions in binary form must reproduce the above copyright notice,
115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     this list of conditions and the following disclaimer in the documentation
125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     and/or other materials provided with the distribution.
135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *  3. The name of the author may not be used to endorse or promote products
145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *     derived from this software without specific prior written permission.
155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org *
165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org */
275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if defined(_MSC_VER) && _MSC_VER < 1300
295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#pragma warning(disable:4786)
305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <cassert>
335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef POSIX
355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <string.h>
365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <errno.h>
375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <fcntl.h>
385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <sys/time.h>
395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <unistd.h>
405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <signal.h>
415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#define WIN32_LEAN_AND_MEAN
455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <windows.h>
465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <winsock2.h>
475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <ws2tcpip.h>
485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#undef SetPort
495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <algorithm>
525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <map>
535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/basictypes.h"
555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/byteorder.h"
565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/common.h"
575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/logging.h"
585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/nethelpers.h"
595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/physicalsocketserver.h"
605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/timeutils.h"
615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/winping.h"
625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/win32socketinit.h"
635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// stm: this will tell us if we are on OSX
655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef HAVE_CONFIG_H
665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "config.h"
675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef POSIX
705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <netinet/tcp.h>  // for TCP_NODELAY
715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#define IP_MTU 14 // Until this is integrated from linux/in.h to netinet/in.h
725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgtypedef void* SockOptArg;
735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // POSIX
745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgtypedef char* SockOptArg;
775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgnamespace talk_base {
805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Standard MTUs, from RFC 1191
825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgconst uint16 PACKET_MAXIMUMS[] = {
835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  65535,    // Theoretical maximum, Hyperchannel
845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  32000,    // Nothing
855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  17914,    // 16Mb IBM Token Ring
865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  8166,     // IEEE 802.4
875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  //4464,   // IEEE 802.5 (4Mb max)
885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  4352,     // FDDI
895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  //2048,   // Wideband Network
905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  2002,     // IEEE 802.5 (4Mb recommended)
915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  //1536,   // Expermental Ethernet Networks
925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  //1500,   // Ethernet, Point-to-Point (default)
935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  1492,     // IEEE 802.3
945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  1006,     // SLIP, ARPANET
955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  //576,    // X.25 Networks
965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  //544,    // DEC IP Portal
975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  //512,    // NETBIOS
985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  508,      // IEEE 802/Source-Rt Bridge, ARCNET
995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  296,      // Point-to-Point (low delay)
1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  68,       // Official minimum
1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  0,        // End of list marker
1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int IP_HEADER_SIZE = 20u;
1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int IPV6_HEADER_SIZE = 40u;
1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int ICMP_HEADER_SIZE = 8u;
1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const int ICMP_PING_TIMEOUT_MILLIS = 10000u;
1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> {
1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  PhysicalSocket(PhysicalSocketServer* ss, SOCKET s = INVALID_SOCKET)
1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    : ss_(ss), s_(s), enabled_events_(0), error_(0),
1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED),
1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      resolver_(NULL) {
1155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // EnsureWinsockInit() ensures that winsock is initialized. The default
1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // version of this function doesn't do anything because winsock is
1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // initialized by constructor of a static object. If neccessary libjingle
1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // users can link it with a different version of this function by replacing
1205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // win32socketinit.cc. See win32socketinit.cc for more details.
1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    EnsureWinsockInit();
1225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
1235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (s_ != INVALID_SOCKET) {
1245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ = DE_READ | DE_WRITE;
1255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      int type = SOCK_STREAM;
1275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      socklen_t len = sizeof(type);
1285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      VERIFY(0 == getsockopt(s_, SOL_SOCKET, SO_TYPE, (SockOptArg)&type, &len));
1295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      udp_ = (SOCK_DGRAM == type);
1305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual ~PhysicalSocket() {
1345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    Close();
1355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Creates the underlying OS socket (same as the "socket" function).
1385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool Create(int family, int type) {
1395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    Close();
1405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    s_ = ::socket(family, type, 0);
1415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    udp_ = (SOCK_DGRAM == type);
1425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    UpdateLastError();
1435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (udp_)
1445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ = DE_READ | DE_WRITE;
1455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return s_ != INVALID_SOCKET;
1465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SocketAddress GetLocalAddress() const {
1495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr_storage addr_storage = {0};
1505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    socklen_t addrlen = sizeof(addr_storage);
1515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage);
1525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int result = ::getsockname(s_, addr, &addrlen);
1535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SocketAddress address;
1545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (result >= 0) {
1555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SocketAddressFromSockAddrStorage(addr_storage, &address);
1565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
1575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket="
1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                      << s_;
1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return address;
1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SocketAddress GetRemoteAddress() const {
1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr_storage addr_storage = {0};
1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    socklen_t addrlen = sizeof(addr_storage);
1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage);
1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int result = ::getpeername(s_, addr, &addrlen);
1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SocketAddress address;
1695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (result >= 0) {
1705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SocketAddressFromSockAddrStorage(addr_storage, &address);
1715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
1725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "GetRemoteAddress: unable to get remote addr, socket="
1735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                      << s_;
1745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return address;
1765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int Bind(const SocketAddress& bind_addr) {
1795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr_storage addr_storage;
1805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    size_t len = bind_addr.ToSockAddrStorage(&addr_storage);
1815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage);
1825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int err = ::bind(s_, addr, static_cast<int>(len));
1835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    UpdateLastError();
1845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef _DEBUG
1855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (0 == err) {
1865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      dbg_addr_ = "Bound @ ";
1875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      dbg_addr_.append(GetLocalAddress().ToString());
1885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // _DEBUG
1905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return err;
1915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int Connect(const SocketAddress& addr) {
1945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // TODO: Implicit creation is required to reconnect...
1955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // ...but should we make it more explicit?
1965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (state_ != CS_CLOSED) {
1975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SetError(EALREADY);
1985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return SOCKET_ERROR;
1995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (addr.IsUnresolved()) {
2015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_VERBOSE) << "Resolving addr in PhysicalSocket::Connect";
2025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      resolver_ = new AsyncResolver();
2035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      resolver_->set_address(addr);
2045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      resolver_->SignalWorkDone.connect(this, &PhysicalSocket::OnResolveResult);
2055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      resolver_->Start();
2065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      state_ = CS_CONNECTING;
2075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return 0;
2085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return DoConnect(addr);
2115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int DoConnect(const SocketAddress& connect_addr) {
2145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((s_ == INVALID_SOCKET) &&
2155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        !Create(connect_addr.family(), SOCK_STREAM)) {
2165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return SOCKET_ERROR;
2175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr_storage addr_storage;
2195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    size_t len = connect_addr.ToSockAddrStorage(&addr_storage);
2205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage);
2215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int err = ::connect(s_, addr, static_cast<int>(len));
2225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    UpdateLastError();
2235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (err == 0) {
2245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      state_ = CS_CONNECTED;
2255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else if (IsBlockingError(error_)) {
2265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      state_ = CS_CONNECTING;
2275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ |= DE_CONNECT;
2285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
2295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return SOCKET_ERROR;
2305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    enabled_events_ |= DE_READ | DE_WRITE;
2335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return 0;
2345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int GetError() const {
2375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return error_;
2385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  void SetError(int error) {
2415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    error_ = error;
2425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ConnState GetState() const {
2455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return state_;
2465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int GetOption(Option opt, int* value) {
2495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int slevel;
2505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int sopt;
2515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (TranslateOption(opt, &slevel, &sopt) == -1)
2525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return -1;
2535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    socklen_t optlen = sizeof(*value);
2545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int ret = ::getsockopt(s_, slevel, sopt, (SockOptArg)value, &optlen);
2555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (ret != -1 && opt == OPT_DONTFRAGMENT) {
2565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef LINUX
2575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      *value = (*value != IP_PMTUDISC_DONT) ? 1 : 0;
2585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
2595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return ret;
2615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int SetOption(Option opt, int value) {
2645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int slevel;
2655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int sopt;
2665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (TranslateOption(opt, &slevel, &sopt) == -1)
2675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return -1;
2685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (opt == OPT_DONTFRAGMENT) {
2695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef LINUX
2705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      value = (value) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
2715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
2725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return ::setsockopt(s_, slevel, sopt, (SockOptArg)&value, sizeof(value));
2745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int Send(const void *pv, size_t cb) {
2775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int sent = ::send(s_, reinterpret_cast<const char *>(pv), (int)cb,
2785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef LINUX
2795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Suppress SIGPIPE. Without this, attempting to send on a socket whose
2805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // other end is closed will result in a SIGPIPE signal being raised to
2815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // our process, which by default will terminate the process, which we
2825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // don't want. By specifying this flag, we'll just get the error EPIPE
2835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // instead and can handle the error gracefully.
2845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        MSG_NOSIGNAL
2855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#else
2865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        0
2875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
2885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        );
2895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    UpdateLastError();
2905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    MaybeRemapSendError();
2915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // We have seen minidumps where this may be false.
2925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(sent <= static_cast<int>(cb));
2935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((sent < 0) && IsBlockingError(error_)) {
2945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ |= DE_WRITE;
2955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return sent;
2975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int SendTo(const void* buffer, size_t length, const SocketAddress& addr) {
3005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr_storage saddr;
3015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    size_t len = addr.ToSockAddrStorage(&saddr);
3025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int sent = ::sendto(
3035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        s_, static_cast<const char *>(buffer), static_cast<int>(length),
3045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef LINUX
3055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Suppress SIGPIPE. See above for explanation.
3065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        MSG_NOSIGNAL,
3075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#else
3085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        0,
3095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
3105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        reinterpret_cast<sockaddr*>(&saddr), static_cast<int>(len));
3115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    UpdateLastError();
3125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    MaybeRemapSendError();
3135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // We have seen minidumps where this may be false.
3145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(sent <= static_cast<int>(length));
3155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((sent < 0) && IsBlockingError(error_)) {
3165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ |= DE_WRITE;
3175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return sent;
3195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int Recv(void* buffer, size_t length) {
3225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int received = ::recv(s_, static_cast<char*>(buffer),
3235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                          static_cast<int>(length), 0);
3245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((received == 0) && (length != 0)) {
3255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Note: on graceful shutdown, recv can return 0.  In this case, we
3265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // pretend it is blocking, and then signal close, so that simplifying
3275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // assumptions can be made about Recv.
3285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "EOF from socket; deferring close event";
3295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Must turn this back on so that the select() loop will notice the close
3305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // event.
3315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ |= DE_READ;
3325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      error_ = EWOULDBLOCK;
3335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return SOCKET_ERROR;
3345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    UpdateLastError();
3365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    bool success = (received >= 0) || IsBlockingError(error_);
3375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (udp_ || success) {
3385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ |= DE_READ;
3395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!success) {
3415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_F(LS_VERBOSE) << "Error = " << error_;
3425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return received;
3445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int RecvFrom(void* buffer, size_t length, SocketAddress *out_addr) {
3475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr_storage addr_storage;
3485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    socklen_t addr_len = sizeof(addr_storage);
3495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage);
3505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int received = ::recvfrom(s_, static_cast<char*>(buffer),
3515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                              static_cast<int>(length), 0, addr, &addr_len);
3525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    UpdateLastError();
3535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((received >= 0) && (out_addr != NULL))
3545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SocketAddressFromSockAddrStorage(addr_storage, out_addr);
3555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    bool success = (received >= 0) || IsBlockingError(error_);
3565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (udp_ || success) {
3575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ |= DE_READ;
3585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!success) {
3605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_F(LS_VERBOSE) << "Error = " << error_;
3615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return received;
3635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int Listen(int backlog) {
3665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int err = ::listen(s_, backlog);
3675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    UpdateLastError();
3685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (err == 0) {
3695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      state_ = CS_CONNECTING;
3705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ |= DE_ACCEPT;
3715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef _DEBUG
3725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      dbg_addr_ = "Listening @ ";
3735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      dbg_addr_.append(GetLocalAddress().ToString());
3745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // _DEBUG
3755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
3765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return err;
3775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  AsyncSocket* Accept(SocketAddress *out_addr) {
3805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr_storage addr_storage;
3815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    socklen_t addr_len = sizeof(addr_storage);
3825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage);
3835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SOCKET s = ::accept(s_, addr, &addr_len);
3845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    UpdateLastError();
3855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (s == INVALID_SOCKET)
3865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return NULL;
3875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    enabled_events_ |= DE_ACCEPT;
3885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (out_addr != NULL)
3895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SocketAddressFromSockAddrStorage(addr_storage, out_addr);
3905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return ss_->WrapSocket(s);
3915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
3925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
3935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int Close() {
3945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (s_ == INVALID_SOCKET)
3955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return 0;
3965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int err = ::closesocket(s_);
3975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    UpdateLastError();
3985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    s_ = INVALID_SOCKET;
3995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    state_ = CS_CLOSED;
4005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    enabled_events_ = 0;
4015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (resolver_) {
4025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      resolver_->Destroy(false);
4035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      resolver_ = NULL;
4045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return err;
4065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int EstimateMTU(uint16* mtu) {
4095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SocketAddress addr = GetRemoteAddress();
4105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (addr.IsAny()) {
4115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      error_ = ENOTCONN;
4125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return -1;
4135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if defined(WIN32)
4165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Gets the interface MTU (TTL=1) for the interface used to reach |addr|.
4175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    WinPing ping;
4185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!ping.IsValid()) {
4195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      error_ = EINVAL; // can't think of a better error ID
4205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return -1;
4215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int header_size = ICMP_HEADER_SIZE;
4235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (addr.family() == AF_INET6) {
4245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      header_size += IPV6_HEADER_SIZE;
4255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else if (addr.family() == AF_INET) {
4265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      header_size += IP_HEADER_SIZE;
4275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) {
4305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      int32 size = PACKET_MAXIMUMS[level] - header_size;
4315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      WinPing::PingResult result = ping.Ping(addr.ipaddr(), size,
4325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                             ICMP_PING_TIMEOUT_MILLIS,
4335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                             1, false);
4345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (result == WinPing::PING_FAIL) {
4355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        error_ = EINVAL; // can't think of a better error ID
4365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return -1;
4375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      } else if (result != WinPing::PING_TOO_LARGE) {
4385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *mtu = PACKET_MAXIMUMS[level];
4395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return 0;
4405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
4415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(false);
4445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return -1;
4455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#elif defined(IOS) || defined(OSX)
4465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // No simple way to do this on Mac OS X.
4475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // SIOCGIFMTU would work if we knew which interface would be used, but
4485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // figuring that out is pretty complicated. For now we'll return an error
4495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // and let the caller pick a default MTU.
4505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    error_ = EINVAL;
4515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return -1;
4525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#elif defined(LINUX) || defined(ANDROID)
4535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Gets the path MTU.
4545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int value;
4555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    socklen_t vlen = sizeof(value);
4565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int err = getsockopt(s_, IPPROTO_IP, IP_MTU, &value, &vlen);
4575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (err < 0) {
4585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      UpdateLastError();
4595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return err;
4605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT((0 <= value) && (value <= 65536));
4635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    *mtu = value;
4645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return 0;
4655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
4665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SocketServer* socketserver() { return ss_; }
4695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org protected:
4715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  void OnResolveResult(SignalThread* thread) {
4725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (thread != resolver_) {
4735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return;
4745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int error = resolver_->error();
4775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (error == 0) {
4785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      error = DoConnect(resolver_->address());
4795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
4805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      Close();
4815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (error) {
4845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      error_ = error;
4855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalCloseEvent(this, error_);
4865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
4875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  void UpdateLastError() {
4905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    error_ = LAST_SYSTEM_ERROR;
4915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
4925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
4935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  void MaybeRemapSendError() {
4945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if defined(OSX)
4955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // https://developer.apple.com/library/mac/documentation/Darwin/
4965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Reference/ManPages/man2/sendto.2.html
4975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // ENOBUFS - The output queue for a network interface is full.
4985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // This generally indicates that the interface has stopped sending,
4995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // but may be caused by transient congestion.
5005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (error_ == ENOBUFS) {
5015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      error_ = EWOULDBLOCK;
5025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
5035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
5045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  static int TranslateOption(Option opt, int* slevel, int* sopt) {
5075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    switch (opt) {
5085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case OPT_DONTFRAGMENT:
5095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
5105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *slevel = IPPROTO_IP;
5115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *sopt = IP_DONTFRAGMENT;
5125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        break;
5135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#elif defined(IOS) || defined(OSX) || defined(BSD)
5145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG(LS_WARNING) << "Socket::OPT_DONTFRAGMENT not supported.";
5155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return -1;
5165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#elif defined(POSIX)
5175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *slevel = IPPROTO_IP;
5185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *sopt = IP_MTU_DISCOVER;
5195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        break;
5205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
5215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case OPT_RCVBUF:
5225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *slevel = SOL_SOCKET;
5235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *sopt = SO_RCVBUF;
5245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        break;
5255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case OPT_SNDBUF:
5265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *slevel = SOL_SOCKET;
5275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *sopt = SO_SNDBUF;
5285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        break;
5295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      case OPT_NODELAY:
5305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *slevel = IPPROTO_TCP;
5315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        *sopt = TCP_NODELAY;
5325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        break;
5335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      default:
5345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        ASSERT(false);
5355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return -1;
5365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
5375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return 0;
5385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  PhysicalSocketServer* ss_;
5415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SOCKET s_;
5425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  uint8 enabled_events_;
5435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool udp_;
5445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int error_;
5455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ConnState state_;
5465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  AsyncResolver* resolver_;
5475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef _DEBUG
5495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::string dbg_addr_;
5505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // _DEBUG;
5515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
5525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef POSIX
5545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass EventDispatcher : public Dispatcher {
5555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
5565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  EventDispatcher(PhysicalSocketServer* ss) : ss_(ss), fSignaled_(false) {
5575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (pipe(afd_) < 0)
5585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LERROR) << "pipe failed";
5595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ss_->Add(this);
5605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual ~EventDispatcher() {
5635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ss_->Remove(this);
5645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    close(afd_[0]);
5655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    close(afd_[1]);
5665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void Signal() {
5695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    CritScope cs(&crit_);
5705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!fSignaled_) {
5715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      const uint8 b[1] = { 0 };
5725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (VERIFY(1 == write(afd_[1], b, sizeof(b)))) {
5735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        fSignaled_ = true;
5745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
5755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
5765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual uint32 GetRequestedEvents() {
5795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return DE_READ;
5805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnPreEvent(uint32 ff) {
5835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // It is not possible to perfectly emulate an auto-resetting event with
5845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // pipes.  This simulates it by resetting before the event is handled.
5855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    CritScope cs(&crit_);
5875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (fSignaled_) {
5885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      uint8 b[4];  // Allow for reading more than 1 byte, but expect 1.
5895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      VERIFY(1 == read(afd_[0], b, sizeof(b)));
5905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      fSignaled_ = false;
5915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
5925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnEvent(uint32 ff, int err) {
5955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(false);
5965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
5975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
5985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual int GetDescriptor() {
5995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return afd_[0];
6005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool IsDescriptorClosed() {
6035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
6045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private:
6075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  PhysicalSocketServer *ss_;
6085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int afd_[2];
6095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool fSignaled_;
6105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CriticalSection crit_;
6115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
6125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// These two classes use the self-pipe trick to deliver POSIX signals to our
6145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// select loop. This is the only safe, reliable, cross-platform way to do
6155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// non-trivial things with a POSIX signal in an event-driven program (until
6165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// proper pselect() implementations become ubiquitous).
6175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass PosixSignalHandler {
6195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
6205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // POSIX only specifies 32 signals, but in principle the system might have
6215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // more and the programmer might choose to use them, so we size our array
6225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // for 128.
6235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  static const int kNumPosixSignals = 128;
6245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // There is just a single global instance. (Signal handlers do not get any
6265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // sort of user-defined void * parameter, so they can't access anything that
6275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // isn't global.)
6285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  static PosixSignalHandler* Instance() {
6295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LIBJINGLE_DEFINE_STATIC_LOCAL(PosixSignalHandler, instance, ());
6305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return &instance;
6315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Returns true if the given signal number is set.
6345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool IsSignalSet(int signum) const {
6355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(signum < ARRAY_SIZE(received_signal_));
6365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (signum < ARRAY_SIZE(received_signal_)) {
6375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return received_signal_[signum];
6385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
6395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
6405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
6415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Clears the given signal number.
6445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  void ClearSignal(int signum) {
6455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(signum < ARRAY_SIZE(received_signal_));
6465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (signum < ARRAY_SIZE(received_signal_)) {
6475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      received_signal_[signum] = false;
6485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
6495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Returns the file descriptor to monitor for signal events.
6525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int GetDescriptor() const {
6535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return afd_[0];
6545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // This is called directly from our real signal handler, so it must be
6575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // signal-handler-safe. That means it cannot assume anything about the
6585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // user-level state of the process, since the handler could be executed at any
6595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // time on any thread.
6605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  void OnPosixSignalReceived(int signum) {
6615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (signum >= ARRAY_SIZE(received_signal_)) {
6625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // We don't have space in our array for this.
6635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return;
6645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
6655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Set a flag saying we've seen this signal.
6665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    received_signal_[signum] = true;
6675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Notify application code that we got a signal.
6685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    const uint8 b[1] = { 0 };
6695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (-1 == write(afd_[1], b, sizeof(b))) {
6705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Nothing we can do here. If there's an error somehow then there's
6715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // nothing we can safely do from a signal handler.
6725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // No, we can't even safely log it.
6735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // But, we still have to check the return value here. Otherwise,
6745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // GCC 4.4.1 complains ignoring return value. Even (void) doesn't help.
6755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return;
6765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
6775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private:
6805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  PosixSignalHandler() {
6815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (pipe(afd_) < 0) {
6825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_ERR(LS_ERROR) << "pipe failed";
6835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return;
6845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
6855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (fcntl(afd_[0], F_SETFL, O_NONBLOCK) < 0) {
6865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_ERR(LS_WARNING) << "fcntl #1 failed";
6875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
6885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (fcntl(afd_[1], F_SETFL, O_NONBLOCK) < 0) {
6895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_ERR(LS_WARNING) << "fcntl #2 failed";
6905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
6915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    memset(const_cast<void *>(static_cast<volatile void *>(received_signal_)),
6925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org           0,
6935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org           sizeof(received_signal_));
6945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
6955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
6965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ~PosixSignalHandler() {
6975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int fd1 = afd_[0];
6985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int fd2 = afd_[1];
6995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // We clobber the stored file descriptor numbers here or else in principle
7005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // a signal that happens to be delivered during application termination
7015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // could erroneously write a zero byte to an unrelated file handle in
7025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // OnPosixSignalReceived() if some other file happens to be opened later
7035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // during shutdown and happens to be given the same file descriptor number
7045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // as our pipe had. Unfortunately even with this precaution there is still a
7055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // race where that could occur if said signal happens to be handled
7065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // concurrently with this code and happens to have already read the value of
7075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // afd_[1] from memory before we clobber it, but that's unlikely.
7085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    afd_[0] = -1;
7095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    afd_[1] = -1;
7105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    close(fd1);
7115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    close(fd2);
7125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int afd_[2];
7155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // These are boolean flags that will be set in our signal handler and read
7165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // and cleared from Wait(). There is a race involved in this, but it is
7175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // benign. The signal handler sets the flag before signaling the pipe, so
7185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // we'll never end up blocking in select() while a flag is still true.
7195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // However, if two of the same signal arrive close to each other then it's
7205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // possible that the second time the handler may set the flag while it's still
7215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // true, meaning that signal will be missed. But the first occurrence of it
7225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // will still be handled, so this isn't a problem.
7235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Volatile is not necessary here for correctness, but this data _is_ volatile
7245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // so I've marked it as such.
7255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  volatile uint8 received_signal_[kNumPosixSignals];
7265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
7275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass PosixSignalDispatcher : public Dispatcher {
7295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
7305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  PosixSignalDispatcher(PhysicalSocketServer *owner) : owner_(owner) {
7315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    owner_->Add(this);
7325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual ~PosixSignalDispatcher() {
7355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    owner_->Remove(this);
7365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual uint32 GetRequestedEvents() {
7395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return DE_READ;
7405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnPreEvent(uint32 ff) {
7435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Events might get grouped if signals come very fast, so we read out up to
7445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // 16 bytes to make sure we keep the pipe empty.
7455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    uint8 b[16];
7465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ssize_t ret = read(GetDescriptor(), b, sizeof(b));
7475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (ret < 0) {
7485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG_ERR(LS_WARNING) << "Error in read()";
7495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else if (ret == 0) {
7505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_WARNING) << "Should have read at least one byte";
7515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
7525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnEvent(uint32 ff, int err) {
7555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    for (int signum = 0; signum < PosixSignalHandler::kNumPosixSignals;
7565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org         ++signum) {
7575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (PosixSignalHandler::Instance()->IsSignalSet(signum)) {
7585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        PosixSignalHandler::Instance()->ClearSignal(signum);
7595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        HandlerMap::iterator i = handlers_.find(signum);
7605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (i == handlers_.end()) {
7615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // This can happen if a signal is delivered to our process at around
7625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // the same time as we unset our handler for it. It is not an error
7635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // condition, but it's unusual enough to be worth logging.
7645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          LOG(LS_INFO) << "Received signal with no handler: " << signum;
7655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        } else {
7665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // Otherwise, execute our handler.
7675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          (*i->second)(signum);
7685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
7695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
7705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
7715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual int GetDescriptor() {
7745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return PosixSignalHandler::Instance()->GetDescriptor();
7755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool IsDescriptorClosed() {
7785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
7795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  void SetHandler(int signum, void (*handler)(int)) {
7825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    handlers_[signum] = handler;
7835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  void ClearHandler(int signum) {
7865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    handlers_.erase(signum);
7875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool HasHandlers() {
7905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return !handlers_.empty();
7915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
7925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private:
7945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  typedef std::map<int, void (*)(int)> HandlerMap;
7955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
7965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  HandlerMap handlers_;
7975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Our owner.
7985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  PhysicalSocketServer *owner_;
7995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
8005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass SocketDispatcher : public Dispatcher, public PhysicalSocket {
8025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
8035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  explicit SocketDispatcher(PhysicalSocketServer *ss) : PhysicalSocket(ss) {
8045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SocketDispatcher(SOCKET s, PhysicalSocketServer *ss) : PhysicalSocket(ss, s) {
8065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual ~SocketDispatcher() {
8095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    Close();
8105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool Initialize() {
8135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ss_->Add(this);
8145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK);
8155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
8165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool Create(int type) {
8195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return Create(AF_INET, type);
8205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool Create(int family, int type) {
8235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Change the socket to be non-blocking.
8245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!PhysicalSocket::Create(family, type))
8255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
8265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return Initialize();
8285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual int GetDescriptor() {
8315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return s_;
8325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool IsDescriptorClosed() {
8355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // We don't have a reliable way of distinguishing end-of-stream
8365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // from readability.  So test on each readable call.  Is this
8375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // inefficient?  Probably.
8385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    char ch;
8395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ssize_t res = ::recv(s_, &ch, 1, MSG_PEEK);
8405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (res > 0) {
8415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Data available, so not closed.
8425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
8435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else if (res == 0) {
8445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // EOF, so closed.
8455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return true;
8465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {  // error
8475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      switch (errno) {
8485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Returned if we've already closed s_.
8495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        case EBADF:
8505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Returned during ungraceful peer shutdown.
8515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        case ECONNRESET:
8525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return true;
8535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        default:
8545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // Assume that all other errors are just blocking errors, meaning the
8555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // connection is still good but we just can't read from it right now.
8565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // This should only happen when connecting (and at most once), because
8575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // in all other cases this function is only called if the file
8585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // descriptor is already known to be in the readable state. However,
8595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // it's not necessary a problem if we spuriously interpret a
8605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // "connection lost"-type error as a blocking error, because typically
8615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // the next recv() will get EOF, so we'll still eventually notice that
8625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // the socket is closed.
8635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          LOG_ERR(LS_WARNING) << "Assuming benign blocking error";
8645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          return false;
8655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
8665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
8675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual uint32 GetRequestedEvents() {
8705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return enabled_events_;
8715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnPreEvent(uint32 ff) {
8745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_CONNECT) != 0)
8755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      state_ = CS_CONNECTED;
8765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_CLOSE) != 0)
8775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      state_ = CS_CLOSED;
8785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
8795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
8805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnEvent(uint32 ff, int err) {
8815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Make sure we deliver connect/accept first. Otherwise, consumers may see
8825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // something like a READ followed by a CONNECT, which would be odd.
8835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_CONNECT) != 0) {
8845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ &= ~DE_CONNECT;
8855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalConnectEvent(this);
8865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
8875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_ACCEPT) != 0) {
8885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ &= ~DE_ACCEPT;
8895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalReadEvent(this);
8905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
8915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_READ) != 0) {
8925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ &= ~DE_READ;
8935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalReadEvent(this);
8945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
8955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_WRITE) != 0) {
8965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ &= ~DE_WRITE;
8975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalWriteEvent(this);
8985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
8995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_CLOSE) != 0) {
9005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // The socket is now dead to us, so stop checking it.
9015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ = 0;
9025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalCloseEvent(this, err);
9035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
9045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual int Close() {
9075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (s_ == INVALID_SOCKET)
9085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return 0;
9095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ss_->Remove(this);
9115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return PhysicalSocket::Close();
9125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
9145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass FileDispatcher: public Dispatcher, public AsyncFile {
9165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
9175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  FileDispatcher(int fd, PhysicalSocketServer *ss) : ss_(ss), fd_(fd) {
9185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    set_readable(true);
9195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ss_->Add(this);
9215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    fcntl(fd_, F_SETFL, fcntl(fd_, F_GETFL, 0) | O_NONBLOCK);
9235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual ~FileDispatcher() {
9265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ss_->Remove(this);
9275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SocketServer* socketserver() { return ss_; }
9305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual int GetDescriptor() {
9325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return fd_;
9335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool IsDescriptorClosed() {
9365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
9375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual uint32 GetRequestedEvents() {
9405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return flags_;
9415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnPreEvent(uint32 ff) {
9445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnEvent(uint32 ff, int err) {
9475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_READ) != 0)
9485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalReadEvent(this);
9495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_WRITE) != 0)
9505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalWriteEvent(this);
9515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_CLOSE) != 0)
9525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalCloseEvent(this, err);
9535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool readable() {
9565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return (flags_ & DE_READ) != 0;
9575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void set_readable(bool value) {
9605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    flags_ = value ? (flags_ | DE_READ) : (flags_ & ~DE_READ);
9615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool writable() {
9645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return (flags_ & DE_WRITE) != 0;
9655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void set_writable(bool value) {
9685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    flags_ = value ? (flags_ | DE_WRITE) : (flags_ & ~DE_WRITE);
9695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
9705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private:
9725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  PhysicalSocketServer* ss_;
9735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int fd_;
9745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int flags_;
9755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
9765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgAsyncFile* PhysicalSocketServer::CreateFile(int fd) {
9785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return new FileDispatcher(fd, this);
9795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
9805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif // POSIX
9825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
9845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic uint32 FlagsToEvents(uint32 events) {
9855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  uint32 ffFD = FD_CLOSE;
9865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (events & DE_READ)
9875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ffFD |= FD_READ;
9885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (events & DE_WRITE)
9895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ffFD |= FD_WRITE;
9905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (events & DE_CONNECT)
9915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ffFD |= FD_CONNECT;
9925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (events & DE_ACCEPT)
9935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ffFD |= FD_ACCEPT;
9945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return ffFD;
9955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
9965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
9975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass EventDispatcher : public Dispatcher {
9985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
9995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  EventDispatcher(PhysicalSocketServer *ss) : ss_(ss) {
10005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    hev_ = WSACreateEvent();
10015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (hev_) {
10025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ss_->Add(this);
10035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
10045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ~EventDispatcher() {
10075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (hev_ != NULL) {
10085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ss_->Remove(this);
10095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      WSACloseEvent(hev_);
10105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      hev_ = NULL;
10115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
10125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void Signal() {
10155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (hev_ != NULL)
10165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      WSASetEvent(hev_);
10175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual uint32 GetRequestedEvents() {
10205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return 0;
10215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnPreEvent(uint32 ff) {
10245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    WSAResetEvent(hev_);
10255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnEvent(uint32 ff, int err) {
10285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual WSAEVENT GetWSAEvent() {
10315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return hev_;
10325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual SOCKET GetSocket() {
10355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return INVALID_SOCKET;
10365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool CheckSignalClose() { return false; }
10395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgprivate:
10415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  PhysicalSocketServer* ss_;
10425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  WSAEVENT hev_;
10435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
10445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass SocketDispatcher : public Dispatcher, public PhysicalSocket {
10465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
10475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  static int next_id_;
10485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int id_;
10495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool signal_close_;
10505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int signal_err_;
10515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SocketDispatcher(PhysicalSocketServer* ss)
10535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      : PhysicalSocket(ss),
10545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        id_(0),
10555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        signal_close_(false) {
10565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SocketDispatcher(SOCKET s, PhysicalSocketServer* ss)
10595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      : PhysicalSocket(ss, s),
10605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        id_(0),
10615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        signal_close_(false) {
10625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual ~SocketDispatcher() {
10655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    Close();
10665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool Initialize() {
10695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ASSERT(s_ != INVALID_SOCKET);
10705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Must be a non-blocking
10715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    u_long argp = 1;
10725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ioctlsocket(s_, FIONBIO, &argp);
10735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ss_->Add(this);
10745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
10755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool Create(int type) {
10785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return Create(AF_INET, type);
10795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool Create(int family, int type) {
10825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Create socket
10835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!PhysicalSocket::Create(family, type))
10845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
10855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!Initialize())
10875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
10885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    do { id_ = ++next_id_; } while (id_ == 0);
10905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
10915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
10925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual int Close() {
10945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (s_ == INVALID_SOCKET)
10955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return 0;
10965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
10975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    id_ = 0;
10985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    signal_close_ = false;
10995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ss_->Remove(this);
11005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return PhysicalSocket::Close();
11015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual uint32 GetRequestedEvents() {
11045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return enabled_events_;
11055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnPreEvent(uint32 ff) {
11085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_CONNECT) != 0)
11095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      state_ = CS_CONNECTED;
11105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // We set CS_CLOSED from CheckSignalClose.
11115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual void OnEvent(uint32 ff, int err) {
11145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int cache_id = id_;
11155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Make sure we deliver connect/accept first. Otherwise, consumers may see
11165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // something like a READ followed by a CONNECT, which would be odd.
11175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (((ff & DE_CONNECT) != 0) && (id_ == cache_id)) {
11185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (ff != DE_CONNECT)
11195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG(LS_VERBOSE) << "Signalled with DE_CONNECT: " << ff;
11205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ &= ~DE_CONNECT;
11215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef _DEBUG
11225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      dbg_addr_ = "Connected @ ";
11235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      dbg_addr_.append(GetRemoteAddress().ToString());
11245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // _DEBUG
11255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalConnectEvent(this);
11265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
11275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (((ff & DE_ACCEPT) != 0) && (id_ == cache_id)) {
11285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ &= ~DE_ACCEPT;
11295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalReadEvent(this);
11305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
11315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((ff & DE_READ) != 0) {
11325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ &= ~DE_READ;
11335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalReadEvent(this);
11345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
11355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (((ff & DE_WRITE) != 0) && (id_ == cache_id)) {
11365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      enabled_events_ &= ~DE_WRITE;
11375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      SignalWriteEvent(this);
11385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
11395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (((ff & DE_CLOSE) != 0) && (id_ == cache_id)) {
11405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      signal_close_ = true;
11415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      signal_err_ = err;
11425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
11435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual WSAEVENT GetWSAEvent() {
11465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return WSA_INVALID_EVENT;
11475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual SOCKET GetSocket() {
11505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return s_;
11515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual bool CheckSignalClose() {
11545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!signal_close_)
11555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
11565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    char ch;
11585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (recv(s_, &ch, 1, MSG_PEEK) > 0)
11595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
11605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    state_ = CS_CLOSED;
11625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    signal_close_ = false;
11635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    SignalCloseEvent(this, signal_err_);
11645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return true;
11655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
11675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgint SocketDispatcher::next_id_ = 0;
11695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // WIN32
11715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Sets the value of a boolean value to false when signaled.
11735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgclass Signaler : public EventDispatcher {
11745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org public:
11755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  Signaler(PhysicalSocketServer* ss, bool* pf)
11765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      : EventDispatcher(ss), pf_(pf) {
11775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  virtual ~Signaler() { }
11795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  void OnEvent(uint32 ff, int err) {
11815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (pf_)
11825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      *pf_ = false;
11835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
11845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org private:
11865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool *pf_;
11875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org};
11885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgPhysicalSocketServer::PhysicalSocketServer()
11905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    : fWait_(false),
11915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      last_tick_tracked_(0),
11925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      last_tick_dispatch_count_(0) {
11935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  signal_wakeup_ = new Signaler(this, &fWait_);
11945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
11955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  socket_ev_ = WSACreateEvent();
11965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
11975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
11985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
11995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgPhysicalSocketServer::~PhysicalSocketServer() {
12005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
12015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  WSACloseEvent(socket_ev_);
12025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
12035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef POSIX
12045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  signal_dispatcher_.reset();
12055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
12065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  delete signal_wakeup_;
12075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(dispatchers_.empty());
12085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
12095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid PhysicalSocketServer::WakeUp() {
12115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  signal_wakeup_->Signal();
12125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
12135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgSocket* PhysicalSocketServer::CreateSocket(int type) {
12155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return CreateSocket(AF_INET, type);
12165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
12175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgSocket* PhysicalSocketServer::CreateSocket(int family, int type) {
12195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  PhysicalSocket* socket = new PhysicalSocket(this);
12205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (socket->Create(family, type)) {
12215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return socket;
12225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
12235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delete socket;
12245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return 0;
12255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
12265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
12275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgAsyncSocket* PhysicalSocketServer::CreateAsyncSocket(int type) {
12295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return CreateAsyncSocket(AF_INET, type);
12305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
12315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgAsyncSocket* PhysicalSocketServer::CreateAsyncSocket(int family, int type) {
12335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SocketDispatcher* dispatcher = new SocketDispatcher(this);
12345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (dispatcher->Create(family, type)) {
12355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return dispatcher;
12365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
12375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delete dispatcher;
12385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return 0;
12395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
12405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
12415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgAsyncSocket* PhysicalSocketServer::WrapSocket(SOCKET s) {
12435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  SocketDispatcher* dispatcher = new SocketDispatcher(s, this);
12445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (dispatcher->Initialize()) {
12455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return dispatcher;
12465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
12475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    delete dispatcher;
12485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return 0;
12495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
12505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
12515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid PhysicalSocketServer::Add(Dispatcher *pdispatcher) {
12535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CritScope cs(&crit_);
12545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Prevent duplicates. This can cause dead dispatchers to stick around.
12555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  DispatcherList::iterator pos = std::find(dispatchers_.begin(),
12565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                           dispatchers_.end(),
12575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                           pdispatcher);
12585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (pos != dispatchers_.end())
12595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return;
12605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  dispatchers_.push_back(pdispatcher);
12615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
12625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgvoid PhysicalSocketServer::Remove(Dispatcher *pdispatcher) {
12645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CritScope cs(&crit_);
12655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  DispatcherList::iterator pos = std::find(dispatchers_.begin(),
12665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                           dispatchers_.end(),
12675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                           pdispatcher);
12685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ASSERT(pos != dispatchers_.end());
12695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  size_t index = pos - dispatchers_.begin();
12705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  dispatchers_.erase(pos);
12715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (IteratorList::iterator it = iterators_.begin(); it != iterators_.end();
12725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org       ++it) {
12735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (index < **it) {
12745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      --**it;
12755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
12765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
12775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
12785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef POSIX
12805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
12815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Calculate timing information
12825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  struct timeval *ptvWait = NULL;
12845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  struct timeval tvWait;
12855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  struct timeval tvStop;
12865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (cmsWait != kForever) {
12875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Calculate wait timeval
12885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    tvWait.tv_sec = cmsWait / 1000;
12895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    tvWait.tv_usec = (cmsWait % 1000) * 1000;
12905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ptvWait = &tvWait;
12915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
12925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Calculate when to return in a timeval
12935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    gettimeofday(&tvStop, NULL);
12945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    tvStop.tv_sec += tvWait.tv_sec;
12955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    tvStop.tv_usec += tvWait.tv_usec;
12965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (tvStop.tv_usec >= 1000000) {
12975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      tvStop.tv_usec -= 1000000;
12985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      tvStop.tv_sec += 1;
12995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
13005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
13015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Zero all fd_sets. Don't need to do this inside the loop since
13035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // select() zeros the descriptors not signaled
13045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  fd_set fdsRead;
13065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  FD_ZERO(&fdsRead);
13075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  fd_set fdsWrite;
13085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  FD_ZERO(&fdsWrite);
13095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  fWait_ = true;
13115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  while (fWait_) {
13135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int fdmax = -1;
13145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    {
13155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CritScope cr(&crit_);
13165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      for (size_t i = 0; i < dispatchers_.size(); ++i) {
13175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Query dispatchers for read and write wait state
13185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        Dispatcher *pdispatcher = dispatchers_[i];
13195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        ASSERT(pdispatcher);
13205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (!process_io && (pdispatcher != signal_wakeup_))
13215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          continue;
13225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        int fd = pdispatcher->GetDescriptor();
13235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (fd > fdmax)
13245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          fdmax = fd;
13255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        uint32 ff = pdispatcher->GetRequestedEvents();
13275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (ff & (DE_READ | DE_ACCEPT))
13285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          FD_SET(fd, &fdsRead);
13295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (ff & (DE_WRITE | DE_CONNECT))
13305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          FD_SET(fd, &fdsWrite);
13315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
13325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
13335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Wait then call handlers as appropriate
13355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // < 0 means error
13365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // 0 means timeout
13375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // > 0 means count of descriptors ready
13385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int n = select(fdmax + 1, &fdsRead, &fdsWrite, NULL, ptvWait);
13395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // If error, return error.
13415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (n < 0) {
13425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (errno != EINTR) {
13435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        LOG_E(LS_ERROR, EN, errno) << "select";
13445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        return false;
13455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
13465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Else ignore the error and keep going. If this EINTR was for one of the
13475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // signals managed by this PhysicalSocketServer, the
13485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // PosixSignalDeliveryDispatcher will be in the signaled state in the next
13495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // iteration.
13505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else if (n == 0) {
13515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // If timeout, return success
13525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return true;
13535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
13545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // We have signaled descriptors
13555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CritScope cr(&crit_);
13565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      for (size_t i = 0; i < dispatchers_.size(); ++i) {
13575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        Dispatcher *pdispatcher = dispatchers_[i];
13585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        int fd = pdispatcher->GetDescriptor();
13595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        uint32 ff = 0;
13605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        int errcode = 0;
13615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Reap any error code, which can be signaled through reads or writes.
13635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // TODO: Should we set errcode if getsockopt fails?
13645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (FD_ISSET(fd, &fdsRead) || FD_ISSET(fd, &fdsWrite)) {
13655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          socklen_t len = sizeof(errcode);
13665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          ::getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &len);
13675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
13685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Check readable descriptors. If we're waiting on an accept, signal
13705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // that. Otherwise we're waiting for data, check to see if we're
13715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // readable or really closed.
13725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // TODO: Only peek at TCP descriptors.
13735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (FD_ISSET(fd, &fdsRead)) {
13745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          FD_CLR(fd, &fdsRead);
13755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          if (pdispatcher->GetRequestedEvents() & DE_ACCEPT) {
13765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            ff |= DE_ACCEPT;
13775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          } else if (errcode || pdispatcher->IsDescriptorClosed()) {
13785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            ff |= DE_CLOSE;
13795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          } else {
13805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            ff |= DE_READ;
13815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          }
13825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
13835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Check writable descriptors. If we're waiting on a connect, detect
13855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // success versus failure by the reaped error code.
13865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (FD_ISSET(fd, &fdsWrite)) {
13875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          FD_CLR(fd, &fdsWrite);
13885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          if (pdispatcher->GetRequestedEvents() & DE_CONNECT) {
13895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            if (!errcode) {
13905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              ff |= DE_CONNECT;
13915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            } else {
13925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              ff |= DE_CLOSE;
13935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            }
13945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          } else {
13955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            ff |= DE_WRITE;
13965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          }
13975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
13985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
13995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        // Tell the descriptor about the event.
14005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (ff != 0) {
14015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          pdispatcher->OnPreEvent(ff);
14025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          pdispatcher->OnEvent(ff, errcode);
14035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
14045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
14055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
14065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Recalc the time remaining to wait. Doing it here means it doesn't get
14085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // calced twice the first time through the loop
14095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (ptvWait) {
14105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ptvWait->tv_sec = 0;
14115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ptvWait->tv_usec = 0;
14125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      struct timeval tvT;
14135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      gettimeofday(&tvT, NULL);
14145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if ((tvStop.tv_sec > tvT.tv_sec)
14155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          || ((tvStop.tv_sec == tvT.tv_sec)
14165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              && (tvStop.tv_usec > tvT.tv_usec))) {
14175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        ptvWait->tv_sec = tvStop.tv_sec - tvT.tv_sec;
14185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        ptvWait->tv_usec = tvStop.tv_usec - tvT.tv_usec;
14195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (ptvWait->tv_usec < 0) {
14205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          ASSERT(ptvWait->tv_sec > 0);
14215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          ptvWait->tv_usec += 1000000;
14225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          ptvWait->tv_sec -= 1;
14235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
14245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
14255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
14265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
14295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
14305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic void GlobalSignalHandler(int signum) {
14325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  PosixSignalHandler::Instance()->OnPosixSignalReceived(signum);
14335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
14345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool PhysicalSocketServer::SetPosixSignalHandler(int signum,
14365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                                 void (*handler)(int)) {
14375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // If handler is SIG_IGN or SIG_DFL then clear our user-level handler,
14385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // otherwise set one.
14395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (handler == SIG_IGN || handler == SIG_DFL) {
14405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!InstallSignal(signum, handler)) {
14415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
14425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
14435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (signal_dispatcher_) {
14445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      signal_dispatcher_->ClearHandler(signum);
14455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (!signal_dispatcher_->HasHandlers()) {
14465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        signal_dispatcher_.reset();
14475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
14485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
14495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  } else {
14505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!signal_dispatcher_) {
14515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      signal_dispatcher_.reset(new PosixSignalDispatcher(this));
14525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
14535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    signal_dispatcher_->SetHandler(signum, handler);
14545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!InstallSignal(signum, &GlobalSignalHandler)) {
14555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
14565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
14575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
14595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
14605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgDispatcher* PhysicalSocketServer::signal_dispatcher() {
14625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return signal_dispatcher_.get();
14635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
14645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool PhysicalSocketServer::InstallSignal(int signum, void (*handler)(int)) {
14665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  struct sigaction act;
14675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // It doesn't really matter what we set this mask to.
14685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (sigemptyset(&act.sa_mask) != 0) {
14695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_ERR(LS_ERROR) << "Couldn't set mask";
14705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
14715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  act.sa_handler = handler;
14735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Use SA_RESTART so that our syscalls don't get EINTR, since we don't need it
14745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // and it's a nuisance. Though some syscalls still return EINTR and there's no
14755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // real standard for which ones. :(
14765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  act.sa_flags = SA_RESTART;
14775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (sigaction(signum, &act, NULL) != 0) {
14785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_ERR(LS_ERROR) << "Couldn't set sigaction";
14795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
14805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
14825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
14835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // POSIX
14845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#ifdef WIN32
14865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool PhysicalSocketServer::Wait(int cmsWait, bool process_io) {
14875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int cmsTotal = cmsWait;
14885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int cmsElapsed = 0;
14895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  uint32 msStart = Time();
14905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if LOGGING
14925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (last_tick_dispatch_count_ == 0) {
14935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    last_tick_tracked_ = msStart;
14945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
14955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
14965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
14975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  fWait_ = true;
14985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  while (fWait_) {
14995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    std::vector<WSAEVENT> events;
15005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    std::vector<Dispatcher *> event_owners;
15015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    events.push_back(socket_ev_);
15035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    {
15055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CritScope cr(&crit_);
15065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      size_t i = 0;
15075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      iterators_.push_back(&i);
15085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Don't track dispatchers_.size(), because we want to pick up any new
15095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // dispatchers that were added while processing the loop.
15105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      while (i < dispatchers_.size()) {
15115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        Dispatcher* disp = dispatchers_[i++];
15125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (!process_io && (disp != signal_wakeup_))
15135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          continue;
15145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        SOCKET s = disp->GetSocket();
15155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        if (disp->CheckSignalClose()) {
15165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          // We just signalled close, don't poll this socket
15175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        } else if (s != INVALID_SOCKET) {
15185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          WSAEventSelect(s,
15195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                         events[0],
15205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                         FlagsToEvents(disp->GetRequestedEvents()));
15215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        } else {
15225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          events.push_back(disp->GetWSAEvent());
15235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          event_owners.push_back(disp);
15245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
15255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
15265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ASSERT(iterators_.back() == &i);
15275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      iterators_.pop_back();
15285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
15295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Which is shorter, the delay wait or the asked wait?
15315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int cmsNext;
15335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (cmsWait == kForever) {
15345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      cmsNext = cmsWait;
15355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
15365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      cmsNext = _max(0, cmsTotal - cmsElapsed);
15375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
15385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Wait for one of the events to signal
15405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    DWORD dw = WSAWaitForMultipleEvents(static_cast<DWORD>(events.size()),
15415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                        &events[0],
15425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                        false,
15435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                        cmsNext,
15445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                        false);
15455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if 0  // LOGGING
15475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // we track this information purely for logging purposes.
15485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    last_tick_dispatch_count_++;
15495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (last_tick_dispatch_count_ >= 1000) {
15505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      int32 elapsed = TimeSince(last_tick_tracked_);
15515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(INFO) << "PhysicalSocketServer took " << elapsed
15525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                << "ms for 1000 events";
15535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // If we get more than 1000 events in a second, we are spinning badly
15555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // (normally it should take about 8-20 seconds).
15565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ASSERT(elapsed > 1000);
15575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      last_tick_tracked_ = Time();
15595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      last_tick_dispatch_count_ = 0;
15605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
15615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
15625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (dw == WSA_WAIT_FAILED) {
15645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Failed?
15655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // TODO: need a better strategy than this!
15665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      int error = WSAGetLastError();
15675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ASSERT(false);
15685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return false;
15695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else if (dw == WSA_WAIT_TIMEOUT) {
15705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Timeout?
15715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      return true;
15725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    } else {
15735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Figure out which one it is and call it
15745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CritScope cr(&crit_);
15755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      int index = dw - WSA_WAIT_EVENT_0;
15765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (index > 0) {
15775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        --index; // The first event is the socket event
15785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        event_owners[index]->OnPreEvent(0);
15795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        event_owners[index]->OnEvent(0, 0);
15805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      } else if (process_io) {
15815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        size_t i = 0, end = dispatchers_.size();
15825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iterators_.push_back(&i);
15835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iterators_.push_back(&end);  // Don't iterate over new dispatchers.
15845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        while (i < end) {
15855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          Dispatcher* disp = dispatchers_[i++];
15865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          SOCKET s = disp->GetSocket();
15875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          if (s == INVALID_SOCKET)
15885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            continue;
15895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          WSANETWORKEVENTS wsaEvents;
15915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          int err = WSAEnumNetworkEvents(s, events[0], &wsaEvents);
15925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          if (err == 0) {
15935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
15945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#if LOGGING
15955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            {
15965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              if ((wsaEvents.lNetworkEvents & FD_READ) &&
15975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  wsaEvents.iErrorCode[FD_READ_BIT] != 0) {
15985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                LOG(WARNING) << "PhysicalSocketServer got FD_READ_BIT error "
15995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                             << wsaEvents.iErrorCode[FD_READ_BIT];
16005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              }
16015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              if ((wsaEvents.lNetworkEvents & FD_WRITE) &&
16025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  wsaEvents.iErrorCode[FD_WRITE_BIT] != 0) {
16035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                LOG(WARNING) << "PhysicalSocketServer got FD_WRITE_BIT error "
16045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                             << wsaEvents.iErrorCode[FD_WRITE_BIT];
16055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              }
16065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              if ((wsaEvents.lNetworkEvents & FD_CONNECT) &&
16075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  wsaEvents.iErrorCode[FD_CONNECT_BIT] != 0) {
16085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                LOG(WARNING) << "PhysicalSocketServer got FD_CONNECT_BIT error "
16095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                             << wsaEvents.iErrorCode[FD_CONNECT_BIT];
16105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              }
16115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              if ((wsaEvents.lNetworkEvents & FD_ACCEPT) &&
16125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  wsaEvents.iErrorCode[FD_ACCEPT_BIT] != 0) {
16135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                LOG(WARNING) << "PhysicalSocketServer got FD_ACCEPT_BIT error "
16145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                             << wsaEvents.iErrorCode[FD_ACCEPT_BIT];
16155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              }
16165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              if ((wsaEvents.lNetworkEvents & FD_CLOSE) &&
16175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                  wsaEvents.iErrorCode[FD_CLOSE_BIT] != 0) {
16185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                LOG(WARNING) << "PhysicalSocketServer got FD_CLOSE_BIT error "
16195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                             << wsaEvents.iErrorCode[FD_CLOSE_BIT];
16205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              }
16215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            }
16225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif
16235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            uint32 ff = 0;
16245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            int errcode = 0;
16255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            if (wsaEvents.lNetworkEvents & FD_READ)
16265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              ff |= DE_READ;
16275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            if (wsaEvents.lNetworkEvents & FD_WRITE)
16285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              ff |= DE_WRITE;
16295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            if (wsaEvents.lNetworkEvents & FD_CONNECT) {
16305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              if (wsaEvents.iErrorCode[FD_CONNECT_BIT] == 0) {
16315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                ff |= DE_CONNECT;
16325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              } else {
16335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                ff |= DE_CLOSE;
16345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                errcode = wsaEvents.iErrorCode[FD_CONNECT_BIT];
16355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              }
16365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            }
16375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            if (wsaEvents.lNetworkEvents & FD_ACCEPT)
16385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              ff |= DE_ACCEPT;
16395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            if (wsaEvents.lNetworkEvents & FD_CLOSE) {
16405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              ff |= DE_CLOSE;
16415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              errcode = wsaEvents.iErrorCode[FD_CLOSE_BIT];
16425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            }
16435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            if (ff != 0) {
16445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              disp->OnPreEvent(ff);
16455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org              disp->OnEvent(ff, errcode);
16465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org            }
16475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          }
16485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        }
16495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        ASSERT(iterators_.back() == &end);
16505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iterators_.pop_back();
16515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        ASSERT(iterators_.back() == &i);
16525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        iterators_.pop_back();
16535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
16545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
16555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Reset the network event until new activity occurs
16565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      WSAResetEvent(socket_ev_);
16575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
16585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
16595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Break?
16605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (!fWait_)
16615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      break;
16625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    cmsElapsed = TimeSince(msStart);
16635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if ((cmsWait != kForever) && (cmsElapsed >= cmsWait)) {
16645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org       break;
16655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
16665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
16675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
16685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Done
16695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
16705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
16715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#endif  // WIN32
16725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
16735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}  // namespace talk_base
1674