2018-12-30 03:33:15 +01:00
|
|
|
/*
|
|
|
|
* IXTest.cpp
|
|
|
|
* Author: Benjamin Sergeant
|
|
|
|
* Copyright (c) 2018 Machine Zone. All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "IXTest.h"
|
|
|
|
#include <ixwebsocket/IXWebSocket.h>
|
2019-01-29 00:14:49 +01:00
|
|
|
#include <ixwebsocket/IXNetSystem.h>
|
2018-12-30 03:33:15 +01:00
|
|
|
|
|
|
|
#include <chrono>
|
|
|
|
#include <thread>
|
2019-01-08 03:04:28 +01:00
|
|
|
#include <mutex>
|
2018-12-30 03:33:15 +01:00
|
|
|
#include <string>
|
|
|
|
#include <fstream>
|
|
|
|
#include <iostream>
|
|
|
|
#include <stdlib.h>
|
2019-01-29 00:14:49 +01:00
|
|
|
#include <stack>
|
2019-03-22 23:33:04 +01:00
|
|
|
#include <iomanip>
|
2018-12-30 03:33:15 +01:00
|
|
|
|
|
|
|
namespace ix
|
|
|
|
{
|
|
|
|
std::atomic<size_t> incomingBytes(0);
|
|
|
|
std::atomic<size_t> outgoingBytes(0);
|
2019-01-08 03:04:28 +01:00
|
|
|
std::mutex Logger::_mutex;
|
2019-01-29 00:14:49 +01:00
|
|
|
std::stack<int> freePorts;
|
2018-12-30 03:33:15 +01:00
|
|
|
|
|
|
|
void setupWebSocketTrafficTrackerCallback()
|
|
|
|
{
|
|
|
|
ix::WebSocket::setTrafficTrackerCallback(
|
|
|
|
[](size_t size, bool incoming)
|
|
|
|
{
|
|
|
|
if (incoming)
|
|
|
|
{
|
|
|
|
incomingBytes += size;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
outgoingBytes += size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
void reportWebSocketTraffic()
|
|
|
|
{
|
2019-01-08 03:04:28 +01:00
|
|
|
Logger() << incomingBytes;
|
|
|
|
Logger() << "Incoming bytes: " << incomingBytes;
|
|
|
|
Logger() << "Outgoing bytes: " << outgoingBytes;
|
2018-12-30 03:33:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void msleep(int ms)
|
|
|
|
{
|
|
|
|
std::chrono::duration<double, std::milli> duration(ms);
|
|
|
|
std::this_thread::sleep_for(duration);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string generateSessionId()
|
|
|
|
{
|
|
|
|
auto now = std::chrono::system_clock::now();
|
2019-02-21 03:59:07 +01:00
|
|
|
auto seconds =
|
2018-12-30 03:33:15 +01:00
|
|
|
std::chrono::duration_cast<std::chrono::seconds>(
|
|
|
|
now.time_since_epoch()).count();
|
|
|
|
|
|
|
|
return std::to_string(seconds);
|
|
|
|
}
|
2019-01-08 03:04:28 +01:00
|
|
|
|
|
|
|
void log(const std::string& msg)
|
|
|
|
{
|
|
|
|
Logger() << msg;
|
|
|
|
}
|
|
|
|
|
2019-03-09 19:45:40 +01:00
|
|
|
int getAnyFreePortSimple()
|
2019-01-29 00:14:49 +01:00
|
|
|
{
|
2019-03-06 02:07:28 +01:00
|
|
|
static int defaultPort = 8090;
|
|
|
|
return defaultPort++;
|
2019-03-09 19:45:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int getAnyFreePort()
|
|
|
|
{
|
2019-01-29 00:14:49 +01:00
|
|
|
int defaultPort = 8090;
|
2019-02-21 03:59:07 +01:00
|
|
|
int sockfd;
|
2019-01-29 00:14:49 +01:00
|
|
|
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
|
|
|
{
|
|
|
|
log("Cannot compute a free port. socket error.");
|
|
|
|
return defaultPort;
|
|
|
|
}
|
|
|
|
|
|
|
|
int enable = 1;
|
|
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
|
|
|
|
(char*) &enable, sizeof(enable)) < 0)
|
|
|
|
{
|
|
|
|
log("Cannot compute a free port. setsockopt error.");
|
|
|
|
return defaultPort;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bind to port 0. This is the standard way to get a free port.
|
|
|
|
struct sockaddr_in server; // server address information
|
|
|
|
server.sin_family = AF_INET;
|
|
|
|
server.sin_port = htons(0);
|
|
|
|
server.sin_addr.s_addr = inet_addr("127.0.0.1");
|
|
|
|
|
|
|
|
if (bind(sockfd, (struct sockaddr *)&server, sizeof(server)) < 0)
|
|
|
|
{
|
|
|
|
log("Cannot compute a free port. bind error.");
|
|
|
|
|
|
|
|
::close(sockfd);
|
|
|
|
return defaultPort;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct sockaddr_in sa; // server address information
|
2019-04-16 17:51:57 +02:00
|
|
|
socklen_t len;
|
2019-01-29 00:14:49 +01:00
|
|
|
if (getsockname(sockfd, (struct sockaddr *) &sa, &len) < 0)
|
|
|
|
{
|
|
|
|
log("Cannot compute a free port. getsockname error.");
|
|
|
|
|
|
|
|
::close(sockfd);
|
|
|
|
return defaultPort;
|
|
|
|
}
|
|
|
|
|
|
|
|
int port = ntohs(sa.sin_port);
|
|
|
|
::close(sockfd);
|
|
|
|
|
|
|
|
return port;
|
|
|
|
}
|
2019-01-29 00:23:33 +01:00
|
|
|
|
|
|
|
int getFreePort()
|
|
|
|
{
|
|
|
|
while (true)
|
|
|
|
{
|
2019-03-09 19:45:40 +01:00
|
|
|
#if defined(__has_feature)
|
|
|
|
# if __has_feature(address_sanitizer)
|
|
|
|
int port = getAnyFreePortSimple();
|
|
|
|
# else
|
2019-01-29 00:23:33 +01:00
|
|
|
int port = getAnyFreePort();
|
2019-03-09 19:45:40 +01:00
|
|
|
# endif
|
|
|
|
#else
|
|
|
|
int port = getAnyFreePort();
|
|
|
|
#endif
|
2019-01-29 00:23:33 +01:00
|
|
|
//
|
|
|
|
// Only port above 1024 can be used by non root users, but for some
|
|
|
|
// reason I got port 7 returned with macOS when binding on port 0...
|
|
|
|
//
|
|
|
|
if (port > 1024)
|
|
|
|
{
|
|
|
|
return port;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
2019-03-22 23:33:04 +01:00
|
|
|
|
|
|
|
void hexDump(const std::string& prefix,
|
|
|
|
const std::string& s)
|
|
|
|
{
|
|
|
|
std::ostringstream ss;
|
|
|
|
bool upper_case = false;
|
|
|
|
|
|
|
|
for (std::string::size_type i = 0; i < s.length(); ++i)
|
|
|
|
{
|
|
|
|
ss << std::hex
|
|
|
|
<< std::setfill('0')
|
|
|
|
<< std::setw(2)
|
|
|
|
<< (upper_case ? std::uppercase : std::nouppercase) << (int)s[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
std::cout << prefix << ": " << s << " => " << ss.str() << std::endl;
|
|
|
|
}
|
2018-12-30 03:33:15 +01:00
|
|
|
}
|