gserver.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 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 // 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 "gmemory.h"
31 #include <algorithm> // std::find()
32 
34  m_address(peer_info.m_address) ,
35  m_socket(peer_info.m_socket) ,
36  m_sp(*this,*this,*m_socket.get(),0U) ,
37  m_handle(peer_info.m_handle) ,
38  m_delete_timer(*this,&ServerPeer::onTimeout,*this)
39 {
40  G_ASSERT( m_socket.get() != NULL ) ;
41  G_DEBUG( "GNet::ServerPeer::ctor: [" << this << "]: " << logId() ) ;
42 
43  m_socket->addReadHandler( *this ) ;
44  m_socket->addExceptionHandler( *this ) ;
46 }
47 
49 {
50  G_DEBUG( "GNet::ServerPeer::dtor: [" << this << "]: fd " << logId() ) ;
52  m_handle->reset() ;
53  m_socket->dropReadHandler() ;
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() != NULL ) ;
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() != NULL ) ;
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 
121 {
122  try
123  {
124  if( m_sp.writeEvent() )
125  onSendComplete() ;
126  }
127  catch( std::exception & e ) // strategy
128  {
129  G_WARNING( "GNet::ServerPeer::writeEvent: exception: " << e.what() ) ;
130  doDelete() ;
131  }
132 }
133 
134 // ===
135 
136 GNet::Server::Server( unsigned int listening_port , ConnectionLookup * connection_lookup ) :
137  m_connection_lookup(connection_lookup)
138 {
139  init( listening_port ) ;
140 }
141 
142 GNet::Server::Server( const Address & listening_address , ConnectionLookup * connection_lookup ) :
143  m_connection_lookup(connection_lookup)
144 {
145  init( listening_address ) ;
146 }
147 
149  m_connection_lookup(NULL) ,
150  m_cleaned_up(false)
151 {
152 }
153 
154 void GNet::Server::init( unsigned int listening_port )
155 {
156  init( Address(listening_port) ) ;
157 }
158 
159 void GNet::Server::init( const Address & listening_address )
160 {
161  m_cleaned_up = false ;
162  m_socket <<= new StreamSocket( listening_address ) ;
163  G_DEBUG( "GNet::Server::init: listening on " << listening_address.displayString() ) ;
164  G::Root claim_root ;
165  if( ! m_socket->bind( listening_address ) )
166  throw CannotBind( listening_address.displayString() ) ;
167  if( ! m_socket->listen(G::limits::net_listen_queue) )
168  throw CannotListen() ;
169  m_socket->addReadHandler( *this ) ;
170 }
171 
172 bool GNet::Server::canBind( const Address & address , bool do_throw )
173 {
174  G::Root claim_root ;
175  StreamSocket s ;
176  bool ok = s.canBindHint( address ) ;
177  if( !ok && do_throw )
178  throw CannotBind( address.displayString() ) ;
179  return ok ;
180 }
181 
183 {
184  serverCleanup() ;
185 }
186 
188 {
189  try
190  {
191  if( ! m_cleaned_up )
192  {
193  m_cleaned_up = true ;
194  serverCleanupCore() ;
195  }
196  }
197  catch(...) // dtor
198  {
199  }
200 }
201 
202 void GNet::Server::serverCleanupCore()
203 {
204  for( PeerList::iterator p = m_peer_list.begin() ; p != m_peer_list.end() ; ++p )
205  {
206  ServerPeerHandle handle = *p ;
207  if( handle.peer() != NULL )
208  {
209  G_DEBUG( "GNet::Server::serverCleanupCore: deleting peer: [" << handle.peer() << "]" ) ;
210  handle.peer()->doDeleteThis(1) ;
211  }
212  }
213 }
214 
215 void GNet::Server::onException( std::exception & e )
216 {
217  G_ERROR( "Server::onException: exception: " << e.what() ) ;
218  throw ; // out of the event loop
219 }
220 
221 std::pair<bool,GNet::Address> GNet::Server::address() const
222 {
223  std::pair<bool,Address> result( false , Address::invalidAddress() ) ;
224  if( m_socket.get() != NULL )
225  result = m_socket->getLocalAddress() ;
226  return result ;
227 }
228 
230 {
231  // read-event-on-listening-port => new connection to accept
232 
233  G_DEBUG( "GNet::Server::readEvent: " << this ) ;
234  G_ASSERT( m_socket.get() != NULL ) ;
235 
236  // take this opportunity to do garbage collection
237  collectGarbage() ;
238 
239  // accept the connection
240  PeerInfo peer_info ;
241  accept( peer_info ) ;
242  G_DEBUG( "GNet::Server::readEvent: new connection from " << peer_info.m_address.displayString()
243  << " (" << peer_info.m_name << ")" ) ;
244 
245  // keep track of peer objects
246  m_peer_list.push_back( ServerPeerHandle() ) ;
247  peer_info.m_handle = &m_peer_list.back() ;
248 
249  // create the peer object -- newPeer() implementations will normally
250  // catch their exceptions to avoid terminating the server
251  //
252  ServerPeer * peer = newPeer( peer_info ) ;
253 
254  // commit or roll back
255  if( peer == NULL )
256  {
257  m_peer_list.pop_back() ;
258  G_DEBUG( "GNet::Server::readEvent: connection rejected from " << peer_info.m_address.displayString() ) ;
259  }
260  else
261  {
262  m_peer_list.back().set( peer ) ;
263  G_DEBUG( "GNet::Server::readEvent: new connection accepted: " << peer->logId() ) ;
264  }
265 }
266 
267 void GNet::Server::accept( PeerInfo & peer_info )
268 {
269  {
270  G::Root claim_root ;
271  AcceptPair accept_pair = m_socket->accept() ;
272  peer_info.m_socket = accept_pair.first ; // auto_ptr assignment
273  peer_info.m_address = accept_pair.second ;
274  }
275 
276  if( G::Test::enabled("accept-throws") )
277  throw AcceptError() ;
278  if( peer_info.m_socket.get() == NULL )
279  throw AcceptError() ;
280 
281  // optionally enrich the peer info
282  if( m_connection_lookup != NULL )
283  {
284  std::pair<bool,Address> local = peer_info.m_socket->getLocalAddress() ;
285  if( local.first )
286  {
287  ConnectionLookup::Connection c = m_connection_lookup->find( local.second , peer_info.m_address ) ;
288  if( c.valid() )
289  peer_info.m_name = c.peerName() ;
290  }
291  }
292 }
293 
294 void GNet::Server::collectGarbage()
295 {
296  // cleanup empty handles, where peer objects have deleted themselves
297  G_DEBUG( "GNet::Server::collectGarbage" ) ;
298  for( PeerList::iterator p = m_peer_list.begin() ; p != m_peer_list.end() ; )
299  {
300  ServerPeerHandle handle = *p ;
301  if( handle.peer() == NULL )
302  {
303  G_DEBUG( "GNet::Server::collectGarbage: [" << handle.old() << "]" ) ;
304  p = m_peer_list.erase( p ) ;
305  }
306  else
307  {
308  ++p ;
309  }
310  }
311 }
312 
314 {
315  G_DEBUG( "GNet::Server::writeEvent" ) ;
316 }
317 
318 // ===
319 
321  m_address(Address::invalidAddress()) ,
322  m_handle(NULL)
323 {
324 }
325 
326 // ===
327 
329  m_p(NULL) ,
330  m_old(NULL)
331 {
332 }
333 
335 {
336  m_p = NULL ;
337 }
338 
340 {
341  return m_p ;
342 }
343 
345 {
346  return m_old ;
347 }
348 
350 {
351  m_p = p ;
352  m_old = p ;
353 }
354 
virtual void onException(std::exception &)
Final override from GNet::EventHandler.
Definition: gserver.cpp:77
void removeServerPeer(const Connection &server_peer)
Removes a server connection.
Definition: gmonitor.cpp:134
bool canBindHint(const Address &address)
Returns true if the socket can probably be bound with the given address.
An abstract base class for the GNet::Server's connection to a remote client.
Definition: gserver.h:191
static bool canBind(const Address &listening_address, bool do_throw)
Checks that the specified address can be bound.
Definition: gserver.cpp:172
virtual std::pair< bool, Address > localAddress() const
Returns the local address.
Definition: gserver.cpp:89
virtual std::pair< bool, Address > peerAddress() const
Returns the peer address.
Definition: gserver.cpp:95
virtual void writeEvent()
Final override from GNet::EventHandler.
Definition: gserver.cpp:120
ServerPeer(Server::PeerInfo)
Constructor.
Definition: gserver.cpp:33
The Address class encapsulates an IP transport address.
Definition: gaddress.h:48
A class which acquires the process's special privileges on construction and releases them on destruct...
Definition: groot.h:49
std::string::size_type size_type
A std::size_t type.
Definition: md5.h:43
static Address invalidAddress()
Returns an invalid address.
ServerPeerHandle * m_handle
Definition: gserver.h:96
void set(ServerPeer *p)
Sets the pointer.
Definition: gserver.cpp:349
A class for getting more information about a connection from the operating system.
A structure used in the implementation of GNet::Server.
Definition: gserver.h:54
A derivation of Socket for a stream socket.
Definition: gsocket.h:270
std::string m_name
Definition: gserver.h:95
virtual void readEvent()
Final override from GNet::EventHandler.
Definition: gserver.cpp:229
#define G_ASSERT(test)
Definition: gassert.h:30
std::string displayString(bool with_port=true, bool with_scope_id=false) const
Returns a string which represents the address for debugging and diagnostics purposes.
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:148
first_type first
Definition: gsocket.h:252
StreamSocket & socket()
Returns a reference to the client-server connection socket.
Definition: gserver.cpp:66
static bool enabled()
Returns true if test features are enabled.
Definition: gtest.cpp:46
#define G_ERROR(expr)
Definition: glog.h:108
static Monitor * instance()
Returns the singleton pointer. Returns null if none.
Definition: gmonitor.cpp:105
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:246
virtual ~Server()
Destructor.
Definition: gserver.cpp:182
void doDeleteThis(int)
Does delete this. Should only be used by the GNet::Server class.
Definition: gserver.cpp:110
virtual void readEvent()
Final override from GNet::EventHandler.
Definition: gserver.cpp:72
#define G_DEBUG(expr)
Definition: glog.h:95
second_type second
Definition: gsocket.h:253
void addServerPeer(const Connection &server_peer)
Adds a server connection.
Definition: gmonitor.cpp:127
virtual std::string peerCertificate() const
Returns the peer's TLS certificate.
Definition: gserver.cpp:100
void reset()
Resets the pointer.
Definition: gserver.cpp:334
virtual void writeEvent()
Final override from GNet::EventHandler.
Definition: gserver.cpp:313
ServerPeer * old()
Returns the pointer value before it was reset().
Definition: gserver.cpp:344
std::string logId() const
Returns an identification string for logging purposes.
Definition: gserver.cpp:56
void init(unsigned int listening_port)
Initilisation after default construction.
Definition: gserver.cpp:154
void serverCleanup()
May be called from the derived class destructor in order to trigger early deletion of peer objects...
Definition: gserver.cpp:187
void sslAccept()
Waits for the peer to start a secure session.
Definition: gserver.cpp:61
virtual ~ServerPeer()
Destructor.
Definition: gserver.cpp:48
A structure used in GNet::Server::newPeer().
Definition: gserver.h:91
ServerPeerHandle()
Default constructor.
Definition: gserver.cpp:328
std::pair< bool, Address > address() const
Returns the listening address.
Definition: gserver.cpp:221
ServerPeer * peer()
Returns the pointer.
Definition: gserver.cpp:339
#define G_WARNING(expr)
Definition: glog.h:107
virtual void onException(std::exception &e)
Final override from GNet::EventHandler.
Definition: gserver.cpp:215