41 bool defunct()
const ;
44 std::string badName()
const ;
45 bool hasEmpties()
const ;
46 std::string logEmpties()
const ;
47 bool noUpdates()
const ;
48 const std::vector<int> & fds()
const ;
49 const std::vector<Address> & fixed()
const ;
50 const std::vector<Address> & dynamic()
const ;
53 void addWildcards(
unsigned int ) ;
54 static int parseFd(
const std::string & ) ;
55 static bool isAddress(
const std::string & ,
unsigned int ) ;
56 static Address address(
const std::string & ,
unsigned int ) ;
57 static int af(
const std::string & ) ;
58 static std::string basename(
const std::string & ) ;
59 static bool isBad(
const std::string & ) ;
65 std::vector<Address> m_fixed ;
66 std::vector<Address> m_dynamic ;
67 std::vector<int> m_fds ;
73 m_listener_list(listener_list) ,
75 m_server_type(server_type) ,
76 m_server_peer_config(server_peer_config) ,
77 m_server_config(server_config) ,
79 m_interface_event_timer(*this,&
MultiServer::onInterfaceEventTimeout,es)
81 Listeners listeners( m_if , m_listener_list , m_port ) ;
84 if( listeners.hasBad() )
85 throw InvalidName( listeners.badName() ) ;
88 if( listeners.defunct() )
89 throw NoListeningAddresses() ;
92 if( listeners.hasEmpties() )
94 G_WARNING(
"GNet::MultiServer::ctor: no addresses bound to named network interface"
95 << listeners.logEmpties() ) ;
99 if( listeners.idle() )
101 G_WARNING(
"GNet::MultiServer::ctor: " << m_server_type <<
" server: nothing to do: "
102 <<
"waiting for interface" << listeners.logEmpties() ) ;
106 if( listeners.noUpdates() )
108 G_WARNING_ONCE(
"GNet::MultiServer::ctor: named network interfaces "
109 "are not being monitored for address updates" ) ;
113 for(
const auto & fd : listeners.fds() )
115 for(
const auto & a : listeners.fixed() )
116 createServer( a ,
true ) ;
117 for(
const auto & a : listeners.dynamic() )
118 createServer( a ,
false ) ;
126void GNet::MultiServer::createServer(
Descriptor fd )
128 m_server_list.emplace_back( std::make_unique<MultiServerImp>( *
this , m_es ,
129 fd , m_server_peer_config , m_server_config ) ) ;
132void GNet::MultiServer::createServer(
const Address & address ,
bool fixed )
134 m_server_list.emplace_back( std::make_unique<MultiServerImp>( *
this , m_es ,
135 fixed , address , m_server_peer_config , m_server_config ) ) ;
138void GNet::MultiServer::createServer(
const Address & address ,
bool fixed , std::nothrow_t )
142 createServer( address , fixed ) ;
143 G_LOG_S(
"GNet::MultiServer::createServer: new " << m_server_type
144 <<
" server on " << displayString(address) ) ;
146 catch( Socket::SocketBindError & e )
149 G_LOG(
"GNet::MultiServer::createServer: failed to bind " << displayString(address)
150 <<
" for new " << m_server_type <<
" server:"
157 for(
auto & server : m_server_list )
163void GNet::MultiServer::onInterfaceEvent(
const std::string & )
166 G_DEBUG(
"GNet::MultiServer::onInterfaceEvent: network configuration change event" ) ;
168 m_interface_event_timer.startTimer( 1U , 500000U ) ;
171void GNet::MultiServer::onInterfaceEventTimeout()
174 Listeners listeners( m_if , m_listener_list , m_port ) ;
177 for(
auto server_iter = m_server_list.begin() ; server_iter != m_server_list.end() ; )
179 if( (*server_iter)->dynamic() && !gotAddressFor( **server_iter , listeners.dynamic() ) )
180 server_iter = removeServer( server_iter ) ;
186 for(
const auto & address : listeners.dynamic() )
188 G_DEBUG(
"GNet::MultiServer::onInterfaceEvent: address: " << displayString(address) ) ;
189 if( !gotServerFor(address) )
191 createServer( address ,
true , std::nothrow ) ;
196GNet::MultiServer::ServerList::iterator GNet::MultiServer::removeServer( ServerList::iterator iter )
199 G_LOG_S(
"GNet::MultiServer::removeServer: deleting " << m_server_type
200 <<
" server on " << displayString(ptr->address()) ) ;
201 return m_server_list.erase( iter ) ;
204bool GNet::MultiServer::match(
const Address & interface_address ,
const Address & server_address )
208 return interface_address.same( server_address , interface_address.scopeId() && server_address.scopeId() ) ;
211bool GNet::MultiServer::gotAddressFor(
const Listener & server ,
const AddressList & address_list )
const
213 Address server_address = server.address() ;
214 return address_list.end() != std::find_if( address_list.begin() , address_list.end() ,
215 [server_address](
const Address & a){ return match(a,server_address); } ) ;
218bool GNet::MultiServer::gotServerFor( Address interface_address )
const
220 return std::any_of( m_server_list.begin() , m_server_list.end() ,
221 [interface_address](
const ServerPtr &ptr){ return match(interface_address,ptr->address()); } ) ;
224std::string GNet::MultiServer::displayString(
const Address & address )
226 return address.displayString(
true ) ;
231 for(
const auto & server : m_server_list )
233 G_ASSERT( server.get() !=
nullptr ) ;
234 if( !server ) continue ;
235 G_LOG_S(
"GNet::MultiServer: " << (group.empty()?
"":
"[") << group << (group.empty()?
"":
"] ")
236 << m_server_type <<
" server on " << displayString(server->address()) ) ;
243 return newPeer( esu , std::move(pi) , si ) ;
248 for(
const auto & server : m_server_list )
250 G_ASSERT( server.get() !=
nullptr ) ;
251 if( !server ) continue ;
252 if( server->hasPeers() )
260 using List = std::vector<std::weak_ptr<ServerPeer>> ;
262 for(
auto & server : m_server_list )
264 G_ASSERT( server.get() !=
nullptr ) ;
265 if( !server ) continue ;
266 List list = server->peers() ;
267 result.insert( result.end() , list.begin() , list.end() ) ;
276 GNet::
Server(es,address,server_peer_config,server_config) ,
282GNet::MultiServerImp::MultiServerImp( MultiServer & ms , ExceptionSink es , Descriptor fd ,
283 ServerPeer::Config server_peer_config , Server::Config server_config ) :
284 GNet::Server(es,fd,server_peer_config,server_config) ,
290GNet::MultiServerImp::~MultiServerImp()
293bool GNet::MultiServerImp::dynamic()
const
298void GNet::MultiServerImp::cleanup()
305 MultiServer::ServerInfo server_info ;
306 server_info.m_address = address() ;
307 return m_ms.doNewPeer( esu , std::move(peer_info) , server_info ) ;
312GNet::MultiServer::ServerInfo::ServerInfo() :
313 m_address(Address::defaultAddress())
319GNet::Listeners::Listeners( Interfaces & if_ ,
const G::StringArray & listener_list ,
unsigned int port )
322 for(
const auto & listener : listener_list )
324 int fd = G::is_windows() ? -1 : parseFd( listener ) ;
327 m_fds.push_back( fd ) ;
329 else if( isAddress(listener,port) )
331 m_fixed.push_back( address(listener,port) ) ;
335 std::size_t n = if_.addresses( m_dynamic , basename(listener) , port , af(listener) ) ;
336 if( n == 0U && isBad(listener) )
338 (n?m_used:m_empties).push_back( listener ) ;
342 addWildcards( port ) ;
345int GNet::Listeners::af(
const std::string & s )
355std::string GNet::Listeners::basename(
const std::string & s )
359 s.substr( 0U , s.length()-5U ) :
363int GNet::Listeners::parseFd(
const std::string & listener )
365 if( listener.size() > 3U && listener.find(
"fd#") == 0U &&
G::Str::isUInt(listener.substr(3U)) )
368 if( fd < 0 )
throw MultiServer::InvalidFd( listener ) ;
374void GNet::Listeners::addWildcards(
unsigned int port )
377 m_fixed.emplace_back( Address::Family::ipv4 , port ) ;
380 m_fixed.emplace_back( Address::Family::ipv6 , port ) ;
383bool GNet::Listeners::isAddress(
const std::string & s ,
unsigned int port )
388GNet::Address GNet::Listeners::address(
const std::string & s ,
unsigned int port )
393bool GNet::Listeners::empty()
const
395 return m_fds.empty() && m_fixed.empty() && m_dynamic.empty() ;
398bool GNet::Listeners::defunct()
const
403bool GNet::Listeners::idle()
const
408bool GNet::Listeners::noUpdates()
const
413bool GNet::Listeners::isBad(
const std::string & s )
419 return s.empty() || ( s.find(
'/') != std::string::npos && s.find(
"/dev/") != 0U ) ;
422bool GNet::Listeners::hasBad()
const
424 return !m_bad.empty() ;
427std::string GNet::Listeners::badName()
const
432bool GNet::Listeners::hasEmpties()
const
434 return !m_empties.empty() ;
437std::string GNet::Listeners::logEmpties()
const
439 return std::string(m_empties.size()==1U?
" \"":
"s \"").append(
G::Str::join(
"\", \"",m_empties)).append(1U,
'"') ;
442const std::vector<int> & GNet::Listeners::fds()
const
447const std::vector<GNet::Address> & GNet::Listeners::fixed()
const
452const std::vector<GNet::Address> & GNet::Listeners::dynamic()
const
The GNet::Address class encapsulates a TCP/UDP transport address.
static bool validStrings(const std::string &ip, const std::string &port_string, std::string *reason=nullptr)
Returns true if the combined network-address string and port string is valid.
static Address parse(const std::string &display_string)
Factory function for any address family.
A class that encapsulates a network socket file descriptor and an associated windows event handle.
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.
A class for getting a list of network interfaces and their addresses.
static bool active()
Returns true if the implementation can raise InterfacesHandler events.
Used by GNet::MultiServer to represent a set of listening inputs (fd, interface or address).
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.
MultiServer(ExceptionSink listener_exception_sink, const G::StringArray &listen_list, unsigned int port, const std::string &server_type, ServerPeer::Config server_peer_config, Server::Config server_config)
Constructor.
void serverReport(const std::string &group={}) const
Writes to the system log a summary of the underlying server objects and their addresses.
std::unique_ptr< ServerPeer > doNewPeer(ExceptionSinkUnbound, ServerPeerInfo &&, const ServerInfo &)
Pseudo-private method used by the pimple class.
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(ExceptionSinkUnbound, ServerPeerInfo &&)=0
A factory method which new()s a ServerPeer-derived object.
static bool supports(Address::Family)
Returns true if stream sockets can be created with the given the address family.
static int toInt(string_view s)
Converts string 's' to an int.
static bool tailMatch(const std::string &in, string_view ending) noexcept
Returns true if the string has the given ending (or the given ending is empty).
static std::string join(string_view sep, const StringArray &strings)
Concatenates an array of strings with separators.
static bool isUInt(string_view s) noexcept
Returns true if the string can be converted into an unsigned integer without throwing an exception.
static std::string fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
static std::string tail(string_view in, std::size_t pos, string_view default_={})
Returns the last part of the string after the given position.
A class like c++17's std::string_view.
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.