35 m_listener_list(listener_list) ,
37 m_server_type(server_type) ,
38 m_server_peer_config(server_peer_config) ,
39 m_server_config(server_config) ,
41 m_interface_event_timer(*this,&
MultiServer::onInterfaceEventTimeout,es)
43 Listeners listeners( m_if , m_listener_list , m_port ) ;
47 throw InvalidName( listeners.
badName() ) ;
51 throw NoListeningAddresses() ;
56 G_WARNING(
"GNet::MultiServer::ctor: no addresses bound to named network interface"
61 if( listeners.
idle() )
63 G_WARNING(
"GNet::MultiServer::ctor: " << m_server_type <<
" server: nothing to do: "
64 <<
"waiting for interface" << listeners.
logEmpties() ) ;
70 G_WARNING_ONCE(
"GNet::MultiServer::ctor: named network interfaces "
71 "are not being monitored for address updates" ) ;
75 for(
const auto & fd : listeners.
fds() )
77 for(
const auto & a : listeners.
fixed() )
78 createServer( a ,
true ) ;
79 for(
const auto & a : listeners.
dynamic() )
80 createServer( a ,
false ) ;
88void GNet::MultiServer::createServer(
Descriptor fd )
90 m_server_list.emplace_back( std::make_unique<MultiServerImp>( *
this , m_es ,
91 fd , m_server_peer_config , m_server_config ) ) ;
94void GNet::MultiServer::createServer(
const Address & address ,
bool fixed )
96 m_server_list.emplace_back( std::make_unique<MultiServerImp>( *
this , m_es ,
97 fixed , address , m_server_peer_config , m_server_config ) ) ;
100void GNet::MultiServer::createServer(
const Address & address ,
bool fixed , std::nothrow_t )
104 createServer( address , fixed ) ;
105 G_LOG_S(
"GNet::MultiServer::createServer: new " << m_server_type
106 <<
" server on " << displayString(address) ) ;
108 catch( Socket::SocketBindError & e )
111 G_LOG(
"GNet::MultiServer::createServer: failed to bind " << displayString(address)
112 <<
" for new " << m_server_type <<
" server:"
113 <<
G::Str::tail(e.what(),std::string_view(e.what()).rfind(
':')) ) ;
119 for(
auto & server : m_server_list )
125void GNet::MultiServer::onInterfaceEvent(
const std::string & )
128 G_DEBUG(
"GNet::MultiServer::onInterfaceEvent: network configuration change event" ) ;
130 m_interface_event_timer.startTimer( 1U , 500000U ) ;
133void GNet::MultiServer::onInterfaceEventTimeout()
136 Listeners listeners( m_if , m_listener_list , m_port ) ;
139 for(
auto server_iter = m_server_list.begin() ; server_iter != m_server_list.end() ; )
141 if( (*server_iter)->dynamic() && !gotAddressFor( **server_iter , listeners.dynamic() ) )
142 server_iter = removeServer( server_iter ) ;
148 for(
const auto & address : listeners.dynamic() )
150 G_DEBUG(
"GNet::MultiServer::onInterfaceEvent: address: " << displayString(address) ) ;
151 if( !gotServerFor(address) )
153 createServer( address ,
true , std::nothrow ) ;
158GNet::MultiServer::ServerList::iterator GNet::MultiServer::removeServer( ServerList::iterator iter )
161 G_LOG_S(
"GNet::MultiServer::removeServer: deleting " << m_server_type
162 <<
" server on " << displayString(ptr->address()) ) ;
163 return m_server_list.erase( iter ) ;
166bool GNet::MultiServer::match(
const Address & interface_address ,
const Address & server_address )
170 return interface_address.same( server_address , interface_address.scopeId() && server_address.scopeId() ) ;
173bool GNet::MultiServer::gotAddressFor(
const Listener & server ,
const AddressList & address_list )
const
175 Address server_address = server.address() ;
176 return address_list.end() != std::find_if( address_list.begin() , address_list.end() ,
177 [server_address](
const Address & a){ return match(a,server_address); } ) ;
180bool GNet::MultiServer::gotServerFor( Address interface_address )
const
182 return std::any_of( m_server_list.begin() , m_server_list.end() ,
183 [interface_address](
const ServerPtr &ptr){ return match(interface_address,ptr->address()); } ) ;
186std::string GNet::MultiServer::displayString(
const Address & address )
188 return address.displayString(
true ) ;
193 for(
const auto & server : m_server_list )
195 G_ASSERT( server.get() !=
nullptr ) ;
196 if( !server ) continue ;
197 G_LOG_S(
"GNet::MultiServer: " << (group.empty()?
"":
"[") << group << (group.empty()?
"":
"] ")
198 << m_server_type <<
" server on " << displayString(server->address()) ) ;
205 return newPeer( esu , std::move(pi) , si ) ;
210 for(
const auto & server : m_server_list )
212 G_ASSERT( server.get() !=
nullptr ) ;
213 if( !server ) continue ;
214 if( server->hasPeers() )
222 using List = std::vector<std::weak_ptr<ServerPeer>> ;
224 for(
auto & server : m_server_list )
226 G_ASSERT( server.get() !=
nullptr ) ;
227 if( !server ) continue ;
228 List list = server->peers() ;
229 result.insert( result.end() , list.begin() , list.end() ) ;
238 GNet::
Server(es,address,server_peer_config,server_config) ,
244GNet::MultiServerImp::MultiServerImp( MultiServer & ms , EventState es , Descriptor fd ,
245 ServerPeer::Config server_peer_config , Server::Config server_config ) :
246 GNet::Server(es,fd,server_peer_config,server_config) ,
252GNet::MultiServerImp::~MultiServerImp()
255bool GNet::MultiServerImp::dynamic()
const
260void GNet::MultiServerImp::cleanup()
267 MultiServer::ServerInfo server_info ;
268 server_info.m_address = address() ;
269 return m_ms.doNewPeer( esu , std::move(peer_info) , server_info ) ;
274GNet::MultiServer::ServerInfo::ServerInfo() :
275 m_address(Address::defaultAddress())
The GNet::Address class encapsulates a TCP/UDP transport address.
A class that encapsulates a network socket file descriptor and an associated windows event handle.
The EventStateUnbound class is used as a device to force factory methods to plumb-in an ExceptionSour...
A lightweight object containing an ExceptionHandler pointer, optional ExceptionSource pointer and opt...
Represents a set of listening inputs which can be file-descriptor, interface or network address.
bool defunct() const
Returns true if no inputs and static.
bool hasEmpties() const
Returns true if some named interfaces have no addresses.
std::string logEmpties() const
Returns a log-line snippet for hasEmpties().
const std::vector< int > & fds() const
Exposes the list of fd inputs.
bool idle() const
Returns true if no inputs but some interfaces might come up.
bool noUpdates() const
Returns true if some inputs are interfaces but GNet::Interfaces is not active().
const std::vector< Address > & fixed() const
Exposes the list of address inputs.
const std::vector< Address > & dynamic() const
Exposes the list of interface addresses.
std::string badName() const
Returns the first invalid input.
bool hasBad() const
Returns true if one or more inputs are invalid.
A server that listens on more than one address using a facade pattern to multiple GNet::Server instan...
~MultiServer() override
Destructor.
bool hasPeers() const
Returns true if peers() is not empty.
std::vector< std::weak_ptr< ServerPeer > > peers()
Returns the list of ServerPeer-derived objects.
std::unique_ptr< ServerPeer > doNewPeer(EventStateUnbound, ServerPeerInfo &&, const ServerInfo &)
Pseudo-private method used by the pimple class.
void serverReport(const std::string &group={}) const
Writes to the system log a summary of the underlying server objects and their addresses.
MultiServer(EventState es_listener, const G::StringArray &listen_list, unsigned int port, const std::string &server_type, ServerPeer::Config server_peer_config, Server::Config server_config)
Constructor.
void serverCleanup()
Should be called from all derived classes' destructors so that peer objects can use their Server obje...
A move-only structure used in GNet::Server::newPeer() and containing the new socket.
A network server class which listens on a specific port and spins off ServerPeer objects for each inc...
virtual std::unique_ptr< ServerPeer > newPeer(EventStateUnbound, ServerPeerInfo &&)=0
A factory method which new()s a ServerPeer-derived object.
static std::string tail(std::string_view in, std::size_t pos, std::string_view default_={})
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().
A configuration structure for GNet::ServerPeer.
A configuration structure for GNet::Server.