E-MailRelay
gmonitor.cpp
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2021 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 "gstr.h"
24#include "gassert.h"
25#include <map>
26#include <deque>
27#include <algorithm> // std::swap()
28#include <utility> // std::swap()
29
30//| \class GNet::MonitorImp
31/// A pimple-pattern implementation class for GNet::Monitor.
32///
34{
35public:
37 explicit MonitorImp( Monitor & monitor ) ;
38 void add( const Connection & , bool is_client ) ;
39 void remove( const Connection & , bool is_client ) noexcept ;
40 void add( const Listener & ) ;
41 void remove( const Listener & ) noexcept ;
42 void report( std::ostream & s , const std::string & px , const std::string & eol ) const ;
43 void report( G::StringArray & ) const ;
44 void emit( Signal & , const char * , const char * ) noexcept ;
45
46private:
47 struct ConnectionInfo
48 {
49 bool is_client ;
50 explicit ConnectionInfo( bool is_client_ ) noexcept : is_client(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 void operator=( const MonitorImp & ) = delete ;
60 void operator=( MonitorImp && ) = delete ;
61
62private:
63 static std::string join( const std::string & , const std::string & ) ;
64 static void add( G::StringArray & , const std::string & , unsigned int , const std::string & ,
65 unsigned int , const std::string & ) ;
66 static void add( G::StringArray & , const std::string & , const std::string & , const std::string & ,
67 const std::string & , const std::string & ) ;
68 static void add( G::StringArray & , const std::string & , const std::string & , const std::string & ) ;
69 static void add( G::StringArray & , const std::string & , const std::string & ) ;
70
71private:
72 ConnectionMap m_connections ;
73 ServerMap m_servers ;
74 unsigned long m_client_adds ;
75 unsigned long m_client_removes ;
76 unsigned long m_server_peer_adds ;
77 unsigned long m_server_peer_removes ;
78} ;
79
80GNet::Monitor * & GNet::Monitor::pthis() noexcept
81{
82 static GNet::Monitor * p = nullptr ;
83 return p ;
84}
85
87 m_imp(std::make_unique<MonitorImp>(*this))
88{
89 G_ASSERT( pthis() == nullptr ) ;
90 pthis() = this ;
91}
92
94{
95 pthis() = nullptr ;
96}
97
99{
100 return pthis() ;
101}
102
104{
105 return m_signal ;
106}
107
109{
110 if( pthis() )
111 {
112 pthis()->m_imp->add( client , true ) ;
113 pthis()->m_imp->emit( pthis()->m_signal , "out" , "start" ) ;
114 }
115}
116
117void GNet::Monitor::removeClient( const Connection & client ) noexcept
118{
119 if( pthis() )
120 {
121 pthis()->m_imp->remove( client , true ) ;
122 pthis()->m_imp->emit( pthis()->m_signal , "out" , "stop" ) ;
123 }
124}
125
126void GNet::Monitor::addServerPeer( const Connection & server_peer )
127{
128 if( pthis() )
129 {
130 pthis()->m_imp->add( server_peer , false ) ;
131 pthis()->m_imp->emit( pthis()->m_signal , "in" , "start" ) ;
132 }
133}
134
135
136void GNet::Monitor::removeServerPeer( const Connection & server_peer ) noexcept
137{
138 if( pthis() )
139 {
140 pthis()->m_imp->remove( server_peer , false ) ;
141 pthis()->m_imp->emit( pthis()->m_signal , "in" , "stop" ) ;
142 }
143}
144
145void GNet::Monitor::addServer( const Listener & server )
146{
147 if( pthis() )
148 {
149 pthis()->m_imp->add( server ) ;
150 pthis()->m_imp->emit( pthis()->m_signal , "listen" , "start" ) ;
151 }
152}
153
154void GNet::Monitor::removeServer( const Listener & server ) noexcept
155{
156 if( pthis() )
157 {
158 pthis()->m_imp->remove( server ) ;
159 pthis()->m_imp->emit( pthis()->m_signal , "listen" , "stop" ) ;
160 }
161}
162
163void GNet::Monitor::report( std::ostream & s , const std::string & px , const std::string & eol ) const
164{
165 m_imp->report( s , px , eol ) ;
166}
167
169{
170 m_imp->report( out ) ;
171}
172
173// ==
174
175GNet::MonitorImp::MonitorImp( Monitor & ) :
176 m_client_adds(0UL) ,
177 m_client_removes(0UL) ,
178 m_server_peer_adds(0UL) ,
179 m_server_peer_removes(0UL)
180{
181}
182
183void GNet::MonitorImp::add( const Connection & connection , bool is_client )
184{
185 bool inserted = m_connections.insert(ConnectionMap::value_type(&connection,ConnectionInfo(is_client))).second ;
186 if( inserted )
187 {
188 if( is_client )
189 m_client_adds++ ;
190 else
191 m_server_peer_adds++ ;
192 }
193}
194
195void GNet::MonitorImp::add( const Listener & server )
196{
197 m_servers.insert( ServerMap::value_type(&server,server.address()) ) ;
198}
199
200void GNet::MonitorImp::emit( Signal & s , const char * a , const char * b ) noexcept
201{
202 try
203 {
204 s.emit( std::string(a) , std::string(b) ) ;
205 }
206 catch(...)
207 {
208 }
209}
210
211void GNet::MonitorImp::remove( const Connection & connection , bool is_client ) noexcept
212{
213 bool removed = 0U != m_connections.erase( &connection ) ; // noexcept since trivial Compare
214 if( removed )
215 {
216 if( is_client )
217 m_client_removes++ ;
218 else
219 m_server_peer_removes++ ;
220 }
221}
222
223void GNet::MonitorImp::remove( const Listener & server ) noexcept
224{
225 m_servers.erase( &server ) ; // noexcept since trivial Compare
226}
227
228void GNet::MonitorImp::report( std::ostream & s , const std::string & px , const std::string & eol ) const
229{
230 for( const auto & server : m_servers )
231 {
232 s << px << "LISTEN: " << server.second.displayString(true) << eol ;
233 }
234
235 s << px << "OUT started: " << m_client_adds << eol ;
236 s << px << "OUT finished: " << m_client_removes << eol ;
237 {
238 for( const auto & connection : m_connections )
239 {
240 if( connection.second.is_client )
241 {
242 s << px
243 << "OUT: "
244 << connection.first->localAddress().second.displayString() << " -> "
245 << connection.first->connectionState() << eol ;
246 }
247 }
248 }
249
250 s << px << "IN started: " << m_server_peer_adds << eol ;
251 s << px << "IN finished: " << m_server_peer_removes << eol ;
252 {
253 for( const auto & connection : m_connections )
254 {
255 if( !connection.second.is_client )
256 {
257 s << px
258 << "IN: "
259 << connection.first->localAddress().second.displayString() << " <- "
260 << connection.first->peerAddress().second.displayString() << eol ;
261 }
262 }
263 }
264}
265
266void GNet::MonitorImp::report( G::StringArray & out ) const
267{
268 for( const auto & server : m_servers )
269 add( out , "Listening address" , server.second.displayString() ) ;
270
271 add( out , "Outgoing connections" , m_client_adds , "started" , m_client_removes , "finished" ) ;
272 add( out , "Incoming connections" , m_server_peer_adds , "started" , m_server_peer_removes , "finished" ) ;
273 for( const auto & connection : m_connections )
274 {
275 if( connection.second.is_client )
276 {
277 add( out , "Outgoing connection" , connection.first->localAddress().second.displayString() , "-->" ,
278 connection.first->connectionState() , "" ) ;
279 }
280 }
281 for( const auto & connection : m_connections )
282 {
283 if( !connection.second.is_client )
284 add( out , "Incoming connection" , connection.first->localAddress().second.displayString() , "<--" ,
285 connection.first->peerAddress().second.displayString() , "" ) ;
286 }
287}
288
289void GNet::MonitorImp::add( G::StringArray & out , const std::string & key ,
290 unsigned int value_1 , const std::string & suffix_1 ,
291 unsigned int value_2 , const std::string & suffix_2 )
292{
293 add( out , key , G::Str::fromUInt(value_1) , suffix_1 , G::Str::fromUInt(value_2) , suffix_2 ) ;
294}
295
296void GNet::MonitorImp::add( G::StringArray & out , const std::string & key ,
297 const std::string & value_1 , const std::string & suffix_1 ,
298 const std::string & value_2 , const std::string & suffix_2 )
299{
300 add( out , key , join(value_1,suffix_1) , join(value_2,suffix_2) ) ;
301}
302
303void GNet::MonitorImp::add( G::StringArray & out , const std::string & key , const std::string & value )
304{
305 add( out , key , value , std::string() ) ;
306}
307
308void GNet::MonitorImp::add( G::StringArray & out , const std::string & key , const std::string & value_1 ,
309 const std::string & value_2 )
310{
311 out.push_back( key ) ;
312 out.push_back( value_1 ) ;
313 out.push_back( value_2 ) ;
314}
315
316std::string GNet::MonitorImp::join( const std::string & s1 , const std::string & s2 )
317{
318 return s2.empty() ? s1 : ( s1 + " " + s2 ) ;
319}
320
An abstract interface which provides address information for a network connection.
Definition: gconnection.h:38
An interface for a network listener.
Definition: glistener.h:37
A pimple-pattern implementation class for GNet::Monitor.
Definition: gmonitor.cpp:34
A singleton for monitoring GNet::Client and GNet::ServerPeer connections.
Definition: gmonitor.h:43
static void addServer(const Listener &server)
Adds a server.
Definition: gmonitor.cpp:145
static void removeClient(const Connection &client) noexcept
Removes a client connection.
Definition: gmonitor.cpp:117
static void addServerPeer(const Connection &server_peer)
Adds a server connection.
Definition: gmonitor.cpp:126
static void removeServer(const Listener &server) noexcept
Removes a server.
Definition: gmonitor.cpp:154
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:103
void report(std::ostream &stream, const std::string &line_prefix=std::string(), const std::string &eol=std::string("\n")) const
Reports itself onto a stream.
Definition: gmonitor.cpp:163
Monitor()
Default constructor.
Definition: gmonitor.cpp:86
static Monitor * instance()
Returns the singleton pointer. Returns nullptr if none.
Definition: gmonitor.cpp:98
~Monitor()
Destructor.
Definition: gmonitor.cpp:93
static void removeServerPeer(const Connection &server_peer) noexcept
Removes a server connection.
Definition: gmonitor.cpp:136
static void addClient(const Connection &client)
Adds a client connection.
Definition: gmonitor.cpp:108
static std::string fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
Definition: gstr.h:579
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstrings.h:31