34 m_interfaces(interfaces) ,
36 m_server_type(server_type) ,
37 m_server_peer_config(server_peer_config) ,
38 m_server_config(server_config) ,
40 m_interface_event_timer(*this,&
MultiServer::onInterfaceEventTimeout,es)
43 std::sort( m_interfaces.begin() , m_interfaces.end() ) ;
44 m_interfaces.erase( std::unique(m_interfaces.begin(),m_interfaces.end()) , m_interfaces.end() ) ;
50 AddressList address_list = addresses( port , used_names , empty_names , bad_names ) ;
53 if( !bad_names.empty() )
54 throw InvalidName( bad_names.at(0) ) ;
58 throw NoListeningAddresses() ;
61 if( !empty_names.empty() )
63 if( !address_list.empty() )
64 G_WARNING(
"GNet::MultiServer::ctor: no addresses bound to named network interface"
65 << (empty_names.size()==1U?
"":
"s")
66 <<
" \"" <<
G::Str::join(
"\", \"",empty_names) <<
"\"" ) ;
68 G_WARNING(
"GNet::MultiServer::ctor: no listening addresses: waiting for interface"
69 << (empty_names.size()>1U?
"s ":
" ")
74 init( address_list ) ;
78 G_WARNING_ONCE(
"GNet::MultiServer::ctor: named network interfaces are not monitored for updates" ) ;
88 for(
auto & server : m_server_list )
94std::vector<GNet::Address> GNet::MultiServer::addresses(
unsigned int port )
const
100 return addresses( port , used_names , empty_names , bad_names ) ;
103std::vector<GNet::Address> GNet::MultiServer::addresses(
unsigned int port ,
G::StringArray & used_names ,
107 if( m_interfaces.empty() )
110 result.push_back( Address(Address::Family::ipv4,port) ) ;
112 result.push_back( Address(Address::Family::ipv6,port) ) ;
116 result = m_if.addresses( m_interfaces , port , used_names , empty_names , bad_names ) ;
121void GNet::MultiServer::init(
const AddressList & address_list )
123 for(
const auto & address : address_list )
125 m_server_list.emplace_back( std::make_unique<MultiServerImp>( *
this , m_es , address , m_server_peer_config , m_server_config ) ) ;
129void GNet::MultiServer::onInterfaceEvent(
const std::string & )
132 G_DEBUG(
"GNet::MultiServer::onInterfaceEvent: network configuration change event" ) ;
135 m_interface_event_timer.startTimer( 1U , 500000U ) ;
138bool GNet::MultiServer::match(
const Address & interface_address ,
const Address & server_address )
144 return interface_address.same( server_address , interface_address.scopeId() && server_address.scopeId() ) ;
147void GNet::MultiServer::onInterfaceEventTimeout()
149 AddressList address_list = addresses( m_port ) ;
152 for(
auto server_ptr_p = m_server_list.begin() ; server_ptr_p != m_server_list.end() ; )
154 Address server_address = (*server_ptr_p)->address() ;
155 G_DEBUG(
"GNet::MultiServer::onInterfaceEvent: server: "
156 << displayString(server_address) ) ;
158 auto address_match_p = std::find_if( address_list.begin() , address_list.end() ,
159 [&](Address & a){return match(a,server_address);} ) ;
161 if( address_match_p == address_list.end() )
163 G_LOG_S(
"GNet::MultiServer::onInterfaceEvent: deleting " << m_server_type
164 <<
" server on " << displayString(server_address) ) ;
165 server_ptr_p = m_server_list.erase( server_ptr_p ) ;
174 for(
const auto & address : address_list )
176 G_DEBUG(
"GNet::MultiServer::onInterfaceEvent: address: " << displayString(address) ) ;
177 if( !gotServerFor(address) )
181 m_server_list.emplace_back( std::make_unique<MultiServerImp>( *
this , m_es , address , m_server_peer_config , m_server_config ) ) ;
182 G_LOG_S(
"GNet::MultiServer::onInterfaceEvent: new " << m_server_type
183 <<
" server on " << displayString(address) ) ;
185 catch( Socket::SocketBindError & e )
188 G_LOG(
"GNet::MultiServer::onInterfaceEvent: failed to bind " << displayString(address)
189 <<
" for new " << m_server_type <<
" server:"
190 <<
G::Str::tail(e.what(),std::string(e.what()).rfind(
':')) ) ;
196bool GNet::MultiServer::gotServerFor(
const Address & interface_address )
const
198 return std::any_of( m_server_list.begin() , m_server_list.end() ,
199 [&interface_address](
const ServerPtr &ptr){return match(interface_address,ptr->address());} ) ;
204 return std::all_of( address_list.begin() , address_list.end() ,
205 [do_throw](
const Address & a){return Server::canBind(a,do_throw);} ) ;
208std::string GNet::MultiServer::displayString(
const Address & address )
215 for(
const auto & server : m_server_list )
217 G_LOG_S(
"GNet::MultiServer: " << m_server_type <<
" server on " << displayString(server->address()) ) ;
224 return newPeer( esu , pi , si ) ;
229 for(
const auto & server : m_server_list )
231 if( server->hasPeers() )
239 using List = std::vector<std::weak_ptr<ServerPeer>> ;
241 for(
auto & server : m_server_list )
243 List list = server->peers() ;
244 result.insert( result.end() , list.begin() , list.end() ) ;
253 GNet::
Server(es,address,server_peer_config,server_config) ,
271 return m_ms.doNewPeer( esu , peer_info , server_info ) ;
276GNet::MultiServer::ServerInfo::ServerInfo() :
277 m_address(
Address::defaultAddress())
The GNet::Address class encapsulates a TCP/UDP transport address.
static bool supports(Family)
Returns true if the implementation supports the given address family.
std::string displayString(bool with_scope_id=false) const
Returns a string which represents the transport address.
A potential ExceptionSink that is realised by bind()ing an exception source pointer.
A tuple containing an ExceptionHandler interface pointer and a bound 'exception source' pointer.
static bool active()
Returns true if the implementation can raise InterfacesHandler events.
std::unique_ptr< ServerPeer > newPeer(ExceptionSinkUnbound, ServerPeerInfo) final
Called by the base class to create a new ServerPeer.
~MultiServerImp() override
Destructor.
MultiServerImp(MultiServer &, ExceptionSink, const Address &, ServerPeerConfig, ServerConfig)
Constructor.
void cleanup()
Calls GNet::Server::serverCleanup().
A server that listens on more than one address using a facade pattern to multiple GNet::Server instan...
~MultiServer() override
Destructor.
static bool canBind(const AddressList &listening_address_list, bool do_throw)
Checks that all the specified addresses can be bound.
bool hasPeers() const
Returns true if peers() is not empty.
std::vector< std::weak_ptr< ServerPeer > > peers()
Returns the list of ServerPeer-derived objects.
void serverReport() const
Writes to the system log a summary of the underlying server objects and their addresses.
MultiServer(ExceptionSink listener_exception_sink, const G::StringArray &addresses, unsigned int port, const std::string &server_type, ServerPeerConfig server_peer_config, ServerConfig server_config)
Constructor.
void serverCleanup()
Should be called from all derived classes' destructors so that peer objects can use their Server obje...
std::unique_ptr< ServerPeer > doNewPeer(ExceptionSinkUnbound, const ServerPeerInfo &, const ServerInfo &)
Pseudo-private method used by the pimple class.
A structure that GNet::Server uses to configure its ServerPeer objects.
A structure used in GNet::Server::newPeer().
A network server class which listens on a specific port and spins off ServerPeer objects for each inc...
static bool supports(Address::Family)
Returns true if stream sockets can be created with the given the address family.
static std::string join(const std::string &sep, const StringArray &strings)
Concatenates an array of strings with separators.
static std::string tail(const std::string &in, std::size_t pos, const std::string &default_=std::string())
Returns the last part of the string after the given position.
std::vector< std::string > StringArray
A std::vector of std::strings.
A structure used in GNet::MultiServer::newPeer().
Address m_address
The server address that the peer connected to.
A configuration structure for GNet::Server.