Chromium Code Reviews| Index: webrtc/base/physicalsocketserver.cc |
| diff --git a/webrtc/base/physicalsocketserver.cc b/webrtc/base/physicalsocketserver.cc |
| index 524617221c894ee8d5530d4167f1a45ac9b3f387..3e454527ca80f3e86282d129cdb403fc5b5c5370 100644 |
| --- a/webrtc/base/physicalsocketserver.cc |
| +++ b/webrtc/base/physicalsocketserver.cc |
| @@ -546,6 +546,220 @@ int PhysicalSocket::TranslateOption(Option opt, int* slevel, int* sopt) { |
| 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) |
| + 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 |
| + return true; |
| +} |
| + |
| +#if defined(WEBRTC_WIN) |
| + |
| +WSAEVENT SocketDispatcher::GetWSAEvent() { |
| + return WSA_INVALID_EVENT; |
| +} |
| + |
| +SOCKET SocketDispatcher::GetSocket() { |
|
joachim
2015/12/20 15:27:32
This could probably be further merged with GetDesc
|
| + 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: |
| + // 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; |
| + } |
| + } |
| +} |
| + |
| +#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 { |
| public: |
| @@ -782,120 +996,6 @@ class PosixSignalDispatcher : public Dispatcher { |
| PhysicalSocketServer *owner_; |
| }; |
| -SocketDispatcher::SocketDispatcher(PhysicalSocketServer *ss) |
| - : PhysicalSocket(ss) { |
| -} |
| - |
| -SocketDispatcher::SocketDispatcher(SOCKET s, PhysicalSocketServer *ss) |
| - : PhysicalSocket(ss, s) { |
| -} |
| - |
| -SocketDispatcher::~SocketDispatcher() { |
| - Close(); |
| -} |
| - |
| -bool SocketDispatcher::Initialize() { |
| - ss_->Add(this); |
| - fcntl(s_, F_SETFL, fcntl(s_, F_GETFL, 0) | O_NONBLOCK); |
| - 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; |
| - |
| - return Initialize(); |
| -} |
| - |
| -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: |
| - // 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 SocketDispatcher::GetRequestedEvents() { |
| - return enabled_events_; |
| -} |
| - |
| -void SocketDispatcher::OnPreEvent(uint32_t ff) { |
| - if ((ff & DE_CONNECT) != 0) |
| - state_ = CS_CONNECTED; |
| - if ((ff & DE_CLOSE) != 0) |
| - state_ = CS_CLOSED; |
| -} |
| - |
| -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); |
| - } |
| -} |
| - |
| -int SocketDispatcher::Close() { |
| - 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) { |
| @@ -1009,124 +1109,6 @@ private: |
| PhysicalSocketServer* ss_; |
| WSAEVENT hev_; |
| }; |
| - |
| -SocketDispatcher::SocketDispatcher(PhysicalSocketServer* ss) |
| - : PhysicalSocket(ss), |
| - id_(0), |
| - signal_close_(false) { |
| -} |
| - |
| -SocketDispatcher::SocketDispatcher(SOCKET s, PhysicalSocketServer* ss) |
| - : PhysicalSocket(ss, s), |
| - id_(0), |
| - signal_close_(false) { |
| -} |
| - |
| -SocketDispatcher::~SocketDispatcher() { |
| - Close(); |
| -} |
| - |
| -bool SocketDispatcher::Initialize() { |
| - ASSERT(s_ != INVALID_SOCKET); |
| - // Must be a non-blocking |
| - u_long argp = 1; |
| - ioctlsocket(s_, FIONBIO, &argp); |
| - ss_->Add(this); |
| - return true; |
| -} |
| - |
| -bool SocketDispatcher::Create(int type) { |
| - return Create(AF_INET, type); |
| -} |
| - |
| -bool SocketDispatcher::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; |
| -} |
| - |
| -int SocketDispatcher::Close() { |
| - if (s_ == INVALID_SOCKET) |
| - return 0; |
| - |
| - id_ = 0; |
| - signal_close_ = false; |
| - ss_->Remove(this); |
| - return PhysicalSocket::Close(); |
| -} |
| - |
| -uint32_t SocketDispatcher::GetRequestedEvents() { |
| - return enabled_events_; |
| -} |
| - |
| -void SocketDispatcher::OnPreEvent(uint32_t ff) { |
| - if ((ff & DE_CONNECT) != 0) |
| - state_ = CS_CONNECTED; |
| - // We set CS_CLOSED from CheckSignalClose. |
| -} |
| - |
| -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; |
| - } |
| -} |
| - |
| -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; |
| - |
| #endif // WEBRTC_WIN |
| // Sets the value of a boolean value to false when signaled. |