/* * IXTest.cpp * Author: Benjamin Sergeant * Copyright (c) 2018 Machine Zone. All rights reserved. */ #include "IXTest.h" #include #include #include #include #include #include #include #include #include #include #include #include namespace ix { std::atomic incomingBytes(0); std::atomic outgoingBytes(0); std::mutex Logger::_mutex; std::stack freePorts; void setupWebSocketTrafficTrackerCallback() { ix::WebSocket::setTrafficTrackerCallback( [](size_t size, bool incoming) { if (incoming) { incomingBytes += size; } else { outgoingBytes += size; } } ); } void reportWebSocketTraffic() { Logger() << incomingBytes; Logger() << "Incoming bytes: " << incomingBytes; Logger() << "Outgoing bytes: " << outgoingBytes; } void msleep(int ms) { std::chrono::duration duration(ms); std::this_thread::sleep_for(duration); } std::string generateSessionId() { auto now = std::chrono::system_clock::now(); auto seconds = std::chrono::duration_cast( now.time_since_epoch()).count(); return std::to_string(seconds); } void log(const std::string& msg) { Logger() << msg; } int getAnyFreePortRandom() { std::random_device rd; std::uniform_int_distribution dist(1024 + 1, 65535); return dist(rd); } int getAnyFreePort() { int defaultPort = 8090; int sockfd; if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { log("Cannot compute a free port. socket error."); return getAnyFreePortRandom(); } int enable = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char*) &enable, sizeof(enable)) < 0) { log("Cannot compute a free port. setsockopt error."); return getAnyFreePortRandom(); } // 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."); Socket::closeSocket(sockfd); return getAnyFreePortRandom(); } struct sockaddr_in sa; // server address information socklen_t len = sizeof(sa); if (getsockname(sockfd, (struct sockaddr *) &sa, &len) < 0) { log("Cannot compute a free port. getsockname error."); Socket::closeSocket(sockfd); return getAnyFreePortRandom(); } int port = ntohs(sa.sin_port); Socket::closeSocket(sockfd); return port; } int getFreePort() { while (true) { #if defined(__has_feature) # if __has_feature(address_sanitizer) int port = getAnyFreePortRandom(); # else int port = getAnyFreePort(); # endif #else int port = getAnyFreePort(); #endif // // 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; } 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; } bool startWebSocketEchoServer(ix::WebSocketServer& server) { server.setOnConnectionCallback( [&server](std::shared_ptr webSocket, std::shared_ptr connectionState) { webSocket->setOnMessageCallback( [webSocket, connectionState, &server](const ix::WebSocketMessagePtr& msg) { if (msg->type == ix::WebSocketMessageType::Open) { Logger() << "New connection"; Logger() << "Uri: " << msg->openInfo.uri; Logger() << "Headers:"; for (auto it : msg->openInfo.headers) { Logger() << it.first << ": " << it.second; } } else if (msg->type == ix::WebSocketMessageType::Close) { Logger() << "Closed connection"; } else if (msg->type == ix::WebSocketMessageType::Message) { for (auto&& client : server.getClients()) { if (client != webSocket) { client->send(msg->str, msg->binary); } } } } ); } ); auto res = server.listen(); if (!res.first) { Logger() << res.second; return false; } server.start(); return true; } }