VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gmonitor.cpp
1 //
2 // Copyright (C) 2017 Graeme Walker
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 // gmonitor.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gnet.h"
23 #include "glimits.h"
24 #include "gmonitor.h"
25 #include "gstr.h"
26 #include "gstrings.h"
27 #include "gassert.h"
28 #include <map>
29 #include <deque>
30 #include <algorithm> // std::swap
31 #include <utility> // std::swap
32 
33 /// \class GNet::MonitorImp
34 /// A pimple-pattern implementation class for GNet::Monitor.
35 ///
37 {
38 public:
39  explicit MonitorImp( Monitor & monitor ) ;
40  void add( const Connection & , bool is_client ) ;
41  void remove( const Connection & , bool is_client ) ;
42  void report( std::ostream & s , const std::string & px , const std::string & eol ) const ;
43  void report( G::StringArray & ) const ;
44  std::string certificateId( const std::string & certificiate ) ;
45  std::pair<std::string,bool> findCertificate( const std::string & certificate ) ;
46 
47 private:
48  static std::string join( const std::string & , const std::string & ) ;
49  static void add( G::StringArray & , const std::string & , unsigned int , const std::string & ,
50  unsigned int , const std::string & ) ;
51  static void add( G::StringArray & , const std::string & , const std::string & , const std::string & ,
52  const std::string & , const std::string & ) ;
53 
54 private:
55  struct ConnectionInfo
56  {
57  bool is_client ;
58  explicit ConnectionInfo( bool is_client_ ) : is_client(is_client_) {}
59  } ;
60  struct CertificateInfo
61  {
62  std::string certificate ;
63  int id ;
64  CertificateInfo( const std::string & c , int id_ ) : certificate(c) , id(id_) {}
65  bool match( std::string s ) const { return s == certificate ; }
66  } ;
67  struct CertificateMatch
68  {
69  const std::string & m_s ;
70  explicit CertificateMatch( const std::string & s ) : m_s(s) {}
71  bool operator()( const CertificateInfo & o ) const { return o.match(m_s) ; }
72  } ;
73  typedef std::map<const Connection*,ConnectionInfo> ConnectionMap ;
74  typedef std::deque<CertificateInfo> Certificates ;
75  ConnectionMap m_connections ;
76  Certificates m_certificates ;
77  int m_id_generator ;
78  unsigned long m_client_adds ;
79  unsigned long m_client_removes ;
80  unsigned long m_server_peer_adds ;
81  unsigned long m_server_peer_removes ;
82 } ;
83 
84 GNet::MonitorImp::MonitorImp( Monitor & ) :
85  m_id_generator(0) ,
86  m_client_adds(0UL) ,
87  m_client_removes(0UL) ,
88  m_server_peer_adds(0UL) ,
89  m_server_peer_removes(0UL)
90 {
91 }
92 
93 // ===
94 
95 GNet::Monitor * & GNet::Monitor::pthis()
96 {
97  static GNet::Monitor * p = nullptr ;
98  return p ;
99 }
100 
102  m_imp( new MonitorImp(*this) )
103 {
104  G_ASSERT( pthis() == nullptr ) ;
105  pthis() = this ;
106 }
107 
109 {
110  delete m_imp ;
111  pthis() = nullptr ;
112 }
113 
115 {
116  return pthis() ;
117 }
118 
120 {
121  return m_signal ;
122 }
123 
124 void GNet::Monitor::addClient( const Connection & client )
125 {
126  m_imp->add( client , true ) ;
127  m_signal.emit( "out" , "start" ) ;
128 }
129 
131 {
132  m_imp->remove( client , true ) ;
133  m_signal.emit( "out" , "end" ) ;
134 }
135 
136 void GNet::Monitor::addServerPeer( const Connection & server_peer )
137 {
138  m_imp->add( server_peer , false ) ;
139  m_signal.emit( "in" , "start" ) ;
140 }
141 
142 
143 void GNet::Monitor::removeServerPeer( const Connection & server_peer )
144 {
145  m_imp->remove( server_peer , false ) ;
146  m_signal.emit( "in" , "end" ) ;
147 }
148 
149 std::pair<std::string,bool> GNet::Monitor::findCertificate( const std::string & certificate )
150 {
151  return m_imp->findCertificate( certificate ) ;
152 }
153 
154 void GNet::Monitor::report( std::ostream & s , const std::string & px , const std::string & eol ) const
155 {
156  m_imp->report( s , px , eol ) ;
157 }
158 
160 {
161  m_imp->report( out ) ;
162 }
163 
164 // ==
165 
166 void GNet::MonitorImp::add( const Connection & connection , bool is_client )
167 {
168  bool inserted = m_connections.insert(ConnectionMap::value_type(&connection,ConnectionInfo(is_client))).second ;
169  if( inserted )
170  {
171  if( is_client )
172  m_client_adds++ ;
173  else
174  m_server_peer_adds++ ;
175  }
176 }
177 
178 void GNet::MonitorImp::remove( const Connection & connection , bool is_client )
179 {
180  bool removed = 0U != m_connections.erase( &connection ) ;
181  if( removed )
182  {
183  if( is_client )
184  m_client_removes++ ;
185  else
186  m_server_peer_removes++ ;
187  }
188 }
189 
190 void GNet::MonitorImp::report( std::ostream & s , const std::string & px , const std::string & eol ) const
191 {
192  s << px << "OUT started: " << m_client_adds << eol ;
193  s << px << "OUT finished: " << m_client_removes << eol ;
194  {
195  for( ConnectionMap::const_iterator p = m_connections.begin() ; p != m_connections.end() ; ++p )
196  {
197  if( (*p).second.is_client )
198  {
199  s << px
200  << "OUT: "
201  << (*p).first->localAddress().second.displayString() << " -> "
202  << (*p).first->peerAddress().second.displayString() << eol ;
203  }
204  }
205  }
206 
207  s << px << "IN started: " << m_server_peer_adds << eol ;
208  s << px << "IN finished: " << m_server_peer_removes << eol ;
209  {
210  for( ConnectionMap::const_iterator p = m_connections.begin() ; p != m_connections.end() ; ++p )
211  {
212  if( !(*p).second.is_client )
213  {
214  s << px
215  << "IN: "
216  << (*p).first->localAddress().second.displayString() << " <- "
217  << (*p).first->peerAddress().second.displayString() << eol ;
218  }
219  }
220  }
221 }
222 
223 void GNet::MonitorImp::report( G::StringArray & out ) const
224 {
225  add( out , "Outgoing connections" , m_client_adds , "started" , m_client_removes , "finished" ) ;
226  add( out , "Incoming connections" , m_server_peer_adds , "started" , m_server_peer_removes , "finished" ) ;
227  for( ConnectionMap::const_iterator p = m_connections.begin() ; p != m_connections.end() ; ++p )
228  {
229  if( (*p).second.is_client )
230  add( out , "Outgoing connection" , (*p).first->localAddress().second.displayString() , "-->" ,
231  (*p).first->peerAddress().second.displayString() , "" ) ;
232  }
233  for( ConnectionMap::const_iterator p = m_connections.begin() ; p != m_connections.end() ; ++p )
234  {
235  if( !(*p).second.is_client )
236  add( out , "Incoming connection" , (*p).first->localAddress().second.displayString() , "<--" ,
237  (*p).first->peerAddress().second.displayString() , "" ) ;
238  }
239 }
240 
241 void GNet::MonitorImp::add( G::StringArray & out , const std::string & key ,
242  unsigned int value_1 , const std::string & suffix_1 ,
243  unsigned int value_2 , const std::string & suffix_2 )
244 {
245  add( out , key , G::Str::fromUInt(value_1) , suffix_1 , G::Str::fromUInt(value_2) , suffix_2 ) ;
246 }
247 
248 std::string GNet::MonitorImp::join( const std::string & s1 , const std::string & s2 )
249 {
250  return s2.empty() ? s1 : ( s1 + " " + s2 ) ;
251 }
252 
253 void GNet::MonitorImp::add( G::StringArray & out , const std::string & key ,
254  const std::string & value_1 , const std::string & suffix_1 ,
255  const std::string & value_2 , const std::string & suffix_2 )
256 {
257  out.push_back( key ) ;
258  out.push_back( join(value_1,suffix_1) ) ;
259  out.push_back( join(value_2,suffix_2) ) ;
260 }
261 
262 std::pair<std::string,bool> GNet::MonitorImp::findCertificate( const std::string & certificate )
263 {
264  std::pair<std::string,bool> result( std::string() , false ) ;
265  if( certificate.empty() )
266  return result ;
267 
268  // lru cache
269  Certificates::iterator const end = m_certificates.end() ;
270  Certificates::iterator p = std::find_if( m_certificates.begin() , end , CertificateMatch(certificate) ) ;
271  if( p != end )
272  {
273  CertificateInfo tmp = *p ;
274  result.first = G::Str::fromInt( (*p).id ) ;
275  result.second = false ;
276  p = std::remove_if( m_certificates.begin() , end , CertificateMatch(certificate) ) ;
277  G_ASSERT( p != end ) ;
278  *p = tmp ; // (remove_if() doesnt remove; it moves the item to the end and returns its iterator)
279  }
280  else
281  {
282  const size_t limit = G::limits::net_certificate_cache_size ;
283  if( m_certificates.size() == limit && !m_certificates.empty() )
284  m_certificates.pop_front() ;
285  int id = ++m_id_generator ;
286  m_certificates.push_back( CertificateInfo(certificate,id) ) ;
287  result.first = G::Str::fromInt( id ) ;
288  result.second = true ;
289  }
290  return result ;
291 }
292 
void removeServerPeer(const Connection &server_peer)
Removes a server connection.
Definition: gmonitor.cpp:143
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:154
std::vector< std::string > StringArray
A std::vector of std::strings.
Definition: gstrings.h:33
void addClient(const Connection &simple_client)
Adds a client connection.
Definition: gmonitor.cpp:124
static std::string fromInt(int i)
Converts int 'i' to a string.
Definition: gstr.cpp:294
G::Slot::Signal2< std::string, std::string > & signal()
Provides a callback signal which can be connect()ed to a slot.
Definition: gmonitor.cpp:119
A pimple-pattern implementation class for GNet::Monitor.
Definition: gmonitor.cpp:36
static std::string fromUInt(unsigned int ui)
Converts unsigned int 'ui' to a string.
Definition: gstr.cpp:315
A singleton for monitoring GNet::SimpleClient and GNet::ServerPeer connections and for storing their ...
Definition: gmonitor.h:42
static Monitor * instance()
Returns the singleton pointer. Returns null if none.
Definition: gmonitor.cpp:114
virtual ~Monitor()
Destructor.
Definition: gmonitor.cpp:108
void removeClient(const Connection &simple_client)
Removes a client connection.
Definition: gmonitor.cpp:130
void addServerPeer(const Connection &server_peer)
Adds a server connection.
Definition: gmonitor.cpp:136
An interface which provides address information for a network connection.
Definition: gconnection.h:37
std::pair< std::string, bool > findCertificate(const std::string &certificate)
Returns a short id for the given certificate and a boolean flag to indicate if it is a new certificat...
Definition: gmonitor.cpp:149
Monitor()
Default constructor.
Definition: gmonitor.cpp:101