diff --git a/server/controlServer.cpp b/server/controlServer.cpp index af084fee..0bae102f 100644 --- a/server/controlServer.cpp +++ b/server/controlServer.cpp @@ -30,7 +30,12 @@ using namespace std; using json = nlohmann::json; -ControlServer::ControlServer(asio::io_service* io_service, size_t port, ControlMessageReceiver* controlMessageReceiver) : io_service_(io_service), port_(port), controlMessageReceiver_(controlMessageReceiver) +ControlServer::ControlServer(asio::io_service* io_service, size_t port, ControlMessageReceiver* controlMessageReceiver) : + acceptor_v4_(nullptr), + acceptor_v6_(nullptr), + io_service_(io_service), + port_(port), + controlMessageReceiver_(controlMessageReceiver) { } @@ -102,8 +107,16 @@ void ControlServer::onMessageReceived(ControlSession* connection, const std::str void ControlServer::startAccept() { - socket_ptr socket = make_shared(*io_service_); - acceptor_->async_accept(*socket, bind(&ControlServer::handleAccept, this, socket)); + if (acceptor_v4_) + { + socket_ptr socket_v4 = make_shared(*io_service_); + acceptor_v4_->async_accept(*socket_v4, bind(&ControlServer::handleAccept, this, socket_v4)); + } + if (acceptor_v6_) + { + socket_ptr socket_v6 = make_shared(*io_service_); + acceptor_v6_->async_accept(*socket_v6, bind(&ControlServer::handleAccept, this, socket_v6)); + } } @@ -136,36 +149,52 @@ void ControlServer::handleAccept(socket_ptr socket) void ControlServer::start() { - asio::ip::address address = asio::ip::address::from_string("::"); - tcp::endpoint endpoint(address, port_); + bool is_v6_only(true); + tcp::endpoint endpoint_v6(tcp::v6(), port_); try { - acceptor_ = make_shared(*io_service_, endpoint); + acceptor_v6_ = make_shared(*io_service_, endpoint_v6); + error_code ec; + acceptor_v6_->set_option(asio::ip::v6_only(false), ec); + asio::ip::v6_only option; + acceptor_v6_->get_option(option); + is_v6_only = option.value(); + LOG(DEBUG) << "IPv6 only: " << is_v6_only << "\n"; } catch (const asio::system_error& e) { LOG(ERROR) << "error creating TCP acceptor: " << e.what() << ", code: " << e.code() << "\n"; - if (e.code().value() == asio::error::address_family_not_supported) - { - endpoint = tcp::endpoint(tcp::v4(), port_); - acceptor_ = make_shared(*io_service_, endpoint); - } - else - throw; } - if (endpoint.protocol() == tcp::v6()) + + if (!acceptor_v6_ || is_v6_only) { - error_code ec; - acceptor_->set_option(asio::ip::v6_only(false), ec); + tcp::endpoint endpoint_v4(tcp::v4(), port_); + try + { + acceptor_v4_ = make_shared(*io_service_, endpoint_v4); + } + catch (const asio::system_error& e) + { + LOG(ERROR) << "error creating TCP acceptor: " << e.what() << ", code: " << e.code() << "\n"; + } } + startAccept(); } void ControlServer::stop() { - if (acceptor_) - acceptor_->cancel(); + if (acceptor_v4_) + { + acceptor_v4_->cancel(); + acceptor_v4_ = nullptr; + } + if (acceptor_v6_) + { + acceptor_v6_->cancel(); + acceptor_v6_ = nullptr; + } std::lock_guard mlock(mutex_); for (auto s: sessions_) s->stop(); diff --git a/server/controlServer.h b/server/controlServer.h index ff2d680d..c0a49fe8 100644 --- a/server/controlServer.h +++ b/server/controlServer.h @@ -65,7 +65,8 @@ private: // void acceptor(); mutable std::recursive_mutex mutex_; std::set> sessions_; - std::shared_ptr acceptor_; + std::shared_ptr acceptor_v4_; + std::shared_ptr acceptor_v6_; Queue> messages_; asio::io_service* io_service_; diff --git a/server/streamServer.cpp b/server/streamServer.cpp index fae6738e..104cc7c8 100644 --- a/server/streamServer.cpp +++ b/server/streamServer.cpp @@ -29,7 +29,11 @@ using namespace std; using json = nlohmann::json; -StreamServer::StreamServer(asio::io_service* io_service, const StreamServerSettings& streamServerSettings) : io_service_(io_service), settings_(streamServerSettings) +StreamServer::StreamServer(asio::io_service* io_service, const StreamServerSettings& streamServerSettings) : + io_service_(io_service), + acceptor_v4_(nullptr), + acceptor_v6_(nullptr), + settings_(streamServerSettings) { } @@ -385,7 +389,7 @@ void StreamServer::ProcessRequest(const jsonrpcpp::request_ptr request, jsonrpcp { if (request->method.find("Stream.SetMeta") == 0) { - /// Request: {"id":4,"jsonrpc":"2.0","method":"Stream.SetMeta","params":{"stream_id":"Spotify", + /// Request: {"id":4,"jsonrpc":"2.0","method":"Stream.SetMeta","params":{"id":"Spotify", /// "meta": {"album": "some album", "artist": "some artist", "track": "some track"...}}} /// /// Response: {"id":4,"jsonrpc":"2.0","result":{"stream_id":"Spotify"}} @@ -620,8 +624,16 @@ session_ptr StreamServer::getStreamSession(const std::string& clientId) const void StreamServer::startAccept() { - socket_ptr socket = make_shared(*io_service_); - acceptor_->async_accept(*socket, bind(&StreamServer::handleAccept, this, socket)); + if (acceptor_v4_) + { + socket_ptr socket_v4 = make_shared(*io_service_); + acceptor_v4_->async_accept(*socket_v4, bind(&StreamServer::handleAccept, this, socket_v4)); + } + if (acceptor_v6_) + { + socket_ptr socket_v6 = make_shared(*io_service_); + acceptor_v6_->async_accept(*socket_v6, bind(&StreamServer::handleAccept, this, socket_v6)); + } } @@ -672,29 +684,36 @@ void StreamServer::start() } streamManager_->start(); - asio::ip::address address = asio::ip::address::from_string("::"); - tcp::endpoint endpoint(address, settings_.port); + bool is_v6_only(true); + tcp::endpoint endpoint_v6(tcp::v6(), settings_.port); try { - acceptor_ = make_shared(*io_service_, endpoint); + acceptor_v6_ = make_shared(*io_service_, endpoint_v6); + error_code ec; + acceptor_v6_->set_option(asio::ip::v6_only(false), ec); + asio::ip::v6_only option; + acceptor_v6_->get_option(option); + is_v6_only = option.value(); + LOG(DEBUG) << "IPv6 only: " << is_v6_only << "\n"; } catch (const asio::system_error& e) { LOG(ERROR) << "error creating TCP acceptor: " << e.what() << ", code: " << e.code() << "\n"; - if (e.code().value() == asio::error::address_family_not_supported) - { - endpoint = tcp::endpoint(tcp::v4(), settings_.port); - acceptor_ = make_shared(*io_service_, endpoint); - } - else - throw; } - if (endpoint.protocol() == tcp::v6()) + if (!acceptor_v6_ || is_v6_only) { - error_code ec; - acceptor_->set_option(asio::ip::v6_only(false), ec); + tcp::endpoint endpoint_v4(tcp::v4(), settings_.port); + try + { + acceptor_v4_ = make_shared(*io_service_, endpoint_v4); + } + catch (const asio::system_error& e) + { + LOG(ERROR) << "error creating TCP acceptor: " << e.what() << ", code: " << e.code() << "\n"; + } } + startAccept(); } catch (const std::exception& e) @@ -733,10 +752,15 @@ void StreamServer::stop() controlServer_ = nullptr; } - if (acceptor_) + if (acceptor_v4_) { - acceptor_->cancel(); - acceptor_ = nullptr; + acceptor_v4_->cancel(); + acceptor_v4_ = nullptr; + } + if (acceptor_v6_) + { + acceptor_v6_->cancel(); + acceptor_v6_ = nullptr; } } diff --git a/server/streamServer.h b/server/streamServer.h index 8542cf10..bbc40a38 100644 --- a/server/streamServer.h +++ b/server/streamServer.h @@ -106,7 +106,8 @@ private: mutable std::recursive_mutex sessionsMutex_; std::set sessions_; asio::io_service* io_service_; - std::shared_ptr acceptor_; + std::shared_ptr acceptor_v4_; + std::shared_ptr acceptor_v6_; StreamServerSettings settings_; Queue> messages_;