VideoTools
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gserver.cpp
Go to the documentation of this file.
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 // gserver.cpp
19 //
20 
21 #include "gdef.h"
22 #include "gnet.h"
23 #include "glimits.h"
24 #include "gserver.h"
25 #include "groot.h"
26 #include "gmonitor.h"
27 #include "gdebug.h"
28 #include "gtest.h"
29 #include "gassert.h"
30 #include <algorithm> // std::find()
31 
33  m_address(peer_info.m_address) ,
34  m_socket(peer_info.m_socket) ,
35  m_sp(*this,*this,*m_socket.get(),0U) ,
36  m_handle(peer_info.m_handle) ,
37  m_delete_timer(*this,&ServerPeer::onTimeout,*this)
38 {
39  G_ASSERT( m_socket.get() != nullptr ) ;
40  G_DEBUG( "GNet::ServerPeer::ctor: [" << this << "]: " << logId() ) ;
41 
42  m_socket->addReadHandler( *this ) ;
43  m_socket->addExceptionHandler( *this ) ;
45 }
46 
48 {
49  G_DEBUG( "GNet::ServerPeer::dtor: [" << this << "]: fd " << logId() ) ;
51  m_handle->reset() ;
52  m_socket->dropReadHandler() ;
53  m_socket->dropExceptionHandler() ;
54 }
55 
56 std::string GNet::ServerPeer::logId() const
57 {
58  return m_address.displayString() + "@" + m_socket->asString() ;
59 }
60 
62 {
63  m_sp.sslAccept() ;
64 }
65 
67 {
68  G_ASSERT( m_socket.get() != nullptr ) ;
69  return *m_socket.get() ;
70 }
71 
73 {
74  m_sp.readEvent() ;
75 }
76 
77 void GNet::ServerPeer::onException( std::exception & e )
78 {
79  G_DEBUG( "ServerPeer::onException: exception: " << e.what() ) ;
80  doDelete( e.what() ) ;
81 }
82 
83 void GNet::ServerPeer::doDelete( const std::string & reason )
84 {
85  onDelete( reason ) ;
86  m_delete_timer.startTimer( 0U ) ;
87 }
88 
89 std::pair<bool,GNet::Address> GNet::ServerPeer::localAddress() const
90 {
91  G_ASSERT( m_socket.get() != nullptr ) ;
92  return m_socket->getLocalAddress() ;
93 }
94 
95 std::pair<bool,GNet::Address> GNet::ServerPeer::peerAddress() const
96 {
97  return std::pair<bool,Address>( true , m_address ) ;
98 }
99 
101 {
102  return m_sp.peerCertificate() ;
103 }
104 
105 void GNet::ServerPeer::onTimeout()
106 {
107  doDeleteThis(1) ;
108 }
109 
111 {
112  delete this ;
113 }
114 
115 bool GNet::ServerPeer::send( const std::string & data , std::string::size_type offset )
116 {
117  return m_sp.send( data , offset ) ;
118 }
119 
120 bool GNet::ServerPeer::send( const std::vector<std::pair<const char*,size_t> > & segments )
121 {
122  return m_sp.send( segments ) ;
123 }
124 
126 {
127  try
128  {
129  if( m_sp.writeEvent() )
130  onSendComplete() ;
131  }
132  catch( std::exception & e )
133  {
134  G_DEBUG( "GNet::ServerPeer::writeEvent: exception: " << e.what() ) ;
135  doDelete( e.what() ) ;
136  }
137 }
138 
139 // ===
140 
141 GNet::Server::Server( const Address & listening_address )
142 {
143  init( listening_address ) ;
144 }
145 
147  m_cleaned_up(false)
148 {
149 }
150 
151 void GNet::Server::init( const Address & listening_address )
152 {
153  m_cleaned_up = false ;
154  m_socket.reset( new StreamSocket(listening_address.domain()) ) ;
155  G_DEBUG( "GNet::Server::init: listening on socket " << m_socket->asString() << " with address " << listening_address.displayString() ) ;
156  {
157  G::Root claim_root ;
158  m_socket->bind( listening_address ) ;
159  }
160  m_socket->listen( G::limits::net_listen_queue ) ;
161  m_socket->addReadHandler( *this ) ;
162 }
163 
164 bool GNet::Server::canBind( const Address & address , bool do_throw )
165 {
166  StreamSocket socket( address.domain() ) ;
167  bool ok = false ;
168  {
169  G::Root claim_root ;
170  ok = socket.canBindHint( address ) ;
171  }
172  if( !ok && do_throw )
173  throw CannotBind( address.displayString() ) ;
174  return ok ;
175 }
176 
178 {
179  serverCleanup() ;
180 }
181 
183 {
184  try
185  {
186  if( ! m_cleaned_up )
187  {
188  m_cleaned_up = true ;
189  serverCleanupCore() ;
190  }
191  }
192  catch(...) // dtor
193  {
194  }
195 }
196 
197 void GNet::Server::serverCleanupCore()
198 {
199  for( PeerList::iterator p = m_peer_list.begin() ; p != m_peer_list.end() ; ++p )
200  {
201  ServerPeerHandle handle = *p ;
202  if( handle.peer() != nullptr )
203  {
204  G_DEBUG( "GNet::Server::serverCleanupCore: deleting peer: [" << handle.peer() << "]" ) ;
205  handle.peer()->doDeleteThis(1) ;
206  }
207  }
208 }
209 
210 std::pair<bool,GNet::Address> GNet::Server::address() const
211 {
212  std::pair<bool,Address> result( false , Address::defaultAddress() ) ;
213  if( m_socket.get() != nullptr )
214  result = m_socket->getLocalAddress() ;
215  return result ;
216 }
217 
219 {
220  // read-event-on-listening-port => new connection to accept
221 
222  G_DEBUG( "GNet::Server::readEvent: " << this ) ;
223  G_ASSERT( m_socket.get() != nullptr ) ;
224 
225  // take this opportunity to do garbage collection
226  collectGarbage() ;
227 
228  // accept the connection
229  PeerInfo peer_info ;
230  accept( peer_info ) ;
231  G_DEBUG( "GNet::Server::readEvent: new connection from " << peer_info.m_address.displayString()
232  << " on " << peer_info.m_socket->asString() ) ;
233 
234  // keep track of peer objects
235  m_peer_list.push_back( ServerPeerHandle() ) ;
236  peer_info.m_handle = &m_peer_list.back() ;
237 
238  // create the peer object -- newPeer() implementations will normally
239  // catch their exceptions to avoid terminating the server
240  //
241  ServerPeer * peer = newPeer( peer_info ) ;
242 
243  // commit or roll back
244  if( peer == nullptr )
245  {
246  m_peer_list.pop_back() ;
247  G_DEBUG( "GNet::Server::readEvent: connection rejected from " << peer_info.m_address.displayString() ) ;
248  }
249  else
250  {
251  m_peer_list.back().set( peer ) ;
252  G_DEBUG( "GNet::Server::readEvent: new connection accepted: " << peer->logId() ) ;
253  }
254 }
255 
256 void GNet::Server::accept( PeerInfo & peer_info )
257 {
258  {
259  G::Root claim_root ;
260  AcceptPair accept_pair = m_socket->accept() ;
261  peer_info.m_socket = accept_pair.first ;
262  peer_info.m_address = accept_pair.second ;
263  }
264  G_ASSERT( peer_info.m_socket.get() != nullptr ) ;
265 }
266 
267 void GNet::Server::collectGarbage()
268 {
269  // cleanup empty handles, where peer objects have deleted themselves
270  G_DEBUG( "GNet::Server::collectGarbage" ) ;
271  for( PeerList::iterator p = m_peer_list.begin() ; p != m_peer_list.end() ; )
272  {
273  ServerPeerHandle handle = *p ;
274  if( handle.peer() == nullptr )
275  {
276  G_DEBUG( "GNet::Server::collectGarbage: [" << handle.old() << "]" ) ;
277  p = m_peer_list.erase( p ) ;
278  }
279  else
280  {
281  ++p ;
282  }
283  }
284 }
285 
287 {
288  G_DEBUG( "GNet::Server::writeEvent" ) ;
289 }
290 
291 // ===
292 
293 GNet::Server::PeerInfo::PeerInfo() :
294  m_address(Address::defaultAddress()) ,
295  m_handle(nullptr)
296 {
297 }
298 
299 // ===
300 
302  m_p(nullptr) ,
303  m_old(nullptr)
304 {
305 }
306 
308 {
309  m_p = nullptr ;
310 }
311 
313 {
314  return m_p ;
315 }
316 
318 {
319  return m_old ;
320 }
321 
323 {
324  m_p = p ;
325  m_old = p ;
326 }
327 
328 /// \file gserver.cpp
void removeServerPeer(const Connection &server_peer)
Removes a server connection.
Definition: gmonitor.cpp:143
An abstract base class for the GNet::Server's connection to a remote client.
Definition: gserver.h:173
static bool canBind(const Address &listening_address, bool do_throw)
Checks that the specified address can be bound.
Definition: gserver.cpp:164
ServerPeer(Server::PeerInfo)
Constructor.
Definition: gserver.cpp:32
The GNet::Address class encapsulates a TCP/UDP transport address.
Definition: gaddress.h:55
A class which acquires the process's special privileges on construction and releases them on destruct...
Definition: groot.h:49
void set(ServerPeer *p)
Sets the pointer.
Definition: gserver.cpp:322
virtual void readEvent() override
Override from GNet::EventHandler.
Definition: gserver.cpp:72
virtual void writeEvent() override
Override from GNet::EventHandler.
Definition: gserver.cpp:286
A structure used in the implementation of GNet::Server.
Definition: gserver.h:52
A derivation of GNet::Socket for a stream socket.
Definition: gsocket.h:245
static Address defaultAddress()
Returns a default address, being the IPv4 wildcard address with a zero port number.
bool send(const std::string &data, std::string::size_type offset=0U)
Sends data down the socket to the peer.
Definition: gserver.cpp:115
Server()
Default constructor. Initialise with init().
Definition: gserver.cpp:146
StreamSocket & socket()
Returns a reference to the client-server connection socket.
Definition: gserver.cpp:66
static Monitor * instance()
Returns the singleton pointer. Returns null if none.
Definition: gmonitor.cpp:114
void doDelete(const std::string &=std::string())
Does "onDelete(); delete this".
Definition: gserver.cpp:83
A class which is used to return a new()ed socket to calling code, together with associated informatio...
Definition: gsocket.h:232
int domain() const
Returns the address 'domain', eg. PF_INET.
virtual ~Server()
Destructor.
Definition: gserver.cpp:177
void doDeleteThis(int)
Does delete this. Should only be used by the GNet::Server class.
Definition: gserver.cpp:110
virtual std::string peerCertificate() const override
Returns the peer's TLS certificate.
Definition: gserver.cpp:100
void addServerPeer(const Connection &server_peer)
Adds a server connection.
Definition: gmonitor.cpp:136
void reset()
Resets the pointer.
Definition: gserver.cpp:307
virtual std::pair< bool, Address > peerAddress() const override
Returns the peer address.
Definition: gserver.cpp:95
virtual void onException(std::exception &) g__final override
Override from GNet::EventHandler.
Definition: gserver.cpp:77
ServerPeer * old()
Returns the pointer value before it was reset().
Definition: gserver.cpp:317
virtual void writeEvent() override
Override from GNet::EventHandler.
Definition: gserver.cpp:125
std::string logId() const
Returns an identification string for logging purposes.
Definition: gserver.cpp:56
void serverCleanup()
May be called from the derived class destructor in order to trigger early deletion of peer objects...
Definition: gserver.cpp:182
void sslAccept()
Waits for the peer to start a secure session.
Definition: gserver.cpp:61
void init(const Address &listening_address)
Initilisation after default construction.
Definition: gserver.cpp:151
virtual ~ServerPeer()
Destructor.
Definition: gserver.cpp:47
A structure used in GNet::Server::newPeer().
Definition: gserver.h:86
ServerPeerHandle()
Default constructor.
Definition: gserver.cpp:301
virtual void readEvent() override
Override from GNet::EventHandler.
Definition: gserver.cpp:218
std::string displayString() const
Returns a string which represents the transport address for debugging and diagnostics purposes...
std::pair< bool, Address > address() const
Returns the listening address.
Definition: gserver.cpp:210
virtual std::pair< bool, Address > localAddress() const override
Returns the local address.
Definition: gserver.cpp:89
ServerPeer * peer()
Returns the pointer.
Definition: gserver.cpp:312