1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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"
28 using namespace NLMISC
;
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
45 server
->noticeConnection( from
);
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
);
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") );
71 CBufServer::setDisconnectionCallback (_NewDisconnectionCallback
, this);
72 CBufServer::setConnectionCallback (cbsNewConnection
, this);
75 _DefaultCallback
= NULL
;
80 * Send a message to the specified host (pushing to its send queue)
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
)
93 sint nb
= nbConnections ();
94 _BytesSent
+= buffer
.length () * nb
;
98 _BytesSent
+= buffer
.length ();
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
)
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
) );
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
)
143 // L1-2 Update (nothing to do in replay mode)
144 CBufServer::update (); // then send
146 #ifdef USE_MESSAGE_RECORDER
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
)
170 // L1-2 Update (nothing to do in replay mode)
171 CBufServer::update (); // then send
173 #ifdef USE_MESSAGE_RECORDER
180 * Read the next message in the receive queue
184 void CCallbackServer::receive (CMessage
&buffer
, TSockId
*hostid
)
186 nlassert (connected ());
188 #ifdef USE_MESSAGE_RECORDER
189 if ( _MR_RecordingState
!= Replay
)
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
) );
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();
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
)
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()
244 TSockId
CCallbackServer::getSockId (TSockId hostid
)
246 nlassert (hostid
!= InvalidSockId
); // invalid hostid
247 nlassert (connected ());
248 nlassert (hostid
!= NULL
);
254 * Returns true if there are messages to read
258 bool CCallbackServer::dataAvailable ()
260 #ifdef USE_MESSAGE_RECORDER
261 if ( _MR_RecordingState
!= Replay
)
265 // Real dataAvailable()
266 return CBufServer::dataAvailable ();
268 #ifdef USE_MESSAGE_RECORDER
272 // Simulated dataAvailable()
273 return CCallbackNetBase::replayDataAvailable();
279 //-------------------------
280 #ifdef USE_MESSAGE_RECORDER
284 * Replay connection and disconnection callbacks, client version
286 bool CCallbackServer::replaySystemCallbacks()
290 if ( _MR_Recorder
.ReceivedMessages
.empty() )
296 // Translate the stored sockid to the replayed 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
;
307 switch( _MR_Recorder
.ReceivedMessages
.front().Event
)
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() );
326 // Replay connection:
328 // Get remote address
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() );
351 nlerror( "LNETL3S: Invalid system event type in client receive queue" );
353 // Extract system event
354 _MR_Recorder
.ReceivedMessages
.pop();
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
)
373 addrmsg
.serial( const_cast<CInetAddress
&>(hostAddress(hostid
)) );
374 _MR_Recorder
.recordNext( _MR_UpdateCounter
, Accepting
, hostid
, addrmsg
);
379 #endif // USE_MESSAGE_RECORDER