- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

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
33 GNet::ServerPeer::ServerPeer( Server::PeerInfo peer_info ) :
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 ) ;
45 if( Monitor::instance() ) Monitor::instance()->addServerPeer(*this) ;
46 }
47
48 GNet::ServerPeer::~ServerPeer()
49 {
50 G_DEBUG( "GNet::ServerPeer::dtor: [" << this << "]: fd " << logId() ) ;
51 if( Monitor::instance() ) Monitor::instance()->removeServerPeer(*this) ;
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
61 void GNet::ServerPeer::sslAccept()
62 {
63 m_sp.sslAccept() ;
64 }
65
66 GNet::StreamSocket & GNet::ServerPeer::socket()
67 {
68 G_ASSERT( m_socket.get() != NULL ) ;
69 return *m_socket.get() ;
70 }
71
72 void GNet::ServerPeer::readEvent()
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
100 std::string GNet::ServerPeer::peerCertificate() const
101 {
102 return m_sp.peerCertificate() ;
103 }
104
105 void GNet::ServerPeer::onTimeout()
106 {
107 doDeleteThis(1) ;
108 }
109
110 void GNet::ServerPeer::doDeleteThis( int )
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 void GNet::ServerPeer::writeEvent()
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
148 GNet::Server::Server() :
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
182 GNet::Server::~Server()
183 {
184 serverCleanup() ;
185 }
186
187 void GNet::Server::serverCleanup()
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
229 void GNet::Server::readEvent()
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
313 void GNet::Server::writeEvent()
314 {
315 G_DEBUG( "GNet::Server::writeEvent" ) ;
316 }
317
318 // ===
319
320 GNet::Server::PeerInfo::PeerInfo() :
321 m_address(Address::invalidAddress()) ,
322 m_handle(NULL)
323 {
324 }
325
326 // ===
327
328 GNet::ServerPeerHandle::ServerPeerHandle() :
329 m_p(NULL) ,
330 m_old(NULL)
331 {
332 }
333
334 void GNet::ServerPeerHandle::reset()
335 {
336 m_p = NULL ;
337 }
338
339 GNet::ServerPeer * GNet::ServerPeerHandle::peer()
340 {
341 return m_p ;
342 }
343
344 GNet::ServerPeer * GNet::ServerPeerHandle::old()
345 {
346 return m_old ;
347 }
348
349 void GNet::ServerPeerHandle::set( ServerPeer * p )
350 {
351 m_p = p ;
352 m_old = p ;
353 }
354
GNet::ServerPeer::onException
virtual void onException(std::exception &)
Final override from GNet::EventHandler.
Definition: gserver.cpp:77
GNet::Monitor::removeServerPeer
void removeServerPeer(const Connection &server_peer)
Removes a server connection.
Definition: gmonitor.cpp:134
GNet::Socket::canBindHint
bool canBindHint(const Address &address)
Returns true if the socket can probably be bound with the given address.
Definition: gsocket_unix.cpp:100
GNet::ServerPeer
An abstract base class for the GNet::Server's connection to a remote client.
Definition: gserver.h:191
gserver.h
GNet::Server::canBind
static bool canBind(const Address &listening_address, bool do_throw)
Checks that the specified address can be bound.
Definition: gserver.cpp:172
GNet::ServerPeer::localAddress
virtual std::pair< bool, Address > localAddress() const
Returns the local address.
Definition: gserver.cpp:89
GNet::ServerPeer::peerAddress
virtual std::pair< bool, Address > peerAddress() const
Returns the peer address.
Definition: gserver.cpp:95
GNet::ServerPeer::writeEvent
virtual void writeEvent()
Final override from GNet::EventHandler.
Definition: gserver.cpp:120
GNet::ServerPeer::ServerPeer
ServerPeer(Server::PeerInfo)
Constructor.
Definition: gserver.cpp:33
GNet::Address
The Address class encapsulates an IP transport address.
Definition: gaddress.h:48
GNet::Server::PeerInfo::m_address
Address m_address
Definition: gserver.h:94
G::Root
A class which acquires the process's special privileges on construction and releases them on destruct...
Definition: groot.h:49
md5::size_type
std::string::size_type size_type
A std::size_t type.
Definition: md5.h:43
GNet::Address::invalidAddress
static Address invalidAddress()
Returns an invalid address.
Definition: gaddress_ipv4.cpp:458
groot.h
GNet::Server::PeerInfo::m_handle
ServerPeerHandle * m_handle
Definition: gserver.h:96
gtest.h
GNet::ServerPeerHandle::set
void set(ServerPeer *p)
Sets the pointer.
Definition: gserver.cpp:349
GNet::ConnectionLookup
A class for getting more information about a connection from the operating system.
Definition: gconnectionlookup.h:42
G::limits::net_listen_queue
Definition: glimits.h:50
GNet::ServerPeerHandle
A structure used in the implementation of GNet::Server.
Definition: gserver.h:54
glimits.h
GNet::StreamSocket
A derivation of Socket for a stream socket.
Definition: gsocket.h:270
GNet::Server::PeerInfo::m_name
std::string m_name
Definition: gserver.h:95
GNet::Server::readEvent
virtual void readEvent()
Final override from GNet::EventHandler.
Definition: gserver.cpp:229
G_ASSERT
#define G_ASSERT(test)
Definition: gassert.h:30
GNet::Address::displayString
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.
Definition: gaddress_ipv4.cpp:581
GNet::ServerPeer::send
bool send(const std::string &data, std::string::size_type offset=0U)
Sends data down the socket to the peer.
Definition: gserver.cpp:115
gassert.h
GNet::Server::Server
Server()
Default constructor. Initialise with init().
Definition: gserver.cpp:148
GNet::AcceptPair::first
first_type first
Definition: gsocket.h:252
GNet::ServerPeer::socket
StreamSocket & socket()
Returns a reference to the client-server connection socket.
Definition: gserver.cpp:66
G::Test::enabled
static bool enabled()
Returns true if test features are enabled.
Definition: gtest.cpp:46
G_ERROR
#define G_ERROR(expr)
Definition: glog.h:108
GNet::Monitor::instance
static Monitor * instance()
Returns the singleton pointer. Returns null if none.
Definition: gmonitor.cpp:105
GNet::ServerPeer::doDelete
void doDelete(const std::string &=std::string())
Does "onDelete(); delete this".
Definition: gserver.cpp:83
GNet::Server::PeerInfo::PeerInfo
PeerInfo()
Definition: gserver.cpp:320
GNet::AcceptPair
A class which is used to return a new()ed socket to calling code, together with associated informatio...
Definition: gsocket.h:246
GNet::Server::~Server
virtual ~Server()
Destructor.
Definition: gserver.cpp:182
GNet::ServerPeer::doDeleteThis
void doDeleteThis(int)
Does delete this. Should only be used by the GNet::Server class.
Definition: gserver.cpp:110
GNet::ServerPeer::readEvent
virtual void readEvent()
Final override from GNet::EventHandler.
Definition: gserver.cpp:72
G_DEBUG
#define G_DEBUG(expr)
Definition: glog.h:95
gmonitor.h
GNet::AcceptPair::second
second_type second
Definition: gsocket.h:253
GNet::Monitor::addServerPeer
void addServerPeer(const Connection &server_peer)
Adds a server connection.
Definition: gmonitor.cpp:127
GNet::ServerPeer::peerCertificate
virtual std::string peerCertificate() const
Returns the peer's TLS certificate.
Definition: gserver.cpp:100
GNet::ServerPeerHandle::reset
void reset()
Resets the pointer.
Definition: gserver.cpp:334
GNet::Server::writeEvent
virtual void writeEvent()
Final override from GNet::EventHandler.
Definition: gserver.cpp:313
GNet::ServerPeerHandle::old
ServerPeer * old()
Returns the pointer value before it was reset().
Definition: gserver.cpp:344
GNet::ServerPeer::logId
std::string logId() const
Returns an identification string for logging purposes.
Definition: gserver.cpp:56
GNet::Server::init
void init(unsigned int listening_port)
Initilisation after default construction.
Definition: gserver.cpp:154
GNet::Server::serverCleanup
void serverCleanup()
May be called from the derived class destructor in order to trigger early deletion of peer objects...
Definition: gserver.cpp:187
GNet::ServerPeer::sslAccept
void sslAccept()
Waits for the peer to start a secure session.
Definition: gserver.cpp:61
gmemory.h
GNet::ServerPeer::~ServerPeer
virtual ~ServerPeer()
Destructor.
Definition: gserver.cpp:48
GNet::Server::PeerInfo
A structure used in GNet::Server::newPeer().
Definition: gserver.h:91
GNet::ServerPeerHandle::ServerPeerHandle
ServerPeerHandle()
Default constructor.
Definition: gserver.cpp:328
GNet::Server::address
std::pair< bool, Address > address() const
Returns the listening address.
Definition: gserver.cpp:221
GNet::ServerPeerHandle::peer
ServerPeer * peer()
Returns the pointer.
Definition: gserver.cpp:339
G_WARNING
#define G_WARNING(expr)
Definition: glog.h:107
gdebug.h
GNet::Server::onException
virtual void onException(std::exception &e)
Final override from GNet::EventHandler.
Definition: gserver.cpp:215