diff --git a/src/protocol/util/AsyncEventServer.cpp b/src/protocol/util/AsyncEventServer.cpp index e9f9411ce1..0e460a6cb4 100644 --- a/src/protocol/util/AsyncEventServer.cpp +++ b/src/protocol/util/AsyncEventServer.cpp @@ -280,9 +280,34 @@ struct AsyncEventServer::implementation : public spl::enable_shared_from_this io_context, const protocol_strategy_factory::ptr& protocol, + const std::string& host, unsigned short port) : io_context_(std::move(io_context)) - , acceptor_(*io_context_, tcp::endpoint(tcp::v4(), port)) + , acceptor_([&]() { + boost::asio::ip::tcp::endpoint endpoint; + if (host.empty()) { + endpoint = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port); + } else { + try { + auto addr = boost::asio::ip::make_address(host); + // Only allow IPv4 to avoid crashes + if (addr.is_v6()) { + CASPAR_LOG(fatal) << "IPv6 addresses are not supported for host: " << host; + throw std::runtime_error("IPv6 not supported"); + } + endpoint = boost::asio::ip::tcp::endpoint(addr, port); + } catch (const std::exception& e) { + CASPAR_LOG(fatal) << "Invalid host address: " << host << " - " << e.what(); + throw; + } + } + tcp::acceptor a(*io_context_); + a.open(endpoint.protocol()); + a.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + a.bind(endpoint); + a.listen(); + return a; + }()) , protocol_factory_(protocol) { } @@ -353,7 +378,13 @@ struct AsyncEventServer::implementation : public spl::enable_shared_from_this io_context, const protocol_strategy_factory::ptr& protocol, unsigned short port) - : impl_(new implementation(std::move(io_context), protocol, port)) + : AsyncEventServer(io_context, protocol, "", port) {} + +AsyncEventServer::AsyncEventServer(std::shared_ptr io_context, + const protocol_strategy_factory::ptr& protocol, + const std::string& host, + unsigned short port) + : impl_(new implementation(std::move(io_context), protocol, host, port)) { impl_->start_accept(); } diff --git a/src/protocol/util/AsyncEventServer.h b/src/protocol/util/AsyncEventServer.h index 115ff07b1c..6e2b26fd06 100644 --- a/src/protocol/util/AsyncEventServer.h +++ b/src/protocol/util/AsyncEventServer.h @@ -38,7 +38,13 @@ class AsyncEventServer public: explicit AsyncEventServer(std::shared_ptr io_context, const protocol_strategy_factory::ptr& protocol, + const std::string& host, unsigned short port); + + AsyncEventServer(std::shared_ptr io_context, + const protocol_strategy_factory::ptr& protocol, + unsigned short port); + ~AsyncEventServer(); void add_client_lifecycle_object_factory(const lifecycle_factory_t& lifecycle_factory); diff --git a/src/shell/server.cpp b/src/shell/server.cpp index 6a56f5673f..64b16535bb 100644 --- a/src/shell/server.cpp +++ b/src/shell/server.cpp @@ -438,11 +438,14 @@ struct server::impl if (name == L"tcp") { auto port = ptree_get(xml_controller.second, L"port"); + std::wstring host_w = xml_controller.second.get(L"host", L""); + auto host_utf8 = u8(host_w); try { auto asyncbootstrapper = spl::make_shared( io_context_, create_protocol(protocol, L"TCP Port " + std::to_wstring(port)), + host_utf8, static_cast(port)); async_servers_.push_back(asyncbootstrapper);