Add infos into target window
[ryzomcore.git] / ryzom / server / src / frontend_service / client_host.h
blob1105131f8d23c7bc44f5e5bef281d92e9e805343
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
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/>.
19 #ifndef NL_CLIENT_HOST_H
20 #define NL_CLIENT_HOST_H
22 #include "nel/misc/types_nl.h"
23 #include "nel/misc/vector.h"
24 #include "nel/misc/time_nl.h"
25 #include "nel/net/inet_address.h"
26 #include "nel/net/login_cookie.h"
28 #include "fe_types.h"
29 #include "fe_receive_task.h"
30 #include "game_share/action.h"
31 #include "client_entity_id_translator.h"
32 #include "impulse_encoder.h"
33 #include "entity_container.h"
34 #include "game_share/ryzom_entity_id.h"
35 #include "game_share/entity_types.h"
36 #include "game_share/welcome_service_itf.h"
38 #include <vector>
39 #include <deque>
42 const uint32 FirstClientId = 1;
43 const uint16 InvalidClientId = 0xFFFF;
45 namespace NLNET
47 class CUdpSock;
50 struct TPairState;
53 /**
54 * CClientIdPool
56 class CClientIdPool
58 public:
60 /// Constructor
61 CClientIdPool()
63 TClientId i;
64 for ( i=0; i<=MaxNbClients; ++i )
66 _UsedPool[i] = false;
70 /// Get a free Id
71 TClientId getNewClientId()
73 TClientId i;
74 for ( i=FirstClientId; i<=MaxNbClients; ++i )
76 if ( ! _UsedPool[i] )
78 _UsedPool[i] = true;
79 return i;
82 return InvalidClientId;
85 /// Release an Id
86 void releaseId( TClientId id )
88 _UsedPool[id] = false;
91 private:
93 bool _UsedPool [MAX_NB_CLIENTS+1];
97 /// Get string for association state
98 const char *associationStateToString( uint8 as );
102 * Client host
103 * \author Olivier Cado
104 * \author Nevrax France
105 * \date 2001
107 class CClientHost
109 public:
110 /// Constructor
111 CClientHost( const NLNET::CInetAddress& addr, TClientId id ) :
112 Uid (0xFFFFFFFF),
113 InstanceId(0xFFFFFFFF),
114 StartupRole(WS::TUserRole::ur_player),
115 NbFreeEntityItems( 255 ),
116 PrioAmount( 0.0f ),
117 _Address(addr),
118 _ClientId(id),
119 _Id(NLMISC::CEntityId::Unknown),
120 _EntityIndex(),
121 _SendNumber(0),
122 _SendSyncTick(0),
123 _Synchronized(false),
124 _Disconnected(false),
125 _FirstReceiveNumber(0),
126 _ReceiveNumber(0xFFFFFFFF),
127 _ReceiveTime(0),
128 _DatagramLost(0),
129 _DatagramRepeated(0),
130 //SheetId(CLFECOMMON::INVALID_SHEETID),
131 //_ToggleBit(false),
132 //_OutBoxMeter(0),
133 IdTranslator(),
134 ImpulseEncoder(),
135 LastReceivedAck(0xFFFFFFFF),
136 ImpulseMultiPartNumber (0),
137 AuthorizedCharSlot(~0),
138 LastReceivedGameCycle(0),
139 LastSentSync(1),
141 LastDummy(~0),
142 LastSentDummy(~0),
143 LastSentCounter(0),
144 LastCounterTime(0),
146 //AvailableImpulseBitsize( "AvailImpulseBitsize", MaxImpulseBitSizes[2] ),
147 NbActionsSentAtCycle(0),
148 QuitId(0)
150 IdTranslator.setId( id );
151 ImpulseEncoder.setClientHost( this );
152 ConnectionState = Synchronize;
153 initClientBandwidth();
156 /// Destructor
157 ~CClientHost();
159 /// Return IP and port
160 const NLNET::CInetAddress& address() { return _Address; }
162 /// Return client Id
163 TClientId clientId() const { return _ClientId; }
165 /// Return the entity index (for access in the entity container)
166 TEntityIndex entityIndex() const { return _EntityIndex; }
168 /// Return the id
169 const NLMISC::CEntityId& eId() const { return _Id; }
171 /// Set the entity index
172 void setEntityIndex( const TEntityIndex& ei );
174 /// Set the CEntityId
175 void setEId( const NLMISC::CEntityId& assigned_id );
177 /// Prepare a clean new outbox with current values
178 void setupOutBox( TOutBox& outbox );
180 /// Prepare a clean system header
181 void setupSystemHeader( TOutBox& outbox, uint8 code);
183 /// Compute host stats
184 void computeHostStats( const TReceivedMessage& msgin, uint32 currentcounter, bool updateAcknowledge );
186 /// Increment send number and return it
187 uint32 getNextSendNumber() { return ++_SendNumber; }
189 /// R access to last send number
190 uint32 sendNumber() const { return _SendNumber; }
192 /// R/W access to first receive number
193 uint32& firstReceiveNumber() { return _FirstReceiveNumber; }
195 /// R/W access to latest receive number
196 uint32& receiveNumber() { return _ReceiveNumber; }
198 /// R/W access to the toggle bit
199 //bool& toggleBit() { return _ToggleBit; }
201 /// Set receive time now
202 void setReceiveTimeNow();
204 /// Return receive time
205 NLMISC::TTime receiveTime() const { return _ReceiveTime; }
207 uint32 datagramLost() const { return _DatagramLost; }
208 void resetDatagramLost() { _DatagramLost = 0; }
210 uint32 datagramRepeated() const { return _DatagramRepeated; }
212 /// Setup sync for tick measures with client connection
213 void setFirstSentPacket(uint32 sentPacket, NLMISC::TGameCycle atTick)
215 #ifdef HALF_FREQUENCY_SENDING_TO_CLIENT
216 _SendSyncTick = atTick - sentPacket*2;
217 #else
218 _SendSyncTick = atTick - sentPacket;
219 #endif
222 /// Convert ack contained in client packet into tick date
223 NLMISC::TGameCycle getPacketTickDate(uint32 receivedPacketAck) const { return _SendSyncTick+receivedPacketAck; }
226 /// Get sync value for this client;
227 NLMISC::TGameCycle getSync() const { return _SendSyncTick; }
229 void disconnect() { _Disconnected = true; }
230 bool isDisconnected() { return _Disconnected; }
232 // Reset client vision
233 void resetClientVision();
235 /// Set clienthost to synchronize state
236 void setSynchronizeState()
238 ConnectionState = Synchronize;
241 /// Set clienthost to synchronize state
242 void setConnectedState()
244 ConnectionState = Connected;
247 /// Set clienthost to synchronize state
248 void setStalledState()
250 ConnectionState = Stalled;
253 /// Set clienthost to probe state
254 void setProbeState()
256 ConnectionState = Probe;
257 LastSentProbe = 0;
258 LastProbeTime = 0;
259 NumConsecutiveProbes = 0;
260 LastReceivedProbe = 0;
263 /// Set clienthost to ForceSynchronize state (i.e. Synchronize must not be replaced by Connected, as a sync must be sent to the client)
264 void setForceSynchronizeState()
266 ConnectionState = ForceSynchronize;
269 /// Initialize the counter/flag
270 void initSendCycle( bool initialState )
272 _WhenToSend = initialState;
275 /// Update the counter/flag
276 void incSendCycle()
278 #ifdef HALF_FREQUENCY_SENDING_TO_CLIENT
279 _WhenToSend = !_WhenToSend;
280 #endif
283 /// Return true if the counter/flag state is "to send" for the current cycle
284 bool whenToSend()
286 #ifdef HALF_FREQUENCY_SENDING_TO_CLIENT
287 return _WhenToSend;
288 #else
289 return true;
290 #endif
293 /// display nlinfo
294 void displayClientProperties( bool full=true, bool allProps=false, bool sortByDistance=false,NLMISC::CLog *log = NLMISC::InfoLog ) const;
296 /// display nlinfo for one slot
297 void displaySlotProperties( CLFECOMMON::TCLEntityId e, bool full=false, NLMISC::CLog *log = NLMISC::InfoLog ) const;
299 /// display nlinfo (1 line only)
300 void displayShortProps(NLMISC::CLog *log = NLMISC::InfoLog) const;
302 /// Return the cardinal direction from the player to the seen entity
303 const char * getDirection( CEntity *seenEntity, const TEntityIndex& seenEntityIndex ) const;
305 /// Initialize the client bandwidth (calls setClientBandwidth)
306 void initClientBandwidth();
308 /// Change the client bandwidth (set the nomimal size)
309 void setClientBandwidth( sint32 cbw )
311 _MaxOutboxSizeInBit = cbw;
312 _BitBandwidthUsageAvg = _MaxOutboxSizeInBit;
313 _BitImpulsionUsageAvg = MaxImpulseBitSizes[2];
314 _ImpulsionPrevRemainingActions = 0;
317 /// Return the current maximum number of bits that can fit in the outbox
318 sint32 getCurrentThrottle() const
320 return std::min( (sint32)(_MaxOutboxSizeInBit*2-_BitBandwidthUsageAvg), (sint32)(_MaxOutboxSizeInBit*3/2) );
323 /// Update the average bits filled that determine the throttle
324 void updateThrottle( TOutBox& outbox )
326 #ifdef NL_DEBUG
327 sint32 prevThrottle = getCurrentThrottle();
328 #endif
329 // Update the average of bits sent
330 _BitBandwidthUsageAvg = (_BitBandwidthUsageAvg*(_SendNumber-1) + outbox.getPosInBit()) / _SendNumber;
331 #ifdef NL_DEBUG
332 sint32 currThrottle = getCurrentThrottle();
333 if ( currThrottle != prevThrottle )
334 nldebug( "NFC: Client %hu, packet %u: throttle %d, %d filled now, %d average (%d kbps), %d nominal", _ClientId, _SendNumber, currThrottle, outbox.getPosInBit(), _BitBandwidthUsageAvg, _BitBandwidthUsageAvg*5/1000, _MaxOutboxSizeInBit );
335 #endif
339 * Calculate the current maximum number of bits that can fit for impulsions,
340 * and set AvailableImpulsionBitSize in the mirror, using:
341 * - The number of bits filled (possibly exceeding the max when sending forced actions (database))
342 * - The number of remaining actions not forced
344 void setImpulsionThrottle( sint32 currentNbBitsFilled, sint32 nominalBitSize, uint nbRemainingActions )
346 if ( !_EntityIndex.isValid() )
347 return;
349 if ( ((_ImpulsionPrevRemainingActions>12) && (nbRemainingActions > _ImpulsionPrevRemainingActions * 5/4))
350 || _ImpulsionPrevRemainingActions>100 )
352 // The connection does not manage to send all the impulsions that come from the back-end, stop the database impulsions
353 CMirrorPropValue<uint16> availableImpulseBitsize( TheDataset, _EntityIndex, DSFirstPropertyAvailableImpulseBitSize );
354 availableImpulseBitsize = 0;
355 #ifdef NL_DEBUG
356 nldebug( "NFC: Client %hu: Blocking the AvailableImpulseBitsize to prevent impulsion congestion", _ClientId );
357 #endif
359 else
361 // The remaining actions number is stable, calculate the available bitsize
362 _BitImpulsionUsageAvg = (_BitImpulsionUsageAvg*(_SendNumber-1) + currentNbBitsFilled) / _SendNumber;
363 sint32 availBitsize;
364 if ( _BitImpulsionUsageAvg < nominalBitSize )
365 availBitsize = nominalBitSize;
366 else
367 availBitsize = std::max( (sint32)0, nominalBitSize*2 - _BitImpulsionUsageAvg );
369 CMirrorPropValue<uint16> availableImpulseBitsize( TheDataset, _EntityIndex, DSFirstPropertyAvailableImpulseBitSize );
370 #ifdef NL_DEBUG
371 if ( availBitsize != availableImpulseBitsize )
372 nldebug( "NFC: Client %hu, packet %u: AvailableImpulseBitsize %u, %d filled now, %d average, %d nominal", _ClientId, _SendNumber, availBitsize, currentNbBitsFilled, _BitImpulsionUsageAvg, nominalBitSize );
373 #endif
374 availableImpulseBitsize = (uint16)availBitsize;
376 _ImpulsionPrevRemainingActions = nbRemainingActions;
379 /// Force the impulsion throttle to 0 to prevent overflooding, when the FS does send any impulsion.
380 void setIdleImpulsionThrottle()
382 if ( !_EntityIndex.isValid() )
383 return;
385 CMirrorPropValue<uint16> availableImpulseBitsize( TheDataset, _EntityIndex, DSFirstPropertyAvailableImpulseBitSize );
386 availableImpulseBitsize = 0;
387 #ifdef NL_DEBUG
388 nldebug( "NFC: Client %hu: Blocking the AvailableImpulseBitsize to prevent impulsion congestion", _ClientId );
389 #endif
391 // The FS must not send any impulsion at this time
392 _ImpulsionPrevRemainingActions = 0;
396 // get Pair state
397 TPairState& getPairState(CLFECOMMON::TCLEntityId e);
398 // get Pair state
399 const TPairState& getPairState(CLFECOMMON::TCLEntityId e) const;
401 /// User identifier
402 TUid Uid;
404 /// User name (put on the NeL Launcher, transmitted by the login system)
405 std::string UserName;
407 /// User privilege (put on the NeL Launcher, transmitted by the login system)
408 std::string UserPriv;
410 /// User extended data (put on the NeL Launcher, transmitted by the login system)
411 std::string UserExtended;
413 /// Language Id
414 std::string LanguageId;
416 /// Login cookie
417 NLNET::CLoginCookie LoginCookie;
419 /// Startup instance
420 uint32 InstanceId;
422 /// Startup role
423 WS::TUserRole StartupRole;
425 /// Sheet identifier
426 //CLFECOMMON::TSheetId SheetId;
428 /// Number of free entity items
429 uint16 NbFreeEntityItems;
431 // Used to differenciate different multi part impulse
432 uint8 ImpulseMultiPartNumber;
434 // The only character slot that will be granted to connect [0..4], or 0xF (15) for any character
435 uint8 AuthorizedCharSlot;
437 /// States of the client connection
438 enum
440 Synchronize = 0,
441 Connected,
442 Probe,
443 Stalled,
444 // Disconnect, // Appears to be unused at least for now
445 ServerDown,
446 ForceSynchronize, // prevents Synchronize to be replaced by Connected
449 /// The current state of the client connection
450 uint ConnectionState;
452 /// The last received probe;
453 uint32 LastReceivedProbe;
455 /// The number of consecutive probes received lastly
456 uint32 NumConsecutiveProbes;
458 /// The last sent probe;
459 uint32 LastSentProbe;
461 /// The last sent sync
462 uint32 LastSentSync;
464 /// The time the last probe was sent
465 NLMISC::TTime LastProbeTime;
467 /// Stat
468 float PrioAmount;
471 /// Counter check
472 uint32 LastSentCounter;
474 /// Counter time
475 NLMISC::TTime LastCounterTime;
477 /// @name Generic action multipart handling structures
478 //@{
479 struct CGenericMultiPartTemp
481 CGenericMultiPartTemp () : NbBlock(0xFFFFFFFF) { }
482 uint32 NbBlock;
483 uint32 NbCurrentBlock;
484 uint32 TempSize;
485 std::vector<std::vector<uint8> > Temp;
487 std::vector<bool> BlockReceived;
489 void set (CLFECOMMON::CActionGenericMultiPart *agmp, CClientHost *client);
492 std::vector<CGenericMultiPartTemp> GenericMultiPartTemp;
493 //@}
495 /// Quit Id
496 uint32 QuitId;
498 private:
500 /// Client IP and port
501 NLNET::CInetAddress _Address;
503 /// Client Id
504 TClientId _ClientId;
506 /// Entity Id
507 TEntityIndex _EntityIndex;
509 /// CEntityId
510 NLMISC::CEntityId _Id;
512 /// Latest send number
513 uint32 _SendNumber;
515 /// Counter (or flag) determining when to send the prioritized properties to the client
516 bool _WhenToSend;
518 /// First tick on front end, corresponding to the first packet sent
519 NLMISC::TGameCycle _SendSyncTick;
520 bool _Synchronized;
521 bool _Disconnected;
523 /// First receive number
524 uint32 _FirstReceiveNumber;
526 /// Latest receive number
527 uint32 _ReceiveNumber;
529 /// Bit for important actions
530 //bool _ToggleBit;
532 /// Timestamp of latest receiving
533 NLMISC::TTime _ReceiveTime;
535 /// Stat
536 uint32 _DatagramLost;
538 /// Stat
539 uint32 _DatagramRepeated;
541 /// Nominal size
542 sint32 _MaxOutboxSizeInBit;
544 /// Number of bits that can be added to the nominal size (>0), or that must be removed from the nominal size (<0)
545 sint32 _DeltaBitsAllowed;
547 /// Previous number of actions not sent by the impulse encoder
548 uint32 _ImpulsionPrevRemainingActions;
550 /// Average of total bits sent
551 sint32 _BitBandwidthUsageAvg;
553 /// Average of impulsion bits sent
554 sint32 _BitImpulsionUsageAvg;
556 public:
558 // Client <- frontend entity id translator
559 CClientEntityIdTranslator IdTranslator;
561 /// Impulse management
562 CImpulseEncoder ImpulseEncoder;
564 /// Last ack number received from client
565 uint32 LastReceivedAck;
568 NLMISC::TGameCycle LastReceivedGameCycle;
570 uint32 LastDummy;
571 uint32 LastSentDummy;
573 // Estimation of available size in bit per cycle
574 //CPropertyBaseType<uint16> AvailableImpulseBitsize;
577 uint NbActionsSentAtCycle;
579 #ifdef NL_DEBUG
580 uint8 MoveNumber;
581 #endif
590 class CLimboClient
592 public:
593 CLimboClient( CClientHost* client ) :
594 AddrFrom(client->address()), Uid(client->Uid), UserName(client->UserName), UserPriv(client->UserPriv), UserExtended(client->UserExtended),
595 LanguageId(client->LanguageId), QuitId(client->QuitId)
597 // Set limbo timeout start
598 Timeout = NLMISC::CTime::getLocalTime();
599 LoginCookie = client->LoginCookie;
602 NLNET::CInetAddress AddrFrom;
603 TUid Uid;
604 std::string UserName, UserPriv, UserExtended, LanguageId;
605 uint32 QuitId;
606 NLMISC::TTime Timeout;
607 NLNET::CLoginCookie LoginCookie;
611 #endif // NL_CLIENT_HOST_H
613 /* End of client_host.h */