diff --git a/docker/Dockerfile.debian b/docker/Dockerfile.debian index a2743e70..2c11e46f 100644 --- a/docker/Dockerfile.debian +++ b/docker/Dockerfile.debian @@ -8,6 +8,7 @@ RUN apt-get -y install gdb RUN apt-get -y install screen RUN apt-get -y install procps RUN apt-get -y install lsof +RUN apt-get -y install libz-dev COPY . . diff --git a/examples/ws_connect/build_linux.sh b/examples/ws_connect/build_linux.sh index 5da47563..5392163d 100644 --- a/examples/ws_connect/build_linux.sh +++ b/examples/ws_connect/build_linux.sh @@ -13,8 +13,11 @@ g++ --std=c++11 \ ../../ixwebsocket/IXSocket.cpp \ ../../ixwebsocket/IXWebSocketTransport.cpp \ ../../ixwebsocket/IXWebSocket.cpp \ + ../../ixwebsocket/IXSocketConnect.cpp \ ../../ixwebsocket/IXSocketOpenSSL.cpp \ + ../../ixwebsocket/IXWebSocketPerMessageDeflate.cpp \ + ../../ixwebsocket/IXWebSocketPerMessageDeflateOptions.cpp \ -I ../.. \ ws_connect.cpp \ -o ws_connect \ - -lcrypto -lssl -lpthread + -lcrypto -lssl -lz -lpthread diff --git a/ixwebsocket/IXSocket.cpp b/ixwebsocket/IXSocket.cpp index d5eeeb81..c86c6a94 100644 --- a/ixwebsocket/IXSocket.cpp +++ b/ixwebsocket/IXSocket.cpp @@ -5,7 +5,6 @@ */ #include "IXSocket.h" -#include "IXSocketConnect.h" #ifdef _WIN32 # include @@ -79,13 +78,14 @@ namespace ix bool Socket::connect(const std::string& host, int port, - std::string& errMsg) + std::string& errMsg, + CancellationRequest isCancellationRequested) { std::lock_guard lock(_socketMutex); if (!_eventfd.clear()) return false; - _sockfd = SocketConnect::connect(host, port, errMsg); + _sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested); return _sockfd != -1; } diff --git a/ixwebsocket/IXSocket.h b/ixwebsocket/IXSocket.h index 17275a3e..f0876e17 100644 --- a/ixwebsocket/IXSocket.h +++ b/ixwebsocket/IXSocket.h @@ -12,6 +12,7 @@ #include #include "IXEventFd.h" +#include "IXSocketConnect.h" struct addrinfo; @@ -32,7 +33,8 @@ namespace ix // Virtual methods virtual bool connect(const std::string& url, int port, - std::string& errMsg); + std::string& errMsg, + CancellationRequest isCancellationRequested); virtual void close(); virtual int send(char* buffer, size_t length); diff --git a/ixwebsocket/IXSocketAppleSSL.cpp b/ixwebsocket/IXSocketAppleSSL.cpp index a4d8c065..0e575113 100644 --- a/ixwebsocket/IXSocketAppleSSL.cpp +++ b/ixwebsocket/IXSocketAppleSSL.cpp @@ -6,7 +6,6 @@ * Adapted from Satori SDK Apple SSL code. */ #include "IXSocketAppleSSL.h" -#include "IXSocketConnect.h" #include #include @@ -157,13 +156,14 @@ namespace ix // No wait support bool SocketAppleSSL::connect(const std::string& host, int port, - std::string& errMsg) + std::string& errMsg, + CancellationRequest isCancellationRequested) { OSStatus status; { std::lock_guard lock(_mutex); - _sockfd = SocketConnect::connect(host, port, errMsg); + _sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested); if (_sockfd == -1) return false; _sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType); diff --git a/ixwebsocket/IXSocketAppleSSL.h b/ixwebsocket/IXSocketAppleSSL.h index 7e1e9719..19cd344a 100644 --- a/ixwebsocket/IXSocketAppleSSL.h +++ b/ixwebsocket/IXSocketAppleSSL.h @@ -7,6 +7,7 @@ #pragma once #include "IXSocket.h" +#include "IXSocketConnect.h" #include #include @@ -23,7 +24,8 @@ namespace ix virtual bool connect(const std::string& host, int port, - std::string& errMsg) final; + std::string& errMsg, + CancellationRequest isCancellationRequested) final; virtual void close() final; virtual int send(char* buffer, size_t length) final; diff --git a/ixwebsocket/IXSocketConnect.cpp b/ixwebsocket/IXSocketConnect.cpp index ac2d8ac6..8fe7123f 100644 --- a/ixwebsocket/IXSocketConnect.cpp +++ b/ixwebsocket/IXSocketConnect.cpp @@ -23,6 +23,7 @@ # include #endif +#include #include #include @@ -32,7 +33,6 @@ # include #endif - namespace { void closeSocket(int fd) @@ -49,7 +49,8 @@ namespace ix { bool SocketConnect::connectToAddress(const struct addrinfo *address, int& sockfd, - std::string& errMsg) + std::string& errMsg, + CancellationRequest isCancellationRequested) { sockfd = -1; @@ -75,10 +76,30 @@ namespace ix return false; } - // 10 seconds timeout, each time we wait for 50ms with select -> 200 attempts - int maxRetries = 200; + // std::cout << "I WAS HERE A" << std::endl; + + // + // If during a connection attempt the request remains idle for longer + // than the timeout interval, the request is considered to have timed + // out. The default timeout interval is 60 seconds. + // + // See https://developer.apple.com/documentation/foundation/nsmutableurlrequest/1414063-timeoutinterval?language=objc + // + // 60 seconds timeout, each time we wait for 50ms with select -> 1200 attempts + // + int selectTimeOut = 50 * 1000; // In micro-seconds => 50ms + int maxRetries = 60 * 1000 * 1000 / selectTimeOut; + for (int i = 0; i < maxRetries; ++i) { + if (isCancellationRequested()) + { + closeSocket(fd); + sockfd = -1; + errMsg = "Cancelled"; + return false; + } + fd_set wfds; FD_ZERO(&wfds); FD_SET(fd, &wfds); @@ -86,7 +107,7 @@ namespace ix // 50ms timeout struct timeval timeout; timeout.tv_sec = 0; - timeout.tv_usec = 1000 * 50; + timeout.tv_usec = selectTimeOut; select(fd + 1, nullptr, &wfds, nullptr, &timeout); @@ -94,8 +115,8 @@ namespace ix if (!FD_ISSET(fd, &wfds)) continue; // Something was written to the socket - int optval = -1; - socklen_t optlen; + int optval; + socklen_t optlen = sizeof(optval); // getsockopt() puts the errno value for connect into optval so 0 // means no-error. @@ -123,7 +144,8 @@ namespace ix int SocketConnect::connect(const std::string& hostname, int port, - std::string& errMsg) + std::string& errMsg, + CancellationRequest isCancellationRequested) { // // First do DNS resolution @@ -155,7 +177,7 @@ namespace ix // // Second try to connect to the remote host // - success = connectToAddress(address, sockfd, errMsg); + success = connectToAddress(address, sockfd, errMsg, isCancellationRequested); if (success) { break; diff --git a/ixwebsocket/IXSocketConnect.h b/ixwebsocket/IXSocketConnect.h index 7d855f67..1857c8a2 100644 --- a/ixwebsocket/IXSocketConnect.h +++ b/ixwebsocket/IXSocketConnect.h @@ -7,20 +7,25 @@ #pragma once #include +#include struct addrinfo; namespace ix { + using CancellationRequest = std::function; + class SocketConnect { public: static int connect(const std::string& hostname, int port, - std::string& errMsg); + std::string& errMsg, + CancellationRequest isCancellationRequested); static bool connectToAddress(const struct addrinfo *address, int& sockfd, - std::string& errMsg); + std::string& errMsg, + CancellationRequest isCancellationRequested); static void configure(int sockfd); }; diff --git a/ixwebsocket/IXSocketOpenSSL.cpp b/ixwebsocket/IXSocketOpenSSL.cpp index e1b0cca2..e6d987db 100644 --- a/ixwebsocket/IXSocketOpenSSL.cpp +++ b/ixwebsocket/IXSocketOpenSSL.cpp @@ -7,7 +7,6 @@ */ #include "IXSocketOpenSSL.h" -#include "IXSocketConnect.h" #include #include @@ -275,7 +274,8 @@ namespace ix // No wait support bool SocketOpenSSL::connect(const std::string& host, int port, - std::string& errMsg) + std::string& errMsg, + CancellationRequest isCancellationRequested) { bool handshakeSuccessful = false; { @@ -286,7 +286,7 @@ namespace ix return false; } - _sockfd = SocketConnect::connect(host, port, errMsg); + _sockfd = SocketConnect::connect(host, port, errMsg, isCancellationRequested); if (_sockfd == -1) return false; _ssl_context = openSSLCreateContext(errMsg); diff --git a/ixwebsocket/IXSocketOpenSSL.h b/ixwebsocket/IXSocketOpenSSL.h index da5f40b4..671de936 100644 --- a/ixwebsocket/IXSocketOpenSSL.h +++ b/ixwebsocket/IXSocketOpenSSL.h @@ -7,6 +7,7 @@ #pragma once #include "IXSocket.h" +#include "IXSocketConnect.h" #include #include @@ -26,7 +27,8 @@ namespace ix virtual bool connect(const std::string& host, int port, - std::string& errMsg) final; + std::string& errMsg, + CancellationRequest isCancellationRequested) final; virtual void close() final; virtual int send(char* buffer, size_t length) final; diff --git a/ixwebsocket/IXWebSocketPerMessageDeflate.cpp b/ixwebsocket/IXWebSocketPerMessageDeflate.cpp index a123bd2d..3a8e3ad3 100644 --- a/ixwebsocket/IXWebSocketPerMessageDeflate.cpp +++ b/ixwebsocket/IXWebSocketPerMessageDeflate.cpp @@ -50,6 +50,7 @@ #include #include +#include namespace { diff --git a/ixwebsocket/IXWebSocketPerMessageDeflate.h b/ixwebsocket/IXWebSocketPerMessageDeflate.h index b8e91ecb..6cfb0ad0 100644 --- a/ixwebsocket/IXWebSocketPerMessageDeflate.h +++ b/ixwebsocket/IXWebSocketPerMessageDeflate.h @@ -36,6 +36,7 @@ #include "zlib.h" #include +#include namespace ix { diff --git a/ixwebsocket/IXWebSocketTransport.cpp b/ixwebsocket/IXWebSocketTransport.cpp index b2f68edf..21a83bc1 100644 --- a/ixwebsocket/IXWebSocketTransport.cpp +++ b/ixwebsocket/IXWebSocketTransport.cpp @@ -191,7 +191,12 @@ namespace ix } std::string errMsg; - bool success = _socket->connect(host, port, errMsg); + bool success = _socket->connect(host, port, errMsg, + [this] + { + return _readyState == CLOSING; + } + ); if (!success) { std::stringstream ss;