E-MailRelay
gmonitor.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2023 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 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 ;
71 unsigned long m_client_removes ;
72 unsigned long m_server_peer_adds ;
73 unsigned long m_server_peer_removes ;
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 m_client_adds(0UL) ,
175 m_client_removes(0UL) ,
176 m_server_peer_adds(0UL) ,
177 m_server_peer_removes(0UL)
178{
179}
180
181void GNet::MonitorImp::add( const Connection & connection , bool is_client )
182{
183 bool inserted = m_connections.insert(ConnectionMap::value_type(&connection,ConnectionInfo{is_client})).second ;
184 if( inserted )
185 {
186 if( is_client )
187 m_client_adds++ ;
188 else
189 m_server_peer_adds++ ;
190 }
191}
192
193void GNet::MonitorImp::add( const Listener & server )
194{
195 m_servers.insert( ServerMap::value_type(&server,server.address()) ) ;
196}
197
198void GNet::MonitorImp::emit( Signal & s , const char * a , const char * b ) noexcept
199{
200 try
201 {
202 s.emit( std::string(a) , std::string(b) ) ;
203 }
204 catch(...)
205 {
206 }
207}
208
209void GNet::MonitorImp::remove( const Connection & connection , bool is_client ) noexcept
210{
211 bool removed = 0U != m_connections.erase( &connection ) ; // noexcept since trivial Compare
212 if( removed )
213 {
214 if( is_client )
215 m_client_removes++ ;
216 else
217 m_server_peer_removes++ ;
218 }
219}
220
221void GNet::MonitorImp::remove( const Listener & server ) noexcept
222{
223 m_servers.erase( &server ) ; // noexcept since trivial Compare
224}
225
226void GNet::MonitorImp::report( std::ostream & s , const std::string & px , const std::string & eol ) const
227{
228 using G::txt ;
229 for( const auto & server : m_servers )
230 {
231 s << px << txt("LISTEN: ") << server.second.displayString(true) << eol ;
232 }
233
234 s << px << txt("OUT started: ") << m_client_adds << eol ;
235 s << px << txt("OUT finished: ") << m_client_removes << eol ;
236 {
237 for( const auto & connection : m_connections )
238 {
239 if( connection.second.is_client )
240 {
241 s << px
242 << txt("OUT: ")
243 << connection.first->localAddress().displayString() << " -> "
244 << connection.first->connectionState() << eol ;
245 }
246 }
247 }
248
249 s << px << txt("IN started: ") << m_server_peer_adds << eol ;
250 s << px << txt("IN finished: ") << m_server_peer_removes << eol ;
251 {
252 for( const auto & connection : m_connections )
253 {
254 if( !connection.second.is_client )
255 {
256 s << px
257 << txt("IN: ")
258 << connection.first->localAddress().displayString() << " <- "
259 << connection.first->peerAddress().displayString() << eol ;
260 }
261 }
262 }
263}
264
266{
267 for( const auto & server : m_servers )
268 add( out , "Listening address" , server.second.displayString() ) ;
269
270 using G::txt ;
271 add( out , txt("Outgoing connections") , m_client_adds , txt("started") , m_client_removes , txt("finished") ) ;
272 add( out , txt("Incoming connections") , m_server_peer_adds , txt("started") , m_server_peer_removes , txt("finished") ) ;
273 for( const auto & connection : m_connections )
274 {
275 if( connection.second.is_client )
276 {
277 add( out , txt("Outgoing connection") ,
278 connection.first->localAddress().displayString() ,
279 connection.first->connectionState() ) ;
280 }
281 }
282 for( const auto & connection : m_connections )
283 {
284 if( !connection.second.is_client )
285 add( out , txt("Incoming connection") ,
286 connection.first->localAddress().displayString() ,
287 connection.first->peerAddress().displayString() ) ;
288 }
289}
290
291void GNet::MonitorImp::add( G::StringArray & out , const std::string & key ,
292 unsigned int value_1 , const std::string & suffix_1 ,
293 unsigned int value_2 , const std::string & suffix_2 )
294{
295 add( out , key ,
296 G::Str::fromUInt(value_1).append(1U,' ').append(suffix_1) ,
297 G::Str::fromUInt(value_2).append(1U,' ').append(suffix_2) ) ;
298}
299
300void GNet::MonitorImp::add( G::StringArray & out , const std::string & key , const std::string & value )
301{
302 add( out , key , value , std::string() ) ;
303}
304
305void GNet::MonitorImp::add( G::StringArray & out , const std::string & key , const std::string & value_1 ,
306 const std::string & value_2 )
307{
308 out.push_back( key ) ;
309 out.push_back( value_1 ) ;
310 out.push_back( value_2 ) ;
311}
312
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:616
void report(const Server *, const std::string &group={})
Calls GPop::Server::report().
const char * txt(const char *p)
A briefer alternative to G::gettext().
Definition: ggettext.h:74
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstringarray.h:30
STL namespace.