From cf0045a48320154dd1aa26fcfb8d1395fe2b3aac Mon Sep 17 00:00:00 2001 From: Benjamin Sergeant Date: Thu, 1 Nov 2018 17:02:49 -0700 Subject: [PATCH] stopping connection on Linux does not close the socket, which can create problem when re-starting the connection --- CMakeLists.txt | 2 + ixwebsocket/IXSocket.cpp | 60 ++++------------------------ ixwebsocket/IXSocket.h | 7 ++-- ixwebsocket/IXSocketOpenSSL.cpp | 1 + ixwebsocket/IXWebSocketTransport.cpp | 15 +++++-- 5 files changed, 26 insertions(+), 59 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index de9e3977..1dadba37 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,12 +12,14 @@ set (CXX_STANDARD_REQUIRED ON) set (CMAKE_CXX_EXTENSIONS OFF) set( IXWEBSOCKET_SOURCES + ixwebsocket/IXEventFd.cpp ixwebsocket/IXSocket.cpp ixwebsocket/IXWebSocket.cpp ixwebsocket/IXWebSocketTransport.cpp ) set( IXWEBSOCKET_HEADERS + ixwebsocket/IXEventFd.h ixwebsocket/IXSocket.h ixwebsocket/IXWebSocket.h ixwebsocket/IXWebSocketTransport.h diff --git a/ixwebsocket/IXSocket.cpp b/ixwebsocket/IXSocket.cpp index 5fbf1895..02b03699 100644 --- a/ixwebsocket/IXSocket.cpp +++ b/ixwebsocket/IXSocket.cpp @@ -32,22 +32,7 @@ #include #include - -// -// Linux/Android has a special type of virtual files. select(2) will react -// when reading/writing to those files, unlike closing sockets. -// -// https://linux.die.net/man/2/eventfd -// -// eventfd was added in Linux kernel 2.x, and our oldest Android (Kitkat 4.4) -// is on Kernel 3.x -// -// cf Android/Kernel table here -// https://android.stackexchange.com/questions/51651/which-android-runs-which-linux-kernel -// -#ifdef __linux__ -# include -#endif +#include // Android needs extra headers for TCP_NODELAY and IPPROTO_TCP #ifdef ANDROID @@ -58,22 +43,14 @@ namespace ix { Socket::Socket() : - _sockfd(-1), - _eventfd(-1) + _sockfd(-1) { -#ifdef __linux__ - _eventfd = eventfd(0, 0); - assert(_eventfd != -1 && "Panic - eventfd not functioning on this platform"); -#endif + } Socket::~Socket() { close(); - -#ifdef __linux__ - ::close(_eventfd); -#endif } bool Socket::connectToAddress(const struct addrinfo *address, @@ -180,36 +157,20 @@ namespace ix FD_SET(_sockfd, &rfds); #ifdef __linux__ - FD_SET(_eventfd, &rfds); + FD_SET(_eventfd.getFd(), &rfds); #endif int sockfd = _sockfd; - int nfds = (std::max)(sockfd, _eventfd); + int nfds = (std::max)(sockfd, _eventfd.getFd()); select(nfds + 1, &rfds, nullptr, nullptr, nullptr); onPollCallback(); } - void Socket::wakeUpFromPollApple() - { - close(); // All OS but Linux will wake up select - // when closing the file descriptor watched by select - } - - void Socket::wakeUpFromPollLinux() - { - std::string str("\n"); // this will wake up the thread blocked on select - const void* buf = reinterpret_cast(str.c_str()); - write(_eventfd, buf, str.size()); - } - void Socket::wakeUpFromPoll() { -#ifdef __APPLE__ - wakeUpFromPollApple(); -#elif defined(__linux__) - wakeUpFromPollLinux(); -#endif + // this will wake up the thread blocked on select, only needed on Linux + _eventfd.notify(); } bool Socket::connect(const std::string& host, @@ -218,12 +179,7 @@ namespace ix { std::lock_guard lock(_socketMutex); -#ifdef __linux__ - if (_eventfd == -1) - { - return false; // impossible to use this socket if eventfd is broken - } -#endif + if (!_eventfd.clear()) return false; _sockfd = Socket::hostname_connect(host, port, errMsg); return _sockfd != -1; diff --git a/ixwebsocket/IXSocket.h b/ixwebsocket/IXSocket.h index adb812dc..f9e307a5 100644 --- a/ixwebsocket/IXSocket.h +++ b/ixwebsocket/IXSocket.h @@ -11,6 +11,8 @@ #include #include +#include "IXEventFd.h" + struct addrinfo; namespace ix @@ -45,14 +47,11 @@ namespace ix static void cleanup(); // Required on Windows to cleanup WinSocket protected: - void wakeUpFromPollApple(); - void wakeUpFromPollLinux(); - void closeSocket(int fd); std::atomic _sockfd; - int _eventfd; std::mutex _socketMutex; + EventFd _eventfd; private: bool connectToAddress(const struct addrinfo *address, diff --git a/ixwebsocket/IXSocketOpenSSL.cpp b/ixwebsocket/IXSocketOpenSSL.cpp index bdaab428..b519c710 100644 --- a/ixwebsocket/IXSocketOpenSSL.cpp +++ b/ixwebsocket/IXSocketOpenSSL.cpp @@ -150,6 +150,7 @@ namespace ix SSL_CTX* ctx = SSL_CTX_new(_ssl_method); if (ctx) { + // To skip verification, pass in SSL_VERIFY_NONE SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, openssl_verify_callback); SSL_CTX_set_verify_depth(ctx, 4); SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); diff --git a/ixwebsocket/IXWebSocketTransport.cpp b/ixwebsocket/IXWebSocketTransport.cpp index 6a085818..1b4eb0b2 100644 --- a/ixwebsocket/IXWebSocketTransport.cpp +++ b/ixwebsocket/IXWebSocketTransport.cpp @@ -34,6 +34,7 @@ #include #include #include +#include namespace ix { @@ -293,14 +294,18 @@ namespace ix { // i is end of string (\0), i-colon is length of string minus key; // subtract 1 for '\0', 1 for '\n', 1 for '\r', // 1 for the ' ' after the ':', and total is -4 - headers[lineStr.substr(0, colon)] = - lineStr.substr(colon + 2, i - colon - 4); + std::string name(lineStr.substr(0, colon)); + + // Make the name lower case. + std::transform(name.begin(), name.end(), name.begin(), ::tolower); + + headers[name] = lineStr.substr(colon + 2, i - colon - 4); } } char output[29] = {}; WebSocketHandshake::generate(secWebSocketKey.c_str(), output); - if (std::string(output) != headers["Sec-WebSocket-Accept"]) + if (std::string(output) != headers["sec-websocket-accept"]) { std::string errorMsg("Invalid Sec-WebSocket-Accept value"); return WebSocketInitResult(false, status, errorMsg); @@ -319,6 +324,9 @@ namespace ix { void WebSocketTransport::setReadyState(ReadyStateValues readyStateValue) { + // No state change, return + if (_readyState == readyStateValue) return; + if (readyStateValue == CLOSED) { std::lock_guard lock(_closeDataMutex); @@ -707,6 +715,7 @@ namespace ix { sendOnSocket(); _socket->wakeUpFromPoll(); + _socket->close(); } } // namespace ix