Compare commits

...

23 Commits

Author SHA1 Message Date
1ac02fdc0e more tests disabled 2019-05-13 12:37:27 -07:00
687956358d disable IXWebSocketPingTimeoutTest 2019-05-13 12:26:40 -07:00
1a42c92325 server code / add dedicated thread to close/join terminated connection threads 2019-05-13 12:20:03 -07:00
6bb00b6788 close with params 2019-05-13 09:33:14 -07:00
12f6cd878d save timepoints after connect and not in contructor, adjusted tests (#72)
* save timepoints after connect and not in contructor, adjusted tests

* move call into setReadyState

* more time to detect client close in test
2019-05-13 09:08:46 -07:00
9aacebbbaf fix for Windows (#69)
* fix for Windows

* fix condition

* make condition only on Windows
2019-05-12 22:21:56 -07:00
701c3745c2 Fix run.py (#71)
* fix run.py

* run.py: fix Windows support

* fix test listing
2019-05-12 18:37:22 -07:00
156288b17b all derived class use final keyword 2019-05-12 11:43:21 -07:00
ed0e23e8a5 bump version to 2.0.0 2019-05-11 14:22:41 -07:00
4c4f99606e use C++11 enums (#67)
* use C++11 enums

* small rename

* update tests

* update tests

* update ws

* update ws

* update README.md
2019-05-11 14:22:06 -07:00
a61586c846 add comment about why a unittest is disabled 2019-05-11 12:25:40 -07:00
d64d50c978 remove irrelevant comment 2019-05-11 12:24:11 -07:00
a64b7b0c4a minor improvements (#66)
* minor improvements

* fix build

* improve tests code
2019-05-11 12:20:58 -07:00
0caeb81327 minor tweaks to have full feature parity before unittest broke 2019-05-11 11:54:21 -07:00
edac7a0171 fix race condition in SelectInteruptPipe, where _fildes are not protected (caught by fedora tsan) 2019-05-11 11:45:26 -07:00
abfadad2e9 remove more iostream includes (#65) 2019-05-11 11:27:58 -07:00
2dc1547bbd rename some variables, minor cleanup 2019-05-11 10:24:28 -07:00
5eb23c9764 uncomment test 2019-05-11 10:15:22 -07:00
9f4b2856b0 fix crash on close 2019-05-11 10:15:22 -07:00
b5fc10326e fix crash on close 2019-05-11 10:12:33 -07:00
8d3a47a873 Fix crash during closing on Windows (#64)
* fix crash on close

* Improve calculateRetryWaitMilliseconds (#63)

* improve calculateRetryWaitMilliseconds

* update comment

* cout -> spdlog

* fix crash on close

* uncomment test

* Revert "uncomment test"

This reverts commit 27df86ee8f.
2019-05-11 09:51:26 -07:00
4df58f3059 fix warning in statsd_client about %m gnu only printf special char 2019-05-11 09:22:29 -07:00
06b8cb8d3b fix overflow warning in msgpack11.cpp 2019-05-10 21:17:05 -07:00
54 changed files with 939 additions and 510 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
build
*.pyc

View File

@ -1 +1 @@
1.5.2
2.0.0

View File

@ -1 +1 @@
docker/Dockerfile.fedora
docker/Dockerfile.ubuntu_xenial

View File

@ -37,7 +37,7 @@ webSocket.setOnMessageCallback(
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Message)
if (messageType == ix::WebSocketMessageType::Message)
{
std::cout << str << std::endl;
}
@ -77,7 +77,7 @@ server.setOnConnectionCallback(
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
std::cerr << "New connection" << std::endl;
@ -96,7 +96,7 @@ server.setOnConnectionCallback(
std::cerr << it.first << ": " << it.second << std::endl;
}
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
// For an echo server, we just send back to the client whatever was received by the server
// All connected clients are available in an std::set. See the broadcast cpp example.
@ -301,10 +301,10 @@ If the connection was closed and sending failed, the return value will be set to
`getReadyState()` returns the state of the connection. There are 4 possible states.
1. WebSocket_ReadyState_Connecting - The connection is not yet open.
2. WebSocket_ReadyState_Open - The connection is open and ready to communicate.
3. WebSocket_ReadyState_Closing - The connection is in the process of closing.
4. WebSocket_MessageType_Close - The connection is closed or could not be opened.
1. ReadyState::Connecting - The connection is not yet open.
2. ReadyState::Open - The connection is open and ready to communicate.
3. ReadyState::Closing - The connection is in the process of closing.
4. ReadyState::Closed - The connection is closed or could not be opened.
### Open and Close notifications
@ -319,7 +319,7 @@ webSocket.setOnMessageCallback(
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
std::cout << "send greetings" << std::endl;
@ -330,7 +330,7 @@ webSocket.setOnMessageCallback(
std::cout << it.first << ": " << it.second << std::endl;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
std::cout << "disconnected" << std::endl;
@ -345,7 +345,7 @@ webSocket.setOnMessageCallback(
### Error notification
A message will be fired when there is an error with the connection. The message type will be `ix::WebSocket_MessageType_Error`. Multiple fields will be available on the event to describe the error.
A message will be fired when there is an error with the connection. The message type will be `ix::WebSocketMessageType::Error`. Multiple fields will be available on the event to describe the error.
```
webSocket.setOnMessageCallback(
@ -356,7 +356,7 @@ webSocket.setOnMessageCallback(
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Error)
if (messageType == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Error: " << error.reason << std::endl;
@ -396,8 +396,8 @@ webSocket.setOnMessageCallback(
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Ping ||
messageType == ix::WebSocket_MessageType_Pong)
if (messageType == ix::WebSocketMessageType::Ping ||
messageType == ix::WebSocketMessageType::Pong)
{
std::cout << "pong data: " << str << std::endl;
}

View File

@ -52,7 +52,7 @@ namespace ix
{
std::stringstream ss;
ss << "Cannot parse url: " << url;
return std::make_tuple(code, HttpErrorCode_UrlMalformed,
return std::make_tuple(code, HttpErrorCode::UrlMalformed,
headers, payload, ss.str(),
uploadSize, downloadSize);
}
@ -63,7 +63,7 @@ namespace ix
if (!_socket)
{
return std::make_tuple(code, HttpErrorCode_CannotCreateSocket,
return std::make_tuple(code, HttpErrorCode::CannotCreateSocket,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
@ -116,7 +116,7 @@ namespace ix
{
std::stringstream ss;
ss << "Cannot connect to url: " << url;
return std::make_tuple(code, HttpErrorCode_CannotConnect,
return std::make_tuple(code, HttpErrorCode::CannotConnect,
headers, payload, ss.str(),
uploadSize, downloadSize);
}
@ -142,7 +142,7 @@ namespace ix
if (!_socket->writeBytes(req, isCancellationRequested))
{
std::string errorMsg("Cannot send request");
return std::make_tuple(code, HttpErrorCode_SendError,
return std::make_tuple(code, HttpErrorCode::SendError,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
@ -156,7 +156,7 @@ namespace ix
if (!lineValid)
{
std::string errorMsg("Cannot retrieve status line");
return std::make_tuple(code, HttpErrorCode_CannotReadStatusLine,
return std::make_tuple(code, HttpErrorCode::CannotReadStatusLine,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
@ -171,7 +171,7 @@ namespace ix
if (sscanf(line.c_str(), "HTTP/1.1 %d", &code) != 1)
{
std::string errorMsg("Cannot parse response code from status line");
return std::make_tuple(code, HttpErrorCode_MissingStatus,
return std::make_tuple(code, HttpErrorCode::MissingStatus,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
@ -183,7 +183,7 @@ namespace ix
if (!headersValid)
{
std::string errorMsg("Cannot parse http headers");
return std::make_tuple(code, HttpErrorCode_HeaderParsingError,
return std::make_tuple(code, HttpErrorCode::HeaderParsingError,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
@ -194,7 +194,7 @@ namespace ix
if (headers.find("Location") == headers.end())
{
std::string errorMsg("Missing location header for redirect");
return std::make_tuple(code, HttpErrorCode_MissingLocation,
return std::make_tuple(code, HttpErrorCode::MissingLocation,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
@ -203,7 +203,7 @@ namespace ix
{
std::stringstream ss;
ss << "Too many redirects: " << redirects;
return std::make_tuple(code, HttpErrorCode_TooManyRedirects,
return std::make_tuple(code, HttpErrorCode::TooManyRedirects,
headers, payload, ss.str(),
uploadSize, downloadSize);
}
@ -215,7 +215,7 @@ namespace ix
if (verb == "HEAD")
{
return std::make_tuple(code, HttpErrorCode_Ok,
return std::make_tuple(code, HttpErrorCode::Ok,
headers, payload, std::string(),
uploadSize, downloadSize);
}
@ -236,7 +236,7 @@ namespace ix
if (!chunkResult.first)
{
errorMsg = "Cannot read chunk";
return std::make_tuple(code, HttpErrorCode_ChunkReadError,
return std::make_tuple(code, HttpErrorCode::ChunkReadError,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
@ -254,7 +254,7 @@ namespace ix
if (!lineResult.first)
{
return std::make_tuple(code, HttpErrorCode_ChunkReadError,
return std::make_tuple(code, HttpErrorCode::ChunkReadError,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
@ -281,7 +281,7 @@ namespace ix
if (!chunkResult.first)
{
errorMsg = "Cannot read chunk";
return std::make_tuple(code, HttpErrorCode_ChunkReadError,
return std::make_tuple(code, HttpErrorCode::ChunkReadError,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
@ -292,7 +292,7 @@ namespace ix
if (!lineResult.first)
{
return std::make_tuple(code, HttpErrorCode_ChunkReadError,
return std::make_tuple(code, HttpErrorCode::ChunkReadError,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
@ -307,7 +307,7 @@ namespace ix
else
{
std::string errorMsg("Cannot read http body");
return std::make_tuple(code, HttpErrorCode_CannotReadBody,
return std::make_tuple(code, HttpErrorCode::CannotReadBody,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
@ -321,14 +321,14 @@ namespace ix
if (!gzipInflate(payload, decompressedPayload))
{
std::string errorMsg("Error decompressing payload");
return std::make_tuple(code, HttpErrorCode_Gzip,
return std::make_tuple(code, HttpErrorCode::Gzip,
headers, payload, errorMsg,
uploadSize, downloadSize);
}
payload = decompressedPayload;
}
return std::make_tuple(code, HttpErrorCode_Ok,
return std::make_tuple(code, HttpErrorCode::Ok,
headers, payload, std::string(),
uploadSize, downloadSize);
}

View File

@ -19,23 +19,23 @@
namespace ix
{
enum HttpErrorCode
enum class HttpErrorCode
{
HttpErrorCode_Ok = 0,
HttpErrorCode_CannotConnect = 1,
HttpErrorCode_Timeout = 2,
HttpErrorCode_Gzip = 3,
HttpErrorCode_UrlMalformed = 4,
HttpErrorCode_CannotCreateSocket = 5,
HttpErrorCode_SendError = 6,
HttpErrorCode_ReadError = 7,
HttpErrorCode_CannotReadStatusLine = 8,
HttpErrorCode_MissingStatus = 9,
HttpErrorCode_HeaderParsingError = 10,
HttpErrorCode_MissingLocation = 11,
HttpErrorCode_TooManyRedirects = 12,
HttpErrorCode_ChunkReadError = 13,
HttpErrorCode_CannotReadBody = 14
Ok = 0,
CannotConnect = 1,
Timeout = 2,
Gzip = 3,
UrlMalformed = 4,
CannotCreateSocket = 5,
SendError = 6,
ReadError = 7,
CannotReadStatusLine = 8,
MissingStatus = 9,
HeaderParsingError = 10,
MissingLocation = 11,
TooManyRedirects = 12,
ChunkReadError = 13,
CannotReadBody = 14
};
using HttpResponse = std::tuple<int, // status

View File

@ -13,7 +13,7 @@
namespace ix
{
class SelectInterruptEventFd : public SelectInterrupt {
class SelectInterruptEventFd final : public SelectInterrupt {
public:
SelectInterruptEventFd();
virtual ~SelectInterruptEventFd();

View File

@ -40,6 +40,8 @@ namespace ix
bool SelectInterruptPipe::init(std::string& errorMsg)
{
std::lock_guard<std::mutex> lock(_fildesMutex);
// calling init twice is a programming error
assert(_fildes[kPipeReadIndex] == -1);
assert(_fildes[kPipeWriteIndex] == -1);
@ -108,6 +110,8 @@ namespace ix
bool SelectInterruptPipe::notify(uint64_t value)
{
std::lock_guard<std::mutex> lock(_fildesMutex);
int fd = _fildes[kPipeWriteIndex];
if (fd == -1) return false;
@ -118,6 +122,8 @@ namespace ix
// TODO: return max uint64_t for errors ?
uint64_t SelectInterruptPipe::read()
{
std::lock_guard<std::mutex> lock(_fildesMutex);
int fd = _fildes[kPipeReadIndex];
uint64_t value = 0;
@ -133,6 +139,8 @@ namespace ix
int SelectInterruptPipe::getFd() const
{
std::lock_guard<std::mutex> lock(_fildesMutex);
return _fildes[kPipeReadIndex];
}
}

View File

@ -10,10 +10,11 @@
#include <stdint.h>
#include <string>
#include <mutex>
namespace ix
{
class SelectInterruptPipe : public SelectInterrupt {
class SelectInterruptPipe final : public SelectInterrupt {
public:
SelectInterruptPipe();
virtual ~SelectInterruptPipe();
@ -30,6 +31,7 @@ namespace ix
// happens between a control thread and a background thread, which is
// blocked on select.
int _fildes[2];
mutable std::mutex _fildesMutex;
// Used to identify the read/write idx
static const int kPipeReadIndex;

View File

@ -73,7 +73,7 @@ namespace ix
struct timeval timeout;
timeout.tv_sec = timeoutMs / 1000;
timeout.tv_usec = (timeoutMs < 1000) ? 0 : 1000 * (timeoutMs % 1000);
timeout.tv_usec = 1000 * (timeoutMs % 1000);
// Compute the highest fd.
int sockfd = _sockfd;

View File

@ -41,12 +41,12 @@ namespace ix
enum class PollResultType
{
ReadyForRead = 0,
ReadyForWrite = 1,
Timeout = 2,
Error = 3,
SendRequest = 4,
CloseRequest = 5
ReadyForRead = 0,
ReadyForWrite = 1,
Timeout = 2,
Error = 3,
SendRequest = 4,
CloseRequest = 5
};
class Socket {

View File

@ -20,8 +20,6 @@
#include <unistd.h>
#include <stdint.h>
#include <iostream>
#include <errno.h>
#define socketerrno errno

View File

@ -16,7 +16,7 @@
namespace ix
{
class SocketAppleSSL : public Socket
class SocketAppleSSL final : public Socket
{
public:
SocketAppleSSL(int fd = -1);

View File

@ -10,7 +10,6 @@
#include "IXSocketConnect.h"
#include <cassert>
#include <iostream>
#include <openssl/x509v3.h>

View File

@ -19,7 +19,7 @@
namespace ix
{
class SocketOpenSSL : public Socket
class SocketOpenSSL final : public Socket
{
public:
SocketOpenSSL(int fd = -1);

View File

@ -10,7 +10,7 @@
namespace ix
{
class SocketSChannel : public Socket
class SocketSChannel final : public Socket
{
public:
SocketSChannel();

View File

@ -30,7 +30,9 @@ namespace ix
_host(host),
_backlog(backlog),
_maxConnections(maxConnections),
_serverFd(-1),
_stop(false),
_stopGc(false),
_connectionStateFactory(&ConnectionState::createConnectionState)
{
@ -124,9 +126,15 @@ namespace ix
void SocketServer::start()
{
if (_thread.joinable()) return; // we've already been started
if (!_thread.joinable())
{
_thread = std::thread(&SocketServer::run, this);
}
_thread = std::thread(&SocketServer::run, this);
if (!_gcThread.joinable())
{
_gcThread = std::thread(&SocketServer::runGC, this);
}
}
void SocketServer::wait()
@ -142,21 +150,21 @@ namespace ix
void SocketServer::stop()
{
while (true)
// Stop accepting connections, and close the 'accept' thread
if (_thread.joinable())
{
if (closeTerminatedThreads()) break;
// wait 10ms and try again later.
// we could have a timeout, but if we exit of here
// we leaked threads, it is quite bad.
std::this_thread::sleep_for(std::chrono::milliseconds(10));
_stop = true;
_thread.join();
_stop = false;
}
if (!_thread.joinable()) return; // nothing to do
_stop = true;
_thread.join();
_stop = false;
// Join all threads and make sure that all connections are terminated
if (_gcThread.joinable())
{
_stopGc = true;
_gcThread.join();
_stopGc = false;
}
_conditionVariable.notify_one();
Socket::closeSocket(_serverFd);
@ -175,7 +183,7 @@ namespace ix
// field becomes true, and we can use that to know that we can join that thread
// and remove it from our _connectionsThreads data structure (a list).
//
bool SocketServer::closeTerminatedThreads()
void SocketServer::closeTerminatedThreads()
{
std::lock_guard<std::mutex> lock(_connectionsThreadsMutex);
auto it = _connectionsThreads.begin();
@ -195,8 +203,6 @@ namespace ix
if (thread.joinable()) thread.join();
it = _connectionsThreads.erase(it);
}
return _connectionsThreads.empty();
}
void SocketServer::run()
@ -208,12 +214,6 @@ namespace ix
{
if (_stop) return;
// Garbage collection to shutdown/join threads for closed connections.
// We could run this in its own thread, so that we dont need to accept
// a new connection to close a thread.
// We could also use a condition variable to be notify when we need to do this
closeTerminatedThreads();
// Use select to check whether a new connection is in progress
fd_set rfds;
struct timeval timeout;
@ -290,5 +290,30 @@ namespace ix
connectionState)));
}
}
size_t SocketServer::getConnectionsThreadsCount()
{
std::lock_guard<std::mutex> lock(_connectionsThreadsMutex);
return _connectionsThreads.size();
}
void SocketServer::runGC()
{
for (;;)
{
// Garbage collection to shutdown/join threads for closed connections.
closeTerminatedThreads();
// We quit this thread if all connections are closed and we received
// a stop request by setting _stopGc to true.
if (_stopGc && getConnectionsThreadsCount() == 0)
{
break;
}
// Sleep a little bit then keep cleaning up
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
}

View File

@ -74,6 +74,12 @@ namespace ix
// background thread to wait for incoming connections
std::atomic<bool> _stop;
std::thread _thread;
void run();
// background thread to cleanup (join) terminated threads
std::atomic<bool> _stopGc;
std::thread _gcThread;
void runGC();
// the list of (connectionState, threads) for each connections
ConnectionThreads _connectionsThreads;
@ -87,13 +93,12 @@ namespace ix
// the factory to create ConnectionState objects
ConnectionStateFactory _connectionStateFactory;
// Methods
void run();
virtual void handleConnection(int fd,
std::shared_ptr<ConnectionState> connectionState) = 0;
virtual size_t getConnectedClientsCount() = 0;
// Returns true if all connection threads are joined
bool closeTerminatedThreads();
void closeTerminatedThreads();
size_t getConnectionsThreadsCount();
};
}

View File

@ -7,8 +7,6 @@
#include "IXUrlParser.h"
#include "LUrlParser.h"
#include <iostream>
namespace ix
{
bool UrlParser::parse(const std::string& url,
@ -66,22 +64,4 @@ namespace ix
return true;
}
void UrlParser::printUrl(const std::string& url)
{
std::string protocol, host, path, query;
int port {0};
if (!parse(url, protocol, host, path, query, port))
{
return;
}
std::cout << "[" << url << "]" << std::endl;
std::cout << protocol << std::endl;
std::cout << host << std::endl;
std::cout << port << std::endl;
std::cout << path << std::endl;
std::cout << query << std::endl;
std::cout << "-------------------------------" << std::endl;
}
}

View File

@ -19,7 +19,5 @@ namespace ix
std::string& path,
std::string& query,
int& port);
static void printUrl(const std::string& url);
};
}

View File

@ -51,7 +51,7 @@ namespace ix
_ws.setOnCloseCallback(
[this](uint16_t code, const std::string& reason, size_t wireSize, bool remote)
{
_onMessageCallback(WebSocket_MessageType_Close, "", wireSize,
_onMessageCallback(WebSocketMessageType::Close, "", wireSize,
WebSocketErrorInfo(), WebSocketOpenInfo(),
WebSocketCloseInfo(code, reason, remote));
}
@ -144,24 +144,16 @@ namespace ix
void WebSocket::stop()
{
bool automaticReconnection = _automaticReconnection;
// This value needs to be forced when shutting down, it is restored later
_automaticReconnection = false;
close();
if (!_thread.joinable())
if (_thread.joinable())
{
_automaticReconnection = automaticReconnection;
return;
// wait until working thread will exit
// it will exit after close operation is finished
_stop = true;
_thread.join();
_stop = false;
}
_stop = true;
_thread.join();
_stop = false;
_automaticReconnection = automaticReconnection;
}
WebSocketInitResult WebSocket::connect(int timeoutSecs)
@ -180,7 +172,7 @@ namespace ix
return status;
}
_onMessageCallback(WebSocket_MessageType_Open, "", 0,
_onMessageCallback(WebSocketMessageType::Open, "", 0,
WebSocketErrorInfo(),
WebSocketOpenInfo(status.uri, status.headers),
WebSocketCloseInfo());
@ -203,7 +195,7 @@ namespace ix
return status;
}
_onMessageCallback(WebSocket_MessageType_Open, "", 0,
_onMessageCallback(WebSocketMessageType::Open, "", 0,
WebSocketErrorInfo(),
WebSocketOpenInfo(status.uri, status.headers),
WebSocketCloseInfo());
@ -212,80 +204,71 @@ namespace ix
bool WebSocket::isConnected() const
{
return getReadyState() == WebSocket_ReadyState_Open;
return getReadyState() == ReadyState::Open;
}
bool WebSocket::isClosing() const
{
return getReadyState() == WebSocket_ReadyState_Closing;
return getReadyState() == ReadyState::Closing;
}
bool WebSocket::isConnectedOrClosing() const
void WebSocket::close(uint16_t code,
const std::string& reason)
{
return isConnected() || isClosing();
_ws.close(code, reason);
}
void WebSocket::close()
void WebSocket::checkConnection(bool firstConnectionAttempt)
{
_ws.close();
}
void WebSocket::reconnectPerpetuallyIfDisconnected()
{
uint32_t retries = 0;
WebSocketErrorInfo connectErr;
ix::WebSocketInitResult status;
using millis = std::chrono::duration<double, std::milli>;
uint32_t retries = 0;
millis duration;
// Try to connect only once when we don't have automaticReconnection setup
if (!isConnectedOrClosing() && !_stop && !_automaticReconnection)
// Try to connect perpertually
while (true)
{
status = connect(_handshakeTimeoutSecs);
if (isConnected() || isClosing() || _stop)
{
break;
}
if (!firstConnectionAttempt && !_automaticReconnection)
{
// Do not attempt to reconnect
break;
}
firstConnectionAttempt = false;
// Only sleep if we are retrying
if (duration.count() > 0)
{
// to do: make sleeping conditional
std::this_thread::sleep_for(duration);
}
// Try to connect synchronously
ix::WebSocketInitResult status = connect(_handshakeTimeoutSecs);
if (!status.success)
{
duration = millis(calculateRetryWaitMilliseconds(retries++));
WebSocketErrorInfo connectErr;
connectErr.retries = retries;
connectErr.wait_time = duration.count();
connectErr.reason = status.errorStr;
connectErr.http_status = status.http_status;
_onMessageCallback(WebSocket_MessageType_Error, "", 0,
connectErr, WebSocketOpenInfo(),
WebSocketCloseInfo());
}
}
else
{
// Otherwise try to reconnect perpertually
while (true)
{
if (isConnectedOrClosing() || _stop || !_automaticReconnection)
{
break;
}
status = connect(_handshakeTimeoutSecs);
if (!status.success)
if (_automaticReconnection)
{
duration = millis(calculateRetryWaitMilliseconds(retries++));
connectErr.retries = retries;
connectErr.wait_time = duration.count();
connectErr.reason = status.errorStr;
connectErr.http_status = status.http_status;
_onMessageCallback(WebSocket_MessageType_Error, "", 0,
connectErr, WebSocketOpenInfo(),
WebSocketCloseInfo());
// Only sleep if we aren't in the middle of stopping
if (!_stop)
{
std::this_thread::sleep_for(duration);
}
connectErr.retries = retries;
}
connectErr.reason = status.errorStr;
connectErr.http_status = status.http_status;
_onMessageCallback(WebSocketMessageType::Error, "", 0,
connectErr, WebSocketOpenInfo(),
WebSocketCloseInfo());
}
}
}
@ -294,19 +277,27 @@ namespace ix
{
setThreadName(getUrl());
bool firstConnectionAttempt = true;
while (true)
{
if (_stop && !isClosing()) return;
// 1. Make sure we are always connected
reconnectPerpetuallyIfDisconnected();
checkConnection(firstConnectionAttempt);
firstConnectionAttempt = false;
// if here we are closed then checkConnection was not able to connect
if (getReadyState() == ReadyState::Closed)
{
break;
}
// 2. Poll to see if there's any new data available
WebSocketTransport::PollPostTreatment pollPostTreatment = _ws.poll();
WebSocketTransport::PollResult pollResult = _ws.poll();
// 3. Dispatch the incoming messages
_ws.dispatch(
pollPostTreatment,
pollResult,
[this](const std::string& msg,
size_t wireSize,
bool decompressionError,
@ -315,24 +306,25 @@ namespace ix
WebSocketMessageType webSocketMessageType;
switch (messageKind)
{
case WebSocketTransport::MSG:
default:
case WebSocketTransport::MessageKind::MSG:
{
webSocketMessageType = WebSocket_MessageType_Message;
webSocketMessageType = WebSocketMessageType::Message;
} break;
case WebSocketTransport::PING:
case WebSocketTransport::MessageKind::PING:
{
webSocketMessageType = WebSocket_MessageType_Ping;
webSocketMessageType = WebSocketMessageType::Ping;
} break;
case WebSocketTransport::PONG:
case WebSocketTransport::MessageKind::PONG:
{
webSocketMessageType = WebSocket_MessageType_Pong;
webSocketMessageType = WebSocketMessageType::Pong;
} break;
case WebSocketTransport::FRAGMENT:
case WebSocketTransport::MessageKind::FRAGMENT:
{
webSocketMessageType = WebSocket_MessageType_Fragment;
webSocketMessageType = WebSocketMessageType::Fragment;
} break;
}
@ -345,9 +337,6 @@ namespace ix
WebSocket::invokeTrafficTrackerCallback(msg.size(), true);
});
// If we aren't trying to reconnect automatically, exit if we aren't connected
if (!isConnectedOrClosing() && !_automaticReconnection) return;
}
}
@ -374,10 +363,10 @@ namespace ix
}
}
WebSocketSendInfo WebSocket::send(const std::string& text,
WebSocketSendInfo WebSocket::send(const std::string& data,
const OnProgressCallback& onProgressCallback)
{
return sendMessage(text, SendMessageKind::Binary, onProgressCallback);
return sendMessage(data, SendMessageKind::Binary, onProgressCallback);
}
WebSocketSendInfo WebSocket::sendText(const std::string& text,
@ -440,11 +429,11 @@ namespace ix
{
switch (_ws.getReadyState())
{
case ix::WebSocketTransport::OPEN: return WebSocket_ReadyState_Open;
case ix::WebSocketTransport::CONNECTING: return WebSocket_ReadyState_Connecting;
case ix::WebSocketTransport::CLOSING: return WebSocket_ReadyState_Closing;
case ix::WebSocketTransport::CLOSED: return WebSocket_ReadyState_Closed;
default: return WebSocket_ReadyState_Closed;
case ix::WebSocketTransport::ReadyState::OPEN : return ReadyState::Open;
case ix::WebSocketTransport::ReadyState::CONNECTING: return ReadyState::Connecting;
case ix::WebSocketTransport::ReadyState::CLOSING : return ReadyState::Closing;
case ix::WebSocketTransport::ReadyState::CLOSED : return ReadyState::Closed;
default: return ReadyState::Closed;
}
}
@ -452,11 +441,11 @@ namespace ix
{
switch (readyState)
{
case WebSocket_ReadyState_Open: return "OPEN";
case WebSocket_ReadyState_Connecting: return "CONNECTING";
case WebSocket_ReadyState_Closing: return "CLOSING";
case WebSocket_ReadyState_Closed: return "CLOSED";
default: return "CLOSED";
case ReadyState::Open : return "OPEN";
case ReadyState::Connecting: return "CONNECTING";
case ReadyState::Closing : return "CLOSING";
case ReadyState::Closed : return "CLOSED";
default: return "UNKNOWN";
}
}

View File

@ -24,23 +24,23 @@
namespace ix
{
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket#Ready_state_constants
enum ReadyState
enum class ReadyState
{
WebSocket_ReadyState_Connecting = 0,
WebSocket_ReadyState_Open = 1,
WebSocket_ReadyState_Closing = 2,
WebSocket_ReadyState_Closed = 3
Connecting = 0,
Open = 1,
Closing = 2,
Closed = 3
};
enum WebSocketMessageType
enum class WebSocketMessageType
{
WebSocket_MessageType_Message = 0,
WebSocket_MessageType_Open = 1,
WebSocket_MessageType_Close = 2,
WebSocket_MessageType_Error = 3,
WebSocket_MessageType_Ping = 4,
WebSocket_MessageType_Pong = 5,
WebSocket_MessageType_Fragment = 6
Message = 0,
Open = 1,
Close = 2,
Error = 3,
Ping = 4,
Pong = 5,
Fragment = 6
};
struct WebSocketOpenInfo
@ -91,7 +91,6 @@ namespace ix
void setUrl(const std::string& url);
void setPerMessageDeflateOptions(const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions);
void setHandshakeTimeout(int handshakeTimeoutSecs);
void setHeartBeatPeriod(int heartBeatPeriodSecs);
void setPingInterval(int pingIntervalSecs); // alias of setHeartBeatPeriod
void setPingTimeout(int pingTimeoutSecs);
@ -100,24 +99,32 @@ namespace ix
// Run asynchronously, by calling start and stop.
void start();
// stop is synchronous
void stop();
// Run in blocking mode, by connecting first manually, and then calling run.
WebSocketInitResult connect(int timeoutSecs);
void run();
WebSocketSendInfo send(const std::string& text,
// send binary data
WebSocketSendInfo send(const std::string& data,
const OnProgressCallback& onProgressCallback = nullptr);
WebSocketSendInfo sendText(const std::string& text,
const OnProgressCallback& onProgressCallback = nullptr);
WebSocketSendInfo ping(const std::string& text);
void close();
// A close frame can provide a code and a reason
// FIXME: use constants
void close(uint16_t code = 1000,
const std::string& reason = "Normal closure");
void setOnMessageCallback(const OnMessageCallback& callback);
static void setTrafficTrackerCallback(const OnTrafficTrackerCallback& callback);
static void resetTrafficTrackerCallback();
ReadyState getReadyState() const;
static std::string readyStateToString(ReadyState readyState);
const std::string& getUrl() const;
const WebSocketPerMessageDeflateOptions& getPerMessageDeflateOptions() const;
int getHeartBeatPeriod() const;
@ -136,13 +143,10 @@ namespace ix
bool isConnected() const;
bool isClosing() const;
bool isConnectedOrClosing() const;
void reconnectPerpetuallyIfDisconnected();
std::string readyStateToString(ReadyState readyState);
void checkConnection(bool firstConnectionAttempt);
static void invokeTrafficTrackerCallback(size_t size, bool incoming);
// Server
void setSocketFileDescriptor(int fd);
WebSocketInitResult connectToSocket(int fd, int timeoutSecs);
WebSocketTransport _ws;

View File

@ -12,10 +12,10 @@ namespace ix
{
struct WebSocketErrorInfo
{
uint32_t retries;
double wait_time;
int http_status;
uint32_t retries = 0;
double wait_time = 0;
int http_status = 0;
std::string reason;
bool decompressionError;
bool decompressionError = false;
};
}

View File

@ -23,7 +23,6 @@ namespace ix
WebSocketPerMessageDeflateOptions(std::string extension);
std::string generateHeader();
std::string parseHeader();
bool enabled() const;
bool getClientNoContextTakeover() const;
bool getServerNoContextTakeover() const;

View File

@ -6,9 +6,6 @@
#pragma once
#include <string>
#include <iostream>
namespace ix
{
struct WebSocketSendInfo

View File

@ -23,7 +23,7 @@ namespace ix
using OnConnectionCallback = std::function<void(std::shared_ptr<WebSocket>,
std::shared_ptr<ConnectionState>)>;
class WebSocketServer : public SocketServer {
class WebSocketServer final : public SocketServer {
public:
WebSocketServer(int port = SocketServer::kDefaultPort,
const std::string& host = SocketServer::kDefaultHost,

View File

@ -86,7 +86,7 @@ namespace ix
WebSocketTransport::WebSocketTransport() :
_useMask(true),
_readyState(CLOSED),
_readyState(ReadyState::CLOSED),
_closeCode(kInternalErrorCode),
_closeReason(kInternalErrorMessage),
_closeWireSize(0),
@ -134,11 +134,6 @@ namespace ix
{
_pingIntervalOrTimeoutGCDSecs = pingIntervalSecs;
}
if (_pingIntervalOrTimeoutGCDSecs > 0)
{
_nextGCDTimePoint = std::chrono::steady_clock::now() + std::chrono::seconds(_pingIntervalOrTimeoutGCDSecs);
}
}
// Client
@ -173,7 +168,7 @@ namespace ix
timeoutSecs);
if (result.success)
{
setReadyState(OPEN);
setReadyState(ReadyState::OPEN);
}
return result;
}
@ -201,22 +196,22 @@ namespace ix
auto result = webSocketHandshake.serverHandshake(fd, timeoutSecs);
if (result.success)
{
setReadyState(OPEN);
setReadyState(ReadyState::OPEN);
}
return result;
}
WebSocketTransport::ReadyStateValues WebSocketTransport::getReadyState() const
WebSocketTransport::ReadyState WebSocketTransport::getReadyState() const
{
return _readyState;
}
void WebSocketTransport::setReadyState(ReadyStateValues readyStateValue)
void WebSocketTransport::setReadyState(ReadyState readyState)
{
// No state change, return
if (_readyState == readyStateValue) return;
if (_readyState == readyState) return;
if (readyStateValue == CLOSED)
if (readyState == ReadyState::CLOSED)
{
std::lock_guard<std::mutex> lock(_closeDataMutex);
_onCloseCallback(_closeCode, _closeReason, _closeWireSize, _closeRemote);
@ -225,8 +220,12 @@ namespace ix
_closeWireSize = 0;
_closeRemote = false;
}
else if (readyState == ReadyState::OPEN)
{
initTimePointsAndGCDAfterConnect();
}
_readyState = readyStateValue;
_readyState = readyState;
}
void WebSocketTransport::setOnCloseCallback(const OnCloseCallback& onCloseCallback)
@ -234,6 +233,23 @@ namespace ix
_onCloseCallback = onCloseCallback;
}
void WebSocketTransport::initTimePointsAndGCDAfterConnect()
{
{
std::lock_guard<std::mutex> lock(_lastSendPingTimePointMutex);
_lastSendPingTimePoint = std::chrono::steady_clock::now();
}
{
std::lock_guard<std::mutex> lock(_lastReceivePongTimePointMutex);
_lastReceivePongTimePoint = std::chrono::steady_clock::now();
}
if (_pingIntervalOrTimeoutGCDSecs > 0)
{
_nextGCDTimePoint = std::chrono::steady_clock::now() + std::chrono::seconds(_pingIntervalOrTimeoutGCDSecs);
}
}
// Only consider send PING time points for that computation.
bool WebSocketTransport::pingIntervalExceeded()
{
@ -262,9 +278,9 @@ namespace ix
return now - _closingTimePoint > std::chrono::milliseconds(kClosingMaximumWaitingDelayInMs);
}
WebSocketTransport::PollPostTreatment WebSocketTransport::poll()
WebSocketTransport::PollResult WebSocketTransport::poll()
{
if (_readyState == OPEN)
if (_readyState == ReadyState::OPEN)
{
// if (1) ping timeout is enabled and (2) duration since last received
// ping response (PONG) exceeds the maximum delay, then close the connection
@ -284,7 +300,7 @@ namespace ix
// No timeout if state is not OPEN, otherwise computed
// pingIntervalOrTimeoutGCD (equals to -1 if no ping and no ping timeout are set)
int lastingTimeoutDelayInMs = (_readyState != OPEN) ? 0 : _pingIntervalOrTimeoutGCDSecs;
int lastingTimeoutDelayInMs = (_readyState != ReadyState::OPEN) ? 0 : _pingIntervalOrTimeoutGCDSecs;
if (_pingIntervalOrTimeoutGCDSecs > 0)
{
@ -303,6 +319,10 @@ namespace ix
}
}
#ifdef _WIN32
if (lastingTimeoutDelayInMs <= 0) lastingTimeoutDelayInMs = 20;
#endif
// poll the socket
PollResultType pollResult = _socket->poll(lastingTimeoutDelayInMs);
@ -319,7 +339,7 @@ namespace ix
if (result == PollResultType::Error)
{
_socket->close();
setReadyState(CLOSED);
setReadyState(ReadyState::CLOSED);
break;
}
else if (result == PollResultType::ReadyForWrite)
@ -345,7 +365,7 @@ namespace ix
_socket->close();
return CHECK_OR_RAISE_ABNORMAL_CLOSE_AFTER_DISPATCH;
return PollResult::AbnormalClose;
}
else
{
@ -364,15 +384,15 @@ namespace ix
_socket->close();
}
if (_readyState == CLOSING && closingDelayExceeded())
if (_readyState == ReadyState::CLOSING && closingDelayExceeded())
{
_rxbuf.clear();
// close code and reason were set when calling close()
_socket->close();
setReadyState(CLOSED);
setReadyState(ReadyState::CLOSED);
}
return NONE;
return PollResult::Succeeded;
}
bool WebSocketTransport::isSendBufferEmpty() const
@ -434,7 +454,7 @@ namespace ix
// | Payload Data continued ... |
// +---------------------------------------------------------------+
//
void WebSocketTransport::dispatch(WebSocketTransport::PollPostTreatment pollPostTreatment,
void WebSocketTransport::dispatch(WebSocketTransport::PollResult pollResult,
const OnMessageCallback& onMessageCallback)
{
while (true)
@ -521,7 +541,7 @@ namespace ix
//
if (ws.fin && _chunks.empty())
{
emitMessage(MSG,
emitMessage(MessageKind::MSG,
std::string(_rxbuf.begin()+ws.header_size,
_rxbuf.begin()+ws.header_size+(size_t) ws.N),
ws,
@ -541,12 +561,12 @@ namespace ix
_rxbuf.begin()+ws.header_size+(size_t)ws.N));
if (ws.fin)
{
emitMessage(MSG, getMergedChunks(), ws, onMessageCallback);
emitMessage(MessageKind::MSG, getMergedChunks(), ws, onMessageCallback);
_chunks.clear();
}
else
{
emitMessage(FRAGMENT, std::string(), ws, onMessageCallback);
emitMessage(MessageKind::FRAGMENT, std::string(), ws, onMessageCallback);
}
}
}
@ -564,7 +584,7 @@ namespace ix
sendData(wsheader_type::PONG, pingData, compress);
}
emitMessage(PING, pingData, ws, onMessageCallback);
emitMessage(MessageKind::PING, pingData, ws, onMessageCallback);
}
else if (ws.opcode == wsheader_type::PONG)
{
@ -575,7 +595,7 @@ namespace ix
std::lock_guard<std::mutex> lck(_lastReceivePongTimePointMutex);
_lastReceivePongTimePoint = std::chrono::steady_clock::now();
emitMessage(PONG, pongData, ws, onMessageCallback);
emitMessage(MessageKind::PONG, pongData, ws, onMessageCallback);
}
else if (ws.opcode == wsheader_type::CLOSE)
{
@ -605,7 +625,7 @@ namespace ix
}
// We receive a CLOSE frame from remote and are NOT the ones who triggered the close
if (_readyState != CLOSING)
if (_readyState != ReadyState::CLOSING)
{
// send back the CLOSE frame
sendCloseFrame(code, reason);
@ -646,18 +666,18 @@ namespace ix
// if an abnormal closure was raised in poll, and nothing else triggered a CLOSED state in
// the received and processed data then close the connection
if (pollPostTreatment == CHECK_OR_RAISE_ABNORMAL_CLOSE_AFTER_DISPATCH)
if (pollResult == PollResult::AbnormalClose)
{
_rxbuf.clear();
// if we previously closed the connection (CLOSING state), then set state to CLOSED (code/reason were set before)
if (_readyState == CLOSING)
if (_readyState == ReadyState::CLOSING)
{
_socket->close();
setReadyState(CLOSED);
setReadyState(ReadyState::CLOSED);
}
// if we weren't closing, then close using abnormal close code and message
else if (_readyState != CLOSED)
else if (_readyState != ReadyState::CLOSED)
{
closeSocketAndSwitchToClosedState(kAbnormalCloseCode, kAbnormalCloseMessage, 0, false);
}
@ -692,7 +712,7 @@ namespace ix
size_t wireSize = message.size();
// When the RSV1 bit is 1 it means the message is compressed
if (_enablePerMessageDeflate && ws.rsv1 && messageKind != FRAGMENT)
if (_enablePerMessageDeflate && ws.rsv1 && messageKind != MessageKind::FRAGMENT)
{
std::string decompressedMessage;
bool success = _perMessageDeflate.decompress(message, decompressedMessage);
@ -719,7 +739,7 @@ namespace ix
bool compress,
const OnProgressCallback& onProgressCallback)
{
if (_readyState == CLOSING || _readyState == CLOSED)
if (_readyState != ReadyState::OPEN)
{
return WebSocketSendInfo();
}
@ -945,7 +965,7 @@ namespace ix
{
_socket->close();
setReadyState(CLOSED);
setReadyState(ReadyState::CLOSED);
break;
}
else
@ -988,14 +1008,14 @@ namespace ix
_closeWireSize = closeWireSize;
_closeRemote = remote;
}
setReadyState(CLOSED);
setReadyState(ReadyState::CLOSED);
}
void WebSocketTransport::close(uint16_t code, const std::string& reason, size_t closeWireSize, bool remote)
{
_requestInitCancellation = true;
if (_readyState == CLOSING || _readyState == CLOSED) return;
if (_readyState == ReadyState::CLOSING || _readyState == ReadyState::CLOSED) return;
sendCloseFrame(code, reason);
{
@ -1009,7 +1029,7 @@ namespace ix
std::lock_guard<std::mutex> lock(_closingTimePointMutex);
_closingTimePoint = std::chrono::steady_clock::now();
}
setReadyState(CLOSING);
setReadyState(ReadyState::CLOSING);
// wake up the poll, but do not close yet
_socket->wakeUpFromPoll(Socket::kSendRequest);

View File

@ -40,7 +40,7 @@ namespace ix
class WebSocketTransport
{
public:
enum ReadyStateValues
enum class ReadyState
{
CLOSING,
CLOSED,
@ -48,7 +48,7 @@ namespace ix
OPEN
};
enum MessageKind
enum class MessageKind
{
MSG,
PING,
@ -56,10 +56,10 @@ namespace ix
FRAGMENT
};
enum PollPostTreatment
enum class PollResult
{
NONE,
CHECK_OR_RAISE_ABNORMAL_CLOSE_AFTER_DISPATCH
Succeeded,
AbnormalClose
};
using OnMessageCallback = std::function<void(const std::string&,
@ -84,7 +84,7 @@ namespace ix
WebSocketInitResult connectToSocket(int fd, // Server
int timeoutSecs);
PollPostTreatment poll();
PollResult poll();
WebSocketSendInfo sendBinary(const std::string& message,
const OnProgressCallback& onProgressCallback);
WebSocketSendInfo sendText(const std::string& message,
@ -96,10 +96,10 @@ namespace ix
size_t closeWireSize = 0,
bool remote = false);
ReadyStateValues getReadyState() const;
void setReadyState(ReadyStateValues readyStateValue);
ReadyState getReadyState() const;
void setReadyState(ReadyState readyState);
void setOnCloseCallback(const OnCloseCallback& onCloseCallback);
void dispatch(PollPostTreatment pollPostTreatment,
void dispatch(PollResult pollResult,
const OnMessageCallback& onMessageCallback);
size_t bufferedAmount() const;
@ -113,11 +113,11 @@ namespace ix
bool mask;
enum opcode_type {
CONTINUATION = 0x0,
TEXT_FRAME = 0x1,
TEXT_FRAME = 0x1,
BINARY_FRAME = 0x2,
CLOSE = 8,
PING = 9,
PONG = 0xa,
CLOSE = 8,
PING = 9,
PONG = 0xa,
} opcode;
int N0;
uint64_t N;
@ -153,7 +153,7 @@ namespace ix
std::shared_ptr<Socket> _socket;
// Hold the state of the connection (OPEN, CLOSED, etc...)
std::atomic<ReadyStateValues> _readyState;
std::atomic<ReadyState> _readyState;
OnCloseCallback _onCloseCallback;
uint16_t _closeCode;
@ -220,6 +220,8 @@ namespace ix
// after calling close(), if no CLOSE frame answer is received back from the remote, we should close the connexion
bool closingDelayExceeded();
void initTimePointsAndGCDAfterConnect();
void sendCloseFrame(uint16_t code, const std::string& reason);
void closeSocketAndSwitchToClosedState(uint16_t code,

View File

@ -4,7 +4,6 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include "../IXSetThreadName.h"
#include <iostream>
#include <Windows.h>
namespace ix

7
test/.gitignore vendored
View File

@ -1,9 +1,10 @@
CMakeCache.txt
package-lock.json
CMakeFiles
ixwebsocket_unittest
cmake_install.cmake
CMakeFiles
ixwebsocket_unittest
cmake_install.cmake
node_modules
ixwebsocket
Makefile
build
ixwebsocket_unittest.xml

View File

@ -5,12 +5,11 @@
cmake_minimum_required (VERSION 3.4.1)
project (ixwebsocket_unittest)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../third_party/sanitizers-cmake/cmake" ${CMAKE_MODULE_PATH})
find_package(Sanitizers)
set (CMAKE_CXX_STANDARD 14)
if (NOT WIN32)
if (UNIX)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../third_party/sanitizers-cmake/cmake" ${CMAKE_MODULE_PATH})
find_package(Sanitizers)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
set(CMAKE_LD_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread")
option(USE_TLS "Add TLS support" ON)
@ -39,18 +38,24 @@ set (SOURCES
IXWebSocketPingTest.cpp
IXWebSocketTestConnectionDisconnection.cpp
IXUrlParserTest.cpp
IXWebSocketServerTest.cpp
IXWebSocketPingTest.cpp
)
# Some unittest don't work on windows yet
if (NOT WIN32)
if (UNIX)
list(APPEND SOURCES
IXWebSocketPingTimeoutTest.cpp
# IXWebSocketPingTimeoutTest.cpp # This test isn't reliable # (multiple platforms), disabling in master
# IXWebSocketCloseTest.cpp #
cmd_websocket_chat.cpp
)
endif()
add_executable(ixwebsocket_unittest ${SOURCES})
add_sanitizers(ixwebsocket_unittest)
if (UNIX)
add_sanitizers(ixwebsocket_unittest)
endif()
if (APPLE AND USE_TLS)
target_link_libraries(ixwebsocket_unittest "-framework foundation" "-framework security")

View File

@ -27,15 +27,6 @@ namespace ix
struct Logger
{
public:
Logger& operator<<(const std::string& msg)
{
std::lock_guard<std::mutex> lock(_mutex);
std::cerr << msg;
std::cerr << std::endl;
return *this;
}
template <typename T>
Logger& operator<<(T const& obj)
{

View File

@ -0,0 +1,407 @@
/*
* IXWebSocketCloseTest.cpp
* Author: Alexandre Konieczny
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include <iostream>
#include <sstream>
#include <queue>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketServer.h>
#include "IXTest.h"
#include "catch.hpp"
using namespace ix;
namespace
{
class WebSocketClient
{
public:
WebSocketClient(int port);
void subscribe(const std::string& channel);
void start();
void stop();
void stop(uint16_t code, const std::string& reason);
bool isReady() const;
void sendMessage(const std::string& text);
uint16_t getCloseCode();
const std::string& getCloseReason();
bool getCloseRemote();
private:
ix::WebSocket _webSocket;
int _port;
mutable std::mutex _mutexCloseData;
uint16_t _closeCode;
std::string _closeReason;
bool _closeRemote;
};
WebSocketClient::WebSocketClient(int port)
: _port(port)
, _closeCode(0)
, _closeReason(std::string(""))
, _closeRemote(false)
{
;
}
bool WebSocketClient::isReady() const
{
return _webSocket.getReadyState() == ix::ReadyState::Open;
}
uint16_t WebSocketClient::getCloseCode()
{
std::lock_guard<std::mutex> lck(_mutexCloseData);
return _closeCode;
}
const std::string& WebSocketClient::getCloseReason()
{
std::lock_guard<std::mutex> lck(_mutexCloseData);
return _closeReason;
}
bool WebSocketClient::getCloseRemote()
{
std::lock_guard<std::mutex> lck(_mutexCloseData);
return _closeRemote;
}
void WebSocketClient::stop()
{
_webSocket.stop();
}
void WebSocketClient::stop(uint16_t code, const std::string& reason)
{
_webSocket.close(code, reason);
_webSocket.stop();
}
void WebSocketClient::start()
{
std::string url;
{
std::stringstream ss;
ss << "ws://localhost:"
<< _port
<< "/";
url = ss.str();
}
_webSocket.setUrl(url);
std::stringstream ss;
log(std::string("Connecting to url: ") + url);
_webSocket.setOnMessageCallback(
[this](ix::WebSocketMessageType messageType,
const std::string& str,
size_t wireSize,
const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
std::stringstream ss;
if (messageType == ix::WebSocketMessageType::Open)
{
log("client connected");
_webSocket.disableAutomaticReconnection();
}
else if (messageType == ix::WebSocketMessageType::Close)
{
log("client disconnected");
std::lock_guard<std::mutex> lck(_mutexCloseData);
_closeCode = closeInfo.code;
_closeReason = std::string(closeInfo.reason);
_closeRemote = closeInfo.remote;
_webSocket.disableAutomaticReconnection();
}
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "Error ! " << error.reason;
log(ss.str());
_webSocket.disableAutomaticReconnection();
}
else if (messageType == ix::WebSocketMessageType::Pong)
{
ss << "Received pong message " << str;
log(ss.str());
}
else if (messageType == ix::WebSocketMessageType::Ping)
{
ss << "Received ping message " << str;
log(ss.str());
}
else if (messageType == ix::WebSocketMessageType::Message)
{
ss << "Received message " << str;
log(ss.str());
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
_webSocket.start();
}
void WebSocketClient::sendMessage(const std::string& text)
{
_webSocket.send(text);
}
bool startServer(ix::WebSocketServer& server,
uint16_t& receivedCloseCode,
std::string& receivedCloseReason,
bool& receivedCloseRemote,
std::mutex& mutexWrite)
{
// A dev/null server
server.setOnConnectionCallback(
[&server, &receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
{
webSocket->setOnMessageCallback(
[webSocket, connectionState, &server, &receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](ix::WebSocketMessageType messageType,
const std::string& str,
size_t wireSize,
const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocketMessageType::Open)
{
Logger() << "New server connection";
Logger() << "id: " << connectionState->getId();
Logger() << "Uri: " << openInfo.uri;
Logger() << "Headers:";
for (auto it : openInfo.headers)
{
Logger() << it.first << ": " << it.second;
}
}
else if (messageType == ix::WebSocketMessageType::Close)
{
log("Server closed connection");
//Logger() << closeInfo.code;
//Logger() << closeInfo.reason;
//Logger() << closeInfo.remote;
std::lock_guard<std::mutex> lck(mutexWrite);
receivedCloseCode = closeInfo.code;
receivedCloseReason = std::string(closeInfo.reason);
receivedCloseRemote = closeInfo.remote;
}
}
);
}
);
auto res = server.listen();
if (!res.first)
{
log(res.second);
return false;
}
server.start();
return true;
}
}
TEST_CASE("Websocket_client_close_default", "[close]")
{
SECTION("Make sure that close code and reason was used and sent to server.")
{
ix::setupWebSocketTrafficTrackerCallback();
int port = getFreePort();
ix::WebSocketServer server(port);
uint16_t serverReceivedCloseCode(0);
bool serverReceivedCloseRemote(false);
std::string serverReceivedCloseReason("");
std::mutex mutexWrite;
REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite));
std::string session = ix::generateSessionId();
WebSocketClient webSocketClient(port);
webSocketClient.start();
// Wait for all chat instance to be ready
while (true)
{
if (webSocketClient.isReady()) break;
ix::msleep(10);
}
REQUIRE(server.getClients().size() == 1);
ix::msleep(100);
webSocketClient.stop();
ix::msleep(200);
// ensure client close is the same as values given
REQUIRE(webSocketClient.getCloseCode() == 1000);
REQUIRE(webSocketClient.getCloseReason() == "Normal closure");
REQUIRE(webSocketClient.getCloseRemote() == false);
{
std::lock_guard<std::mutex> lck(mutexWrite);
// Here we read the code/reason received by the server, and ensure that remote is true
REQUIRE(serverReceivedCloseCode == 1000);
REQUIRE(serverReceivedCloseReason == "Normal closure");
REQUIRE(serverReceivedCloseRemote == true);
}
// Give us 1000ms for the server to notice that clients went away
ix::msleep(1000);
REQUIRE(server.getClients().size() == 0);
ix::reportWebSocketTraffic();
}
}
TEST_CASE("Websocket_client_close_params_given", "[close]")
{
SECTION("Make sure that close code and reason was used and sent to server.")
{
ix::setupWebSocketTrafficTrackerCallback();
int port = getFreePort();
ix::WebSocketServer server(port);
uint16_t serverReceivedCloseCode(0);
bool serverReceivedCloseRemote(false);
std::string serverReceivedCloseReason("");
std::mutex mutexWrite;
REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite));
std::string session = ix::generateSessionId();
WebSocketClient webSocketClient(port);
webSocketClient.start();
// Wait for all chat instance to be ready
while (true)
{
if (webSocketClient.isReady()) break;
ix::msleep(10);
}
REQUIRE(server.getClients().size() == 1);
ix::msleep(100);
webSocketClient.stop(4000, "My reason");
ix::msleep(500);
// ensure client close is the same as values given
REQUIRE(webSocketClient.getCloseCode() == 4000);
REQUIRE(webSocketClient.getCloseReason() == "My reason");
REQUIRE(webSocketClient.getCloseRemote() == false);
{
std::lock_guard<std::mutex> lck(mutexWrite);
// Here we read the code/reason received by the server, and ensure that remote is true
REQUIRE(serverReceivedCloseCode == 4000);
REQUIRE(serverReceivedCloseReason == "My reason");
REQUIRE(serverReceivedCloseRemote == true);
}
// Give us 1000ms for the server to notice that clients went away
ix::msleep(1000);
REQUIRE(server.getClients().size() == 0);
ix::reportWebSocketTraffic();
}
}
TEST_CASE("Websocket_server_close", "[close]")
{
SECTION("Make sure that close code and reason was read from server.")
{
ix::setupWebSocketTrafficTrackerCallback();
int port = getFreePort();
ix::WebSocketServer server(port);
uint16_t serverReceivedCloseCode(0);
bool serverReceivedCloseRemote(false);
std::string serverReceivedCloseReason("");
std::mutex mutexWrite;
REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite));
std::string session = ix::generateSessionId();
WebSocketClient webSocketClient(port);
webSocketClient.start();
// Wait for all chat instance to be ready
while (true)
{
if (webSocketClient.isReady()) break;
ix::msleep(10);
}
REQUIRE(server.getClients().size() == 1);
ix::msleep(200);
server.stop();
ix::msleep(500);
// ensure client close is the same as values given
REQUIRE(webSocketClient.getCloseCode() == 1000);
REQUIRE(webSocketClient.getCloseReason() == "Normal closure");
REQUIRE(webSocketClient.getCloseRemote() == true);
{
std::lock_guard<std::mutex> lck(mutexWrite);
// Here we read the code/reason received by the server, and ensure that remote is true
REQUIRE(serverReceivedCloseCode == 1000);
REQUIRE(serverReceivedCloseReason == "Normal closure");
REQUIRE(serverReceivedCloseRemote == false);
}
// Give us 1000ms for the server to notice that clients went away
ix::msleep(1000);
REQUIRE(server.getClients().size() == 0);
ix::reportWebSocketTraffic();
}
}

View File

@ -43,7 +43,7 @@ namespace
bool WebSocketClient::isReady() const
{
return _webSocket.getReadyState() == ix::WebSocket_ReadyState_Open;
return _webSocket.getReadyState() == ix::ReadyState::Open;
}
void WebSocketClient::stop()
@ -88,30 +88,30 @@ namespace
const ix::WebSocketCloseInfo& closeInfo)
{
std::stringstream ss;
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
log("client connected");
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
log("client disconnected");
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "Error ! " << error.reason;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Pong)
else if (messageType == ix::WebSocketMessageType::Pong)
{
ss << "Received pong message " << str;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Ping)
else if (messageType == ix::WebSocketMessageType::Ping)
{
ss << "Received ping message " << str;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
// too many messages to log
}
@ -145,7 +145,7 @@ namespace
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
Logger() << "New server connection";
Logger() << "id: " << connectionState->getId();
@ -156,16 +156,16 @@ namespace
Logger() << it.first << ": " << it.second;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
log("Server closed connection");
}
else if (messageType == ix::WebSocket_MessageType_Ping)
else if (messageType == ix::WebSocketMessageType::Ping)
{
log("Server received a ping");
receivedPingMessages++;
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
// to many messages to log
for(auto client: server.getClients())
@ -413,13 +413,13 @@ TEST_CASE("Websocket_ping_no_data_sent_setHeartBeatPeriod", "[setHeartBeatPeriod
REQUIRE(server.getClients().size() == 1);
ix::msleep(1850);
ix::msleep(1900);
webSocketClient.stop();
// Here we test ping interval
// -> expected ping messages == 1 as 1850 seconds, 1 ping sent every second
// -> expected ping messages == 1 as 1900 seconds, 1 ping sent every second
REQUIRE(serverReceivedPingMessages == 1);
// Give us 500ms for the server to notice that clients went away
@ -460,7 +460,7 @@ TEST_CASE("Websocket_ping_data_sent_setHeartBeatPeriod", "[setHeartBeatPeriod]")
webSocketClient.sendMessage("hello world");
ix::msleep(900);
webSocketClient.sendMessage("hello world");
ix::msleep(900);
ix::msleep(1100);
webSocketClient.stop();
@ -469,7 +469,7 @@ TEST_CASE("Websocket_ping_data_sent_setHeartBeatPeriod", "[setHeartBeatPeriod]")
// Here we test ping interval
// client has sent data, but ping should have been sent no matter what
// -> expected ping messages == 2 as 900+900+900 = 2700 seconds, 1 ping sent every second
// -> expected ping messages == 2 as 900+900+1100 = 2900 seconds, 1 ping sent every second
REQUIRE(serverReceivedPingMessages == 2);
// Give us 500ms for the server to notice that clients went away

View File

@ -52,12 +52,12 @@ namespace
bool WebSocketClient::isReady() const
{
return _webSocket.getReadyState() == ix::WebSocket_ReadyState_Open;
return _webSocket.getReadyState() == ix::ReadyState::Open;
}
bool WebSocketClient::isClosed() const
{
return _webSocket.getReadyState() == ix::WebSocket_ReadyState_Closed;
return _webSocket.getReadyState() == ix::ReadyState::Closed;
}
void WebSocketClient::stop()
@ -97,12 +97,12 @@ namespace
const ix::WebSocketCloseInfo& closeInfo)
{
std::stringstream ss;
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
log("client connected");
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
log("client disconnected");
@ -112,24 +112,24 @@ namespace
}
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "Error ! " << error.reason;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Pong)
else if (messageType == ix::WebSocketMessageType::Pong)
{
_receivedPongMessages++;
ss << "Received pong message " << str;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Ping)
else if (messageType == ix::WebSocketMessageType::Ping)
{
ss << "Received ping message " << str;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
ss << "Received message " << str;
log(ss.str());
@ -174,7 +174,7 @@ namespace
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
Logger() << "New server connection";
Logger() << "id: " << connectionState->getId();
@ -185,11 +185,11 @@ namespace
Logger() << it.first << ": " << it.second;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
log("Server closed connection");
}
else if (messageType == ix::WebSocket_MessageType_Ping)
else if (messageType == ix::WebSocketMessageType::Ping)
{
log("Server received a ping");
receivedPingMessages++;
@ -350,7 +350,7 @@ TEST_CASE("Websocket_no_ping_but_timeout", "[setPingTimeout]")
REQUIRE(server.getClients().size() == 1);
ix::msleep(2700);
ix::msleep(2900);
// Here we test ping timeout, no timeout yet
REQUIRE(serverReceivedPingMessages == 0);
@ -359,7 +359,7 @@ TEST_CASE("Websocket_no_ping_but_timeout", "[setPingTimeout]")
REQUIRE(webSocketClient.isClosed() == false);
REQUIRE(webSocketClient.closedDueToPingTimeout() == false);
ix::msleep(400);
ix::msleep(200);
// Here we test ping timeout, timeout
REQUIRE(serverReceivedPingMessages == 0);
@ -410,7 +410,7 @@ TEST_CASE("Websocket_ping_timeout", "[setPingTimeout]")
REQUIRE(serverReceivedPingMessages == 1);
REQUIRE(webSocketClient.getReceivedPongMessages() == 0);
ix::msleep(1000);
ix::msleep(1100);
// Here we test ping timeout, timeout
REQUIRE(serverReceivedPingMessages == 1);

View File

@ -50,7 +50,7 @@ namespace ix
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
Logger() << "New connection";
connectionState->computeId();
@ -64,11 +64,11 @@ namespace ix
connectionId = connectionState->getId();
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
Logger() << "Closed connection";
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
for (auto&& client : server.getClients())
{

View File

@ -60,33 +60,33 @@ namespace
const ix::WebSocketCloseInfo& closeInfo)
{
std::stringstream ss;
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
log("cmd_websocket_satori_chat: connected !");
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
log("cmd_websocket_satori_chat: disconnected !");
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "cmd_websocket_satori_chat: Error! ";
ss << error.reason;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
log("cmd_websocket_satori_chat: received message.!");
}
else if (messageType == ix::WebSocket_MessageType_Ping)
else if (messageType == ix::WebSocketMessageType::Ping)
{
log("cmd_websocket_satori_chat: received ping message.!");
}
else if (messageType == ix::WebSocket_MessageType_Pong)
else if (messageType == ix::WebSocketMessageType::Pong)
{
log("cmd_websocket_satori_chat: received pong message.!");
}
else if (messageType == ix::WebSocket_MessageType_Fragment)
else if (messageType == ix::WebSocketMessageType::Fragment)
{
log("cmd_websocket_satori_chat: received fragment.!");
}
@ -109,38 +109,40 @@ TEST_CASE("websocket_connections", "[websocket]")
{
SECTION("Try to connect to invalid servers.")
{
IXWebSocketTestConnectionDisconnection chatA;
IXWebSocketTestConnectionDisconnection test;
chatA.start(GOOGLE_URL);
test.start(GOOGLE_URL);
ix::msleep(1000);
chatA.stop();
test.stop();
chatA.start(UNKNOWN_URL);
test.start(UNKNOWN_URL);
ix::msleep(1000);
chatA.stop();
test.stop();
}
SECTION("Try to connect and disconnect with different timing, not enough time to succesfully connect")
{
IXWebSocketTestConnectionDisconnection chatA;
IXWebSocketTestConnectionDisconnection test;
for (int i = 0; i < 50; ++i)
{
log(std::string("Run: ") + std::to_string(i));
chatA.start(WEBSOCKET_DOT_ORG_URL);
test.start(WEBSOCKET_DOT_ORG_URL);
ix::msleep(i);
chatA.stop();
test.stop();
}
}
// This test breaks on travis CI - Ubuntu Xenial + gcc + tsan
// We should fix this.
/*SECTION("Try to connect and disconnect with different timing, from not enough time to successfull connect")
{
IXWebSocketTestConnectionDisconnection chatA;
IXWebSocketTestConnectionDisconnection test;
for (int i = 0; i < 20; ++i)
{
log(std::string("Run: ") + std::to_string(i));
chatA.start(WEBSOCKET_DOT_ORG_URL);
test.start(WEBSOCKET_DOT_ORG_URL);
ix::msleep(i*50);
chatA.stop();
test.stop();
}
}*/
}

View File

@ -87,7 +87,7 @@ namespace
bool WebSocketChat::isReady() const
{
return _webSocket.getReadyState() == ix::WebSocket_ReadyState_Open;
return _webSocket.getReadyState() == ix::ReadyState::Open;
}
void WebSocketChat::stop()
@ -122,21 +122,21 @@ namespace
const ix::WebSocketCloseInfo& closeInfo)
{
std::stringstream ss;
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
ss << "cmd_websocket_chat: user "
<< _user
<< " Connected !";
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
ss << "cmd_websocket_chat: user "
<< _user
<< " disconnected !";
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
auto result = decodeMessage(str);
@ -159,20 +159,20 @@ namespace
<< _user << " > ";
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "cmd_websocket_chat: Error ! " << error.reason;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Ping)
else if (messageType == ix::WebSocketMessageType::Ping)
{
log("cmd_websocket_chat: received ping message");
}
else if (messageType == ix::WebSocket_MessageType_Pong)
else if (messageType == ix::WebSocketMessageType::Pong)
{
log("cmd_websocket_chat: received pong message");
}
else if (messageType == ix::WebSocket_MessageType_Fragment)
else if (messageType == ix::WebSocketMessageType::Fragment)
{
log("cmd_websocket_chat: received message fragment");
}
@ -228,7 +228,7 @@ namespace
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
Logger() << "New connection";
Logger() << "id: " << connectionState->getId();
@ -239,11 +239,11 @@ namespace
Logger() << it.first << ": " << it.second;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
log("Closed connection");
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
for (auto&& client : server.getClients())
{

View File

@ -28,9 +28,9 @@ try:
except ImportError:
hasClick = False
DEFAULT_EXE = 'ixwebsocket_unittest'
BUILD_TYPE = 'Debug'
XML_OUTPUT_FILE = 'ixwebsocket_unittest.xml'
TEST_EXE_PATH = None
class Command(object):
"""Run system commands with timeout
@ -65,7 +65,7 @@ class Command(object):
return True, self.process.returncode
def runCommand(cmd, assertOnFailure=True, timeout=None):
def runCommand(cmd, abortOnFailure=True, timeout=None):
'''Small wrapper to run a command and make sure it succeed'''
if timeout is None:
@ -73,16 +73,13 @@ def runCommand(cmd, assertOnFailure=True, timeout=None):
print('\nRunning', cmd)
command = Command(cmd)
timedout, ret = command.run(timeout)
succeed, ret = command.run(timeout)
if timedout:
print('Unittest timed out')
msg = 'cmd {} failed with error code {}'.format(cmd, ret)
if ret != 0:
if not succeed or ret != 0:
msg = 'cmd {}\nfailed with error code {}'.format(cmd, ret)
print(msg)
if assertOnFailure:
assert False
if abortOnFailure:
sys.exit(-1)
def runCMake(sanitizer, buildDir):
@ -91,12 +88,6 @@ def runCMake(sanitizer, buildDir):
(remove build sub-folder).
'''
# CMake installed via Self Service ends up here.
cmake_executable = '/Applications/CMake.app/Contents/bin/cmake'
if not os.path.exists(cmake_executable):
cmake_executable = 'cmake'
sanitizersFlags = {
'asan': '-DSANITIZE_ADDRESS=On',
'ubsan': '-DSANITIZE_UNDEFINED=On',
@ -110,19 +101,22 @@ def runCMake(sanitizer, buildDir):
if not os.path.exists(cmakeExecutable):
cmakeExecutable = 'cmake'
generator = '"Unix Makefiles"'
if platform.system() == 'Windows':
generator = '"NMake Makefiles"'
#generator = '"NMake Makefiles"'
generator = '"Visual Studio 16 2019"'
else:
generator = '"Unix Makefiles"'
fmt = '''
{cmakeExecutable} -H. \
CMAKE_BUILD_TYPE = BUILD_TYPE
fmt = '{cmakeExecutable} -H. \
{sanitizerFlag} \
-B{buildDir} \
-DCMAKE_BUILD_TYPE=Debug \
-B"{buildDir}" \
-DCMAKE_BUILD_TYPE={CMAKE_BUILD_TYPE} \
-DUSE_TLS=1 \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-G{generator}
'''
-G{generator}'
cmakeCmd = fmt.format(**locals())
runCommand(cmakeCmd)
@ -133,10 +127,10 @@ def runTest(args, buildDir, xmlOutput, testRunName):
if args is None:
args = ''
fmt = '{buildDir}/{DEFAULT_EXE} -o {xmlOutput} -n "{testRunName}" -r junit "{args}"'
testCommand = fmt.format(**locals())
testCommand = '{} -o {} -n "{}" -r junit "{}"'.format(TEST_EXE_PATH, xmlOutput, testRunName, args)
runCommand(testCommand,
assertOnFailure=False)
abortOnFailure=False)
def validateTestSuite(xmlOutput):
@ -296,8 +290,7 @@ def executeJobs(jobs):
def computeAllTestNames(buildDir):
'''Compute all test case names, by executing the unittest in a custom mode'''
executable = os.path.join(buildDir, DEFAULT_EXE)
cmd = '"{}" --list-test-names-only'.format(executable)
cmd = '"{}" --list-test-names-only'.format(TEST_EXE_PATH)
names = os.popen(cmd).read().splitlines()
names.sort() # Sort test names for execution determinism
return names
@ -344,7 +337,7 @@ def generateXmlOutput(results, xmlOutput, testRunName, runTime):
})
systemOut = ET.Element('system-out')
systemOut.text = result['output'].decode('utf-8')
systemOut.text = result['output'].decode('utf-8', 'ignore')
testCase.append(systemOut)
if not result['success']:
@ -365,16 +358,19 @@ def run(testName, buildDir, sanitizer, xmlOutput, testRunName, buildOnly, useLLD
runCMake(sanitizer, buildDir)
# build with make
makeCmd = 'make'
jobs = '-j8'
#makeCmd = 'cmake --build '
#jobs = '-j8'
if platform.system() == 'Windows':
makeCmd = 'nmake'
#if platform.system() == 'Windows':
# makeCmd = 'nmake'
# nmake does not have a -j option
jobs = ''
# jobs = ''
runCommand('{} -C {} {}'.format(makeCmd, buildDir, jobs))
#runCommand('{} -C {} {}'.format(makeCmd, buildDir, jobs))
# build with cmake
runCommand('cmake --build ' + buildDir)
if buildOnly:
return
@ -409,12 +405,7 @@ def run(testName, buildDir, sanitizer, xmlOutput, testRunName, buildOnly, useLLD
continue
# testName can contains spaces, so we enclose them in double quotes
executable = os.path.join(buildDir, DEFAULT_EXE)
if platform.system() == 'Windows':
executable += '.exe'
cmd = '{} "{}" "{}" > "{}" 2>&1'.format(lldb, executable, testName, outputPath)
cmd = '{} "{}" "{}" > "{}" 2>&1'.format(lldb, TEST_EXE_PATH, testName, outputPath)
jobs.append({
'name': testName,
@ -454,8 +445,6 @@ def main():
if not os.path.exists(buildDir):
os.makedirs(buildDir)
defaultOutput = DEFAULT_EXE + '.xml'
parser = argparse.ArgumentParser(description='Build and Run the engine unittest')
sanitizers = ['tsan', 'asan', 'ubsan', 'none']
@ -481,14 +470,29 @@ def main():
# Default sanitizer is tsan
sanitizer = args.sanitizer
if args.sanitizer is None:
if args.no_sanitizer:
sanitizer = 'none'
elif args.sanitizer is None:
sanitizer = 'tsan'
# Sanitizers display lots of strange errors on Linux on CI,
# which looks like false positives
if platform.system() != 'Darwin':
sanitizer = 'none'
defaultRunName = 'ixengine_{}_{}'.format(platform.system(), sanitizer)
xmlOutput = args.output or defaultOutput
xmlOutput = args.output or XML_OUTPUT_FILE
testRunName = args.run_name or os.getenv('IXENGINE_TEST_RUN_NAME') or defaultRunName
global TEST_EXE_PATH
if platform.system() == 'Windows':
TEST_EXE_PATH = os.path.join(buildDir, BUILD_TYPE, 'ixwebsocket_unittest.exe')
else:
TEST_EXE_PATH = os.path.join(buildDir, 'ixwebsocket_unittest')
if args.list:
# catch2 exit with a different error code when requesting the list of files
try:
@ -505,11 +509,6 @@ def main():
print('LLDB is only supported on Apple at this point')
args.lldb = False
# Sanitizers display lots of strange errors on Linux on CI,
# which looks like false positives
if platform.system() != 'Darwin':
sanitizer = 'none'
return run(args.test, buildDir, sanitizer, xmlOutput,
testRunName, args.build_only, args.lldb)

View File

@ -119,62 +119,62 @@ static void verify_length(size_t len)
}
static void dump(NullStruct, std::string &out) {
out.push_back(0xc0);
out.push_back((char) 0xc0);
}
static void dump(float value, std::string &out) {
out.push_back(0xca);
out.push_back((char) 0xca);
dump_data(value, out);
}
static void dump(double value, std::string &out) {
out.push_back(0xcb);
out.push_back((char) 0xcb);
dump_data(value, out);
}
static void dump(int8_t value, std::string &out) {
if( value < -32 )
{
out.push_back(0xd0);
out.push_back((char) 0xd0);
}
out.push_back(value);
}
static void dump(int16_t value, std::string &out) {
out.push_back(0xd1);
out.push_back((char) 0xd1);
dump_data(value, out);
}
static void dump(int32_t value, std::string &out) {
out.push_back(0xd2);
out.push_back((char) 0xd2);
dump_data(value, out);
}
static void dump(int64_t value, std::string &out) {
out.push_back(0xd3);
out.push_back((char) 0xd3);
dump_data(value, out);
}
static void dump(uint8_t value, std::string &out) {
if(128 <= value)
{
out.push_back(0xcc);
out.push_back((char) 0xcc);
}
out.push_back(value);
}
static void dump(uint16_t value, std::string &out) {
out.push_back(0xcd);
out.push_back((char) 0xcd);
dump_data(value, out);
}
static void dump(uint32_t value, std::string &out) {
out.push_back(0xce);
out.push_back((char) 0xce);
dump_data(value, out);
}
static void dump(uint64_t value, std::string &out) {
out.push_back(0xcf);
out.push_back((char) 0xcf);
dump_data(value, out);
}
@ -194,19 +194,19 @@ static void dump(const std::string& value, std::string &out) {
else if(len <= 0xff)
{
uint8_t const length = static_cast<uint8_t>(len);
out.push_back(0xd9);
out.push_back((char) 0xd9);
out.push_back(length);
}
else if(len <= 0xffff)
{
uint16_t const length = static_cast<uint16_t>(len);
out.push_back(0xda);
out.push_back((char) 0xda);
dump_data(length, out);
}
else
{
uint32_t const length = static_cast<uint32_t>(len);
out.push_back(0xdb);
out.push_back((char) 0xdb);
dump_data(length, out);
}
@ -226,13 +226,13 @@ static void dump(const MsgPack::array& value, std::string &out) {
else if(len <= 0xffff)
{
uint16_t const length = static_cast<uint16_t>(len);
out.push_back(0xdc);
out.push_back((char) 0xdc);
dump_data(length, out);
}
else
{
uint32_t const length = static_cast<uint32_t>(len);
out.push_back(0xdd);
out.push_back((char) 0xdd);
dump_data(length, out);
}
@ -252,13 +252,13 @@ static void dump(const MsgPack::object& value, std::string &out) {
else if(len <= 0xffff)
{
uint16_t const length = static_cast<uint16_t>(len);
out.push_back(0xde);
out.push_back((char) 0xde);
dump_data(length, out);
}
else
{
uint32_t const length = static_cast<uint32_t>(len);
out.push_back(0xdf);
out.push_back((char) 0xdf);
dump_data(length, out);
}
@ -274,19 +274,19 @@ static void dump(const MsgPack::binary& value, std::string &out) {
if(len <= 0xff)
{
uint8_t const length = static_cast<uint8_t>(len);
out.push_back(0xc4);
out.push_back((char) 0xc4);
dump_data(length, out);
}
else if(len <= 0xffff)
{
uint16_t const length = static_cast<uint16_t>(len);
out.push_back(0xc5);
out.push_back((char) 0xc5);
dump_data(length, out);
}
else
{
uint32_t const length = static_cast<uint32_t>(len);
out.push_back(0xc6);
out.push_back((char) 0xc6);
dump_data(length, out);
}
@ -302,33 +302,33 @@ static void dump(const MsgPack::extension& value, std::string &out) {
verify_length(len);
if(len == 0x01) {
out.push_back(0xd4);
out.push_back((char) 0xd4);
}
else if(len == 0x02) {
out.push_back(0xd5);
out.push_back((char) 0xd5);
}
else if(len == 0x04) {
out.push_back(0xd6);
out.push_back((char) 0xd6);
}
else if(len == 0x08) {
out.push_back(0xd7);
out.push_back((char) 0xd7);
}
else if(len == 0x10) {
out.push_back(0xd8);
out.push_back((char) 0xd8);
}
else if(len <= 0xff) {
uint8_t const length = static_cast<uint8_t>(len);
out.push_back(0xc7);
out.push_back((char) 0xc7);
out.push_back(length);
}
else if(len <= 0xffff) {
uint16_t const length = static_cast<uint16_t>(len);
out.push_back(0xc8);
out.push_back((char) 0xc8);
dump_data(length, out);
}
else {
uint32_t const length = static_cast<uint32_t>(len);
out.push_back(0xc9);
out.push_back((char) 0xc9);
dump_data(length, out);
}

View File

@ -108,7 +108,7 @@ int StatsdClient::init()
d->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if ( d->sock == -1 ) {
snprintf(d->errmsg, sizeof(d->errmsg), "could not create socket, err=%m");
snprintf(d->errmsg, sizeof(d->errmsg), "could not create socket, err=%s", strerror(errno));
return -1;
}
@ -229,7 +229,7 @@ int StatsdClient::send_to_daemon(const string &message) {
ret = (int) sendto(d->sock, message.data(), message.size(), 0, (struct sockaddr *) &d->server, sizeof(d->server));
if ( ret == -1) {
snprintf(d->errmsg, sizeof(d->errmsg),
"sendto server fail, host=%s:%d, err=%m", d->host.c_str(), d->port);
"sendto server fail, host=%s:%d, err=%s", d->host.c_str(), d->port, strerror(errno));
return -1;
}

View File

@ -162,7 +162,7 @@ namespace ix
std::cerr << "Download size: " << downloadSize << std::endl;
std::cerr << "Status: " << statusCode << std::endl;
if (errorCode != HttpErrorCode_Ok)
if (errorCode != HttpErrorCode::Ok)
{
std::cerr << "error message: " << errorMsg << std::endl;
}

View File

@ -100,14 +100,14 @@ namespace ix
CobraConnection::invokeTrafficTrackerCallback(wireSize, true);
std::stringstream ss;
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
invokeEventCallback(ix::CobraConnection_EventType_Open,
std::string(),
openInfo.headers);
sendHandshakeMessage();
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
_authenticated = false;
@ -117,7 +117,7 @@ namespace ix
invokeEventCallback(ix::CobraConnection_EventType_Closed,
ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
Json::Value data;
Json::Reader reader;
@ -187,7 +187,7 @@ namespace ix
invokeErrorCallback("Un-handled message type", str);
}
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << error.reason << std::endl;
@ -384,7 +384,7 @@ namespace ix
bool CobraConnection::isConnected() const
{
return _webSocket->getReadyState() == ix::WebSocket_ReadyState_Open;
return _webSocket->getReadyState() == ix::ReadyState::Open;
}
bool CobraConnection::isAuthenticated() const

View File

@ -14,6 +14,7 @@
#include "nlohmann/json.hpp"
#include <sstream>
#include <iostream>
namespace snake
{

View File

@ -65,7 +65,7 @@ namespace snake
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
std::cerr << "New connection" << std::endl;
std::cerr << "id: " << state->getId() << std::endl;
@ -86,13 +86,13 @@ namespace snake
std::cerr << "Cannot connect to redis host" << std::endl;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
std::cerr << "Closed connection"
<< " code " << closeInfo.code
<< " reason " << closeInfo.reason << std::endl;
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << error.reason << std::endl;
@ -101,11 +101,11 @@ namespace snake
ss << "HTTP Status: " << error.http_status << std::endl;
std::cerr << ss.str();
}
else if (messageType == ix::WebSocket_MessageType_Fragment)
else if (messageType == ix::WebSocketMessageType::Fragment)
{
std::cerr << "Received message fragment" << std::endl;
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
std::cerr << "Received " << wireSize << " bytes" << std::endl;
processCobraMessage(state, webSocket, _appConfig, str);

View File

@ -28,7 +28,7 @@ namespace ix
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
std::cerr << "New connection" << std::endl;
std::cerr << "id: " << connectionState->getId() << std::endl;
@ -39,13 +39,13 @@ namespace ix
std::cerr << it.first << ": " << it.second << std::endl;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
std::cerr << "Closed connection"
<< " code " << closeInfo.code
<< " reason " << closeInfo.reason << std::endl;
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << error.reason << std::endl;
@ -54,11 +54,11 @@ namespace ix
ss << "HTTP Status: " << error.http_status << std::endl;
std::cerr << ss.str();
}
else if (messageType == ix::WebSocket_MessageType_Fragment)
else if (messageType == ix::WebSocketMessageType::Fragment)
{
std::cerr << "Received message fragment" << std::endl;
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
std::cerr << "Received " << wireSize << " bytes" << std::endl;

View File

@ -68,7 +68,7 @@ namespace ix
bool WebSocketChat::isReady() const
{
return _webSocket.getReadyState() == ix::WebSocket_ReadyState_Open;
return _webSocket.getReadyState() == ix::ReadyState::Open;
}
void WebSocketChat::stop()
@ -92,7 +92,7 @@ namespace ix
const ix::WebSocketCloseInfo& closeInfo)
{
std::stringstream ss;
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
log("ws chat: connected");
std::cout << "Uri: " << openInfo.uri << std::endl;
@ -107,7 +107,7 @@ namespace ix
<< " Connected !";
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
ss << "ws chat: user "
<< _user
@ -116,7 +116,7 @@ namespace ix
<< " reason " << closeInfo.reason;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
auto result = decodeMessage(str);
@ -132,7 +132,7 @@ namespace ix
<< _user << " > ";
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "Connection error: " << error.reason << std::endl;
ss << "#retries: " << error.retries << std::endl;

View File

@ -36,9 +36,6 @@ namespace ix
{
if (disableAutomaticReconnection)
{
std::cout << "Disabling automatic reconnection with "
"_webSocket.disableAutomaticReconnection()"
" not supported yet" << std::endl;
_webSocket.disableAutomaticReconnection();
}
}
@ -73,7 +70,7 @@ namespace ix
const ix::WebSocketCloseInfo& closeInfo)
{
std::stringstream ss;
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
log("ws_connect: connected");
std::cout << "Uri: " << openInfo.uri << std::endl;
@ -83,14 +80,14 @@ namespace ix
std::cout << it.first << ": " << it.second << std::endl;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
ss << "ws_connect: connection closed:";
ss << " code " << closeInfo.code;
ss << " reason " << closeInfo.reason << std::endl;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
std::cerr << "Received " << wireSize << " bytes" << std::endl;
@ -98,7 +95,7 @@ namespace ix
<< str;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "Connection error: " << error.reason << std::endl;
ss << "#retries: " << error.retries << std::endl;
@ -106,15 +103,15 @@ namespace ix
ss << "HTTP Status: " << error.http_status << std::endl;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Fragment)
else if (messageType == ix::WebSocketMessageType::Fragment)
{
std::cerr << "Received message fragment" << std::endl;
}
else if (messageType == ix::WebSocket_MessageType_Ping)
else if (messageType == ix::WebSocketMessageType::Ping)
{
std::cerr << "Received ping" << std::endl;
}
else if (messageType == ix::WebSocket_MessageType_Pong)
else if (messageType == ix::WebSocketMessageType::Pong)
{
std::cerr << "Received pong" << std::endl;
}

View File

@ -28,7 +28,7 @@ namespace ix
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
std::cerr << "New connection" << std::endl;
std::cerr << "id: " << connectionState->getId() << std::endl;
@ -39,13 +39,13 @@ namespace ix
std::cerr << it.first << ": " << it.second << std::endl;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
std::cerr << "Closed connection"
<< " code " << closeInfo.code
<< " reason " << closeInfo.reason << std::endl;
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << error.reason << std::endl;
@ -54,7 +54,7 @@ namespace ix
ss << "HTTP Status: " << error.http_status << std::endl;
std::cerr << ss.str();
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
std::cerr << "Received "
<< wireSize << " bytes"

View File

@ -150,12 +150,12 @@ namespace ix
std::cerr << "Download size: " << downloadSize << std::endl;
std::cerr << "Status: " << statusCode << std::endl;
if (errorCode != HttpErrorCode_Ok)
if (errorCode != HttpErrorCode::Ok)
{
std::cerr << "error message: " << errorMsg << std::endl;
}
if (!headersOnly && errorCode == HttpErrorCode_Ok)
if (!headersOnly && errorCode == HttpErrorCode::Ok)
{
if (save || !output.empty())
{

View File

@ -64,7 +64,7 @@ namespace ix
std::cerr << "Received " << wireSize << " bytes" << std::endl;
std::stringstream ss;
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
log("ping_pong: connected");
@ -75,7 +75,7 @@ namespace ix
std::cout << it.first << ": " << it.second << std::endl;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
ss << "ping_pong: disconnected:"
<< " code " << closeInfo.code
@ -83,25 +83,25 @@ namespace ix
<< str;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
ss << "ping_pong: received message: "
<< str;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Ping)
else if (messageType == ix::WebSocketMessageType::Ping)
{
ss << "ping_pong: received ping message: "
<< str;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Pong)
else if (messageType == ix::WebSocketMessageType::Pong)
{
ss << "ping_pong: received pong message: "
<< str;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "Connection error: " << error.reason << std::endl;
ss << "#retries: " << error.retries << std::endl;

View File

@ -191,7 +191,7 @@ namespace ix
const ix::WebSocketCloseInfo& closeInfo)
{
std::stringstream ss;
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
_condition.notify_one();
@ -203,21 +203,21 @@ namespace ix
std::cout << it.first << ": " << it.second << std::endl;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
ss << "ws_receive: connection closed:";
ss << " code " << closeInfo.code;
ss << " reason " << closeInfo.reason << std::endl;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
ss << "ws_receive: transfered " << wireSize << " bytes";
log(ss.str());
handleMessage(str);
_condition.notify_one();
}
else if (messageType == ix::WebSocket_MessageType_Fragment)
else if (messageType == ix::WebSocketMessageType::Fragment)
{
ss << "ws_receive: received fragment " << _receivedFragmentCounter++;
log(ss.str());
@ -229,7 +229,7 @@ namespace ix
std::this_thread::sleep_for(duration);
}
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "ws_receive ";
ss << "Connection error: " << error.reason << std::endl;

View File

@ -120,7 +120,7 @@ namespace ix
const ix::WebSocketCloseInfo& closeInfo)
{
std::stringstream ss;
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
_condition.notify_one();
@ -132,14 +132,14 @@ namespace ix
std::cout << it.first << ": " << it.second << std::endl;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
ss << "ws_send: connection closed:";
ss << " code " << closeInfo.code;
ss << " reason " << closeInfo.reason << std::endl;
log(ss.str());
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
_condition.notify_one();
@ -160,7 +160,7 @@ namespace ix
std::cerr << "Invalid id" << std::endl;
}
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "ws_send ";
ss << "Connection error: " << error.reason << std::endl;

View File

@ -28,7 +28,7 @@ namespace ix
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
if (messageType == ix::WebSocket_MessageType_Open)
if (messageType == ix::WebSocketMessageType::Open)
{
std::cerr << "New connection" << std::endl;
std::cerr << "id: " << connectionState->getId() << std::endl;
@ -39,13 +39,13 @@ namespace ix
std::cerr << it.first << ": " << it.second << std::endl;
}
}
else if (messageType == ix::WebSocket_MessageType_Close)
else if (messageType == ix::WebSocketMessageType::Close)
{
std::cerr << "Closed connection"
<< " code " << closeInfo.code
<< " reason " << closeInfo.reason << std::endl;
}
else if (messageType == ix::WebSocket_MessageType_Error)
else if (messageType == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << error.reason << std::endl;
@ -54,12 +54,12 @@ namespace ix
ss << "HTTP Status: " << error.http_status << std::endl;
std::cerr << ss.str();
}
else if (messageType == ix::WebSocket_MessageType_Fragment)
else if (messageType == ix::WebSocketMessageType::Fragment)
{
std::cerr << "Received message fragment "
<< std::endl;
}
else if (messageType == ix::WebSocket_MessageType_Message)
else if (messageType == ix::WebSocketMessageType::Message)
{
std::cerr << "Received " << wireSize << " bytes" << std::endl;
for (auto&& client : server.getClients())