1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2016 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
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"
39 CCallbackClient::CCallbackClient( TRecordingState rec
, const std::string
& recfilename
, bool recordall
, bool initPipeForDataAvailable
) :
40 CCallbackNetBase( rec
, recfilename
, recordall
), CBufClient( true, rec
==Replay
, initPipeForDataAvailable
)
43 CBufClient::setDisconnectionCallback (_NewDisconnectionCallback
, this);
46 _DefaultCallback
= NULL
;
49 CCallbackClient::~CCallbackClient()
51 nlassert(!LockDeletion
);
55 * Send a message to the remote host (pushing to its send queue)
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 ();
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
)
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
) );
93 * Force to send all data pending in the send queue.
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
)
106 // Flush sending (nothing to do in replay mode)
107 return CBufClient::flush( nbBytesRemaining
);
109 #ifdef USE_MESSAGE_RECORDER
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
)
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
)
138 // L1-2 Update (nothing to do in replay mode)
139 CBufClient::update (); // then send
141 #ifdef USE_MESSAGE_RECORDER
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
)
157 // nldebug ("L3: Client: update()");
159 H_AUTO(L3UpdateClient
);
161 baseUpdate (timeout
); // first receive
163 #ifdef USE_MESSAGE_RECORDER
164 if ( _MR_RecordingState
!= Replay
)
168 // L1-2 Update (nothing to do in replay mode)
169 CBufClient::update (); // then send
171 #ifdef USE_MESSAGE_RECORDER
175 LockDeletion
= false;
180 * Returns true if there are messages to read
184 bool CCallbackClient::dataAvailable ()
186 #ifdef USE_MESSAGE_RECORDER
187 if ( _MR_RecordingState
!= Replay
)
191 // Real dataAvailable()
192 return CBufClient::dataAvailable ();
194 #ifdef USE_MESSAGE_RECORDER
198 // Simulated dataAvailable()
199 return CCallbackNetBase::replayDataAvailable();
206 * Read the next message in the receive queue
210 void CCallbackClient::receive (CMessage
&buffer
, TSockId
*hostid
)
212 // nlassert (connected ());
213 *hostid
= InvalidSockId
;
215 #ifdef USE_MESSAGE_RECORDER
216 if ( _MR_RecordingState
!= Replay
)
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
226 uint32 val
= NLMISC_BSWAP32(*(uint32
*)buffer
.buffer ());
228 uint32 val
= *(uint32
*)buffer
.buffer ();
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
) );
240 // Retrieve received message loaded by dataAvailable()
241 buffer
= _MR_Recorder
.ReceivedMessages
.front().Message
;
242 _MR_Recorder
.ReceivedMessages
.pop();
252 TSockId
CCallbackClient::getSockId (TSockId hostid
)
254 nlassert (hostid
== InvalidSockId
);
261 * Connect to the specified host
265 void CCallbackClient::connect( const CInetAddress
& addr
)
267 #ifdef USE_MESSAGE_RECORDER
268 if ( _MR_RecordingState
!= Replay
)
275 CBufClient::connect( addr
);
277 #ifdef USE_MESSAGE_RECORDER
278 if ( _MR_RecordingState
== Record
)
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
)
292 addrmsg
.serial( const_cast<CInetAddress
&>(addr
) );
293 _MR_Recorder
.recordNext( _MR_UpdateCounter
, ConnFailing
, _BufSock
, addrmsg
);
300 // Check the connection : failure or not
301 TNetworkEvent event
= _MR_Recorder
.replayConnectionAttempt( addr
);
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;*/
314 throw ESocketConnectionFailed( addr
);
317 nlwarning( "LNETL3C: No connection event in replay data, at update #%" NL_I64
"u", _MR_UpdateCounter
);
325 * Disconnect a connection
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
)
343 CBufClient::disconnect ();
345 #ifdef USE_MESSAGE_RECORDER
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
);
362 #ifdef USE_MESSAGE_RECORDER
366 * replay connection and disconnection callbacks, client version
368 bool CCallbackClient::replaySystemCallbacks()
372 if ( _MR_Recorder
.ReceivedMessages
.empty() )
378 switch( _MR_Recorder
.ReceivedMessages
.front().Event
)
384 LNETL3_DEBUG( "LNETL3C: Disconnection event" );
385 _BufSock
->setConnectedState( false );
387 // Call callback if needed
388 if ( disconnectionCallback() != NULL
)
390 disconnectionCallback()( id(), argOfDisconnectionCallback() );
395 nlerror( "LNETL3C: Invalid system event type in client receive queue" );
397 // Extract system event
398 _MR_Recorder
.ReceivedMessages
.pop();
405 #endif // USE_MESSAGE_RECORDER