reformat everything with clang-format

This commit is contained in:
Benjamin Sergeant 2019-09-23 10:25:23 -07:00
parent b667c0ad40
commit 6f2fe49a7b
92 changed files with 3158 additions and 3348 deletions

View File

@ -10,14 +10,13 @@
namespace ix
{
CancellationRequest makeCancellationRequestWithTimeout(int secs,
std::atomic<bool>& requestInitCancellation)
CancellationRequest makeCancellationRequestWithTimeout(
int secs, std::atomic<bool>& requestInitCancellation)
{
auto start = std::chrono::system_clock::now();
auto timeout = std::chrono::seconds(secs);
auto isCancellationRequested = [&requestInitCancellation, start, timeout]() -> bool
{
auto isCancellationRequested = [&requestInitCancellation, start, timeout]() -> bool {
// Was an explicit cancellation requested ?
if (requestInitCancellation) return true;
@ -30,4 +29,4 @@ namespace ix
return isCancellationRequested;
}
}
} // namespace ix

View File

@ -10,7 +10,8 @@ namespace ix
{
std::atomic<uint64_t> ConnectionState::_globalId(0);
ConnectionState::ConnectionState() : _terminated(false)
ConnectionState::ConnectionState()
: _terminated(false)
{
computeId();
}
@ -39,5 +40,4 @@ namespace ix
{
_terminated = true;
}
}
} // namespace ix

View File

@ -5,22 +5,22 @@
*/
#include "IXDNSLookup.h"
#include "IXNetSystem.h"
#include <string.h>
#include "IXNetSystem.h"
#include <chrono>
#include <string.h>
#include <thread>
namespace ix
{
const int64_t DNSLookup::kDefaultWait = 1; // ms
DNSLookup::DNSLookup(const std::string& hostname, int port, int64_t wait) :
_hostname(hostname),
_port(port),
_wait(wait),
_res(nullptr),
_done(false)
DNSLookup::DNSLookup(const std::string& hostname, int port, int64_t wait)
: _hostname(hostname)
, _port(port)
, _wait(wait)
, _res(nullptr)
, _done(false)
{
;
}
@ -38,8 +38,7 @@ namespace ix
std::string sport = std::to_string(port);
struct addrinfo* res;
int getaddrinfo_result = getaddrinfo(hostname.c_str(), sport.c_str(),
&hints, &res);
int getaddrinfo_result = getaddrinfo(hostname.c_str(), sport.c_str(), &hints, &res);
if (getaddrinfo_result)
{
errMsg = gai_strerror(getaddrinfo_result);
@ -56,8 +55,8 @@ namespace ix
: resolveUnCancellable(errMsg, isCancellationRequested);
}
struct addrinfo* DNSLookup::resolveUnCancellable(std::string& errMsg,
const CancellationRequest& isCancellationRequested)
struct addrinfo* DNSLookup::resolveUnCancellable(
std::string& errMsg, const CancellationRequest& isCancellationRequested)
{
errMsg = "no error";
@ -71,8 +70,8 @@ namespace ix
return getAddrInfo(_hostname, _port, errMsg);
}
struct addrinfo* DNSLookup::resolveCancellable(std::string& errMsg,
const CancellationRequest& isCancellationRequested)
struct addrinfo* DNSLookup::resolveCancellable(
std::string& errMsg, const CancellationRequest& isCancellationRequested)
{
errMsg = "no error";
@ -126,7 +125,9 @@ namespace ix
return getRes();
}
void DNSLookup::run(std::weak_ptr<DNSLookup> self, std::string hostname, int port) // thread runner
void DNSLookup::run(std::weak_ptr<DNSLookup> self,
std::string hostname,
int port) // thread runner
{
// We don't want to read or write into members variables of an object that could be
// gone, so we use temporary variables (res) or we pass in by copy everything that
@ -167,4 +168,4 @@ namespace ix
std::lock_guard<std::mutex> lock(_resMutex);
return _res;
}
}
} // namespace ix

View File

@ -10,9 +10,8 @@
namespace ix
{
uint32_t calculateRetryWaitMilliseconds(
uint32_t retry_count,
uint32_t maxWaitBetweenReconnectionRetries)
uint32_t calculateRetryWaitMilliseconds(uint32_t retry_count,
uint32_t maxWaitBetweenReconnectionRetries)
{
uint32_t wait_time = std::pow(2, retry_count) * 100;
@ -23,4 +22,4 @@ namespace ix
return wait_time;
}
}
} // namespace ix

View File

@ -10,7 +10,6 @@
namespace ix
{
uint32_t calculateRetryWaitMilliseconds(
uint32_t retry_count,
uint32_t maxWaitBetweenReconnectionRetries);
uint32_t calculateRetryWaitMilliseconds(uint32_t retry_count,
uint32_t maxWaitBetweenReconnectionRetries);
} // namespace ix

View File

@ -5,9 +5,9 @@
*/
#include "IXHttp.h"
#include "IXCancellationRequest.h"
#include "IXSocket.h"
#include <sstream>
#include <vector>
@ -57,7 +57,8 @@ namespace ix
return std::make_pair(httpVersion, statusCode);
}
std::tuple<std::string, std::string, std::string> Http::parseRequestLine(const std::string& line)
std::tuple<std::string, std::string, std::string> Http::parseRequestLine(
const std::string& line)
{
// Request-Line = Method SP Request-URI SP HTTP-Version CRLF
std::string token;
@ -114,8 +115,8 @@ namespace ix
// Parse request line (GET /foo HTTP/1.1\r\n)
auto requestLine = Http::parseRequestLine(line);
auto method = std::get<0>(requestLine);
auto uri = std::get<1>(requestLine);
auto method = std::get<0>(requestLine);
auto uri = std::get<1>(requestLine);
auto httpVersion = std::get<2>(requestLine);
// Retrieve and validate HTTP headers
@ -161,8 +162,6 @@ namespace ix
return false;
}
return response->payload.empty()
? true
: socket->writeBytes(response->payload, nullptr);
return response->payload.empty() ? true : socket->writeBytes(response->payload, nullptr);
}
}
} // namespace ix

View File

@ -115,8 +115,7 @@ namespace ix
std::shared_ptr<Socket> socket);
static bool sendResponse(HttpResponsePtr response, std::shared_ptr<Socket> socket);
static std::pair<std::string, int> parseStatusLine(
const std::string& line);
static std::pair<std::string, int> parseStatusLine(const std::string& line);
static std::tuple<std::string, std::string, std::string> parseRequestLine(
const std::string& line);
static std::string trim(const std::string& str);

View File

@ -5,17 +5,16 @@
*/
#include "IXHttpClient.h"
#include "IXSocketFactory.h"
#include "IXUrlParser.h"
#include "IXUserAgent.h"
#include "IXWebSocketHttpHeaders.h"
#include "IXSocketFactory.h"
#include <sstream>
#include <iomanip>
#include <vector>
#include <cstring>
#include <assert.h>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <vector>
#include <zlib.h>
namespace ix
@ -26,7 +25,9 @@ namespace ix
const std::string HttpClient::kDel = "DEL";
const std::string HttpClient::kPut = "PUT";
HttpClient::HttpClient(bool async) : _async(async), _stop(false)
HttpClient::HttpClient(bool async)
: _async(async)
, _stop(false)
{
if (!_async) return;
@ -42,8 +43,7 @@ namespace ix
_thread.join();
}
HttpRequestArgsPtr HttpClient::createRequest(const std::string& url,
const std::string& verb)
HttpRequestArgsPtr HttpClient::createRequest(const std::string& url, const std::string& verb)
{
auto request = std::make_shared<HttpRequestArgs>();
request->url = url;
@ -106,12 +106,11 @@ namespace ix
}
}
HttpResponsePtr HttpClient::request(
const std::string& url,
const std::string& verb,
const std::string& body,
HttpRequestArgsPtr args,
int redirects)
HttpResponsePtr HttpClient::request(const std::string& url,
const std::string& verb,
const std::string& body,
HttpRequestArgsPtr args,
int redirects)
{
// We only have one socket connection, so we cannot
// make multiple requests concurrently.
@ -131,9 +130,14 @@ namespace ix
{
std::stringstream ss;
ss << "Cannot parse url: " << url;
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::UrlMalformed,
headers, payload, ss.str(),
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::UrlMalformed,
headers,
payload,
ss.str(),
uploadSize,
downloadSize);
}
bool tls = protocol == "https";
@ -143,9 +147,14 @@ namespace ix
if (!_socket)
{
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::CannotCreateSocket,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::CannotCreateSocket,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
// Build request string
@ -155,7 +164,8 @@ namespace ix
if (args->compress)
{
ss << "Accept-Encoding: gzip" << "\r\n";
ss << "Accept-Encoding: gzip"
<< "\r\n";
}
// Append extra headers
@ -167,7 +177,8 @@ namespace ix
// Set a default Accept header if none is present
if (headers.find("Accept") == headers.end())
{
ss << "Accept: */*" << "\r\n";
ss << "Accept: */*"
<< "\r\n";
}
// Set a default User agent if none is present
@ -183,7 +194,8 @@ namespace ix
// Set default Content-Type if unspecified
if (args->extraHeaders.find("Content-Type") == args->extraHeaders.end())
{
ss << "Content-Type: application/x-www-form-urlencoded" << "\r\n";
ss << "Content-Type: application/x-www-form-urlencoded"
<< "\r\n";
}
ss << "\r\n";
ss << body;
@ -206,9 +218,14 @@ namespace ix
{
std::stringstream ss;
ss << "Cannot connect to url: " << url << " / error : " << errMsg;
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::CannotConnect,
headers, payload, ss.str(),
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::CannotConnect,
headers,
payload,
ss.str(),
uploadSize,
downloadSize);
}
// Make a new cancellation object dealing with transfer timeout
@ -222,8 +239,7 @@ namespace ix
<< "to " << host << ":" << port << std::endl
<< "request size: " << req.size() << " bytes" << std::endl
<< "=============" << std::endl
<< req
<< "=============" << std::endl
<< req << "=============" << std::endl
<< std::endl;
log(ss.str(), args);
@ -232,9 +248,14 @@ namespace ix
if (!_socket->writeBytes(req, isCancellationRequested))
{
std::string errorMsg("Cannot send request");
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::SendError,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::SendError,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
uploadSize = req.size();
@ -246,9 +267,14 @@ namespace ix
if (!lineValid)
{
std::string errorMsg("Cannot retrieve status line");
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::CannotReadStatusLine,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::CannotReadStatusLine,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
if (args->verbose)
@ -261,9 +287,14 @@ 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_shared<HttpResponse>(code, description, HttpErrorCode::MissingStatus,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::MissingStatus,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
auto result = parseHttpHeaders(_socket, isCancellationRequested);
@ -273,9 +304,14 @@ namespace ix
if (!headersValid)
{
std::string errorMsg("Cannot parse http headers");
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::HeaderParsingError,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::HeaderParsingError,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
// Redirect ?
@ -284,30 +320,45 @@ namespace ix
if (headers.find("Location") == headers.end())
{
std::string errorMsg("Missing location header for redirect");
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::MissingLocation,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::MissingLocation,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
if (redirects >= args->maxRedirects)
{
std::stringstream ss;
ss << "Too many redirects: " << redirects;
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::TooManyRedirects,
headers, payload, ss.str(),
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::TooManyRedirects,
headers,
payload,
ss.str(),
uploadSize,
downloadSize);
}
// Recurse
std::string location = headers["Location"];
return request(location, verb, body, args, redirects+1);
return request(location, verb, body, args, redirects + 1);
}
if (verb == "HEAD")
{
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::Ok,
headers, payload, std::string(),
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::Ok,
headers,
payload,
std::string(),
uploadSize,
downloadSize);
}
// Parse response:
@ -320,15 +371,19 @@ namespace ix
payload.reserve(contentLength);
auto chunkResult = _socket->readBytes(contentLength,
args->onProgressCallback,
isCancellationRequested);
auto chunkResult = _socket->readBytes(
contentLength, args->onProgressCallback, isCancellationRequested);
if (!chunkResult.first)
{
errorMsg = "Cannot read chunk";
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::ChunkReadError,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
payload += chunkResult.second;
}
@ -344,9 +399,14 @@ namespace ix
if (!lineResult.first)
{
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::ChunkReadError,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
uint64_t chunkSize;
@ -357,23 +417,26 @@ namespace ix
if (args->verbose)
{
std::stringstream oss;
oss << "Reading " << chunkSize << " bytes"
<< std::endl;
oss << "Reading " << chunkSize << " bytes" << std::endl;
log(oss.str(), args);
}
payload.reserve(payload.size() + (size_t) chunkSize);
// Read a chunk
auto chunkResult = _socket->readBytes((size_t) chunkSize,
args->onProgressCallback,
isCancellationRequested);
auto chunkResult = _socket->readBytes(
(size_t) chunkSize, args->onProgressCallback, isCancellationRequested);
if (!chunkResult.first)
{
errorMsg = "Cannot read chunk";
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::ChunkReadError,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
payload += chunkResult.second;
@ -382,9 +445,14 @@ namespace ix
if (!lineResult.first)
{
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::ChunkReadError,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::ChunkReadError,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
if (chunkSize == 0) break;
@ -397,9 +465,14 @@ namespace ix
else
{
std::string errorMsg("Cannot read http body");
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::CannotReadBody,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::CannotReadBody,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
downloadSize = payload.size();
@ -411,32 +484,39 @@ namespace ix
if (!gzipInflate(payload, decompressedPayload))
{
std::string errorMsg("Error decompressing payload");
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::Gzip,
headers, payload, errorMsg,
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::Gzip,
headers,
payload,
errorMsg,
uploadSize,
downloadSize);
}
payload = decompressedPayload;
}
return std::make_shared<HttpResponse>(code, description, HttpErrorCode::Ok,
headers, payload, std::string(),
uploadSize, downloadSize);
return std::make_shared<HttpResponse>(code,
description,
HttpErrorCode::Ok,
headers,
payload,
std::string(),
uploadSize,
downloadSize);
}
HttpResponsePtr HttpClient::get(const std::string& url,
HttpRequestArgsPtr args)
HttpResponsePtr HttpClient::get(const std::string& url, HttpRequestArgsPtr args)
{
return request(url, kGet, std::string(), args);
}
HttpResponsePtr HttpClient::head(const std::string& url,
HttpRequestArgsPtr args)
HttpResponsePtr HttpClient::head(const std::string& url, HttpRequestArgsPtr args)
{
return request(url, kHead, std::string(), args);
}
HttpResponsePtr HttpClient::del(const std::string& url,
HttpRequestArgsPtr args)
HttpResponsePtr HttpClient::del(const std::string& url, HttpRequestArgsPtr args)
{
return request(url, kDel, std::string(), args);
}
@ -475,8 +555,7 @@ namespace ix
escaped.fill('0');
escaped << std::hex;
for (std::string::const_iterator i = value.begin(), n = value.end();
i != n; ++i)
for (std::string::const_iterator i = value.begin(), n = value.end(); i != n; ++i)
{
std::string::value_type c = (*i);
@ -504,21 +583,17 @@ namespace ix
for (auto&& it : httpParameters)
{
ss << urlEncode(it.first)
<< "="
<< urlEncode(it.second);
ss << urlEncode(it.first) << "=" << urlEncode(it.second);
if (i++ < (count-1))
if (i++ < (count - 1))
{
ss << "&";
ss << "&";
}
}
return ss.str();
}
bool HttpClient::gzipInflate(
const std::string& in,
std::string& out)
bool HttpClient::gzipInflate(const std::string& in, std::string& out)
{
z_stream inflateState;
std::memset(&inflateState, 0, sizeof(inflateState));
@ -529,13 +604,13 @@ namespace ix
inflateState.avail_in = 0;
inflateState.next_in = Z_NULL;
if (inflateInit2(&inflateState, 16+MAX_WBITS) != Z_OK)
if (inflateInit2(&inflateState, 16 + MAX_WBITS) != Z_OK)
{
return false;
}
inflateState.avail_in = (uInt) in.size();
inflateState.next_in = (unsigned char *)(const_cast<char *>(in.data()));
inflateState.next_in = (unsigned char*) (const_cast<char*>(in.data()));
const int kBufferSize = 1 << 14;
@ -555,22 +630,19 @@ namespace ix
return false;
}
out.append(
reinterpret_cast<char *>(compressBuffer.get()),
kBufferSize - inflateState.avail_out
);
out.append(reinterpret_cast<char*>(compressBuffer.get()),
kBufferSize - inflateState.avail_out);
} while (inflateState.avail_out == 0);
inflateEnd(&inflateState);
return true;
}
void HttpClient::log(const std::string& msg,
HttpRequestArgsPtr args)
void HttpClient::log(const std::string& msg, HttpRequestArgsPtr args)
{
if (args->logger)
{
args->logger(msg);
}
}
}
} // namespace ix

View File

@ -5,13 +5,13 @@
*/
#include "IXHttpServer.h"
#include "IXNetSystem.h"
#include "IXSocketConnect.h"
#include "IXSocketFactory.h"
#include "IXNetSystem.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>
namespace
@ -28,7 +28,7 @@ namespace
file.seekg(0, file.beg);
memblock.resize((size_t) size);
file.read((char*)&memblock.front(), static_cast<std::streamsize>(size));
file.read((char*) &memblock.front(), static_cast<std::streamsize>(size));
return std::make_pair(true, memblock);
}
@ -39,15 +39,13 @@ namespace
auto vec = res.second;
return std::make_pair(res.first, std::string(vec.begin(), vec.end()));
}
}
} // namespace
namespace ix
{
HttpServer::HttpServer(int port,
const std::string& host,
int backlog,
size_t maxConnections) : SocketServer(port, host, backlog, maxConnections),
_connectedClientsCount(0)
HttpServer::HttpServer(int port, const std::string& host, int backlog, size_t maxConnections)
: SocketServer(port, host, backlog, maxConnections)
, _connectedClientsCount(0)
{
setDefaultConnectionCallback();
}
@ -71,9 +69,7 @@ namespace ix
_onConnectionCallback = callback;
}
void HttpServer::handleConnection(
int fd,
std::shared_ptr<ConnectionState> connectionState)
void HttpServer::handleConnection(int fd, std::shared_ptr<ConnectionState> connectionState)
{
_connectedClientsCount++;
@ -109,8 +105,7 @@ namespace ix
{
setOnConnectionCallback(
[this](HttpRequestPtr request,
std::shared_ptr<ConnectionState> /*connectionState*/) -> HttpResponsePtr
{
std::shared_ptr<ConnectionState> /*connectionState*/) -> HttpResponsePtr {
std::string uri(request->uri);
if (uri.empty() || uri == "/")
{
@ -122,23 +117,16 @@ namespace ix
bool found = res.first;
if (!found)
{
return std::make_shared<HttpResponse>(404, "Not Found",
HttpErrorCode::Ok,
WebSocketHttpHeaders(),
std::string());
return std::make_shared<HttpResponse>(
404, "Not Found", HttpErrorCode::Ok, WebSocketHttpHeaders(), std::string());
}
std::string content = res.second;
// Log request
std::stringstream ss;
ss << request->method
<< " "
<< request->headers["User-Agent"]
<< " "
<< request->uri
<< " "
<< content.size();
ss << request->method << " " << request->headers["User-Agent"] << " "
<< request->uri << " " << content.size();
logInfo(ss.str());
WebSocketHttpHeaders headers;
@ -151,11 +139,8 @@ namespace ix
headers[it.first] = it.second;
}
return std::make_shared<HttpResponse>(200, "OK",
HttpErrorCode::Ok,
headers,
content);
}
);
return std::make_shared<HttpResponse>(
200, "OK", HttpErrorCode::Ok, headers, content);
});
}
}
} // namespace ix

View File

@ -42,7 +42,7 @@ namespace ix
//
// So we make it a select wrapper
//
int poll(struct pollfd *fds, nfds_t nfds, int timeout)
int poll(struct pollfd* fds, nfds_t nfds, int timeout)
{
#ifdef _WIN32
int maxfd = 0;
@ -53,7 +53,7 @@ namespace ix
for (nfds_t i = 0; i < nfds; ++i)
{
struct pollfd *fd = &fds[i];
struct pollfd* fd = &fds[i];
if (fd->fd > maxfd)
{
@ -77,8 +77,7 @@ namespace ix
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
int ret = select(maxfd + 1, &readfds, &writefds, &errorfds,
timeout != -1 ? &tv : NULL);
int ret = select(maxfd + 1, &readfds, &writefds, &errorfds, timeout != -1 ? &tv : NULL);
if (ret < 0)
{
@ -87,7 +86,7 @@ namespace ix
for (nfds_t i = 0; i < nfds; ++i)
{
struct pollfd *fd = &fds[i];
struct pollfd* fd = &fds[i];
fd->revents = 0;
if (FD_ISSET(fd->fd, &readfds))

View File

@ -42,5 +42,4 @@ namespace ix
{
return -1;
}
}
} // namespace ix

View File

@ -26,14 +26,13 @@
#include "IXSelectInterruptEventFd.h"
#include <sys/eventfd.h>
#include <unistd.h> // for write
#include <string.h> // for strerror
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sstream>
#include <string.h> // for strerror
#include <sys/eventfd.h>
#include <unistd.h> // for write
namespace ix
{
@ -113,4 +112,4 @@ namespace ix
{
return _eventfd;
}
}
} // namespace ix

View File

@ -7,9 +7,9 @@
#include "IXSelectInterruptFactory.h"
#if defined(__linux__) || defined(__APPLE__)
# include <ixwebsocket/IXSelectInterruptPipe.h>
#include <ixwebsocket/IXSelectInterruptPipe.h>
#else
# include <ixwebsocket/IXSelectInterrupt.h>
#include <ixwebsocket/IXSelectInterrupt.h>
#endif
namespace ix
@ -22,4 +22,4 @@ namespace ix
return std::make_shared<SelectInterrupt>();
#endif
}
}
} // namespace ix

View File

@ -10,12 +10,12 @@
#include "IXSelectInterruptPipe.h"
#include <unistd.h> // for write
#include <string.h> // for strerror
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sstream>
#include <string.h> // for strerror
#include <unistd.h> // for write
namespace ix
{
@ -143,4 +143,4 @@ namespace ix
return _fildes[kPipeReadIndex];
}
}
} // namespace ix

View File

@ -5,21 +5,20 @@
*/
#include "IXSocket.h"
#include "IXSocketConnect.h"
#include "IXNetSystem.h"
#include "IXSelectInterrupt.h"
#include "IXSelectInterruptFactory.h"
#include "IXSocketConnect.h"
#include <algorithm>
#include <assert.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/types.h>
#include <algorithm>
#ifdef min
#undef min
#endif
@ -32,9 +31,9 @@ namespace ix
const uint64_t Socket::kCloseRequest = 2;
constexpr size_t Socket::kChunkSize;
Socket::Socket(int fd) :
_sockfd(fd),
_selectInterrupt(createSelectInterrupt())
Socket::Socket(int fd)
: _sockfd(fd)
, _selectInterrupt(createSelectInterrupt())
{
;
}
@ -123,8 +122,7 @@ namespace ix
// getsockopt() puts the errno value for connect into optval so 0
// means no-error.
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1 ||
optval != 0)
if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) == -1 || optval != 0)
{
pollResult = PollResultType::Error;
@ -201,7 +199,7 @@ namespace ix
ssize_t Socket::send(const std::string& buffer)
{
return send((char*)&buffer[0], buffer.size());
return send((char*) &buffer[0], buffer.size());
}
ssize_t Socket::recv(void* buffer, size_t length)
@ -263,7 +261,7 @@ namespace ix
{
if (isCancellationRequested && isCancellationRequested()) return false;
ssize_t ret = send((char*)&str[offset], len);
ssize_t ret = send((char*) &str[offset], len);
// We wrote some bytes, as needed, all good.
if (ret > 0)
@ -292,8 +290,7 @@ namespace ix
}
}
bool Socket::readByte(void* buffer,
const CancellationRequest& isCancellationRequested)
bool Socket::readByte(void* buffer, const CancellationRequest& isCancellationRequested)
{
while (true)
{
@ -332,7 +329,7 @@ namespace ix
std::string line;
line.reserve(64);
for (int i = 0; i < 2 || (line[i-2] != '\r' && line[i-1] != '\n'); ++i)
for (int i = 0; i < 2 || (line[i - 2] != '\r' && line[i - 1] != '\n'); ++i)
{
if (!readByte(&c, isCancellationRequested))
{
@ -365,13 +362,11 @@ namespace ix
}
size_t size = std::min(kChunkSize, length - output.size());
ssize_t ret = recv((char*)&_readBuffer[0], size);
ssize_t ret = recv((char*) &_readBuffer[0], size);
if (ret > 0)
{
output.insert(output.end(),
_readBuffer.begin(),
_readBuffer.begin() + ret);
output.insert(output.end(), _readBuffer.begin(), _readBuffer.begin() + ret);
}
else if (ret <= 0 && !Socket::isWaitNeeded())
{
@ -388,7 +383,6 @@ namespace ix
}
}
return std::make_pair(true, std::string(output.begin(),
output.end()));
return std::make_pair(true, std::string(output.begin(), output.end()));
}
}
} // namespace ix

View File

@ -6,11 +6,13 @@
* Adapted from Satori SDK Apple SSL code.
*/
#include "IXSocketAppleSSL.h"
#include "IXSocketConnect.h"
#include "IXSocketConnect.h"
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/tcp.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -18,132 +20,125 @@
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#define socketerrno errno
#include <Security/SecureTransport.h>
namespace {
OSStatus read_from_socket(SSLConnectionRef connection, void *data, size_t *len)
namespace
{
int fd = (int) (long) connection;
if (fd < 0)
return errSSLInternal;
assert(data != nullptr);
assert(len != nullptr);
size_t requested_sz = *len;
ssize_t status = read(fd, data, requested_sz);
if (status > 0)
OSStatus read_from_socket(SSLConnectionRef connection, void* data, size_t* len)
{
*len = (size_t) status;
if (requested_sz > *len)
return errSSLWouldBlock;
else
return noErr;
}
else if (0 == status)
{
*len = 0;
return errSSLClosedGraceful;
}
else
{
*len = 0;
switch (errno) {
case ENOENT:
return errSSLClosedGraceful;
int fd = (int) (long) connection;
if (fd < 0) return errSSLInternal;
case EAGAIN:
assert(data != nullptr);
assert(len != nullptr);
size_t requested_sz = *len;
ssize_t status = read(fd, data, requested_sz);
if (status > 0)
{
*len = (size_t) status;
if (requested_sz > *len)
return errSSLWouldBlock;
case ECONNRESET:
return errSSLClosedAbort;
default:
return errSecIO;
else
return noErr;
}
}
}
OSStatus write_to_socket(SSLConnectionRef connection, const void *data, size_t *len)
{
int fd = (int) (long) connection;
if (fd < 0)
return errSSLInternal;
assert(data != nullptr);
assert(len != nullptr);
size_t to_write_sz = *len;
ssize_t status = write(fd, data, to_write_sz);
if (status > 0)
{
*len = (size_t) status;
if (to_write_sz > *len)
return errSSLWouldBlock;
else
return noErr;
}
else if (0 == status)
{
*len = 0;
return errSSLClosedGraceful;
}
else
{
*len = 0;
if (EAGAIN == errno)
else if (0 == status)
{
return errSSLWouldBlock;
*len = 0;
return errSSLClosedGraceful;
}
else
{
return errSecIO;
}
}
}
std::string getSSLErrorDescription(OSStatus status)
{
std::string errMsg("Unknown SSL error.");
CFErrorRef error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL);
if (error)
{
CFStringRef message = CFErrorCopyDescription(error);
if (message)
{
char localBuffer[128];
Boolean success;
success = CFStringGetCString(message, localBuffer, 128,
CFStringGetSystemEncoding());
if (success)
*len = 0;
switch (errno)
{
errMsg = localBuffer;
case ENOENT: return errSSLClosedGraceful;
case EAGAIN: return errSSLWouldBlock;
case ECONNRESET: return errSSLClosedAbort;
default: return errSecIO;
}
CFRelease(message);
}
CFRelease(error);
}
return errMsg;
}
OSStatus write_to_socket(SSLConnectionRef connection, const void* data, size_t* len)
{
int fd = (int) (long) connection;
if (fd < 0) return errSSLInternal;
assert(data != nullptr);
assert(len != nullptr);
size_t to_write_sz = *len;
ssize_t status = write(fd, data, to_write_sz);
if (status > 0)
{
*len = (size_t) status;
if (to_write_sz > *len)
return errSSLWouldBlock;
else
return noErr;
}
else if (0 == status)
{
*len = 0;
return errSSLClosedGraceful;
}
else
{
*len = 0;
if (EAGAIN == errno)
{
return errSSLWouldBlock;
}
else
{
return errSecIO;
}
}
}
std::string getSSLErrorDescription(OSStatus status)
{
std::string errMsg("Unknown SSL error.");
CFErrorRef error = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, status, NULL);
if (error)
{
CFStringRef message = CFErrorCopyDescription(error);
if (message)
{
char localBuffer[128];
Boolean success;
success =
CFStringGetCString(message, localBuffer, 128, CFStringGetSystemEncoding());
if (success)
{
errMsg = localBuffer;
}
CFRelease(message);
}
CFRelease(error);
}
return errMsg;
}
} // anonymous namespace
namespace ix
{
SocketAppleSSL::SocketAppleSSL(const SocketTLSOptions& tlsOptions, int fd) : Socket(fd),
_sslContext(nullptr),
_tlsOptions(tlsOptions)
SocketAppleSSL::SocketAppleSSL(const SocketTLSOptions& tlsOptions, int fd)
: Socket(fd)
, _sslContext(nullptr)
, _tlsOptions(tlsOptions)
{
;
}
@ -169,14 +164,14 @@ namespace ix
_sslContext = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
SSLSetIOFuncs(_sslContext, read_from_socket, write_to_socket);
SSLSetConnection(_sslContext, (SSLConnectionRef) (long) _sockfd);
SSLSetConnection(_sslContext, (SSLConnectionRef)(long) _sockfd);
SSLSetProtocolVersionMin(_sslContext, kTLSProtocol12);
SSLSetPeerDomainName(_sslContext, host.c_str(), host.size());
do {
do
{
status = SSLHandshake(_sslContext);
} while (errSSLWouldBlock == status ||
errSSLServerAuthCompleted == status);
} while (errSSLWouldBlock == status || errSSLServerAuthCompleted == status);
}
if (noErr != status)
@ -206,7 +201,8 @@ namespace ix
{
ssize_t ret = 0;
OSStatus status;
do {
do
{
size_t processed = 0;
std::lock_guard<std::mutex> lock(_mutex);
status = SSLWrite(_sslContext, buf, nbyte, &processed);
@ -215,14 +211,13 @@ namespace ix
nbyte -= processed;
} while (nbyte > 0 && errSSLWouldBlock == status);
if (ret == 0 && errSSLClosedAbort != status)
ret = -1;
if (ret == 0 && errSSLClosedAbort != status) ret = -1;
return ret;
}
ssize_t SocketAppleSSL::send(const std::string& buffer)
{
return send((char*)&buffer[0], buffer.size());
return send((char*) &buffer[0], buffer.size());
}
// No wait support
@ -235,13 +230,11 @@ namespace ix
std::lock_guard<std::mutex> lock(_mutex);
status = SSLRead(_sslContext, buf, nbyte, &processed);
if (processed > 0)
return (ssize_t) processed;
if (processed > 0) return (ssize_t) processed;
// The connection was reset, inform the caller that this
// Socket should close
if (status == errSSLClosedGraceful ||
status == errSSLClosedNoNotify ||
if (status == errSSLClosedGraceful || status == errSSLClosedNoNotify ||
status == errSSLClosedAbort)
{
errno = ECONNRESET;
@ -257,4 +250,4 @@ namespace ix
return -1;
}
}
} // namespace ix

View File

@ -5,36 +5,34 @@
*/
#include "IXSocketConnect.h"
#include "IXDNSLookup.h"
#include "IXNetSystem.h"
#include "IXSocket.h"
#include <string.h>
#include <fcntl.h>
#include <string.h>
#include <sys/types.h>
// Android needs extra headers for TCP_NODELAY and IPPROTO_TCP
#ifdef ANDROID
# include <linux/in.h>
# include <linux/tcp.h>
#include <linux/in.h>
#include <linux/tcp.h>
#endif
namespace ix
{
//
// This function can be cancelled every 50 ms
// This is important so that we don't block the main UI thread when shutting down a connection which is
// already trying to reconnect, and can be blocked waiting for ::connect to respond.
// This is important so that we don't block the main UI thread when shutting down a connection
// which is already trying to reconnect, and can be blocked waiting for ::connect to respond.
//
int SocketConnect::connectToAddress(const struct addrinfo *address,
int SocketConnect::connectToAddress(const struct addrinfo* address,
std::string& errMsg,
const CancellationRequest& isCancellationRequested)
{
errMsg = "no error";
int fd = socket(address->ai_family,
address->ai_socktype,
address->ai_protocol);
int fd = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
if (fd < 0)
{
errMsg = "Cannot create a socket";
@ -74,8 +72,7 @@ namespace ix
else if (pollResult == PollResultType::Error)
{
Socket::closeSocket(fd);
errMsg = std::string("Connect error: ") +
strerror(Socket::getErrno());
errMsg = std::string("Connect error: ") + strerror(Socket::getErrno());
return -1;
}
else if (pollResult == PollResultType::ReadyForWrite)
@ -85,8 +82,7 @@ namespace ix
else
{
Socket::closeSocket(fd);
errMsg = std::string("Connect error: ") +
strerror(Socket::getErrno());
errMsg = std::string("Connect error: ") + strerror(Socket::getErrno());
return -1;
}
}
@ -105,7 +101,7 @@ namespace ix
// First do DNS resolution
//
auto dnsLookup = std::make_shared<DNSLookup>(hostname, port);
struct addrinfo *res = dnsLookup->resolve(errMsg, isCancellationRequested);
struct addrinfo* res = dnsLookup->resolve(errMsg, isCancellationRequested);
if (res == nullptr)
{
return -1;
@ -114,7 +110,7 @@ namespace ix
int sockfd = -1;
// iterate through the records to find a working peer
struct addrinfo *address;
struct addrinfo* address;
for (address = res; address != nullptr; address = address->ai_next)
{
//
@ -149,8 +145,7 @@ namespace ix
// 3. (apple) prevent SIGPIPE from being emitted when the remote end disconnect
#ifdef SO_NOSIGPIPE
int value = 1;
setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE,
(void *)&value, sizeof(value));
setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void*) &value, sizeof(value));
#endif
}
}
} // namespace ix

View File

@ -7,15 +7,16 @@
#pragma once
#include "IXSocketTLSOptions.h"
#include <memory>
#include <string>
#include "IXSocketTLSOptions.h"
namespace ix
{
class Socket;
std::shared_ptr<Socket> createSocket(bool tls, std::string& errorMsg, const SocketTLSOptions& tlsOptions);
std::shared_ptr<Socket> createSocket(bool tls,
std::string& errorMsg,
const SocketTLSOptions& tlsOptions);
std::shared_ptr<Socket> createSocket(int fd, std::string& errorMsg);
} // namespace ix

View File

@ -9,16 +9,16 @@
*/
#include "IXSocketMbedTLS.h"
#include "IXSocketConnect.h"
#include "IXNetSystem.h"
#include "IXSocket.h"
#include "IXSocketConnect.h"
#include <string.h>
namespace ix
{
SocketMbedTLS::SocketMbedTLS(const SocketTLSOptions& tlsOptions) :
_tlsOptions(tlsOptions)
SocketMbedTLS::SocketMbedTLS(const SocketTLSOptions& tlsOptions)
: _tlsOptions(tlsOptions)
{
;
}
@ -36,13 +36,13 @@ namespace ix
mbedtls_ssl_config_init(&_conf);
mbedtls_ctr_drbg_init(&_ctr_drbg);
const char *pers = "IXSocketMbedTLS";
const char* pers = "IXSocketMbedTLS";
mbedtls_entropy_init(&_entropy);
if (mbedtls_ctr_drbg_seed(&_ctr_drbg,
mbedtls_entropy_func,
&_entropy,
(const unsigned char *) pers,
(const unsigned char*) pers,
strlen(pers)) != 0)
{
errMsg = "Setting entropy seed failed";
@ -52,7 +52,7 @@ namespace ix
if (mbedtls_ssl_config_defaults(&_conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT ) != 0)
MBEDTLS_SSL_PRESET_DEFAULT) != 0)
{
errMsg = "Setting config default failed";
return false;
@ -102,8 +102,7 @@ namespace ix
{
std::lock_guard<std::mutex> lock(_mutex);
res = mbedtls_ssl_handshake(&_ssl);
}
while (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE);
} while (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE);
if (res != 0)
{
@ -142,13 +141,18 @@ namespace ix
ssize_t res = mbedtls_ssl_write(&_ssl, (unsigned char*) buf, nbyte);
if (res > 0) {
if (res > 0)
{
nbyte -= res;
sent += res;
} else if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE) {
}
else if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE)
{
errno = EWOULDBLOCK;
return -1;
} else {
}
else
{
return -1;
}
}
@ -157,7 +161,7 @@ namespace ix
ssize_t SocketMbedTLS::send(const std::string& buffer)
{
return send((char*)&buffer[0], buffer.size());
return send((char*) &buffer[0], buffer.size());
}
ssize_t SocketMbedTLS::recv(void* buf, size_t nbyte)
@ -181,4 +185,4 @@ namespace ix
}
}
}
} // namespace ix

View File

@ -121,7 +121,9 @@ namespace ix
});
SSL_CTX_set_verify_depth(ctx, 4);
} else {
}
else
{
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, nullptr);
}

View File

@ -13,12 +13,12 @@
#include "IXSocketSChannel.h"
#ifdef _WIN32
# include <basetsd.h>
# include <WinSock2.h>
# include <ws2def.h>
# include <WS2tcpip.h>
# include <schannel.h>
# include <io.h>
#include <WS2tcpip.h>
#include <WinSock2.h>
#include <basetsd.h>
#include <io.h>
#include <schannel.h>
#include <ws2def.h>
#define WIN32_LEAN_AND_MEAN
@ -26,14 +26,15 @@
#define UNICODE
#endif
#include <windows.h>
#include <winsock2.h>
#include <mstcpip.h>
#include <ws2tcpip.h>
#include <rpc.h>
#include <ntdsapi.h>
#include <rpc.h>
#include <stdio.h>
#include <tchar.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#define RECV_DATA_BUF_SIZE 256
@ -50,12 +51,8 @@
// has already been initialized
#else
# error("This file should only be built on Windows")
#error("This file should only be built on Windows")
#endif
namespace ix
@ -67,12 +64,9 @@ namespace ix
SocketSChannel::~SocketSChannel()
{
}
bool SocketSChannel::connect(const std::string& host,
int port,
std::string& errMsg)
bool SocketSChannel::connect(const std::string& host, int port, std::string& errMsg)
{
return Socket::connect(host, port, errMsg, nullptr);
}
@ -103,4 +97,4 @@ namespace ix
return Socket::recv(buf, nbyte);
}
}
} // namespace ix

View File

@ -5,14 +5,14 @@
*/
#include "IXSocketServer.h"
#include "IXNetSystem.h"
#include "IXSocket.h"
#include "IXSocketConnect.h"
#include "IXNetSystem.h"
#include <assert.h>
#include <iostream>
#include <sstream>
#include <string.h>
#include <assert.h>
namespace ix
{
@ -24,17 +24,16 @@ namespace ix
SocketServer::SocketServer(int port,
const std::string& host,
int backlog,
size_t maxConnections) :
_port(port),
_host(host),
_backlog(backlog),
_maxConnections(maxConnections),
_serverFd(-1),
_stop(false),
_stopGc(false),
_connectionStateFactory(&ConnectionState::createConnectionState)
size_t maxConnections)
: _port(port)
, _host(host)
, _backlog(backlog)
, _maxConnections(maxConnections)
, _serverFd(-1)
, _stop(false)
, _stopGc(false)
, _connectionStateFactory(&ConnectionState::createConnectionState)
{
}
SocketServer::~SocketServer()
@ -62,21 +61,18 @@ namespace ix
if ((_serverFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
std::stringstream ss;
ss << "SocketServer::listen() error creating socket): "
<< strerror(Socket::getErrno());
ss << "SocketServer::listen() error creating socket): " << strerror(Socket::getErrno());
return std::make_pair(false, ss.str());
}
// Make that socket reusable. (allow restarting this server at will)
int enable = 1;
if (setsockopt(_serverFd, SOL_SOCKET, SO_REUSEADDR,
(char*) &enable, sizeof(enable)) < 0)
if (setsockopt(_serverFd, SOL_SOCKET, SO_REUSEADDR, (char*) &enable, sizeof(enable)) < 0)
{
std::stringstream ss;
ss << "SocketServer::listen() error calling setsockopt(SO_REUSEADDR) "
<< "at address " << _host << ":" << _port
<< " : " << strerror(Socket::getErrno());
<< "at address " << _host << ":" << _port << " : " << strerror(Socket::getErrno());
Socket::closeSocket(_serverFd);
return std::make_pair(false, ss.str());
@ -84,7 +80,7 @@ namespace ix
// Bind the socket to the server address.
server.sin_family = AF_INET;
server.sin_port = htons(_port);
server.sin_port = htons(_port);
// Using INADDR_ANY trigger a pop-up box as binding to any address is detected
// by the osx firewall. We need to codesign the binary with a self-signed cert
@ -95,12 +91,11 @@ namespace ix
//
server.sin_addr.s_addr = inet_addr(_host.c_str());
if (bind(_serverFd, (struct sockaddr *)&server, sizeof(server)) < 0)
if (bind(_serverFd, (struct sockaddr*) &server, sizeof(server)) < 0)
{
std::stringstream ss;
ss << "SocketServer::listen() error calling bind "
<< "at address " << _host << ":" << _port
<< " : " << strerror(Socket::getErrno());
<< "at address " << _host << ":" << _port << " : " << strerror(Socket::getErrno());
Socket::closeSocket(_serverFd);
return std::make_pair(false, ss.str());
@ -113,8 +108,7 @@ namespace ix
{
std::stringstream ss;
ss << "SocketServer::listen() error calling listen "
<< "at address " << _host << ":" << _port
<< " : " << strerror(Socket::getErrno());
<< "at address " << _host << ":" << _port << " : " << strerror(Socket::getErrno());
Socket::closeSocket(_serverFd);
return std::make_pair(false, ss.str());
@ -186,7 +180,7 @@ namespace ix
{
std::lock_guard<std::mutex> lock(_connectionsThreadsMutex);
auto it = _connectionsThreads.begin();
auto itEnd = _connectionsThreads.end();
auto itEnd = _connectionsThreads.end();
while (it != itEnd)
{
@ -221,8 +215,7 @@ namespace ix
if (pollResult == PollResultType::Error)
{
std::stringstream ss;
ss << "SocketServer::run() error in select: "
<< strerror(Socket::getErrno());
ss << "SocketServer::run() error in select: " << strerror(Socket::getErrno());
logError(ss.str());
continue;
}
@ -238,15 +231,15 @@ namespace ix
socklen_t addressLen = sizeof(client);
memset(&client, 0, sizeof(client));
if ((clientFd = accept(_serverFd, (struct sockaddr *)&client, &addressLen)) < 0)
if ((clientFd = accept(_serverFd, (struct sockaddr*) &client, &addressLen)) < 0)
{
if (!Socket::isWaitNeeded())
{
// FIXME: that error should be propagated
int err = Socket::getErrno();
std::stringstream ss;
ss << "SocketServer::run() error accepting connection: "
<< err << ", " << strerror(err);
ss << "SocketServer::run() error accepting connection: " << err << ", "
<< strerror(err);
logError(ss.str());
}
continue;
@ -255,8 +248,7 @@ namespace ix
if (getConnectedClientsCount() >= _maxConnections)
{
std::stringstream ss;
ss << "SocketServer::run() reached max connections = "
<< _maxConnections << ". "
ss << "SocketServer::run() reached max connections = " << _maxConnections << ". "
<< "Not accepting connection";
logError(ss.str());
@ -276,11 +268,8 @@ namespace ix
// Launch the handleConnection work asynchronously in its own thread.
std::lock_guard<std::mutex> lock(_connectionsThreadsMutex);
_connectionsThreads.push_back(std::make_pair(
connectionState,
std::thread(&SocketServer::handleConnection,
this,
clientFd,
connectionState)));
connectionState,
std::thread(&SocketServer::handleConnection, this, clientFd, connectionState)));
}
}
@ -308,5 +297,4 @@ namespace ix
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
}
} // namespace ix

View File

@ -4,16 +4,17 @@
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
*/
#include <assert.h>
#include "IXSocketTLSOptions.h"
#include <assert.h>
namespace ix
{
SocketTLSOptions::SocketTLSOptions() {
SocketTLSOptions::SocketTLSOptions()
{
#ifndef IXWEBSOCKET_USE_TLS
assert(false && "To use TLS features the library must be compiled with USE_TLS");
#endif
#endif
}
bool SocketTLSOptions::isUsingClientCert() const

View File

@ -18,7 +18,7 @@ namespace ix
std::string certFile;
// the key used for signing/encryption
std::string keyFile;
// the ca certificate (or certificate bundle) file containing
// the ca certificate (or certificate bundle) file containing
// certificates to be trusted by peers; use 'SYSTEM' to
// leverage the system defaults, use 'NONE' to disable peer verification
std::string caFile = "SYSTEM";

View File

@ -5,6 +5,7 @@
*/
#include "IXUrlParser.h"
#include "LUrlParser.h"
namespace ix
@ -24,9 +25,9 @@ namespace ix
}
protocol = res.m_Scheme;
host = res.m_Host;
path = res.m_Path;
query = res.m_Query;
host = res.m_Host;
path = res.m_Path;
query = res.m_Query;
if (!res.GetPort(&port))
{
@ -64,4 +65,4 @@ namespace ix
return true;
}
}
} // namespace ix

View File

@ -5,44 +5,44 @@
*/
#include "IXUserAgent.h"
#include "IXWebSocketVersion.h"
#include "IXWebSocketVersion.h"
#include <sstream>
#include <zlib.h>
// Platform name
#if defined(_WIN32)
#define PLATFORM_NAME "windows" // Windows
#define PLATFORM_NAME "windows" // Windows
#elif defined(_WIN64)
#define PLATFORM_NAME "windows" // Windows
#define PLATFORM_NAME "windows" // Windows
#elif defined(__CYGWIN__) && !defined(_WIN32)
#define PLATFORM_NAME "windows" // Windows (Cygwin POSIX under Microsoft Window)
#define PLATFORM_NAME "windows" // Windows (Cygwin POSIX under Microsoft Window)
#elif defined(__ANDROID__)
#define PLATFORM_NAME "android" // Android (implies Linux, so it must come first)
#define PLATFORM_NAME "android" // Android (implies Linux, so it must come first)
#elif defined(__linux__)
#define PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other
#define PLATFORM_NAME "linux" // Debian, Ubuntu, Gentoo, Fedora, openSUSE, RedHat, Centos and other
#elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__)
#include <sys/param.h>
#if defined(BSD)
#define PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD
#endif
#include <sys/param.h>
#if defined(BSD)
#define PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD
#endif
#elif defined(__hpux)
#define PLATFORM_NAME "hp-ux" // HP-UX
#define PLATFORM_NAME "hp-ux" // HP-UX
#elif defined(_AIX)
#define PLATFORM_NAME "aix" // IBM AIX
#define PLATFORM_NAME "aix" // IBM AIX
#elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin)
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
#define PLATFORM_NAME "ios" // Apple iOS
#elif TARGET_OS_IPHONE == 1
#define PLATFORM_NAME "ios" // Apple iOS
#elif TARGET_OS_MAC == 1
#define PLATFORM_NAME "macos" // Apple OSX
#endif
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
#define PLATFORM_NAME "ios" // Apple iOS
#elif TARGET_OS_IPHONE == 1
#define PLATFORM_NAME "ios" // Apple iOS
#elif TARGET_OS_MAC == 1
#define PLATFORM_NAME "macos" // Apple OSX
#endif
#elif defined(__sun) && defined(__SVR4)
#define PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana
#define PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana
#else
#define PLATFORM_NAME "unknown platform"
#define PLATFORM_NAME "unknown platform"
#endif
// SSL
@ -80,4 +80,4 @@ namespace ix
return ss.str();
}
}
} // namespace ix

View File

@ -24,7 +24,7 @@
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
*/
/*
* IXUtf8Validator.h
@ -48,20 +48,31 @@ namespace ix
/// Lookup table for the UTF8 decode state machine
static uint8_t const utf8d[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df
0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef
0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff
0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2
1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4
1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6
1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf
8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df
0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // e0..ef
0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // f0..ff
0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2
1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4
1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6
1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1,
1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // s7..s8
};
/// Decode the next byte of a UTF8 sequence
@ -71,16 +82,14 @@ namespace ix
* @param [in] byte The byte to input
* @return The ending state of the decode operation
*/
inline uint32_t decodeNextByte(uint32_t * state, uint32_t * codep, uint8_t byte)
inline uint32_t decodeNextByte(uint32_t* state, uint32_t* codep, uint8_t byte)
{
uint32_t type = utf8d[byte];
uint32_t type = utf8d[byte];
*codep = (*state != utf8_accept) ?
(byte & 0x3fu) | (*codep << 6) :
(0xff >> type) & (byte);
*codep = (*state != utf8_accept) ? (byte & 0x3fu) | (*codep << 6) : (0xff >> type) & (byte);
*state = utf8d[256 + *state*16 + type];
return *state;
*state = utf8d[256 + *state * 16 + type];
return *state;
}
/// Provides streaming UTF8 validation functionality
@ -88,7 +97,11 @@ namespace ix
{
public:
/// Construct and initialize the validator
Utf8Validator() : m_state(utf8_accept),m_codepoint(0) {}
Utf8Validator()
: m_state(utf8_accept)
, m_codepoint(0)
{
}
/// Advance the state of the validator with the next input byte
/**
@ -97,7 +110,7 @@ namespace ix
*/
bool consume(uint8_t byte)
{
if (decodeNextByte(&m_state,&m_codepoint,byte) == utf8_reject)
if (decodeNextByte(&m_state, &m_codepoint, byte) == utf8_reject)
{
return false;
}
@ -110,16 +123,13 @@ namespace ix
* @param end Input iterator to the end of the input range
* @return Whether or not decoding the bytes resulted in a validation error.
*/
template <typename iterator_type>
template<typename iterator_type>
bool decode(iterator_type begin, iterator_type end)
{
for (iterator_type it = begin; it != end; ++it)
{
unsigned int result = decodeNextByte(
&m_state,
&m_codepoint,
static_cast<uint8_t>(*it)
);
unsigned int result =
decodeNextByte(&m_state, &m_codepoint, static_cast<uint8_t>(*it));
if (result == utf8_reject)
{
@ -144,9 +154,10 @@ namespace ix
m_state = utf8_accept;
m_codepoint = 0;
}
private:
uint32_t m_state;
uint32_t m_codepoint;
uint32_t m_state;
uint32_t m_codepoint;
};
/// Validate a UTF8 string
@ -154,10 +165,10 @@ namespace ix
* convenience function that creates a Validator, validates a complete string
* and returns the result.
*/
inline bool validateUtf8(std::string const & s)
inline bool validateUtf8(std::string const& s)
{
Utf8Validator v;
if (!v.decode(s.begin(),s.end()))
if (!v.decode(s.begin(), s.end()))
{
return false;
}

View File

@ -5,13 +5,13 @@
*/
#include "IXWebSocket.h"
#include "IXSetThreadName.h"
#include "IXWebSocketHandshake.h"
#include "IXExponentialBackoff.h"
#include "IXUtf8Validator.h"
#include <cmath>
#include "IXExponentialBackoff.h"
#include "IXSetThreadName.h"
#include "IXUtf8Validator.h"
#include "IXWebSocketHandshake.h"
#include <cassert>
#include <cmath>
namespace ix
@ -23,26 +23,26 @@ namespace ix
const bool WebSocket::kDefaultEnablePong(true);
const uint32_t WebSocket::kDefaultMaxWaitBetweenReconnectionRetries(10 * 1000); // 10s
WebSocket::WebSocket() :
_onMessageCallback(OnMessageCallback()),
_stop(false),
_automaticReconnection(true),
_maxWaitBetweenReconnectionRetries(kDefaultMaxWaitBetweenReconnectionRetries),
_handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs),
_enablePong(kDefaultEnablePong),
_pingIntervalSecs(kDefaultPingIntervalSecs),
_pingTimeoutSecs(kDefaultPingTimeoutSecs)
WebSocket::WebSocket()
: _onMessageCallback(OnMessageCallback())
, _stop(false)
, _automaticReconnection(true)
, _maxWaitBetweenReconnectionRetries(kDefaultMaxWaitBetweenReconnectionRetries)
, _handshakeTimeoutSecs(kDefaultHandShakeTimeoutSecs)
, _enablePong(kDefaultEnablePong)
, _pingIntervalSecs(kDefaultPingIntervalSecs)
, _pingTimeoutSecs(kDefaultPingTimeoutSecs)
{
_ws.setOnCloseCallback(
[this](uint16_t code, const std::string& reason, size_t wireSize, bool remote)
{
[this](uint16_t code, const std::string& reason, size_t wireSize, bool remote) {
_onMessageCallback(
std::make_shared<WebSocketMessage>(
WebSocketMessageType::Close, "", wireSize,
WebSocketErrorInfo(), WebSocketOpenInfo(),
WebSocketCloseInfo(code, reason, remote)));
}
);
std::make_shared<WebSocketMessage>(WebSocketMessageType::Close,
"",
wireSize,
WebSocketErrorInfo(),
WebSocketOpenInfo(),
WebSocketCloseInfo(code, reason, remote)));
});
}
WebSocket::~WebSocket()
@ -67,7 +67,8 @@ namespace ix
return _url;
}
void WebSocket::setPerMessageDeflateOptions(const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions)
void WebSocket::setPerMessageDeflateOptions(
const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions)
{
std::lock_guard<std::mutex> lock(_configMutex);
_perMessageDeflateOptions = perMessageDeflateOptions;
@ -159,8 +160,7 @@ namespace ix
_thread = std::thread(&WebSocket::run, this);
}
void WebSocket::stop(uint16_t code,
const std::string& reason)
void WebSocket::stop(uint16_t code, const std::string& reason)
{
close(code, reason);
@ -192,11 +192,12 @@ namespace ix
}
_onMessageCallback(
std::make_shared<WebSocketMessage>(
WebSocketMessageType::Open, "", 0,
WebSocketErrorInfo(),
WebSocketOpenInfo(status.uri, status.headers),
WebSocketCloseInfo()));
std::make_shared<WebSocketMessage>(WebSocketMessageType::Open,
"",
0,
WebSocketErrorInfo(),
WebSocketOpenInfo(status.uri, status.headers),
WebSocketCloseInfo()));
return status;
}
@ -218,11 +219,12 @@ namespace ix
}
_onMessageCallback(
std::make_shared<WebSocketMessage>(
WebSocketMessageType::Open, "", 0,
WebSocketErrorInfo(),
WebSocketOpenInfo(status.uri, status.headers),
WebSocketCloseInfo()));
std::make_shared<WebSocketMessage>(WebSocketMessageType::Open,
"",
0,
WebSocketErrorInfo(),
WebSocketOpenInfo(status.uri, status.headers),
WebSocketCloseInfo()));
return status;
}
@ -236,8 +238,7 @@ namespace ix
return getReadyState() == ReadyState::Closing;
}
void WebSocket::close(uint16_t code,
const std::string& reason)
void WebSocket::close(uint16_t code, const std::string& reason)
{
_ws.close(code, reason);
}
@ -281,20 +282,22 @@ namespace ix
if (_automaticReconnection)
{
duration = millis(calculateRetryWaitMilliseconds(retries++, _maxWaitBetweenReconnectionRetries));
duration = millis(calculateRetryWaitMilliseconds(
retries++, _maxWaitBetweenReconnectionRetries));
connectErr.wait_time = duration.count();
connectErr.retries = retries;
}
connectErr.reason = status.errorStr;
connectErr.reason = status.errorStr;
connectErr.http_status = status.http_status;
_onMessageCallback(
std::make_shared<WebSocketMessage>(
WebSocketMessageType::Error, "", 0,
connectErr, WebSocketOpenInfo(),
WebSocketCloseInfo()));
_onMessageCallback(std::make_shared<WebSocketMessage>(WebSocketMessageType::Error,
"",
0,
connectErr,
WebSocketOpenInfo(),
WebSocketCloseInfo()));
}
}
}
@ -330,8 +333,7 @@ namespace ix
[this](const std::string& msg,
size_t wireSize,
bool decompressionError,
WebSocketTransport::MessageKind messageKind)
{
WebSocketTransport::MessageKind messageKind) {
WebSocketMessageType webSocketMessageType;
switch (messageKind)
{
@ -339,22 +341,26 @@ namespace ix
case WebSocketTransport::MessageKind::MSG_BINARY:
{
webSocketMessageType = WebSocketMessageType::Message;
} break;
}
break;
case WebSocketTransport::MessageKind::PING:
{
webSocketMessageType = WebSocketMessageType::Ping;
} break;
}
break;
case WebSocketTransport::MessageKind::PONG:
{
webSocketMessageType = WebSocketMessageType::Pong;
} break;
}
break;
case WebSocketTransport::MessageKind::FRAGMENT:
{
webSocketMessageType = WebSocketMessageType::Fragment;
} break;
}
break;
}
WebSocketErrorInfo webSocketErrorInfo;
@ -362,11 +368,13 @@ namespace ix
bool binary = messageKind == WebSocketTransport::MessageKind::MSG_BINARY;
_onMessageCallback(
std::make_shared<WebSocketMessage>(
webSocketMessageType, msg, wireSize,
webSocketErrorInfo, WebSocketOpenInfo(),
WebSocketCloseInfo(), binary));
_onMessageCallback(std::make_shared<WebSocketMessage>(webSocketMessageType,
msg,
wireSize,
webSocketErrorInfo,
WebSocketOpenInfo(),
WebSocketCloseInfo(),
binary));
WebSocket::invokeTrafficTrackerCallback(msg.size(), true);
});
@ -453,17 +461,20 @@ namespace ix
case SendMessageKind::Text:
{
webSocketSendInfo = _ws.sendText(text, onProgressCallback);
} break;
}
break;
case SendMessageKind::Binary:
{
webSocketSendInfo = _ws.sendBinary(text, onProgressCallback);
} break;
}
break;
case SendMessageKind::Ping:
{
webSocketSendInfo = _ws.sendPing(text);
} break;
}
break;
}
WebSocket::invokeTrafficTrackerCallback(webSocketSendInfo.wireSize, false);
@ -475,10 +486,10 @@ namespace ix
{
switch (_ws.getReadyState())
{
case ix::WebSocketTransport::ReadyState::OPEN : return ReadyState::Open;
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;
case ix::WebSocketTransport::ReadyState::CLOSING: return ReadyState::Closing;
case ix::WebSocketTransport::ReadyState::CLOSED: return ReadyState::Closed;
default: return ReadyState::Closed;
}
}
@ -487,10 +498,10 @@ namespace ix
{
switch (readyState)
{
case ReadyState::Open : return "OPEN";
case ReadyState::Open: return "OPEN";
case ReadyState::Connecting: return "CONNECTING";
case ReadyState::Closing : return "CLOSING";
case ReadyState::Closed : return "CLOSED";
case ReadyState::Closing: return "CLOSING";
case ReadyState::Closed: return "CLOSED";
default: return "UNKNOWN";
}
}
@ -514,4 +525,4 @@ namespace ix
{
return _ws.bufferedAmount();
}
}
} // namespace ix

View File

@ -22,10 +22,15 @@ namespace ix
const std::string WebSocketCloseConstants::kProtocolErrorMessage("Protocol error");
const std::string WebSocketCloseConstants::kNoStatusCodeErrorMessage("No status code");
const std::string WebSocketCloseConstants::kProtocolErrorReservedBitUsed("Reserved bit used");
const std::string WebSocketCloseConstants::kProtocolErrorPingPayloadOversized("Ping reason control frame with payload length > 125 octets");
const std::string WebSocketCloseConstants::kProtocolErrorCodeControlMessageFragmented("Control message fragmented");
const std::string WebSocketCloseConstants::kProtocolErrorCodeDataOpcodeOutOfSequence("Fragmentation: data message out of sequence");
const std::string WebSocketCloseConstants::kProtocolErrorCodeContinuationOpCodeOutOfSequence("Fragmentation: continuation opcode out of sequence");
const std::string WebSocketCloseConstants::kInvalidFramePayloadDataMessage("Invalid frame payload data");
const std::string WebSocketCloseConstants::kProtocolErrorPingPayloadOversized(
"Ping reason control frame with payload length > 125 octets");
const std::string WebSocketCloseConstants::kProtocolErrorCodeControlMessageFragmented(
"Control message fragmented");
const std::string WebSocketCloseConstants::kProtocolErrorCodeDataOpcodeOutOfSequence(
"Fragmentation: data message out of sequence");
const std::string WebSocketCloseConstants::kProtocolErrorCodeContinuationOpCodeOutOfSequence(
"Fragmentation: continuation opcode out of sequence");
const std::string WebSocketCloseConstants::kInvalidFramePayloadDataMessage(
"Invalid frame payload data");
const std::string WebSocketCloseConstants::kInvalidCloseCodeMessage("Invalid close code");
}
} // namespace ix

View File

@ -5,50 +5,45 @@
*/
#include "IXWebSocketHandshake.h"
#include "IXHttp.h"
#include "IXSocketConnect.h"
#include "IXUrlParser.h"
#include "IXHttp.h"
#include "IXUserAgent.h"
#include "libwshandshake.hpp"
#include <sstream>
#include <random>
#include <algorithm>
#include <random>
#include <sstream>
namespace ix
{
WebSocketHandshake::WebSocketHandshake(std::atomic<bool>& requestInitCancellation,
std::shared_ptr<Socket> socket,
WebSocketPerMessageDeflate& perMessageDeflate,
WebSocketPerMessageDeflateOptions& perMessageDeflateOptions,
std::atomic<bool>& enablePerMessageDeflate) :
_requestInitCancellation(requestInitCancellation),
_socket(socket),
_perMessageDeflate(perMessageDeflate),
_perMessageDeflateOptions(perMessageDeflateOptions),
_enablePerMessageDeflate(enablePerMessageDeflate)
WebSocketHandshake::WebSocketHandshake(
std::atomic<bool>& requestInitCancellation,
std::shared_ptr<Socket> socket,
WebSocketPerMessageDeflate& perMessageDeflate,
WebSocketPerMessageDeflateOptions& perMessageDeflateOptions,
std::atomic<bool>& enablePerMessageDeflate)
: _requestInitCancellation(requestInitCancellation)
, _socket(socket)
, _perMessageDeflate(perMessageDeflate)
, _perMessageDeflateOptions(perMessageDeflateOptions)
, _enablePerMessageDeflate(enablePerMessageDeflate)
{
}
bool WebSocketHandshake::insensitiveStringCompare(const std::string& a, const std::string& b)
{
return std::equal(a.begin(), a.end(),
b.begin(), b.end(),
[](char a, char b)
{
return tolower(a) == tolower(b);
});
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) {
return tolower(a) == tolower(b);
});
}
std::string WebSocketHandshake::genRandomString(const int len)
{
std::string alphanum =
"0123456789"
"ABCDEFGH"
"abcdefgh";
std::string alphanum = "0123456789"
"ABCDEFGH"
"abcdefgh";
std::random_device r;
std::default_random_engine e1(r());
@ -88,12 +83,13 @@ namespace ix
return WebSocketInitResult(false, code, reason);
}
WebSocketInitResult WebSocketHandshake::clientHandshake(const std::string& url,
const WebSocketHttpHeaders& extraHeaders,
const std::string& host,
const std::string& path,
int port,
int timeoutSecs)
WebSocketInitResult WebSocketHandshake::clientHandshake(
const std::string& url,
const WebSocketHttpHeaders& extraHeaders,
const std::string& host,
const std::string& path,
int port,
int timeoutSecs)
{
_requestInitCancellation = false;
@ -105,9 +101,7 @@ namespace ix
if (!success)
{
std::stringstream ss;
ss << "Unable to connect to " << host
<< " on port " << port
<< ", error: " << errMsg;
ss << "Unable to connect to " << host << " on port " << port << ", error: " << errMsg;
return WebSocketInitResult(false, 0, ss.str());
}
@ -123,7 +117,7 @@ namespace ix
std::stringstream ss;
ss << "GET " << path << " HTTP/1.1\r\n";
ss << "Host: "<< host << ":" << port << "\r\n";
ss << "Host: " << host << ":" << port << "\r\n";
ss << "Upgrade: websocket\r\n";
ss << "Connection: Upgrade\r\n";
ss << "Sec-WebSocket-Version: 13\r\n";
@ -149,7 +143,8 @@ namespace ix
if (!_socket->writeBytes(ss.str(), isCancellationRequested))
{
return WebSocketInitResult(false, 0, std::string("Failed sending GET request to ") + url);
return WebSocketInitResult(
false, 0, std::string("Failed sending GET request to ") + url);
}
// Read HTTP status line
@ -159,8 +154,8 @@ namespace ix
if (!lineValid)
{
return WebSocketInitResult(false, 0,
std::string("Failed reading HTTP status line from ") + url);
return WebSocketInitResult(
false, 0, std::string("Failed reading HTTP status line from ") + url);
}
// Validate status
@ -173,8 +168,7 @@ namespace ix
{
std::stringstream ss;
ss << "Expecting HTTP/1.1, got " << httpVersion << ". "
<< "Rejecting connection to " << host << ":" << port
<< ", status: " << status
<< "Rejecting connection to " << host << ":" << port << ", status: " << status
<< ", HTTP Status line: " << line;
return WebSocketInitResult(false, status, ss.str());
}
@ -183,8 +177,7 @@ namespace ix
if (status != 101)
{
std::stringstream ss;
ss << "Got bad status connecting to " << host << ":" << port
<< ", status: " << status
ss << "Got bad status connecting to " << host << ":" << port << ", status: " << status
<< ", HTTP Status line: " << line;
return WebSocketInitResult(false, status, ss.str());
}
@ -269,8 +262,8 @@ namespace ix
// Validate request line (GET /foo HTTP/1.1\r\n)
auto requestLine = Http::parseRequestLine(line);
auto method = std::get<0>(requestLine);
auto uri = std::get<1>(requestLine);
auto method = std::get<0>(requestLine);
auto uri = std::get<1>(requestLine);
auto httpVersion = std::get<2>(requestLine);
if (method != "GET")
@ -280,7 +273,8 @@ namespace ix
if (httpVersion != "HTTP/1.1")
{
return sendErrorResponse(400, "Invalid HTTP version, need HTTP/1.1, got: " + httpVersion);
return sendErrorResponse(400,
"Invalid HTTP version, need HTTP/1.1, got: " + httpVersion);
}
// Retrieve and validate HTTP headers
@ -305,8 +299,10 @@ namespace ix
if (!insensitiveStringCompare(headers["upgrade"], "WebSocket"))
{
return sendErrorResponse(400, "Invalid Upgrade header, "
"need WebSocket, got " + headers["upgrade"]);
return sendErrorResponse(400,
"Invalid Upgrade header, "
"need WebSocket, got " +
headers["upgrade"]);
}
if (headers.find("sec-websocket-version") == headers.end())
@ -322,8 +318,10 @@ namespace ix
if (version != 13)
{
return sendErrorResponse(400, "Invalid Sec-WebSocket-Version, "
"need 13, got " + ss.str());
return sendErrorResponse(400,
"Invalid Sec-WebSocket-Version, "
"need 13, got " +
ss.str());
}
}
@ -349,7 +347,7 @@ namespace ix
if (!_perMessageDeflate.init(webSocketPerMessageDeflateOptions))
{
return WebSocketInitResult(
false, 0,"Failed to initialize per message deflate engine");
false, 0, "Failed to initialize per message deflate engine");
}
ss << webSocketPerMessageDeflateOptions.generateHeader();
}
@ -358,9 +356,10 @@ namespace ix
if (!_socket->writeBytes(ss.str(), isCancellationRequested))
{
return WebSocketInitResult(false, 0, std::string("Failed sending response to ") + remote);
return WebSocketInitResult(
false, 0, std::string("Failed sending response to ") + remote);
}
return WebSocketInitResult(true, 200, "", headers, uri);
}
}
} // namespace ix

View File

@ -49,13 +49,12 @@ namespace ix
WebSocketPerMessageDeflateOptions& perMessageDeflateOptions,
std::atomic<bool>& enablePerMessageDeflate);
WebSocketInitResult clientHandshake(
const std::string& url,
const WebSocketHttpHeaders& extraHeaders,
const std::string& host,
const std::string& path,
int port,
int timeoutSecs);
WebSocketInitResult clientHandshake(const std::string& url,
const WebSocketHttpHeaders& extraHeaders,
const std::string& host,
const std::string& path,
int port,
int timeoutSecs);
WebSocketInitResult serverHandshake(int fd, int timeoutSecs);

View File

@ -5,13 +5,15 @@
*/
#include "IXWebSocketHttpHeaders.h"
#include "IXSocket.h"
#include <algorithm>
#include <locale>
namespace ix
{
bool CaseInsensitiveLess::NocaseCompare::operator()(const unsigned char & c1, const unsigned char & c2) const
bool CaseInsensitiveLess::NocaseCompare::operator()(const unsigned char& c1,
const unsigned char& c2) const
{
#ifdef _WIN32
return std::tolower(c1, std::locale()) < std::tolower(c2, std::locale());
@ -20,17 +22,17 @@ namespace ix
#endif
}
bool CaseInsensitiveLess::operator()(const std::string & s1, const std::string & s2) const
bool CaseInsensitiveLess::operator()(const std::string& s1, const std::string& s2) const
{
return std::lexicographical_compare
(s1.begin(), s1.end(), // source range
s2.begin(), s2.end(), // dest range
NocaseCompare()); // comparison
return std::lexicographical_compare(s1.begin(),
s1.end(), // source range
s2.begin(),
s2.end(), // dest range
NocaseCompare()); // comparison
}
std::pair<bool, WebSocketHttpHeaders> parseHttpHeaders(
std::shared_ptr<Socket> socket,
const CancellationRequest& isCancellationRequested)
std::shared_ptr<Socket> socket, const CancellationRequest& isCancellationRequested)
{
WebSocketHttpHeaders headers;
@ -41,11 +43,9 @@ namespace ix
{
int colon = 0;
for (i = 0;
i < 2 || (i < 1023 && line[i-2] != '\r' && line[i-1] != '\n');
++i)
for (i = 0; i < 2 || (i < 1023 && line[i - 2] != '\r' && line[i - 1] != '\n'); ++i)
{
if (!socket->readByte(line+i, isCancellationRequested))
if (!socket->readByte(line + i, isCancellationRequested))
{
return std::make_pair(false, headers);
}
@ -79,4 +79,4 @@ namespace ix
return std::make_pair(true, headers);
}
}
} // namespace ix

View File

@ -8,7 +8,6 @@
namespace ix
{
WebSocketMessageQueue::WebSocketMessageQueue(WebSocket* websocket)
{
bindWebsocket(websocket);
@ -24,7 +23,7 @@ namespace ix
bindWebsocket(nullptr);
}
void WebSocketMessageQueue::bindWebsocket(WebSocket * websocket)
void WebSocketMessageQueue::bindWebsocket(WebSocket* websocket)
{
if (_websocket == websocket) return;
@ -40,8 +39,7 @@ namespace ix
// bind new
if (_websocket)
{
_websocket->setOnMessageCallback([this](const WebSocketMessagePtr& msg)
{
_websocket->setOnMessageCallback([this](const WebSocketMessagePtr& msg) {
std::lock_guard<std::mutex> lock(_messagesMutex);
_messages.emplace_back(std::move(msg));
});
@ -74,8 +72,7 @@ namespace ix
void WebSocketMessageQueue::poll(int count)
{
if (!_onMessageUserCallback)
return;
if (!_onMessageUserCallback) return;
WebSocketMessagePtr message;
@ -86,4 +83,4 @@ namespace ix
}
}
}
} // namespace ix

View File

@ -41,19 +41,21 @@
* - Added more documentation.
*
* Per message Deflate RFC: https://tools.ietf.org/html/rfc7692
* Chrome websocket -> https://github.com/chromium/chromium/tree/2ca8c5037021c9d2ecc00b787d58a31ed8fc8bcb/net/websockets
* Chrome websocket ->
* https://github.com/chromium/chromium/tree/2ca8c5037021c9d2ecc00b787d58a31ed8fc8bcb/net/websockets
*
*/
#include "IXWebSocketPerMessageDeflate.h"
#include "IXWebSocketPerMessageDeflateOptions.h"
#include "IXWebSocketPerMessageDeflateCodec.h"
#include "IXWebSocketPerMessageDeflateOptions.h"
namespace ix
{
WebSocketPerMessageDeflate::WebSocketPerMessageDeflate() :
_compressor(std::make_unique<WebSocketPerMessageDeflateCompressor>()),
_decompressor(std::make_unique<WebSocketPerMessageDeflateDecompressor>())
WebSocketPerMessageDeflate::WebSocketPerMessageDeflate()
: _compressor(std::make_unique<WebSocketPerMessageDeflateCompressor>())
, _decompressor(std::make_unique<WebSocketPerMessageDeflateDecompressor>())
{
;
}
@ -63,10 +65,10 @@ namespace ix
;
}
bool WebSocketPerMessageDeflate::init(const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions)
bool WebSocketPerMessageDeflate::init(
const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions)
{
bool clientNoContextTakeover =
perMessageDeflateOptions.getClientNoContextTakeover();
bool clientNoContextTakeover = perMessageDeflateOptions.getClientNoContextTakeover();
uint8_t deflateBits = perMessageDeflateOptions.getClientMaxWindowBits();
uint8_t inflateBits = perMessageDeflateOptions.getServerMaxWindowBits();
@ -75,16 +77,14 @@ namespace ix
_decompressor->init(inflateBits, clientNoContextTakeover);
}
bool WebSocketPerMessageDeflate::compress(const std::string& in,
std::string& out)
bool WebSocketPerMessageDeflate::compress(const std::string& in, std::string& out)
{
return _compressor->compress(in, out);
}
bool WebSocketPerMessageDeflate::decompress(const std::string& in,
std::string &out)
bool WebSocketPerMessageDeflate::decompress(const std::string& in, std::string& out)
{
return _decompressor->decompress(in, out);
}
}
} // namespace ix

View File

@ -5,8 +5,8 @@
*/
#include "IXWebSocketPerMessageDeflateCodec.h"
#include "IXWebSocketPerMessageDeflateOptions.h"
#include "IXWebSocketPerMessageDeflateOptions.h"
#include <cassert>
#include <string.h>
@ -18,7 +18,7 @@ namespace
const std::string kEmptyUncompressedBlock = std::string("\x00\x00\xff\xff", 4);
const int kBufferSize = 1 << 14;
}
} // namespace
namespace ix
{
@ -26,7 +26,7 @@ namespace ix
// Compressor
//
WebSocketPerMessageDeflateCompressor::WebSocketPerMessageDeflateCompressor()
: _compressBufferSize(kBufferSize)
: _compressBufferSize(kBufferSize)
{
memset(&_deflateState, 0, sizeof(_deflateState));
@ -43,22 +43,18 @@ namespace ix
bool WebSocketPerMessageDeflateCompressor::init(uint8_t deflateBits,
bool clientNoContextTakeOver)
{
int ret = deflateInit2(
&_deflateState,
Z_DEFAULT_COMPRESSION,
Z_DEFLATED,
-1*deflateBits,
4, // memory level 1-9
Z_DEFAULT_STRATEGY
);
int ret = deflateInit2(&_deflateState,
Z_DEFAULT_COMPRESSION,
Z_DEFLATED,
-1 * deflateBits,
4, // memory level 1-9
Z_DEFAULT_STRATEGY);
if (ret != Z_OK) return false;
_compressBuffer = std::make_unique<unsigned char[]>(_compressBufferSize);
_flush = (clientNoContextTakeOver)
? Z_FULL_FLUSH
: Z_SYNC_FLUSH;
_flush = (clientNoContextTakeOver) ? Z_FULL_FLUSH : Z_SYNC_FLUSH;
return true;
}
@ -70,8 +66,7 @@ namespace ix
return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
}
bool WebSocketPerMessageDeflateCompressor::compress(const std::string& in,
std::string& out)
bool WebSocketPerMessageDeflateCompressor::compress(const std::string& in, std::string& out)
{
//
// 7.2.1. Compression
@ -95,7 +90,7 @@ namespace ix
if (in.empty())
{
uint8_t buf[6] = {0x02, 0x00, 0x00, 0x00, 0xff, 0xff};
out.append((char *)(buf), 6);
out.append((char*) (buf), 6);
return true;
}
@ -112,7 +107,7 @@ namespace ix
output = _compressBufferSize - _deflateState.avail_out;
out.append((char *)(_compressBuffer.get()),output);
out.append((char*) (_compressBuffer.get()), output);
} while (_deflateState.avail_out == 0);
if (endsWith(out, kEmptyUncompressedBlock))
@ -127,7 +122,7 @@ namespace ix
// Decompressor
//
WebSocketPerMessageDeflateDecompressor::WebSocketPerMessageDeflateDecompressor()
: _compressBufferSize(kBufferSize)
: _compressBufferSize(kBufferSize)
{
memset(&_inflateState, 0, sizeof(_inflateState));
@ -146,24 +141,18 @@ namespace ix
bool WebSocketPerMessageDeflateDecompressor::init(uint8_t inflateBits,
bool clientNoContextTakeOver)
{
int ret = inflateInit2(
&_inflateState,
-1*inflateBits
);
int ret = inflateInit2(&_inflateState, -1 * inflateBits);
if (ret != Z_OK) return false;
_compressBuffer = std::make_unique<unsigned char[]>(_compressBufferSize);
_flush = (clientNoContextTakeOver)
? Z_FULL_FLUSH
: Z_SYNC_FLUSH;
_flush = (clientNoContextTakeOver) ? Z_FULL_FLUSH : Z_SYNC_FLUSH;
return true;
}
bool WebSocketPerMessageDeflateDecompressor::decompress(const std::string& in,
std::string& out)
bool WebSocketPerMessageDeflateDecompressor::decompress(const std::string& in, std::string& out)
{
//
// 7.2.2. Decompression
@ -179,7 +168,7 @@ namespace ix
inFixed += kEmptyUncompressedBlock;
_inflateState.avail_in = (uInt) inFixed.size();
_inflateState.next_in = (unsigned char *)(const_cast<char *>(inFixed.data()));
_inflateState.next_in = (unsigned char*) (const_cast<char*>(inFixed.data()));
do
{
@ -193,13 +182,10 @@ namespace ix
return false; // zlib error
}
out.append(
reinterpret_cast<char *>(_compressBuffer.get()),
_compressBufferSize - _inflateState.avail_out
);
out.append(reinterpret_cast<char*>(_compressBuffer.get()),
_compressBufferSize - _inflateState.avail_out);
} while (_inflateState.avail_out == 0);
return true;
}
}
} // namespace ix

View File

@ -6,9 +6,9 @@
#include "IXWebSocketPerMessageDeflateOptions.h"
#include <sstream>
#include <algorithm>
#include <cctype>
#include <sstream>
namespace ix
{
@ -48,7 +48,8 @@ namespace ix
//
// Server response could look like that:
//
// Sec-WebSocket-Extensions: permessage-deflate; client_no_context_takeover; server_no_context_takeover
// Sec-WebSocket-Extensions: permessage-deflate; client_no_context_takeover;
// server_no_context_takeover
//
WebSocketPerMessageDeflateOptions::WebSocketPerMessageDeflateOptions(std::string extension)
{
@ -92,8 +93,7 @@ namespace ix
// Sanitize values to be in the proper range [8, 15] in
// case a server would give us bogus values
_serverMaxWindowBits =
std::min(maxServerMaxWindowBits,
std::max(x, minServerMaxWindowBits));
std::min(maxServerMaxWindowBits, std::max(x, minServerMaxWindowBits));
}
if (startsWith(token, "client_max_window_bits="))
@ -107,8 +107,7 @@ namespace ix
// Sanitize values to be in the proper range [8, 15] in
// case a server would give us bogus values
_clientMaxWindowBits =
std::min(maxClientMaxWindowBits,
std::max(x, minClientMaxWindowBits));
std::min(maxClientMaxWindowBits, std::max(x, minClientMaxWindowBits));
sanitizeClientMaxWindowBits();
}
@ -175,11 +174,10 @@ namespace ix
std::string WebSocketPerMessageDeflateOptions::removeSpaces(const std::string& str)
{
std::string out(str);
out.erase(std::remove_if(out.begin(),
out.end(),
[](unsigned char x){ return std::isspace(x); }),
out.end());
out.erase(
std::remove_if(out.begin(), out.end(), [](unsigned char x) { return std::isspace(x); }),
out.end());
return out;
}
}
} // namespace ix

View File

@ -5,13 +5,13 @@
*/
#include "IXWebSocketServer.h"
#include "IXWebSocketTransport.h"
#include "IXWebSocket.h"
#include "IXSocketConnect.h"
#include "IXNetSystem.h"
#include <sstream>
#include "IXNetSystem.h"
#include "IXSocketConnect.h"
#include "IXWebSocket.h"
#include "IXWebSocketTransport.h"
#include <future>
#include <sstream>
#include <string.h>
namespace ix
@ -23,11 +23,11 @@ namespace ix
const std::string& host,
int backlog,
size_t maxConnections,
int handshakeTimeoutSecs) : SocketServer(port, host, backlog, maxConnections),
_handshakeTimeoutSecs(handshakeTimeoutSecs),
_enablePong(kDefaultEnablePong)
int handshakeTimeoutSecs)
: SocketServer(port, host, backlog, maxConnections)
, _handshakeTimeoutSecs(handshakeTimeoutSecs)
, _enablePong(kDefaultEnablePong)
{
}
WebSocketServer::~WebSocketServer()
@ -63,9 +63,7 @@ namespace ix
_onConnectionCallback = callback;
}
void WebSocketServer::handleConnection(
int fd,
std::shared_ptr<ConnectionState> connectionState)
void WebSocketServer::handleConnection(int fd, std::shared_ptr<ConnectionState> connectionState)
{
auto webSocket = std::make_shared<WebSocket>();
_onConnectionCallback(webSocket, connectionState);
@ -93,10 +91,8 @@ namespace ix
else
{
std::stringstream ss;
ss << "WebSocketServer::handleConnection() HTTP status: "
<< status.http_status
<< " error: "
<< status.errorStr;
ss << "WebSocketServer::handleConnection() HTTP status: " << status.http_status
<< " error: " << status.errorStr;
logError(ss.str());
}
@ -126,4 +122,4 @@ namespace ix
std::lock_guard<std::mutex> lock(_clientsMutex);
return _clients.size();
}
}
} // namespace ix

View File

@ -32,24 +32,23 @@
// Adapted from https://github.com/dhbaird/easywsclient
//
#include "IXSocketTLSOptions.h"
#include "IXWebSocketTransport.h"
#include "IXSocketFactory.h"
#include "IXSocketTLSOptions.h"
#include "IXUrlParser.h"
#include "IXUtf8Validator.h"
#include "IXWebSocketHandshake.h"
#include "IXWebSocketHttpHeaders.h"
#include "IXUrlParser.h"
#include "IXSocketFactory.h"
#include "IXUtf8Validator.h"
#include <string.h>
#include <stdlib.h>
#include <cstdlib>
#include <vector>
#include <string>
#include <cstdarg>
#include <sstream>
#include <chrono>
#include <cstdarg>
#include <cstdlib>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <thread>
#include <vector>
namespace
@ -65,7 +64,7 @@ namespace
return a;
}
}
} // namespace
namespace ix
{
@ -76,24 +75,24 @@ namespace ix
const int WebSocketTransport::kClosingMaximumWaitingDelayInMs(300);
constexpr size_t WebSocketTransport::kChunkSize;
WebSocketTransport::WebSocketTransport() :
_useMask(true),
_compressedMessage(false),
_readyState(ReadyState::CLOSED),
_closeCode(WebSocketCloseConstants::kInternalErrorCode),
_closeReason(WebSocketCloseConstants::kInternalErrorMessage),
_closeWireSize(0),
_closeRemote(false),
_enablePerMessageDeflate(false),
_requestInitCancellation(false),
_closingTimePoint(std::chrono::steady_clock::now()),
_enablePong(kDefaultEnablePong),
_pingIntervalSecs(kDefaultPingIntervalSecs),
_pingTimeoutSecs(kDefaultPingTimeoutSecs),
_pingIntervalOrTimeoutGCDSecs(-1),
_nextGCDTimePoint(std::chrono::steady_clock::now()),
_lastSendPingTimePoint(std::chrono::steady_clock::now()),
_lastReceivePongTimePoint(std::chrono::steady_clock::now())
WebSocketTransport::WebSocketTransport()
: _useMask(true)
, _compressedMessage(false)
, _readyState(ReadyState::CLOSED)
, _closeCode(WebSocketCloseConstants::kInternalErrorCode)
, _closeReason(WebSocketCloseConstants::kInternalErrorMessage)
, _closeWireSize(0)
, _closeRemote(false)
, _enablePerMessageDeflate(false)
, _requestInitCancellation(false)
, _closingTimePoint(std::chrono::steady_clock::now())
, _enablePong(kDefaultEnablePong)
, _pingIntervalSecs(kDefaultPingIntervalSecs)
, _pingTimeoutSecs(kDefaultPingTimeoutSecs)
, _pingIntervalOrTimeoutGCDSecs(-1)
, _nextGCDTimePoint(std::chrono::steady_clock::now())
, _lastSendPingTimePoint(std::chrono::steady_clock::now())
, _lastReceivePongTimePoint(std::chrono::steady_clock::now())
{
_readbuf.resize(kChunkSize);
}
@ -103,11 +102,12 @@ namespace ix
;
}
void WebSocketTransport::configure(const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions,
const SocketTLSOptions& socketTLSOptions,
bool enablePong,
int pingIntervalSecs,
int pingTimeoutSecs)
void WebSocketTransport::configure(
const WebSocketPerMessageDeflateOptions& perMessageDeflateOptions,
const SocketTLSOptions& socketTLSOptions,
bool enablePong,
int pingIntervalSecs,
int pingTimeoutSecs)
{
_perMessageDeflateOptions = perMessageDeflateOptions;
_enablePerMessageDeflate = _perMessageDeflateOptions.enabled();
@ -118,8 +118,8 @@ namespace ix
if (pingIntervalSecs > 0 && pingTimeoutSecs > 0)
{
_pingIntervalOrTimeoutGCDSecs = greatestCommonDivisor(pingIntervalSecs,
pingTimeoutSecs);
_pingIntervalOrTimeoutGCDSecs =
greatestCommonDivisor(pingIntervalSecs, pingTimeoutSecs);
}
else if (_pingTimeoutSecs > 0)
{
@ -132,10 +132,9 @@ namespace ix
}
// Client
WebSocketInitResult WebSocketTransport::connectToUrl(
const std::string& url,
const WebSocketHttpHeaders& headers,
int timeoutSecs)
WebSocketInitResult WebSocketTransport::connectToUrl(const std::string& url,
const WebSocketHttpHeaders& headers,
int timeoutSecs)
{
std::lock_guard<std::mutex> lock(_socketMutex);
@ -144,8 +143,7 @@ namespace ix
if (!UrlParser::parse(url, protocol, host, path, query, port))
{
return WebSocketInitResult(false, 0,
std::string("Could not parse URL ") + url);
return WebSocketInitResult(false, 0, std::string("Could not parse URL ") + url);
}
std::string errorMsg;
@ -163,8 +161,8 @@ namespace ix
_perMessageDeflateOptions,
_enablePerMessageDeflate);
auto result = webSocketHandshake.clientHandshake(url, headers, host, path,
port, timeoutSecs);
auto result =
webSocketHandshake.clientHandshake(url, headers, host, path, port, timeoutSecs);
if (result.success)
{
setReadyState(ReadyState::OPEN);
@ -247,15 +245,15 @@ namespace ix
if (_pingIntervalOrTimeoutGCDSecs > 0)
{
_nextGCDTimePoint = std::chrono::steady_clock::now() + std::chrono::seconds(_pingIntervalOrTimeoutGCDSecs);
_nextGCDTimePoint = std::chrono::steady_clock::now() +
std::chrono::seconds(_pingIntervalOrTimeoutGCDSecs);
}
}
// Only consider send PING time points for that computation.
bool WebSocketTransport::pingIntervalExceeded()
{
if (_pingIntervalSecs <= 0)
return false;
if (_pingIntervalSecs <= 0) return false;
std::lock_guard<std::mutex> lock(_lastSendPingTimePointMutex);
auto now = std::chrono::steady_clock::now();
@ -264,8 +262,7 @@ namespace ix
bool WebSocketTransport::pingTimeoutExceeded()
{
if (_pingTimeoutSecs <= 0)
return false;
if (_pingTimeoutSecs <= 0) return false;
std::lock_guard<std::mutex> lock(_lastReceivePongTimePointMutex);
auto now = std::chrono::steady_clock::now();
@ -302,7 +299,8 @@ 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 != ReadyState::OPEN) ? 0 : _pingIntervalOrTimeoutGCDSecs;
int lastingTimeoutDelayInMs =
(_readyState != ReadyState::OPEN) ? 0 : _pingIntervalOrTimeoutGCDSecs;
if (_pingIntervalOrTimeoutGCDSecs > 0)
{
@ -317,7 +315,10 @@ namespace ix
}
else
{
lastingTimeoutDelayInMs = (int)std::chrono::duration_cast<std::chrono::milliseconds>(_nextGCDTimePoint - now).count();
lastingTimeoutDelayInMs =
(int) std::chrono::duration_cast<std::chrono::milliseconds>(_nextGCDTimePoint -
now)
.count();
}
}
@ -365,7 +366,7 @@ namespace ix
{
while (true)
{
ssize_t ret = _socket->recv((char*)&_readbuf[0], _readbuf.size());
ssize_t ret = _socket->recv((char*) &_readbuf[0], _readbuf.size());
if (ret < 0 && Socket::isWaitNeeded())
{
@ -373,8 +374,9 @@ namespace ix
}
else if (ret <= 0)
{
// if there are received data pending to be processed, then delay the abnormal closure
// to after dispatch (other close code/reason could be read from the buffer)
// if there are received data pending to be processed, then delay the abnormal
// closure to after dispatch (other close code/reason could be read from the
// buffer)
closeSocket();
@ -382,9 +384,7 @@ namespace ix
}
else
{
_rxbuf.insert(_rxbuf.end(),
_readbuf.begin(),
_readbuf.begin() + ret);
_rxbuf.insert(_rxbuf.end(), _readbuf.begin(), _readbuf.begin() + ret);
}
}
}
@ -429,7 +429,7 @@ namespace ix
{
for (size_t i = 0; i != (size_t) message_size; ++i)
{
*(_txbuf.end() - (size_t) message_size + i) ^= masking_key[i&0x3];
*(_txbuf.end() - (size_t) message_size + i) ^= masking_key[i & 0x3];
}
}
}
@ -440,7 +440,7 @@ namespace ix
{
for (size_t j = 0; j != ws.N; ++j)
{
_rxbuf[j+ws.header_size] ^= ws.masking_key[j&0x3];
_rxbuf[j + ws.header_size] ^= ws.masking_key[j & 0x3];
}
}
}
@ -473,16 +473,17 @@ namespace ix
while (true)
{
wsheader_type ws;
if (_rxbuf.size() < 2) break; /* Need at least 2 */
const uint8_t * data = (uint8_t *) &_rxbuf[0]; // peek, but don't consume
if (_rxbuf.size() < 2) break; /* Need at least 2 */
const uint8_t* data = (uint8_t*) &_rxbuf[0]; // peek, but don't consume
ws.fin = (data[0] & 0x80) == 0x80;
ws.rsv1 = (data[0] & 0x40) == 0x40;
ws.rsv2 = (data[0] & 0x20) == 0x20;
ws.rsv3 = (data[0] & 0x10) == 0x10;
ws.opcode = (wsheader_type::opcode_type) (data[0] & 0x0f);
ws.opcode = (wsheader_type::opcode_type)(data[0] & 0x0f);
ws.mask = (data[1] & 0x80) == 0x80;
ws.N0 = (data[1] & 0x7f);
ws.header_size = 2 + (ws.N0 == 126? 2 : 0) + (ws.N0 == 127? 8 : 0) + (ws.mask? 4 : 0);
ws.header_size =
2 + (ws.N0 == 126 ? 2 : 0) + (ws.N0 == 127 ? 8 : 0) + (ws.mask ? 4 : 0);
if (_rxbuf.size() < ws.header_size) break; /* Need: ws.header_size - _rxbuf.size() */
if ((ws.rsv1 && !_enablePerMessageDeflate) || ws.rsv2 || ws.rsv3)
@ -533,10 +534,10 @@ namespace ix
if (ws.mask)
{
ws.masking_key[0] = ((uint8_t) data[i+0]) << 0;
ws.masking_key[1] = ((uint8_t) data[i+1]) << 0;
ws.masking_key[2] = ((uint8_t) data[i+2]) << 0;
ws.masking_key[3] = ((uint8_t) data[i+3]) << 0;
ws.masking_key[0] = ((uint8_t) data[i + 0]) << 0;
ws.masking_key[1] = ((uint8_t) data[i + 1]) << 0;
ws.masking_key[2] = ((uint8_t) data[i + 2]) << 0;
ws.masking_key[3] = ((uint8_t) data[i + 3]) << 0;
}
else
{
@ -546,16 +547,14 @@ namespace ix
ws.masking_key[3] = 0;
}
if (_rxbuf.size() < ws.header_size+ws.N)
if (_rxbuf.size() < ws.header_size + ws.N)
{
return; /* Need: ws.header_size+ws.N - _rxbuf.size() */
}
if (!ws.fin && (
ws.opcode == wsheader_type::PING
|| ws.opcode == wsheader_type::PONG
|| ws.opcode == wsheader_type::CLOSE
)){
if (!ws.fin && (ws.opcode == wsheader_type::PING || ws.opcode == wsheader_type::PONG ||
ws.opcode == wsheader_type::CLOSE))
{
// Control messages should not be fragmented
close(WebSocketCloseConstants::kProtocolErrorCode,
WebSocketCloseConstants::kProtocolErrorCodeControlMessageFragmented);
@ -563,22 +562,19 @@ namespace ix
}
unmaskReceiveBuffer(ws);
std::string frameData(_rxbuf.begin()+ws.header_size,
_rxbuf.begin()+ws.header_size+(size_t) ws.N);
std::string frameData(_rxbuf.begin() + ws.header_size,
_rxbuf.begin() + ws.header_size + (size_t) ws.N);
// We got a whole message, now do something with it:
if (
ws.opcode == wsheader_type::TEXT_FRAME
|| ws.opcode == wsheader_type::BINARY_FRAME
|| ws.opcode == wsheader_type::CONTINUATION
) {
if (ws.opcode == wsheader_type::TEXT_FRAME ||
ws.opcode == wsheader_type::BINARY_FRAME ||
ws.opcode == wsheader_type::CONTINUATION)
{
if (ws.opcode != wsheader_type::CONTINUATION)
{
_fragmentedMessageKind =
(ws.opcode == wsheader_type::TEXT_FRAME)
? MessageKind::MSG_TEXT
: MessageKind::MSG_BINARY;
_fragmentedMessageKind = (ws.opcode == wsheader_type::TEXT_FRAME)
? MessageKind::MSG_TEXT
: MessageKind::MSG_BINARY;
_compressedMessage = _enablePerMessageDeflate && ws.rsv1;
@ -592,8 +588,9 @@ namespace ix
else if (_chunks.empty())
{
// Continuation message need to follow a non-fin TEXT or BINARY message
close(WebSocketCloseConstants::kProtocolErrorCode,
WebSocketCloseConstants::kProtocolErrorCodeContinuationOpCodeOutOfSequence);
close(
WebSocketCloseConstants::kProtocolErrorCode,
WebSocketCloseConstants::kProtocolErrorCodeContinuationOpCodeOutOfSequence);
}
//
@ -601,10 +598,8 @@ namespace ix
//
if (ws.fin && _chunks.empty())
{
emitMessage(_fragmentedMessageKind,
frameData,
_compressedMessage,
onMessageCallback);
emitMessage(
_fragmentedMessageKind, frameData, _compressedMessage, onMessageCallback);
_compressedMessage = false;
}
@ -621,8 +616,10 @@ namespace ix
if (ws.fin)
{
emitMessage(_fragmentedMessageKind, getMergedChunks(),
_compressedMessage, onMessageCallback);
emitMessage(_fragmentedMessageKind,
getMergedChunks(),
_compressedMessage,
onMessageCallback);
_chunks.clear();
_compressedMessage = false;
@ -668,8 +665,8 @@ namespace ix
if (ws.N >= 2)
{
// Extract the close code first, available as the first 2 bytes
code |= ((uint64_t) _rxbuf[ws.header_size]) << 8;
code |= ((uint64_t) _rxbuf[ws.header_size+1]) << 0;
code |= ((uint64_t) _rxbuf[ws.header_size]) << 8;
code |= ((uint64_t) _rxbuf[ws.header_size + 1]) << 0;
// Get the reason.
if (ws.N > 2)
@ -690,13 +687,11 @@ namespace ix
// Full list of status code and status range is defined in the dedicated
// RFC section at https://tools.ietf.org/html/rfc6455#page-45
//
if (code < 1000 || code == 1004 || code == 1006 ||
(code > 1013 && code < 3000))
if (code < 1000 || code == 1004 || code == 1006 || (code > 1013 && code < 3000))
{
// build up an error message containing the bad error code
std::stringstream ss;
ss << WebSocketCloseConstants::kInvalidCloseCodeMessage
<< ": " << code;
ss << WebSocketCloseConstants::kInvalidCloseCodeMessage << ": " << code;
reason = ss.str();
code = WebSocketCloseConstants::kProtocolErrorCode;
@ -722,8 +717,8 @@ namespace ix
}
else
{
// we got the CLOSE frame answer from our close, so we can close the connection if
// the code/reason are the same
// we got the CLOSE frame answer from our close, so we can close the connection
// if the code/reason are the same
bool identicalReason;
{
std::lock_guard<std::mutex> lock(_closeDataMutex);
@ -746,8 +741,7 @@ namespace ix
}
// Erase the message that has been processed from the input/read buffer
_rxbuf.erase(_rxbuf.begin(),
_rxbuf.begin() + ws.header_size + (size_t) ws.N);
_rxbuf.erase(_rxbuf.begin(), _rxbuf.begin() + ws.header_size + (size_t) ws.N);
}
// if an abnormal closure was raised in poll, and nothing else triggered a CLOSED state in
@ -756,7 +750,8 @@ namespace ix
{
_rxbuf.clear();
// if we previously closed the connection (CLOSING state), then set state to CLOSED (code/reason were set before)
// if we previously closed the connection (CLOSING state), then set state to CLOSED
// (code/reason were set before)
if (_readyState == ReadyState::CLOSING)
{
closeSocket();
@ -767,7 +762,8 @@ namespace ix
{
closeSocketAndSwitchToClosedState(WebSocketCloseConstants::kAbnormalCloseCode,
WebSocketCloseConstants::kAbnormalCloseMessage,
0, false);
0,
false);
}
}
}
@ -832,16 +828,14 @@ namespace ix
{
auto now = std::chrono::system_clock::now();
auto seconds =
std::chrono::duration_cast<std::chrono::seconds>(
now.time_since_epoch()).count();
std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
return static_cast<unsigned>(seconds);
}
WebSocketSendInfo WebSocketTransport::sendData(
wsheader_type::opcode_type type,
const std::string& message,
bool compress,
const OnProgressCallback& onProgressCallback)
WebSocketSendInfo WebSocketTransport::sendData(wsheader_type::opcode_type type,
const std::string& message,
bool compress,
const OnProgressCallback& onProgressCallback)
{
if (_readyState != ReadyState::OPEN && _readyState != ReadyState::CLOSING)
{
@ -895,10 +889,10 @@ namespace ix
std::string::const_iterator begin = message_begin;
std::string::const_iterator end = message_end;
for (uint64_t i = 0 ; i < steps; ++i)
for (uint64_t i = 0; i < steps; ++i)
{
bool firstStep = i == 0;
bool lastStep = (i+1) == steps;
bool lastStep = (i + 1) == steps;
bool fin = lastStep;
end = begin + kChunkSize;
@ -916,7 +910,7 @@ namespace ix
// Send message
sendFragment(opcodeType, fin, begin, end, compress);
if (onProgressCallback && !onProgressCallback((int)i, (int) steps))
if (onProgressCallback && !onProgressCallback((int) i, (int) steps))
{
break;
}
@ -946,14 +940,13 @@ namespace ix
uint8_t masking_key[4] = {};
masking_key[0] = (x >> 24);
masking_key[1] = (x >> 16) & 0xff;
masking_key[2] = (x >> 8) & 0xff;
masking_key[3] = (x) & 0xff;
masking_key[2] = (x >> 8) & 0xff;
masking_key[3] = (x) &0xff;
std::vector<uint8_t> header;
header.assign(2 +
(message_size >= 126 ? 2 : 0) +
(message_size >= 65536 ? 6 : 0) +
(_useMask ? 4 : 0), 0);
header.assign(2 + (message_size >= 126 ? 2 : 0) + (message_size >= 65536 ? 6 : 0) +
(_useMask ? 4 : 0),
0);
header[0] = type;
// The fin bit indicate that this is the last fragment. Fin is French for end.
@ -1004,8 +997,8 @@ namespace ix
header[5] = (message_size >> 32) & 0xff;
header[6] = (message_size >> 24) & 0xff;
header[7] = (message_size >> 16) & 0xff;
header[8] = (message_size >> 8) & 0xff;
header[9] = (message_size >> 0) & 0xff;
header[8] = (message_size >> 8) & 0xff;
header[9] = (message_size >> 0) & 0xff;
if (_useMask)
{
@ -1017,8 +1010,7 @@ namespace ix
}
// _txbuf will keep growing until it can be transmitted over the socket:
appendToSendBuffer(header, message_begin, message_end,
message_size, masking_key);
appendToSendBuffer(header, message_begin, message_end, message_size, masking_key);
// Now actually send this data
sendOnSocket();
@ -1038,28 +1030,26 @@ namespace ix
return info;
}
WebSocketSendInfo WebSocketTransport::sendBinary(
const std::string& message,
const OnProgressCallback& onProgressCallback)
WebSocketSendInfo WebSocketTransport::sendBinary(const std::string& message,
const OnProgressCallback& onProgressCallback)
{
return sendData(wsheader_type::BINARY_FRAME, message,
_enablePerMessageDeflate, onProgressCallback);
return sendData(
wsheader_type::BINARY_FRAME, message, _enablePerMessageDeflate, onProgressCallback);
}
WebSocketSendInfo WebSocketTransport::sendText(
const std::string& message,
const OnProgressCallback& onProgressCallback)
WebSocketSendInfo WebSocketTransport::sendText(const std::string& message,
const OnProgressCallback& onProgressCallback)
{
return sendData(wsheader_type::TEXT_FRAME, message,
_enablePerMessageDeflate, onProgressCallback);
return sendData(
wsheader_type::TEXT_FRAME, message, _enablePerMessageDeflate, onProgressCallback);
}
ssize_t WebSocketTransport::send()
{
std::lock_guard<std::mutex> lock(_socketMutex);
return _socket->send((char*)&_txbuf[0], _txbuf.size());
return _socket->send((char*) &_txbuf[0], _txbuf.size());
}
void WebSocketTransport::sendOnSocket()
@ -1096,7 +1086,7 @@ namespace ix
{
// See list of close events here:
// https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent
std::string closure{(char)(code >> 8), (char)(code & 0xff)};
std::string closure {(char) (code >> 8), (char) (code & 0xff)};
// copy reason after code
closure.append(reason);
@ -1116,8 +1106,10 @@ namespace ix
_socket->close();
}
void WebSocketTransport::closeSocketAndSwitchToClosedState(
uint16_t code, const std::string& reason, size_t closeWireSize, bool remote)
void WebSocketTransport::closeSocketAndSwitchToClosedState(uint16_t code,
const std::string& reason,
size_t closeWireSize,
bool remote)
{
closeSocket();
@ -1133,8 +1125,10 @@ namespace ix
_requestInitCancellation = false;
}
void WebSocketTransport::close(
uint16_t code, const std::string& reason, size_t closeWireSize, bool remote)
void WebSocketTransport::close(uint16_t code,
const std::string& reason,
size_t closeWireSize,
bool remote)
{
_requestInitCancellation = true;

View File

@ -25,7 +25,6 @@
#include <memory>
#include <mutex>
#include <string>
#include <vector>
namespace ix

View File

@ -32,232 +32,249 @@
#include <stdlib.h>
// check if the scheme name is valid
static bool IsSchemeValid( const std::string& SchemeName )
static bool IsSchemeValid(const std::string& SchemeName)
{
for ( auto c : SchemeName )
{
if ( !isalpha( c ) && c != '+' && c != '-' && c != '.' ) return false;
}
for (auto c : SchemeName)
{
if (!isalpha(c) && c != '+' && c != '-' && c != '.') return false;
}
return true;
return true;
}
bool LUrlParser::clParseURL::GetPort( int* OutPort ) const
bool LUrlParser::clParseURL::GetPort(int* OutPort) const
{
if ( !IsValid() ) { return false; }
if (!IsValid())
{
return false;
}
int Port = atoi( m_Port.c_str() );
int Port = atoi(m_Port.c_str());
if ( Port <= 0 || Port > 65535 ) { return false; }
if (Port <= 0 || Port > 65535)
{
return false;
}
if ( OutPort ) { *OutPort = Port; }
if (OutPort)
{
*OutPort = Port;
}
return true;
return true;
}
// based on RFC 1738 and RFC 3986
LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL )
LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL(const std::string& URL)
{
LUrlParser::clParseURL Result;
LUrlParser::clParseURL Result;
const char* CurrentString = URL.c_str();
const char* CurrentString = URL.c_str();
/*
* <scheme>:<scheme-specific-part>
* <scheme> := [a-z\+\-\.]+
* For resiliency, programs interpreting URLs should treat upper case letters as equivalent to lower case in scheme names
*/
/*
* <scheme>:<scheme-specific-part>
* <scheme> := [a-z\+\-\.]+
* For resiliency, programs interpreting URLs should treat upper case letters as equivalent to
*lower case in scheme names
*/
// try to read scheme
{
const char* LocalString = strchr( CurrentString, ':' );
// try to read scheme
{
const char* LocalString = strchr(CurrentString, ':');
if ( !LocalString )
{
return clParseURL( LUrlParserError_NoUrlCharacter );
}
if (!LocalString)
{
return clParseURL(LUrlParserError_NoUrlCharacter);
}
// save the scheme name
Result.m_Scheme = std::string( CurrentString, LocalString - CurrentString );
// save the scheme name
Result.m_Scheme = std::string(CurrentString, LocalString - CurrentString);
if ( !IsSchemeValid( Result.m_Scheme ) )
{
return clParseURL( LUrlParserError_InvalidSchemeName );
}
if (!IsSchemeValid(Result.m_Scheme))
{
return clParseURL(LUrlParserError_InvalidSchemeName);
}
// scheme should be lowercase
std::transform( Result.m_Scheme.begin(), Result.m_Scheme.end(), Result.m_Scheme.begin(), ::tolower );
// scheme should be lowercase
std::transform(
Result.m_Scheme.begin(), Result.m_Scheme.end(), Result.m_Scheme.begin(), ::tolower);
// skip ':'
CurrentString = LocalString+1;
}
// skip ':'
CurrentString = LocalString + 1;
}
/*
* //<user>:<password>@<host>:<port>/<url-path>
* any ":", "@" and "/" must be normalized
*/
/*
* //<user>:<password>@<host>:<port>/<url-path>
* any ":", "@" and "/" must be normalized
*/
// skip "//"
if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError_NoDoubleSlash );
if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError_NoDoubleSlash );
// skip "//"
if (*CurrentString++ != '/') return clParseURL(LUrlParserError_NoDoubleSlash);
if (*CurrentString++ != '/') return clParseURL(LUrlParserError_NoDoubleSlash);
// check if the user name and password are specified
bool bHasUserName = false;
// check if the user name and password are specified
bool bHasUserName = false;
const char* LocalString = CurrentString;
const char* LocalString = CurrentString;
while ( *LocalString )
{
if ( *LocalString == '@' )
{
// user name and password are specified
bHasUserName = true;
break;
}
else if ( *LocalString == '/' )
{
// end of <host>:<port> specification
bHasUserName = false;
break;
}
while (*LocalString)
{
if (*LocalString == '@')
{
// user name and password are specified
bHasUserName = true;
break;
}
else if (*LocalString == '/')
{
// end of <host>:<port> specification
bHasUserName = false;
break;
}
LocalString++;
}
LocalString++;
}
// user name and password
LocalString = CurrentString;
// user name and password
LocalString = CurrentString;
if ( bHasUserName )
{
// read user name
while ( *LocalString && *LocalString != ':' && *LocalString != '@' ) LocalString++;
if (bHasUserName)
{
// read user name
while (*LocalString && *LocalString != ':' && *LocalString != '@')
LocalString++;
Result.m_UserName = std::string( CurrentString, LocalString - CurrentString );
Result.m_UserName = std::string(CurrentString, LocalString - CurrentString);
// proceed with the current pointer
CurrentString = LocalString;
// proceed with the current pointer
CurrentString = LocalString;
if ( *CurrentString == ':' )
{
// skip ':'
CurrentString++;
if (*CurrentString == ':')
{
// skip ':'
CurrentString++;
// read password
LocalString = CurrentString;
// read password
LocalString = CurrentString;
while ( *LocalString && *LocalString != '@' ) LocalString++;
while (*LocalString && *LocalString != '@')
LocalString++;
Result.m_Password = std::string( CurrentString, LocalString - CurrentString );
Result.m_Password = std::string(CurrentString, LocalString - CurrentString);
CurrentString = LocalString;
}
CurrentString = LocalString;
}
// skip '@'
if ( *CurrentString != '@' )
{
return clParseURL( LUrlParserError_NoAtSign );
}
// skip '@'
if (*CurrentString != '@')
{
return clParseURL(LUrlParserError_NoAtSign);
}
CurrentString++;
}
CurrentString++;
}
bool bHasBracket = ( *CurrentString == '[' );
bool bHasBracket = (*CurrentString == '[');
// go ahead, read the host name
LocalString = CurrentString;
// go ahead, read the host name
LocalString = CurrentString;
while ( *LocalString )
{
if ( bHasBracket && *LocalString == ']' )
{
// end of IPv6 address
LocalString++;
break;
}
else if ( !bHasBracket && ( *LocalString == ':' || *LocalString == '/' ) )
{
// port number is specified
break;
}
while (*LocalString)
{
if (bHasBracket && *LocalString == ']')
{
// end of IPv6 address
LocalString++;
break;
}
else if (!bHasBracket && (*LocalString == ':' || *LocalString == '/'))
{
// port number is specified
break;
}
LocalString++;
}
LocalString++;
}
Result.m_Host = std::string( CurrentString, LocalString - CurrentString );
Result.m_Host = std::string(CurrentString, LocalString - CurrentString);
CurrentString = LocalString;
CurrentString = LocalString;
// is port number specified?
if ( *CurrentString == ':' )
{
CurrentString++;
// is port number specified?
if (*CurrentString == ':')
{
CurrentString++;
// read port number
LocalString = CurrentString;
// read port number
LocalString = CurrentString;
while ( *LocalString && *LocalString != '/' ) LocalString++;
while (*LocalString && *LocalString != '/')
LocalString++;
Result.m_Port = std::string( CurrentString, LocalString - CurrentString );
Result.m_Port = std::string(CurrentString, LocalString - CurrentString);
CurrentString = LocalString;
}
CurrentString = LocalString;
}
// end of string
if ( !*CurrentString )
{
Result.m_ErrorCode = LUrlParserError_Ok;
// end of string
if (!*CurrentString)
{
Result.m_ErrorCode = LUrlParserError_Ok;
return Result;
}
return Result;
}
// skip '/'
if ( *CurrentString != '/' )
{
return clParseURL( LUrlParserError_NoSlash );
}
// skip '/'
if (*CurrentString != '/')
{
return clParseURL(LUrlParserError_NoSlash);
}
CurrentString++;
CurrentString++;
// parse the path
LocalString = CurrentString;
// parse the path
LocalString = CurrentString;
while ( *LocalString && *LocalString != '#' && *LocalString != '?' ) LocalString++;
while (*LocalString && *LocalString != '#' && *LocalString != '?')
LocalString++;
Result.m_Path = std::string( CurrentString, LocalString - CurrentString );
Result.m_Path = std::string(CurrentString, LocalString - CurrentString);
CurrentString = LocalString;
CurrentString = LocalString;
// check for query
if ( *CurrentString == '?' )
{
// skip '?'
CurrentString++;
// check for query
if (*CurrentString == '?')
{
// skip '?'
CurrentString++;
// read query
LocalString = CurrentString;
// read query
LocalString = CurrentString;
while ( *LocalString && *LocalString != '#' ) LocalString++;
while (*LocalString && *LocalString != '#')
LocalString++;
Result.m_Query = std::string( CurrentString, LocalString - CurrentString );
Result.m_Query = std::string(CurrentString, LocalString - CurrentString);
CurrentString = LocalString;
}
CurrentString = LocalString;
}
// check for fragment
if ( *CurrentString == '#' )
{
// skip '#'
CurrentString++;
// check for fragment
if (*CurrentString == '#')
{
// skip '#'
CurrentString++;
// read fragment
LocalString = CurrentString;
// read fragment
LocalString = CurrentString;
while ( *LocalString ) LocalString++;
while (*LocalString)
LocalString++;
Result.m_Fragment = std::string( CurrentString, LocalString - CurrentString );
}
Result.m_Fragment = std::string(CurrentString, LocalString - CurrentString);
}
Result.m_ErrorCode = LUrlParserError_Ok;
Result.m_ErrorCode = LUrlParserError_Ok;
return Result;
return Result;
}

View File

@ -62,7 +62,10 @@ namespace LUrlParser
}
/// return 'true' if the parsing was successful
bool IsValid() const { return m_ErrorCode == LUrlParserError_Ok; }
bool IsValid() const
{
return m_ErrorCode == LUrlParserError_Ok;
}
/// helper to convert the port number to int, return 'true' if the port is valid (within the
/// 0..65535 range)

View File

@ -17,4 +17,4 @@ namespace ix
//
pthread_setname_np(name.substr(0, 63).c_str());
}
}
} // namespace ix

View File

@ -15,7 +15,6 @@ namespace ix
// See prctl and PR_SET_NAME property in
// http://man7.org/linux/man-pages/man2/prctl.2.html
//
pthread_setname_np(pthread_self(),
name.substr(0, 15).c_str());
pthread_setname_np(pthread_self(), name.substr(0, 15).c_str());
}
}
} // namespace ix

View File

@ -4,13 +4,14 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include "../IXSetThreadName.h"
#include <Windows.h>
namespace ix
{
const DWORD MS_VC_EXCEPTION = 0x406D1388;
#pragma pack(push,8)
#pragma pack(push, 8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
@ -30,7 +31,8 @@ namespace ix
__try
{
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)& info);
RaiseException(
MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*) &info);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
@ -41,4 +43,4 @@ namespace ix
{
SetThreadName(-1, name.c_str());
}
}
} // namespace ix

View File

@ -4,14 +4,13 @@
* Copyright (c) 2017 Machine Zone. All rights reserved.
*/
#include <iostream>
#include "IXSnakeServer.h"
#include "IXTest.h"
#include "catch.hpp"
#include <chrono>
#include <iostream>
#include <ixcobra/IXCobraConnection.h>
#include <ixcrypto/IXUuid.h>
#include "IXTest.h"
#include "IXSnakeServer.h"
#include "catch.hpp"
using namespace ix;
@ -22,67 +21,64 @@ namespace
void setupTrafficTrackerCallback()
{
ix::CobraConnection::setTrafficTrackerCallback(
[](size_t size, bool incoming)
ix::CobraConnection::setTrafficTrackerCallback([](size_t size, bool incoming) {
if (incoming)
{
if (incoming)
{
incomingBytes += size;
}
else
{
outgoingBytes += size;
}
incomingBytes += size;
}
);
else
{
outgoingBytes += size;
}
});
}
class SatoriChat
{
public:
SatoriChat(const std::string& user,
const std::string& session,
const std::string& endpoint);
public:
SatoriChat(const std::string& user,
const std::string& session,
const std::string& endpoint);
void subscribe(const std::string& channel);
void start();
void stop();
void run();
bool isReady() const;
void subscribe(const std::string& channel);
void start();
void stop();
void run();
bool isReady() const;
void sendMessage(const std::string& text);
size_t getReceivedMessagesCount() const;
void sendMessage(const std::string& text);
size_t getReceivedMessagesCount() const;
bool hasPendingMessages() const;
Json::Value popMessage();
bool hasPendingMessages() const;
Json::Value popMessage();
private:
std::string _user;
std::string _session;
std::string _endpoint;
private:
std::string _user;
std::string _session;
std::string _endpoint;
std::queue<Json::Value> _publish_queue;
mutable std::mutex _queue_mutex;
std::queue<Json::Value> _publish_queue;
mutable std::mutex _queue_mutex;
std::thread _thread;
std::atomic<bool> _stop;
std::thread _thread;
std::atomic<bool> _stop;
ix::CobraConnection _conn;
std::atomic<bool> _connectedAndSubscribed;
ix::CobraConnection _conn;
std::atomic<bool> _connectedAndSubscribed;
std::queue<Json::Value> _receivedQueue;
std::queue<Json::Value> _receivedQueue;
std::mutex _logMutex;
std::mutex _logMutex;
};
SatoriChat::SatoriChat(const std::string& user,
const std::string& session,
const std::string& endpoint) :
_user(user),
_session(session),
_endpoint(endpoint),
_stop(false),
_connectedAndSubscribed(false)
const std::string& endpoint)
: _user(user)
, _session(session)
, _endpoint(endpoint)
, _stop(false)
, _connectedAndSubscribed(false)
{
}
@ -127,35 +123,30 @@ namespace
void SatoriChat::subscribe(const std::string& channel)
{
std::string filter;
_conn.subscribe(channel, filter,
[this](const Json::Value& msg)
{
std::cout << msg.toStyledString() << std::endl;
if (!msg.isObject()) return;
if (!msg.isMember("user")) return;
if (!msg.isMember("text")) return;
if (!msg.isMember("session")) return;
_conn.subscribe(channel, filter, [this](const Json::Value& msg) {
std::cout << msg.toStyledString() << std::endl;
if (!msg.isObject()) return;
if (!msg.isMember("user")) return;
if (!msg.isMember("text")) return;
if (!msg.isMember("session")) return;
std::string msg_user = msg["user"].asString();
std::string msg_text = msg["text"].asString();
std::string msg_session = msg["session"].asString();
std::string msg_user = msg["user"].asString();
std::string msg_text = msg["text"].asString();
std::string msg_session = msg["session"].asString();
// We are not interested in messages
// from a different session.
if (msg_session != _session) return;
// We are not interested in messages
// from a different session.
if (msg_session != _session) return;
// We are not interested in our own messages
if (msg_user == _user) return;
// We are not interested in our own messages
if (msg_user == _user) return;
_receivedQueue.push(msg);
_receivedQueue.push(msg);
std::stringstream ss;
ss << std::endl
<< msg_user << " > " << msg_text
<< std::endl
<< _user << " > ";
log(ss.str());
});
std::stringstream ss;
ss << std::endl << msg_user << " > " << msg_text << std::endl << _user << " > ";
log(ss.str());
});
}
void SatoriChat::sendMessage(const std::string& text)
@ -189,50 +180,46 @@ namespace
std::string role = "_sub";
std::string secret = "66B1dA3ED5fA074EB5AE84Dd8CE3b5ba";
_conn.configure(appkey, _endpoint, role, secret,
ix::WebSocketPerMessageDeflateOptions(true));
_conn.configure(
appkey, _endpoint, role, secret, ix::WebSocketPerMessageDeflateOptions(true));
_conn.connect();
_conn.setEventCallback(
[this, channel]
(ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& /*headers*/,
const std::string& subscriptionId,
CobraConnection::MsgId msgId)
_conn.setEventCallback([this, channel](ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& /*headers*/,
const std::string& subscriptionId,
CobraConnection::MsgId msgId) {
if (eventType == ix::CobraConnection_EventType_Open)
{
if (eventType == ix::CobraConnection_EventType_Open)
{
log("Subscriber connected: " + _user);
}
else if (eventType == ix::CobraConnection_EventType_Authenticated)
{
log("Subscriber authenticated: " + _user);
subscribe(channel);
}
else if (eventType == ix::CobraConnection_EventType_Error)
{
log(errMsg + _user);
}
else if (eventType == ix::CobraConnection_EventType_Closed)
{
log("Connection closed: " + _user);
}
else if (eventType == ix::CobraConnection_EventType_Subscribed)
{
log("Subscription ok: " + _user + " subscription_id " + subscriptionId);
_connectedAndSubscribed = true;
}
else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
{
log("Unsubscription ok: " + _user + " subscription_id " + subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_Published)
{
Logger() << "Subscriber: published message acked: " << msgId;
}
log("Subscriber connected: " + _user);
}
);
else if (eventType == ix::CobraConnection_EventType_Authenticated)
{
log("Subscriber authenticated: " + _user);
subscribe(channel);
}
else if (eventType == ix::CobraConnection_EventType_Error)
{
log(errMsg + _user);
}
else if (eventType == ix::CobraConnection_EventType_Closed)
{
log("Connection closed: " + _user);
}
else if (eventType == ix::CobraConnection_EventType_Subscribed)
{
log("Subscription ok: " + _user + " subscription_id " + subscriptionId);
_connectedAndSubscribed = true;
}
else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
{
log("Unsubscription ok: " + _user + " subscription_id " + subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_Published)
{
Logger() << "Subscriber: published message acked: " << msgId;
}
});
while (!_stop)
{
@ -261,19 +248,15 @@ namespace
ix::msleep(50);
_conn.disconnect();
_conn.setEventCallback([]
(ix::CobraConnectionEventType /*eventType*/,
const std::string& /*errMsg*/,
const ix::WebSocketHttpHeaders& /*headers*/,
const std::string& /*subscriptionId*/,
CobraConnection::MsgId /*msgId*/)
{
;
});
_conn.setEventCallback([](ix::CobraConnectionEventType /*eventType*/,
const std::string& /*errMsg*/,
const ix::WebSocketHttpHeaders& /*headers*/,
const std::string& /*subscriptionId*/,
CobraConnection::MsgId /*msgId*/) { ; });
snakeServer.stop();
}
}
} // namespace
TEST_CASE("Cobra_chat", "[cobra_chat]")
{

View File

@ -3,14 +3,13 @@
* Copyright (c) 2018 Machine Zone. All rights reserved.
*/
#include <iostream>
#include <set>
#include <ixcrypto/IXUuid.h>
#include <ixcobra/IXCobraMetricsPublisher.h>
#include "IXTest.h"
#include "IXSnakeServer.h"
#include "IXTest.h"
#include "catch.hpp"
#include <iostream>
#include <ixcobra/IXCobraMetricsPublisher.h>
#include <ixcrypto/IXUuid.h>
#include <set>
using namespace ix;
@ -45,70 +44,67 @@ namespace
gMessageCount = 0;
ix::CobraConnection conn;
conn.configure(APPKEY, endpoint, SUBSCRIBER_ROLE, SUBSCRIBER_SECRET,
conn.configure(APPKEY,
endpoint,
SUBSCRIBER_ROLE,
SUBSCRIBER_SECRET,
ix::WebSocketPerMessageDeflateOptions(true));
conn.connect();
conn.setEventCallback(
[&conn]
(ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& /*headers*/,
const std::string& subscriptionId,
CobraConnection::MsgId msgId)
conn.setEventCallback([&conn](ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& /*headers*/,
const std::string& subscriptionId,
CobraConnection::MsgId msgId) {
if (eventType == ix::CobraConnection_EventType_Open)
{
if (eventType == ix::CobraConnection_EventType_Open)
{
Logger() << "Subscriber connected:";
}
if (eventType == ix::CobraConnection_EventType_Error)
{
Logger() << "Subscriber error:" << errMsg;
}
else if (eventType == ix::CobraConnection_EventType_Authenticated)
{
log("Subscriber authenticated");
std::string filter;
conn.subscribe(CHANNEL, filter,
[](const Json::Value& msg)
{
log(msg.toStyledString());
Logger() << "Subscriber connected:";
}
if (eventType == ix::CobraConnection_EventType_Error)
{
Logger() << "Subscriber error:" << errMsg;
}
else if (eventType == ix::CobraConnection_EventType_Authenticated)
{
log("Subscriber authenticated");
std::string filter;
conn.subscribe(CHANNEL, filter, [](const Json::Value& msg) {
log(msg.toStyledString());
std::string id = msg["id"].asString();
{
std::lock_guard<std::mutex> guard(gProtectIds);
gIds.insert(id);
}
std::string id = msg["id"].asString();
{
std::lock_guard<std::mutex> guard(gProtectIds);
gIds.insert(id);
}
gMessageCount++;
});
}
else if (eventType == ix::CobraConnection_EventType_Subscribed)
gMessageCount++;
});
}
else if (eventType == ix::CobraConnection_EventType_Subscribed)
{
Logger() << "Subscriber: subscribed to channel " << subscriptionId;
if (subscriptionId == CHANNEL)
{
Logger() << "Subscriber: subscribed to channel " << subscriptionId;
if (subscriptionId == CHANNEL)
{
gSubscriberConnectedAndSubscribed = true;
}
else
{
Logger() << "Subscriber: unexpected channel " << subscriptionId;
}
gSubscriberConnectedAndSubscribed = true;
}
else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
else
{
Logger() << "Subscriber: ununexpected from channel " << subscriptionId;
if (subscriptionId != CHANNEL)
{
Logger() << "Subscriber: unexpected channel " << subscriptionId;
}
}
else if (eventType == ix::CobraConnection_EventType_Published)
{
Logger() << "Subscriber: published message acked: " << msgId;
Logger() << "Subscriber: unexpected channel " << subscriptionId;
}
}
);
else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
{
Logger() << "Subscriber: ununexpected from channel " << subscriptionId;
if (subscriptionId != CHANNEL)
{
Logger() << "Subscriber: unexpected channel " << subscriptionId;
}
}
else if (eventType == ix::CobraConnection_EventType_Published)
{
Logger() << "Subscriber: published message acked: " << msgId;
}
});
while (!gStop)
{
@ -121,7 +117,7 @@ namespace
gUniqueMessageIdsCount = gIds.size();
}
}
} // namespace
TEST_CASE("Cobra_Metrics_Publisher", "[cobra]")
{
@ -158,8 +154,8 @@ TEST_CASE("Cobra_Metrics_Publisher", "[cobra]")
ix::CobraMetricsPublisher cobraMetricsPublisher;
bool perMessageDeflate = true;
cobraMetricsPublisher.configure(APPKEY, endpoint, CHANNEL,
PUBLISHER_ROLE, PUBLISHER_SECRET, perMessageDeflate);
cobraMetricsPublisher.configure(
APPKEY, endpoint, CHANNEL, PUBLISHER_ROLE, PUBLISHER_SECRET, perMessageDeflate);
cobraMetricsPublisher.setSession(uuid4());
cobraMetricsPublisher.enable(true); // disabled by default, needs to be enabled to be active
@ -189,7 +185,7 @@ TEST_CASE("Cobra_Metrics_Publisher", "[cobra]")
// (msg #6)
cobraMetricsPublisher.setRateControl({
{"sms_metric_C_id", 1}, // published once per minute (60 seconds) max
{"sms_metric_C_id", 1}, // published once per minute (60 seconds) max
});
// (msg #7)
cobraMetricsPublisher.push("sms_metric_C_id", data);
@ -205,7 +201,7 @@ TEST_CASE("Cobra_Metrics_Publisher", "[cobra]")
log("Testing suspend/resume now, which will disconnect the cobraMetricsPublisher.");
// Test suspend + resume
for (int i = 0 ; i < 3 ; ++i)
for (int i = 0; i < 3; ++i)
{
cobraMetricsPublisher.suspend();
ix::msleep(500);
@ -214,7 +210,7 @@ TEST_CASE("Cobra_Metrics_Publisher", "[cobra]")
cobraMetricsPublisher.push("sms_metric_D_id", data); // will not be sent this time
cobraMetricsPublisher.resume();
ix::msleep(2000); // give cobra 2s to connect
ix::msleep(2000); // give cobra 2s to connect
REQUIRE(cobraMetricsPublisher.isConnected()); // Check that we are connected now
cobraMetricsPublisher.push("sms_metric_E_id", data);

View File

@ -4,11 +4,10 @@
* Copyright (c) 2018 Machine Zone. All rights reserved.
*/
#include "catch.hpp"
#include "IXTest.h"
#include <ixwebsocket/IXDNSLookup.h>
#include "catch.hpp"
#include <iostream>
#include <ixwebsocket/IXDNSLookup.h>
using namespace ix;
@ -32,7 +31,11 @@ TEST_CASE("dns", "[net]")
auto dnsLookup = std::make_shared<DNSLookup>("wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww", 80);
std::string errMsg;
struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return false; });
struct addrinfo* res = dnsLookup->resolve(errMsg,
[]
{
return false;
});
std::cerr << "Error message: " << errMsg << std::endl;
REQUIRE(res == nullptr);
}
@ -43,7 +46,11 @@ TEST_CASE("dns", "[net]")
std::string errMsg;
// The callback returning true means we are requesting cancellation
struct addrinfo* res = dnsLookup->resolve(errMsg, [] { return true; });
struct addrinfo* res = dnsLookup->resolve(errMsg,
[]
{
return true;
});
std::cerr << "Error message: " << errMsg << std::endl;
REQUIRE(res == nullptr);
}

View File

@ -5,11 +5,11 @@
*/
#include "IXGetFreePort.h"
#include <ixwebsocket/IXNetSystem.h>
#include <ixwebsocket/IXSocket.h>
#include <string>
#include <random>
#include <string>
namespace ix
{
@ -30,8 +30,7 @@ namespace ix
}
int enable = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(char*) &enable, sizeof(enable)) < 0)
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*) &enable, sizeof(enable)) < 0)
{
return getAnyFreePortRandom();
}
@ -39,10 +38,10 @@ namespace ix
// Bind to port 0. This is the standard way to get a free port.
struct sockaddr_in server; // server address information
server.sin_family = AF_INET;
server.sin_port = htons(0);
server.sin_port = htons(0);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
if (bind(sockfd, (struct sockaddr*) &server, sizeof(server)) < 0)
{
Socket::closeSocket(sockfd);
return getAnyFreePortRandom();
@ -50,7 +49,7 @@ namespace ix
struct sockaddr_in sa; // server address information
socklen_t len = sizeof(sa);
if (getsockname(sockfd, (struct sockaddr *) &sa, &len) < 0)
if (getsockname(sockfd, (struct sockaddr*) &sa, &len) < 0)
{
Socket::closeSocket(sockfd);
return getAnyFreePortRandom();
@ -67,11 +66,11 @@ namespace ix
while (true)
{
#if defined(__has_feature)
# if __has_feature(address_sanitizer)
#if __has_feature(address_sanitizer)
int port = getAnyFreePortRandom();
# else
#else
int port = getAnyFreePort();
# endif
#endif
#else
int port = getAnyFreePort();
#endif

View File

@ -4,11 +4,10 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include "catch.hpp"
#include <iostream>
#include <ixwebsocket/IXHttpClient.h>
#include "catch.hpp"
using namespace ix;
TEST_CASE("http client", "[http]")
@ -28,14 +27,10 @@ TEST_CASE("http client", "[http]")
args->maxRedirects = 10;
args->verbose = true;
args->compress = true;
args->logger = [](const std::string& msg)
{
std::cout << msg;
};
args->onProgressCallback = [](int current, int total) -> bool
{
std::cerr << "\r" << "Downloaded "
<< current << " bytes out of " << total;
args->logger = [](const std::string& msg) { std::cout << msg; };
args->onProgressCallback = [](int current, int total) -> bool {
std::cerr << "\r"
<< "Downloaded " << current << " bytes out of " << total;
return true;
};
@ -70,14 +65,10 @@ TEST_CASE("http client", "[http]")
args->maxRedirects = 10;
args->verbose = true;
args->compress = true;
args->logger = [](const std::string& msg)
{
std::cout << msg;
};
args->onProgressCallback = [](int current, int total) -> bool
{
std::cerr << "\r" << "Downloaded "
<< current << " bytes out of " << total;
args->logger = [](const std::string& msg) { std::cout << msg; };
args->onProgressCallback = [](int current, int total) -> bool {
std::cerr << "\r"
<< "Downloaded " << current << " bytes out of " << total;
return true;
};
@ -113,23 +104,18 @@ TEST_CASE("http client", "[http]")
args->maxRedirects = 10;
args->verbose = true;
args->compress = true;
args->logger = [](const std::string& msg)
{
std::cout << msg;
};
args->onProgressCallback = [](int current, int total) -> bool
{
std::cerr << "\r" << "Downloaded "
<< current << " bytes out of " << total;
args->logger = [](const std::string& msg) { std::cout << msg; };
args->onProgressCallback = [](int current, int total) -> bool {
std::cerr << "\r"
<< "Downloaded " << current << " bytes out of " << total;
return true;
};
std::atomic<bool> requestCompleted(false);
std::atomic<int> statusCode(0);
httpClient.performRequest(args, [&requestCompleted, &statusCode]
(const HttpResponsePtr& response)
{
httpClient.performRequest(
args, [&requestCompleted, &statusCode](const HttpResponsePtr& response) {
std::cerr << "Upload size: " << response->uploadSize << std::endl;
std::cerr << "Download size: " << response->downloadSize << std::endl;
std::cerr << "Status: " << response->statusCode << std::endl;
@ -138,8 +124,7 @@ TEST_CASE("http client", "[http]")
// In case of failure, print response->errorMsg
statusCode = response->statusCode;
requestCompleted = true;
}
);
});
int wait = 0;
while (wait < 5000)
@ -171,14 +156,10 @@ TEST_CASE("http client", "[http]")
args->maxRedirects = 10;
args->verbose = true;
args->compress = true;
args->logger = [](const std::string& msg)
{
std::cout << msg;
};
args->onProgressCallback = [](int current, int total) -> bool
{
std::cerr << "\r" << "Downloaded "
<< current << " bytes out of " << total;
args->logger = [](const std::string& msg) { std::cout << msg; };
args->onProgressCallback = [](int current, int total) -> bool {
std::cerr << "\r"
<< "Downloaded " << current << " bytes out of " << total;
return true;
};
@ -189,9 +170,10 @@ TEST_CASE("http client", "[http]")
for (int i = 0; i < 3; ++i)
{
httpClient.performRequest(args, [i, &requestCompleted, &statusCode0, &statusCode1, &statusCode2]
(const HttpResponsePtr& response)
{
httpClient.performRequest(
args,
[i, &requestCompleted, &statusCode0, &statusCode1, &statusCode2](
const HttpResponsePtr& response) {
std::cerr << "Upload size: " << response->uploadSize << std::endl;
std::cerr << "Download size: " << response->downloadSize << std::endl;
std::cerr << "Status: " << response->statusCode << std::endl;
@ -211,8 +193,7 @@ TEST_CASE("http client", "[http]")
statusCode2 = response->statusCode;
requestCompleted = true;
}
}
);
});
}
int wait = 0;

View File

@ -4,12 +4,11 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include "IXGetFreePort.h"
#include "catch.hpp"
#include <iostream>
#include <ixwebsocket/IXHttpClient.h>
#include <ixwebsocket/IXHttpServer.h>
#include "IXGetFreePort.h"
#include "catch.hpp"
using namespace ix;
@ -39,14 +38,10 @@ TEST_CASE("http server", "[httpd]")
args->maxRedirects = 10;
args->verbose = true;
args->compress = true;
args->logger = [](const std::string& msg)
{
std::cout << msg;
};
args->onProgressCallback = [](int current, int total) -> bool
{
std::cerr << "\r" << "Downloaded "
<< current << " bytes out of " << total;
args->logger = [](const std::string& msg) { std::cout << msg; };
args->onProgressCallback = [](int current, int total) -> bool {
std::cerr << "\r"
<< "Downloaded " << current << " bytes out of " << total;
return true;
};

View File

@ -4,52 +4,50 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include "catch.hpp"
#include <iostream>
#include <ixwebsocket/IXHttp.h>
#include "catch.hpp"
#include <string.h>
namespace ix
{
TEST_CASE("http", "[http]")
{
SECTION("Normal case")
TEST_CASE("http", "[http]")
{
std::string line = "HTTP/1.1 200";
auto result = Http::parseStatusLine(line);
SECTION("Normal case")
{
std::string line = "HTTP/1.1 200";
auto result = Http::parseStatusLine(line);
REQUIRE(result.first == "HTTP/1.1");
REQUIRE(result.second == 200);
REQUIRE(result.first == "HTTP/1.1");
REQUIRE(result.second == 200);
}
SECTION("http/1.0 case")
{
std::string line = "HTTP/1.0 200";
auto result = Http::parseStatusLine(line);
REQUIRE(result.first == "HTTP/1.0");
REQUIRE(result.second == 200);
}
SECTION("empty case")
{
std::string line = "";
auto result = Http::parseStatusLine(line);
REQUIRE(result.first == "");
REQUIRE(result.second == -1);
}
SECTION("empty case")
{
std::string line = "HTTP/1.1";
auto result = Http::parseStatusLine(line);
REQUIRE(result.first == "HTTP/1.1");
REQUIRE(result.second == -1);
}
}
SECTION("http/1.0 case")
{
std::string line = "HTTP/1.0 200";
auto result = Http::parseStatusLine(line);
REQUIRE(result.first == "HTTP/1.0");
REQUIRE(result.second == 200);
}
SECTION("empty case")
{
std::string line = "";
auto result = Http::parseStatusLine(line);
REQUIRE(result.first == "");
REQUIRE(result.second == -1);
}
SECTION("empty case")
{
std::string line = "HTTP/1.1";
auto result = Http::parseStatusLine(line);
REQUIRE(result.first == "HTTP/1.1");
REQUIRE(result.second == -1);
}
}
}
} // namespace ix

View File

@ -4,11 +4,10 @@
* Copyright (c) 2018 Machine Zone. All rights reserved.
*/
#include "catch.hpp"
#include "IXTest.h"
#include <ixwebsocket/IXSocketConnect.h>
#include "catch.hpp"
#include <iostream>
#include <ixwebsocket/IXSocketConnect.h>
using namespace ix;

View File

@ -4,13 +4,12 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include <iostream>
#include <ixwebsocket/IXSocketFactory.h>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXCancellationRequest.h>
#include "IXTest.h"
#include "catch.hpp"
#include <iostream>
#include <ixwebsocket/IXCancellationRequest.h>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXSocketFactory.h>
#include <string.h>
using namespace ix;
@ -33,8 +32,7 @@ namespace ix
Logger() << "errMsg: " << errMsg;
REQUIRE(success);
Logger() << "Sending request: " << request
<< "to " << host << ":" << port;
Logger() << "Sending request: " << request << "to " << host << ":" << port;
REQUIRE(socket->writeBytes(request, isCancellationRequested));
auto lineResult = socket->readLine(isCancellationRequested);
@ -49,11 +47,12 @@ namespace ix
REQUIRE(sscanf(line.c_str(), "HTTP/1.1 %d", &status) == 1);
REQUIRE(status == expectedStatus);
}
}
} // namespace ix
TEST_CASE("socket", "[socket]")
{
SECTION("Connect to a local websocket server over a free port. Send GET request without header. Should return 400")
SECTION("Connect to a local websocket server over a free port. Send GET request without "
"header. Should return 400")
{
// Start a server first which we'll hit with our socket code
int port = getFreePort();
@ -78,7 +77,8 @@ TEST_CASE("socket", "[socket]")
}
#if defined(IXWEBSOCKET_USE_TLS)
SECTION("Connect to google HTTPS server over port 443. Send GET request without header. Should return 200")
SECTION("Connect to google HTTPS server over port 443. Send GET request without header. Should "
"return 200")
{
std::string errMsg;
bool tls = true;

View File

@ -5,19 +5,19 @@
*/
#include "IXTest.h"
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXNetSystem.h>
#include <chrono>
#include <thread>
#include <mutex>
#include <string>
#include <fstream>
#include <iostream>
#include <stdlib.h>
#include <stack>
#include <iomanip>
#include <iostream>
#include <ixwebsocket/IXNetSystem.h>
#include <ixwebsocket/IXWebSocket.h>
#include <mutex>
#include <random>
#include <stack>
#include <stdlib.h>
#include <string>
#include <thread>
namespace ix
@ -29,19 +29,16 @@ namespace ix
void setupWebSocketTrafficTrackerCallback()
{
ix::WebSocket::setTrafficTrackerCallback(
[](size_t size, bool incoming)
ix::WebSocket::setTrafficTrackerCallback([](size_t size, bool incoming) {
if (incoming)
{
if (incoming)
{
incomingBytes += size;
}
else
{
outgoingBytes += size;
}
incomingBytes += size;
}
);
else
{
outgoingBytes += size;
}
});
}
void reportWebSocketTraffic()
@ -61,8 +58,7 @@ namespace ix
{
auto now = std::chrono::system_clock::now();
auto seconds =
std::chrono::duration_cast<std::chrono::seconds>(
now.time_since_epoch()).count();
std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
return std::to_string(seconds);
}
@ -72,18 +68,15 @@ namespace ix
Logger() << msg;
}
void hexDump(const std::string& prefix,
const std::string& s)
void hexDump(const std::string& prefix, const std::string& s)
{
std::ostringstream ss;
bool upper_case = false;
for (std::string::size_type i = 0; i < s.length(); ++i)
{
ss << std::hex
<< std::setfill('0')
<< std::setw(2)
<< (upper_case ? std::uppercase : std::nouppercase) << (int)s[i];
ss << std::hex << std::setfill('0') << std::setw(2)
<< (upper_case ? std::uppercase : std::nouppercase) << (int) s[i];
}
std::cout << prefix << ": " << s << " => " << ss.str() << std::endl;
@ -91,41 +84,36 @@ namespace ix
bool startWebSocketEchoServer(ix::WebSocketServer& server)
{
server.setOnConnectionCallback(
[&server](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
{
webSocket->setOnMessageCallback(
[webSocket, connectionState, &server](const ix::WebSocketMessagePtr& msg)
server.setOnConnectionCallback([&server](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState) {
webSocket->setOnMessageCallback(
[webSocket, connectionState, &server](const ix::WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Open)
{
if (msg->type == ix::WebSocketMessageType::Open)
Logger() << "New connection";
Logger() << "Uri: " << msg->openInfo.uri;
Logger() << "Headers:";
for (auto it : msg->openInfo.headers)
{
Logger() << "New connection";
Logger() << "Uri: " << msg->openInfo.uri;
Logger() << "Headers:";
for (auto it : msg->openInfo.headers)
{
Logger() << it.first << ": " << it.second;
}
Logger() << it.first << ": " << it.second;
}
else if (msg->type == ix::WebSocketMessageType::Close)
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
Logger() << "Closed connection";
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
for (auto&& client : server.getClients())
{
Logger() << "Closed connection";
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
for (auto&& client : server.getClients())
if (client != webSocket)
{
if (client != webSocket)
{
client->send(msg->str, msg->binary);
}
client->send(msg->str, msg->binary);
}
}
}
);
}
);
});
});
auto res = server.listen();
if (!res.first)
@ -150,7 +138,7 @@ namespace ix
file.seekg(0, file.beg);
memblock.resize((size_t) size);
file.read((char*)&memblock.front(), static_cast<std::streamsize>(size));
file.read((char*) &memblock.front(), static_cast<std::streamsize>(size));
return memblock;
}
@ -190,4 +178,4 @@ namespace ix
return appConfig;
}
}
} // namespace ix

View File

@ -6,10 +6,10 @@
#pragma once
#include "IXAppConfig.h"
#include "IXGetFreePort.h"
#include <iostream>
#include <ixwebsocket/IXWebSocketServer.h>
#include "IXAppConfig.h"
#include <mutex>
#include <spdlog/spdlog.h>
#include <sstream>

View File

@ -4,6 +4,7 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include "catch.hpp"
#include <ixwebsocket/IXCancellationRequest.h>
#include <ixwebsocket/IXConnectionState.h>
#include <ixwebsocket/IXDNSLookup.h>
@ -39,8 +40,6 @@
#include <ixwebsocket/LUrlParser.h>
#include <ixwebsocket/libwshandshake.hpp>
#include "catch.hpp"
using namespace ix;
TEST_CASE("unity build", "[unity_build]")

View File

@ -4,105 +4,115 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include <iostream>
#include <ixwebsocket/IXUrlParser.h>
#include "IXTest.h"
#include "catch.hpp"
#include <iostream>
#include <ixwebsocket/IXUrlParser.h>
#include <string.h>
using namespace ix;
namespace ix
{
TEST_CASE("urlParser", "[urlParser]")
{
SECTION("http://google.com")
TEST_CASE("urlParser", "[urlParser]")
{
std::string url = "http://google.com";
std::string protocol, host, path, query;
int port;
bool res;
SECTION("http://google.com")
{
std::string url = "http://google.com";
std::string protocol, host, path, query;
int port;
bool res;
res = UrlParser::parse(url, protocol, host, path, query, port);
res = UrlParser::parse(url, protocol, host, path, query, port);
REQUIRE(res);
REQUIRE(protocol == "http");
REQUIRE(host == "google.com");
REQUIRE(path == "/");
REQUIRE(query == "");
REQUIRE(port == 80); // default port for http
REQUIRE(res);
REQUIRE(protocol == "http");
REQUIRE(host == "google.com");
REQUIRE(path == "/");
REQUIRE(query == "");
REQUIRE(port == 80); // default port for http
}
SECTION("https://google.com")
{
std::string url = "https://google.com";
std::string protocol, host, path, query;
int port;
bool res;
res = UrlParser::parse(url, protocol, host, path, query, port);
REQUIRE(res);
REQUIRE(protocol == "https");
REQUIRE(host == "google.com");
REQUIRE(path == "/");
REQUIRE(query == "");
REQUIRE(port == 443); // default port for https
}
SECTION("ws://google.com")
{
std::string url = "ws://google.com";
std::string protocol, host, path, query;
int port;
bool res;
res = UrlParser::parse(url, protocol, host, path, query, port);
REQUIRE(res);
REQUIRE(protocol == "ws");
REQUIRE(host == "google.com");
REQUIRE(path == "/");
REQUIRE(query == "");
REQUIRE(port == 80); // default port for ws
}
SECTION("wss://google.com/ws?arg=value")
{
std::string url = "wss://google.com/ws?arg=value&arg2=value2";
std::string protocol, host, path, query;
int port;
bool res;
res = UrlParser::parse(url, protocol, host, path, query, port);
REQUIRE(res);
REQUIRE(protocol == "wss");
REQUIRE(host == "google.com");
REQUIRE(path == "/ws?arg=value&arg2=value2");
REQUIRE(query == "arg=value&arg2=value2");
REQUIRE(port == 443); // default port for wss
}
SECTION("real test")
{
std::string url =
"ws://127.0.0.1:7350/"
"ws?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJleHAiOjE1NTcxNzAwNzIsInVpZCI6ImMwZmZjOGE1LTk4OTktNDAwYi1hNGU5LTJjNWM3NjFmNWQxZi"
"IsInVzbiI6InN2YmhOdlNJSmEifQ.5L8BUbpTA4XAHlSrdwhIVlrlIpRtjExepim7Yh5eEO4&status="
"true&format=protobuf";
std::string protocol, host, path, query;
int port;
bool res;
res = UrlParser::parse(url, protocol, host, path, query, port);
REQUIRE(res);
REQUIRE(protocol == "ws");
REQUIRE(host == "127.0.0.1");
REQUIRE(path ==
"/ws?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJleHAiOjE1NTcxNzAwNzIsInVpZCI6ImMwZmZjOGE1LTk4OTktNDAwYi1hNGU5LTJjNWM3NjFmNW"
"QxZiIsInVzbiI6InN2YmhOdlNJSmEifQ.5L8BUbpTA4XAHlSrdwhIVlrlIpRtjExepim7Yh5eEO4&"
"status=true&format=protobuf");
REQUIRE(query ==
"token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJleHAiOjE1NTcxNzAwNzIsInVpZCI6ImMwZmZjOGE1LTk4OTktNDAwYi1hNGU5LTJjNWM3NjFmNW"
"QxZiIsInVzbiI6InN2YmhOdlNJSmEifQ.5L8BUbpTA4XAHlSrdwhIVlrlIpRtjExepim7Yh5eEO4&"
"status=true&format=protobuf");
REQUIRE(port == 7350);
}
}
SECTION("https://google.com")
{
std::string url = "https://google.com";
std::string protocol, host, path, query;
int port;
bool res;
res = UrlParser::parse(url, protocol, host, path, query, port);
REQUIRE(res);
REQUIRE(protocol == "https");
REQUIRE(host == "google.com");
REQUIRE(path == "/");
REQUIRE(query == "");
REQUIRE(port == 443); // default port for https
}
SECTION("ws://google.com")
{
std::string url = "ws://google.com";
std::string protocol, host, path, query;
int port;
bool res;
res = UrlParser::parse(url, protocol, host, path, query, port);
REQUIRE(res);
REQUIRE(protocol == "ws");
REQUIRE(host == "google.com");
REQUIRE(path == "/");
REQUIRE(query == "");
REQUIRE(port == 80); // default port for ws
}
SECTION("wss://google.com/ws?arg=value")
{
std::string url = "wss://google.com/ws?arg=value&arg2=value2";
std::string protocol, host, path, query;
int port;
bool res;
res = UrlParser::parse(url, protocol, host, path, query, port);
REQUIRE(res);
REQUIRE(protocol == "wss");
REQUIRE(host == "google.com");
REQUIRE(path == "/ws?arg=value&arg2=value2");
REQUIRE(query == "arg=value&arg2=value2");
REQUIRE(port == 443); // default port for wss
}
SECTION("real test")
{
std::string url = "ws://127.0.0.1:7350/ws?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTcxNzAwNzIsInVpZCI6ImMwZmZjOGE1LTk4OTktNDAwYi1hNGU5LTJjNWM3NjFmNWQxZiIsInVzbiI6InN2YmhOdlNJSmEifQ.5L8BUbpTA4XAHlSrdwhIVlrlIpRtjExepim7Yh5eEO4&status=true&format=protobuf";
std::string protocol, host, path, query;
int port;
bool res;
res = UrlParser::parse(url, protocol, host, path, query, port);
REQUIRE(res);
REQUIRE(protocol == "ws");
REQUIRE(host == "127.0.0.1");
REQUIRE(path == "/ws?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTcxNzAwNzIsInVpZCI6ImMwZmZjOGE1LTk4OTktNDAwYi1hNGU5LTJjNWM3NjFmNWQxZiIsInVzbiI6InN2YmhOdlNJSmEifQ.5L8BUbpTA4XAHlSrdwhIVlrlIpRtjExepim7Yh5eEO4&status=true&format=protobuf");
REQUIRE(query == "token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTcxNzAwNzIsInVpZCI6ImMwZmZjOGE1LTk4OTktNDAwYi1hNGU5LTJjNWM3NjFmNWQxZiIsInVzbiI6InN2YmhOdlNJSmEifQ.5L8BUbpTA4XAHlSrdwhIVlrlIpRtjExepim7Yh5eEO4&status=true&format=protobuf");
REQUIRE(port == 7350);
}
}
}
} // namespace ix

View File

@ -9,17 +9,15 @@
// websocket_chat_server/broacast-server.js
//
#include "IXTest.h"
#include "catch.hpp"
#include "msgpack11.hpp"
#include <iostream>
#include <sstream>
#include <vector>
#include <mutex>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketServer.h>
#include "msgpack11.hpp"
#include "IXTest.h"
#include "catch.hpp"
#include <mutex>
#include <sstream>
#include <vector>
using msgpack11::MsgPack;
using namespace ix;
@ -28,41 +26,37 @@ namespace
{
class WebSocketChat
{
public:
WebSocketChat(const std::string& user,
const std::string& session,
int port);
public:
WebSocketChat(const std::string& user, const std::string& session, int port);
void subscribe(const std::string& channel);
void start();
void stop();
bool isReady() const;
void subscribe(const std::string& channel);
void start();
void stop();
bool isReady() const;
void sendMessage(const std::string& text);
size_t getReceivedMessagesCount() const;
const std::vector<std::string>& getReceivedMessages() const;
void sendMessage(const std::string& text);
size_t getReceivedMessagesCount() const;
const std::vector<std::string>& getReceivedMessages() const;
std::string encodeMessage(const std::string& text);
std::pair<std::string, std::string> decodeMessage(const std::string& str);
void appendMessage(const std::string& message);
std::string encodeMessage(const std::string& text);
std::pair<std::string, std::string> decodeMessage(const std::string& str);
void appendMessage(const std::string& message);
private:
std::string _user;
std::string _session;
int _port;
private:
std::string _user;
std::string _session;
int _port;
ix::WebSocket _webSocket;
ix::WebSocket _webSocket;
std::vector<std::string> _receivedMessages;
mutable std::mutex _mutex;
std::vector<std::string> _receivedMessages;
mutable std::mutex _mutex;
};
WebSocketChat::WebSocketChat(const std::string& user,
const std::string& session,
int port) :
_user(user),
_session(session),
_port(port)
WebSocketChat::WebSocketChat(const std::string& user, const std::string& session, int port)
: _user(user)
, _session(session)
, _port(port)
{
;
}
@ -100,10 +94,7 @@ namespace
std::string url;
{
std::stringstream ss;
ss << "ws://127.0.0.1:"
<< _port
<< "/"
<< _user;
ss << "ws://127.0.0.1:" << _port << "/" << _user;
url = ss.str();
}
@ -113,70 +104,61 @@ namespace
std::stringstream ss;
log(std::string("Connecting to url: ") + url);
_webSocket.setOnMessageCallback(
[this](const ix::WebSocketMessagePtr& msg)
_webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
ss << "cmd_websocket_chat: user "
<< _user
<< " Connected !";
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "cmd_websocket_chat: user "
<< _user
<< " disconnected !";
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
auto result = decodeMessage(msg->str);
ss << "cmd_websocket_chat: user " << _user << " Connected !";
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "cmd_websocket_chat: user " << _user << " disconnected !";
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
auto result = decodeMessage(msg->str);
// Our "chat" / "broacast" node.js server does not send us
// the messages we send, so we don't need to have a msg_user != user
// as we do for the satori chat example.
// Our "chat" / "broacast" node.js server does not send us
// the messages we send, so we don't need to have a msg_user != user
// as we do for the satori chat example.
// store text
appendMessage(result.second);
// store text
appendMessage(result.second);
std::string payload = result.second;
if (payload.size() > 2000)
{
payload = "<message too large>";
}
std::string payload = result.second;
if (payload.size() > 2000)
{
payload = "<message too large>";
}
ss << std::endl
<< result.first << " > " << payload
<< std::endl
<< _user << " > ";
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "cmd_websocket_chat: Error ! " << msg->errorInfo.reason;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
log("cmd_websocket_chat: received ping message");
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
log("cmd_websocket_chat: received pong message");
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
log("cmd_websocket_chat: received message fragment");
}
else
{
ss << "Unexpected ix::WebSocketMessageType";
log(ss.str());
}
});
ss << std::endl << result.first << " > " << payload << std::endl << _user << " > ";
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "cmd_websocket_chat: Error ! " << msg->errorInfo.reason;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
log("cmd_websocket_chat: received ping message");
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
log("cmd_websocket_chat: received pong message");
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
log("cmd_websocket_chat: received message fragment");
}
else
{
ss << "Unexpected ix::WebSocketMessageType";
log(ss.str());
}
});
_webSocket.start();
}
@ -211,42 +193,37 @@ namespace
bool startServer(ix::WebSocketServer& server)
{
server.setOnConnectionCallback(
[&server](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
{
webSocket->setOnMessageCallback(
[webSocket, connectionState, &server](const ix::WebSocketMessagePtr& msg)
server.setOnConnectionCallback([&server](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState) {
webSocket->setOnMessageCallback(
[webSocket, connectionState, &server](const ix::WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Open)
{
if (msg->type == ix::WebSocketMessageType::Open)
Logger() << "New connection";
Logger() << "id: " << connectionState->getId();
Logger() << "Uri: " << msg->openInfo.uri;
Logger() << "Headers:";
for (auto it : msg->openInfo.headers)
{
Logger() << "New connection";
Logger() << "id: " << connectionState->getId();
Logger() << "Uri: " << msg->openInfo.uri;
Logger() << "Headers:";
for (auto it : msg->openInfo.headers)
{
Logger() << it.first << ": " << it.second;
}
Logger() << it.first << ": " << it.second;
}
else if (msg->type == ix::WebSocketMessageType::Close)
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
log("Closed connection");
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
for (auto&& client : server.getClients())
{
log("Closed connection");
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
for (auto&& client : server.getClients())
if (client != webSocket)
{
if (client != webSocket)
{
client->sendBinary(msg->str);
}
client->sendBinary(msg->str);
}
}
}
);
}
);
});
});
auto res = server.listen();
if (!res.first)
@ -258,7 +235,7 @@ namespace
server.start();
return true;
}
}
} // namespace
TEST_CASE("Websocket_chat", "[websocket_chat]")
{
@ -305,8 +282,7 @@ TEST_CASE("Websocket_chat", "[websocket_chat]")
// Wait until all messages are received. 10s timeout
int attempts = 0;
while (chatA.getReceivedMessagesCount() != 3 ||
chatB.getReceivedMessagesCount() != 3)
while (chatA.getReceivedMessagesCount() != 3 || chatB.getReceivedMessagesCount() != 3)
{
REQUIRE(attempts++ < 10);
ix::msleep(1000);

View File

@ -4,15 +4,13 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include "IXTest.h"
#include "catch.hpp"
#include <iostream>
#include <sstream>
#include <queue>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketServer.h>
#include "IXTest.h"
#include "catch.hpp"
#include <queue>
#include <sstream>
using namespace ix;
@ -20,30 +18,30 @@ namespace
{
class WebSocketClient
{
public:
WebSocketClient(int port);
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 subscribe(const std::string& channel);
void start();
void stop();
void stop(uint16_t code, const std::string& reason);
bool isReady() const;
uint16_t getCloseCode();
const std::string& getCloseReason();
bool getCloseRemote();
uint16_t getCloseCode();
const std::string& getCloseReason();
bool getCloseRemote();
bool hasConnectionError() const;
bool hasConnectionError() const;
private:
ix::WebSocket _webSocket;
int _port;
private:
ix::WebSocket _webSocket;
int _port;
mutable std::mutex _mutexCloseData;
uint16_t _closeCode;
std::string _closeReason;
bool _closeRemote;
std::atomic<bool> _connectionError;
mutable std::mutex _mutexCloseData;
uint16_t _closeCode;
std::string _closeReason;
bool _closeRemote;
std::atomic<bool> _connectionError;
};
WebSocketClient::WebSocketClient(int port)
@ -102,9 +100,7 @@ namespace
std::string url;
{
std::stringstream ss;
ss << "ws://localhost:"
<< _port
<< "/";
ss << "ws://localhost:" << _port << "/";
url = ss.str();
}
@ -115,57 +111,52 @@ namespace
std::stringstream ss;
log(std::string("Connecting to url: ") + url);
_webSocket.setOnMessageCallback(
[this](const ix::WebSocketMessagePtr& msg)
_webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
log("client connected");
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
log("client connected");
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
std::stringstream ss;
ss << "client disconnected("
<< msg->closeInfo.code
<< ","
<< msg->closeInfo.reason
<< ")";
log(ss.str());
ss << "client disconnected(" << msg->closeInfo.code << "," << msg->closeInfo.reason
<< ")";
log(ss.str());
std::lock_guard<std::mutex> lck(_mutexCloseData);
std::lock_guard<std::mutex> lck(_mutexCloseData);
_closeCode = msg->closeInfo.code;
_closeReason = std::string(msg->closeInfo.reason);
_closeRemote = msg->closeInfo.remote;
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
_connectionError = true;
ss << "Error ! " << msg->errorInfo.reason;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
ss << "Received pong message " << msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
ss << "Received ping message " << msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
ss << "Received message " << msg->str;
log(ss.str());
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
_closeCode = msg->closeInfo.code;
_closeReason = std::string(msg->closeInfo.reason);
_closeRemote = msg->closeInfo.remote;
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
_connectionError = true;
ss << "Error ! " << msg->errorInfo.reason;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
ss << "Received pong message " << msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
ss << "Received ping message " << msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
ss << "Received message " << msg->str;
log(ss.str());
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
_webSocket.start();
}
@ -178,43 +169,41 @@ namespace
{
// A dev/null server
server.setOnConnectionCallback(
[&receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
{
webSocket->setOnMessageCallback(
[webSocket, connectionState, &receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](const ix::WebSocketMessagePtr& msg)
[&receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](
std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState) {
webSocket->setOnMessageCallback([webSocket,
connectionState,
&receivedCloseCode,
&receivedCloseReason,
&receivedCloseRemote,
&mutexWrite](const ix::WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Open)
{
if (msg->type == ix::WebSocketMessageType::Open)
Logger() << "New server connection";
Logger() << "id: " << connectionState->getId();
Logger() << "Uri: " << msg->openInfo.uri;
Logger() << "Headers:";
for (auto it : msg->openInfo.headers)
{
Logger() << "New server connection";
Logger() << "id: " << connectionState->getId();
Logger() << "Uri: " << msg->openInfo.uri;
Logger() << "Headers:";
for (auto it : msg->openInfo.headers)
{
Logger() << it.first << ": " << it.second;
}
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
std::stringstream ss;
ss << "Server closed connection("
<< msg->closeInfo.code
<< ","
<< msg->closeInfo.reason
<< ")";
log(ss.str());
std::lock_guard<std::mutex> lck(mutexWrite);
receivedCloseCode = msg->closeInfo.code;
receivedCloseReason = std::string(msg->closeInfo.reason);
receivedCloseRemote = msg->closeInfo.remote;
Logger() << it.first << ": " << it.second;
}
}
);
}
);
else if (msg->type == ix::WebSocketMessageType::Close)
{
std::stringstream ss;
ss << "Server closed connection(" << msg->closeInfo.code << ","
<< msg->closeInfo.reason << ")";
log(ss.str());
std::lock_guard<std::mutex> lck(mutexWrite);
receivedCloseCode = msg->closeInfo.code;
receivedCloseReason = std::string(msg->closeInfo.reason);
receivedCloseRemote = msg->closeInfo.remote;
}
});
});
auto res = server.listen();
if (!res.first)
@ -226,7 +215,7 @@ namespace
server.start();
return true;
}
}
} // namespace
TEST_CASE("Websocket_client_close_default", "[close]")
{
@ -242,7 +231,11 @@ TEST_CASE("Websocket_client_close_default", "[close]")
std::string serverReceivedCloseReason("");
std::mutex mutexWrite;
REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite));
REQUIRE(startServer(server,
serverReceivedCloseCode,
serverReceivedCloseReason,
serverReceivedCloseRemote,
mutexWrite));
std::string session = ix::generateSessionId();
WebSocketClient webSocketClient(port);
@ -301,7 +294,11 @@ TEST_CASE("Websocket_client_close_params_given", "[close]")
std::string serverReceivedCloseReason("");
std::mutex mutexWrite;
REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite));
REQUIRE(startServer(server,
serverReceivedCloseCode,
serverReceivedCloseReason,
serverReceivedCloseRemote,
mutexWrite));
std::string session = ix::generateSessionId();
WebSocketClient webSocketClient(port);
@ -359,7 +356,11 @@ TEST_CASE("Websocket_server_close", "[close]")
std::string serverReceivedCloseReason("");
std::mutex mutexWrite;
REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite));
REQUIRE(startServer(server,
serverReceivedCloseCode,
serverReceivedCloseReason,
serverReceivedCloseRemote,
mutexWrite));
std::string session = ix::generateSessionId();
WebSocketClient webSocketClient(port);
@ -417,7 +418,11 @@ TEST_CASE("Websocket_server_close_immediatly", "[close]")
std::string serverReceivedCloseReason("");
std::mutex mutexWrite;
REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite));
REQUIRE(startServer(server,
serverReceivedCloseCode,
serverReceivedCloseReason,
serverReceivedCloseRemote,
mutexWrite));
std::string session = ix::generateSessionId();
WebSocketClient webSocketClient(port);

View File

@ -4,12 +4,11 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketServer.h>
#include <ixwebsocket/IXWebSocketMessageQueue.h>
#include "IXTest.h"
#include "catch.hpp"
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketMessageQueue.h>
#include <ixwebsocket/IXWebSocketServer.h>
#include <thread>
using namespace ix;
@ -18,42 +17,37 @@ namespace
{
bool startServer(ix::WebSocketServer& server)
{
server.setOnConnectionCallback(
[&server](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
{
server.setOnConnectionCallback([&server](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState) {
webSocket->setOnMessageCallback(
[connectionState, &server](const WebSocketMessagePtr& msg)
{
if (msg->type == ix::WebSocketMessageType::Open)
{
Logger() << "New connection";
connectionState->computeId();
Logger() << "id: " << connectionState->getId();
Logger() << "Uri: " << msg->openInfo.uri;
Logger() << "Headers:";
for (auto&& it : msg->openInfo.headers)
[connectionState, &server](const WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Open)
{
Logger() << it.first << ": " << it.second;
Logger() << "New connection";
connectionState->computeId();
Logger() << "id: " << connectionState->getId();
Logger() << "Uri: " << msg->openInfo.uri;
Logger() << "Headers:";
for (auto&& it : msg->openInfo.headers)
{
Logger() << it.first << ": " << it.second;
}
}
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
Logger() << "Closed connection";
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
Logger() << "Message received: " << msg->str;
else if (msg->type == ix::WebSocketMessageType::Close)
{
Logger() << "Closed connection";
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
Logger() << "Message received: " << msg->str;
for (auto&& client : server.getClients())
{
client->send(msg->str);
for (auto&& client : server.getClients())
{
client->send(msg->str);
}
}
}
}
);
}
);
});
});
auto res = server.listen();
if (!res.first)
@ -73,8 +67,7 @@ namespace
{
msgQ.bindWebsocket(&ws);
msgQ.setOnMessageCallback([this](const WebSocketMessagePtr& msg)
{
msgQ.setOnMessageCallback([this](const WebSocketMessagePtr& msg) {
REQUIRE(mainThreadId == std::this_thread::get_id());
std::stringstream ss;
@ -153,7 +146,10 @@ namespace
}
}
bool isSucceeded() const { return succeeded; }
bool isSucceeded() const
{
return succeeded;
}
private:
WebSocket ws;
@ -163,7 +159,7 @@ namespace
std::thread::id mainThreadId;
bool succeeded = false;
};
}
} // namespace
TEST_CASE("Websocket_message_queue", "[websocket_message_q]")
{

View File

@ -4,15 +4,13 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include "IXTest.h"
#include "catch.hpp"
#include <iostream>
#include <sstream>
#include <queue>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketServer.h>
#include "IXTest.h"
#include "catch.hpp"
#include <queue>
#include <sstream>
using namespace ix;
@ -20,23 +18,23 @@ namespace
{
class WebSocketClient
{
public:
WebSocketClient(int port, bool useHeartBeatMethod);
public:
WebSocketClient(int port, bool useHeartBeatMethod);
void start();
void stop();
bool isReady() const;
void sendMessage(const std::string& text);
void start();
void stop();
bool isReady() const;
void sendMessage(const std::string& text);
private:
ix::WebSocket _webSocket;
int _port;
bool _useHeartBeatMethod;
private:
ix::WebSocket _webSocket;
int _port;
bool _useHeartBeatMethod;
};
WebSocketClient::WebSocketClient(int port, bool useHeartBeatMethod)
: _port(port),
_useHeartBeatMethod(useHeartBeatMethod)
: _port(port)
, _useHeartBeatMethod(useHeartBeatMethod)
{
;
}
@ -56,9 +54,7 @@ namespace
std::string url;
{
std::stringstream ss;
ss << "ws://127.0.0.1:"
<< _port
<< "/";
ss << "ws://127.0.0.1:" << _port << "/";
url = ss.str();
}
@ -79,48 +75,46 @@ namespace
std::stringstream ss;
log(std::string("Connecting to url: ") + url);
_webSocket.setOnMessageCallback(
[](ix::WebSocketMessageType messageType,
const std::string& str,
size_t wireSize,
const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
_webSocket.setOnMessageCallback([](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)
{
std::stringstream ss;
if (messageType == ix::WebSocketMessageType::Open)
{
log("client connected");
}
else if (messageType == ix::WebSocketMessageType::Close)
{
log("client disconnected");
}
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "Error ! " << error.reason;
log(ss.str());
}
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)
{
// too many messages to log
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
log("client connected");
}
else if (messageType == ix::WebSocketMessageType::Close)
{
log("client disconnected");
}
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "Error ! " << error.reason;
log(ss.str());
}
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)
{
// too many messages to log
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
_webSocket.start();
}
@ -135,16 +129,15 @@ namespace
// A dev/null server
server.setOnConnectionCallback(
[&server, &receivedPingMessages](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
{
std::shared_ptr<ConnectionState> connectionState) {
webSocket->setOnMessageCallback(
[webSocket, connectionState, &server, &receivedPingMessages](ix::WebSocketMessageType messageType,
const std::string& str,
size_t wireSize,
const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
[webSocket, connectionState, &server, &receivedPingMessages](
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";
@ -168,15 +161,13 @@ namespace
else if (messageType == ix::WebSocketMessageType::Message)
{
// to many messages to log
for(auto client: server.getClients())
for (auto client : server.getClients())
{
client->sendText("reply");
}
}
}
);
}
);
});
});
auto res = server.listen();
if (!res.first)
@ -188,7 +179,7 @@ namespace
server.start();
return true;
}
}
} // namespace
TEST_CASE("Websocket_ping_no_data_sent_setPingInterval", "[setPingInterval]")
{
@ -282,7 +273,8 @@ TEST_CASE("Websocket_ping_data_sent_setPingInterval", "[setPingInterval]")
TEST_CASE("Websocket_ping_data_sent_setPingInterval_half_full", "[setPingInterval]")
{
SECTION("Make sure that ping messages are sent, even if other messages are sent continuously during a given time")
SECTION("Make sure that ping messages are sent, even if other messages are sent continuously "
"during a given time")
{
ix::setupWebSocketTrafficTrackerCallback();
@ -309,7 +301,7 @@ TEST_CASE("Websocket_ping_data_sent_setPingInterval_half_full", "[setPingInterva
// send continuously for 1100ms
auto now = std::chrono::steady_clock::now();
while(std::chrono::steady_clock::now() - now <= std::chrono::milliseconds(900))
while (std::chrono::steady_clock::now() - now <= std::chrono::milliseconds(900))
{
webSocketClient.sendMessage("message");
ix::msleep(1);
@ -335,7 +327,8 @@ TEST_CASE("Websocket_ping_data_sent_setPingInterval_half_full", "[setPingInterva
TEST_CASE("Websocket_ping_data_sent_setPingInterval_full", "[setPingInterval]")
{
SECTION("Make sure that ping messages are sent, even if other messages are sent continuously for longer than ping interval")
SECTION("Make sure that ping messages are sent, even if other messages are sent continuously "
"for longer than ping interval")
{
ix::setupWebSocketTrafficTrackerCallback();
@ -362,7 +355,7 @@ TEST_CASE("Websocket_ping_data_sent_setPingInterval_full", "[setPingInterval]")
// send continuously for 1100ms
auto now = std::chrono::steady_clock::now();
while(std::chrono::steady_clock::now() - now <= std::chrono::milliseconds(1100))
while (std::chrono::steady_clock::now() - now <= std::chrono::milliseconds(1100))
{
webSocketClient.sendMessage("message");
ix::msleep(1);

View File

@ -4,15 +4,13 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include "IXTest.h"
#include "catch.hpp"
#include <iostream>
#include <sstream>
#include <queue>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketServer.h>
#include "IXTest.h"
#include "catch.hpp"
#include <queue>
#include <sstream>
using namespace ix;
@ -20,32 +18,32 @@ namespace
{
class WebSocketClient
{
public:
WebSocketClient(int port, int pingInterval, int pingTimeout);
public:
WebSocketClient(int port, int pingInterval, int pingTimeout);
void start();
void stop();
bool isReady() const;
bool isClosed() const;
void sendMessage(const std::string& text);
int getReceivedPongMessages();
bool closedDueToPingTimeout();
void start();
void stop();
bool isReady() const;
bool isClosed() const;
void sendMessage(const std::string& text);
int getReceivedPongMessages();
bool closedDueToPingTimeout();
private:
ix::WebSocket _webSocket;
int _port;
int _pingInterval;
int _pingTimeout;
std::atomic<int> _receivedPongMessages;
std::atomic<bool> _closedDueToPingTimeout;
private:
ix::WebSocket _webSocket;
int _port;
int _pingInterval;
int _pingTimeout;
std::atomic<int> _receivedPongMessages;
std::atomic<bool> _closedDueToPingTimeout;
};
WebSocketClient::WebSocketClient(int port, int pingInterval, int pingTimeout)
: _port(port),
_receivedPongMessages(0),
_closedDueToPingTimeout(false),
_pingInterval(pingInterval),
_pingTimeout(pingTimeout)
: _port(port)
, _receivedPongMessages(0)
, _closedDueToPingTimeout(false)
, _pingInterval(pingInterval)
, _pingTimeout(pingTimeout)
{
;
}
@ -70,9 +68,7 @@ namespace
std::string url;
{
std::stringstream ss;
ss << "ws://127.0.0.1:"
<< _port
<< "/";
ss << "ws://127.0.0.1:" << _port << "/";
url = ss.str();
}
@ -88,58 +84,54 @@ namespace
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)
_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)
{
std::stringstream ss;
if (messageType == ix::WebSocketMessageType::Open)
{
log("client connected");
log("client connected");
}
else if (messageType == ix::WebSocketMessageType::Close)
{
log("client disconnected");
}
else if (messageType == ix::WebSocketMessageType::Close)
if (msg->closeInfo.code == 1011)
{
log("client disconnected");
_closedDueToPingTimeout = true;
}
}
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "Error ! " << error.reason;
log(ss.str());
}
else if (messageType == ix::WebSocketMessageType::Pong)
{
_receivedPongMessages++;
if (msg->closeInfo.code == 1011)
{
_closedDueToPingTimeout = true;
}
}
else if (messageType == ix::WebSocketMessageType::Error)
{
ss << "Error ! " << error.reason;
log(ss.str());
}
else if (messageType == ix::WebSocketMessageType::Pong)
{
_receivedPongMessages++;
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());
}
});
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();
}
@ -159,21 +151,22 @@ namespace
return _closedDueToPingTimeout;
}
bool startServer(ix::WebSocketServer& server, std::atomic<int>& receivedPingMessages, bool enablePong)
bool startServer(ix::WebSocketServer& server,
std::atomic<int>& receivedPingMessages,
bool enablePong)
{
// A dev/null server
server.setOnConnectionCallback(
[&server, &receivedPingMessages](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
{
std::shared_ptr<ConnectionState> connectionState) {
webSocket->setOnMessageCallback(
[webSocket, connectionState, &server, &receivedPingMessages](ix::WebSocketMessageType messageType,
const std::string& str,
size_t wireSize,
const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo)
{
[webSocket, connectionState, &server, &receivedPingMessages](
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";
@ -194,10 +187,8 @@ namespace
log("Server received a ping");
receivedPingMessages++;
}
}
);
}
);
});
});
if (!enablePong)
{
@ -215,7 +206,7 @@ namespace
server.start();
return true;
}
}
} // namespace
TEST_CASE("Websocket_ping_timeout_not_checked", "[setPingTimeout]")
{
@ -336,7 +327,7 @@ TEST_CASE("Websocket_no_ping_but_timeout", "[setPingTimeout]")
REQUIRE(startServer(server, serverReceivedPingMessages, enablePong));
std::string session = ix::generateSessionId();
int pingIntervalSecs = -1; // no ping set
int pingIntervalSecs = -1; // no ping set
int pingTimeoutSecs = 3;
WebSocketClient webSocketClient(port, pingIntervalSecs, pingTimeoutSecs);
webSocketClient.start();

View File

@ -4,15 +4,13 @@
* Copyright (c) 2019 Machine Zone. All rights reserved.
*/
#include "IXTest.h"
#include "catch.hpp"
#include <iostream>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXSocketFactory.h>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketServer.h>
#include <ixwebsocket/IXSocketFactory.h>
#include "IXTest.h"
#include "catch.hpp"
using namespace ix;
@ -28,55 +26,48 @@ namespace ix
}
};
bool startServer(ix::WebSocketServer& server,
std::string& connectionId)
bool startServer(ix::WebSocketServer& server, std::string& connectionId)
{
auto factory = []() -> std::shared_ptr<ConnectionState>
{
auto factory = []() -> std::shared_ptr<ConnectionState> {
return std::make_shared<ConnectionStateCustom>();
};
server.setConnectionStateFactory(factory);
server.setOnConnectionCallback(
[&server, &connectionId](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
{
webSocket->setOnMessageCallback(
[webSocket, connectionState,
&connectionId, &server](const ix::WebSocketMessagePtr& msg)
server.setOnConnectionCallback([&server, &connectionId](
std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState) {
webSocket->setOnMessageCallback([webSocket, connectionState, &connectionId, &server](
const ix::WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Open)
{
Logger() << "New connection";
connectionState->computeId();
Logger() << "id: " << connectionState->getId();
Logger() << "Uri: " << msg->openInfo.uri;
Logger() << "Headers:";
for (auto it : msg->openInfo.headers)
{
if (msg->type == ix::WebSocketMessageType::Open)
{
Logger() << "New connection";
connectionState->computeId();
Logger() << "id: " << connectionState->getId();
Logger() << "Uri: " << msg->openInfo.uri;
Logger() << "Headers:";
for (auto it : msg->openInfo.headers)
{
Logger() << it.first << ": " << it.second;
}
Logger() << it.first << ": " << it.second;
}
connectionId = connectionState->getId();
}
else if (msg->type == ix::WebSocketMessageType::Close)
connectionId = connectionState->getId();
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
Logger() << "Closed connection";
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
for (auto&& client : server.getClients())
{
if (client != webSocket)
{
Logger() << "Closed connection";
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
for (auto&& client : server.getClients())
{
if (client != webSocket)
{
client->send(msg->str);
}
}
client->send(msg->str);
}
}
);
}
);
}
});
});
auto res = server.listen();
if (!res.first)
@ -88,7 +79,7 @@ namespace ix
server.start();
return true;
}
}
} // namespace ix
TEST_CASE("Websocket_server", "[websocket_server]")
{
@ -103,10 +94,7 @@ TEST_CASE("Websocket_server", "[websocket_server]")
bool tls = false;
std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
std::string host("127.0.0.1");
auto isCancellationRequested = []() -> bool
{
return false;
};
auto isCancellationRequested = []() -> bool { return false; };
bool success = socket->connect(host, port, errMsg, isCancellationRequested);
REQUIRE(success);
@ -139,10 +127,7 @@ TEST_CASE("Websocket_server", "[websocket_server]")
bool tls = false;
std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
std::string host("127.0.0.1");
auto isCancellationRequested = []() -> bool
{
return false;
};
auto isCancellationRequested = []() -> bool { return false; };
bool success = socket->connect(host, port, errMsg, isCancellationRequested);
REQUIRE(success);
@ -178,10 +163,7 @@ TEST_CASE("Websocket_server", "[websocket_server]")
bool tls = false;
std::shared_ptr<Socket> socket = createSocket(tls, errMsg);
std::string host("127.0.0.1");
auto isCancellationRequested = []() -> bool
{
return false;
};
auto isCancellationRequested = []() -> bool { return false; };
bool success = socket->connect(host, port, errMsg, isCancellationRequested);
REQUIRE(success);

View File

@ -4,13 +4,12 @@
* Copyright (c) 2017 Machine Zone. All rights reserved.
*/
#include <iostream>
#include <sstream>
#include <set>
#include <ixwebsocket/IXWebSocket.h>
#include "IXTest.h"
#include "catch.hpp"
#include <iostream>
#include <ixwebsocket/IXWebSocket.h>
#include <set>
#include <sstream>
using namespace ix;
@ -19,19 +18,19 @@ namespace
const std::string WEBSOCKET_DOT_ORG_URL("wss://echo.websocket.org");
const std::string GOOGLE_URL("wss://google.com");
const std::string UNKNOWN_URL("wss://asdcasdcaasdcasdcasdcasdcasdcasdcasassdd.com");
}
} // namespace
namespace
{
class IXWebSocketTestConnectionDisconnection
{
public:
IXWebSocketTestConnectionDisconnection();
void start(const std::string& url);
void stop();
public:
IXWebSocketTestConnectionDisconnection();
void start(const std::string& url);
void stop();
private:
ix::WebSocket _webSocket;
private:
ix::WebSocket _webSocket;
};
IXWebSocketTestConnectionDisconnection::IXWebSocketTestConnectionDisconnection()
@ -51,45 +50,43 @@ namespace
std::stringstream ss;
log(std::string("Connecting to url: ") + url);
_webSocket.setOnMessageCallback(
[](const ix::WebSocketMessagePtr& msg)
_webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg) {
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
log("TestConnectionDisconnection: connected !");
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
log("TestConnectionDisconnection: disconnected !");
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "TestConnectionDisconnection: Error! ";
ss << msg->errorInfo.reason;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
log("TestConnectionDisconnection: received message.!");
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
log("TestConnectionDisconnection: received ping message.!");
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
log("TestConnectionDisconnection: received pong message.!");
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
log("TestConnectionDisconnection: received fragment.!");
}
else
{
log("Invalid ix::WebSocketMessageType");
}
});
log("TestConnectionDisconnection: connected !");
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
log("TestConnectionDisconnection: disconnected !");
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "TestConnectionDisconnection: Error! ";
ss << msg->errorInfo.reason;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
log("TestConnectionDisconnection: received message.!");
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
log("TestConnectionDisconnection: received ping message.!");
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
log("TestConnectionDisconnection: received pong message.!");
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
log("TestConnectionDisconnection: received fragment.!");
}
else
{
log("Invalid ix::WebSocketMessageType");
}
});
_webSocket.enableAutomaticReconnection();
REQUIRE(_webSocket.isAutomaticReconnectionEnabled() == true);
@ -100,11 +97,12 @@ namespace
// Start the connection
_webSocket.start();
}
}
} // namespace
//
// We try to connect to different servers, and make sure there are no crashes.
// FIXME: We could do more checks (make sure that we were not able to connect to unknown servers, etc...)
// FIXME: We could do more checks (make sure that we were not able to connect to unknown servers,
// etc...)
//
TEST_CASE("websocket_connections", "[websocket]")
{
@ -121,7 +119,8 @@ TEST_CASE("websocket_connections", "[websocket]")
test.stop();
}
SECTION("Try to connect and disconnect with different timing, not enough time to succesfully connect")
SECTION("Try to connect and disconnect with different timing, not enough time to succesfully "
"connect")
{
IXWebSocketTestConnectionDisconnection test;
log(std::string("50 Runs"));
@ -141,7 +140,8 @@ TEST_CASE("websocket_connections", "[websocket]")
// 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")
SECTION("Try to connect and disconnect with different timing, from not enough time to "
"successfull connect")
{
IXWebSocketTestConnectionDisconnection test;
log(std::string("20 Runs"));
@ -152,7 +152,7 @@ TEST_CASE("websocket_connections", "[websocket]")
test.start(WEBSOCKET_DOT_ORG_URL);
log(std::string("Sleeping"));
ix::msleep(i*50);
ix::msleep(i * 50);
log(std::string("Stopping"));
test.stop();

View File

@ -6,20 +6,15 @@
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
#include <spdlog/spdlog.h>
#include <ixwebsocket/IXNetSystem.h>
#include <ixcore/utils/IXCoreLogger.h>
#include <ixwebsocket/IXNetSystem.h>
#include <spdlog/spdlog.h>
int main(int argc, char* argv[])
{
ix::initNetSystem();
ix::IXCoreLogger::LogFunc logFunc = [](const char* msg)
{
spdlog::info(msg);
};
ix::IXCoreLogger::LogFunc logFunc = [](const char* msg) { spdlog::info(msg); };
ix::IXCoreLogger::setLogFunction(logFunc);
int result = Catch::Session().run(argc, argv);

View File

@ -5,14 +5,14 @@
*/
#include "IXRedisClient.h"
#include <ixwebsocket/IXSocketFactory.h>
#include <ixwebsocket/IXSocket.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXSocketFactory.h>
#include <sstream>
#include <vector>
namespace ix
{
@ -31,8 +31,7 @@ namespace ix
return _socket->connect(hostname, port, errMsg, nullptr);
}
bool RedisClient::auth(const std::string& password,
std::string& response)
bool RedisClient::auth(const std::string& password, std::string& response)
{
response.clear();
@ -203,7 +202,7 @@ namespace ix
int arraySize;
{
std::stringstream ss;
ss << line.substr(1, line.size()-1);
ss << line.substr(1, line.size() - 1);
ss >> arraySize;
}
@ -220,7 +219,7 @@ namespace ix
// => $7 (7 bytes)
int stringSize;
std::stringstream ss;
ss << line.substr(1, line.size()-1);
ss << line.substr(1, line.size() - 1);
ss >> stringSize;
auto readResult = _socket->readBytes(stringSize, nullptr, nullptr);
@ -246,4 +245,4 @@ namespace ix
{
_stop = true;
}
}
} // namespace ix

View File

@ -6,9 +6,9 @@
#pragma once
#include <atomic>
#include <functional>
#include <memory>
#include <atomic>
namespace ix
{
@ -20,7 +20,10 @@ namespace ix
using OnRedisSubscribeResponseCallback = std::function<void(const std::string&)>;
using OnRedisSubscribeCallback = std::function<void(const std::string&)>;
RedisClient() : _stop(false) {}
RedisClient()
: _stop(false)
{
}
~RedisClient() = default;
bool connect(const std::string& hostname, int port);

View File

@ -8,17 +8,16 @@
#include <chrono>
#include <iostream>
#include <spdlog/spdlog.h>
#include <ixwebsocket/IXWebSocketHttpHeaders.h>
#include <spdlog/spdlog.h>
namespace ix
{
SentryClient::SentryClient(const std::string& dsn) :
_dsn(dsn),
_validDsn(false),
_luaFrameRegex("\t([^/]+):([0-9]+): in function '([^/]+)'")
SentryClient::SentryClient(const std::string& dsn)
: _dsn(dsn)
, _validDsn(false)
, _luaFrameRegex("\t([^/]+):([0-9]+): in function '([^/]+)'")
{
const std::regex dsnRegex("(http[s]?)://([^:]+):([^@]+)@([^/]+)/([0-9]+)");
std::smatch group;
@ -168,8 +167,7 @@ namespace ix
return _jsonWriter.write(payload);
}
std::pair<HttpResponsePtr, std::string> SentryClient::send(const Json::Value& msg,
bool verbose)
std::pair<HttpResponsePtr, std::string> SentryClient::send(const Json::Value& msg, bool verbose)
{
auto args = _httpClient.createRequest();
args->extraHeaders["X-Sentry-Auth"] = SentryClient::computeAuthHeader();
@ -177,10 +175,7 @@ namespace ix
args->transferTimeout = 5 * 60;
args->followRedirects = true;
args->verbose = verbose;
args->logger = [](const std::string& msg)
{
spdlog::info("request logger: {}", msg);
};
args->logger = [](const std::string& msg) { spdlog::info("request logger: {}", msg); };
std::string body = computePayload(msg);
HttpResponsePtr response = _httpClient.post(_url, body, args);

View File

@ -4,24 +4,20 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include "IXSnakeProtocol.h"
#include "IXAppConfig.h"
#include "IXSnakeProtocol.h"
#include <iostream>
#include <ixcrypto/IXUuid.h>
namespace snake
{
bool isAppKeyValid(
const AppConfig& appConfig,
std::string appkey)
bool isAppKeyValid(const AppConfig& appConfig, std::string appkey)
{
return appConfig.apps.count(appkey) != 0;
}
std::string getRoleSecret(
const AppConfig& appConfig,
std::string appkey,
std::string role)
std::string getRoleSecret(const AppConfig& appConfig, std::string appkey, std::string role)
{
if (!isAppKeyValid(appConfig, appkey))
{
@ -49,4 +45,4 @@ namespace snake
std::cout << "redis password: " << appConfig.redisPassword << std::endl;
std::cout << "redis port: " << appConfig.redisPort << std::endl;
}
}
} // namespace snake

View File

@ -16,16 +16,37 @@ namespace snake
class SnakeConnectionState : public ix::ConnectionState
{
public:
std::string getNonce() { return _nonce; }
void setNonce(const std::string& nonce) { _nonce = nonce; }
std::string getNonce()
{
return _nonce;
}
void setNonce(const std::string& nonce)
{
_nonce = nonce;
}
std::string appkey() { return _appkey; }
void setAppkey(const std::string& appkey) { _appkey = appkey; }
std::string appkey()
{
return _appkey;
}
void setAppkey(const std::string& appkey)
{
_appkey = appkey;
}
std::string role() { return _role; }
void setRole(const std::string& role) { _role = role; }
std::string role()
{
return _role;
}
void setRole(const std::string& role)
{
_role = role;
}
ix::RedisClient& redisClient() { return _redisClient; }
ix::RedisClient& redisClient()
{
return _redisClient;
}
std::future<void> fut;

View File

@ -6,41 +6,32 @@
#include "IXSnakeProtocol.h"
#include <ixwebsocket/IXWebSocket.h>
#include <ixcrypto/IXHMac.h>
#include "IXSnakeConnectionState.h"
#include "IXAppConfig.h"
#include "IXSnakeConnectionState.h"
#include "nlohmann/json.hpp"
#include <sstream>
#include <iostream>
#include <ixcrypto/IXHMac.h>
#include <ixwebsocket/IXWebSocket.h>
#include <sstream>
namespace snake
{
void handleError(
const std::string& action,
std::shared_ptr<ix::WebSocket> ws,
nlohmann::json pdu,
const std::string& errMsg)
void handleError(const std::string& action,
std::shared_ptr<ix::WebSocket> ws,
nlohmann::json pdu,
const std::string& errMsg)
{
std::string actionError(action);
actionError += "/error";
nlohmann::json response = {
{"action", actionError},
{"id", pdu.value("id", 1)},
{"body", {
{"reason", errMsg}
}}
};
{"action", actionError}, {"id", pdu.value("id", 1)}, {"body", {{"reason", errMsg}}}};
ws->sendText(response.dump());
}
void handleHandshake(
std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const nlohmann::json& pdu)
void handleHandshake(std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const nlohmann::json& pdu)
{
std::string role = pdu["body"]["data"]["role"];
@ -50,13 +41,10 @@ namespace snake
nlohmann::json response = {
{"action", "auth/handshake/ok"},
{"id", pdu.value("id", 1)},
{"body", {
{"data", {
{"nonce", state->getNonce()},
{"connection_id", state->getId()}
}},
}}
};
{"body",
{
{"data", {{"nonce", state->getNonce()}, {"connection_id", state->getId()}}},
}}};
auto serializedResponse = response.dump();
std::cout << "response = " << serializedResponse << std::endl;
@ -64,11 +52,10 @@ namespace snake
ws->sendText(serializedResponse);
}
void handleAuth(
std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const AppConfig& appConfig,
const nlohmann::json& pdu)
void handleAuth(std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const AppConfig& appConfig,
const nlohmann::json& pdu)
{
auto secret = getRoleSecret(appConfig, state->appkey(), state->role());
std::cout << "secret = " << secret << std::endl;
@ -78,11 +65,7 @@ namespace snake
nlohmann::json response = {
{"action", "auth/authenticate/error"},
{"id", pdu.value("id", 1)},
{"body", {
{"error", "authentication_failed"},
{"reason", "invalid secret"}
}}
};
{"body", {{"error", "authentication_failed"}, {"reason", "invalid secret"}}}};
ws->sendText(response.dump());
return;
}
@ -102,28 +85,20 @@ namespace snake
nlohmann::json response = {
{"action", "auth/authenticate/error"},
{"id", pdu.value("id", 1)},
{"body", {
{"error", "authentication_failed"},
{"reason", "invalid hash"}
}}
};
{"body", {{"error", "authentication_failed"}, {"reason", "invalid hash"}}}};
ws->sendText(response.dump());
return;
}
nlohmann::json response = {
{"action", "auth/authenticate/ok"},
{"id", pdu.value("id", 1)},
{"body", {}}
};
{"action", "auth/authenticate/ok"}, {"id", pdu.value("id", 1)}, {"body", {}}};
ws->sendText(response.dump());
}
void handlePublish(
std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const nlohmann::json& pdu)
void handlePublish(std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const nlohmann::json& pdu)
{
std::vector<std::string> channels;
@ -150,9 +125,7 @@ namespace snake
for (auto&& channel : channels)
{
std::stringstream ss;
ss << state->appkey()
<< "::"
<< channel;
ss << state->appkey() << "::" << channel;
std::string errMsg;
if (!state->redisClient().publish(ss.str(), pdu.dump(), errMsg))
@ -165,10 +138,7 @@ namespace snake
}
nlohmann::json response = {
{"action", "rtm/publish/ok"},
{"id", pdu.value("id", 1)},
{"body", {}}
};
{"action", "rtm/publish/ok"}, {"id", pdu.value("id", 1)}, {"body", {}}};
ws->sendText(response.dump());
}
@ -176,19 +146,16 @@ namespace snake
//
// FIXME: this is not cancellable. We should be able to cancel the redis subscription
//
void handleRedisSubscription(
std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const AppConfig& appConfig,
const nlohmann::json& pdu)
void handleRedisSubscription(std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const AppConfig& appConfig,
const nlohmann::json& pdu)
{
std::string channel = pdu["body"]["channel"];
std::string subscriptionId = channel;
std::stringstream ss;
ss << state->appkey()
<< "::"
<< channel;
ss << state->appkey() << "::" << channel;
std::string appChannel(ss.str());
@ -224,8 +191,7 @@ namespace snake
}
int id = 0;
auto callback = [ws, &id, &subscriptionId](const std::string& messageStr)
{
auto callback = [ws, &id, &subscriptionId](const std::string& messageStr) {
auto msg = nlohmann::json::parse(messageStr);
msg = msg["body"]["message"];
@ -233,27 +199,18 @@ namespace snake
nlohmann::json response = {
{"action", "rtm/subscription/data"},
{"id", id++},
{"body", {
{"subscription_id", subscriptionId},
{"messages", {msg}}
}}
};
{"body", {{"subscription_id", subscriptionId}, {"messages", {msg}}}}};
ws->sendText(response.dump());
};
auto responseCallback = [ws, pdu, &subscriptionId](const std::string& redisResponse)
{
auto responseCallback = [ws, pdu, &subscriptionId](const std::string& redisResponse) {
std::cout << "Redis subscribe response: " << redisResponse << std::endl;
// Success
nlohmann::json response = {
{"action", "rtm/subscribe/ok"},
{"id", pdu.value("id", 1)},
{"body", {
{"subscription_id", subscriptionId}
}}
};
nlohmann::json response = {{"action", "rtm/subscribe/ok"},
{"id", pdu.value("id", 1)},
{"body", {{"subscription_id", subscriptionId}}}};
ws->sendText(response.dump());
};
@ -267,24 +224,18 @@ namespace snake
}
}
void handleSubscribe(
std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const AppConfig& appConfig,
const nlohmann::json& pdu)
void handleSubscribe(std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const AppConfig& appConfig,
const nlohmann::json& pdu)
{
state->fut = std::async(std::launch::async,
handleRedisSubscription,
state,
ws,
appConfig,
pdu);
state->fut =
std::async(std::launch::async, handleRedisSubscription, state, ws, appConfig, pdu);
}
void handleUnSubscribe(
std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const nlohmann::json& pdu)
void handleUnSubscribe(std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const nlohmann::json& pdu)
{
// extract subscription_id
auto body = pdu["body"];
@ -292,21 +243,16 @@ namespace snake
state->redisClient().stop();
nlohmann::json response = {
{"action", "rtm/unsubscribe/ok"},
{"id", pdu.value("id", 1)},
{"body", {
{"subscription_id", subscriptionId}
}}
};
nlohmann::json response = {{"action", "rtm/unsubscribe/ok"},
{"id", pdu.value("id", 1)},
{"body", {{"subscription_id", subscriptionId}}}};
ws->sendText(response.dump());
}
void processCobraMessage(
std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const AppConfig& appConfig,
const std::string& str)
void processCobraMessage(std::shared_ptr<SnakeConnectionState> state,
std::shared_ptr<ix::WebSocket> ws,
const AppConfig& appConfig,
const std::string& str)
{
auto pdu = nlohmann::json::parse(str);
std::cout << "Got " << str << std::endl;
@ -339,4 +285,4 @@ namespace snake
std::cerr << "Unhandled action: " << action << std::endl;
}
}
}
} // namespace snake

View File

@ -5,18 +5,18 @@
*/
#include "IXSnakeServer.h"
#include "IXSnakeProtocol.h"
#include "IXSnakeConnectionState.h"
#include "IXAppConfig.h"
#include "IXAppConfig.h"
#include "IXSnakeConnectionState.h"
#include "IXSnakeProtocol.h"
#include <iostream>
#include <sstream>
namespace snake
{
SnakeServer::SnakeServer(const AppConfig& appConfig) :
_appConfig(appConfig),
_server(appConfig.port, appConfig.hostname)
SnakeServer::SnakeServer(const AppConfig& appConfig)
: _appConfig(appConfig)
, _server(appConfig.port, appConfig.hostname)
{
;
}
@ -32,7 +32,7 @@ namespace snake
idx = path.rfind('=');
if (idx != std::string::npos)
{
std::string appkey = path.substr(idx+1);
std::string appkey = path.substr(idx + 1);
return appkey;
}
else
@ -45,21 +45,18 @@ namespace snake
{
std::cout << "Listening on " << _appConfig.hostname << ":" << _appConfig.port << std::endl;
auto factory = []() -> std::shared_ptr<ix::ConnectionState>
{
auto factory = []() -> std::shared_ptr<ix::ConnectionState> {
return std::make_shared<SnakeConnectionState>();
};
_server.setConnectionStateFactory(factory);
_server.setOnConnectionCallback(
[this](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ix::ConnectionState> connectionState)
{
std::shared_ptr<ix::ConnectionState> connectionState) {
auto state = std::dynamic_pointer_cast<SnakeConnectionState>(connectionState);
webSocket->setOnMessageCallback(
[this, webSocket, state](const ix::WebSocketMessagePtr& msg)
{
[this, webSocket, state](const ix::WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Open)
{
std::cerr << "New connection" << std::endl;
@ -84,16 +81,16 @@ namespace snake
else if (msg->type == ix::WebSocketMessageType::Close)
{
std::cerr << "Closed connection"
<< " code " << msg->closeInfo.code
<< " reason " << msg->closeInfo.reason << std::endl;
<< " code " << msg->closeInfo.code << " reason "
<< msg->closeInfo.reason << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
std::cerr << ss.str();
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
@ -105,10 +102,8 @@ namespace snake
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
processCobraMessage(state, webSocket, _appConfig, msg->str);
}
}
);
}
);
});
});
auto res = _server.listen();
if (!res.first)
@ -133,4 +128,4 @@ namespace snake
{
_server.stop();
}
}
} // namespace snake

112
ws/ws.cpp
View File

@ -9,27 +9,22 @@
//
#include "ws.h"
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <cli11/CLI11.hpp>
#include <spdlog/spdlog.h>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXNetSystem.h>
#include <fstream>
#include <iostream>
#include <ixcore/utils/IXCoreLogger.h>
#include <ixwebsocket/IXNetSystem.h>
#include <ixwebsocket/IXSocket.h>
#include <spdlog/spdlog.h>
#include <sstream>
#include <string>
int main(int argc, char** argv)
{
ix::initNetSystem();
ix::IXCoreLogger::LogFunc logFunc = [](const char* msg)
{
spdlog::info(msg);
};
ix::IXCoreLogger::LogFunc logFunc = [](const char* msg) { spdlog::info(msg); };
ix::IXCoreLogger::setLogFunction(logFunc);
// Display command.
@ -43,7 +38,7 @@ int main(int argc, char** argv)
std::cout << std::endl;
}
CLI::App app{"ws is a websocket tool"};
CLI::App app {"ws is a websocket tool"};
app.require_subcommand();
std::string url("ws://127.0.0.1:8008");
@ -94,13 +89,16 @@ int main(int argc, char** argv)
CLI::App* sendApp = app.add_subcommand("send", "Send a file");
sendApp->add_option("url", url, "Connection url")->required();
sendApp->add_option("path", path, "Path to the file to send")
->required()->check(CLI::ExistingPath);
->required()
->check(CLI::ExistingPath);
sendApp->add_option("--pidfile", pidfile, "Pid file");
CLI::App* receiveApp = app.add_subcommand("receive", "Receive a file");
receiveApp->add_option("url", url, "Connection url")->required();
receiveApp->add_option("--delay", delayMs, "Delay (ms) to wait after receiving a fragment"
" to artificially slow down the receiver");
receiveApp->add_option("--delay",
delayMs,
"Delay (ms) to wait after receiving a fragment"
" to artificially slow down the receiver");
receiveApp->add_option("--pidfile", pidfile, "Pid file");
CLI::App* transferApp = app.add_subcommand("transfer", "Broadcasting server");
@ -114,7 +112,9 @@ int main(int argc, char** argv)
connectApp->add_flag("-d", disableAutomaticReconnection, "Disable Automatic Reconnection");
connectApp->add_flag("-x", disablePerMessageDeflate, "Disable per message deflate");
connectApp->add_flag("-b", binaryMode, "Send in binary mode");
connectApp->add_option("--max_wait", maxWaitBetweenReconnectionRetries, "Max Wait Time between reconnection retries");
connectApp->add_option("--max_wait",
maxWaitBetweenReconnectionRetries,
"Max Wait Time between reconnection retries");
CLI::App* chatApp = app.add_subcommand("chat", "Group chat");
chatApp->add_option("url", url, "Connection url")->required();
@ -181,9 +181,11 @@ int main(int argc, char** argv)
cobraPublish->add_option("channel", channel, "Channel")->required();
cobraPublish->add_option("--pidfile", pidfile, "Pid file");
cobraPublish->add_option("path", path, "Path to the file to send")
->required()->check(CLI::ExistingPath);
->required()
->check(CLI::ExistingPath);
CLI::App* cobraMetricsPublish = app.add_subcommand("cobra_metrics_publish", "Cobra metrics publisher");
CLI::App* cobraMetricsPublish =
app.add_subcommand("cobra_metrics_publish", "Cobra metrics publisher");
cobraMetricsPublish->add_option("--appkey", appkey, "Appkey");
cobraMetricsPublish->add_option("--endpoint", endpoint, "Endpoint");
cobraMetricsPublish->add_option("--rolename", rolename, "Role name");
@ -191,7 +193,8 @@ int main(int argc, char** argv)
cobraMetricsPublish->add_option("channel", channel, "Channel")->required();
cobraMetricsPublish->add_option("--pidfile", pidfile, "Pid file");
cobraMetricsPublish->add_option("path", path, "Path to the file to send")
->required()->check(CLI::ExistingPath);
->required()
->check(CLI::ExistingPath);
cobraMetricsPublish->add_flag("--stress", stress, "Stress mode");
CLI::App* cobra2statsd = app.add_subcommand("cobra_to_statsd", "Cobra to statsd");
@ -269,8 +272,11 @@ int main(int argc, char** argv)
}
else if (app.got_subcommand("connect"))
{
ret = ix::ws_connect_main(url, headers, disableAutomaticReconnection,
disablePerMessageDeflate, binaryMode,
ret = ix::ws_connect_main(url,
headers,
disableAutomaticReconnection,
disablePerMessageDeflate,
binaryMode,
maxWaitBetweenReconnectionRetries);
}
else if (app.got_subcommand("chat"))
@ -291,15 +297,22 @@ int main(int argc, char** argv)
}
else if (app.got_subcommand("curl"))
{
ret = ix::ws_http_client_main(url, headers, data, headersOnly,
connectTimeOut, transferTimeout,
followRedirects, maxRedirects, verbose,
save, output, compress);
ret = ix::ws_http_client_main(url,
headers,
data,
headersOnly,
connectTimeOut,
transferTimeout,
followRedirects,
maxRedirects,
verbose,
save,
output,
compress);
}
else if (app.got_subcommand("redis_publish"))
{
ret = ix::ws_redis_publish_main(hostname, redisPort, password,
channel, message, count);
ret = ix::ws_redis_publish_main(hostname, redisPort, password, channel, message, count);
}
else if (app.got_subcommand("redis_subscribe"))
{
@ -307,42 +320,41 @@ int main(int argc, char** argv)
}
else if (app.got_subcommand("cobra_subscribe"))
{
ret = ix::ws_cobra_subscribe_main(appkey, endpoint,
rolename, rolesecret,
channel, filter, quiet);
ret = ix::ws_cobra_subscribe_main(
appkey, endpoint, rolename, rolesecret, channel, filter, quiet);
}
else if (app.got_subcommand("cobra_publish"))
{
ret = ix::ws_cobra_publish_main(appkey, endpoint,
rolename, rolesecret,
channel, path);
ret = ix::ws_cobra_publish_main(appkey, endpoint, rolename, rolesecret, channel, path);
}
else if (app.got_subcommand("cobra_metrics_publish"))
{
ret = ix::ws_cobra_metrics_publish_main(appkey, endpoint,
rolename, rolesecret,
channel, path, stress);
ret = ix::ws_cobra_metrics_publish_main(
appkey, endpoint, rolename, rolesecret, channel, path, stress);
}
else if (app.got_subcommand("cobra_to_statsd"))
{
ret = ix::ws_cobra_to_statsd_main(appkey, endpoint,
rolename, rolesecret,
channel, filter, hostname, statsdPort,
prefix, fields, verbose);
ret = ix::ws_cobra_to_statsd_main(appkey,
endpoint,
rolename,
rolesecret,
channel,
filter,
hostname,
statsdPort,
prefix,
fields,
verbose);
}
else if (app.got_subcommand("cobra_to_sentry"))
{
ret = ix::ws_cobra_to_sentry_main(appkey, endpoint,
rolename, rolesecret,
channel, filter, dsn,
verbose, strict, jobs);
ret = ix::ws_cobra_to_sentry_main(
appkey, endpoint, rolename, rolesecret, channel, filter, dsn, verbose, strict, jobs);
}
else if (app.got_subcommand("snake"))
{
ret = ix::ws_snake_main(port, hostname,
redisHosts, redisPort,
redisPassword, verbose,
appsConfigPath);
ret = ix::ws_snake_main(
port, hostname, redisHosts, redisPort, redisPassword, verbose, appsConfigPath);
}
else if (app.got_subcommand("httpd"))
{

View File

@ -21,7 +21,8 @@
//
//
// 2 Run the test server (using docker)
// docker run -it --rm -v "${PWD}/config:/config" -v "${PWD}/reports:/reports" -p 9001:9001 --name fuzzingserver crossbario/autobahn-testsuite
// docker run -it --rm -v "${PWD}/config:/config" -v "${PWD}/reports:/reports" -p 9001:9001 --name
// fuzzingserver crossbario/autobahn-testsuite
//
// 3. Run this command
// ws autobahn -q --url ws://localhost:9001
@ -29,15 +30,14 @@
// 4. A HTML report will be generated, you can inspect it to see if you are compliant or not
//
#include <iostream>
#include <sstream>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <ixwebsocket/IXWebSocket.h>
#include <iostream>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <mutex>
#include <spdlog/spdlog.h>
#include <sstream>
namespace
@ -53,31 +53,31 @@ namespace
return str.substr(0, n) + "...";
}
}
}
} // namespace
namespace ix
{
class AutobahnTestCase
{
public:
AutobahnTestCase(const std::string& _url, bool quiet);
void run();
public:
AutobahnTestCase(const std::string& _url, bool quiet);
void run();
private:
void log(const std::string& msg);
private:
void log(const std::string& msg);
std::string _url;
ix::WebSocket _webSocket;
std::string _url;
ix::WebSocket _webSocket;
bool _quiet;
bool _quiet;
std::mutex _mutex;
std::condition_variable _condition;
std::mutex _mutex;
std::condition_variable _condition;
};
AutobahnTestCase::AutobahnTestCase(const std::string& url, bool quiet) :
_url(url),
_quiet(quiet)
AutobahnTestCase::AutobahnTestCase(const std::string& url, bool quiet)
: _url(url)
, _quiet(quiet)
{
_webSocket.disableAutomaticReconnection();
@ -102,67 +102,63 @@ namespace ix
std::stringstream ss;
log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback(
[this](const ix::WebSocketMessagePtr& msg)
_webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
log("autobahn: connected");
ss << "Uri: " << msg->openInfo.uri << std::endl;
ss << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
log("autobahn: connected");
ss << "Uri: " << msg->openInfo.uri << std::endl;
ss << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
ss << it.first << ": " << it.second << std::endl;
}
ss << it.first << ": " << it.second << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "autobahn: connection closed:";
ss << " code " << msg->closeInfo.code;
ss << " reason " << msg->closeInfo.reason << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "autobahn: connection closed:";
ss << " code " << msg->closeInfo.code;
ss << " reason " << msg->closeInfo.reason << std::endl;
_condition.notify_one();
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
ss << "Received " << msg->wireSize << " bytes" << std::endl;
_condition.notify_one();
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
ss << "Received " << msg->wireSize << " bytes" << std::endl;
ss << "autobahn: received message: "
<< truncate(msg->str, 40)
<< std::endl;
ss << "autobahn: received message: " << truncate(msg->str, 40) << std::endl;
_webSocket.send(msg->str, msg->binary);
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
_webSocket.send(msg->str, msg->binary);
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
// And error can happen, in which case the test-case is marked done
_condition.notify_one();
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
ss << "Received message fragment" << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
ss << "Received ping" << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
ss << "Received pong" << std::endl;
}
else
{
ss << "Invalid ix::WebSocketMessageType" << std::endl;
}
// And error can happen, in which case the test-case is marked done
_condition.notify_one();
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
ss << "Received message fragment" << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
ss << "Received ping" << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
ss << "Received pong" << std::endl;
}
else
{
ss << "Invalid ix::WebSocketMessageType" << std::endl;
}
log(ss.str());
});
log(ss.str());
});
_webSocket.start();
@ -184,27 +180,24 @@ namespace ix
std::atomic<bool> success(true);
std::condition_variable condition;
webSocket.setOnMessageCallback(
[&condition, &success](const ix::WebSocketMessagePtr& msg)
webSocket.setOnMessageCallback([&condition, &success](const ix::WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Close)
{
if (msg->type == ix::WebSocketMessageType::Close)
{
std::cerr << "Report generated" << std::endl;
condition.notify_one();
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
std::cerr << ss.str() << std::endl;
success = false;
}
std::cerr << "Report generated" << std::endl;
condition.notify_one();
}
);
else if (msg->type == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
std::cerr << ss.str() << std::endl;
success = false;
}
});
webSocket.start();
std::mutex mutex;
@ -231,33 +224,30 @@ namespace ix
int count = -1;
std::condition_variable condition;
webSocket.setOnMessageCallback(
[&condition, &count](const ix::WebSocketMessagePtr& msg)
webSocket.setOnMessageCallback([&condition, &count](const ix::WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Close)
{
if (msg->type == ix::WebSocketMessageType::Close)
{
condition.notify_one();
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
std::cerr << ss.str() << std::endl;
condition.notify_one();
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
// response is a string
std::stringstream ss;
ss << msg->str;
ss >> count;
}
condition.notify_one();
}
);
else if (msg->type == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
std::cerr << ss.str() << std::endl;
condition.notify_one();
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
// response is a string
std::stringstream ss;
ss << msg->str;
ss >> count;
}
});
webSocket.start();
std::mutex mutex;
@ -289,17 +279,14 @@ namespace ix
testCasesCount++;
for (int i = 1 ; i < testCasesCount; ++i)
for (int i = 1; i < testCasesCount; ++i)
{
spdlog::info("Execute test case {}", i);
int caseNumber = i;
std::stringstream ss;
ss << url
<< "/runCase?case="
<< caseNumber
<< "&agent=ixwebsocket";
ss << url << "/runCase?case=" << caseNumber << "&agent=ixwebsocket";
std::string url(ss.str());
@ -309,4 +296,4 @@ namespace ix
return generateReport(url) ? 0 : 1;
}
}
} // namespace ix

View File

@ -5,8 +5,8 @@
*/
#include <iostream>
#include <sstream>
#include <ixwebsocket/IXWebSocketServer.h>
#include <sstream>
namespace ix
{
@ -16,75 +16,67 @@ namespace ix
ix::WebSocketServer server(port, hostname);
server.setOnConnectionCallback(
[&server](std::shared_ptr<WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
{
webSocket->setOnMessageCallback(
[webSocket, connectionState, &server](const WebSocketMessagePtr& msg)
server.setOnConnectionCallback([&server](std::shared_ptr<WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState) {
webSocket->setOnMessageCallback([webSocket, connectionState, &server](
const WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Open)
{
std::cerr << "New connection" << std::endl;
std::cerr << "id: " << connectionState->getId() << std::endl;
std::cerr << "Uri: " << msg->openInfo.uri << std::endl;
std::cerr << "Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
if (msg->type == ix::WebSocketMessageType::Open)
std::cerr << it.first << ": " << it.second << std::endl;
}
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
std::cerr << "Closed connection"
<< " code " << msg->closeInfo.code << " reason "
<< msg->closeInfo.reason << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
std::cerr << ss.str();
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
std::cerr << "Received message fragment" << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
for (auto&& client : server.getClients())
{
if (client != webSocket)
{
std::cerr << "New connection" << std::endl;
std::cerr << "id: " << connectionState->getId() << std::endl;
std::cerr << "Uri: " << msg->openInfo.uri << std::endl;
std::cerr << "Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
client->send(msg->str, msg->binary, [](int current, int total) -> bool {
std::cerr << "Step " << current << " out of " << total << std::endl;
return true;
});
do
{
std::cerr << it.first << ": " << it.second << std::endl;
}
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
std::cerr << "Closed connection"
<< " code " << msg->closeInfo.code
<< " reason " << msg->closeInfo.reason << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
std::cerr << ss.str();
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
std::cerr << "Received message fragment" << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
size_t bufferedAmount = client->bufferedAmount();
std::cerr << bufferedAmount << " bytes left to be sent"
<< std::endl;
for (auto&& client : server.getClients())
{
if (client != webSocket)
{
client->send(msg->str,
msg->binary,
[](int current, int total) -> bool
{
std::cerr << "Step " << current
<< " out of " << total << std::endl;
return true;
});
do
{
size_t bufferedAmount = client->bufferedAmount();
std::cerr << bufferedAmount << " bytes left to be sent" << std::endl;
std::chrono::duration<double, std::milli> duration(10);
std::this_thread::sleep_for(duration);
} while (client->bufferedAmount() != 0);
}
}
std::chrono::duration<double, std::milli> duration(10);
std::this_thread::sleep_for(duration);
} while (client->bufferedAmount() != 0);
}
}
);
}
);
}
});
});
auto res = server.listen();
if (!res.first)
@ -98,4 +90,4 @@ namespace ix
return 0;
}
}
} // namespace ix

View File

@ -9,13 +9,12 @@
// Broadcast server can be ran with `ws broadcast_server`
//
#include <iostream>
#include <sstream>
#include <queue>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXSocket.h>
#include "nlohmann/json.hpp"
#include <iostream>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <queue>
#include <sstream>
// for convenience
using json = nlohmann::json;
@ -24,34 +23,32 @@ namespace ix
{
class WebSocketChat
{
public:
WebSocketChat(const std::string& url,
const std::string& user);
public:
WebSocketChat(const std::string& url, const std::string& user);
void subscribe(const std::string& channel);
void start();
void stop();
bool isReady() const;
void subscribe(const std::string& channel);
void start();
void stop();
bool isReady() const;
void sendMessage(const std::string& text);
size_t getReceivedMessagesCount() const;
void sendMessage(const std::string& text);
size_t getReceivedMessagesCount() const;
std::string encodeMessage(const std::string& text);
std::pair<std::string, std::string> decodeMessage(const std::string& str);
std::string encodeMessage(const std::string& text);
std::pair<std::string, std::string> decodeMessage(const std::string& str);
private:
std::string _url;
std::string _user;
ix::WebSocket _webSocket;
std::queue<std::string> _receivedQueue;
private:
std::string _url;
std::string _user;
ix::WebSocket _webSocket;
std::queue<std::string> _receivedQueue;
void log(const std::string& msg);
void log(const std::string& msg);
};
WebSocketChat::WebSocketChat(const std::string& url,
const std::string& user) :
_url(url),
_user(user)
WebSocketChat::WebSocketChat(const std::string& url, const std::string& user)
: _url(url)
, _user(user)
{
;
}
@ -83,64 +80,57 @@ namespace ix
std::stringstream ss;
log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback(
[this](const WebSocketMessagePtr& msg)
_webSocket.setOnMessageCallback([this](const WebSocketMessagePtr& msg) {
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
log("ws chat: connected");
std::cout << "Uri: " << msg->openInfo.uri << std::endl;
std::cout << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
log("ws chat: connected");
std::cout << "Uri: " << msg->openInfo.uri << std::endl;
std::cout << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
std::cout << it.first << ": " << it.second << std::endl;
}
std::cout << it.first << ": " << it.second << std::endl;
}
ss << "ws chat: user "
<< _user
<< " Connected !";
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "ws chat: user "
<< _user
<< " disconnected !"
<< " code " << msg->closeInfo.code
<< " reason " << msg->closeInfo.reason;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
auto result = decodeMessage(msg->str);
ss << "ws chat: user " << _user << " Connected !";
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "ws chat: user " << _user << " disconnected !"
<< " code " << msg->closeInfo.code << " reason " << msg->closeInfo.reason;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
auto result = decodeMessage(msg->str);
// Our "chat" / "broacast" node.js server does not send us
// the messages we send, so we don't have to filter it out.
// Our "chat" / "broacast" node.js server does not send us
// the messages we send, so we don't have to filter it out.
// store text
_receivedQueue.push(result.second);
// store text
_receivedQueue.push(result.second);
ss << std::endl
<< result.first << "(" << msg->wireSize << " bytes)" << " > " << result.second
<< std::endl
<< _user << " > ";
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
log(ss.str());
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
ss << std::endl
<< result.first << "(" << msg->wireSize << " bytes)"
<< " > " << result.second << std::endl
<< _user << " > ";
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
log(ss.str());
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
_webSocket.start();
}
@ -170,8 +160,7 @@ namespace ix
_webSocket.sendText(encodeMessage(text));
}
int ws_chat_main(const std::string& url,
const std::string& user)
int ws_chat_main(const std::string& url, const std::string& user)
{
std::cout << "Type Ctrl-D to exit prompt..." << std::endl;
WebSocketChat webSocketChat(url, user);
@ -196,4 +185,4 @@ namespace ix
return 0;
}
}
} // namespace ix

View File

@ -4,15 +4,15 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <chrono>
#include <thread>
#include <atomic>
#include <jsoncpp/json/json.h>
#include <chrono>
#include <fstream>
#include <iostream>
#include <ixcobra/IXCobraMetricsPublisher.h>
#include <jsoncpp/json/json.h>
#include <spdlog/spdlog.h>
#include <sstream>
#include <thread>
namespace ix
{
@ -27,25 +27,23 @@ namespace ix
std::atomic<int> sentMessages(0);
std::atomic<int> ackedMessages(0);
CobraConnection::setPublishTrackerCallback(
[&sentMessages, &ackedMessages](bool sent, bool acked)
{
[&sentMessages, &ackedMessages](bool sent, bool acked) {
if (sent) sentMessages++;
if (acked) ackedMessages++;
}
);
});
CobraMetricsPublisher cobraMetricsPublisher;
cobraMetricsPublisher.enable(true);
bool enablePerMessageDeflate = true;
cobraMetricsPublisher.configure(appkey, endpoint, channel,
rolename, rolesecret, enablePerMessageDeflate);
cobraMetricsPublisher.configure(
appkey, endpoint, channel, rolename, rolesecret, enablePerMessageDeflate);
while (!cobraMetricsPublisher.isAuthenticated()) ;
while (!cobraMetricsPublisher.isAuthenticated())
;
std::ifstream f(path);
std::string str((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>());
std::string str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
Json::Value data;
Json::Reader reader;
@ -61,7 +59,7 @@ namespace ix
// Stress mode to try to trigger server and client bugs
while (true)
{
for (int i = 0 ; i < 1000; ++i)
for (int i = 0; i < 1000; ++i)
{
cobraMetricsPublisher.push(channel, data);
}
@ -70,7 +68,8 @@ namespace ix
cobraMetricsPublisher.resume();
// FIXME: investigate why without this check we trigger a lock
while (!cobraMetricsPublisher.isAuthenticated()) ;
while (!cobraMetricsPublisher.isAuthenticated())
;
}
}
@ -83,5 +82,4 @@ namespace ix
return 0;
}
}
} // namespace ix

View File

@ -4,17 +4,17 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <chrono>
#include <thread>
#include <atomic>
#include <mutex>
#include <chrono>
#include <condition_variable>
#include <jsoncpp/json/json.h>
#include <fstream>
#include <iostream>
#include <ixcobra/IXCobraMetricsPublisher.h>
#include <jsoncpp/json/json.h>
#include <mutex>
#include <spdlog/spdlog.h>
#include <sstream>
#include <thread>
namespace ix
{
@ -26,8 +26,7 @@ namespace ix
const std::string& path)
{
std::ifstream f(path);
std::string str((std::istreambuf_iterator<char>(f)),
std::istreambuf_iterator<char>());
std::string str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
Json::Value data;
Json::Reader reader;
@ -38,9 +37,8 @@ namespace ix
}
ix::CobraConnection conn;
conn.configure(appkey, endpoint,
rolename, rolesecret,
ix::WebSocketPerMessageDeflateOptions(true));
conn.configure(
appkey, endpoint, rolename, rolesecret, ix::WebSocketPerMessageDeflateOptions(true));
conn.connect();
// Display incoming messages
@ -48,59 +46,58 @@ namespace ix
std::atomic<bool> messageAcked(false);
std::condition_variable condition;
conn.setEventCallback(
[&conn, &channel, &data, &authenticated, &messageAcked, &condition]
(ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& headers,
const std::string& subscriptionId,
CobraConnection::MsgId msgId)
conn.setEventCallback([&conn, &channel, &data, &authenticated, &messageAcked, &condition](
ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& headers,
const std::string& subscriptionId,
CobraConnection::MsgId msgId) {
if (eventType == ix::CobraConnection_EventType_Open)
{
if (eventType == ix::CobraConnection_EventType_Open)
{
spdlog::info("Publisher connected");
spdlog::info("Publisher connected");
for (auto it : headers)
{
spdlog::info("{}: {}", it.first, it.second);
}
}
else if (eventType == ix::CobraConnection_EventType_Authenticated)
for (auto it : headers)
{
spdlog::info("Publisher authenticated");
authenticated = true;
Json::Value channels;
channels[0] = channel;
auto msgId = conn.publish(channels, data);
spdlog::info("Published msg {}", msgId);
}
else if (eventType == ix::CobraConnection_EventType_Subscribed)
{
spdlog::info("Publisher: subscribed to channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
{
spdlog::info("Publisher: unsubscribed from channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_Error)
{
spdlog::error("Publisher: error {}", errMsg);
condition.notify_one();
}
else if (eventType == ix::CobraConnection_EventType_Published)
{
spdlog::info("Published message id {} acked", msgId);
messageAcked = true;
condition.notify_one();
spdlog::info("{}: {}", it.first, it.second);
}
}
);
else if (eventType == ix::CobraConnection_EventType_Authenticated)
{
spdlog::info("Publisher authenticated");
authenticated = true;
while (!authenticated) ;
while (!messageAcked) ;
Json::Value channels;
channels[0] = channel;
auto msgId = conn.publish(channels, data);
spdlog::info("Published msg {}", msgId);
}
else if (eventType == ix::CobraConnection_EventType_Subscribed)
{
spdlog::info("Publisher: subscribed to channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
{
spdlog::info("Publisher: unsubscribed from channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_Error)
{
spdlog::error("Publisher: error {}", errMsg);
condition.notify_one();
}
else if (eventType == ix::CobraConnection_EventType_Published)
{
spdlog::info("Published message id {} acked", msgId);
messageAcked = true;
condition.notify_one();
}
});
while (!authenticated)
;
while (!messageAcked)
;
return 0;
}
}
} // namespace ix

View File

@ -4,14 +4,13 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include <iostream>
#include <sstream>
#include <chrono>
#include <thread>
#include <atomic>
#include <chrono>
#include <iostream>
#include <ixcobra/IXCobraConnection.h>
#include <spdlog/spdlog.h>
#include <sstream>
#include <thread>
namespace ix
{
@ -24,9 +23,8 @@ namespace ix
bool quiet)
{
ix::CobraConnection conn;
conn.configure(appkey, endpoint,
rolename, rolesecret,
ix::WebSocketPerMessageDeflateOptions(true));
conn.configure(
appkey, endpoint, rolename, rolesecret, ix::WebSocketPerMessageDeflateOptions(true));
conn.connect();
Json::FastWriter jsonWriter;
@ -35,13 +33,11 @@ namespace ix
std::atomic<int> msgPerSeconds(0);
std::atomic<int> msgCount(0);
auto timer = [&msgPerSeconds, &msgCount]
{
auto timer = [&msgPerSeconds, &msgCount] {
while (true)
{
std::cout << "#messages " << msgCount << " "
<< "msg/s " << msgPerSeconds
<< std::endl;
<< "msg/s " << msgPerSeconds << std::endl;
msgPerSeconds = 0;
auto duration = std::chrono::seconds(1);
@ -52,13 +48,12 @@ namespace ix
std::thread t(timer);
conn.setEventCallback(
[&conn, &channel, &jsonWriter, &filter, &msgCount, &msgPerSeconds, &quiet]
(ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& headers,
const std::string& subscriptionId,
CobraConnection::MsgId msgId)
{
[&conn, &channel, &jsonWriter, &filter, &msgCount, &msgPerSeconds, &quiet](
ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& headers,
const std::string& subscriptionId,
CobraConnection::MsgId msgId) {
if (eventType == ix::CobraConnection_EventType_Open)
{
spdlog::info("Subscriber connected");
@ -71,18 +66,18 @@ namespace ix
else if (eventType == ix::CobraConnection_EventType_Authenticated)
{
spdlog::info("Subscriber authenticated");
conn.subscribe(channel, filter,
[&jsonWriter, &quiet,
&msgPerSeconds, &msgCount](const Json::Value& msg)
{
if (!quiet)
{
std::cout << jsonWriter.write(msg) << std::endl;
}
conn.subscribe(
channel,
filter,
[&jsonWriter, &quiet, &msgPerSeconds, &msgCount](const Json::Value& msg) {
if (!quiet)
{
std::cout << jsonWriter.write(msg) << std::endl;
}
msgPerSeconds++;
msgCount++;
});
msgPerSeconds++;
msgCount++;
});
}
else if (eventType == ix::CobraConnection_EventType_Subscribed)
{
@ -100,8 +95,7 @@ namespace ix
{
spdlog::error("Published message hacked: {}", msgId);
}
}
);
});
while (true)
{
@ -111,4 +105,4 @@ namespace ix
return 0;
}
}
} // namespace ix

View File

@ -4,19 +4,18 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include <iostream>
#include <sstream>
#include <chrono>
#include <thread>
#include <atomic>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <ixcobra/IXCobraConnection.h>
#include <spdlog/spdlog.h>
#include "IXSentryClient.h"
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <ixcobra/IXCobraConnection.h>
#include <mutex>
#include <queue>
#include <spdlog/spdlog.h>
#include <sstream>
#include <thread>
#include <vector>
namespace ix
{
@ -32,9 +31,8 @@ namespace ix
int jobs)
{
ix::CobraConnection conn;
conn.configure(appkey, endpoint,
rolename, rolesecret,
ix::WebSocketPerMessageDeflateOptions(true));
conn.configure(
appkey, endpoint, rolename, rolesecret, ix::WebSocketPerMessageDeflateOptions(true));
conn.connect();
Json::FastWriter jsonWriter;
@ -48,10 +46,15 @@ namespace ix
std::condition_variable progressCondition;
std::queue<Json::Value> queue;
auto sentrySender = [&condition, &progressCondition, &conditionVariableMutex,
&queue, verbose, &errorSending, &sentCount,
&stop, &dsn]
{
auto sentrySender = [&condition,
&progressCondition,
&conditionVariableMutex,
&queue,
verbose,
&errorSending,
&sentCount,
&stop,
&dsn] {
SentryClient sentryClient(dsn);
while (true)
@ -60,7 +63,7 @@ namespace ix
{
std::unique_lock<std::mutex> lock(conditionVariableMutex);
condition.wait(lock, [&queue, &stop]{ return !queue.empty() && !stop; });
condition.wait(lock, [&queue, &stop] { return !queue.empty() && !stop; });
msg = queue.front();
queue.pop();
@ -94,88 +97,93 @@ namespace ix
pool.push_back(std::thread(sentrySender));
}
conn.setEventCallback(
[&conn, &channel, &filter, &jsonWriter,
verbose, &receivedCount, &sentCount,
&condition, &conditionVariableMutex,
&progressCondition, &queue]
(ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& headers,
const std::string& subscriptionId,
CobraConnection::MsgId msgId)
conn.setEventCallback([&conn,
&channel,
&filter,
&jsonWriter,
verbose,
&receivedCount,
&sentCount,
&condition,
&conditionVariableMutex,
&progressCondition,
&queue](ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& headers,
const std::string& subscriptionId,
CobraConnection::MsgId msgId) {
if (eventType == ix::CobraConnection_EventType_Open)
{
if (eventType == ix::CobraConnection_EventType_Open)
{
spdlog::info("Subscriber connected");
spdlog::info("Subscriber connected");
for (auto it : headers)
{
spdlog::info("{}: {}", it.first, it.second);
}
}
if (eventType == ix::CobraConnection_EventType_Closed)
for (auto it : headers)
{
spdlog::info("Subscriber closed");
spdlog::info("{}: {}", it.first, it.second);
}
else if (eventType == ix::CobraConnection_EventType_Authenticated)
{
std::cerr << "Subscriber authenticated" << std::endl;
conn.subscribe(channel, filter,
[&jsonWriter, verbose,
&sentCount, &receivedCount,
&condition, &conditionVariableMutex,
&progressCondition, &queue]
(const Json::Value& msg)
}
if (eventType == ix::CobraConnection_EventType_Closed)
{
spdlog::info("Subscriber closed");
}
else if (eventType == ix::CobraConnection_EventType_Authenticated)
{
std::cerr << "Subscriber authenticated" << std::endl;
conn.subscribe(channel,
filter,
[&jsonWriter,
verbose,
&sentCount,
&receivedCount,
&condition,
&conditionVariableMutex,
&progressCondition,
&queue](const Json::Value& msg) {
if (verbose)
{
if (verbose)
{
spdlog::info(jsonWriter.write(msg));
}
spdlog::info(jsonWriter.write(msg));
}
// If we cannot send to sentry fast enough, drop the message
const uint64_t scaleFactor = 2;
// If we cannot send to sentry fast enough, drop the message
const uint64_t scaleFactor = 2;
if (sentCount != 0 &&
receivedCount != 0 &&
(sentCount * scaleFactor < receivedCount))
{
spdlog::warn("message dropped: sending is backlogged !");
condition.notify_one();
progressCondition.notify_one();
return;
}
++receivedCount;
{
std::unique_lock<std::mutex> lock(conditionVariableMutex);
queue.push(msg);
}
if (sentCount != 0 && receivedCount != 0 &&
(sentCount * scaleFactor < receivedCount))
{
spdlog::warn("message dropped: sending is backlogged !");
condition.notify_one();
progressCondition.notify_one();
});
}
else if (eventType == ix::CobraConnection_EventType_Subscribed)
{
spdlog::info("Subscriber: subscribed to channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
{
spdlog::info("Subscriber: unsubscribed from channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_Error)
{
spdlog::error("Subscriber: error {}", errMsg);
}
else if (eventType == ix::CobraConnection_EventType_Published)
{
spdlog::error("Published message hacked: {}", msgId);
}
return;
}
++receivedCount;
{
std::unique_lock<std::mutex> lock(conditionVariableMutex);
queue.push(msg);
}
condition.notify_one();
progressCondition.notify_one();
});
}
);
else if (eventType == ix::CobraConnection_EventType_Subscribed)
{
spdlog::info("Subscriber: subscribed to channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
{
spdlog::info("Subscriber: unsubscribed from channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_Error)
{
spdlog::error("Subscriber: error {}", errMsg);
}
else if (eventType == ix::CobraConnection_EventType_Published)
{
spdlog::error("Published message hacked: {}", msgId);
}
});
std::mutex progressConditionVariableMutex;
while (true)
@ -200,4 +208,4 @@ namespace ix
return (strict && errorSending) ? 1 : 0;
}
}
} // namespace ix

View File

@ -4,15 +4,14 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include <iostream>
#include <sstream>
#include <chrono>
#include <thread>
#include <atomic>
#include <vector>
#include <chrono>
#include <iostream>
#include <ixcobra/IXCobraConnection.h>
#include <spdlog/spdlog.h>
#include <sstream>
#include <thread>
#include <vector>
#ifndef _WIN32
#include <statsd_client.h>
@ -41,8 +40,7 @@ namespace ix
// Extract an attribute from a Json Value.
// extractAttr("foo.bar", {"foo": {"bar": "baz"}}) => baz
//
std::string extractAttr(const std::string& attr,
const Json::Value& jsonValue)
std::string extractAttr(const std::string& attr, const Json::Value& jsonValue)
{
// Split by .
std::string token;
@ -71,9 +69,8 @@ namespace ix
bool verbose)
{
ix::CobraConnection conn;
conn.configure(appkey, endpoint,
rolename, rolesecret,
ix::WebSocketPerMessageDeflateOptions(true));
conn.configure(
appkey, endpoint, rolename, rolesecret, ix::WebSocketPerMessageDeflateOptions(true));
conn.connect();
auto tokens = parseFields(fields);
@ -90,72 +87,75 @@ namespace ix
Json::FastWriter jsonWriter;
uint64_t msgCount = 0;
conn.setEventCallback(
[&conn, &channel, &filter, &jsonWriter, &statsdClient, verbose, &tokens, &prefix, &msgCount]
(ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& headers,
const std::string& subscriptionId,
CobraConnection::MsgId msgId)
conn.setEventCallback([&conn,
&channel,
&filter,
&jsonWriter,
&statsdClient,
verbose,
&tokens,
&prefix,
&msgCount](ix::CobraConnectionEventType eventType,
const std::string& errMsg,
const ix::WebSocketHttpHeaders& headers,
const std::string& subscriptionId,
CobraConnection::MsgId msgId) {
if (eventType == ix::CobraConnection_EventType_Open)
{
if (eventType == ix::CobraConnection_EventType_Open)
{
spdlog::info("Subscriber connected");
spdlog::info("Subscriber connected");
for (auto it : headers)
{
spdlog::info("{}: {}", it.first, it.second);
}
}
if (eventType == ix::CobraConnection_EventType_Closed)
for (auto it : headers)
{
spdlog::info("Subscriber closed");
}
else if (eventType == ix::CobraConnection_EventType_Authenticated)
{
spdlog::info("Subscriber authenticated");
conn.subscribe(channel, filter,
[&jsonWriter, &statsdClient,
verbose, &tokens, &prefix, &msgCount]
(const Json::Value& msg)
{
if (verbose)
{
spdlog::info(jsonWriter.write(msg));
}
std::string id;
for (auto&& attr : tokens)
{
id += ".";
id += extractAttr(attr, msg);
}
spdlog::info("{} {}{}", msgCount++, prefix, id);
#ifndef _WIN32
statsdClient.count(id, 1);
#endif
});
}
else if (eventType == ix::CobraConnection_EventType_Subscribed)
{
spdlog::info("Subscriber: subscribed to channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
{
spdlog::info("Subscriber: unsubscribed from channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_Error)
{
spdlog::error("Subscriber: error {}", errMsg);
}
else if (eventType == ix::CobraConnection_EventType_Published)
{
spdlog::error("Published message hacked: {}", msgId);
spdlog::info("{}: {}", it.first, it.second);
}
}
);
if (eventType == ix::CobraConnection_EventType_Closed)
{
spdlog::info("Subscriber closed");
}
else if (eventType == ix::CobraConnection_EventType_Authenticated)
{
spdlog::info("Subscriber authenticated");
conn.subscribe(channel,
filter,
[&jsonWriter, &statsdClient, verbose, &tokens, &prefix, &msgCount](
const Json::Value& msg) {
if (verbose)
{
spdlog::info(jsonWriter.write(msg));
}
std::string id;
for (auto&& attr : tokens)
{
id += ".";
id += extractAttr(attr, msg);
}
spdlog::info("{} {}{}", msgCount++, prefix, id);
#ifndef _WIN32
statsdClient.count(id, 1);
#endif
});
}
else if (eventType == ix::CobraConnection_EventType_Subscribed)
{
spdlog::info("Subscriber: subscribed to channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_UnSubscribed)
{
spdlog::info("Subscriber: unsubscribed from channel {}", subscriptionId);
}
else if (eventType == ix::CobraConnection_EventType_Error)
{
spdlog::error("Subscriber: error {}", errMsg);
}
else if (eventType == ix::CobraConnection_EventType_Published)
{
spdlog::error("Published message hacked: {}", msgId);
}
});
while (true)
{
@ -165,4 +165,4 @@ namespace ix
return 0;
}
}
} // namespace ix

View File

@ -4,41 +4,40 @@
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
*/
#include <iostream>
#include <sstream>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXSocket.h>
#include "linenoise.hpp"
#include <iostream>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <sstream>
namespace ix
{
class WebSocketConnect
{
public:
WebSocketConnect(const std::string& _url,
const std::string& headers,
bool disableAutomaticReconnection,
bool disablePerMessageDeflate,
bool binaryMode,
uint32_t maxWaitBetweenReconnectionRetries);
public:
WebSocketConnect(const std::string& _url,
const std::string& headers,
bool disableAutomaticReconnection,
bool disablePerMessageDeflate,
bool binaryMode,
uint32_t maxWaitBetweenReconnectionRetries);
void subscribe(const std::string& channel);
void start();
void stop();
void subscribe(const std::string& channel);
void start();
void stop();
void sendMessage(const std::string& text);
void sendMessage(const std::string& text);
private:
std::string _url;
WebSocketHttpHeaders _headers;
ix::WebSocket _webSocket;
bool _disablePerMessageDeflate;
bool _binaryMode;
private:
std::string _url;
WebSocketHttpHeaders _headers;
ix::WebSocket _webSocket;
bool _disablePerMessageDeflate;
bool _binaryMode;
void log(const std::string& msg);
WebSocketHttpHeaders parseHeaders(const std::string& data);
void log(const std::string& msg);
WebSocketHttpHeaders parseHeaders(const std::string& data);
};
WebSocketConnect::WebSocketConnect(const std::string& url,
@ -46,10 +45,10 @@ namespace ix
bool disableAutomaticReconnection,
bool disablePerMessageDeflate,
bool binaryMode,
uint32_t maxWaitBetweenReconnectionRetries) :
_url(url),
_disablePerMessageDeflate(disablePerMessageDeflate),
_binaryMode(binaryMode)
uint32_t maxWaitBetweenReconnectionRetries)
: _url(url)
, _disablePerMessageDeflate(disablePerMessageDeflate)
, _binaryMode(binaryMode)
{
if (disableAutomaticReconnection)
{
@ -81,7 +80,7 @@ namespace ix
if (pos == std::string::npos) continue;
auto key = token.substr(0, pos);
auto val = token.substr(pos+1);
auto val = token.substr(pos + 1);
std::cerr << key << ": " << val << std::endl;
headers[key] = val;
@ -114,61 +113,58 @@ namespace ix
std::stringstream ss;
log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback(
[this](const ix::WebSocketMessagePtr& msg)
_webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
log("ws_connect: connected");
std::cout << "Uri: " << msg->openInfo.uri << std::endl;
std::cout << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
log("ws_connect: connected");
std::cout << "Uri: " << msg->openInfo.uri << std::endl;
std::cout << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
std::cout << it.first << ": " << it.second << std::endl;
}
std::cout << it.first << ": " << it.second << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "ws_connect: connection closed:";
ss << " code " << msg->closeInfo.code;
ss << " reason " << msg->closeInfo.reason << std::endl;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "ws_connect: connection closed:";
ss << " code " << msg->closeInfo.code;
ss << " reason " << msg->closeInfo.reason << std::endl;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
ss << "ws_connect: received message: "
<< msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
std::cerr << "Received message fragment" << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
std::cerr << "Received ping" << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
std::cerr << "Received pong" << std::endl;
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
ss << "ws_connect: received message: " << msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
std::cerr << "Received message fragment" << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
std::cerr << "Received ping" << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
std::cerr << "Received pong" << std::endl;
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
_webSocket.start();
}
@ -237,5 +233,4 @@ namespace ix
return 0;
}
}
} // namespace ix

View File

@ -5,8 +5,8 @@
*/
#include <iostream>
#include <sstream>
#include <ixwebsocket/IXWebSocketServer.h>
#include <sstream>
namespace ix
{
@ -18,11 +18,9 @@ namespace ix
server.setOnConnectionCallback(
[greetings](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
{
std::shared_ptr<ConnectionState> connectionState) {
webSocket->setOnMessageCallback(
[webSocket, connectionState, greetings](const WebSocketMessagePtr& msg)
{
[webSocket, connectionState, greetings](const WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Open)
{
std::cerr << "New connection" << std::endl;
@ -42,29 +40,25 @@ namespace ix
else if (msg->type == ix::WebSocketMessageType::Close)
{
std::cerr << "Closed connection"
<< " code " << msg->closeInfo.code
<< " reason " << msg->closeInfo.reason << std::endl;
<< " code " << msg->closeInfo.code << " reason "
<< msg->closeInfo.reason << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
std::cerr << ss.str();
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
std::cerr << "Received "
<< msg->wireSize << " bytes"
<< std::endl;
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
webSocket->send(msg->str, msg->binary);
}
}
);
}
);
});
});
auto res = server.listen();
if (!res.first)
@ -78,4 +72,4 @@ namespace ix
return 0;
}
}
} // namespace ix

View File

@ -4,11 +4,11 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include <iostream>
#include <sstream>
#include <fstream>
#include <iostream>
#include <ixwebsocket/IXHttpClient.h>
#include <ixwebsocket/IXWebSocketHttpHeaders.h>
#include <sstream>
namespace ix
{
@ -19,7 +19,7 @@ namespace ix
idx = path.rfind('/');
if (idx != std::string::npos)
{
std::string filename = path.substr(idx+1);
std::string filename = path.substr(idx + 1);
return filename;
}
else
@ -44,7 +44,7 @@ namespace ix
if (pos == std::string::npos) continue;
auto key = token.substr(0, pos);
auto val = token.substr(pos+1);
auto val = token.substr(pos + 1);
std::cerr << key << ": " << val << std::endl;
headers[key] = val;
@ -73,7 +73,7 @@ namespace ix
if (pos == std::string::npos) continue;
auto key = token.substr(0, pos);
auto val = token.substr(pos+1);
auto val = token.substr(pos + 1);
std::cerr << key << ": " << val << std::endl;
httpParameters[key] = val;
@ -104,14 +104,10 @@ namespace ix
args->maxRedirects = maxRedirects;
args->verbose = verbose;
args->compress = compress;
args->logger = [](const std::string& msg)
{
std::cout << msg;
};
args->onProgressCallback = [](int current, int total) -> bool
{
std::cerr << "\r" << "Downloaded "
<< current << " bytes out of " << total;
args->logger = [](const std::string& msg) { std::cout << msg; };
args->onProgressCallback = [](int current, int total) -> bool {
std::cerr << "\r"
<< "Downloaded " << current << " bytes out of " << total;
return true;
};
@ -160,7 +156,7 @@ namespace ix
std::cout << "Writing to disk: " << filename << std::endl;
std::ofstream out(filename);
out.write((char*)&response->payload.front(), response->payload.size());
out.write((char*) &response->payload.front(), response->payload.size());
out.close();
}
else
@ -173,11 +169,12 @@ namespace ix
{
std::cerr << "Binary output can mess up your terminal." << std::endl;
std::cerr << "Use the -O flag to save the file to disk." << std::endl;
std::cerr << "You can also use the --output option to specify a filename." << std::endl;
std::cerr << "You can also use the --output option to specify a filename."
<< std::endl;
}
}
}
return 0;
}
}
} // namespace ix

View File

@ -4,12 +4,12 @@
* Copyright (c) 2018 Machine Zone, Inc. All rights reserved.
*/
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
#include <ixwebsocket/IXHttpServer.h>
#include <spdlog/spdlog.h>
#include <sstream>
#include <vector>
namespace ix
{
@ -31,4 +31,4 @@ namespace ix
return 0;
}
}
} // namespace ix

View File

@ -5,33 +5,33 @@
*/
#include <iostream>
#include <sstream>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <sstream>
namespace ix
{
class WebSocketPingPong
{
public:
WebSocketPingPong(const std::string& _url);
public:
WebSocketPingPong(const std::string& _url);
void subscribe(const std::string& channel);
void start();
void stop();
void subscribe(const std::string& channel);
void start();
void stop();
void ping(const std::string& text);
void send(const std::string& text);
void ping(const std::string& text);
void send(const std::string& text);
private:
std::string _url;
ix::WebSocket _webSocket;
private:
std::string _url;
ix::WebSocket _webSocket;
void log(const std::string& msg);
void log(const std::string& msg);
};
WebSocketPingPong::WebSocketPingPong(const std::string& url) :
_url(url)
WebSocketPingPong::WebSocketPingPong(const std::string& url)
: _url(url)
{
;
}
@ -53,63 +53,57 @@ namespace ix
std::stringstream ss;
log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback(
[this](const ix::WebSocketMessagePtr& msg)
_webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
log("ping_pong: connected");
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
std::cout << "Uri: " << msg->openInfo.uri << std::endl;
std::cout << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
log("ping_pong: connected");
std::cout << "Uri: " << msg->openInfo.uri << std::endl;
std::cout << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
std::cout << it.first << ": " << it.second << std::endl;
}
std::cout << it.first << ": " << it.second << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "ping_pong: disconnected:"
<< " code " << msg->closeInfo.code
<< " reason " << msg->closeInfo.reason
<< msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
ss << "ping_pong: received message: "
<< msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
ss << "ping_pong: received ping message: "
<< msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
ss << "ping_pong: received pong message: "
<< msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
log(ss.str());
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "ping_pong: disconnected:"
<< " code " << msg->closeInfo.code << " reason " << msg->closeInfo.reason
<< msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
ss << "ping_pong: received message: " << msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Ping)
{
ss << "ping_pong: received ping message: " << msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Pong)
{
ss << "ping_pong: received pong message: " << msg->str;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
log(ss.str());
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
_webSocket.start();
}
@ -118,7 +112,8 @@ namespace ix
{
if (!_webSocket.ping(text).success)
{
std::cerr << "Failed to send ping message. Message too long (> 125 bytes) or endpoint is disconnected"
std::cerr << "Failed to send ping message. Message too long (> 125 bytes) or endpoint "
"is disconnected"
<< std::endl;
}
}
@ -160,4 +155,4 @@ namespace ix
return 0;
}
}
} // namespace ix

View File

@ -4,19 +4,19 @@
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXSocket.h>
#include <ixcrypto/IXUuid.h>
#include <condition_variable>
#include <fstream>
#include <iostream>
#include <ixcrypto/IXBase64.h>
#include <ixcrypto/IXHash.h>
#include <ixcrypto/IXUuid.h>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <msgpack11/msgpack11.hpp>
#include <mutex>
#include <sstream>
#include <vector>
using msgpack11::MsgPack;
@ -24,42 +24,40 @@ namespace ix
{
class WebSocketReceiver
{
public:
WebSocketReceiver(const std::string& _url,
bool enablePerMessageDeflate,
int delayMs);
public:
WebSocketReceiver(const std::string& _url, bool enablePerMessageDeflate, int delayMs);
void subscribe(const std::string& channel);
void start();
void stop();
void subscribe(const std::string& channel);
void start();
void stop();
void waitForConnection();
void waitForMessage();
void handleMessage(const std::string& str);
void waitForConnection();
void waitForMessage();
void handleMessage(const std::string& str);
private:
std::string _url;
std::string _id;
ix::WebSocket _webSocket;
bool _enablePerMessageDeflate;
int _delayMs;
int _receivedFragmentCounter;
private:
std::string _url;
std::string _id;
ix::WebSocket _webSocket;
bool _enablePerMessageDeflate;
int _delayMs;
int _receivedFragmentCounter;
std::mutex _conditionVariableMutex;
std::condition_variable _condition;
std::mutex _conditionVariableMutex;
std::condition_variable _condition;
std::string extractFilename(const std::string& path);
void handleError(const std::string& errMsg, const std::string& id);
void log(const std::string& msg);
std::string extractFilename(const std::string& path);
void handleError(const std::string& errMsg, const std::string& id);
void log(const std::string& msg);
};
WebSocketReceiver::WebSocketReceiver(const std::string& url,
bool enablePerMessageDeflate,
int delayMs) :
_url(url),
_enablePerMessageDeflate(enablePerMessageDeflate),
_delayMs(delayMs),
_receivedFragmentCounter(0)
int delayMs)
: _url(url)
, _enablePerMessageDeflate(enablePerMessageDeflate)
, _delayMs(delayMs)
, _receivedFragmentCounter(0)
{
;
}
@ -98,7 +96,7 @@ namespace ix
idx = path.rfind('/');
if (idx != std::string::npos)
{
std::string filename = path.substr(idx+1);
std::string filename = path.substr(idx + 1);
return filename;
}
else
@ -107,8 +105,7 @@ namespace ix
}
}
void WebSocketReceiver::handleError(const std::string& errMsg,
const std::string& id)
void WebSocketReceiver::handleError(const std::string& errMsg, const std::string& id)
{
std::map<MsgPack, MsgPack> pdu;
pdu["kind"] = "error";
@ -156,7 +153,7 @@ namespace ix
std::cout << "Writing to disk: " << filenameTmp << std::endl;
std::ofstream out(filenameTmp);
out.write((char*)&content.front(), content.size());
out.write((char*) &content.front(), content.size());
out.close();
std::cout << "Renaming " << filenameTmp << " to " << filename << std::endl;
@ -182,70 +179,66 @@ namespace ix
std::stringstream ss;
log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback(
[this](const ix::WebSocketMessagePtr& msg)
_webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
_condition.notify_one();
_condition.notify_one();
log("ws_receive: connected");
std::cout << "Uri: " << msg->openInfo.uri << std::endl;
std::cout << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
std::cout << it.first << ": " << it.second << std::endl;
}
}
else if (msg->type == ix::WebSocketMessageType::Close)
log("ws_receive: connected");
std::cout << "Uri: " << msg->openInfo.uri << std::endl;
std::cout << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
ss << "ws_receive: connection closed:";
ss << " code " << msg->closeInfo.code;
ss << " reason " << msg->closeInfo.reason << std::endl;
log(ss.str());
std::cout << it.first << ": " << it.second << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
ss << "ws_receive: transfered " << msg->wireSize << " bytes";
log(ss.str());
handleMessage(msg->str);
_condition.notify_one();
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
ss << "ws_receive: received fragment " << _receivedFragmentCounter++;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "ws_receive: connection closed:";
ss << " code " << msg->closeInfo.code;
ss << " reason " << msg->closeInfo.reason << std::endl;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
ss << "ws_receive: transfered " << msg->wireSize << " bytes";
log(ss.str());
handleMessage(msg->str);
_condition.notify_one();
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
ss << "ws_receive: received fragment " << _receivedFragmentCounter++;
log(ss.str());
if (_delayMs > 0)
{
// Introduce an arbitrary delay, to simulate a slow connection
std::chrono::duration<double, std::milli> duration(_delayMs);
std::this_thread::sleep_for(duration);
}
}
else if (msg->type == ix::WebSocketMessageType::Error)
if (_delayMs > 0)
{
ss << "ws_receive ";
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
log(ss.str());
// Introduce an arbitrary delay, to simulate a slow connection
std::chrono::duration<double, std::milli> duration(_delayMs);
std::this_thread::sleep_for(duration);
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "ws_receive ";
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
log(ss.str());
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
_webSocket.start();
}
void wsReceive(const std::string& url,
bool enablePerMessageDeflate,
int delayMs)
void wsReceive(const std::string& url, bool enablePerMessageDeflate, int delayMs)
{
WebSocketReceiver webSocketReceiver(url, enablePerMessageDeflate, delayMs);
webSocketReceiver.start();
@ -261,11 +254,9 @@ namespace ix
webSocketReceiver.stop();
}
int ws_receive_main(const std::string& url,
bool enablePerMessageDeflate,
int delayMs)
int ws_receive_main(const std::string& url, bool enablePerMessageDeflate, int delayMs)
{
wsReceive(url, enablePerMessageDeflate, delayMs);
return 0;
}
}
} // namespace ix

View File

@ -4,9 +4,9 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include "IXRedisClient.h"
#include <iostream>
#include <sstream>
#include "IXRedisClient.h"
namespace ix
{
@ -41,8 +41,7 @@ namespace ix
{
if (!redisClient.publish(channel, message, errMsg))
{
std::cerr << "Error publishing to channel " << channel
<< "error: " << errMsg
std::cerr << "Error publishing to channel " << channel << "error: " << errMsg
<< std::endl;
return 1;
}
@ -50,4 +49,4 @@ namespace ix
return 0;
}
}
} // namespace ix

View File

@ -4,12 +4,12 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/
#include "IXRedisClient.h"
#include <atomic>
#include <chrono>
#include <iostream>
#include <sstream>
#include <chrono>
#include <thread>
#include <atomic>
#include "IXRedisClient.h"
namespace ix
{
@ -41,9 +41,7 @@ namespace ix
std::atomic<int> msgPerSeconds(0);
std::atomic<int> msgCount(0);
auto callback = [&msgPerSeconds, &msgCount, verbose]
(const std::string& message)
{
auto callback = [&msgPerSeconds, &msgCount, verbose](const std::string& message) {
if (verbose)
{
std::cout << "received: " << message << std::endl;
@ -53,18 +51,15 @@ namespace ix
msgCount++;
};
auto responseCallback = [](const std::string& redisResponse)
{
auto responseCallback = [](const std::string& redisResponse) {
std::cout << "Redis subscribe response: " << redisResponse << std::endl;
};
auto timer = [&msgPerSeconds, &msgCount]
{
auto timer = [&msgPerSeconds, &msgCount] {
while (true)
{
std::cout << "#messages " << msgCount << " "
<< "msg/s " << msgPerSeconds
<< std::endl;
<< "msg/s " << msgPerSeconds << std::endl;
msgPerSeconds = 0;
auto duration = std::chrono::seconds(1);
@ -83,4 +78,4 @@ namespace ix
return 0;
}
}
} // namespace ix

View File

@ -4,19 +4,19 @@
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved.
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <condition_variable>
#include <mutex>
#include <chrono>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXSocket.h>
#include <ixcrypto/IXUuid.h>
#include <condition_variable>
#include <fstream>
#include <iostream>
#include <ixcrypto/IXBase64.h>
#include <ixcrypto/IXHash.h>
#include <ixcrypto/IXUuid.h>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <msgpack11/msgpack11.hpp>
#include <mutex>
#include <sstream>
#include <vector>
using msgpack11::MsgPack;
@ -24,35 +24,33 @@ namespace ix
{
class WebSocketSender
{
public:
WebSocketSender(const std::string& _url,
bool enablePerMessageDeflate);
public:
WebSocketSender(const std::string& _url, bool enablePerMessageDeflate);
void subscribe(const std::string& channel);
void start();
void stop();
void subscribe(const std::string& channel);
void start();
void stop();
void waitForConnection();
void waitForAck();
void waitForConnection();
void waitForAck();
void sendMessage(const std::string& filename, bool throttle);
void sendMessage(const std::string& filename, bool throttle);
private:
std::string _url;
std::string _id;
ix::WebSocket _webSocket;
bool _enablePerMessageDeflate;
private:
std::string _url;
std::string _id;
ix::WebSocket _webSocket;
bool _enablePerMessageDeflate;
std::mutex _conditionVariableMutex;
std::condition_variable _condition;
std::mutex _conditionVariableMutex;
std::condition_variable _condition;
void log(const std::string& msg);
void log(const std::string& msg);
};
WebSocketSender::WebSocketSender(const std::string& url,
bool enablePerMessageDeflate) :
_url(url),
_enablePerMessageDeflate(enablePerMessageDeflate)
WebSocketSender::WebSocketSender(const std::string& url, bool enablePerMessageDeflate)
: _url(url)
, _enablePerMessageDeflate(enablePerMessageDeflate)
{
;
}
@ -95,7 +93,7 @@ namespace ix
file.seekg(0, file.beg);
memblock.resize((size_t) size);
file.read((char*)&memblock.front(), static_cast<std::streamsize>(size));
file.read((char*) &memblock.front(), static_cast<std::streamsize>(size));
return memblock;
}
@ -111,114 +109,110 @@ namespace ix
std::stringstream ss;
log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback(
[this](const WebSocketMessagePtr& msg)
_webSocket.setOnMessageCallback([this](const WebSocketMessagePtr& msg) {
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open)
{
_condition.notify_one();
_condition.notify_one();
log("ws_send: connected");
std::cout << "Uri: " << msg->openInfo.uri << std::endl;
std::cout << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
std::cout << it.first << ": " << it.second << std::endl;
}
}
else if (msg->type == ix::WebSocketMessageType::Close)
log("ws_send: connected");
std::cout << "Uri: " << msg->openInfo.uri << std::endl;
std::cout << "Handshake Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
ss << "ws_send: connection closed:";
ss << " code " << msg->closeInfo.code;
ss << " reason " << msg->closeInfo.reason << std::endl;
log(ss.str());
std::cout << it.first << ": " << it.second << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
_condition.notify_one();
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
ss << "ws_send: connection closed:";
ss << " code " << msg->closeInfo.code;
ss << " reason " << msg->closeInfo.reason << std::endl;
log(ss.str());
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
_condition.notify_one();
ss << "ws_send: received message (" << msg->wireSize << " bytes)";
log(ss.str());
ss << "ws_send: received message (" << msg->wireSize << " bytes)";
log(ss.str());
std::string errMsg;
MsgPack data = MsgPack::parse(msg->str, errMsg);
if (!errMsg.empty())
{
std::cerr << "Invalid MsgPack response" << std::endl;
return;
}
std::string errMsg;
MsgPack data = MsgPack::parse(msg->str, errMsg);
if (!errMsg.empty())
{
std::cerr << "Invalid MsgPack response" << std::endl;
return;
}
std::string id = data["id"].string_value();
if (_id != id)
{
std::cerr << "Invalid id" << std::endl;
}
}
else if (msg->type == ix::WebSocketMessageType::Error)
std::string id = data["id"].string_value();
if (_id != id)
{
ss << "ws_send ";
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
log(ss.str());
std::cerr << "Invalid id" << std::endl;
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
ss << "ws_send ";
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
log(ss.str());
}
else
{
ss << "Invalid ix::WebSocketMessageType";
log(ss.str());
}
});
_webSocket.start();
}
class Bench
{
public:
Bench(const std::string& description) :
_description(description),
_start(std::chrono::system_clock::now()),
_reported(false)
public:
Bench(const std::string& description)
: _description(description)
, _start(std::chrono::system_clock::now())
, _reported(false)
{
;
}
~Bench()
{
if (!_reported)
{
;
report();
}
}
~Bench()
{
if (!_reported)
{
report();
}
}
void report()
{
auto now = std::chrono::system_clock::now();
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now - _start);
void report()
{
auto now = std::chrono::system_clock::now();
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now - _start);
_ms = milliseconds.count();
std::cout << _description << " completed in " << _ms << "ms" << std::endl;
_ms = milliseconds.count();
std::cout << _description << " completed in "
<< _ms << "ms" << std::endl;
_reported = true;
}
_reported = true;
}
uint64_t getDuration() const
{
return _ms;
}
uint64_t getDuration() const
{
return _ms;
}
private:
std::string _description;
std::chrono::time_point<std::chrono::system_clock> _start;
uint64_t _ms;
bool _reported;
private:
std::string _description;
std::chrono::time_point<std::chrono::system_clock> _start;
uint64_t _ms;
bool _reported;
};
void WebSocketSender::sendMessage(const std::string& filename,
bool throttle)
void WebSocketSender::sendMessage(const std::string& filename, bool throttle)
{
std::vector<uint8_t> content;
{
@ -239,9 +233,7 @@ namespace ix
MsgPack msg(pdu);
Bench bench("Sending file through websocket");
_webSocket.sendBinary(msg.dump(),
[throttle](int current, int total) -> bool
{
_webSocket.sendBinary(msg.dump(), [throttle](int current, int total) -> bool {
std::cout << "ws_send: Step " << current << " out of " << total << std::endl;
if (throttle)
@ -256,8 +248,7 @@ namespace ix
do
{
size_t bufferedAmount = _webSocket.bufferedAmount();
std::cout << "ws_send: " << bufferedAmount
<< " bytes left to be sent" << std::endl;
std::cout << "ws_send: " << bufferedAmount << " bytes left to be sent" << std::endl;
std::chrono::duration<double, std::milli> duration(10);
std::this_thread::sleep_for(duration);
@ -289,8 +280,7 @@ namespace ix
webSocketSender.stop();
}
int ws_send_main(const std::string& url,
const std::string& path)
int ws_send_main(const std::string& url, const std::string& path)
{
bool throttle = false;
bool enablePerMessageDeflate = false;
@ -298,4 +288,4 @@ namespace ix
wsSend(url, path, enablePerMessageDeflate, throttle);
return 0;
}
}
} // namespace ix

View File

@ -5,10 +5,9 @@
*/
#include "IXSnakeServer.h"
#include <fstream>
#include <iostream>
#include <sstream>
#include <fstream>
namespace
{
@ -24,7 +23,7 @@ namespace
file.seekg(0, file.beg);
memblock.resize((size_t) size);
file.read((char*)&memblock.front(), static_cast<std::streamsize>(size));
file.read((char*) &memblock.front(), static_cast<std::streamsize>(size));
return memblock;
}
@ -34,7 +33,7 @@ namespace
auto vec = load(path);
return std::string(vec.begin(), vec.end());
}
}
} // namespace
namespace ix
{
@ -80,4 +79,4 @@ namespace ix
return 0; // should never reach this
}
}
} // namespace ix

View File

@ -5,8 +5,8 @@
*/
#include <iostream>
#include <sstream>
#include <ixwebsocket/IXWebSocketServer.h>
#include <sstream>
namespace ix
{
@ -16,76 +16,67 @@ namespace ix
ix::WebSocketServer server(port, hostname);
server.setOnConnectionCallback(
[&server](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState)
{
webSocket->setOnMessageCallback(
[webSocket, connectionState, &server](const WebSocketMessagePtr& msg)
server.setOnConnectionCallback([&server](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState) {
webSocket->setOnMessageCallback([webSocket, connectionState, &server](
const WebSocketMessagePtr& msg) {
if (msg->type == ix::WebSocketMessageType::Open)
{
std::cerr << "New connection" << std::endl;
std::cerr << "id: " << connectionState->getId() << std::endl;
std::cerr << "Uri: " << msg->openInfo.uri << std::endl;
std::cerr << "Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
if (msg->type == ix::WebSocketMessageType::Open)
std::cerr << it.first << ": " << it.second << std::endl;
}
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
std::cerr << "Closed connection"
<< " code " << msg->closeInfo.code << " reason "
<< msg->closeInfo.reason << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
std::cerr << ss.str();
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
std::cerr << "Received message fragment " << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
for (auto&& client : server.getClients())
{
if (client != webSocket)
{
std::cerr << "New connection" << std::endl;
std::cerr << "id: " << connectionState->getId() << std::endl;
std::cerr << "Uri: " << msg->openInfo.uri << std::endl;
std::cerr << "Headers:" << std::endl;
for (auto it : msg->openInfo.headers)
{
std::cerr << it.first << ": " << it.second << std::endl;
}
}
else if (msg->type == ix::WebSocketMessageType::Close)
{
std::cerr << "Closed connection"
<< " code " << msg->closeInfo.code
<< " reason " << msg->closeInfo.reason << std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Error)
{
std::stringstream ss;
ss << "Connection error: " << msg->errorInfo.reason << std::endl;
ss << "#retries: " << msg->errorInfo.retries << std::endl;
ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl;
ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl;
std::cerr << ss.str();
}
else if (msg->type == ix::WebSocketMessageType::Fragment)
{
std::cerr << "Received message fragment "
<< std::endl;
}
else if (msg->type == ix::WebSocketMessageType::Message)
{
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
for (auto&& client : server.getClients())
{
if (client != webSocket)
{
client->send(msg->str,
msg->binary,
[](int current, int total) -> bool
{
std::cerr << "ws_transfer: Step " << current
<< " out of " << total << std::endl;
return true;
});
client->send(msg->str, msg->binary, [](int current, int total) -> bool {
std::cerr << "ws_transfer: Step " << current << " out of " << total
<< std::endl;
return true;
});
do
{
size_t bufferedAmount = client->bufferedAmount();
std::cerr << "ws_transfer: " << bufferedAmount
<< " bytes left to be sent" << std::endl;
do
{
size_t bufferedAmount = client->bufferedAmount();
std::cerr << "ws_transfer: " << bufferedAmount
<< " bytes left to be sent" << std::endl;
std::chrono::duration<double, std::milli> duration(10);
std::this_thread::sleep_for(duration);
} while (client->bufferedAmount() != 0);
}
}
std::chrono::duration<double, std::milli> duration(10);
std::this_thread::sleep_for(duration);
} while (client->bufferedAmount() != 0);
}
}
);
}
);
}
});
});
auto res = server.listen();
if (!res.first)
@ -99,4 +90,4 @@ namespace ix
return 0;
}
}
} // namespace ix