stopping connection on Linux does not close the socket, which can create problem when re-starting the connection
This commit is contained in:
parent
7117c74142
commit
c1ed83a005
@ -12,12 +12,14 @@ set (CXX_STANDARD_REQUIRED ON)
|
|||||||
set (CMAKE_CXX_EXTENSIONS OFF)
|
set (CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
set( IXWEBSOCKET_SOURCES
|
set( IXWEBSOCKET_SOURCES
|
||||||
|
ixwebsocket/IXEventFd.cpp
|
||||||
ixwebsocket/IXSocket.cpp
|
ixwebsocket/IXSocket.cpp
|
||||||
ixwebsocket/IXWebSocket.cpp
|
ixwebsocket/IXWebSocket.cpp
|
||||||
ixwebsocket/IXWebSocketTransport.cpp
|
ixwebsocket/IXWebSocketTransport.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set( IXWEBSOCKET_HEADERS
|
set( IXWEBSOCKET_HEADERS
|
||||||
|
ixwebsocket/IXEventFd.h
|
||||||
ixwebsocket/IXSocket.h
|
ixwebsocket/IXSocket.h
|
||||||
ixwebsocket/IXWebSocket.h
|
ixwebsocket/IXWebSocket.h
|
||||||
ixwebsocket/IXWebSocketTransport.h
|
ixwebsocket/IXWebSocketTransport.h
|
||||||
|
@ -32,22 +32,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <iostream>
|
||||||
//
|
|
||||||
// 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 <sys/eventfd.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Android needs extra headers for TCP_NODELAY and IPPROTO_TCP
|
// Android needs extra headers for TCP_NODELAY and IPPROTO_TCP
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
@ -58,22 +43,14 @@
|
|||||||
namespace ix
|
namespace ix
|
||||||
{
|
{
|
||||||
Socket::Socket() :
|
Socket::Socket() :
|
||||||
_sockfd(-1),
|
_sockfd(-1)
|
||||||
_eventfd(-1)
|
|
||||||
{
|
{
|
||||||
#ifdef __linux__
|
|
||||||
_eventfd = eventfd(0, 0);
|
|
||||||
assert(_eventfd != -1 && "Panic - eventfd not functioning on this platform");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Socket::~Socket()
|
Socket::~Socket()
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
|
|
||||||
#ifdef __linux__
|
|
||||||
::close(_eventfd);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Socket::connectToAddress(const struct addrinfo *address,
|
bool Socket::connectToAddress(const struct addrinfo *address,
|
||||||
@ -180,36 +157,20 @@ namespace ix
|
|||||||
FD_SET(_sockfd, &rfds);
|
FD_SET(_sockfd, &rfds);
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
FD_SET(_eventfd, &rfds);
|
FD_SET(_eventfd.getFd(), &rfds);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int sockfd = _sockfd;
|
int sockfd = _sockfd;
|
||||||
int nfds = (std::max)(sockfd, _eventfd);
|
int nfds = (std::max)(sockfd, _eventfd.getFd());
|
||||||
select(nfds + 1, &rfds, nullptr, nullptr, nullptr);
|
select(nfds + 1, &rfds, nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
onPollCallback();
|
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<const void*>(str.c_str());
|
|
||||||
write(_eventfd, buf, str.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Socket::wakeUpFromPoll()
|
void Socket::wakeUpFromPoll()
|
||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
// this will wake up the thread blocked on select, only needed on Linux
|
||||||
wakeUpFromPollApple();
|
_eventfd.notify();
|
||||||
#elif defined(__linux__)
|
|
||||||
wakeUpFromPollLinux();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Socket::connect(const std::string& host,
|
bool Socket::connect(const std::string& host,
|
||||||
@ -218,12 +179,7 @@ namespace ix
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_socketMutex);
|
std::lock_guard<std::mutex> lock(_socketMutex);
|
||||||
|
|
||||||
#ifdef __linux__
|
if (!_eventfd.clear()) return false;
|
||||||
if (_eventfd == -1)
|
|
||||||
{
|
|
||||||
return false; // impossible to use this socket if eventfd is broken
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
_sockfd = Socket::hostname_connect(host, port, errMsg);
|
_sockfd = Socket::hostname_connect(host, port, errMsg);
|
||||||
return _sockfd != -1;
|
return _sockfd != -1;
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "IXEventFd.h"
|
||||||
|
|
||||||
struct addrinfo;
|
struct addrinfo;
|
||||||
|
|
||||||
namespace ix
|
namespace ix
|
||||||
@ -45,14 +47,11 @@ namespace ix
|
|||||||
static void cleanup(); // Required on Windows to cleanup WinSocket
|
static void cleanup(); // Required on Windows to cleanup WinSocket
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void wakeUpFromPollApple();
|
|
||||||
void wakeUpFromPollLinux();
|
|
||||||
|
|
||||||
void closeSocket(int fd);
|
void closeSocket(int fd);
|
||||||
|
|
||||||
std::atomic<int> _sockfd;
|
std::atomic<int> _sockfd;
|
||||||
int _eventfd;
|
|
||||||
std::mutex _socketMutex;
|
std::mutex _socketMutex;
|
||||||
|
EventFd _eventfd;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool connectToAddress(const struct addrinfo *address,
|
bool connectToAddress(const struct addrinfo *address,
|
||||||
|
@ -150,6 +150,7 @@ namespace ix
|
|||||||
SSL_CTX* ctx = SSL_CTX_new(_ssl_method);
|
SSL_CTX* ctx = SSL_CTX_new(_ssl_method);
|
||||||
if (ctx)
|
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(ctx, SSL_VERIFY_PEER, openssl_verify_callback);
|
||||||
SSL_CTX_set_verify_depth(ctx, 4);
|
SSL_CTX_set_verify_depth(ctx, 4);
|
||||||
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
#include <regex>
|
#include <regex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
||||||
namespace ix {
|
namespace ix {
|
||||||
@ -293,14 +294,18 @@ namespace ix {
|
|||||||
// i is end of string (\0), i-colon is length of string minus key;
|
// i is end of string (\0), i-colon is length of string minus key;
|
||||||
// subtract 1 for '\0', 1 for '\n', 1 for '\r',
|
// subtract 1 for '\0', 1 for '\n', 1 for '\r',
|
||||||
// 1 for the ' ' after the ':', and total is -4
|
// 1 for the ' ' after the ':', and total is -4
|
||||||
headers[lineStr.substr(0, colon)] =
|
std::string name(lineStr.substr(0, colon));
|
||||||
lineStr.substr(colon + 2, i - colon - 4);
|
|
||||||
|
// 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] = {};
|
char output[29] = {};
|
||||||
WebSocketHandshake::generate(secWebSocketKey.c_str(), output);
|
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");
|
std::string errorMsg("Invalid Sec-WebSocket-Accept value");
|
||||||
return WebSocketInitResult(false, status, errorMsg);
|
return WebSocketInitResult(false, status, errorMsg);
|
||||||
@ -319,6 +324,9 @@ namespace ix {
|
|||||||
|
|
||||||
void WebSocketTransport::setReadyState(ReadyStateValues readyStateValue)
|
void WebSocketTransport::setReadyState(ReadyStateValues readyStateValue)
|
||||||
{
|
{
|
||||||
|
// No state change, return
|
||||||
|
if (_readyState == readyStateValue) return;
|
||||||
|
|
||||||
if (readyStateValue == CLOSED)
|
if (readyStateValue == CLOSED)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(_closeDataMutex);
|
std::lock_guard<std::mutex> lock(_closeDataMutex);
|
||||||
@ -707,6 +715,7 @@ namespace ix {
|
|||||||
sendOnSocket();
|
sendOnSocket();
|
||||||
|
|
||||||
_socket->wakeUpFromPoll();
|
_socket->wakeUpFromPoll();
|
||||||
|
_socket->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ix
|
} // namespace ix
|
||||||
|
Loading…
Reference in New Issue
Block a user