diff options
Diffstat (limited to 'webrtc/base/physicalsocketserver.cc')
-rw-r--r-- | webrtc/base/physicalsocketserver.cc | 1234 |
1 files changed, 603 insertions, 631 deletions
diff --git a/webrtc/base/physicalsocketserver.cc b/webrtc/base/physicalsocketserver.cc index 86abcf279b..3e454527ca 100644 --- a/webrtc/base/physicalsocketserver.cc +++ b/webrtc/base/physicalsocketserver.cc @@ -39,11 +39,11 @@ #include <algorithm> #include <map> +#include "webrtc/base/arraysize.h" #include "webrtc/base/basictypes.h" #include "webrtc/base/byteorder.h" #include "webrtc/base/common.h" #include "webrtc/base/logging.h" -#include "webrtc/base/nethelpers.h" #include "webrtc/base/physicalsocketserver.h" #include "webrtc/base/timeutils.h" #include "webrtc/base/winping.h" @@ -96,463 +96,669 @@ static const int ICMP_HEADER_SIZE = 8u; static const int ICMP_PING_TIMEOUT_MILLIS = 10000u; #endif -class PhysicalSocket : public AsyncSocket, public sigslot::has_slots<> { - public: - PhysicalSocket(PhysicalSocketServer* ss, SOCKET s = INVALID_SOCKET) - : ss_(ss), s_(s), enabled_events_(0), error_(0), - state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED), - resolver_(NULL) { +PhysicalSocket::PhysicalSocket(PhysicalSocketServer* ss, SOCKET s) + : ss_(ss), s_(s), enabled_events_(0), error_(0), + state_((s == INVALID_SOCKET) ? CS_CLOSED : CS_CONNECTED), + resolver_(nullptr) { #if defined(WEBRTC_WIN) - // EnsureWinsockInit() ensures that winsock is initialized. The default - // version of this function doesn't do anything because winsock is - // initialized by constructor of a static object. If neccessary libjingle - // users can link it with a different version of this function by replacing - // win32socketinit.cc. See win32socketinit.cc for more details. - EnsureWinsockInit(); + // EnsureWinsockInit() ensures that winsock is initialized. The default + // version of this function doesn't do anything because winsock is + // initialized by constructor of a static object. If neccessary libjingle + // users can link it with a different version of this function by replacing + // win32socketinit.cc. See win32socketinit.cc for more details. + EnsureWinsockInit(); #endif - if (s_ != INVALID_SOCKET) { - enabled_events_ = DE_READ | DE_WRITE; + if (s_ != INVALID_SOCKET) { + enabled_events_ = DE_READ | DE_WRITE; - int type = SOCK_STREAM; - socklen_t len = sizeof(type); - VERIFY(0 == getsockopt(s_, SOL_SOCKET, SO_TYPE, (SockOptArg)&type, &len)); - udp_ = (SOCK_DGRAM == type); - } + int type = SOCK_STREAM; + socklen_t len = sizeof(type); + VERIFY(0 == getsockopt(s_, SOL_SOCKET, SO_TYPE, (SockOptArg)&type, &len)); + udp_ = (SOCK_DGRAM == type); } +} - ~PhysicalSocket() override { - Close(); - } +PhysicalSocket::~PhysicalSocket() { + Close(); +} - // Creates the underlying OS socket (same as the "socket" function). - virtual bool Create(int family, int type) { - Close(); - s_ = ::socket(family, type, 0); - udp_ = (SOCK_DGRAM == type); - UpdateLastError(); - if (udp_) - enabled_events_ = DE_READ | DE_WRITE; - return s_ != INVALID_SOCKET; - } - - SocketAddress GetLocalAddress() const override { - sockaddr_storage addr_storage = {0}; - socklen_t addrlen = sizeof(addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - int result = ::getsockname(s_, addr, &addrlen); - SocketAddress address; - if (result >= 0) { - SocketAddressFromSockAddrStorage(addr_storage, &address); - } else { - LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket=" - << s_; - } - return address; - } +bool PhysicalSocket::Create(int family, int type) { + Close(); + s_ = ::socket(family, type, 0); + udp_ = (SOCK_DGRAM == type); + UpdateLastError(); + if (udp_) + enabled_events_ = DE_READ | DE_WRITE; + return s_ != INVALID_SOCKET; +} - SocketAddress GetRemoteAddress() const override { - sockaddr_storage addr_storage = {0}; - socklen_t addrlen = sizeof(addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - int result = ::getpeername(s_, addr, &addrlen); - SocketAddress address; - if (result >= 0) { - SocketAddressFromSockAddrStorage(addr_storage, &address); - } else { - LOG(LS_WARNING) << "GetRemoteAddress: unable to get remote addr, socket=" - << s_; - } - return address; +SocketAddress PhysicalSocket::GetLocalAddress() const { + sockaddr_storage addr_storage = {0}; + socklen_t addrlen = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int result = ::getsockname(s_, addr, &addrlen); + SocketAddress address; + if (result >= 0) { + SocketAddressFromSockAddrStorage(addr_storage, &address); + } else { + LOG(LS_WARNING) << "GetLocalAddress: unable to get local addr, socket=" + << s_; } + return address; +} - int Bind(const SocketAddress& bind_addr) override { - sockaddr_storage addr_storage; - size_t len = bind_addr.ToSockAddrStorage(&addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - int err = ::bind(s_, addr, static_cast<int>(len)); - UpdateLastError(); -#ifdef _DEBUG - if (0 == err) { - dbg_addr_ = "Bound @ "; - dbg_addr_.append(GetLocalAddress().ToString()); - } -#endif // _DEBUG - return err; +SocketAddress PhysicalSocket::GetRemoteAddress() const { + sockaddr_storage addr_storage = {0}; + socklen_t addrlen = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int result = ::getpeername(s_, addr, &addrlen); + SocketAddress address; + if (result >= 0) { + SocketAddressFromSockAddrStorage(addr_storage, &address); + } else { + LOG(LS_WARNING) << "GetRemoteAddress: unable to get remote addr, socket=" + << s_; } + return address; +} - int Connect(const SocketAddress& addr) override { - // TODO: Implicit creation is required to reconnect... - // ...but should we make it more explicit? - if (state_ != CS_CLOSED) { - SetError(EALREADY); - return SOCKET_ERROR; - } - if (addr.IsUnresolved()) { - LOG(LS_VERBOSE) << "Resolving addr in PhysicalSocket::Connect"; - resolver_ = new AsyncResolver(); - resolver_->SignalDone.connect(this, &PhysicalSocket::OnResolveResult); - resolver_->Start(addr); - state_ = CS_CONNECTING; - return 0; - } - - return DoConnect(addr); +int PhysicalSocket::Bind(const SocketAddress& bind_addr) { + sockaddr_storage addr_storage; + size_t len = bind_addr.ToSockAddrStorage(&addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int err = ::bind(s_, addr, static_cast<int>(len)); + UpdateLastError(); +#if !defined(NDEBUG) + if (0 == err) { + dbg_addr_ = "Bound @ "; + dbg_addr_.append(GetLocalAddress().ToString()); } +#endif + return err; +} - int DoConnect(const SocketAddress& connect_addr) { - if ((s_ == INVALID_SOCKET) && - !Create(connect_addr.family(), SOCK_STREAM)) { - return SOCKET_ERROR; - } - sockaddr_storage addr_storage; - size_t len = connect_addr.ToSockAddrStorage(&addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - int err = ::connect(s_, addr, static_cast<int>(len)); - UpdateLastError(); - if (err == 0) { - state_ = CS_CONNECTED; - } else if (IsBlockingError(GetError())) { - state_ = CS_CONNECTING; - enabled_events_ |= DE_CONNECT; - } else { - return SOCKET_ERROR; - } - - enabled_events_ |= DE_READ | DE_WRITE; +int PhysicalSocket::Connect(const SocketAddress& addr) { + // TODO(pthatcher): Implicit creation is required to reconnect... + // ...but should we make it more explicit? + if (state_ != CS_CLOSED) { + SetError(EALREADY); + return SOCKET_ERROR; + } + if (addr.IsUnresolvedIP()) { + LOG(LS_VERBOSE) << "Resolving addr in PhysicalSocket::Connect"; + resolver_ = new AsyncResolver(); + resolver_->SignalDone.connect(this, &PhysicalSocket::OnResolveResult); + resolver_->Start(addr); + state_ = CS_CONNECTING; return 0; } - int GetError() const override { - CritScope cs(&crit_); - return error_; - } + return DoConnect(addr); +} - void SetError(int error) override { - CritScope cs(&crit_); - error_ = error; +int PhysicalSocket::DoConnect(const SocketAddress& connect_addr) { + if ((s_ == INVALID_SOCKET) && + !Create(connect_addr.family(), SOCK_STREAM)) { + return SOCKET_ERROR; + } + sockaddr_storage addr_storage; + size_t len = connect_addr.ToSockAddrStorage(&addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int err = ::connect(s_, addr, static_cast<int>(len)); + UpdateLastError(); + if (err == 0) { + state_ = CS_CONNECTED; + } else if (IsBlockingError(GetError())) { + state_ = CS_CONNECTING; + enabled_events_ |= DE_CONNECT; + } else { + return SOCKET_ERROR; } - ConnState GetState() const override { return state_; } + enabled_events_ |= DE_READ | DE_WRITE; + return 0; +} - int GetOption(Option opt, int* value) override { - int slevel; - int sopt; - if (TranslateOption(opt, &slevel, &sopt) == -1) - return -1; - socklen_t optlen = sizeof(*value); - int ret = ::getsockopt(s_, slevel, sopt, (SockOptArg)value, &optlen); - if (ret != -1 && opt == OPT_DONTFRAGMENT) { +int PhysicalSocket::GetError() const { + CritScope cs(&crit_); + return error_; +} + +void PhysicalSocket::SetError(int error) { + CritScope cs(&crit_); + error_ = error; +} + +AsyncSocket::ConnState PhysicalSocket::GetState() const { + return state_; +} + +int PhysicalSocket::GetOption(Option opt, int* value) { + int slevel; + int sopt; + if (TranslateOption(opt, &slevel, &sopt) == -1) + return -1; + socklen_t optlen = sizeof(*value); + int ret = ::getsockopt(s_, slevel, sopt, (SockOptArg)value, &optlen); + if (ret != -1 && opt == OPT_DONTFRAGMENT) { #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) - *value = (*value != IP_PMTUDISC_DONT) ? 1 : 0; + *value = (*value != IP_PMTUDISC_DONT) ? 1 : 0; #endif - } - return ret; } + return ret; +} - int SetOption(Option opt, int value) override { - int slevel; - int sopt; - if (TranslateOption(opt, &slevel, &sopt) == -1) - return -1; - if (opt == OPT_DONTFRAGMENT) { +int PhysicalSocket::SetOption(Option opt, int value) { + int slevel; + int sopt; + if (TranslateOption(opt, &slevel, &sopt) == -1) + return -1; + if (opt == OPT_DONTFRAGMENT) { #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) - value = (value) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; + value = (value) ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; #endif - } - return ::setsockopt(s_, slevel, sopt, (SockOptArg)&value, sizeof(value)); } + return ::setsockopt(s_, slevel, sopt, (SockOptArg)&value, sizeof(value)); +} - int Send(const void* pv, size_t cb) override { - int sent = ::send(s_, reinterpret_cast<const char *>(pv), (int)cb, +int PhysicalSocket::Send(const void* pv, size_t cb) { + int sent = ::send(s_, reinterpret_cast<const char *>(pv), (int)cb, #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) - // Suppress SIGPIPE. Without this, attempting to send on a socket whose - // other end is closed will result in a SIGPIPE signal being raised to - // our process, which by default will terminate the process, which we - // don't want. By specifying this flag, we'll just get the error EPIPE - // instead and can handle the error gracefully. - MSG_NOSIGNAL + // Suppress SIGPIPE. Without this, attempting to send on a socket whose + // other end is closed will result in a SIGPIPE signal being raised to + // our process, which by default will terminate the process, which we + // don't want. By specifying this flag, we'll just get the error EPIPE + // instead and can handle the error gracefully. + MSG_NOSIGNAL #else - 0 + 0 #endif - ); - UpdateLastError(); - MaybeRemapSendError(); - // We have seen minidumps where this may be false. - ASSERT(sent <= static_cast<int>(cb)); - if ((sent < 0) && IsBlockingError(GetError())) { - enabled_events_ |= DE_WRITE; - } - return sent; - } + ); + UpdateLastError(); + MaybeRemapSendError(); + // We have seen minidumps where this may be false. + ASSERT(sent <= static_cast<int>(cb)); + if ((sent < 0) && IsBlockingError(GetError())) { + enabled_events_ |= DE_WRITE; + } + return sent; +} - int SendTo(const void* buffer, - size_t length, - const SocketAddress& addr) override { - sockaddr_storage saddr; - size_t len = addr.ToSockAddrStorage(&saddr); - int sent = ::sendto( - s_, static_cast<const char *>(buffer), static_cast<int>(length), +int PhysicalSocket::SendTo(const void* buffer, + size_t length, + const SocketAddress& addr) { + sockaddr_storage saddr; + size_t len = addr.ToSockAddrStorage(&saddr); + int sent = ::sendto( + s_, static_cast<const char *>(buffer), static_cast<int>(length), #if defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) - // Suppress SIGPIPE. See above for explanation. - MSG_NOSIGNAL, + // Suppress SIGPIPE. See above for explanation. + MSG_NOSIGNAL, #else - 0, + 0, #endif - reinterpret_cast<sockaddr*>(&saddr), static_cast<int>(len)); - UpdateLastError(); - MaybeRemapSendError(); - // We have seen minidumps where this may be false. - ASSERT(sent <= static_cast<int>(length)); - if ((sent < 0) && IsBlockingError(GetError())) { - enabled_events_ |= DE_WRITE; - } - return sent; - } - - int Recv(void* buffer, size_t length) override { - int received = ::recv(s_, static_cast<char*>(buffer), - static_cast<int>(length), 0); - if ((received == 0) && (length != 0)) { - // Note: on graceful shutdown, recv can return 0. In this case, we - // pretend it is blocking, and then signal close, so that simplifying - // assumptions can be made about Recv. - LOG(LS_WARNING) << "EOF from socket; deferring close event"; - // Must turn this back on so that the select() loop will notice the close - // event. - enabled_events_ |= DE_READ; - SetError(EWOULDBLOCK); - return SOCKET_ERROR; - } - UpdateLastError(); - int error = GetError(); - bool success = (received >= 0) || IsBlockingError(error); - if (udp_ || success) { - enabled_events_ |= DE_READ; - } - if (!success) { - LOG_F(LS_VERBOSE) << "Error = " << error; - } - return received; - } + reinterpret_cast<sockaddr*>(&saddr), static_cast<int>(len)); + UpdateLastError(); + MaybeRemapSendError(); + // We have seen minidumps where this may be false. + ASSERT(sent <= static_cast<int>(length)); + if ((sent < 0) && IsBlockingError(GetError())) { + enabled_events_ |= DE_WRITE; + } + return sent; +} - int RecvFrom(void* buffer, size_t length, SocketAddress* out_addr) override { - sockaddr_storage addr_storage; - socklen_t addr_len = sizeof(addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - int received = ::recvfrom(s_, static_cast<char*>(buffer), - static_cast<int>(length), 0, addr, &addr_len); - UpdateLastError(); - if ((received >= 0) && (out_addr != NULL)) - SocketAddressFromSockAddrStorage(addr_storage, out_addr); - int error = GetError(); - bool success = (received >= 0) || IsBlockingError(error); - if (udp_ || success) { - enabled_events_ |= DE_READ; - } - if (!success) { - LOG_F(LS_VERBOSE) << "Error = " << error; - } - return received; - } +int PhysicalSocket::Recv(void* buffer, size_t length) { + int received = ::recv(s_, static_cast<char*>(buffer), + static_cast<int>(length), 0); + if ((received == 0) && (length != 0)) { + // Note: on graceful shutdown, recv can return 0. In this case, we + // pretend it is blocking, and then signal close, so that simplifying + // assumptions can be made about Recv. + LOG(LS_WARNING) << "EOF from socket; deferring close event"; + // Must turn this back on so that the select() loop will notice the close + // event. + enabled_events_ |= DE_READ; + SetError(EWOULDBLOCK); + return SOCKET_ERROR; + } + UpdateLastError(); + int error = GetError(); + bool success = (received >= 0) || IsBlockingError(error); + if (udp_ || success) { + enabled_events_ |= DE_READ; + } + if (!success) { + LOG_F(LS_VERBOSE) << "Error = " << error; + } + return received; +} - int Listen(int backlog) override { - int err = ::listen(s_, backlog); - UpdateLastError(); - if (err == 0) { - state_ = CS_CONNECTING; - enabled_events_ |= DE_ACCEPT; -#ifdef _DEBUG - dbg_addr_ = "Listening @ "; - dbg_addr_.append(GetLocalAddress().ToString()); -#endif // _DEBUG - } - return err; - } +int PhysicalSocket::RecvFrom(void* buffer, + size_t length, + SocketAddress* out_addr) { + sockaddr_storage addr_storage; + socklen_t addr_len = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + int received = ::recvfrom(s_, static_cast<char*>(buffer), + static_cast<int>(length), 0, addr, &addr_len); + UpdateLastError(); + if ((received >= 0) && (out_addr != nullptr)) + SocketAddressFromSockAddrStorage(addr_storage, out_addr); + int error = GetError(); + bool success = (received >= 0) || IsBlockingError(error); + if (udp_ || success) { + enabled_events_ |= DE_READ; + } + if (!success) { + LOG_F(LS_VERBOSE) << "Error = " << error; + } + return received; +} - AsyncSocket* Accept(SocketAddress* out_addr) override { - sockaddr_storage addr_storage; - socklen_t addr_len = sizeof(addr_storage); - sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); - SOCKET s = ::accept(s_, addr, &addr_len); - UpdateLastError(); - if (s == INVALID_SOCKET) - return NULL; +int PhysicalSocket::Listen(int backlog) { + int err = ::listen(s_, backlog); + UpdateLastError(); + if (err == 0) { + state_ = CS_CONNECTING; enabled_events_ |= DE_ACCEPT; - if (out_addr != NULL) - SocketAddressFromSockAddrStorage(addr_storage, out_addr); - return ss_->WrapSocket(s); +#if !defined(NDEBUG) + dbg_addr_ = "Listening @ "; + dbg_addr_.append(GetLocalAddress().ToString()); +#endif } + return err; +} - int Close() override { - if (s_ == INVALID_SOCKET) - return 0; - int err = ::closesocket(s_); - UpdateLastError(); - s_ = INVALID_SOCKET; - state_ = CS_CLOSED; - enabled_events_ = 0; - if (resolver_) { - resolver_->Destroy(false); - resolver_ = NULL; - } - return err; - } +AsyncSocket* PhysicalSocket::Accept(SocketAddress* out_addr) { + // Always re-subscribe DE_ACCEPT to make sure new incoming connections will + // trigger an event even if DoAccept returns an error here. + enabled_events_ |= DE_ACCEPT; + sockaddr_storage addr_storage; + socklen_t addr_len = sizeof(addr_storage); + sockaddr* addr = reinterpret_cast<sockaddr*>(&addr_storage); + SOCKET s = DoAccept(s_, addr, &addr_len); + UpdateLastError(); + if (s == INVALID_SOCKET) + return nullptr; + if (out_addr != nullptr) + SocketAddressFromSockAddrStorage(addr_storage, out_addr); + return ss_->WrapSocket(s); +} - int EstimateMTU(uint16_t* mtu) override { - SocketAddress addr = GetRemoteAddress(); - if (addr.IsAnyIP()) { - SetError(ENOTCONN); - return -1; - } +int PhysicalSocket::Close() { + if (s_ == INVALID_SOCKET) + return 0; + int err = ::closesocket(s_); + UpdateLastError(); + s_ = INVALID_SOCKET; + state_ = CS_CLOSED; + enabled_events_ = 0; + if (resolver_) { + resolver_->Destroy(false); + resolver_ = nullptr; + } + return err; +} + +int PhysicalSocket::EstimateMTU(uint16_t* mtu) { + SocketAddress addr = GetRemoteAddress(); + if (addr.IsAnyIP()) { + SetError(ENOTCONN); + return -1; + } #if defined(WEBRTC_WIN) - // Gets the interface MTU (TTL=1) for the interface used to reach |addr|. - WinPing ping; - if (!ping.IsValid()) { + // Gets the interface MTU (TTL=1) for the interface used to reach |addr|. + WinPing ping; + if (!ping.IsValid()) { + SetError(EINVAL); // can't think of a better error ID + return -1; + } + int header_size = ICMP_HEADER_SIZE; + if (addr.family() == AF_INET6) { + header_size += IPV6_HEADER_SIZE; + } else if (addr.family() == AF_INET) { + header_size += IP_HEADER_SIZE; + } + + for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) { + int32_t size = PACKET_MAXIMUMS[level] - header_size; + WinPing::PingResult result = ping.Ping(addr.ipaddr(), size, + ICMP_PING_TIMEOUT_MILLIS, + 1, false); + if (result == WinPing::PING_FAIL) { SetError(EINVAL); // can't think of a better error ID return -1; + } else if (result != WinPing::PING_TOO_LARGE) { + *mtu = PACKET_MAXIMUMS[level]; + return 0; } - int header_size = ICMP_HEADER_SIZE; - if (addr.family() == AF_INET6) { - header_size += IPV6_HEADER_SIZE; - } else if (addr.family() == AF_INET) { - header_size += IP_HEADER_SIZE; - } - - for (int level = 0; PACKET_MAXIMUMS[level + 1] > 0; ++level) { - int32_t size = PACKET_MAXIMUMS[level] - header_size; - WinPing::PingResult result = ping.Ping(addr.ipaddr(), size, - ICMP_PING_TIMEOUT_MILLIS, - 1, false); - if (result == WinPing::PING_FAIL) { - SetError(EINVAL); // can't think of a better error ID - return -1; - } else if (result != WinPing::PING_TOO_LARGE) { - *mtu = PACKET_MAXIMUMS[level]; - return 0; - } - } + } - ASSERT(false); - return -1; + ASSERT(false); + return -1; #elif defined(WEBRTC_MAC) - // No simple way to do this on Mac OS X. - // SIOCGIFMTU would work if we knew which interface would be used, but - // figuring that out is pretty complicated. For now we'll return an error - // and let the caller pick a default MTU. - SetError(EINVAL); - return -1; + // No simple way to do this on Mac OS X. + // SIOCGIFMTU would work if we knew which interface would be used, but + // figuring that out is pretty complicated. For now we'll return an error + // and let the caller pick a default MTU. + SetError(EINVAL); + return -1; #elif defined(WEBRTC_LINUX) - // Gets the path MTU. - int value; - socklen_t vlen = sizeof(value); - int err = getsockopt(s_, IPPROTO_IP, IP_MTU, &value, &vlen); - if (err < 0) { - UpdateLastError(); - return err; - } + // Gets the path MTU. + int value; + socklen_t vlen = sizeof(value); + int err = getsockopt(s_, IPPROTO_IP, IP_MTU, &value, &vlen); + if (err < 0) { + UpdateLastError(); + return err; + } - ASSERT((0 <= value) && (value <= 65536)); - *mtu = value; - return 0; + ASSERT((0 <= value) && (value <= 65536)); + *mtu = value; + return 0; #elif defined(__native_client__) - // Most socket operations, including this, will fail in NaCl's sandbox. - error_ = EACCES; - return -1; + // Most socket operations, including this, will fail in NaCl's sandbox. + error_ = EACCES; + return -1; #endif - } +} - SocketServer* socketserver() { return ss_; } - protected: - void OnResolveResult(AsyncResolverInterface* resolver) { - if (resolver != resolver_) { - return; - } +SOCKET PhysicalSocket::DoAccept(SOCKET socket, + sockaddr* addr, + socklen_t* addrlen) { + return ::accept(socket, addr, addrlen); +} - int error = resolver_->GetError(); - if (error == 0) { - error = DoConnect(resolver_->address()); - } else { - Close(); - } +void PhysicalSocket::OnResolveResult(AsyncResolverInterface* resolver) { + if (resolver != resolver_) { + return; + } - if (error) { - SetError(error); - SignalCloseEvent(this, error); - } + int error = resolver_->GetError(); + if (error == 0) { + error = DoConnect(resolver_->address()); + } else { + Close(); } - void UpdateLastError() { - SetError(LAST_SYSTEM_ERROR); + if (error) { + SetError(error); + SignalCloseEvent(this, error); } +} - void MaybeRemapSendError() { +void PhysicalSocket::UpdateLastError() { + SetError(LAST_SYSTEM_ERROR); +} + +void PhysicalSocket::MaybeRemapSendError() { #if defined(WEBRTC_MAC) - // https://developer.apple.com/library/mac/documentation/Darwin/ - // Reference/ManPages/man2/sendto.2.html - // ENOBUFS - The output queue for a network interface is full. - // This generally indicates that the interface has stopped sending, - // but may be caused by transient congestion. - if (GetError() == ENOBUFS) { - SetError(EWOULDBLOCK); - } -#endif + // https://developer.apple.com/library/mac/documentation/Darwin/ + // Reference/ManPages/man2/sendto.2.html + // ENOBUFS - The output queue for a network interface is full. + // This generally indicates that the interface has stopped sending, + // but may be caused by transient congestion. + if (GetError() == ENOBUFS) { + SetError(EWOULDBLOCK); } +#endif +} - static int TranslateOption(Option opt, int* slevel, int* sopt) { - switch (opt) { - case OPT_DONTFRAGMENT: +int PhysicalSocket::TranslateOption(Option opt, int* slevel, int* sopt) { + switch (opt) { + case OPT_DONTFRAGMENT: #if defined(WEBRTC_WIN) - *slevel = IPPROTO_IP; - *sopt = IP_DONTFRAGMENT; - break; + *slevel = IPPROTO_IP; + *sopt = IP_DONTFRAGMENT; + break; #elif defined(WEBRTC_MAC) || defined(BSD) || defined(__native_client__) - LOG(LS_WARNING) << "Socket::OPT_DONTFRAGMENT not supported."; - return -1; + LOG(LS_WARNING) << "Socket::OPT_DONTFRAGMENT not supported."; + return -1; +#elif defined(WEBRTC_POSIX) + *slevel = IPPROTO_IP; + *sopt = IP_MTU_DISCOVER; + break; +#endif + case OPT_RCVBUF: + *slevel = SOL_SOCKET; + *sopt = SO_RCVBUF; + break; + case OPT_SNDBUF: + *slevel = SOL_SOCKET; + *sopt = SO_SNDBUF; + break; + case OPT_NODELAY: + *slevel = IPPROTO_TCP; + *sopt = TCP_NODELAY; + break; + case OPT_DSCP: + LOG(LS_WARNING) << "Socket::OPT_DSCP not supported."; + return -1; + case OPT_RTP_SENDTIME_EXTN_ID: + return -1; // No logging is necessary as this not a OS socket option. + default: + ASSERT(false); + return -1; + } + return 0; +} + +SocketDispatcher::SocketDispatcher(PhysicalSocketServer *ss) +#if defined(WEBRTC_WIN) + : PhysicalSocket(ss), id_(0), signal_close_(false) +#else + : PhysicalSocket(ss) +#endif +{ +} + +SocketDispatcher::SocketDispatcher(SOCKET s, PhysicalSocketServer *ss) +#if defined(WEBRTC_WIN) + : PhysicalSocket(ss, s), id_(0), signal_close_(false) +#else + : PhysicalSocket(ss, s) +#endif +{ +} + +SocketDispatcher::~SocketDispatcher() { + Close(); +} + +bool SocketDispatcher::Initialize() { + ASSERT(s_ != INVALID_SOCKET); + // Must be a non-blocking +#if defined(WEBRTC_WIN) + u_long argp = 1; + ioctlsocket(s_, FIONBIO, &argp); #elif defined(WEBRTC_POSIX) - *slevel = IPPROTO_IP; - *sopt = IP_MTU_DISCOVER; - break; + fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK); +#endif + ss_->Add(this); + return true; +} + +bool SocketDispatcher::Create(int type) { + return Create(AF_INET, type); +} + +bool SocketDispatcher::Create(int family, int type) { + // Change the socket to be non-blocking. + if (!PhysicalSocket::Create(family, type)) + return false; + + if (!Initialize()) + return false; + +#if defined(WEBRTC_WIN) + do { id_ = ++next_id_; } while (id_ == 0); #endif - case OPT_RCVBUF: - *slevel = SOL_SOCKET; - *sopt = SO_RCVBUF; - break; - case OPT_SNDBUF: - *slevel = SOL_SOCKET; - *sopt = SO_SNDBUF; - break; - case OPT_NODELAY: - *slevel = IPPROTO_TCP; - *sopt = TCP_NODELAY; - break; - case OPT_DSCP: - LOG(LS_WARNING) << "Socket::OPT_DSCP not supported."; - return -1; - case OPT_RTP_SENDTIME_EXTN_ID: - return -1; // No logging is necessary as this not a OS socket option. + return true; +} + +#if defined(WEBRTC_WIN) + +WSAEVENT SocketDispatcher::GetWSAEvent() { + return WSA_INVALID_EVENT; +} + +SOCKET SocketDispatcher::GetSocket() { + return s_; +} + +bool SocketDispatcher::CheckSignalClose() { + if (!signal_close_) + return false; + + char ch; + if (recv(s_, &ch, 1, MSG_PEEK) > 0) + return false; + + state_ = CS_CLOSED; + signal_close_ = false; + SignalCloseEvent(this, signal_err_); + return true; +} + +int SocketDispatcher::next_id_ = 0; + +#elif defined(WEBRTC_POSIX) + +int SocketDispatcher::GetDescriptor() { + return s_; +} + +bool SocketDispatcher::IsDescriptorClosed() { + // We don't have a reliable way of distinguishing end-of-stream + // from readability. So test on each readable call. Is this + // inefficient? Probably. + char ch; + ssize_t res = ::recv(s_, &ch, 1, MSG_PEEK); + if (res > 0) { + // Data available, so not closed. + return false; + } else if (res == 0) { + // EOF, so closed. + return true; + } else { // error + switch (errno) { + // Returned if we've already closed s_. + case EBADF: + // Returned during ungraceful peer shutdown. + case ECONNRESET: + return true; default: - ASSERT(false); - return -1; + // Assume that all other errors are just blocking errors, meaning the + // connection is still good but we just can't read from it right now. + // This should only happen when connecting (and at most once), because + // in all other cases this function is only called if the file + // descriptor is already known to be in the readable state. However, + // it's not necessary a problem if we spuriously interpret a + // "connection lost"-type error as a blocking error, because typically + // the next recv() will get EOF, so we'll still eventually notice that + // the socket is closed. + LOG_ERR(LS_WARNING) << "Assuming benign blocking error"; + return false; } - return 0; } +} - PhysicalSocketServer* ss_; - SOCKET s_; - uint8_t enabled_events_; - bool udp_; - int error_; - // Protects |error_| that is accessed from different threads. - mutable CriticalSection crit_; - ConnState state_; - AsyncResolver* resolver_; - -#ifdef _DEBUG - std::string dbg_addr_; -#endif // _DEBUG; -}; +#endif // WEBRTC_POSIX + +uint32_t SocketDispatcher::GetRequestedEvents() { + return enabled_events_; +} + +void SocketDispatcher::OnPreEvent(uint32_t ff) { + if ((ff & DE_CONNECT) != 0) + state_ = CS_CONNECTED; + +#if defined(WEBRTC_WIN) + // We set CS_CLOSED from CheckSignalClose. +#elif defined(WEBRTC_POSIX) + if ((ff & DE_CLOSE) != 0) + state_ = CS_CLOSED; +#endif +} + +#if defined(WEBRTC_WIN) + +void SocketDispatcher::OnEvent(uint32_t ff, int err) { + int cache_id = id_; + // Make sure we deliver connect/accept first. Otherwise, consumers may see + // something like a READ followed by a CONNECT, which would be odd. + if (((ff & DE_CONNECT) != 0) && (id_ == cache_id)) { + if (ff != DE_CONNECT) + LOG(LS_VERBOSE) << "Signalled with DE_CONNECT: " << ff; + enabled_events_ &= ~DE_CONNECT; +#if !defined(NDEBUG) + dbg_addr_ = "Connected @ "; + dbg_addr_.append(GetRemoteAddress().ToString()); +#endif + SignalConnectEvent(this); + } + if (((ff & DE_ACCEPT) != 0) && (id_ == cache_id)) { + enabled_events_ &= ~DE_ACCEPT; + SignalReadEvent(this); + } + if ((ff & DE_READ) != 0) { + enabled_events_ &= ~DE_READ; + SignalReadEvent(this); + } + if (((ff & DE_WRITE) != 0) && (id_ == cache_id)) { + enabled_events_ &= ~DE_WRITE; + SignalWriteEvent(this); + } + if (((ff & DE_CLOSE) != 0) && (id_ == cache_id)) { + signal_close_ = true; + signal_err_ = err; + } +} + +#elif defined(WEBRTC_POSIX) + +void SocketDispatcher::OnEvent(uint32_t ff, int err) { + // Make sure we deliver connect/accept first. Otherwise, consumers may see + // something like a READ followed by a CONNECT, which would be odd. + if ((ff & DE_CONNECT) != 0) { + enabled_events_ &= ~DE_CONNECT; + SignalConnectEvent(this); + } + if ((ff & DE_ACCEPT) != 0) { + enabled_events_ &= ~DE_ACCEPT; + SignalReadEvent(this); + } + if ((ff & DE_READ) != 0) { + enabled_events_ &= ~DE_READ; + SignalReadEvent(this); + } + if ((ff & DE_WRITE) != 0) { + enabled_events_ &= ~DE_WRITE; + SignalWriteEvent(this); + } + if ((ff & DE_CLOSE) != 0) { + // The socket is now dead to us, so stop checking it. + enabled_events_ = 0; + SignalCloseEvent(this, err); + } +} + +#endif // WEBRTC_POSIX + +int SocketDispatcher::Close() { + if (s_ == INVALID_SOCKET) + return 0; + +#if defined(WEBRTC_WIN) + id_ = 0; + signal_close_ = false; +#endif + ss_->Remove(this); + return PhysicalSocket::Close(); +} #if defined(WEBRTC_POSIX) class EventDispatcher : public Dispatcher { @@ -628,8 +834,8 @@ class PosixSignalHandler { // Returns true if the given signal number is set. bool IsSignalSet(int signum) const { - ASSERT(signum < ARRAY_SIZE(received_signal_)); - if (signum < ARRAY_SIZE(received_signal_)) { + ASSERT(signum < static_cast<int>(arraysize(received_signal_))); + if (signum < static_cast<int>(arraysize(received_signal_))) { return received_signal_[signum]; } else { return false; @@ -638,8 +844,8 @@ class PosixSignalHandler { // Clears the given signal number. void ClearSignal(int signum) { - ASSERT(signum < ARRAY_SIZE(received_signal_)); - if (signum < ARRAY_SIZE(received_signal_)) { + ASSERT(signum < static_cast<int>(arraysize(received_signal_))); + if (signum < static_cast<int>(arraysize(received_signal_))) { received_signal_[signum] = false; } } @@ -654,7 +860,7 @@ class PosixSignalHandler { // user-level state of the process, since the handler could be executed at any // time on any thread. void OnPosixSignalReceived(int signum) { - if (signum >= ARRAY_SIZE(received_signal_)) { + if (signum >= static_cast<int>(arraysize(received_signal_))) { // We don't have space in our array for this. return; } @@ -790,116 +996,6 @@ class PosixSignalDispatcher : public Dispatcher { PhysicalSocketServer *owner_; }; -class SocketDispatcher : public Dispatcher, public PhysicalSocket { - public: - explicit SocketDispatcher(PhysicalSocketServer *ss) : PhysicalSocket(ss) { - } - SocketDispatcher(SOCKET s, PhysicalSocketServer *ss) : PhysicalSocket(ss, s) { - } - - ~SocketDispatcher() override { - Close(); - } - - bool Initialize() { - ss_->Add(this); - fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK); - return true; - } - - virtual bool Create(int type) { - return Create(AF_INET, type); - } - - bool Create(int family, int type) override { - // Change the socket to be non-blocking. - if (!PhysicalSocket::Create(family, type)) - return false; - - return Initialize(); - } - - int GetDescriptor() override { return s_; } - - bool IsDescriptorClosed() override { - // We don't have a reliable way of distinguishing end-of-stream - // from readability. So test on each readable call. Is this - // inefficient? Probably. - char ch; - ssize_t res = ::recv(s_, &ch, 1, MSG_PEEK); - if (res > 0) { - // Data available, so not closed. - return false; - } else if (res == 0) { - // EOF, so closed. - return true; - } else { // error - switch (errno) { - // Returned if we've already closed s_. - case EBADF: - // Returned during ungraceful peer shutdown. - case ECONNRESET: - return true; - default: - // Assume that all other errors are just blocking errors, meaning the - // connection is still good but we just can't read from it right now. - // This should only happen when connecting (and at most once), because - // in all other cases this function is only called if the file - // descriptor is already known to be in the readable state. However, - // it's not necessary a problem if we spuriously interpret a - // "connection lost"-type error as a blocking error, because typically - // the next recv() will get EOF, so we'll still eventually notice that - // the socket is closed. - LOG_ERR(LS_WARNING) << "Assuming benign blocking error"; - return false; - } - } - } - - uint32_t GetRequestedEvents() override { return enabled_events_; } - - void OnPreEvent(uint32_t ff) override { - if ((ff & DE_CONNECT) != 0) - state_ = CS_CONNECTED; - if ((ff & DE_CLOSE) != 0) - state_ = CS_CLOSED; - } - - void OnEvent(uint32_t ff, int err) override { - // Make sure we deliver connect/accept first. Otherwise, consumers may see - // something like a READ followed by a CONNECT, which would be odd. - if ((ff & DE_CONNECT) != 0) { - enabled_events_ &= ~DE_CONNECT; - SignalConnectEvent(this); - } - if ((ff & DE_ACCEPT) != 0) { - enabled_events_ &= ~DE_ACCEPT; - SignalReadEvent(this); - } - if ((ff & DE_READ) != 0) { - enabled_events_ &= ~DE_READ; - SignalReadEvent(this); - } - if ((ff & DE_WRITE) != 0) { - enabled_events_ &= ~DE_WRITE; - SignalWriteEvent(this); - } - if ((ff & DE_CLOSE) != 0) { - // The socket is now dead to us, so stop checking it. - enabled_events_ = 0; - SignalCloseEvent(this, err); - } - } - - int Close() override { - if (s_ == INVALID_SOCKET) - return 0; - - ss_->Remove(this); - return PhysicalSocket::Close(); - } -}; - class FileDispatcher: public Dispatcher, public AsyncFile { public: FileDispatcher(int fd, PhysicalSocketServer *ss) : ss_(ss), fd_(fd) { @@ -1013,130 +1109,6 @@ private: PhysicalSocketServer* ss_; WSAEVENT hev_; }; - -class SocketDispatcher : public Dispatcher, public PhysicalSocket { - public: - static int next_id_; - int id_; - bool signal_close_; - int signal_err_; - - SocketDispatcher(PhysicalSocketServer* ss) - : PhysicalSocket(ss), - id_(0), - signal_close_(false) { - } - - SocketDispatcher(SOCKET s, PhysicalSocketServer* ss) - : PhysicalSocket(ss, s), - id_(0), - signal_close_(false) { - } - - virtual ~SocketDispatcher() { - Close(); - } - - bool Initialize() { - ASSERT(s_ != INVALID_SOCKET); - // Must be a non-blocking - u_long argp = 1; - ioctlsocket(s_, FIONBIO, &argp); - ss_->Add(this); - return true; - } - - virtual bool Create(int type) { - return Create(AF_INET, type); - } - - virtual bool Create(int family, int type) { - // Create socket - if (!PhysicalSocket::Create(family, type)) - return false; - - if (!Initialize()) - return false; - - do { id_ = ++next_id_; } while (id_ == 0); - return true; - } - - virtual int Close() { - if (s_ == INVALID_SOCKET) - return 0; - - id_ = 0; - signal_close_ = false; - ss_->Remove(this); - return PhysicalSocket::Close(); - } - - virtual uint32_t GetRequestedEvents() { return enabled_events_; } - - virtual void OnPreEvent(uint32_t ff) { - if ((ff & DE_CONNECT) != 0) - state_ = CS_CONNECTED; - // We set CS_CLOSED from CheckSignalClose. - } - - virtual void OnEvent(uint32_t ff, int err) { - int cache_id = id_; - // Make sure we deliver connect/accept first. Otherwise, consumers may see - // something like a READ followed by a CONNECT, which would be odd. - if (((ff & DE_CONNECT) != 0) && (id_ == cache_id)) { - if (ff != DE_CONNECT) - LOG(LS_VERBOSE) << "Signalled with DE_CONNECT: " << ff; - enabled_events_ &= ~DE_CONNECT; -#ifdef _DEBUG - dbg_addr_ = "Connected @ "; - dbg_addr_.append(GetRemoteAddress().ToString()); -#endif // _DEBUG - SignalConnectEvent(this); - } - if (((ff & DE_ACCEPT) != 0) && (id_ == cache_id)) { - enabled_events_ &= ~DE_ACCEPT; - SignalReadEvent(this); - } - if ((ff & DE_READ) != 0) { - enabled_events_ &= ~DE_READ; - SignalReadEvent(this); - } - if (((ff & DE_WRITE) != 0) && (id_ == cache_id)) { - enabled_events_ &= ~DE_WRITE; - SignalWriteEvent(this); - } - if (((ff & DE_CLOSE) != 0) && (id_ == cache_id)) { - signal_close_ = true; - signal_err_ = err; - } - } - - virtual WSAEVENT GetWSAEvent() { - return WSA_INVALID_EVENT; - } - - virtual SOCKET GetSocket() { - return s_; - } - - virtual bool CheckSignalClose() { - if (!signal_close_) - return false; - - char ch; - if (recv(s_, &ch, 1, MSG_PEEK) > 0) - return false; - - state_ = CS_CLOSED; - signal_close_ = false; - SignalCloseEvent(this, signal_err_); - return true; - } -}; - -int SocketDispatcher::next_id_ = 0; - #endif // WEBRTC_WIN // Sets the value of a boolean value to false when signaled. @@ -1189,7 +1161,7 @@ Socket* PhysicalSocketServer::CreateSocket(int family, int type) { return socket; } else { delete socket; - return 0; + return nullptr; } } @@ -1203,7 +1175,7 @@ AsyncSocket* PhysicalSocketServer::CreateAsyncSocket(int family, int type) { return dispatcher; } else { delete dispatcher; - return 0; + return nullptr; } } @@ -1213,7 +1185,7 @@ AsyncSocket* PhysicalSocketServer::WrapSocket(SOCKET s) { return dispatcher; } else { delete dispatcher; - return 0; + return nullptr; } } @@ -1342,7 +1314,7 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) { int errcode = 0; // Reap any error code, which can be signaled through reads or writes. - // TODO: Should we set errcode if getsockopt fails? + // TODO(pthatcher): Should we set errcode if getsockopt fails? if (FD_ISSET(fd, &fdsRead) || FD_ISSET(fd, &fdsWrite)) { socklen_t len = sizeof(errcode); ::getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &len); @@ -1351,7 +1323,7 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) { // Check readable descriptors. If we're waiting on an accept, signal // that. Otherwise we're waiting for data, check to see if we're // readable or really closed. - // TODO: Only peek at TCP descriptors. + // TODO(pthatcher): Only peek at TCP descriptors. if (FD_ISSET(fd, &fdsRead)) { FD_CLR(fd, &fdsRead); if (pdispatcher->GetRequestedEvents() & DE_ACCEPT) { @@ -1525,7 +1497,7 @@ bool PhysicalSocketServer::Wait(int cmsWait, bool process_io) { if (dw == WSA_WAIT_FAILED) { // Failed? - // TODO: need a better strategy than this! + // TODO(pthatcher): need a better strategy than this! WSAGetLastError(); ASSERT(false); return false; |