Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / net / callback_server.cpp
blobafb4fb3b3e979236318401e25db8fbaaeb8c20fb
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (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 Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "stdnet.h"
19 #include "nel/net/callback_server.h"
20 #include "nel/net/net_log.h"
23 #ifdef USE_MESSAGE_RECORDER
24 #include "nel/net/dummy_tcp_sock.h"
25 #endif
27 using namespace std;
28 using namespace NLMISC;
30 namespace NLNET {
34 * Connection callback (the disconnection callback is in callback_net_base.cpp
36 void cbsNewConnection (TSockId from, void *data)
38 nlassert (data != NULL);
39 CCallbackServer *server = (CCallbackServer *)data;
41 LNETL3_DEBUG("LNETL3S: newConnection()");
43 #ifdef USE_MESSAGE_RECORDER
44 // Record connection
45 server->noticeConnection( from );
46 #endif
48 // send all my association to the new client
49 // association are disactivated so we don t need to send them
50 // server->sendAllMyAssociations (from);
52 // call the client callback if necessary
53 if (server->_ConnectionCallback != NULL)
54 server->_ConnectionCallback (from, server->_ConnectionCbArg);
59 * Constructor
61 CCallbackServer::CCallbackServer( TRecordingState rec, const string& recfilename, bool recordall, bool initPipeForDataAvailable ) :
62 CCallbackNetBase( rec, recfilename, recordall ),
63 CBufServer( DEFAULT_STRATEGY, DEFAULT_MAX_THREADS, DEFAULT_MAX_SOCKETS_PER_THREADS, true, rec==Replay, initPipeForDataAvailable ),
64 _ConnectionCallback(NULL),
65 _ConnectionCbArg(NULL)
67 #ifndef USE_MESSAGE_RECORDER
68 nlassertex( rec==Off, ("LNETL3S: The message recorder is disabled at compilation time ; switch the recording state Off") );
69 #endif
71 CBufServer::setDisconnectionCallback (_NewDisconnectionCallback, this);
72 CBufServer::setConnectionCallback (cbsNewConnection, this);
74 _IsAServer = true;
75 _DefaultCallback = NULL;
80 * Send a message to the specified host (pushing to its send queue)
81 * Recorded : YES
82 * Replayed : MAYBE
84 void CCallbackServer::send (const CMessage &buffer, TSockId hostid, bool /* log */)
86 nlassert (connected ());
87 nlassert (buffer.length() != 0);
88 nlassert (buffer.typeIsSet());
90 if (hostid == InvalidSockId)
92 // broadcast
93 sint nb = nbConnections ();
94 _BytesSent += buffer.length () * nb;
96 else
98 _BytesSent += buffer.length ();
101 // if (log)
103 // LNETL3_DEBUG ("LNETL3S: Server: send(%s, %s)", buffer.toString().c_str(), hostid->asString().c_str());
106 #ifdef USE_MESSAGE_RECORDER
107 if ( _MR_RecordingState != Replay )
109 #endif
111 // Send
112 CBufServer::send (buffer, hostid);
114 #ifdef USE_MESSAGE_RECORDER
115 if ( _MR_RecordingState == Record )
117 // Record sent message
118 _MR_Recorder.recordNext( _MR_UpdateCounter, Sending, hostid, const_cast<CMessage&>(buffer) );
121 #endif
126 * Updates the network (call this method evenly)
127 * Recorded : YES (in baseUpdate())
128 * Replayed : YES (in baseUpdate())
130 void CCallbackServer::update2 ( sint32 timeout, sint32 mintime )
132 H_AUTO(L3UpdateServer);
134 nlassert (connected ());
136 // LNETL3_DEBUG ("LNETL3S: Client: update()");
137 baseUpdate2 ( timeout, mintime ); // first receive
139 #ifdef USE_MESSAGE_RECORDER
140 if ( _MR_RecordingState != Replay )
142 #endif
143 // L1-2 Update (nothing to do in replay mode)
144 CBufServer::update (); // then send
146 #ifdef USE_MESSAGE_RECORDER
148 #endif
153 * Updates the network (call this method evenly) (legacy)
154 * Recorded : YES (in baseUpdate())
155 * Replayed : YES (in baseUpdate())
157 void CCallbackServer::update ( sint32 timeout )
159 H_AUTO(L3UpdateServer);
161 nlassert (connected ());
163 // LNETL3_DEBUG ("LNETL3S: Client: update()");
164 baseUpdate ( timeout ); // first receive
166 #ifdef USE_MESSAGE_RECORDER
167 if ( _MR_RecordingState != Replay )
169 #endif
170 // L1-2 Update (nothing to do in replay mode)
171 CBufServer::update (); // then send
173 #ifdef USE_MESSAGE_RECORDER
175 #endif
180 * Read the next message in the receive queue
181 * Recorded : YES
182 * Replayed : YES
184 void CCallbackServer::receive (CMessage &buffer, TSockId *hostid)
186 nlassert (connected ());
188 #ifdef USE_MESSAGE_RECORDER
189 if ( _MR_RecordingState != Replay )
191 #endif
193 // Receive
194 CBufServer::receive (buffer, hostid);
196 #ifdef USE_MESSAGE_RECORDER
197 if ( _MR_RecordingState == Record )
199 // Record received message
200 _MR_Recorder.recordNext( _MR_UpdateCounter, Receiving, *hostid, const_cast<CMessage&>(buffer) );
203 else
205 // Retrieve received message loaded by dataAvailable()
206 buffer = _MR_Recorder.ReceivedMessages.front().Message;
207 *hostid = _MR_Recorder.ReceivedMessages.front().SockId;
208 _MR_Recorder.ReceivedMessages.pop();
210 #endif
212 buffer.readType ();
217 * Disconnect a connection
218 * Set hostid to InvalidSockId to disconnect all connections.
219 * If hostid is not null and the socket is not connected, the method does nothing.
220 * Before disconnecting, any pending data is actually sent.
221 * Recorded : YES in noticeDisconnection called in the disconnection callback
222 * Replayed : YES in noticeDisconnection called in the disconnection callback
224 void CCallbackServer::disconnect( TSockId hostid )
226 #ifdef USE_MESSAGE_RECORDER
227 if ( _MR_RecordingState != Replay )
229 #endif
230 // Disconnect
231 CBufServer::disconnect( hostid );
233 #ifdef USE_MESSAGE_RECORDER
235 // else, no need to manually replay the disconnection, such as in CCallbackClient,
236 // it will be replayed during the next update()
237 #endif
244 TSockId CCallbackServer::getSockId (TSockId hostid)
246 nlassert (hostid != InvalidSockId); // invalid hostid
247 nlassert (connected ());
248 nlassert (hostid != NULL);
249 return hostid;
254 * Returns true if there are messages to read
255 * Recorded : NO
256 * Replayed : YES
258 bool CCallbackServer::dataAvailable ()
260 #ifdef USE_MESSAGE_RECORDER
261 if ( _MR_RecordingState != Replay )
263 #endif
265 // Real dataAvailable()
266 return CBufServer::dataAvailable ();
268 #ifdef USE_MESSAGE_RECORDER
270 else
272 // Simulated dataAvailable()
273 return CCallbackNetBase::replayDataAvailable();
275 #endif
279 //-------------------------
280 #ifdef USE_MESSAGE_RECORDER
284 * Replay connection and disconnection callbacks, client version
286 bool CCallbackServer::replaySystemCallbacks()
290 if ( _MR_Recorder.ReceivedMessages.empty() )
292 return false;
294 else
296 // Translate the stored sockid to the replayed sockid
297 TSockId sockid;
298 std::map<TSockId,TSockId>::iterator isi = _MR_SockIds.find( _MR_Recorder.ReceivedMessages.front().SockId );
299 if ( isi != _MR_SockIds.end() )
301 // The sockid is found in the map if the connection already exists
302 sockid = (*isi).second;
303 _MR_Recorder.ReceivedMessages.front().SockId = sockid;
306 // Test event type
307 switch( _MR_Recorder.ReceivedMessages.front().Event )
309 case Receiving:
310 return true;
312 case Disconnecting:
313 LNETL3_DEBUG( "LNETL3S: Disconnection event for %p", sockid );
314 sockid->Sock->disconnect();
315 sockid->setConnectedState( false );
317 // Call callback if needed
318 if ( disconnectionCallback() != NULL )
320 disconnectionCallback()( sockid, argOfDisconnectionCallback() );
322 break;
324 case Accepting:
326 // Replay connection:
328 // Get remote address
329 CInetAddress addr;
330 _MR_Recorder.ReceivedMessages.front().Message.serial( addr );
332 // Create a new connection
333 sockid = new CBufSock( new CDummyTcpSock() );
334 sockid->Sock->connect( addr );
335 _MR_Connections.push_back( sockid );
337 // Bind it to the "old" sockid
338 _MR_SockIds.insert( make_pair( _MR_Recorder.ReceivedMessages.front().SockId, sockid ) );
340 LNETL3_DEBUG( "LNETL3S: Connection event for %p", sockid );
341 sockid->setConnectedState( true );
343 // Call callback if needed
344 if ( connectionCallback() != NULL )
346 connectionCallback()( sockid, argOfConnectionCallback() );
348 break;
350 default:
351 nlerror( "LNETL3S: Invalid system event type in client receive queue" );
353 // Extract system event
354 _MR_Recorder.ReceivedMessages.pop();
357 while ( true );
362 * Record or replay connection
364 void CCallbackServer::noticeConnection( TSockId hostid )
366 nlassert (hostid != InvalidSockId); // invalid hostid
367 if ( _MR_RecordingState != Replay )
369 if ( _MR_RecordingState == Record )
371 // Record connection
372 CMessage addrmsg;
373 addrmsg.serial( const_cast<CInetAddress&>(hostAddress(hostid)) );
374 _MR_Recorder.recordNext( _MR_UpdateCounter, Accepting, hostid, addrmsg );
379 #endif // USE_MESSAGE_RECORDER
382 } // NLNET