reformat everything with clang-format

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

View File

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

View File

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

View File

@ -5,22 +5,22 @@
*/ */
#include "IXDNSLookup.h" #include "IXDNSLookup.h"
#include "IXNetSystem.h"
#include <string.h> #include "IXNetSystem.h"
#include <chrono> #include <chrono>
#include <string.h>
#include <thread> #include <thread>
namespace ix namespace ix
{ {
const int64_t DNSLookup::kDefaultWait = 1; // ms const int64_t DNSLookup::kDefaultWait = 1; // ms
DNSLookup::DNSLookup(const std::string& hostname, int port, int64_t wait) : DNSLookup::DNSLookup(const std::string& hostname, int port, int64_t wait)
_hostname(hostname), : _hostname(hostname)
_port(port), , _port(port)
_wait(wait), , _wait(wait)
_res(nullptr), , _res(nullptr)
_done(false) , _done(false)
{ {
; ;
} }
@ -38,8 +38,7 @@ namespace ix
std::string sport = std::to_string(port); std::string sport = std::to_string(port);
struct addrinfo* res; struct addrinfo* res;
int getaddrinfo_result = getaddrinfo(hostname.c_str(), sport.c_str(), int getaddrinfo_result = getaddrinfo(hostname.c_str(), sport.c_str(), &hints, &res);
&hints, &res);
if (getaddrinfo_result) if (getaddrinfo_result)
{ {
errMsg = gai_strerror(getaddrinfo_result); errMsg = gai_strerror(getaddrinfo_result);
@ -56,8 +55,8 @@ namespace ix
: resolveUnCancellable(errMsg, isCancellationRequested); : resolveUnCancellable(errMsg, isCancellationRequested);
} }
struct addrinfo* DNSLookup::resolveUnCancellable(std::string& errMsg, struct addrinfo* DNSLookup::resolveUnCancellable(
const CancellationRequest& isCancellationRequested) std::string& errMsg, const CancellationRequest& isCancellationRequested)
{ {
errMsg = "no error"; errMsg = "no error";
@ -71,8 +70,8 @@ namespace ix
return getAddrInfo(_hostname, _port, errMsg); return getAddrInfo(_hostname, _port, errMsg);
} }
struct addrinfo* DNSLookup::resolveCancellable(std::string& errMsg, struct addrinfo* DNSLookup::resolveCancellable(
const CancellationRequest& isCancellationRequested) std::string& errMsg, const CancellationRequest& isCancellationRequested)
{ {
errMsg = "no error"; errMsg = "no error";
@ -126,7 +125,9 @@ namespace ix
return getRes(); 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 // 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 // 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); std::lock_guard<std::mutex> lock(_resMutex);
return _res; return _res;
} }
} } // namespace ix

View File

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

View File

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

View File

@ -5,9 +5,9 @@
*/ */
#include "IXHttp.h" #include "IXHttp.h"
#include "IXCancellationRequest.h" #include "IXCancellationRequest.h"
#include "IXSocket.h" #include "IXSocket.h"
#include <sstream> #include <sstream>
#include <vector> #include <vector>
@ -57,7 +57,8 @@ namespace ix
return std::make_pair(httpVersion, statusCode); 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 // Request-Line = Method SP Request-URI SP HTTP-Version CRLF
std::string token; std::string token;
@ -161,8 +162,6 @@ namespace ix
return false; return false;
} }
return response->payload.empty() return response->payload.empty() ? true : socket->writeBytes(response->payload, nullptr);
? true
: socket->writeBytes(response->payload, nullptr);
} }
} } // namespace ix

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,14 +5,14 @@
*/ */
#include "IXSocketServer.h" #include "IXSocketServer.h"
#include "IXNetSystem.h"
#include "IXSocket.h" #include "IXSocket.h"
#include "IXSocketConnect.h" #include "IXSocketConnect.h"
#include "IXNetSystem.h" #include <assert.h>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <string.h> #include <string.h>
#include <assert.h>
namespace ix namespace ix
{ {
@ -24,17 +24,16 @@ namespace ix
SocketServer::SocketServer(int port, SocketServer::SocketServer(int port,
const std::string& host, const std::string& host,
int backlog, int backlog,
size_t maxConnections) : size_t maxConnections)
_port(port), : _port(port)
_host(host), , _host(host)
_backlog(backlog), , _backlog(backlog)
_maxConnections(maxConnections), , _maxConnections(maxConnections)
_serverFd(-1), , _serverFd(-1)
_stop(false), , _stop(false)
_stopGc(false), , _stopGc(false)
_connectionStateFactory(&ConnectionState::createConnectionState) , _connectionStateFactory(&ConnectionState::createConnectionState)
{ {
} }
SocketServer::~SocketServer() SocketServer::~SocketServer()
@ -62,21 +61,18 @@ namespace ix
if ((_serverFd = socket(AF_INET, SOCK_STREAM, 0)) < 0) if ((_serverFd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{ {
std::stringstream ss; std::stringstream ss;
ss << "SocketServer::listen() error creating socket): " ss << "SocketServer::listen() error creating socket): " << strerror(Socket::getErrno());
<< strerror(Socket::getErrno());
return std::make_pair(false, ss.str()); return std::make_pair(false, ss.str());
} }
// Make that socket reusable. (allow restarting this server at will) // Make that socket reusable. (allow restarting this server at will)
int enable = 1; int enable = 1;
if (setsockopt(_serverFd, SOL_SOCKET, SO_REUSEADDR, if (setsockopt(_serverFd, SOL_SOCKET, SO_REUSEADDR, (char*) &enable, sizeof(enable)) < 0)
(char*) &enable, sizeof(enable)) < 0)
{ {
std::stringstream ss; std::stringstream ss;
ss << "SocketServer::listen() error calling setsockopt(SO_REUSEADDR) " ss << "SocketServer::listen() error calling setsockopt(SO_REUSEADDR) "
<< "at address " << _host << ":" << _port << "at address " << _host << ":" << _port << " : " << strerror(Socket::getErrno());
<< " : " << strerror(Socket::getErrno());
Socket::closeSocket(_serverFd); Socket::closeSocket(_serverFd);
return std::make_pair(false, ss.str()); return std::make_pair(false, ss.str());
@ -95,12 +91,11 @@ namespace ix
// //
server.sin_addr.s_addr = inet_addr(_host.c_str()); 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; std::stringstream ss;
ss << "SocketServer::listen() error calling bind " ss << "SocketServer::listen() error calling bind "
<< "at address " << _host << ":" << _port << "at address " << _host << ":" << _port << " : " << strerror(Socket::getErrno());
<< " : " << strerror(Socket::getErrno());
Socket::closeSocket(_serverFd); Socket::closeSocket(_serverFd);
return std::make_pair(false, ss.str()); return std::make_pair(false, ss.str());
@ -113,8 +108,7 @@ namespace ix
{ {
std::stringstream ss; std::stringstream ss;
ss << "SocketServer::listen() error calling listen " ss << "SocketServer::listen() error calling listen "
<< "at address " << _host << ":" << _port << "at address " << _host << ":" << _port << " : " << strerror(Socket::getErrno());
<< " : " << strerror(Socket::getErrno());
Socket::closeSocket(_serverFd); Socket::closeSocket(_serverFd);
return std::make_pair(false, ss.str()); return std::make_pair(false, ss.str());
@ -221,8 +215,7 @@ namespace ix
if (pollResult == PollResultType::Error) if (pollResult == PollResultType::Error)
{ {
std::stringstream ss; std::stringstream ss;
ss << "SocketServer::run() error in select: " ss << "SocketServer::run() error in select: " << strerror(Socket::getErrno());
<< strerror(Socket::getErrno());
logError(ss.str()); logError(ss.str());
continue; continue;
} }
@ -238,15 +231,15 @@ namespace ix
socklen_t addressLen = sizeof(client); socklen_t addressLen = sizeof(client);
memset(&client, 0, 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()) if (!Socket::isWaitNeeded())
{ {
// FIXME: that error should be propagated // FIXME: that error should be propagated
int err = Socket::getErrno(); int err = Socket::getErrno();
std::stringstream ss; std::stringstream ss;
ss << "SocketServer::run() error accepting connection: " ss << "SocketServer::run() error accepting connection: " << err << ", "
<< err << ", " << strerror(err); << strerror(err);
logError(ss.str()); logError(ss.str());
} }
continue; continue;
@ -255,8 +248,7 @@ namespace ix
if (getConnectedClientsCount() >= _maxConnections) if (getConnectedClientsCount() >= _maxConnections)
{ {
std::stringstream ss; std::stringstream ss;
ss << "SocketServer::run() reached max connections = " ss << "SocketServer::run() reached max connections = " << _maxConnections << ". "
<< _maxConnections << ". "
<< "Not accepting connection"; << "Not accepting connection";
logError(ss.str()); logError(ss.str());
@ -277,10 +269,7 @@ namespace ix
std::lock_guard<std::mutex> lock(_connectionsThreadsMutex); std::lock_guard<std::mutex> lock(_connectionsThreadsMutex);
_connectionsThreads.push_back(std::make_pair( _connectionsThreads.push_back(std::make_pair(
connectionState, connectionState,
std::thread(&SocketServer::handleConnection, std::thread(&SocketServer::handleConnection, this, clientFd, connectionState)));
this,
clientFd,
connectionState)));
} }
} }
@ -308,5 +297,4 @@ namespace ix
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
} }
} } // namespace ix

View File

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

View File

@ -5,6 +5,7 @@
*/ */
#include "IXUrlParser.h" #include "IXUrlParser.h"
#include "LUrlParser.h" #include "LUrlParser.h"
namespace ix namespace ix
@ -64,4 +65,4 @@ namespace ix
return true; return true;
} }
} } // namespace ix

View File

@ -5,44 +5,44 @@
*/ */
#include "IXUserAgent.h" #include "IXUserAgent.h"
#include "IXWebSocketVersion.h"
#include "IXWebSocketVersion.h"
#include <sstream> #include <sstream>
#include <zlib.h> #include <zlib.h>
// Platform name // Platform name
#if defined(_WIN32) #if defined(_WIN32)
#define PLATFORM_NAME "windows" // Windows #define PLATFORM_NAME "windows" // Windows
#elif defined(_WIN64) #elif defined(_WIN64)
#define PLATFORM_NAME "windows" // Windows #define PLATFORM_NAME "windows" // Windows
#elif defined(__CYGWIN__) && !defined(_WIN32) #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__) #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__) #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__) #elif defined(__unix__) || !defined(__APPLE__) && defined(__MACH__)
#include <sys/param.h> #include <sys/param.h>
#if defined(BSD) #if defined(BSD)
#define PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD #define PLATFORM_NAME "bsd" // FreeBSD, NetBSD, OpenBSD, DragonFly BSD
#endif #endif
#elif defined(__hpux) #elif defined(__hpux)
#define PLATFORM_NAME "hp-ux" // HP-UX #define PLATFORM_NAME "hp-ux" // HP-UX
#elif defined(_AIX) #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) #elif defined(__APPLE__) && defined(__MACH__) // Apple OSX and iOS (Darwin)
#include <TargetConditionals.h> #include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1 #if TARGET_IPHONE_SIMULATOR == 1
#define PLATFORM_NAME "ios" // Apple iOS #define PLATFORM_NAME "ios" // Apple iOS
#elif TARGET_OS_IPHONE == 1 #elif TARGET_OS_IPHONE == 1
#define PLATFORM_NAME "ios" // Apple iOS #define PLATFORM_NAME "ios" // Apple iOS
#elif TARGET_OS_MAC == 1 #elif TARGET_OS_MAC == 1
#define PLATFORM_NAME "macos" // Apple OSX #define PLATFORM_NAME "macos" // Apple OSX
#endif #endif
#elif defined(__sun) && defined(__SVR4) #elif defined(__sun) && defined(__SVR4)
#define PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana #define PLATFORM_NAME "solaris" // Oracle Solaris, Open Indiana
#else #else
#define PLATFORM_NAME "unknown platform" #define PLATFORM_NAME "unknown platform"
#endif #endif
// SSL // SSL
@ -80,4 +80,4 @@ namespace ix
return ss.str(); return ss.str();
} }
} } // namespace ix

View File

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

View File

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

View File

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

View File

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

View File

@ -49,8 +49,7 @@ namespace ix
WebSocketPerMessageDeflateOptions& perMessageDeflateOptions, WebSocketPerMessageDeflateOptions& perMessageDeflateOptions,
std::atomic<bool>& enablePerMessageDeflate); std::atomic<bool>& enablePerMessageDeflate);
WebSocketInitResult clientHandshake( WebSocketInitResult clientHandshake(const std::string& url,
const std::string& url,
const WebSocketHttpHeaders& extraHeaders, const WebSocketHttpHeaders& extraHeaders,
const std::string& host, const std::string& host,
const std::string& path, const std::string& path,

View File

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

View File

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

View File

@ -41,19 +41,21 @@
* - Added more documentation. * - Added more documentation.
* *
* Per message Deflate RFC: https://tools.ietf.org/html/rfc7692 * 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 "IXWebSocketPerMessageDeflate.h"
#include "IXWebSocketPerMessageDeflateOptions.h"
#include "IXWebSocketPerMessageDeflateCodec.h" #include "IXWebSocketPerMessageDeflateCodec.h"
#include "IXWebSocketPerMessageDeflateOptions.h"
namespace ix namespace ix
{ {
WebSocketPerMessageDeflate::WebSocketPerMessageDeflate() : WebSocketPerMessageDeflate::WebSocketPerMessageDeflate()
_compressor(std::make_unique<WebSocketPerMessageDeflateCompressor>()), : _compressor(std::make_unique<WebSocketPerMessageDeflateCompressor>())
_decompressor(std::make_unique<WebSocketPerMessageDeflateDecompressor>()) , _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 = bool clientNoContextTakeover = perMessageDeflateOptions.getClientNoContextTakeover();
perMessageDeflateOptions.getClientNoContextTakeover();
uint8_t deflateBits = perMessageDeflateOptions.getClientMaxWindowBits(); uint8_t deflateBits = perMessageDeflateOptions.getClientMaxWindowBits();
uint8_t inflateBits = perMessageDeflateOptions.getServerMaxWindowBits(); uint8_t inflateBits = perMessageDeflateOptions.getServerMaxWindowBits();
@ -75,16 +77,14 @@ namespace ix
_decompressor->init(inflateBits, clientNoContextTakeover); _decompressor->init(inflateBits, clientNoContextTakeover);
} }
bool WebSocketPerMessageDeflate::compress(const std::string& in, bool WebSocketPerMessageDeflate::compress(const std::string& in, std::string& out)
std::string& out)
{ {
return _compressor->compress(in, out); return _compressor->compress(in, out);
} }
bool WebSocketPerMessageDeflate::decompress(const std::string& in, bool WebSocketPerMessageDeflate::decompress(const std::string& in, std::string& out)
std::string &out)
{ {
return _decompressor->decompress(in, out); return _decompressor->decompress(in, out);
} }
} } // namespace ix

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -32,31 +32,40 @@
#include <stdlib.h> #include <stdlib.h>
// check if the scheme name is valid // 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 ) for (auto c : SchemeName)
{ {
if ( !isalpha( c ) && c != '+' && c != '-' && c != '.' ) return false; 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 // 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;
@ -65,31 +74,33 @@ LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL
/* /*
* <scheme>:<scheme-specific-part> * <scheme>:<scheme-specific-part>
* <scheme> := [a-z\+\-\.]+ * <scheme> := [a-z\+\-\.]+
* For resiliency, programs interpreting URLs should treat upper case letters as equivalent to lower case in scheme names * For resiliency, programs interpreting URLs should treat upper case letters as equivalent to
*lower case in scheme names
*/ */
// try to read scheme // try to read scheme
{ {
const char* LocalString = strchr( CurrentString, ':' ); const char* LocalString = strchr(CurrentString, ':');
if ( !LocalString ) if (!LocalString)
{ {
return clParseURL( LUrlParserError_NoUrlCharacter ); return clParseURL(LUrlParserError_NoUrlCharacter);
} }
// save the scheme name // save the scheme name
Result.m_Scheme = std::string( CurrentString, LocalString - CurrentString ); Result.m_Scheme = std::string(CurrentString, LocalString - CurrentString);
if ( !IsSchemeValid( Result.m_Scheme ) ) if (!IsSchemeValid(Result.m_Scheme))
{ {
return clParseURL( LUrlParserError_InvalidSchemeName ); return clParseURL(LUrlParserError_InvalidSchemeName);
} }
// scheme should be lowercase // scheme should be lowercase
std::transform( Result.m_Scheme.begin(), Result.m_Scheme.end(), Result.m_Scheme.begin(), ::tolower ); std::transform(
Result.m_Scheme.begin(), Result.m_Scheme.end(), Result.m_Scheme.begin(), ::tolower);
// skip ':' // skip ':'
CurrentString = LocalString+1; CurrentString = LocalString + 1;
} }
/* /*
@ -98,23 +109,23 @@ LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL
*/ */
// skip "//" // skip "//"
if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError_NoDoubleSlash ); if (*CurrentString++ != '/') return clParseURL(LUrlParserError_NoDoubleSlash);
if ( *CurrentString++ != '/' ) return clParseURL( LUrlParserError_NoDoubleSlash ); if (*CurrentString++ != '/') return clParseURL(LUrlParserError_NoDoubleSlash);
// check if the user name and password are specified // check if the user name and password are specified
bool bHasUserName = false; bool bHasUserName = false;
const char* LocalString = CurrentString; const char* LocalString = CurrentString;
while ( *LocalString ) while (*LocalString)
{ {
if ( *LocalString == '@' ) if (*LocalString == '@')
{ {
// user name and password are specified // user name and password are specified
bHasUserName = true; bHasUserName = true;
break; break;
} }
else if ( *LocalString == '/' ) else if (*LocalString == '/')
{ {
// end of <host>:<port> specification // end of <host>:<port> specification
bHasUserName = false; bHasUserName = false;
@ -127,17 +138,18 @@ LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL
// user name and password // user name and password
LocalString = CurrentString; LocalString = CurrentString;
if ( bHasUserName ) if (bHasUserName)
{ {
// read user name // read user name
while ( *LocalString && *LocalString != ':' && *LocalString != '@' ) LocalString++; 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 // proceed with the current pointer
CurrentString = LocalString; CurrentString = LocalString;
if ( *CurrentString == ':' ) if (*CurrentString == ':')
{ {
// skip ':' // skip ':'
CurrentString++; CurrentString++;
@ -145,36 +157,37 @@ LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL
// read password // read password
LocalString = CurrentString; 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 '@' // skip '@'
if ( *CurrentString != '@' ) if (*CurrentString != '@')
{ {
return clParseURL( LUrlParserError_NoAtSign ); return clParseURL(LUrlParserError_NoAtSign);
} }
CurrentString++; CurrentString++;
} }
bool bHasBracket = ( *CurrentString == '[' ); bool bHasBracket = (*CurrentString == '[');
// go ahead, read the host name // go ahead, read the host name
LocalString = CurrentString; LocalString = CurrentString;
while ( *LocalString ) while (*LocalString)
{ {
if ( bHasBracket && *LocalString == ']' ) if (bHasBracket && *LocalString == ']')
{ {
// end of IPv6 address // end of IPv6 address
LocalString++; LocalString++;
break; break;
} }
else if ( !bHasBracket && ( *LocalString == ':' || *LocalString == '/' ) ) else if (!bHasBracket && (*LocalString == ':' || *LocalString == '/'))
{ {
// port number is specified // port number is specified
break; break;
@ -183,27 +196,28 @@ LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL
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? // is port number specified?
if ( *CurrentString == ':' ) if (*CurrentString == ':')
{ {
CurrentString++; CurrentString++;
// read port number // read port number
LocalString = CurrentString; 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 // end of string
if ( !*CurrentString ) if (!*CurrentString)
{ {
Result.m_ErrorCode = LUrlParserError_Ok; Result.m_ErrorCode = LUrlParserError_Ok;
@ -211,9 +225,9 @@ LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL
} }
// skip '/' // skip '/'
if ( *CurrentString != '/' ) if (*CurrentString != '/')
{ {
return clParseURL( LUrlParserError_NoSlash ); return clParseURL(LUrlParserError_NoSlash);
} }
CurrentString++; CurrentString++;
@ -221,14 +235,15 @@ LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL
// parse the path // parse the path
LocalString = CurrentString; 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 // check for query
if ( *CurrentString == '?' ) if (*CurrentString == '?')
{ {
// skip '?' // skip '?'
CurrentString++; CurrentString++;
@ -236,15 +251,16 @@ LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL
// read query // read query
LocalString = CurrentString; 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 // check for fragment
if ( *CurrentString == '#' ) if (*CurrentString == '#')
{ {
// skip '#' // skip '#'
CurrentString++; CurrentString++;
@ -252,9 +268,10 @@ LUrlParser::clParseURL LUrlParser::clParseURL::ParseURL( const std::string& URL
// read fragment // read fragment
LocalString = CurrentString; 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;

View File

@ -62,7 +62,10 @@ namespace LUrlParser
} }
/// return 'true' if the parsing was successful /// 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 /// helper to convert the port number to int, return 'true' if the port is valid (within the
/// 0..65535 range) /// 0..65535 range)

View File

@ -17,4 +17,4 @@ namespace ix
// //
pthread_setname_np(name.substr(0, 63).c_str()); 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 // See prctl and PR_SET_NAME property in
// http://man7.org/linux/man-pages/man2/prctl.2.html // http://man7.org/linux/man-pages/man2/prctl.2.html
// //
pthread_setname_np(pthread_self(), pthread_setname_np(pthread_self(), name.substr(0, 15).c_str());
name.substr(0, 15).c_str());
} }
} } // namespace ix

View File

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

View File

@ -4,14 +4,13 @@
* Copyright (c) 2017 Machine Zone. All rights reserved. * Copyright (c) 2017 Machine Zone. All rights reserved.
*/ */
#include <iostream> #include "IXSnakeServer.h"
#include "IXTest.h"
#include "catch.hpp"
#include <chrono> #include <chrono>
#include <iostream>
#include <ixcobra/IXCobraConnection.h> #include <ixcobra/IXCobraConnection.h>
#include <ixcrypto/IXUuid.h> #include <ixcrypto/IXUuid.h>
#include "IXTest.h"
#include "IXSnakeServer.h"
#include "catch.hpp"
using namespace ix; using namespace ix;
@ -22,9 +21,7 @@ namespace
void setupTrafficTrackerCallback() void setupTrafficTrackerCallback()
{ {
ix::CobraConnection::setTrafficTrackerCallback( ix::CobraConnection::setTrafficTrackerCallback([](size_t size, bool incoming) {
[](size_t size, bool incoming)
{
if (incoming) if (incoming)
{ {
incomingBytes += size; incomingBytes += size;
@ -33,8 +30,7 @@ namespace
{ {
outgoingBytes += size; outgoingBytes += size;
} }
} });
);
} }
class SatoriChat class SatoriChat
@ -77,12 +73,12 @@ namespace
SatoriChat::SatoriChat(const std::string& user, SatoriChat::SatoriChat(const std::string& user,
const std::string& session, const std::string& session,
const std::string& endpoint) : const std::string& endpoint)
_user(user), : _user(user)
_session(session), , _session(session)
_endpoint(endpoint), , _endpoint(endpoint)
_stop(false), , _stop(false)
_connectedAndSubscribed(false) , _connectedAndSubscribed(false)
{ {
} }
@ -127,9 +123,7 @@ namespace
void SatoriChat::subscribe(const std::string& channel) void SatoriChat::subscribe(const std::string& channel)
{ {
std::string filter; std::string filter;
_conn.subscribe(channel, filter, _conn.subscribe(channel, filter, [this](const Json::Value& msg) {
[this](const Json::Value& msg)
{
std::cout << msg.toStyledString() << std::endl; std::cout << msg.toStyledString() << std::endl;
if (!msg.isObject()) return; if (!msg.isObject()) return;
if (!msg.isMember("user")) return; if (!msg.isMember("user")) return;
@ -150,10 +144,7 @@ namespace
_receivedQueue.push(msg); _receivedQueue.push(msg);
std::stringstream ss; std::stringstream ss;
ss << std::endl ss << std::endl << msg_user << " > " << msg_text << std::endl << _user << " > ";
<< msg_user << " > " << msg_text
<< std::endl
<< _user << " > ";
log(ss.str()); log(ss.str());
}); });
} }
@ -189,18 +180,15 @@ namespace
std::string role = "_sub"; std::string role = "_sub";
std::string secret = "66B1dA3ED5fA074EB5AE84Dd8CE3b5ba"; std::string secret = "66B1dA3ED5fA074EB5AE84Dd8CE3b5ba";
_conn.configure(appkey, _endpoint, role, secret, _conn.configure(
ix::WebSocketPerMessageDeflateOptions(true)); appkey, _endpoint, role, secret, ix::WebSocketPerMessageDeflateOptions(true));
_conn.connect(); _conn.connect();
_conn.setEventCallback( _conn.setEventCallback([this, channel](ix::CobraConnectionEventType eventType,
[this, channel]
(ix::CobraConnectionEventType eventType,
const std::string& errMsg, const std::string& errMsg,
const ix::WebSocketHttpHeaders& /*headers*/, const ix::WebSocketHttpHeaders& /*headers*/,
const std::string& subscriptionId, const std::string& subscriptionId,
CobraConnection::MsgId msgId) CobraConnection::MsgId msgId) {
{
if (eventType == ix::CobraConnection_EventType_Open) if (eventType == ix::CobraConnection_EventType_Open)
{ {
log("Subscriber connected: " + _user); log("Subscriber connected: " + _user);
@ -231,8 +219,7 @@ namespace
{ {
Logger() << "Subscriber: published message acked: " << msgId; Logger() << "Subscriber: published message acked: " << msgId;
} }
} });
);
while (!_stop) while (!_stop)
{ {
@ -261,19 +248,15 @@ namespace
ix::msleep(50); ix::msleep(50);
_conn.disconnect(); _conn.disconnect();
_conn.setEventCallback([] _conn.setEventCallback([](ix::CobraConnectionEventType /*eventType*/,
(ix::CobraConnectionEventType /*eventType*/,
const std::string& /*errMsg*/, const std::string& /*errMsg*/,
const ix::WebSocketHttpHeaders& /*headers*/, const ix::WebSocketHttpHeaders& /*headers*/,
const std::string& /*subscriptionId*/, const std::string& /*subscriptionId*/,
CobraConnection::MsgId /*msgId*/) CobraConnection::MsgId /*msgId*/) { ; });
{
;
});
snakeServer.stop(); snakeServer.stop();
} }
} } // namespace
TEST_CASE("Cobra_chat", "[cobra_chat]") TEST_CASE("Cobra_chat", "[cobra_chat]")
{ {

View File

@ -3,14 +3,13 @@
* Copyright (c) 2018 Machine Zone. All rights reserved. * 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 "IXSnakeServer.h"
#include "IXTest.h"
#include "catch.hpp" #include "catch.hpp"
#include <iostream>
#include <ixcobra/IXCobraMetricsPublisher.h>
#include <ixcrypto/IXUuid.h>
#include <set>
using namespace ix; using namespace ix;
@ -45,18 +44,18 @@ namespace
gMessageCount = 0; gMessageCount = 0;
ix::CobraConnection conn; ix::CobraConnection conn;
conn.configure(APPKEY, endpoint, SUBSCRIBER_ROLE, SUBSCRIBER_SECRET, conn.configure(APPKEY,
endpoint,
SUBSCRIBER_ROLE,
SUBSCRIBER_SECRET,
ix::WebSocketPerMessageDeflateOptions(true)); ix::WebSocketPerMessageDeflateOptions(true));
conn.connect(); conn.connect();
conn.setEventCallback( conn.setEventCallback([&conn](ix::CobraConnectionEventType eventType,
[&conn]
(ix::CobraConnectionEventType eventType,
const std::string& errMsg, const std::string& errMsg,
const ix::WebSocketHttpHeaders& /*headers*/, const ix::WebSocketHttpHeaders& /*headers*/,
const std::string& subscriptionId, const std::string& subscriptionId,
CobraConnection::MsgId msgId) CobraConnection::MsgId msgId) {
{
if (eventType == ix::CobraConnection_EventType_Open) if (eventType == ix::CobraConnection_EventType_Open)
{ {
Logger() << "Subscriber connected:"; Logger() << "Subscriber connected:";
@ -69,9 +68,7 @@ namespace
{ {
log("Subscriber authenticated"); log("Subscriber authenticated");
std::string filter; std::string filter;
conn.subscribe(CHANNEL, filter, conn.subscribe(CHANNEL, filter, [](const Json::Value& msg) {
[](const Json::Value& msg)
{
log(msg.toStyledString()); log(msg.toStyledString());
std::string id = msg["id"].asString(); std::string id = msg["id"].asString();
@ -107,8 +104,7 @@ namespace
{ {
Logger() << "Subscriber: published message acked: " << msgId; Logger() << "Subscriber: published message acked: " << msgId;
} }
} });
);
while (!gStop) while (!gStop)
{ {
@ -121,7 +117,7 @@ namespace
gUniqueMessageIdsCount = gIds.size(); gUniqueMessageIdsCount = gIds.size();
} }
} } // namespace
TEST_CASE("Cobra_Metrics_Publisher", "[cobra]") TEST_CASE("Cobra_Metrics_Publisher", "[cobra]")
{ {
@ -158,8 +154,8 @@ TEST_CASE("Cobra_Metrics_Publisher", "[cobra]")
ix::CobraMetricsPublisher cobraMetricsPublisher; ix::CobraMetricsPublisher cobraMetricsPublisher;
bool perMessageDeflate = true; bool perMessageDeflate = true;
cobraMetricsPublisher.configure(APPKEY, endpoint, CHANNEL, cobraMetricsPublisher.configure(
PUBLISHER_ROLE, PUBLISHER_SECRET, perMessageDeflate); APPKEY, endpoint, CHANNEL, PUBLISHER_ROLE, PUBLISHER_SECRET, perMessageDeflate);
cobraMetricsPublisher.setSession(uuid4()); cobraMetricsPublisher.setSession(uuid4());
cobraMetricsPublisher.enable(true); // disabled by default, needs to be enabled to be active cobraMetricsPublisher.enable(true); // disabled by default, needs to be enabled to be active
@ -205,7 +201,7 @@ TEST_CASE("Cobra_Metrics_Publisher", "[cobra]")
log("Testing suspend/resume now, which will disconnect the cobraMetricsPublisher."); log("Testing suspend/resume now, which will disconnect the cobraMetricsPublisher.");
// Test suspend + resume // Test suspend + resume
for (int i = 0 ; i < 3 ; ++i) for (int i = 0; i < 3; ++i)
{ {
cobraMetricsPublisher.suspend(); cobraMetricsPublisher.suspend();
ix::msleep(500); ix::msleep(500);

View File

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

View File

@ -5,11 +5,11 @@
*/ */
#include "IXGetFreePort.h" #include "IXGetFreePort.h"
#include <ixwebsocket/IXNetSystem.h> #include <ixwebsocket/IXNetSystem.h>
#include <ixwebsocket/IXSocket.h> #include <ixwebsocket/IXSocket.h>
#include <string>
#include <random> #include <random>
#include <string>
namespace ix namespace ix
{ {
@ -30,8 +30,7 @@ namespace ix
} }
int enable = 1; int enable = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*) &enable, sizeof(enable)) < 0)
(char*) &enable, sizeof(enable)) < 0)
{ {
return getAnyFreePortRandom(); return getAnyFreePortRandom();
} }
@ -42,7 +41,7 @@ namespace ix
server.sin_port = htons(0); server.sin_port = htons(0);
server.sin_addr.s_addr = inet_addr("127.0.0.1"); 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); Socket::closeSocket(sockfd);
return getAnyFreePortRandom(); return getAnyFreePortRandom();
@ -50,7 +49,7 @@ namespace ix
struct sockaddr_in sa; // server address information struct sockaddr_in sa; // server address information
socklen_t len = sizeof(sa); socklen_t len = sizeof(sa);
if (getsockname(sockfd, (struct sockaddr *) &sa, &len) < 0) if (getsockname(sockfd, (struct sockaddr*) &sa, &len) < 0)
{ {
Socket::closeSocket(sockfd); Socket::closeSocket(sockfd);
return getAnyFreePortRandom(); return getAnyFreePortRandom();
@ -67,11 +66,11 @@ namespace ix
while (true) while (true)
{ {
#if defined(__has_feature) #if defined(__has_feature)
# if __has_feature(address_sanitizer) #if __has_feature(address_sanitizer)
int port = getAnyFreePortRandom(); int port = getAnyFreePortRandom();
# else #else
int port = getAnyFreePort(); int port = getAnyFreePort();
# endif #endif
#else #else
int port = getAnyFreePort(); int port = getAnyFreePort();
#endif #endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,19 +5,19 @@
*/ */
#include "IXTest.h" #include "IXTest.h"
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXNetSystem.h>
#include <chrono> #include <chrono>
#include <thread>
#include <mutex>
#include <string>
#include <fstream> #include <fstream>
#include <iostream>
#include <stdlib.h>
#include <stack>
#include <iomanip> #include <iomanip>
#include <iostream>
#include <ixwebsocket/IXNetSystem.h>
#include <ixwebsocket/IXWebSocket.h>
#include <mutex>
#include <random> #include <random>
#include <stack>
#include <stdlib.h>
#include <string>
#include <thread>
namespace ix namespace ix
@ -29,9 +29,7 @@ namespace ix
void setupWebSocketTrafficTrackerCallback() void setupWebSocketTrafficTrackerCallback()
{ {
ix::WebSocket::setTrafficTrackerCallback( ix::WebSocket::setTrafficTrackerCallback([](size_t size, bool incoming) {
[](size_t size, bool incoming)
{
if (incoming) if (incoming)
{ {
incomingBytes += size; incomingBytes += size;
@ -40,8 +38,7 @@ namespace ix
{ {
outgoingBytes += size; outgoingBytes += size;
} }
} });
);
} }
void reportWebSocketTraffic() void reportWebSocketTraffic()
@ -61,8 +58,7 @@ namespace ix
{ {
auto now = std::chrono::system_clock::now(); auto now = std::chrono::system_clock::now();
auto seconds = auto seconds =
std::chrono::duration_cast<std::chrono::seconds>( std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count();
now.time_since_epoch()).count();
return std::to_string(seconds); return std::to_string(seconds);
} }
@ -72,18 +68,15 @@ namespace ix
Logger() << msg; Logger() << msg;
} }
void hexDump(const std::string& prefix, void hexDump(const std::string& prefix, const std::string& s)
const std::string& s)
{ {
std::ostringstream ss; std::ostringstream ss;
bool upper_case = false; bool upper_case = false;
for (std::string::size_type i = 0; i < s.length(); ++i) for (std::string::size_type i = 0; i < s.length(); ++i)
{ {
ss << std::hex ss << std::hex << std::setfill('0') << std::setw(2)
<< std::setfill('0') << (upper_case ? std::uppercase : std::nouppercase) << (int) s[i];
<< std::setw(2)
<< (upper_case ? std::uppercase : std::nouppercase) << (int)s[i];
} }
std::cout << prefix << ": " << s << " => " << ss.str() << std::endl; std::cout << prefix << ": " << s << " => " << ss.str() << std::endl;
@ -91,13 +84,10 @@ namespace ix
bool startWebSocketEchoServer(ix::WebSocketServer& server) bool startWebSocketEchoServer(ix::WebSocketServer& server)
{ {
server.setOnConnectionCallback( server.setOnConnectionCallback([&server](std::shared_ptr<ix::WebSocket> webSocket,
[&server](std::shared_ptr<ix::WebSocket> webSocket, std::shared_ptr<ConnectionState> connectionState) {
std::shared_ptr<ConnectionState> connectionState)
{
webSocket->setOnMessageCallback( webSocket->setOnMessageCallback(
[webSocket, connectionState, &server](const ix::WebSocketMessagePtr& msg) [webSocket, connectionState, &server](const ix::WebSocketMessagePtr& msg) {
{
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
Logger() << "New connection"; Logger() << "New connection";
@ -122,10 +112,8 @@ namespace ix
} }
} }
} }
} });
); });
}
);
auto res = server.listen(); auto res = server.listen();
if (!res.first) if (!res.first)
@ -150,7 +138,7 @@ namespace ix
file.seekg(0, file.beg); file.seekg(0, file.beg);
memblock.resize((size_t) size); 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; return memblock;
} }
@ -190,4 +178,4 @@ namespace ix
return appConfig; return appConfig;
} }
} } // namespace ix

View File

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

View File

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

View File

@ -4,20 +4,18 @@
* Copyright (c) 2019 Machine Zone. All rights reserved. * Copyright (c) 2019 Machine Zone. All rights reserved.
*/ */
#include <iostream>
#include <ixwebsocket/IXUrlParser.h>
#include "IXTest.h" #include "IXTest.h"
#include "catch.hpp" #include "catch.hpp"
#include <iostream>
#include <ixwebsocket/IXUrlParser.h>
#include <string.h> #include <string.h>
using namespace ix; using namespace ix;
namespace ix namespace ix
{ {
TEST_CASE("urlParser", "[urlParser]")
TEST_CASE("urlParser", "[urlParser]") {
{
SECTION("http://google.com") SECTION("http://google.com")
{ {
std::string url = "http://google.com"; std::string url = "http://google.com";
@ -88,7 +86,12 @@ TEST_CASE("urlParser", "[urlParser]")
SECTION("real test") SECTION("real test")
{ {
std::string url = "ws://127.0.0.1:7350/ws?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTcxNzAwNzIsInVpZCI6ImMwZmZjOGE1LTk4OTktNDAwYi1hNGU5LTJjNWM3NjFmNWQxZiIsInVzbiI6InN2YmhOdlNJSmEifQ.5L8BUbpTA4XAHlSrdwhIVlrlIpRtjExepim7Yh5eEO4&status=true&format=protobuf"; 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; std::string protocol, host, path, query;
int port; int port;
bool res; bool res;
@ -98,11 +101,18 @@ TEST_CASE("urlParser", "[urlParser]")
REQUIRE(res); REQUIRE(res);
REQUIRE(protocol == "ws"); REQUIRE(protocol == "ws");
REQUIRE(host == "127.0.0.1"); REQUIRE(host == "127.0.0.1");
REQUIRE(path == "/ws?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTcxNzAwNzIsInVpZCI6ImMwZmZjOGE1LTk4OTktNDAwYi1hNGU5LTJjNWM3NjFmNWQxZiIsInVzbiI6InN2YmhOdlNJSmEifQ.5L8BUbpTA4XAHlSrdwhIVlrlIpRtjExepim7Yh5eEO4&status=true&format=protobuf"); REQUIRE(path ==
REQUIRE(query == "token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTcxNzAwNzIsInVpZCI6ImMwZmZjOGE1LTk4OTktNDAwYi1hNGU5LTJjNWM3NjFmNWQxZiIsInVzbiI6InN2YmhOdlNJSmEifQ.5L8BUbpTA4XAHlSrdwhIVlrlIpRtjExepim7Yh5eEO4&status=true&format=protobuf"); "/ws?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJleHAiOjE1NTcxNzAwNzIsInVpZCI6ImMwZmZjOGE1LTk4OTktNDAwYi1hNGU5LTJjNWM3NjFmNW"
"QxZiIsInVzbiI6InN2YmhOdlNJSmEifQ.5L8BUbpTA4XAHlSrdwhIVlrlIpRtjExepim7Yh5eEO4&"
"status=true&format=protobuf");
REQUIRE(query ==
"token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9."
"eyJleHAiOjE1NTcxNzAwNzIsInVpZCI6ImMwZmZjOGE1LTk4OTktNDAwYi1hNGU5LTJjNWM3NjFmNW"
"QxZiIsInVzbiI6InN2YmhOdlNJSmEifQ.5L8BUbpTA4XAHlSrdwhIVlrlIpRtjExepim7Yh5eEO4&"
"status=true&format=protobuf");
REQUIRE(port == 7350); REQUIRE(port == 7350);
} }
}
} } // namespace ix
}

View File

@ -9,17 +9,15 @@
// websocket_chat_server/broacast-server.js // websocket_chat_server/broacast-server.js
// //
#include "IXTest.h"
#include "catch.hpp"
#include "msgpack11.hpp"
#include <iostream> #include <iostream>
#include <sstream>
#include <vector>
#include <mutex>
#include <ixwebsocket/IXWebSocket.h> #include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketServer.h> #include <ixwebsocket/IXWebSocketServer.h>
#include "msgpack11.hpp" #include <mutex>
#include <sstream>
#include "IXTest.h" #include <vector>
#include "catch.hpp"
using msgpack11::MsgPack; using msgpack11::MsgPack;
using namespace ix; using namespace ix;
@ -29,9 +27,7 @@ namespace
class WebSocketChat class WebSocketChat
{ {
public: public:
WebSocketChat(const std::string& user, WebSocketChat(const std::string& user, const std::string& session, int port);
const std::string& session,
int port);
void subscribe(const std::string& channel); void subscribe(const std::string& channel);
void start(); void start();
@ -57,12 +53,10 @@ namespace
mutable std::mutex _mutex; mutable std::mutex _mutex;
}; };
WebSocketChat::WebSocketChat(const std::string& user, WebSocketChat::WebSocketChat(const std::string& user, const std::string& session, int port)
const std::string& session, : _user(user)
int port) : , _session(session)
_user(user), , _port(port)
_session(session),
_port(port)
{ {
; ;
} }
@ -100,10 +94,7 @@ namespace
std::string url; std::string url;
{ {
std::stringstream ss; std::stringstream ss;
ss << "ws://127.0.0.1:" ss << "ws://127.0.0.1:" << _port << "/" << _user;
<< _port
<< "/"
<< _user;
url = ss.str(); url = ss.str();
} }
@ -113,22 +104,16 @@ namespace
std::stringstream ss; std::stringstream ss;
log(std::string("Connecting to url: ") + url); log(std::string("Connecting to url: ") + url);
_webSocket.setOnMessageCallback( _webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
[this](const ix::WebSocketMessagePtr& msg)
{
std::stringstream ss; std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
ss << "cmd_websocket_chat: user " ss << "cmd_websocket_chat: user " << _user << " Connected !";
<< _user
<< " Connected !";
log(ss.str()); log(ss.str());
} }
else if (msg->type == ix::WebSocketMessageType::Close) else if (msg->type == ix::WebSocketMessageType::Close)
{ {
ss << "cmd_websocket_chat: user " ss << "cmd_websocket_chat: user " << _user << " disconnected !";
<< _user
<< " disconnected !";
log(ss.str()); log(ss.str());
} }
else if (msg->type == ix::WebSocketMessageType::Message) else if (msg->type == ix::WebSocketMessageType::Message)
@ -148,10 +133,7 @@ namespace
payload = "<message too large>"; payload = "<message too large>";
} }
ss << std::endl ss << std::endl << result.first << " > " << payload << std::endl << _user << " > ";
<< result.first << " > " << payload
<< std::endl
<< _user << " > ";
log(ss.str()); log(ss.str());
} }
else if (msg->type == ix::WebSocketMessageType::Error) else if (msg->type == ix::WebSocketMessageType::Error)
@ -211,13 +193,10 @@ namespace
bool startServer(ix::WebSocketServer& server) bool startServer(ix::WebSocketServer& server)
{ {
server.setOnConnectionCallback( server.setOnConnectionCallback([&server](std::shared_ptr<ix::WebSocket> webSocket,
[&server](std::shared_ptr<ix::WebSocket> webSocket, std::shared_ptr<ConnectionState> connectionState) {
std::shared_ptr<ConnectionState> connectionState)
{
webSocket->setOnMessageCallback( webSocket->setOnMessageCallback(
[webSocket, connectionState, &server](const ix::WebSocketMessagePtr& msg) [webSocket, connectionState, &server](const ix::WebSocketMessagePtr& msg) {
{
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
Logger() << "New connection"; Logger() << "New connection";
@ -243,10 +222,8 @@ namespace
} }
} }
} }
} });
); });
}
);
auto res = server.listen(); auto res = server.listen();
if (!res.first) if (!res.first)
@ -258,7 +235,7 @@ namespace
server.start(); server.start();
return true; return true;
} }
} } // namespace
TEST_CASE("Websocket_chat", "[websocket_chat]") TEST_CASE("Websocket_chat", "[websocket_chat]")
{ {
@ -305,8 +282,7 @@ TEST_CASE("Websocket_chat", "[websocket_chat]")
// Wait until all messages are received. 10s timeout // Wait until all messages are received. 10s timeout
int attempts = 0; int attempts = 0;
while (chatA.getReceivedMessagesCount() != 3 || while (chatA.getReceivedMessagesCount() != 3 || chatB.getReceivedMessagesCount() != 3)
chatB.getReceivedMessagesCount() != 3)
{ {
REQUIRE(attempts++ < 10); REQUIRE(attempts++ < 10);
ix::msleep(1000); ix::msleep(1000);

View File

@ -4,15 +4,13 @@
* Copyright (c) 2019 Machine Zone. All rights reserved. * Copyright (c) 2019 Machine Zone. All rights reserved.
*/ */
#include "IXTest.h"
#include "catch.hpp"
#include <iostream> #include <iostream>
#include <sstream>
#include <queue>
#include <ixwebsocket/IXWebSocket.h> #include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketServer.h> #include <ixwebsocket/IXWebSocketServer.h>
#include <queue>
#include "IXTest.h" #include <sstream>
#include "catch.hpp"
using namespace ix; using namespace ix;
@ -102,9 +100,7 @@ namespace
std::string url; std::string url;
{ {
std::stringstream ss; std::stringstream ss;
ss << "ws://localhost:" ss << "ws://localhost:" << _port << "/";
<< _port
<< "/";
url = ss.str(); url = ss.str();
} }
@ -115,9 +111,7 @@ namespace
std::stringstream ss; std::stringstream ss;
log(std::string("Connecting to url: ") + url); log(std::string("Connecting to url: ") + url);
_webSocket.setOnMessageCallback( _webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
[this](const ix::WebSocketMessagePtr& msg)
{
std::stringstream ss; std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
@ -126,10 +120,7 @@ namespace
else if (msg->type == ix::WebSocketMessageType::Close) else if (msg->type == ix::WebSocketMessageType::Close)
{ {
std::stringstream ss; std::stringstream ss;
ss << "client disconnected(" ss << "client disconnected(" << msg->closeInfo.code << "," << msg->closeInfo.reason
<< msg->closeInfo.code
<< ","
<< msg->closeInfo.reason
<< ")"; << ")";
log(ss.str()); log(ss.str());
@ -178,12 +169,15 @@ namespace
{ {
// A dev/null server // A dev/null server
server.setOnConnectionCallback( server.setOnConnectionCallback(
[&receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](std::shared_ptr<ix::WebSocket> webSocket, [&receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](
std::shared_ptr<ConnectionState> connectionState) std::shared_ptr<ix::WebSocket> webSocket,
{ std::shared_ptr<ConnectionState> connectionState) {
webSocket->setOnMessageCallback( webSocket->setOnMessageCallback([webSocket,
[webSocket, connectionState, &receivedCloseCode, &receivedCloseReason, &receivedCloseRemote, &mutexWrite](const ix::WebSocketMessagePtr& msg) 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() << "New server connection";
@ -198,11 +192,8 @@ namespace
else if (msg->type == ix::WebSocketMessageType::Close) else if (msg->type == ix::WebSocketMessageType::Close)
{ {
std::stringstream ss; std::stringstream ss;
ss << "Server closed connection(" ss << "Server closed connection(" << msg->closeInfo.code << ","
<< msg->closeInfo.code << msg->closeInfo.reason << ")";
<< ","
<< msg->closeInfo.reason
<< ")";
log(ss.str()); log(ss.str());
std::lock_guard<std::mutex> lck(mutexWrite); std::lock_guard<std::mutex> lck(mutexWrite);
@ -211,10 +202,8 @@ namespace
receivedCloseReason = std::string(msg->closeInfo.reason); receivedCloseReason = std::string(msg->closeInfo.reason);
receivedCloseRemote = msg->closeInfo.remote; receivedCloseRemote = msg->closeInfo.remote;
} }
} });
); });
}
);
auto res = server.listen(); auto res = server.listen();
if (!res.first) if (!res.first)
@ -226,7 +215,7 @@ namespace
server.start(); server.start();
return true; return true;
} }
} } // namespace
TEST_CASE("Websocket_client_close_default", "[close]") TEST_CASE("Websocket_client_close_default", "[close]")
{ {
@ -242,7 +231,11 @@ TEST_CASE("Websocket_client_close_default", "[close]")
std::string serverReceivedCloseReason(""); std::string serverReceivedCloseReason("");
std::mutex mutexWrite; std::mutex mutexWrite;
REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite)); REQUIRE(startServer(server,
serverReceivedCloseCode,
serverReceivedCloseReason,
serverReceivedCloseRemote,
mutexWrite));
std::string session = ix::generateSessionId(); std::string session = ix::generateSessionId();
WebSocketClient webSocketClient(port); WebSocketClient webSocketClient(port);
@ -301,7 +294,11 @@ TEST_CASE("Websocket_client_close_params_given", "[close]")
std::string serverReceivedCloseReason(""); std::string serverReceivedCloseReason("");
std::mutex mutexWrite; std::mutex mutexWrite;
REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite)); REQUIRE(startServer(server,
serverReceivedCloseCode,
serverReceivedCloseReason,
serverReceivedCloseRemote,
mutexWrite));
std::string session = ix::generateSessionId(); std::string session = ix::generateSessionId();
WebSocketClient webSocketClient(port); WebSocketClient webSocketClient(port);
@ -359,7 +356,11 @@ TEST_CASE("Websocket_server_close", "[close]")
std::string serverReceivedCloseReason(""); std::string serverReceivedCloseReason("");
std::mutex mutexWrite; std::mutex mutexWrite;
REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite)); REQUIRE(startServer(server,
serverReceivedCloseCode,
serverReceivedCloseReason,
serverReceivedCloseRemote,
mutexWrite));
std::string session = ix::generateSessionId(); std::string session = ix::generateSessionId();
WebSocketClient webSocketClient(port); WebSocketClient webSocketClient(port);
@ -417,7 +418,11 @@ TEST_CASE("Websocket_server_close_immediatly", "[close]")
std::string serverReceivedCloseReason(""); std::string serverReceivedCloseReason("");
std::mutex mutexWrite; std::mutex mutexWrite;
REQUIRE(startServer(server, serverReceivedCloseCode, serverReceivedCloseReason, serverReceivedCloseRemote, mutexWrite)); REQUIRE(startServer(server,
serverReceivedCloseCode,
serverReceivedCloseReason,
serverReceivedCloseRemote,
mutexWrite));
std::string session = ix::generateSessionId(); std::string session = ix::generateSessionId();
WebSocketClient webSocketClient(port); WebSocketClient webSocketClient(port);

View File

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

View File

@ -4,15 +4,13 @@
* Copyright (c) 2019 Machine Zone. All rights reserved. * Copyright (c) 2019 Machine Zone. All rights reserved.
*/ */
#include "IXTest.h"
#include "catch.hpp"
#include <iostream> #include <iostream>
#include <sstream>
#include <queue>
#include <ixwebsocket/IXWebSocket.h> #include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketServer.h> #include <ixwebsocket/IXWebSocketServer.h>
#include <queue>
#include "IXTest.h" #include <sstream>
#include "catch.hpp"
using namespace ix; using namespace ix;
@ -35,8 +33,8 @@ namespace
}; };
WebSocketClient::WebSocketClient(int port, bool useHeartBeatMethod) WebSocketClient::WebSocketClient(int port, bool useHeartBeatMethod)
: _port(port), : _port(port)
_useHeartBeatMethod(useHeartBeatMethod) , _useHeartBeatMethod(useHeartBeatMethod)
{ {
; ;
} }
@ -56,9 +54,7 @@ namespace
std::string url; std::string url;
{ {
std::stringstream ss; std::stringstream ss;
ss << "ws://127.0.0.1:" ss << "ws://127.0.0.1:" << _port << "/";
<< _port
<< "/";
url = ss.str(); url = ss.str();
} }
@ -79,14 +75,12 @@ namespace
std::stringstream ss; std::stringstream ss;
log(std::string("Connecting to url: ") + url); log(std::string("Connecting to url: ") + url);
_webSocket.setOnMessageCallback( _webSocket.setOnMessageCallback([](ix::WebSocketMessageType messageType,
[](ix::WebSocketMessageType messageType,
const std::string& str, const std::string& str,
size_t wireSize, size_t wireSize,
const ix::WebSocketErrorInfo& error, const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo, const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo) const ix::WebSocketCloseInfo& closeInfo) {
{
std::stringstream ss; std::stringstream ss;
if (messageType == ix::WebSocketMessageType::Open) if (messageType == ix::WebSocketMessageType::Open)
{ {
@ -135,16 +129,15 @@ namespace
// A dev/null server // A dev/null server
server.setOnConnectionCallback( server.setOnConnectionCallback(
[&server, &receivedPingMessages](std::shared_ptr<ix::WebSocket> webSocket, [&server, &receivedPingMessages](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState) std::shared_ptr<ConnectionState> connectionState) {
{
webSocket->setOnMessageCallback( webSocket->setOnMessageCallback(
[webSocket, connectionState, &server, &receivedPingMessages](ix::WebSocketMessageType messageType, [webSocket, connectionState, &server, &receivedPingMessages](
ix::WebSocketMessageType messageType,
const std::string& str, const std::string& str,
size_t wireSize, size_t wireSize,
const ix::WebSocketErrorInfo& error, const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo, const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo) const ix::WebSocketCloseInfo& closeInfo) {
{
if (messageType == ix::WebSocketMessageType::Open) if (messageType == ix::WebSocketMessageType::Open)
{ {
Logger() << "New server connection"; Logger() << "New server connection";
@ -168,15 +161,13 @@ namespace
else if (messageType == ix::WebSocketMessageType::Message) else if (messageType == ix::WebSocketMessageType::Message)
{ {
// to many messages to log // to many messages to log
for(auto client: server.getClients()) for (auto client : server.getClients())
{ {
client->sendText("reply"); client->sendText("reply");
} }
} }
} });
); });
}
);
auto res = server.listen(); auto res = server.listen();
if (!res.first) if (!res.first)
@ -188,7 +179,7 @@ namespace
server.start(); server.start();
return true; return true;
} }
} } // namespace
TEST_CASE("Websocket_ping_no_data_sent_setPingInterval", "[setPingInterval]") 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]") 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(); ix::setupWebSocketTrafficTrackerCallback();
@ -309,7 +301,7 @@ TEST_CASE("Websocket_ping_data_sent_setPingInterval_half_full", "[setPingInterva
// send continuously for 1100ms // send continuously for 1100ms
auto now = std::chrono::steady_clock::now(); 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"); webSocketClient.sendMessage("message");
ix::msleep(1); 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]") 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(); ix::setupWebSocketTrafficTrackerCallback();
@ -362,7 +355,7 @@ TEST_CASE("Websocket_ping_data_sent_setPingInterval_full", "[setPingInterval]")
// send continuously for 1100ms // send continuously for 1100ms
auto now = std::chrono::steady_clock::now(); 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"); webSocketClient.sendMessage("message");
ix::msleep(1); ix::msleep(1);

View File

@ -4,15 +4,13 @@
* Copyright (c) 2019 Machine Zone. All rights reserved. * Copyright (c) 2019 Machine Zone. All rights reserved.
*/ */
#include "IXTest.h"
#include "catch.hpp"
#include <iostream> #include <iostream>
#include <sstream>
#include <queue>
#include <ixwebsocket/IXWebSocket.h> #include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXWebSocketServer.h> #include <ixwebsocket/IXWebSocketServer.h>
#include <queue>
#include "IXTest.h" #include <sstream>
#include "catch.hpp"
using namespace ix; using namespace ix;
@ -41,11 +39,11 @@ namespace
}; };
WebSocketClient::WebSocketClient(int port, int pingInterval, int pingTimeout) WebSocketClient::WebSocketClient(int port, int pingInterval, int pingTimeout)
: _port(port), : _port(port)
_receivedPongMessages(0), , _receivedPongMessages(0)
_closedDueToPingTimeout(false), , _closedDueToPingTimeout(false)
_pingInterval(pingInterval), , _pingInterval(pingInterval)
_pingTimeout(pingTimeout) , _pingTimeout(pingTimeout)
{ {
; ;
} }
@ -70,9 +68,7 @@ namespace
std::string url; std::string url;
{ {
std::stringstream ss; std::stringstream ss;
ss << "ws://127.0.0.1:" ss << "ws://127.0.0.1:" << _port << "/";
<< _port
<< "/";
url = ss.str(); url = ss.str();
} }
@ -88,19 +84,16 @@ namespace
std::stringstream ss; std::stringstream ss;
log(std::string("Connecting to url: ") + url); log(std::string("Connecting to url: ") + url);
_webSocket.setOnMessageCallback( _webSocket.setOnMessageCallback([this](ix::WebSocketMessageType messageType,
[this](ix::WebSocketMessageType messageType,
const std::string& str, const std::string& str,
size_t wireSize, size_t wireSize,
const ix::WebSocketErrorInfo& error, const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo, const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo) const ix::WebSocketCloseInfo& closeInfo) {
{
std::stringstream ss; std::stringstream ss;
if (messageType == ix::WebSocketMessageType::Open) if (messageType == ix::WebSocketMessageType::Open)
{ {
log("client connected"); log("client connected");
} }
else if (messageType == ix::WebSocketMessageType::Close) else if (messageType == ix::WebSocketMessageType::Close)
{ {
@ -110,7 +103,6 @@ namespace
{ {
_closedDueToPingTimeout = true; _closedDueToPingTimeout = true;
} }
} }
else if (messageType == ix::WebSocketMessageType::Error) else if (messageType == ix::WebSocketMessageType::Error)
{ {
@ -159,21 +151,22 @@ namespace
return _closedDueToPingTimeout; 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 // A dev/null server
server.setOnConnectionCallback( server.setOnConnectionCallback(
[&server, &receivedPingMessages](std::shared_ptr<ix::WebSocket> webSocket, [&server, &receivedPingMessages](std::shared_ptr<ix::WebSocket> webSocket,
std::shared_ptr<ConnectionState> connectionState) std::shared_ptr<ConnectionState> connectionState) {
{
webSocket->setOnMessageCallback( webSocket->setOnMessageCallback(
[webSocket, connectionState, &server, &receivedPingMessages](ix::WebSocketMessageType messageType, [webSocket, connectionState, &server, &receivedPingMessages](
ix::WebSocketMessageType messageType,
const std::string& str, const std::string& str,
size_t wireSize, size_t wireSize,
const ix::WebSocketErrorInfo& error, const ix::WebSocketErrorInfo& error,
const ix::WebSocketOpenInfo& openInfo, const ix::WebSocketOpenInfo& openInfo,
const ix::WebSocketCloseInfo& closeInfo) const ix::WebSocketCloseInfo& closeInfo) {
{
if (messageType == ix::WebSocketMessageType::Open) if (messageType == ix::WebSocketMessageType::Open)
{ {
Logger() << "New server connection"; Logger() << "New server connection";
@ -194,10 +187,8 @@ namespace
log("Server received a ping"); log("Server received a ping");
receivedPingMessages++; receivedPingMessages++;
} }
} });
); });
}
);
if (!enablePong) if (!enablePong)
{ {
@ -215,7 +206,7 @@ namespace
server.start(); server.start();
return true; return true;
} }
} } // namespace
TEST_CASE("Websocket_ping_timeout_not_checked", "[setPingTimeout]") TEST_CASE("Websocket_ping_timeout_not_checked", "[setPingTimeout]")
{ {

View File

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

View File

@ -4,13 +4,12 @@
* Copyright (c) 2017 Machine Zone. All rights reserved. * Copyright (c) 2017 Machine Zone. All rights reserved.
*/ */
#include <iostream>
#include <sstream>
#include <set>
#include <ixwebsocket/IXWebSocket.h>
#include "IXTest.h" #include "IXTest.h"
#include "catch.hpp" #include "catch.hpp"
#include <iostream>
#include <ixwebsocket/IXWebSocket.h>
#include <set>
#include <sstream>
using namespace ix; using namespace ix;
@ -19,7 +18,7 @@ namespace
const std::string WEBSOCKET_DOT_ORG_URL("wss://echo.websocket.org"); const std::string WEBSOCKET_DOT_ORG_URL("wss://echo.websocket.org");
const std::string GOOGLE_URL("wss://google.com"); const std::string GOOGLE_URL("wss://google.com");
const std::string UNKNOWN_URL("wss://asdcasdcaasdcasdcasdcasdcasdcasdcasassdd.com"); const std::string UNKNOWN_URL("wss://asdcasdcaasdcasdcasdcasdcasdcasdcasassdd.com");
} } // namespace
namespace namespace
{ {
@ -51,9 +50,7 @@ namespace
std::stringstream ss; std::stringstream ss;
log(std::string("Connecting to url: ") + url); log(std::string("Connecting to url: ") + url);
_webSocket.setOnMessageCallback( _webSocket.setOnMessageCallback([](const ix::WebSocketMessagePtr& msg) {
[](const ix::WebSocketMessagePtr& msg)
{
std::stringstream ss; std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
@ -100,11 +97,12 @@ namespace
// Start the connection // Start the connection
_webSocket.start(); _webSocket.start();
} }
} } // namespace
// //
// We try to connect to different servers, and make sure there are no crashes. // 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]") TEST_CASE("websocket_connections", "[websocket]")
{ {
@ -121,7 +119,8 @@ TEST_CASE("websocket_connections", "[websocket]")
test.stop(); 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; IXWebSocketTestConnectionDisconnection test;
log(std::string("50 Runs")); log(std::string("50 Runs"));
@ -141,7 +140,8 @@ TEST_CASE("websocket_connections", "[websocket]")
// This test breaks on travis CI - Ubuntu Xenial + gcc + tsan // This test breaks on travis CI - Ubuntu Xenial + gcc + tsan
// We should fix this. // 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; IXWebSocketTestConnectionDisconnection test;
log(std::string("20 Runs")); log(std::string("20 Runs"));
@ -152,7 +152,7 @@ TEST_CASE("websocket_connections", "[websocket]")
test.start(WEBSOCKET_DOT_ORG_URL); test.start(WEBSOCKET_DOT_ORG_URL);
log(std::string("Sleeping")); log(std::string("Sleeping"));
ix::msleep(i*50); ix::msleep(i * 50);
log(std::string("Stopping")); log(std::string("Stopping"));
test.stop(); test.stop();

View File

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

View File

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

View File

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

View File

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

View File

@ -4,24 +4,20 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. * Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/ */
#include "IXSnakeProtocol.h"
#include "IXAppConfig.h" #include "IXAppConfig.h"
#include "IXSnakeProtocol.h"
#include <iostream> #include <iostream>
#include <ixcrypto/IXUuid.h> #include <ixcrypto/IXUuid.h>
namespace snake namespace snake
{ {
bool isAppKeyValid( bool isAppKeyValid(const AppConfig& appConfig, std::string appkey)
const AppConfig& appConfig,
std::string appkey)
{ {
return appConfig.apps.count(appkey) != 0; return appConfig.apps.count(appkey) != 0;
} }
std::string getRoleSecret( std::string getRoleSecret(const AppConfig& appConfig, std::string appkey, std::string role)
const AppConfig& appConfig,
std::string appkey,
std::string role)
{ {
if (!isAppKeyValid(appConfig, appkey)) if (!isAppKeyValid(appConfig, appkey))
{ {
@ -49,4 +45,4 @@ namespace snake
std::cout << "redis password: " << appConfig.redisPassword << std::endl; std::cout << "redis password: " << appConfig.redisPassword << std::endl;
std::cout << "redis port: " << appConfig.redisPort << 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 class SnakeConnectionState : public ix::ConnectionState
{ {
public: public:
std::string getNonce() { return _nonce; } std::string getNonce()
void setNonce(const std::string& nonce) { _nonce = nonce; } {
return _nonce;
}
void setNonce(const std::string& nonce)
{
_nonce = nonce;
}
std::string appkey() { return _appkey; } std::string appkey()
void setAppkey(const std::string& appkey) { _appkey = appkey; } {
return _appkey;
}
void setAppkey(const std::string& appkey)
{
_appkey = appkey;
}
std::string role() { return _role; } std::string role()
void setRole(const std::string& role) { _role = 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; std::future<void> fut;

View File

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

View File

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

110
ws/ws.cpp
View File

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

View File

@ -21,7 +21,8 @@
// //
// //
// 2 Run the test server (using docker) // 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 // 3. Run this command
// ws autobahn -q --url ws://localhost:9001 // 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 // 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 <atomic>
#include <mutex>
#include <condition_variable> #include <condition_variable>
#include <ixwebsocket/IXWebSocket.h> #include <iostream>
#include <ixwebsocket/IXSocket.h> #include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <mutex>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <sstream>
namespace namespace
@ -53,7 +53,7 @@ namespace
return str.substr(0, n) + "..."; return str.substr(0, n) + "...";
} }
} }
} } // namespace
namespace ix namespace ix
{ {
@ -75,9 +75,9 @@ namespace ix
std::condition_variable _condition; std::condition_variable _condition;
}; };
AutobahnTestCase::AutobahnTestCase(const std::string& url, bool quiet) : AutobahnTestCase::AutobahnTestCase(const std::string& url, bool quiet)
_url(url), : _url(url)
_quiet(quiet) , _quiet(quiet)
{ {
_webSocket.disableAutomaticReconnection(); _webSocket.disableAutomaticReconnection();
@ -102,9 +102,7 @@ namespace ix
std::stringstream ss; std::stringstream ss;
log(std::string("Connecting to url: ") + _url); log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback( _webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
[this](const ix::WebSocketMessagePtr& msg)
{
std::stringstream ss; std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
@ -128,9 +126,7 @@ namespace ix
{ {
ss << "Received " << msg->wireSize << " bytes" << std::endl; ss << "Received " << msg->wireSize << " bytes" << std::endl;
ss << "autobahn: received message: " ss << "autobahn: received message: " << truncate(msg->str, 40) << std::endl;
<< truncate(msg->str, 40)
<< std::endl;
_webSocket.send(msg->str, msg->binary); _webSocket.send(msg->str, msg->binary);
} }
@ -184,9 +180,7 @@ namespace ix
std::atomic<bool> success(true); std::atomic<bool> success(true);
std::condition_variable condition; std::condition_variable condition;
webSocket.setOnMessageCallback( webSocket.setOnMessageCallback([&condition, &success](const ix::WebSocketMessagePtr& msg) {
[&condition, &success](const ix::WebSocketMessagePtr& msg)
{
if (msg->type == ix::WebSocketMessageType::Close) if (msg->type == ix::WebSocketMessageType::Close)
{ {
std::cerr << "Report generated" << std::endl; std::cerr << "Report generated" << std::endl;
@ -203,8 +197,7 @@ namespace ix
success = false; success = false;
} }
} });
);
webSocket.start(); webSocket.start();
std::mutex mutex; std::mutex mutex;
@ -231,9 +224,7 @@ namespace ix
int count = -1; int count = -1;
std::condition_variable condition; std::condition_variable condition;
webSocket.setOnMessageCallback( webSocket.setOnMessageCallback([&condition, &count](const ix::WebSocketMessagePtr& msg) {
[&condition, &count](const ix::WebSocketMessagePtr& msg)
{
if (msg->type == ix::WebSocketMessageType::Close) if (msg->type == ix::WebSocketMessageType::Close)
{ {
condition.notify_one(); condition.notify_one();
@ -256,8 +247,7 @@ namespace ix
ss << msg->str; ss << msg->str;
ss >> count; ss >> count;
} }
} });
);
webSocket.start(); webSocket.start();
std::mutex mutex; std::mutex mutex;
@ -289,17 +279,14 @@ namespace ix
testCasesCount++; testCasesCount++;
for (int i = 1 ; i < testCasesCount; ++i) for (int i = 1; i < testCasesCount; ++i)
{ {
spdlog::info("Execute test case {}", i); spdlog::info("Execute test case {}", i);
int caseNumber = i; int caseNumber = i;
std::stringstream ss; std::stringstream ss;
ss << url ss << url << "/runCase?case=" << caseNumber << "&agent=ixwebsocket";
<< "/runCase?case="
<< caseNumber
<< "&agent=ixwebsocket";
std::string url(ss.str()); std::string url(ss.str());
@ -309,4 +296,4 @@ namespace ix
return generateReport(url) ? 0 : 1; return generateReport(url) ? 0 : 1;
} }
} } // namespace ix

View File

@ -5,8 +5,8 @@
*/ */
#include <iostream> #include <iostream>
#include <sstream>
#include <ixwebsocket/IXWebSocketServer.h> #include <ixwebsocket/IXWebSocketServer.h>
#include <sstream>
namespace ix namespace ix
{ {
@ -16,13 +16,10 @@ namespace ix
ix::WebSocketServer server(port, hostname); ix::WebSocketServer server(port, hostname);
server.setOnConnectionCallback( server.setOnConnectionCallback([&server](std::shared_ptr<WebSocket> webSocket,
[&server](std::shared_ptr<WebSocket> webSocket, std::shared_ptr<ConnectionState> connectionState) {
std::shared_ptr<ConnectionState> connectionState) webSocket->setOnMessageCallback([webSocket, connectionState, &server](
{ const WebSocketMessagePtr& msg) {
webSocket->setOnMessageCallback(
[webSocket, connectionState, &server](const WebSocketMessagePtr& msg)
{
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
std::cerr << "New connection" << std::endl; std::cerr << "New connection" << std::endl;
@ -37,8 +34,8 @@ namespace ix
else if (msg->type == ix::WebSocketMessageType::Close) else if (msg->type == ix::WebSocketMessageType::Close)
{ {
std::cerr << "Closed connection" std::cerr << "Closed connection"
<< " code " << msg->closeInfo.code << " code " << msg->closeInfo.code << " reason "
<< " reason " << msg->closeInfo.reason << std::endl; << msg->closeInfo.reason << std::endl;
} }
else if (msg->type == ix::WebSocketMessageType::Error) else if (msg->type == ix::WebSocketMessageType::Error)
{ {
@ -61,19 +58,16 @@ namespace ix
{ {
if (client != webSocket) if (client != webSocket)
{ {
client->send(msg->str, client->send(msg->str, msg->binary, [](int current, int total) -> bool {
msg->binary, std::cerr << "Step " << current << " out of " << total << std::endl;
[](int current, int total) -> bool
{
std::cerr << "Step " << current
<< " out of " << total << std::endl;
return true; return true;
}); });
do do
{ {
size_t bufferedAmount = client->bufferedAmount(); size_t bufferedAmount = client->bufferedAmount();
std::cerr << bufferedAmount << " bytes left to be sent" << std::endl; std::cerr << bufferedAmount << " bytes left to be sent"
<< std::endl;
std::chrono::duration<double, std::milli> duration(10); std::chrono::duration<double, std::milli> duration(10);
std::this_thread::sleep_for(duration); std::this_thread::sleep_for(duration);
@ -81,10 +75,8 @@ namespace ix
} }
} }
} }
} });
); });
}
);
auto res = server.listen(); auto res = server.listen();
if (!res.first) if (!res.first)
@ -98,4 +90,4 @@ namespace ix
return 0; return 0;
} }
} } // namespace ix

View File

@ -9,13 +9,12 @@
// Broadcast server can be ran with `ws broadcast_server` // 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 "nlohmann/json.hpp"
#include <iostream>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <queue>
#include <sstream>
// for convenience // for convenience
using json = nlohmann::json; using json = nlohmann::json;
@ -25,8 +24,7 @@ namespace ix
class WebSocketChat class WebSocketChat
{ {
public: public:
WebSocketChat(const std::string& url, WebSocketChat(const std::string& url, const std::string& user);
const std::string& user);
void subscribe(const std::string& channel); void subscribe(const std::string& channel);
void start(); void start();
@ -48,10 +46,9 @@ namespace ix
void log(const std::string& msg); void log(const std::string& msg);
}; };
WebSocketChat::WebSocketChat(const std::string& url, WebSocketChat::WebSocketChat(const std::string& url, const std::string& user)
const std::string& user) : : _url(url)
_url(url), , _user(user)
_user(user)
{ {
; ;
} }
@ -83,9 +80,7 @@ namespace ix
std::stringstream ss; std::stringstream ss;
log(std::string("Connecting to url: ") + _url); log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback( _webSocket.setOnMessageCallback([this](const WebSocketMessagePtr& msg) {
[this](const WebSocketMessagePtr& msg)
{
std::stringstream ss; std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
@ -97,18 +92,13 @@ namespace ix
std::cout << it.first << ": " << it.second << std::endl; std::cout << it.first << ": " << it.second << std::endl;
} }
ss << "ws chat: user " ss << "ws chat: user " << _user << " Connected !";
<< _user
<< " Connected !";
log(ss.str()); log(ss.str());
} }
else if (msg->type == ix::WebSocketMessageType::Close) else if (msg->type == ix::WebSocketMessageType::Close)
{ {
ss << "ws chat: user " ss << "ws chat: user " << _user << " disconnected !"
<< _user << " code " << msg->closeInfo.code << " reason " << msg->closeInfo.reason;
<< " disconnected !"
<< " code " << msg->closeInfo.code
<< " reason " << msg->closeInfo.reason;
log(ss.str()); log(ss.str());
} }
else if (msg->type == ix::WebSocketMessageType::Message) else if (msg->type == ix::WebSocketMessageType::Message)
@ -122,8 +112,8 @@ namespace ix
_receivedQueue.push(result.second); _receivedQueue.push(result.second);
ss << std::endl ss << std::endl
<< result.first << "(" << msg->wireSize << " bytes)" << " > " << result.second << result.first << "(" << msg->wireSize << " bytes)"
<< std::endl << " > " << result.second << std::endl
<< _user << " > "; << _user << " > ";
log(ss.str()); log(ss.str());
} }
@ -170,8 +160,7 @@ namespace ix
_webSocket.sendText(encodeMessage(text)); _webSocket.sendText(encodeMessage(text));
} }
int ws_chat_main(const std::string& url, int ws_chat_main(const std::string& url, const std::string& user)
const std::string& user)
{ {
std::cout << "Type Ctrl-D to exit prompt..." << std::endl; std::cout << "Type Ctrl-D to exit prompt..." << std::endl;
WebSocketChat webSocketChat(url, user); WebSocketChat webSocketChat(url, user);
@ -196,4 +185,4 @@ namespace ix
return 0; return 0;
} }
} } // namespace ix

View File

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

View File

@ -4,17 +4,17 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. * Copyright (c) 2019 Machine Zone, Inc. All rights reserved.
*/ */
#include <iostream>
#include <fstream>
#include <sstream>
#include <chrono>
#include <thread>
#include <atomic> #include <atomic>
#include <mutex> #include <chrono>
#include <condition_variable> #include <condition_variable>
#include <jsoncpp/json/json.h> #include <fstream>
#include <iostream>
#include <ixcobra/IXCobraMetricsPublisher.h> #include <ixcobra/IXCobraMetricsPublisher.h>
#include <jsoncpp/json/json.h>
#include <mutex>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <sstream>
#include <thread>
namespace ix namespace ix
{ {
@ -26,8 +26,7 @@ namespace ix
const std::string& path) const std::string& path)
{ {
std::ifstream f(path); std::ifstream f(path);
std::string str((std::istreambuf_iterator<char>(f)), std::string str((std::istreambuf_iterator<char>(f)), std::istreambuf_iterator<char>());
std::istreambuf_iterator<char>());
Json::Value data; Json::Value data;
Json::Reader reader; Json::Reader reader;
@ -38,9 +37,8 @@ namespace ix
} }
ix::CobraConnection conn; ix::CobraConnection conn;
conn.configure(appkey, endpoint, conn.configure(
rolename, rolesecret, appkey, endpoint, rolename, rolesecret, ix::WebSocketPerMessageDeflateOptions(true));
ix::WebSocketPerMessageDeflateOptions(true));
conn.connect(); conn.connect();
// Display incoming messages // Display incoming messages
@ -48,14 +46,12 @@ namespace ix
std::atomic<bool> messageAcked(false); std::atomic<bool> messageAcked(false);
std::condition_variable condition; std::condition_variable condition;
conn.setEventCallback( conn.setEventCallback([&conn, &channel, &data, &authenticated, &messageAcked, &condition](
[&conn, &channel, &data, &authenticated, &messageAcked, &condition] ix::CobraConnectionEventType eventType,
(ix::CobraConnectionEventType eventType,
const std::string& errMsg, const std::string& errMsg,
const ix::WebSocketHttpHeaders& headers, const ix::WebSocketHttpHeaders& headers,
const std::string& subscriptionId, const std::string& subscriptionId,
CobraConnection::MsgId msgId) CobraConnection::MsgId msgId) {
{
if (eventType == ix::CobraConnection_EventType_Open) if (eventType == ix::CobraConnection_EventType_Open)
{ {
spdlog::info("Publisher connected"); spdlog::info("Publisher connected");
@ -95,12 +91,13 @@ namespace ix
messageAcked = true; messageAcked = true;
condition.notify_one(); condition.notify_one();
} }
} });
);
while (!authenticated) ; while (!authenticated)
while (!messageAcked) ; ;
while (!messageAcked)
;
return 0; return 0;
} }
} } // namespace ix

View File

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

View File

@ -4,19 +4,18 @@
* Copyright (c) 2019 Machine Zone, Inc. All rights reserved. * 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 "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 namespace ix
{ {
@ -32,9 +31,8 @@ namespace ix
int jobs) int jobs)
{ {
ix::CobraConnection conn; ix::CobraConnection conn;
conn.configure(appkey, endpoint, conn.configure(
rolename, rolesecret, appkey, endpoint, rolename, rolesecret, ix::WebSocketPerMessageDeflateOptions(true));
ix::WebSocketPerMessageDeflateOptions(true));
conn.connect(); conn.connect();
Json::FastWriter jsonWriter; Json::FastWriter jsonWriter;
@ -48,10 +46,15 @@ namespace ix
std::condition_variable progressCondition; std::condition_variable progressCondition;
std::queue<Json::Value> queue; std::queue<Json::Value> queue;
auto sentrySender = [&condition, &progressCondition, &conditionVariableMutex, auto sentrySender = [&condition,
&queue, verbose, &errorSending, &sentCount, &progressCondition,
&stop, &dsn] &conditionVariableMutex,
{ &queue,
verbose,
&errorSending,
&sentCount,
&stop,
&dsn] {
SentryClient sentryClient(dsn); SentryClient sentryClient(dsn);
while (true) while (true)
@ -60,7 +63,7 @@ namespace ix
{ {
std::unique_lock<std::mutex> lock(conditionVariableMutex); 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(); msg = queue.front();
queue.pop(); queue.pop();
@ -94,17 +97,21 @@ namespace ix
pool.push_back(std::thread(sentrySender)); pool.push_back(std::thread(sentrySender));
} }
conn.setEventCallback( conn.setEventCallback([&conn,
[&conn, &channel, &filter, &jsonWriter, &channel,
verbose, &receivedCount, &sentCount, &filter,
&condition, &conditionVariableMutex, &jsonWriter,
&progressCondition, &queue] verbose,
(ix::CobraConnectionEventType eventType, &receivedCount,
&sentCount,
&condition,
&conditionVariableMutex,
&progressCondition,
&queue](ix::CobraConnectionEventType eventType,
const std::string& errMsg, const std::string& errMsg,
const ix::WebSocketHttpHeaders& headers, const ix::WebSocketHttpHeaders& headers,
const std::string& subscriptionId, const std::string& subscriptionId,
CobraConnection::MsgId msgId) CobraConnection::MsgId msgId) {
{
if (eventType == ix::CobraConnection_EventType_Open) if (eventType == ix::CobraConnection_EventType_Open)
{ {
spdlog::info("Subscriber connected"); spdlog::info("Subscriber connected");
@ -121,13 +128,16 @@ namespace ix
else if (eventType == ix::CobraConnection_EventType_Authenticated) else if (eventType == ix::CobraConnection_EventType_Authenticated)
{ {
std::cerr << "Subscriber authenticated" << std::endl; std::cerr << "Subscriber authenticated" << std::endl;
conn.subscribe(channel, filter, conn.subscribe(channel,
[&jsonWriter, verbose, filter,
&sentCount, &receivedCount, [&jsonWriter,
&condition, &conditionVariableMutex, verbose,
&progressCondition, &queue] &sentCount,
(const Json::Value& msg) &receivedCount,
{ &condition,
&conditionVariableMutex,
&progressCondition,
&queue](const Json::Value& msg) {
if (verbose) if (verbose)
{ {
spdlog::info(jsonWriter.write(msg)); spdlog::info(jsonWriter.write(msg));
@ -136,8 +146,7 @@ namespace ix
// If we cannot send to sentry fast enough, drop the message // If we cannot send to sentry fast enough, drop the message
const uint64_t scaleFactor = 2; const uint64_t scaleFactor = 2;
if (sentCount != 0 && if (sentCount != 0 && receivedCount != 0 &&
receivedCount != 0 &&
(sentCount * scaleFactor < receivedCount)) (sentCount * scaleFactor < receivedCount))
{ {
spdlog::warn("message dropped: sending is backlogged !"); spdlog::warn("message dropped: sending is backlogged !");
@ -174,8 +183,7 @@ namespace ix
{ {
spdlog::error("Published message hacked: {}", msgId); spdlog::error("Published message hacked: {}", msgId);
} }
} });
);
std::mutex progressConditionVariableMutex; std::mutex progressConditionVariableMutex;
while (true) while (true)
@ -200,4 +208,4 @@ namespace ix
return (strict && errorSending) ? 1 : 0; return (strict && errorSending) ? 1 : 0;
} }
} } // namespace ix

View File

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

View File

@ -4,12 +4,11 @@
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. * 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 "linenoise.hpp"
#include <iostream>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <sstream>
namespace ix namespace ix
@ -46,10 +45,10 @@ namespace ix
bool disableAutomaticReconnection, bool disableAutomaticReconnection,
bool disablePerMessageDeflate, bool disablePerMessageDeflate,
bool binaryMode, bool binaryMode,
uint32_t maxWaitBetweenReconnectionRetries) : uint32_t maxWaitBetweenReconnectionRetries)
_url(url), : _url(url)
_disablePerMessageDeflate(disablePerMessageDeflate), , _disablePerMessageDeflate(disablePerMessageDeflate)
_binaryMode(binaryMode) , _binaryMode(binaryMode)
{ {
if (disableAutomaticReconnection) if (disableAutomaticReconnection)
{ {
@ -81,7 +80,7 @@ namespace ix
if (pos == std::string::npos) continue; if (pos == std::string::npos) continue;
auto key = token.substr(0, pos); auto key = token.substr(0, pos);
auto val = token.substr(pos+1); auto val = token.substr(pos + 1);
std::cerr << key << ": " << val << std::endl; std::cerr << key << ": " << val << std::endl;
headers[key] = val; headers[key] = val;
@ -114,9 +113,7 @@ namespace ix
std::stringstream ss; std::stringstream ss;
log(std::string("Connecting to url: ") + _url); log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback( _webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
[this](const ix::WebSocketMessagePtr& msg)
{
std::stringstream ss; std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
@ -139,8 +136,7 @@ namespace ix
{ {
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl; std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
ss << "ws_connect: received message: " ss << "ws_connect: received message: " << msg->str;
<< msg->str;
log(ss.str()); log(ss.str());
} }
else if (msg->type == ix::WebSocketMessageType::Error) else if (msg->type == ix::WebSocketMessageType::Error)
@ -237,5 +233,4 @@ namespace ix
return 0; return 0;
} }
} } // namespace ix

View File

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

View File

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

View File

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

View File

@ -5,9 +5,9 @@
*/ */
#include <iostream> #include <iostream>
#include <sstream>
#include <ixwebsocket/IXWebSocket.h>
#include <ixwebsocket/IXSocket.h> #include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <sstream>
namespace ix namespace ix
{ {
@ -30,8 +30,8 @@ namespace ix
void log(const std::string& msg); void log(const std::string& msg);
}; };
WebSocketPingPong::WebSocketPingPong(const std::string& url) : WebSocketPingPong::WebSocketPingPong(const std::string& url)
_url(url) : _url(url)
{ {
; ;
} }
@ -53,9 +53,7 @@ namespace ix
std::stringstream ss; std::stringstream ss;
log(std::string("Connecting to url: ") + _url); log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback( _webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
[this](const ix::WebSocketMessagePtr& msg)
{
std::cerr << "Received " << msg->wireSize << " bytes" << std::endl; std::cerr << "Received " << msg->wireSize << " bytes" << std::endl;
std::stringstream ss; std::stringstream ss;
@ -73,27 +71,23 @@ namespace ix
else if (msg->type == ix::WebSocketMessageType::Close) else if (msg->type == ix::WebSocketMessageType::Close)
{ {
ss << "ping_pong: disconnected:" ss << "ping_pong: disconnected:"
<< " code " << msg->closeInfo.code << " code " << msg->closeInfo.code << " reason " << msg->closeInfo.reason
<< " reason " << msg->closeInfo.reason
<< msg->str; << msg->str;
log(ss.str()); log(ss.str());
} }
else if (msg->type == ix::WebSocketMessageType::Message) else if (msg->type == ix::WebSocketMessageType::Message)
{ {
ss << "ping_pong: received message: " ss << "ping_pong: received message: " << msg->str;
<< msg->str;
log(ss.str()); log(ss.str());
} }
else if (msg->type == ix::WebSocketMessageType::Ping) else if (msg->type == ix::WebSocketMessageType::Ping)
{ {
ss << "ping_pong: received ping message: " ss << "ping_pong: received ping message: " << msg->str;
<< msg->str;
log(ss.str()); log(ss.str());
} }
else if (msg->type == ix::WebSocketMessageType::Pong) else if (msg->type == ix::WebSocketMessageType::Pong)
{ {
ss << "ping_pong: received pong message: " ss << "ping_pong: received pong message: " << msg->str;
<< msg->str;
log(ss.str()); log(ss.str());
} }
else if (msg->type == ix::WebSocketMessageType::Error) else if (msg->type == ix::WebSocketMessageType::Error)
@ -118,7 +112,8 @@ namespace ix
{ {
if (!_webSocket.ping(text).success) 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; << std::endl;
} }
} }
@ -160,4 +155,4 @@ namespace ix
return 0; return 0;
} }
} } // namespace ix

View File

@ -4,19 +4,19 @@
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. * 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 <chrono>
#include <ixwebsocket/IXWebSocket.h> #include <condition_variable>
#include <ixwebsocket/IXSocket.h> #include <fstream>
#include <ixcrypto/IXUuid.h> #include <iostream>
#include <ixcrypto/IXBase64.h> #include <ixcrypto/IXBase64.h>
#include <ixcrypto/IXHash.h> #include <ixcrypto/IXHash.h>
#include <ixcrypto/IXUuid.h>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <msgpack11/msgpack11.hpp> #include <msgpack11/msgpack11.hpp>
#include <mutex>
#include <sstream>
#include <vector>
using msgpack11::MsgPack; using msgpack11::MsgPack;
@ -25,9 +25,7 @@ namespace ix
class WebSocketReceiver class WebSocketReceiver
{ {
public: public:
WebSocketReceiver(const std::string& _url, WebSocketReceiver(const std::string& _url, bool enablePerMessageDeflate, int delayMs);
bool enablePerMessageDeflate,
int delayMs);
void subscribe(const std::string& channel); void subscribe(const std::string& channel);
void start(); void start();
@ -55,11 +53,11 @@ namespace ix
WebSocketReceiver::WebSocketReceiver(const std::string& url, WebSocketReceiver::WebSocketReceiver(const std::string& url,
bool enablePerMessageDeflate, bool enablePerMessageDeflate,
int delayMs) : int delayMs)
_url(url), : _url(url)
_enablePerMessageDeflate(enablePerMessageDeflate), , _enablePerMessageDeflate(enablePerMessageDeflate)
_delayMs(delayMs), , _delayMs(delayMs)
_receivedFragmentCounter(0) , _receivedFragmentCounter(0)
{ {
; ;
} }
@ -98,7 +96,7 @@ namespace ix
idx = path.rfind('/'); idx = path.rfind('/');
if (idx != std::string::npos) if (idx != std::string::npos)
{ {
std::string filename = path.substr(idx+1); std::string filename = path.substr(idx + 1);
return filename; return filename;
} }
else else
@ -107,8 +105,7 @@ namespace ix
} }
} }
void WebSocketReceiver::handleError(const std::string& errMsg, void WebSocketReceiver::handleError(const std::string& errMsg, const std::string& id)
const std::string& id)
{ {
std::map<MsgPack, MsgPack> pdu; std::map<MsgPack, MsgPack> pdu;
pdu["kind"] = "error"; pdu["kind"] = "error";
@ -156,7 +153,7 @@ namespace ix
std::cout << "Writing to disk: " << filenameTmp << std::endl; std::cout << "Writing to disk: " << filenameTmp << std::endl;
std::ofstream out(filenameTmp); std::ofstream out(filenameTmp);
out.write((char*)&content.front(), content.size()); out.write((char*) &content.front(), content.size());
out.close(); out.close();
std::cout << "Renaming " << filenameTmp << " to " << filename << std::endl; std::cout << "Renaming " << filenameTmp << " to " << filename << std::endl;
@ -182,9 +179,7 @@ namespace ix
std::stringstream ss; std::stringstream ss;
log(std::string("Connecting to url: ") + _url); log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback( _webSocket.setOnMessageCallback([this](const ix::WebSocketMessagePtr& msg) {
[this](const ix::WebSocketMessagePtr& msg)
{
std::stringstream ss; std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
@ -243,9 +238,7 @@ namespace ix
_webSocket.start(); _webSocket.start();
} }
void wsReceive(const std::string& url, void wsReceive(const std::string& url, bool enablePerMessageDeflate, int delayMs)
bool enablePerMessageDeflate,
int delayMs)
{ {
WebSocketReceiver webSocketReceiver(url, enablePerMessageDeflate, delayMs); WebSocketReceiver webSocketReceiver(url, enablePerMessageDeflate, delayMs);
webSocketReceiver.start(); webSocketReceiver.start();
@ -261,11 +254,9 @@ namespace ix
webSocketReceiver.stop(); webSocketReceiver.stop();
} }
int ws_receive_main(const std::string& url, int ws_receive_main(const std::string& url, bool enablePerMessageDeflate, int delayMs)
bool enablePerMessageDeflate,
int delayMs)
{ {
wsReceive(url, enablePerMessageDeflate, delayMs); wsReceive(url, enablePerMessageDeflate, delayMs);
return 0; return 0;
} }
} } // namespace ix

View File

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

View File

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

View File

@ -4,19 +4,19 @@
* Copyright (c) 2017-2018 Machine Zone, Inc. All rights reserved. * 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 <chrono>
#include <ixwebsocket/IXWebSocket.h> #include <condition_variable>
#include <ixwebsocket/IXSocket.h> #include <fstream>
#include <ixcrypto/IXUuid.h> #include <iostream>
#include <ixcrypto/IXBase64.h> #include <ixcrypto/IXBase64.h>
#include <ixcrypto/IXHash.h> #include <ixcrypto/IXHash.h>
#include <ixcrypto/IXUuid.h>
#include <ixwebsocket/IXSocket.h>
#include <ixwebsocket/IXWebSocket.h>
#include <msgpack11/msgpack11.hpp> #include <msgpack11/msgpack11.hpp>
#include <mutex>
#include <sstream>
#include <vector>
using msgpack11::MsgPack; using msgpack11::MsgPack;
@ -25,8 +25,7 @@ namespace ix
class WebSocketSender class WebSocketSender
{ {
public: public:
WebSocketSender(const std::string& _url, WebSocketSender(const std::string& _url, bool enablePerMessageDeflate);
bool enablePerMessageDeflate);
void subscribe(const std::string& channel); void subscribe(const std::string& channel);
void start(); void start();
@ -49,10 +48,9 @@ namespace ix
void log(const std::string& msg); void log(const std::string& msg);
}; };
WebSocketSender::WebSocketSender(const std::string& url, WebSocketSender::WebSocketSender(const std::string& url, bool enablePerMessageDeflate)
bool enablePerMessageDeflate) : : _url(url)
_url(url), , _enablePerMessageDeflate(enablePerMessageDeflate)
_enablePerMessageDeflate(enablePerMessageDeflate)
{ {
; ;
} }
@ -95,7 +93,7 @@ namespace ix
file.seekg(0, file.beg); file.seekg(0, file.beg);
memblock.resize((size_t) size); 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; return memblock;
} }
@ -111,9 +109,7 @@ namespace ix
std::stringstream ss; std::stringstream ss;
log(std::string("Connecting to url: ") + _url); log(std::string("Connecting to url: ") + _url);
_webSocket.setOnMessageCallback( _webSocket.setOnMessageCallback([this](const WebSocketMessagePtr& msg) {
[this](const WebSocketMessagePtr& msg)
{
std::stringstream ss; std::stringstream ss;
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
@ -177,10 +173,10 @@ namespace ix
class Bench class Bench
{ {
public: public:
Bench(const std::string& description) : Bench(const std::string& description)
_description(description), : _description(description)
_start(std::chrono::system_clock::now()), , _start(std::chrono::system_clock::now())
_reported(false) , _reported(false)
{ {
; ;
} }
@ -199,8 +195,7 @@ namespace ix
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now - _start); auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now - _start);
_ms = milliseconds.count(); _ms = milliseconds.count();
std::cout << _description << " completed in " std::cout << _description << " completed in " << _ms << "ms" << std::endl;
<< _ms << "ms" << std::endl;
_reported = true; _reported = true;
} }
@ -217,8 +212,7 @@ namespace ix
bool _reported; bool _reported;
}; };
void WebSocketSender::sendMessage(const std::string& filename, void WebSocketSender::sendMessage(const std::string& filename, bool throttle)
bool throttle)
{ {
std::vector<uint8_t> content; std::vector<uint8_t> content;
{ {
@ -239,9 +233,7 @@ namespace ix
MsgPack msg(pdu); MsgPack msg(pdu);
Bench bench("Sending file through websocket"); Bench bench("Sending file through websocket");
_webSocket.sendBinary(msg.dump(), _webSocket.sendBinary(msg.dump(), [throttle](int current, int total) -> bool {
[throttle](int current, int total) -> bool
{
std::cout << "ws_send: Step " << current << " out of " << total << std::endl; std::cout << "ws_send: Step " << current << " out of " << total << std::endl;
if (throttle) if (throttle)
@ -256,8 +248,7 @@ namespace ix
do do
{ {
size_t bufferedAmount = _webSocket.bufferedAmount(); size_t bufferedAmount = _webSocket.bufferedAmount();
std::cout << "ws_send: " << bufferedAmount std::cout << "ws_send: " << bufferedAmount << " bytes left to be sent" << std::endl;
<< " bytes left to be sent" << std::endl;
std::chrono::duration<double, std::milli> duration(10); std::chrono::duration<double, std::milli> duration(10);
std::this_thread::sleep_for(duration); std::this_thread::sleep_for(duration);
@ -289,8 +280,7 @@ namespace ix
webSocketSender.stop(); webSocketSender.stop();
} }
int ws_send_main(const std::string& url, int ws_send_main(const std::string& url, const std::string& path)
const std::string& path)
{ {
bool throttle = false; bool throttle = false;
bool enablePerMessageDeflate = false; bool enablePerMessageDeflate = false;
@ -298,4 +288,4 @@ namespace ix
wsSend(url, path, enablePerMessageDeflate, throttle); wsSend(url, path, enablePerMessageDeflate, throttle);
return 0; return 0;
} }
} } // namespace ix

View File

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

View File

@ -5,8 +5,8 @@
*/ */
#include <iostream> #include <iostream>
#include <sstream>
#include <ixwebsocket/IXWebSocketServer.h> #include <ixwebsocket/IXWebSocketServer.h>
#include <sstream>
namespace ix namespace ix
{ {
@ -16,13 +16,10 @@ namespace ix
ix::WebSocketServer server(port, hostname); ix::WebSocketServer server(port, hostname);
server.setOnConnectionCallback( server.setOnConnectionCallback([&server](std::shared_ptr<ix::WebSocket> webSocket,
[&server](std::shared_ptr<ix::WebSocket> webSocket, std::shared_ptr<ConnectionState> connectionState) {
std::shared_ptr<ConnectionState> connectionState) webSocket->setOnMessageCallback([webSocket, connectionState, &server](
{ const WebSocketMessagePtr& msg) {
webSocket->setOnMessageCallback(
[webSocket, connectionState, &server](const WebSocketMessagePtr& msg)
{
if (msg->type == ix::WebSocketMessageType::Open) if (msg->type == ix::WebSocketMessageType::Open)
{ {
std::cerr << "New connection" << std::endl; std::cerr << "New connection" << std::endl;
@ -37,8 +34,8 @@ namespace ix
else if (msg->type == ix::WebSocketMessageType::Close) else if (msg->type == ix::WebSocketMessageType::Close)
{ {
std::cerr << "Closed connection" std::cerr << "Closed connection"
<< " code " << msg->closeInfo.code << " code " << msg->closeInfo.code << " reason "
<< " reason " << msg->closeInfo.reason << std::endl; << msg->closeInfo.reason << std::endl;
} }
else if (msg->type == ix::WebSocketMessageType::Error) else if (msg->type == ix::WebSocketMessageType::Error)
{ {
@ -51,8 +48,7 @@ namespace ix
} }
else if (msg->type == ix::WebSocketMessageType::Fragment) else if (msg->type == ix::WebSocketMessageType::Fragment)
{ {
std::cerr << "Received message fragment " std::cerr << "Received message fragment " << std::endl;
<< std::endl;
} }
else if (msg->type == ix::WebSocketMessageType::Message) else if (msg->type == ix::WebSocketMessageType::Message)
{ {
@ -61,12 +57,9 @@ namespace ix
{ {
if (client != webSocket) if (client != webSocket)
{ {
client->send(msg->str, client->send(msg->str, msg->binary, [](int current, int total) -> bool {
msg->binary, std::cerr << "ws_transfer: Step " << current << " out of " << total
[](int current, int total) -> bool << std::endl;
{
std::cerr << "ws_transfer: Step " << current
<< " out of " << total << std::endl;
return true; return true;
}); });
@ -82,10 +75,8 @@ namespace ix
} }
} }
} }
} });
); });
}
);
auto res = server.listen(); auto res = server.listen();
if (!res.first) if (!res.first)
@ -99,4 +90,4 @@ namespace ix
return 0; return 0;
} }
} } // namespace ix