diff --git a/ws/CMakeLists.txt b/ws/CMakeLists.txt index 2bd98259..29a98283 100644 --- a/ws/CMakeLists.txt +++ b/ws/CMakeLists.txt @@ -55,6 +55,7 @@ add_executable(ws ws_cobra_metrics_to_redis.cpp ws_httpd.cpp ws_autobahn.cpp + ws_proxy_server.cpp ws.cpp) target_link_libraries(ws ixsnake) diff --git a/ws/ws.cpp b/ws/ws.cpp index 459835a6..e040822e 100644 --- a/ws/ws.cpp +++ b/ws/ws.cpp @@ -72,6 +72,7 @@ int main(int argc, char** argv) std::string redisPassword; std::string appsConfigPath("appsConfig.json"); std::string subprotocol; + std::string remoteHost; ix::SocketTLSOptions tlsOptions; std::string ciphers; std::string redirectUrl; @@ -99,6 +100,7 @@ int main(int argc, char** argv) int delayMs = -1; int count = 1; int jobs = 4; + int remotePort = 8008; uint32_t maxWaitBetweenReconnectionRetries; auto addTLSOptions = [&tlsOptions, &verifyNone](CLI::App* app) { @@ -304,6 +306,12 @@ int main(int argc, char** argv) redisServerApp->add_option("--port", port, "Port"); redisServerApp->add_option("--host", hostname, "Hostname"); + CLI::App* proxyServerApp = app.add_subcommand("proxy_server", "Proxy server"); + proxyServerApp->add_option("--port", port, "Port"); + proxyServerApp->add_option("--host", hostname, "Hostname"); + proxyServerApp->add_option("--remote_port", remotePort, "Remote Port"); + proxyServerApp->add_option("--remote_host", remoteHost, "Remote Hostname"); + CLI11_PARSE(app, argc, argv); // pid file handling @@ -442,6 +450,10 @@ int main(int argc, char** argv) { ret = ix::ws_redis_server_main(port, hostname); } + else if (app.got_subcommand("proxy_server")) + { + ret = ix::ws_proxy_server_main(port, hostname, tlsOptions, remoteHost, remotePort); + } else if (version) { std::cout << "ws " << ix::userAgent() << std::endl; diff --git a/ws/ws.h b/ws/ws.h index df41be5b..49eb1a94 100644 --- a/ws/ws.h +++ b/ws/ws.h @@ -142,4 +142,10 @@ namespace ix int ws_autobahn_main(const std::string& url, bool quiet); int ws_redis_server_main(int port, const std::string& hostname); + + int ws_proxy_server_main(int port, + const std::string& hostname, + const ix::SocketTLSOptions& tlsOptions, + const std::string& remoteHost, + int remotePort); } // namespace ix diff --git a/ws/ws_proxy_server.cpp b/ws/ws_proxy_server.cpp new file mode 100644 index 00000000..eaf073d7 --- /dev/null +++ b/ws/ws_proxy_server.cpp @@ -0,0 +1,75 @@ +/* + * ws_proxy_server.cpp + * Author: Benjamin Sergeant + * Copyright (c) 2018 Machine Zone, Inc. All rights reserved. + */ + +#include +#include +#include + +namespace ix +{ + int ws_proxy_server_main(int port, + const std::string& hostname, + const ix::SocketTLSOptions& tlsOptions, + const std::string& remoteHost, + int remotePort) + { + std::cout << "Listening on " << hostname << ":" << port << std::endl; + + ix::WebSocketServer server(port, hostname); + server.setTLSOptions(tlsOptions); + + server.setOnConnectionCallback( + [remoteHost, remotePort](std::shared_ptr webSocket, + std::shared_ptr connectionState) { + webSocket->setOnMessageCallback( + [webSocket, connectionState, remoteHost, remotePort](const WebSocketMessagePtr& msg) { + if (msg->type == ix::WebSocketMessageType::Open) + { + std::cerr << "New connection" << std::endl; + std::cerr << "id: " << connectionState->getId() << std::endl; + std::cerr << "Uri: " << msg->openInfo.uri << std::endl; + std::cerr << "Headers:" << std::endl; + for (auto it : msg->openInfo.headers) + { + std::cerr << it.first << ": " << it.second << std::endl; + } + } + else if (msg->type == ix::WebSocketMessageType::Close) + { + std::cerr << "Closed connection" + << " code " << msg->closeInfo.code << " reason " + << msg->closeInfo.reason << std::endl; + } + else if (msg->type == ix::WebSocketMessageType::Error) + { + std::stringstream ss; + ss << "Connection error: " << msg->errorInfo.reason << std::endl; + ss << "#retries: " << msg->errorInfo.retries << std::endl; + ss << "Wait time(ms): " << msg->errorInfo.wait_time << std::endl; + ss << "HTTP Status: " << msg->errorInfo.http_status << std::endl; + std::cerr << ss.str(); + } + else if (msg->type == ix::WebSocketMessageType::Message) + { + std::cerr << "Received " << msg->wireSize << " bytes" << std::endl; + webSocket->send(msg->str, msg->binary); + } + }); + }); + + auto res = server.listen(); + if (!res.first) + { + std::cerr << res.second << std::endl; + return 1; + } + + server.start(); + server.wait(); + + return 0; + } +} // namespace ix