E-MailRelay
gmonitor.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file gmonitor.cpp
19///
20
21#include "gdef.h"
22#include "gmonitor.h"
23#include "ggettext.h"
24#include "gstr.h"
25#include "gassert.h"
26#include <map>
27#include <deque>
28#include <algorithm> // std::swap()
29#include <utility> // std::swap()
30
31//| \class GNet::MonitorImp
32/// A pimple-pattern implementation class for GNet::Monitor.
33///
34class GNet::MonitorImp
35{
36public:
38 explicit MonitorImp( Monitor & monitor ) ;
39 void add( const Connection & , bool is_client ) ;
40 void remove( const Connection & , bool is_client ) noexcept ;
41 void add( const Listener & ) ;
42 void remove( const Listener & ) noexcept ;
43 void report( std::ostream & s , const std::string & px , const std::string & eol ) const ;
44 void report( G::StringArray & ) const ;
45 static void emit( Signal & , const char * , const char * ) noexcept ;
46
47private:
48 struct ConnectionInfo
49 {
50 bool is_client ;
51 } ;
52 using ConnectionMap = std::map<const Connection*,ConnectionInfo> ;
53 using ServerMap = std::map<const Listener*,Address> ;
54
55public:
56 ~MonitorImp() = default ;
57 MonitorImp( const MonitorImp & ) = delete ;
58 MonitorImp( MonitorImp && ) = delete ;
59 MonitorImp & operator=( const MonitorImp & ) = delete ;
60 MonitorImp & operator=( MonitorImp && ) = delete ;
61
62private:
63 static void add( G::StringArray & , const std::string & , unsigned int , const std::string & , unsigned int , const std::string & ) ;
64 static void add( G::StringArray & , const std::string & , const std::string & ) ;
65 static void add( G::StringArray & , const std::string & , const std::string & , const std::string & ) ;
66
67private:
68 ConnectionMap m_connections ;
69 ServerMap m_servers ;
70 unsigned long m_client_adds {0UL} ;
71 unsigned long m_client_removes {0UL} ;
72 unsigned long m_server_peer_adds {0UL} ;
73 unsigned long m_server_peer_removes {0UL} ;
74} ;
75
76GNet::Monitor * & GNet::Monitor::pthis() noexcept
77{
78 static GNet::Monitor * p = nullptr ;
79 return p ;
80}
81
83 m_imp(std::make_unique<MonitorImp>(*this))
84{
85 G_ASSERT( pthis() == nullptr ) ;
86 pthis() = this ;
87}
88
90{
91 pthis() = nullptr ;
92}
93
95{
96 return pthis() ;
97}
98
100{
101 return m_signal ;
102}
103
105{
106 if( pthis() )
107 {
108 pthis()->m_imp->add( client , true ) ;
109 pthis()->m_imp->emit( pthis()->m_signal , "out" , "start" ) ;
110 }
111}
112
113void GNet::Monitor::removeClient( const Connection & client ) noexcept
114{
115 if( pthis() )
116 {
117 pthis()->m_imp->remove( client , true ) ;
118 pthis()->m_imp->emit( pthis()->m_signal , "out" , "stop" ) ;
119 }
120}
121
122void GNet::Monitor::addServerPeer( const Connection & server_peer )
123{
124 if( pthis() )
125 {
126 pthis()->m_imp->add( server_peer , false ) ;
127 pthis()->m_imp->emit( pthis()->m_signal , "in" , "start" ) ;
128 }
129}
130
131
132void GNet::Monitor::removeServerPeer( const Connection & server_peer ) noexcept
133{
134 if( pthis() )
135 {
136 pthis()->m_imp->remove( server_peer , false ) ;
137 pthis()->m_imp->emit( pthis()->m_signal , "in" , "stop" ) ;
138 }
139}
140
141void GNet::Monitor::addServer( const Listener & server )
142{
143 if( pthis() )
144 {
145 pthis()->m_imp->add( server ) ;
146 pthis()->m_imp->emit( pthis()->m_signal , "listen" , "start" ) ;
147 }
148}
149
150void GNet::Monitor::removeServer( const Listener & server ) noexcept
151{
152 if( pthis() )
153 {
154 pthis()->m_imp->remove( server ) ;
155 pthis()->m_imp->emit( pthis()->m_signal , "listen" , "stop" ) ;
156 }
157}
158
159void GNet::Monitor::report( std::ostream & s , const std::string & px , const std::string & eol ) const
160{
161 m_imp->report( s , px , eol ) ;
162}
163
164#ifndef G_LIB_SMALL
166{
167 m_imp->report( out ) ;
168}
169#endif
170
171// ==
172
173GNet::MonitorImp::MonitorImp( Monitor & )
174{
175}
176
177void GNet::MonitorImp::add( const Connection & connection , bool is_client )
178{
179 bool inserted = m_connections.insert(ConnectionMap::value_type(&connection,ConnectionInfo{is_client})).second ;
180 if( inserted )
181 {
182 if( is_client )
183 m_client_adds++ ;
184 else
185 m_server_peer_adds++ ;
186 }
187}
188
189void GNet::MonitorImp::add( const Listener & server )
190{
191 m_servers.insert( ServerMap::value_type(&server,server.address()) ) ;
192}
193
194void GNet::MonitorImp::emit( Signal & s , const char * a , const char * b ) noexcept
195{
196 try
197 {
198 s.emit( std::string(a) , std::string(b) ) ;
199 }
200 catch(...)
201 {
202 }
203}
204
205void GNet::MonitorImp::remove( const Connection & connection , bool is_client ) noexcept
206{
207 bool removed = 0U != m_connections.erase( &connection ) ; // noexcept since trivial Compare
208 if( removed )
209 {
210 if( is_client )
211 m_client_removes++ ;
212 else
213 m_server_peer_removes++ ;
214 }
215}
216
217void GNet::MonitorImp::remove( const Listener & server ) noexcept
218{
219 m_servers.erase( &server ) ; // noexcept since trivial Compare
220}
221
222void GNet::MonitorImp::report( std::ostream & s , const std::string & px , const std::string & eol ) const
223{
224 using G::txt ;
225 for( const auto & server : m_servers )
226 {
227 s << px << txt("LISTEN: ") << server.second.displayString(true) << eol ;
228 }
229
230 s << px << txt("OUT started: ") << m_client_adds << eol ;
231 s << px << txt("OUT finished: ") << m_client_removes << eol ;
232 {
233 for( const auto & connection : m_connections )
234 {
235 if( connection.second.is_client )
236 {
237 s << px
238 << txt("OUT: ")
239 << connection.first->localAddress().displayString() << " -> "
240 << connection.first->connectionState() << eol ;
241 }
242 }
243 }
244
245 s << px << txt("IN started: ") << m_server_peer_adds << eol ;
246 s << px << txt("IN finished: ") << m_server_peer_removes << eol ;
247 {
248 for( const auto & connection : m_connections )
249 {
250 if( !connection.second.is_client )
251 {
252 s << px
253 << txt("IN: ")
254 << connection.first->localAddress().displayString() << " <- "
255 << connection.first->peerAddress().displayString() << eol ;
256 }
257 }
258 }
259}
260
262{
263 for( const auto & server : m_servers )
264 add( out , "Listening address" , server.second.displayString() ) ;
265
266 using G::txt ;
267 add( out , txt("Outgoing connections") , m_client_adds , txt("started") , m_client_removes , txt("finished") ) ;
268 add( out , txt("Incoming connections") , m_server_peer_adds , txt("started") , m_server_peer_removes , txt("finished") ) ;
269 for( const auto & connection : m_connections )
270 {
271 if( connection.second.is_client )
272 {
273 add( out , txt("Outgoing connection") ,
274 connection.first->localAddress().displayString() ,
275 connection.first->connectionState() ) ;
276 }
277 }
278 for( const auto & connection : m_connections )
279 {
280 if( !connection.second.is_client )
281 add( out , txt("Incoming connection") ,
282 connection.first->localAddress().displayString() ,
283 connection.first->peerAddress().displayString() ) ;
284 }
285}
286
287void GNet::MonitorImp::add( G::StringArray & out , const std::string & key ,
288 unsigned int value_1 , const std::string & suffix_1 ,
289 unsigned int value_2 , const std::string & suffix_2 )
290{
291 add( out , key ,
292 G::Str::fromUInt(value_1).append(1U,' ').append(suffix_1) ,
293 G::Str::fromUInt(value_2).append(1U,' ').append(suffix_2) ) ;
294}
295
296void GNet::MonitorImp::add( G::StringArray & out , const std::string & key , const std::string & value )
297{
298 add( out , key , value , std::string() ) ;
299}
300
301void GNet::MonitorImp::add( G::StringArray & out , const std::string & key , const std::string & value_1 ,
302 const std::string & value_2 )
303{
304 out.push_back( key ) ;
305 out.push_back( value_1 ) ;
306 out.push_back( value_2 ) ;
307}
308
An abstract interface which provides information about a network connection.
Definition: gconnection.h:38
An interface for a network listener.
Definition: glistener.h:37
A singleton for monitoring GNet::Client and GNet::ServerPeer connections.
Definition: gmonitor.h:44
static void addServer(const Listener &server)
Adds a server.
Definition: gmonitor.cpp:141
static void removeClient(const Connection &client) noexcept
Removes a client connection.
Definition: gmonitor.cpp:113
static void addServerPeer(const Connection &server_peer)
Adds a server connection.
Definition: gmonitor.cpp:122
static void removeServer(const Listener &server) noexcept
Removes a server.
Definition: gmonitor.cpp:150
G::Slot::Signal< const std::string &, const std::string & > & signal()
Provides a callback signal which can be connect()ed to a slot.
Definition: gmonitor.cpp:99
void report(std::ostream &stream, const std::string &line_prefix={}, const std::string &eol=std::string("\n")) const
Reports itself onto a stream.
Definition: gmonitor.cpp:159
Monitor()
Default constructor.
Definition: gmonitor.cpp:82
static Monitor * instance()
Returns the singleton pointer. Returns nullptr if none.
Definition: gmonitor.cpp:94
~Monitor()
Destructor.
Definition: gmonitor.cpp:89
static void removeServerPeer(const Connection &server_peer) noexcept
Removes a server connection.
Definition: gmonitor.cpp:132
static void addClient(const Connection &client)
Adds a client connection.
Definition: gmonitor.cpp:104
static std::string fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
Definition: gstr.h:612
void report(const Server *, const std::string &group={})
Calls GPop::Server::report().
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30
const char * txt(const char *p) noexcept
A briefer alternative to G::gettext().
Definition: ggettext.h:74
STL namespace.