Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / net / callback_client.cpp
blob6533be17c3bdf6db1854ebe10d6885bdb150fe89
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2016 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "stdnet.h"
22 #include "nel/misc/types_nl.h"
23 #include "nel/net/callback_net_base.h"
24 #include "nel/net/callback_client.h"
25 #include "nel/net/net_log.h"
28 #ifdef USE_MESSAGE_RECORDER
29 #include "nel/net/message_recorder.h"
30 #endif
33 namespace NLNET {
37 * Constructor
39 CCallbackClient::CCallbackClient( TRecordingState rec, const std::string& recfilename, bool recordall, bool initPipeForDataAvailable ) :
40 CCallbackNetBase( rec, recfilename, recordall ), CBufClient( true, rec==Replay, initPipeForDataAvailable )
42 LockDeletion = false;
43 CBufClient::setDisconnectionCallback (_NewDisconnectionCallback, this);
45 _IsAServer = false;
46 _DefaultCallback = NULL;
49 CCallbackClient::~CCallbackClient()
51 nlassert(!LockDeletion);
55 * Send a message to the remote host (pushing to its send queue)
56 * Recorded : YES
57 * Replayed : MAYBE
59 void CCallbackClient::send (const CMessage &buffer, TSockId hostid, bool /* log */)
61 nlassert (hostid == InvalidSockId); // should always be InvalidSockId on client
62 nlassert (connected ());
63 nlassert (buffer.length() != 0);
64 nlassert (buffer.typeIsSet());
66 _BytesSent += buffer.length ();
68 // if (log)
70 // nldebug ("LNETL3C: Client: send(%s)", buffer.toString().c_str());
71 // nldebug ("send message number %u", SendNextValue);
74 #ifdef USE_MESSAGE_RECORDER
75 if ( _MR_RecordingState != Replay )
77 #endif
79 // Send
80 CBufClient::send (buffer);
82 #ifdef USE_MESSAGE_RECORDER
83 if ( _MR_RecordingState == Record )
85 // Record sent message
86 _MR_Recorder.recordNext( _MR_UpdateCounter, Sending, hostid, const_cast<CMessage&>(buffer) );
89 #endif
93 * Force to send all data pending in the send queue.
94 * Recorded : NO
95 * Replayed : NO
97 bool CCallbackClient::flush (TSockId hostid, uint *nbBytesRemaining)
99 nlassert (hostid == InvalidSockId); // should always be InvalidSockId on client
101 #ifdef USE_MESSAGE_RECORDER
102 if ( _MR_RecordingState != Replay )
104 #endif
106 // Flush sending (nothing to do in replay mode)
107 return CBufClient::flush( nbBytesRemaining );
109 #ifdef USE_MESSAGE_RECORDER
111 else
113 return true;
115 #endif
120 * Updates the network (call this method evenly)
121 * Recorded : YES (in baseUpdate())
122 * Replayed : YES (in baseUpdate())
124 void CCallbackClient::update2 ( sint32 timeout, sint32 mintime )
126 LockDeletion = true;
127 // nldebug ("L3: Client: update()");
129 H_AUTO(L3UpdateClient2);
131 baseUpdate2 (timeout, mintime); // first receive
133 #ifdef USE_MESSAGE_RECORDER
134 if ( _MR_RecordingState != Replay )
136 #endif
138 // L1-2 Update (nothing to do in replay mode)
139 CBufClient::update (); // then send
141 #ifdef USE_MESSAGE_RECORDER
143 #endif
145 LockDeletion = false;
150 * Updates the network (call this method evenly) (legacy)
151 * Recorded : YES (in baseUpdate())
152 * Replayed : YES (in baseUpdate())
154 void CCallbackClient::update ( sint32 timeout )
156 LockDeletion = true;
157 // nldebug ("L3: Client: update()");
159 H_AUTO(L3UpdateClient);
161 baseUpdate (timeout); // first receive
163 #ifdef USE_MESSAGE_RECORDER
164 if ( _MR_RecordingState != Replay )
166 #endif
168 // L1-2 Update (nothing to do in replay mode)
169 CBufClient::update (); // then send
171 #ifdef USE_MESSAGE_RECORDER
173 #endif
175 LockDeletion = false;
180 * Returns true if there are messages to read
181 * Recorded : NO
182 * Replayed : YES
184 bool CCallbackClient::dataAvailable ()
186 #ifdef USE_MESSAGE_RECORDER
187 if ( _MR_RecordingState != Replay )
189 #endif
191 // Real dataAvailable()
192 return CBufClient::dataAvailable ();
194 #ifdef USE_MESSAGE_RECORDER
196 else
198 // Simulated dataAvailable()
199 return CCallbackNetBase::replayDataAvailable();
201 #endif
206 * Read the next message in the receive queue
207 * Recorded : YES
208 * Replayed : YES
210 void CCallbackClient::receive (CMessage &buffer, TSockId *hostid)
212 // nlassert (connected ());
213 *hostid = InvalidSockId;
215 #ifdef USE_MESSAGE_RECORDER
216 if ( _MR_RecordingState != Replay )
218 #endif
220 // Receive
221 CBufClient::receive (buffer);
223 // debug features, we number all packet to be sure that they are all sent and received
224 // \todo remove this debug feature when ok
225 #ifdef NL_BIG_ENDIAN
226 uint32 val = NLMISC_BSWAP32(*(uint32*)buffer.buffer ());
227 #else
228 uint32 val = *(uint32*)buffer.buffer ();
229 #endif
231 #ifdef USE_MESSAGE_RECORDER
232 if ( _MR_RecordingState == Record )
234 // Record received message
235 _MR_Recorder.recordNext( _MR_UpdateCounter, Receiving, *hostid, const_cast<CMessage&>(buffer) );
238 else
240 // Retrieve received message loaded by dataAvailable()
241 buffer = _MR_Recorder.ReceivedMessages.front().Message;
242 _MR_Recorder.ReceivedMessages.pop();
244 #endif
246 buffer.readType ();
252 TSockId CCallbackClient::getSockId (TSockId hostid)
254 nlassert (hostid == InvalidSockId);
256 return id ();
261 * Connect to the specified host
262 * Recorded : YES
263 * Replayed : YES
265 void CCallbackClient::connect( const CInetAddress& addr )
267 #ifdef USE_MESSAGE_RECORDER
268 if ( _MR_RecordingState != Replay )
272 #endif
274 // Connect
275 CBufClient::connect( addr );
277 #ifdef USE_MESSAGE_RECORDER
278 if ( _MR_RecordingState == Record )
280 // Record connection
281 CMessage addrmsg;
282 addrmsg.serial( const_cast<CInetAddress&>(addr) );
283 _MR_Recorder.recordNext( _MR_UpdateCounter, Connecting, _BufSock, addrmsg );
286 catch (const ESocketConnectionFailed&)
288 if ( _MR_RecordingState == Record )
290 // Record connection
291 CMessage addrmsg;
292 addrmsg.serial( const_cast<CInetAddress&>(addr) );
293 _MR_Recorder.recordNext( _MR_UpdateCounter, ConnFailing, _BufSock, addrmsg );
295 throw;
298 else
300 // Check the connection : failure or not
301 TNetworkEvent event = _MR_Recorder.replayConnectionAttempt( addr );
302 switch ( event )
304 case Connecting :
305 // Set the remote address
306 nlassert( ! _BufSock->Sock->connected() );
307 _BufSock->connect( addr, _NoDelay, true );
308 _PrevBytesDownloaded = 0;
309 _PrevBytesUploaded = 0;
310 /*_PrevBytesReceived = 0;
311 _PrevBytesSent = 0;*/
312 break;
313 case ConnFailing :
314 throw ESocketConnectionFailed( addr );
315 //break;
316 default :
317 nlwarning( "LNETL3C: No connection event in replay data, at update #%" NL_I64 "u", _MR_UpdateCounter );
320 #endif
325 * Disconnect a connection
326 * Recorded : YES
327 * Replayed : YES
329 void CCallbackClient::disconnect( TSockId hostid )
331 nlassert (hostid == InvalidSockId); // should always be InvalidSockId on client
333 // Disconnect only if connected (same as physically connected for the client)
334 if ( _BufSock->connectedState() )
337 #ifdef USE_MESSAGE_RECORDER
338 if ( _MR_RecordingState != Replay )
340 #endif
342 // Disconnect
343 CBufClient::disconnect ();
345 #ifdef USE_MESSAGE_RECORDER
347 else
349 // Read (skip) disconnection in the file
350 if ( ! (_MR_Recorder.checkNextOne( _MR_UpdateCounter ) == Disconnecting) )
352 nlwarning( "LNETL3C: No disconnection event in the replay data, at update #%" NL_I64 "u", _MR_UpdateCounter );
355 // Record or replay disconnection (because disconnect() in the client does not push a disc. event)
356 noticeDisconnection( _BufSock );
357 #endif
362 #ifdef USE_MESSAGE_RECORDER
366 * replay connection and disconnection callbacks, client version
368 bool CCallbackClient::replaySystemCallbacks()
372 if ( _MR_Recorder.ReceivedMessages.empty() )
374 return false;
376 else
378 switch( _MR_Recorder.ReceivedMessages.front().Event )
380 case Receiving:
381 return true;
383 case Disconnecting:
384 LNETL3_DEBUG( "LNETL3C: Disconnection event" );
385 _BufSock->setConnectedState( false );
387 // Call callback if needed
388 if ( disconnectionCallback() != NULL )
390 disconnectionCallback()( id(), argOfDisconnectionCallback() );
392 break;
394 default:
395 nlerror( "LNETL3C: Invalid system event type in client receive queue" );
397 // Extract system event
398 _MR_Recorder.ReceivedMessages.pop();
401 while ( true );
405 #endif // USE_MESSAGE_RECORDER
408 } // NLNET