!I integrate from //ce/main...
[CRYENGINE.git] / Code / CryPlugins / CryLobby / Module / CryLobby.cpp
blobdb2491ecd361137eaf4c232bc2cf3fbfc132768d
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
3 #include "StdAfx.h"
5 #include "CryLobby.h"
6 #include "CrySharedLobbyPacket.h"
7 #include "LAN/CryLANLobby.h"
8 #if USE_LIVE
9 #include "Live/CryLiveLobby.h"
10 #endif
11 #if USE_PSN
12 #if CRY_PLATFORM_ORBIS
13 #include "PSNOrbis/CryPSN2Lobby.h"
14 #endif
15 #endif
16 #if USE_STEAM
17 #include "Steam/CrySteamLobby.h"
18 #endif
19 #if USE_DURANGOLIVE
20 #include "DurangoLive/CryDurangoLiveLobby.h"
21 #endif
23 #include <CryGame/IGameFramework.h>
24 #include "INetworkPrivate.h"
25 #include "Protocol/FrameTypes.h"
26 #include <CryMemory/BucketAllocatorImpl.h>
28 #include <CryMath/Random.h>
29 #include <CryCore/Platform/platform_impl.inl>
31 const int LOBBY_KEEP_ALIVE_INTERVAL = (CryLobbySendInterval + 100);
32 const int LOBBY_FORCE_DISCONNECT_TIMER = 99999999;
34 static const uint8 CONNECTION_COUNTER_MAX = 255;
36 #if ENCRYPT_LOBBY_PACKETS
37 const char* g_lobbyEncryptionKey = "gSPyI9\"£$h83H8Uasd73nn()u12gh[[&";
38 #endif
40 #define INVALID_CONNECTION_COOKIE 0
42 #if !defined(_LIB)
43 CTimeValue g_time;
44 SObjectCounters* g_pObjcnt = NULL;
45 #endif
47 #ifdef USE_GLOBAL_BUCKET_ALLOCATOR
48 CCryLobby::CMemAllocator::LobbyBuckets CCryLobby::CMemAllocator::m_bucketAllocator(NULL, false);
49 #else
50 CCryLobby::CMemAllocator::LobbyBuckets CCryLobby::CMemAllocator::m_bucketAllocator;
51 #endif
52 ICryLobby* CCryLobby::m_pLobby = NULL;
54 #if defined(_RELEASE) && !defined(DEDICATED_SERVER)
55 #define NO_NETWORK_SECURITY_LOGS
56 #endif
58 #if defined(NO_NETWORK_SECURITY_LOGS)
59 #define SECURE_NET_LOG(...)
60 #else
61 #define SECURE_NET_LOG NetLog
62 #endif
64 CRYREGISTER_SINGLETON_CLASS(CCryLobby)
66 CCryLobby::CCryLobby()
68 gEnv->pLobby = this;
71 CCryLobby::~CCryLobby()
73 int a;
75 #if NETWORK_HOST_MIGRATION
76 RemoveHostMigrationEventListener(this);
77 #endif
79 for (a = 0; a < eCLS_NumServices; a++)
81 InternalSocketDie(ECryLobbyService(a));
84 #if ENCRYPT_LOBBY_PACKETS
85 if (gEnv->pNetwork)
87 gEnv->pNetwork->EndCipher(m_cipher);
89 #endif
91 m_pLobby = NULL;
94 bool CCryLobby::Initialize(SSystemGlobalEnvironment& env, const SSystemInitParams& initParams)
96 if (m_pLobby)
98 CryFatalError("Trying to create a lobby when we already have one, this does not end well");
101 m_pLobby = this;
102 g_time = gEnv->pTimer->GetAsyncTime();
104 for (uint32 i = 0; i < eCLS_NumServices; i++)
106 m_services[i] = NULL;
107 m_task[i].cb = NULL;
108 m_task[i].cbArg = NULL;
110 m_socketServices[i].m_socket = NULL;
111 m_socketServices[i].m_socketListenPort = 0;
112 m_socketServices[i].m_socketConnectPort = 0;
114 memset(&m_serviceParams[i], 0, sizeof(SCryLobbyParameters));
116 m_servicePacketEnd[i] = 0xffff;
119 for (uint32 i = 0; i < MAX_LOBBY_TASKS; i++)
121 m_serviceTask[i].used = false;
124 for (uint32 i = 0; i < MAX_LOBBY_CONNECTIONS; i++)
126 m_connection[i].used = false;
129 m_userPacketEnd = 0xffff;
131 m_lvlName[0] = 0;
132 m_rulName[0] = 0;
134 m_callbacks.reserve(10); // pre-reserve space for callback event data
135 m_service = eCLS_LAN;
136 m_natType = eNT_Unknown;
138 #if USE_GFWL
139 m_gfwlExtras = new CCryLobbyGFWLExtras;
140 #else
141 m_gfwlExtras = NULL;
142 #endif
144 #if NETWORK_HOST_MIGRATION
145 //m_hostMigrationListeners.reserve(10);
146 AddHostMigrationEventListener(this, "CryLobby", ELPT_Engine);
147 #endif
149 #if ENCRYPT_LOBBY_PACKETS
150 if (gEnv->pNetwork)
152 m_cipher = gEnv->pNetwork->BeginCipher((const uint8*)g_lobbyEncryptionKey, 32);
154 #endif
156 return true;
159 ECryLobbyService CCryLobby::SetLobbyService(ECryLobbyService service)
161 LOBBY_AUTO_LOCK;
163 ECryLobbyService ret = m_service;
165 assert(service < eCLS_NumServices);
166 #if CRY_PLATFORM_DURANGO || CRY_PLATFORM_ORBIS
167 m_service = eCLS_Online;
168 #else
169 m_service = service;
170 #endif
172 return ret;
175 #if NETWORK_HOST_MIGRATION
176 IHostMigrationEventListener::EHostMigrationReturn CCryLobby::OnInitiate(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
178 NetLog("[Host Migration]: CCryLobby::OnInitiate() started");
180 SHostMigrationInfo_Private& privateInfo = static_cast<SHostMigrationInfo_Private&>(hostMigrationInfo);
181 privateInfo.m_lobbyHMStatus = eLHMS_InitiateMigrate;
183 NetLog("[Host Migration]: CCryLobby::OnInitiate() finished");
184 return IHostMigrationEventListener::Listener_Done;
187 IHostMigrationEventListener::EHostMigrationReturn CCryLobby::OnDisconnectClient(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
189 return IHostMigrationEventListener::Listener_Done;
192 IHostMigrationEventListener::EHostMigrationReturn CCryLobby::OnDemoteToClient(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
194 return IHostMigrationEventListener::Listener_Done;
197 IHostMigrationEventListener::EHostMigrationReturn CCryLobby::OnPromoteToServer(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
199 bool done = false;
200 CCryMatchMaking* pMatchMaking = (CCryMatchMaking*)GetMatchMaking();
202 if (pMatchMaking)
204 SHostMigrationInfo_Private& privateInfo = static_cast<SHostMigrationInfo_Private&>(hostMigrationInfo);
205 switch (privateInfo.m_lobbyHMStatus)
207 case eLHMS_InitiateMigrate:
208 NetLog("[Host Migration]: CCryLobby::OnPromoteToServer() started");
209 pMatchMaking->HostMigrationServer(&hostMigrationInfo);
210 ++privateInfo.m_lobbyHMStatus;
211 break;
212 case eLHMS_Migrating:
213 default:
214 done = pMatchMaking->IsSessionMigrated(&hostMigrationInfo);
215 if (done)
217 privateInfo.m_lobbyHMStatus = eLHMS_InitiateMigrate;
219 break;
222 if (hostMigrationInfo.m_logProgress || (done == true))
224 NetLog("[Host Migration]: CCryLobby::OnPromoteToServer() %s for " PRFORMAT_SH, ((done == true) ? "finished" : "waiting"), PRARG_SH(pMatchMaking->GetSessionHandleFromGameSessionHandle(hostMigrationInfo.m_session)));
228 if (done)
230 return IHostMigrationEventListener::Listener_Done;
233 return IHostMigrationEventListener::Listener_Wait;
236 IHostMigrationEventListener::EHostMigrationReturn CCryLobby::OnReconnectClient(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
238 bool done = false;
239 CCryMatchMaking* pMatchMaking = (CCryMatchMaking*)GetMatchMaking();
240 if (pMatchMaking)
242 SHostMigrationInfo_Private& privateInfo = static_cast<SHostMigrationInfo_Private&>(hostMigrationInfo);
243 switch (privateInfo.m_lobbyHMStatus)
245 case eLHMS_InitiateMigrate:
246 NetLog("[Host Migration]: CCryLobby::OnReconnectClient() started");
247 ++privateInfo.m_lobbyHMStatus;
248 break;
249 case eLHMS_Migrating:
250 done = pMatchMaking->IsSessionMigrated(&hostMigrationInfo);
251 default:
252 break;
255 if (hostMigrationInfo.m_logProgress || (done == true))
257 NetLog("[Host Migration]: CCryLobby::OnReconnectClient() %s for " PRFORMAT_SH, ((done == true) ? "finished" : "waiting"), PRARG_SH(pMatchMaking->GetSessionHandleFromGameSessionHandle(hostMigrationInfo.m_session)));
260 if (done)
262 pMatchMaking->OnReconnectClient(hostMigrationInfo);
266 if (done)
268 return IHostMigrationEventListener::Listener_Done;
271 return IHostMigrationEventListener::Listener_Wait;
274 IHostMigrationEventListener::EHostMigrationReturn CCryLobby::OnFinalise(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
276 return IHostMigrationEventListener::Listener_Done;
279 IHostMigrationEventListener::EHostMigrationReturn CCryLobby::OnTerminate(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
281 return IHostMigrationEventListener::Listener_Done;
284 IHostMigrationEventListener::EHostMigrationReturn CCryLobby::OnReset(SHostMigrationInfo& hostMigrationInfo, HMStateType& state)
286 return IHostMigrationEventListener::Listener_Done;
288 #endif
290 void CCryLobby::InviteAccepted(ECryLobbyService service, uint32 user, CrySessionID sessionID, ECryLobbyError error)
292 UCryLobbyEventData eventData;
293 SCryLobbyInviteAcceptedData inviteData;
295 eventData.pInviteAcceptedData = &inviteData;
296 inviteData.m_service = service;
297 inviteData.m_user = user;
298 inviteData.m_id = sessionID;
299 inviteData.m_error = error;
300 DispatchEvent(eCLSE_InviteAccepted, eventData);
303 void CCryLobby::InviteAccepted(ECryLobbyService service, uint32 user, CryUserID userID, ECryLobbyError error, ECryLobbyInviteType inviteType)
305 UCryLobbyEventData eventData;
306 SCryLobbyUserInviteAcceptedData inviteData;
308 eventData.pUserInviteAcceptedData = &inviteData;
309 inviteData.m_service = service;
310 inviteData.m_user = user;
311 inviteData.m_inviterId = userID;
312 inviteData.m_error = error;
313 inviteData.m_type = inviteType;
314 DispatchEvent(eCLSE_UserInviteAccepted, eventData);
317 uint32 CCryLobby::GetDisconnectTimeOut()
319 const CNetCVars* pNetCVars = GetNetCVars();
321 if (pNetCVars)
323 if (gEnv->pSystem->IsDevMode())
325 if (pNetCVars->InactivityTimeoutDevmode > 0.0f)
327 return (uint32)(1000.0f * pNetCVars->InactivityTimeoutDevmode);
330 else
332 if (pNetCVars->InactivityTimeout > 0.0f)
334 return (uint32)(1000.0f * pNetCVars->InactivityTimeout);
339 return CryLobbyTimeOut;
342 void CCryLobby::LogPacketsInBuffer(const uint8* pBuffer, uint32 size)
344 #if !defined(_RELEASE) || defined(RELEASE_LOGGING)
345 CCrySharedLobbyPacket packet;
346 SCryLobbyPacketHeader* pPacketHeader = packet.GetLobbyPacketHeader();
347 SCryLobbyPacketDataHeader* pDataHeader = packet.GetLobbyPacketDataHeader();
349 packet.SetReadBuffer(pBuffer, size);
350 pPacketHeader->reliable = true; // No point reading whole header for this log
351 packet.SetReadBufferPos(CryLobbyPacketReliablePacketHeaderSize);
353 while (packet.GetReadBufferPos() < size)
355 packet.ReadDataHeader();
356 uint32 encodedPacketType = pDataHeader->lobbyPacketType;
357 DecodePacketDataHeader(&packet);
358 NetLog(" packet %d (%d) size %d", pDataHeader->lobbyPacketType, encodedPacketType, pDataHeader->dataSize);
359 packet.SetReadBufferPos(packet.GetReadBufferPos() + pDataHeader->dataSize);
361 #endif // #if !defined(_RELEASE) || defined(RELEASE_LOGGING)
364 void CCryLobby::Tick(bool flush)
366 if (gEnv->IsEditor() || (gEnv->pSystem && gEnv->pSystem->IsQuitting()))
368 return;
371 ProcessCachedPacketBuffer();
373 uint32 lastFrameTime = 0;
374 uint32 disconnectTimeOut = GetDisconnectTimeOut();
375 uint32 CryLobbyKeepAliveInterval = LOBBY_KEEP_ALIVE_INTERVAL;
377 g_time = gEnv->pTimer->GetAsyncTime();
379 if (!flush)
381 lastFrameTime = (uint32)(g_time.GetMilliSecondsAsInt64() - m_lastTickTime.GetMilliSecondsAsInt64());
382 if (lastFrameTime > CryLobbySendInterval)
384 NetLog("CCryLobby::TimerCallback() long frame detected, lastFrameTime=%u", lastFrameTime);
385 // Guard against very long frames that can cause sends to time out even before they have started.
386 lastFrameTime = CryLobbySendInterval;
390 #if USE_LOBBY_REMOTE_CONNECTIONS
391 for (uint32 i = 0; i < MAX_LOBBY_CONNECTIONS; i++)
393 SConnection* pConnection = &m_connection[i];
395 if (pConnection->used)
397 bool doneSend = false;
399 pConnection->timeSinceSend += lastFrameTime;
400 pConnection->timeSinceRecv += lastFrameTime;
402 switch (pConnection->state)
404 case eCLCS_NotConnected:
405 if (pConnection->refCount == 0)
407 SECURE_NET_LOG("[lobby] Release connection " PRFORMAT_LCINFO, PRARG_LCINFO(CryLobbyConnectionID(i), pConnection->addr));
409 FreeConnection(i);
412 break;
414 case eCLCS_Pending:
416 if (pConnection->timeSinceSend >= CryLobbySendInterval)
418 const uint32 MaxBufferSize = CryLobbyPacketHeaderSize
419 #if RESET_CONNECTED_CONNECTION
420 + CryLobbyPacketUINT64Size;
421 #endif
423 uint8 buffer[MaxBufferSize];
424 CCrySharedLobbyPacket packet;
426 packet.SetWriteBuffer(buffer, MaxBufferSize);
427 doneSend = true;
428 packet.StartWrite(eLobbyPT_ConnectionRequest, false);
430 #if RESET_CONNECTED_CONNECTION
431 SECURE_NET_LOG("[Lobby] Sending connection request with cookie %llx connection " PRFORMAT_LCINFO, pConnection->sendCookie, PRARG_LCINFO(CryLobbyConnectionID(i), pConnection->addr));
432 packet.WriteUINT64(pConnection->sendCookie);
433 #endif
435 if (Send(&packet, pConnection->addr, i, NULL) != eSE_Ok)
437 SECURE_NET_LOG("[Lobby] Failed to send setting pending connection " PRFORMAT_LCINFO " to eCLCS_NotConnected", PRARG_LCINFO(CryLobbyConnectionID(i), pConnection->addr));
438 pConnection->state = eCLCS_NotConnected;
443 break;
445 case eCLCS_Connected:
446 if (((pConnection->timeSinceRecv > CryLobbyKeepAliveInterval) && (pConnection->timeSinceSend > CryLobbyKeepAliveInterval)) ||
447 ((pConnection->timeSinceSend >= CryLobbySendInterval) && (pConnection->ping.times[NUM_LOBBY_PINGS - 1] == CRYLOBBY_INVALID_PING)) ||
448 (pConnection->timeSinceSend >= CryLobbyInGameSendInterval))
450 const uint32 MaxBufferSize = CryLobbyPacketHeaderSize + CryLobbyPacketUINT64Size;
451 uint8 buffer[MaxBufferSize];
452 CCrySharedLobbyPacket packet;
454 packet.SetWriteBuffer(buffer, MaxBufferSize);
455 doneSend = true;
456 packet.StartWrite(eLobbyPT_Ping, false);
457 packet.WriteUINT64(gEnv->pTimer->GetAsyncTime().GetMilliSecondsAsInt64());
459 if (Send(&packet, pConnection->addr, i, NULL) != eSE_Ok)
461 SECURE_NET_LOG("[Lobby] Failed to send setting connected connection " PRFORMAT_LCINFO " to eCLCS_NotConnected", PRARG_LCINFO(CryLobbyConnectionID(i), pConnection->addr));
462 pConnection->state = eCLCS_NotConnected;
466 if (pConnection->refCount == 0)
468 // There are no references to this connection.
469 if (pConnection->dataQueue.Empty())
471 pConnection->disconnectTimer += lastFrameTime;
473 if (pConnection->disconnectTimer > disconnectTimeOut)
475 // It hasn't been in use for a while
476 SECURE_NET_LOG("[Lobby] No references to connection setting connected connection " PRFORMAT_LCINFO " to eCLCS_NotConnected", PRARG_LCINFO(CryLobbyConnectionID(i), pConnection->addr));
477 pConnection->state = eCLCS_NotConnected;
480 else
482 // It's still in use so reset counter.
483 pConnection->disconnectTimer = 0;
486 else
488 pConnection->disconnectTimer = 0;
491 break;
494 if (pConnection->timeSinceRecv > disconnectTimeOut)
496 // It hasn't been in use for a while
497 if (pConnection->state != eCLCS_NotConnected)
499 SECURE_NET_LOG("[Lobby] Connection to " PRFORMAT_LCINFO " has timed out (timeSinceRecv %u disconnectTimeOut %u) setting to eCLCS_NotConnected", PRARG_LCINFO(CryLobbyConnectionID(i), pConnection->addr), pConnection->timeSinceRecv, disconnectTimeOut);
500 pConnection->state = eCLCS_NotConnected;
504 if (pConnection->dataQueue.Empty() && (pConnection->reliableBuildPacket.GetWriteBufferPos() > 0))
506 AddReliablePacketToSendQueue(i, &pConnection->reliableBuildPacket);
509 if (!pConnection->dataQueue.Empty())
511 if ((pConnection->timeSinceSend >= CryLobbySendInterval) || flush)
513 SConnection::SData& data = pConnection->dataQueue.Front();
515 #if !defined(_RELEASE) || defined(RELEASE_LOGGING)
516 CCrySharedLobbyPacket packetInfo;
518 packetInfo.SetReadBuffer((const uint8*)MemGetPtr(data.data), data.dataSize);
520 packetInfo.ReadPacketHeader();
522 SECURE_NET_LOG("[lobby] Send reliable connection " PRFORMAT_LCINFO " from " PRFORMAT_UID " counter %d size %d",
523 PRARG_LCINFO(CryLobbyConnectionID(i), pConnection->addr), PRARG_UID(packetInfo.GetLobbyPacketHeader()->fromUID), data.counter, data.dataSize);
525 LogPacketsInBuffer((uint8*)MemGetPtr(data.data), data.dataSize);
526 #endif // #if !defined(_RELEASE) || defined(RELEASE_LOGGING)
528 doneSend = true;
530 // Data hasn't been acknowledged so try sending again
531 SSocketService* pSocketService = GetCorrectSocketServiceForAddr(pConnection->addr);
532 if (pSocketService->m_socket)
534 if (pSocketService->m_socket->Send(EncryptPacket((uint8*)MemGetPtr(data.data), data.dataSize), data.dataSize, pConnection->addr) != eSE_Ok)
536 SECURE_NET_LOG("[Lobby] Failed to send setting connection " PRFORMAT_LCINFO " to eCLCS_NotConnected", PRARG_LCINFO(CryLobbyConnectionID(i), pConnection->addr));
537 pConnection->state = eCLCS_NotConnected;
542 if ((pConnection->timeSinceRecv > disconnectTimeOut) || (pConnection->state == eCLCS_NotConnected))
544 // Timeout on send
545 OnError(pConnection->addr, eSE_UnreachableAddress);
548 else
550 if (pConnection->state == eCLCS_Freeing)
552 SECURE_NET_LOG("[Lobby] Setting freeing connection " PRFORMAT_LCINFO " to eCLCS_NotConnected", PRARG_LCINFO(CryLobbyConnectionID(i), pConnection->addr));
553 pConnection->state = eCLCS_NotConnected;
557 if (doneSend)
559 pConnection->timeSinceSend = 0;
563 #endif // USE_LOBBY_REMOTE_CONNECTIONS
565 if (m_mutex.TryLock())
567 m_fromGameQueue.Flush(false);
568 m_mutex.Unlock();
571 if (flush)
573 // We're flushing, so no need to tick services or reset the timer
574 return;
577 // Tick all lobby services.
578 // Things like invite notifications for a service still need to be processed even if currently using a different service
579 for (uint32 i = 0; i < eCLS_NumServices; i++)
581 if (m_services[i])
583 m_services[i]->Tick(g_time);
587 m_lastTickTime = g_time;
590 void CCryLobby::InitialiseServiceCB(ECryLobbyError error, CCryLobby* lobby, ECryLobbyService service)
592 if (error != eCLE_Success)
594 lobby->m_services[service] = NULL;
597 if (lobby->m_task[service].cb)
599 lobby->m_task[service].cb(service, error, lobby->m_task[service].cbArg);
603 void CCryLobby::TerminateServiceCB(ECryLobbyError error, CCryLobby* lobby, ECryLobbyService service)
605 // Remove our reference to the service. It will be deleted when all references are gone.
606 lobby->m_services[service] = NULL;
608 lobby->CheckFreeGlobalResources();
610 if (lobby->m_task[service].cb)
612 lobby->m_task[service].cb(service, error, lobby->m_task[service].cbArg);
616 #define MAX_IP_EXPECTED (16)
617 #define MAX_ADDRESS_SIZE (MAX_IP_EXPECTED + 6 + 1)
619 void FixPortBinding(TNetAddress& defaultBind, int port)
621 #if CRY_PLATFORM_WINDOWS // On windows we should check the sv_bind variable and attempt to play nice and bind to the address requested
622 CNetAddressResolver* pResolver = CCryLobby::GetResolver();
624 if (pResolver)
626 char address[MAX_ADDRESS_SIZE];
628 cry_sprintf(address, "0.0.0.0:%d", port);
630 ICVar* pCVar = gEnv->pConsole->GetCVar("sv_bind");
631 if (pCVar && pCVar->GetString())
633 if (strlen(pCVar->GetString()) <= MAX_IP_EXPECTED)
635 cry_sprintf(address, "%s:%d", pCVar->GetString(), port);
637 else
639 NetLog("Address to bind '%s' does not appear to be an IP address", pCVar->GetString());
643 CNameRequestPtr pReq = pResolver->RequestNameLookup(address);
644 pReq->Wait();
645 if (pReq->GetResult() != eNRR_Succeeded)
647 NetLog("Name resolution for '%s' failed - binding to 0.0.0.0", address);
649 else
651 defaultBind = pReq->GetAddrs()[0];
655 #endif // CRY_PLATFORM_WINDOWS
658 void CCryLobby::InternalSocketCreate(ECryLobbyService service)
660 SSocketService* pSocketService = GetCorrectSocketService(service);
662 CRY_ASSERT_MESSAGE(service < eCLS_NumServices, "Illegal service specified");
663 CRY_ASSERT_MESSAGE(m_services[service] != NULL, "Tried to create a socket for a non existant service.");
665 pSocketService->m_socketConnectPort = 0;
666 pSocketService->m_socketListenPort = 0;
668 if (m_services[service] != NULL)
670 m_services[service]->GetSocketPorts(pSocketService->m_socketConnectPort, pSocketService->m_socketListenPort);
673 uint16 port = pSocketService->m_socketListenPort;
674 TNetAddress defaultBind = TNetAddress(SIPv4Addr(0, port));
675 FixPortBinding(defaultBind, port);
677 ISocketIOManager* pSocketIOManager = GetExternalSocketIOManager();
678 uint32 flags = eSF_Online;
680 if (service == eCLS_LAN)
682 pSocketIOManager = GetInternalSocketIOManager();
683 flags = (eSF_BroadcastSend | eSF_BroadcastReceive);
686 if (pSocketIOManager && !pSocketService->m_socket)
688 InternalSocketFree(service);
690 NetLog("[Lobby] Creating socket on port %u (service [%s], socket manager [%s])", port, (service == eCLS_LAN) ? "LAN" : "Online", pSocketIOManager->GetName());
691 pSocketService->m_socket = pSocketIOManager->CreateDatagramSocket(defaultBind, flags);
693 if (!pSocketService->m_socket)
695 NetLog("[Lobby] Failed to create socket on port %u", port);
696 if ((gEnv->IsDedicated() == false) || ((gEnv->IsClient() == true) && (gEnv->bServer == false)))
698 // If we are not a dedicated server (Which should always use the port specified in the cfg file) and we fail to create the socket
699 // try to create on some different ports.
701 for (uint32 i = 1; i < MAX_SOCKET_PORTS_TRY; i++)
703 port++;
704 defaultBind = TNetAddress(SIPv4Addr(0, port));
705 FixPortBinding(defaultBind, port);
706 NetLog("[Lobby] Creating socket on port %u", port);
707 pSocketService->m_socket = pSocketIOManager->CreateDatagramSocket(defaultBind, flags);
709 if (pSocketService->m_socket)
711 break;
713 else
715 NetLog("[Lobby] Failed to create socket on port %u", port);
721 if (pSocketService->m_socket)
723 NetLog("[Lobby] Created socket on port %u", port);
724 pSocketService->m_socket->RegisterListener(this);
725 pSocketService->m_socketListenPort = port;
726 m_serviceParams[service].m_listenPort = port;
727 if (m_services[service] != NULL)
729 m_services[service]->OnInternalSocketChanged(pSocketService->m_socket);
732 else
734 CryWarning(VALIDATOR_MODULE_ONLINE, VALIDATOR_ERROR,
735 "[Lobby] Socket could not be created, check firewall or try a different port. Connecting to network games may fail if not fixed.");
740 void CCryLobby::InternalSocketDie(ECryLobbyService service)
742 CRY_ASSERT_MESSAGE(service < eCLS_NumServices, "Illegal service specified");
743 SSocketService* pSocketService = GetCorrectSocketService(service);
744 ISocketIOManager* pSocketIOManager = GetExternalSocketIOManager();
745 if (service == eCLS_LAN)
747 pSocketIOManager = GetInternalSocketIOManager();
750 if (pSocketIOManager && pSocketService->m_socket)
752 pSocketService->m_socket->UnregisterListener(this);
753 pSocketIOManager->FreeDatagramSocket(pSocketService->m_socket);
754 pSocketService->m_socket = NULL;
757 if (m_services[service])
759 m_services[service]->OnInternalSocketChanged(pSocketService->m_socket);
763 void CCryLobby::InternalSocketFree(ECryLobbyService service)
765 SSocketService* pSocketService = GetCorrectSocketService(service);
766 if (pSocketService->m_socket)
768 InternalSocketDie(service);
772 ECryLobbyError CCryLobby::CheckAllocGlobalResources()
774 g_pObjcnt = &((INetworkPrivate*)gEnv->pNetwork)->GetObjectCounters();
775 return eCLE_Success;
778 void CCryLobby::CheckFreeGlobalResources()
780 uint32 i;
782 for (i = 0; i < eCLS_NumServices; i++)
784 if (m_services[i])
786 break;
790 if (i == eCLS_NumServices)
792 int a;
794 for (i = 0; i < MAX_LOBBY_TASKS; i++)
796 m_serviceTask[i].used = false;
799 for (i = 0; i < MAX_LOBBY_CONNECTIONS; i++)
801 FreeConnection(i);
804 for (a = 0; a < eCLS_NumServices; a++)
806 InternalSocketDie(ECryLobbyService(a));
811 CryLobbyTaskID CCryLobby::CreateTask()
813 for (uint32 i = 0; i < MAX_LOBBY_TASKS; i++)
815 if (!m_serviceTask[i].used)
817 m_serviceTask[i].used = true;
818 #if ENABLE_CRYLOBBY_DEBUG_TESTS
819 m_serviceTask[i].startTaskTime = 0LL;
820 m_serviceTask[i].tickTaskTime = 0LL;
821 m_serviceTask[i].generateErrorDone = false;
822 m_serviceTask[i].startTaskTimerStarted = false;
823 m_serviceTask[i].startTaskDone = false;
824 m_serviceTask[i].tickTaskTimerStarted = false;
825 m_serviceTask[i].tickTaskDone = false;
826 #endif
827 return i;
831 return CryLobbyInvalidTaskID;
834 void CCryLobby::ReleaseTask(CryLobbyTaskID id)
836 m_serviceTask[id].used = false;
839 #if ENABLE_CRYLOBBY_DEBUG_TESTS
840 bool CCryLobby::DebugGenerateError(CryLobbyTaskID id, ECryLobbyError& error)
842 if (CLobbyCVars::Get().cldEnable)
844 SServiceTask* pTask = &m_serviceTask[id];
846 if (!pTask->generateErrorDone)
848 pTask->generateErrorDone = true;
850 if (cry_random(0, 99) < CLobbyCVars::Get().cldErrorPercentage)
852 NetLog("[Lobby] Generating random eCLE_TimeOut on task %u", id);
853 error = eCLE_TimeOut;
854 return true;
859 return false;
862 bool CCryLobby::DebugOKToStartTaskRunning(CryLobbyTaskID id)
864 int minDelay = CLobbyCVars::Get().cldMinDelayTime;
865 int maxDelay = CLobbyCVars::Get().cldMaxDelayTime;
867 if (CLobbyCVars::Get().cldEnable && (minDelay >= 0) && (maxDelay > minDelay))
869 SServiceTask* pTask = &m_serviceTask[id];
871 if (!pTask->startTaskTimerStarted)
873 CTimeValue addTime;
874 int64 addMilliSeconds;
876 addMilliSeconds = cry_random(minDelay, maxDelay);
878 addTime.SetMilliSeconds(addMilliSeconds);
880 pTask->startTaskTimerStarted = true;
881 pTask->startTaskDone = false;
882 pTask->startTaskTime = g_time + addTime;
884 NetLog("[Lobby] Delay start task %u for %" PRIi64 " milliseconds", id, addMilliSeconds);
886 return false;
889 NetLog("[Lobby] Delayed task %u started", id);
892 return true;
895 bool CCryLobby::DebugTickCallStartTaskRunning(CryLobbyTaskID id)
897 if (CLobbyCVars::Get().cldEnable)
899 SServiceTask* pTask = &m_serviceTask[id];
901 if (pTask->startTaskTimerStarted && !pTask->startTaskDone)
903 if (g_time > pTask->startTaskTime)
905 pTask->startTaskDone = true;
906 return true;
911 return false;
914 bool CCryLobby::DebugOKToTickTask(CryLobbyTaskID id, bool running)
916 int minDelay = CLobbyCVars::Get().cldMinDelayTime;
917 int maxDelay = CLobbyCVars::Get().cldMaxDelayTime;
919 if (CLobbyCVars::Get().cldEnable && (minDelay >= 0) && (maxDelay > minDelay))
921 SServiceTask* pTask = &m_serviceTask[id];
923 if (running && !pTask->startTaskDone)
925 if (!pTask->tickTaskTimerStarted)
927 CTimeValue addTime;
928 int64 addMilliSeconds;
930 addMilliSeconds = cry_random(minDelay, maxDelay);
932 addTime.SetMilliSeconds(addMilliSeconds);
934 pTask->tickTaskTimerStarted = true;
935 pTask->tickTaskTime = g_time + addTime;
937 NetLog("[Lobby] Delay start ticking task %u for %" PRIi64 " milliseconds", id, addMilliSeconds);
939 return false;
941 else
943 if (g_time > pTask->tickTaskTime)
945 if (!pTask->tickTaskDone)
947 NetLog("[Lobby] Delayed task %u ticking", id);
949 pTask->tickTaskDone = true;
952 return true;
954 else
956 return false;
962 return true;
964 #endif
966 ECryLobbyError CCryLobby::Initialise(ECryLobbyService service, ECryLobbyServiceFeatures features, CryLobbyConfigurationCallback cfgCb, CryLobbyCallback cb, void* cbArg)
968 LOBBY_AUTO_LOCK;
970 ECryLobbyError error = eCLE_Success;
971 if (features & eCLSO_Base)
973 error = CheckAllocGlobalResources();
976 assert(service >= 0 && service < eCLS_NumServices);
978 if (error == eCLE_Success)
980 switch (service)
982 case eCLS_LAN:
983 //#if !defined(_RELEASE) && !defined(DEDICATED_SERVER) && !defined(PURE_CLIENT)
984 #if USE_LAN
985 if (m_services[eCLS_LAN] == NULL)
987 m_services[eCLS_LAN] = new CCryLANLobbyService(this, service);
989 if (!m_services[eCLS_LAN])
991 error = eCLE_OutOfMemory;
994 #else
995 error = eCLE_ServiceNotSupported;
996 #endif // USE_LAN
998 break;
1000 case eCLS_Online:
1001 if (m_services[eCLS_Online] == NULL)
1003 #if USE_STEAM
1004 if (CLobbyCVars::Get().useSteamAsOnlineLobby)
1006 m_services[eCLS_Online] = new CCrySteamLobbyService(this, service);
1008 if (!m_services[eCLS_Online])
1010 error = eCLE_OutOfMemory;
1013 else
1015 error = eCLE_ServiceNotSupported;
1017 #else
1018 #if USE_LIVE
1019 m_services[eCLS_Online] = new CCryLiveLobbyService(this, service);
1021 if (!m_services[eCLS_Online])
1023 error = eCLE_OutOfMemory;
1025 #elif USE_PSN
1026 m_services[eCLS_Online] = new CCryPSNLobbyService(this, service);
1028 if (!m_services[eCLS_Online])
1030 error = eCLE_OutOfMemory;
1032 #elif USE_DURANGOLIVE
1033 m_services[eCLS_Online] = new CCryDurangoLiveLobbyService(this, service);
1035 if (!m_services[eCLS_Online])
1037 error = eCLE_OutOfMemory;
1039 #else
1040 m_services[eCLS_Online] = NULL;
1041 error = eCLE_ServiceNotSupported;
1042 #endif
1043 #endif
1044 break;
1048 if (error == eCLE_Success)
1050 m_task[service].cb = cb;
1051 m_task[service].cbArg = cbArg;
1052 this->m_configCB = cfgCb;
1054 error = m_services[service]->Initialise(features, (features & eCLSO_Base) ? InitialiseServiceCB : NULL);
1056 if (error == eCLE_Success)
1058 if (features & eCLSO_Base)
1060 FROM_GAME_TO_LOBBY(&CCryLobbyService::CreateSocketNT, m_services[service].get());
1063 else
1065 // Task didn't start so remove our reference to the service
1066 m_services[service] = NULL;
1071 if ((error == eCLE_Success) && (features & eCLSO_Base))
1073 // Final step, initialise lobby parameters
1074 m_services[service]->GetSocketPorts(m_serviceParams[service].m_connectPort, m_serviceParams[service].m_listenPort);
1077 CryLog("[Lobby] Initialise service %d error %d\n", service, error);
1079 return error;
1082 ECryLobbyError CCryLobby::Terminate(ECryLobbyService service, ECryLobbyServiceFeatures features, CryLobbyCallback cb, void* cbArg)
1084 LOBBY_AUTO_LOCK;
1085 ECryLobbyError error;
1087 if (m_services[service])
1089 m_task[service].cb = cb;
1090 m_task[service].cbArg = cbArg;
1092 error = m_services[service]->Terminate(features, (features & eCLSO_Base) ? TerminateServiceCB : NULL);
1094 if (features & eCLSO_Base)
1096 m_services[service] = NULL;
1099 else
1101 error = eCLE_NotInitialised;
1105 if (features & eCLSO_Base)
1107 CheckFreeGlobalResources();
1110 CryLog("[Lobby] Terminate service %d error %d\n", service, error);
1112 return error;
1115 ECryLobbyError CCryLobby::ProcessEvents()
1117 if (m_safetyToGameMutex.TryLock())
1119 m_toGameQueue.Flush(false);
1120 m_safetyToGameMutex.Unlock();
1121 return eCLE_Success;
1124 return eCLE_SuccessContinue;
1127 CryLobbyConnectionID CCryLobby::CreateConnection(const TNetAddress& address)
1129 #if USE_LOBBY_REMOTE_CONNECTIONS
1130 for (uint32 i = 0; i < MAX_LOBBY_CONNECTIONS; i++)
1132 if (!m_connection[i].used)
1134 SConnection* pConnection = &m_connection[i];
1136 #if RESET_CONNECTED_CONNECTION
1137 pConnection->sendCookie = gEnv->pTimer->GetAsyncTime().GetValue();
1138 pConnection->recvCookie = INVALID_CONNECTION_COOKIE;
1139 #endif
1141 pConnection->timeSinceSend = 0;
1142 pConnection->timeSinceRecv = 0;
1143 pConnection->disconnectTimer = 0;
1144 pConnection->addr = address;
1145 pConnection->state = eCLCS_Pending;
1146 pConnection->refCount = 0;
1147 pConnection->counterIn = 0;
1148 pConnection->counterOut = 0;
1149 pConnection->used = true;
1150 pConnection->reliableBuildPacket.SetWriteBuffer(pConnection->reliableBuildPacketBuffer, MAX_LOBBY_PACKET_SIZE);
1152 pConnection->ping.aveTime = CRYLOBBY_INVALID_PING;
1153 pConnection->ping.currentTime = 0;
1155 for (uint32 j = 0; j < NUM_LOBBY_PINGS; j++)
1157 pConnection->ping.times[j] = CRYLOBBY_INVALID_PING;
1160 ECryLobbyService service = GetCorrectSocketServiceTypeForAddr(address);
1161 if (!GetInternalSocket(service))
1163 NetLog("[Lobby] Socket was not previously ready, trying again");
1164 InternalSocketCreate(service);
1167 SECURE_NET_LOG("[lobby] Create reliable connection " PRFORMAT_LCINFO, PRARG_LCINFO(CryLobbyConnectionID(i), pConnection->addr));
1169 return i;
1172 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1174 return CryLobbyInvalidConnectionID;
1177 CryLobbyConnectionID CCryLobby::FindConnection(const TNetAddress& address)
1179 #if USE_LOBBY_REMOTE_CONNECTIONS
1180 for (uint32 i = 0; i < MAX_LOBBY_CONNECTIONS; i++)
1182 if (m_connection[i].used && (m_connection[i].addr == address))
1184 return i;
1187 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1189 return CryLobbyInvalidConnectionID;
1192 void CCryLobby::ConnectionAddRef(CryLobbyConnectionID c)
1194 #if USE_LOBBY_REMOTE_CONNECTIONS
1195 if (c != CryLobbyInvalidConnectionID)
1197 SConnection* pConnection = &m_connection[c];
1199 if (pConnection->used)
1201 SECURE_NET_LOG("RefCount of connection " PRFORMAT_LCINFO " is incrementing, %u->%u. Thread #%" PRI_THREADID, PRARG_LCINFO(c, pConnection->addr), pConnection->refCount, pConnection->refCount + 1u, CryGetCurrentThreadId());
1203 pConnection->refCount++;
1206 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1209 bool CCryLobby::KeepPacketAfterDisconnect(uint32 packetType)
1211 return ((packetType == eLobbyPT_SessionDeleteRemoteConnection) ||
1212 (packetType == eLobbyPT_SessionRequestJoinResult));
1215 void CCryLobby::ConnectionRemoveRef(CryLobbyConnectionID c)
1217 #if USE_LOBBY_REMOTE_CONNECTIONS
1218 if (c != CryLobbyInvalidConnectionID)
1220 SConnection* pConnection = &m_connection[c];
1222 if (pConnection->used)
1224 if (pConnection->refCount > 0)
1226 SECURE_NET_LOG("RefCount of connection " PRFORMAT_LCINFO " is decrementing, %u->%d. Thread #%" PRI_THREADID, PRARG_LCINFO(c, pConnection->addr), pConnection->refCount, pConnection->refCount - 1u, CryGetCurrentThreadId());
1228 pConnection->refCount--;
1230 if (pConnection->refCount == 0)
1232 if (pConnection->reliableBuildPacket.GetWriteBufferPos() > 0)
1234 AddReliablePacketToSendQueue(c, &pConnection->reliableBuildPacket);
1237 // We only need to keep eLobbyPT_SessionDeleteRemoteConnection in the send queue so the other end knows we are leaving.
1238 // All other packets should be removed as they are not important now.
1239 NetLog("[Lobby] %u packets in send queue", pConnection->dataQueue.Size());
1240 pConnection->counterOut -= (uint8) pConnection->dataQueue.Size();
1242 if (!pConnection->dataQueue.Empty())
1244 uint32 numCheck = pConnection->dataQueue.Size();
1246 for (uint32 i = 0; i < numCheck; i++)
1248 SConnection::SData& data = pConnection->dataQueue.Front();
1249 uint8* pData = (uint8*)MemGetPtr(data.data);
1250 CCrySharedLobbyPacket packet;
1251 uint32 dataPos = 0;
1252 SCryLobbyPacketDataHeader* pDataHeader = packet.GetLobbyPacketDataHeader();
1254 pConnection->dataQueue.Pop();
1256 while (GetNextPacketFromBuffer(pData, data.dataSize, dataPos, &packet))
1258 #if !defined(EXCLUDE_NORMAL_LOG)
1259 uint32 encodedPacketType = pDataHeader->lobbyPacketType;
1260 #endif
1261 DecodePacketDataHeader(&packet);
1263 if (KeepPacketAfterDisconnect(pDataHeader->lobbyPacketType))
1265 NetLog("[Lobby] Keep packet %u (%u) Size %u", pDataHeader->lobbyPacketType, encodedPacketType, pDataHeader->dataSize);
1266 EncodePacketDataHeader(&packet);
1267 AddPacketToReliableBuildPacket(c, &packet);
1269 else
1271 NetLog("[Lobby] Remove packet %u Size %u", pDataHeader->lobbyPacketType, pDataHeader->dataSize);
1275 MemFree(data.data);
1279 if (pConnection->reliableBuildPacket.GetWriteBufferPos() > 0)
1281 AddReliablePacketToSendQueue(c, &pConnection->reliableBuildPacket);
1283 // Put connection into freeing state
1284 // Any sends in queue will still try and send and no new sends will be accepted
1285 pConnection->state = eCLCS_Freeing;
1287 else
1289 SECURE_NET_LOG("[lobby] Release connection " PRFORMAT_LCINFO, PRARG_LCINFO(c, pConnection->addr));
1291 FreeConnection(c);
1295 else
1297 #if !defined(_RELEASE)
1298 CryFatalError("RefCount of connection " PRFORMAT_LCINFO " is trying to drop below 0! Thread #%" PRI_THREADID ".", PRARG_LCINFO(c, pConnection->addr), CryGetCurrentThreadId());
1299 #else
1300 SECURE_NET_LOG("RefCount of connection " PRFORMAT_LCINFO " is trying to drop below 0! Thread #%" PRI_THREADID ".", PRARG_LCINFO(c, pConnection->addr), CryGetCurrentThreadId());
1301 #endif
1305 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1308 bool CCryLobby::ConnectionHasReference(CryLobbyConnectionID c)
1310 #if USE_LOBBY_REMOTE_CONNECTIONS
1311 if (c != CryLobbyInvalidConnectionID)
1313 SConnection* pConnection = &m_connection[c];
1315 if (pConnection->used)
1317 return pConnection->refCount > 0;
1320 #endif
1322 return false;
1325 void CCryLobby::ConnectionSetState(CryLobbyConnectionID c, ECryLobbyConnectionState state)
1327 #if USE_LOBBY_REMOTE_CONNECTIONS
1328 if (c != CryLobbyInvalidConnectionID)
1330 SConnection* pConnection = &m_connection[c];
1332 if (pConnection->used)
1334 pConnection->state = state;
1337 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1340 ECryLobbyConnectionState CCryLobby::ConnectionGetState(CryLobbyConnectionID c)
1342 #if USE_LOBBY_REMOTE_CONNECTIONS
1343 if (c != CryLobbyInvalidConnectionID)
1345 SConnection* pConnection = &m_connection[c];
1347 if (pConnection->used)
1349 return pConnection->state;
1352 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1354 return eCLCS_NotConnected;
1357 void CCryLobby::FreeConnection(CryLobbyConnectionID c)
1359 #if USE_LOBBY_REMOTE_CONNECTIONS
1360 if (c != CryLobbyInvalidConnectionID)
1362 SConnection* connection = &m_connection[c];
1364 if (connection->used)
1366 connection->used = false;
1368 while (!connection->dataQueue.Empty())
1370 SConnection::SData& data = connection->dataQueue.Front();
1372 MemFree(data.data);
1373 connection->dataQueue.Pop();
1377 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1380 bool CCryLobby::ConnectionFromAddress(CryLobbyConnectionID* connection, const TNetAddress& address)
1382 *connection = FindConnection(address);
1384 return *connection != CryLobbyInvalidConnectionID;
1387 bool CCryLobby::AddressFromConnection(TNetAddress& address, CryLobbyConnectionID c)
1389 #if USE_LOBBY_REMOTE_CONNECTIONS
1390 assert(c == CryLobbyInvalidConnectionID || c < MAX_LOBBY_CONNECTIONS);
1392 if (c < MAX_LOBBY_CONNECTIONS)
1394 SConnection* connection = &m_connection[c];
1396 if (connection->used)
1398 address = connection->addr;
1399 return true;
1402 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1404 return false;
1407 bool CCryLobby::SetConnectionAddress(CryLobbyConnectionID c, TNetAddress& address)
1409 #if USE_LOBBY_REMOTE_CONNECTIONS
1410 if (c != CryLobbyInvalidConnectionID)
1412 SConnection* connection = &m_connection[c];
1414 if (connection->used)
1416 connection->addr = address;
1417 return true;
1420 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1422 return false;
1425 void CCryLobby::FlushMessageQueue()
1427 Tick(true);
1430 bool CCryLobby::AddReliablePacketToSendQueue(CryLobbyConnectionID connectionID, CCryLobbyPacket* pPacket)
1432 #if USE_LOBBY_REMOTE_CONNECTIONS
1433 SConnection* pConnection = &m_connection[connectionID];
1435 if (!pConnection->dataQueue.Full())
1437 SConnection::SData sdata;
1439 sdata.data = MemAlloc(pPacket->GetWriteBufferPos());
1441 if (sdata.data != TMemInvalidHdl)
1443 uint8* pData = (uint8*)MemGetPtr(sdata.data);
1445 memcpy(pData, pPacket->GetWriteBuffer(), pPacket->GetWriteBufferPos());
1447 sdata.dataSize = pPacket->GetWriteBufferPos();
1448 sdata.counter = pConnection->counterOut;
1449 pConnection->dataQueue.Push(sdata);
1451 pPacket->SetWriteBufferPos(0);
1453 return true;
1456 else
1458 SECURE_NET_LOG("[Lobby] Trying to send to connection " PRFORMAT_LCINFO " but the send queue is full", PRARG_LCINFO(connectionID, pConnection->addr));
1459 const int numPacketsInQueue = pConnection->dataQueue.Size();
1460 for (int i = 0; i < numPacketsInQueue; ++i)
1462 SConnection::SData& data = pConnection->dataQueue[i];
1463 NetLog("counter %d size %d", data.counter, data.dataSize);
1464 LogPacketsInBuffer((uint8*)MemGetPtr(data.data), data.dataSize);
1467 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1469 return false;
1472 bool CCryLobby::AddPacketToReliableBuildPacket(CryLobbyConnectionID connectionID, CCryLobbyPacket* pPacket)
1474 #if USE_LOBBY_REMOTE_CONNECTIONS
1475 SConnection* pConnection = &m_connection[connectionID];
1476 CCrySharedLobbyPacket* pSBuildPacket = (CCrySharedLobbyPacket*)&pConnection->reliableBuildPacket;
1477 SCryLobbyPacketHeader* pBuildPacketHeader = pSBuildPacket->GetLobbyPacketHeader();
1478 SCryLobbyPacketDataHeader* pBuildDataHeader = pSBuildPacket->GetLobbyPacketDataHeader();
1479 CCrySharedLobbyPacket* pSPacket = (CCrySharedLobbyPacket*)pPacket;
1480 SCryLobbyPacketHeader* pPacketHeader = pSPacket->GetLobbyPacketHeader();
1481 SCryLobbyPacketDataHeader* pDataHeader = pSPacket->GetLobbyPacketDataHeader();
1482 uint8* pDataBuffer = pSPacket->GetWriteBuffer() + CryLobbyPacketReliableHeaderSize;
1483 uint32 dataSize = pSPacket->GetWriteBufferPos() - CryLobbyPacketReliableHeaderSize;
1485 if (pSPacket->GetWriteBufferPos() > MAX_LOBBY_PACKET_SIZE)
1487 if (pSBuildPacket->GetWriteBufferPos() > 0)
1489 if (!AddReliablePacketToSendQueue(connectionID, pSBuildPacket))
1491 return false;
1495 pConnection->counterOut++;
1497 *pBuildPacketHeader = *pPacketHeader;
1498 *pBuildDataHeader = *pDataHeader;
1500 pPacketHeader->counterOut = pConnection->counterOut;
1501 pPacketHeader->counterIn = pConnection->counterIn;
1502 pDataHeader->dataSize = dataSize;
1504 uint32 bufferPos = pSPacket->GetWriteBufferPos();
1505 pSPacket->SetWriteBufferPos(0);
1506 pSPacket->WritePacketHeader();
1507 pSPacket->WriteDataHeader();
1508 pSPacket->SetWriteBufferPos(bufferPos);
1510 if (AddReliablePacketToSendQueue(connectionID, pSPacket))
1512 return true;
1515 return false;
1518 if (pSBuildPacket->GetWriteBufferPos() > 0)
1520 // Send and start new if
1521 if (((pSBuildPacket->GetWriteBufferPos() + CryLobbyPacketReliableDataHeaderSize + dataSize) > pSBuildPacket->GetReadBufferSize()) || // Data will not fit in current packet
1522 (pBuildPacketHeader->fromUID.m_sid != pPacketHeader->fromUID.m_sid)) // sid has changed due to host migration
1524 if (!AddReliablePacketToSendQueue(connectionID, pSBuildPacket))
1526 return false;
1531 if (pSBuildPacket->GetWriteBufferPos() == 0)
1533 // Build packet is empty so start with this packet
1534 pConnection->counterOut++;
1536 *pBuildPacketHeader = *pPacketHeader;
1537 *pBuildDataHeader = *pDataHeader;
1539 pBuildPacketHeader->counterOut = pConnection->counterOut;
1540 pBuildPacketHeader->counterIn = pConnection->counterIn;
1541 pBuildDataHeader->dataSize = dataSize;
1543 pSBuildPacket->WritePacketHeader();
1544 pSBuildPacket->WriteDataHeader();
1545 pSBuildPacket->WriteData(pDataBuffer, dataSize);
1547 else
1549 // Add data to end of current packet.
1550 *pBuildDataHeader = *pDataHeader;
1551 pBuildDataHeader->dataSize = dataSize;
1552 pSBuildPacket->WriteDataHeader();
1553 pSBuildPacket->WriteData(pDataBuffer, dataSize);
1556 return true;
1557 #else // USE_LOBBY_REMOTE_CONNECTIONS
1558 return false;
1559 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1562 void CCryLobby::CalculatePacketTypeEncoding()
1564 CMTRand_int32 r(CRYLOBBY_PACKET_TYPE_ENCODE_SEED);
1565 uint32 i;
1567 for (i = 0; i < 256; i++)
1569 m_encodePacketType[i] = i;
1572 for (i = 0; i < 1024; i++)
1574 uint32 lhs = r.GenerateUint32() & 0xff;
1575 uint32 rhs = r.GenerateUint32() & 0xff;
1577 std::swap(m_encodePacketType[lhs], m_encodePacketType[rhs]);
1580 for (i = 0; i < 256; i++)
1582 m_decodePacketType[m_encodePacketType[i]] = i;
1585 for (i = m_servicePacketEnd[eCLS_LAN]; i <= CRYLANLOBBY_PACKET_MAX; i++)
1587 m_decodePacketType[m_encodePacketType[i]] = eLobbyPT_InvalidPackeType;
1590 for (i = m_servicePacketEnd[eCLS_Online]; i <= CRYONLINELOBBY_PACKET_MAX; i++)
1592 m_decodePacketType[m_encodePacketType[i]] = eLobbyPT_InvalidPackeType;
1595 for (i = m_userPacketEnd; i <= CRYLOBBY_USER_PACKET_MAX; i++)
1597 m_decodePacketType[m_encodePacketType[i]] = eLobbyPT_InvalidPackeType;
1601 void CCryLobby::EncodePacketDataHeader(CCryLobbyPacket* pPacket)
1603 CCrySharedLobbyPacket* pSPacket = (CCrySharedLobbyPacket*)pPacket;
1604 SCryLobbyPacketDataHeader* pDataHeader = pSPacket->GetLobbyPacketDataHeader();
1606 pDataHeader->lobbyPacketType = m_encodePacketType[pDataHeader->lobbyPacketType];
1609 void CCryLobby::DecodePacketDataHeader(CCryLobbyPacket* pPacket)
1611 CCrySharedLobbyPacket* pSPacket = (CCrySharedLobbyPacket*)pPacket;
1612 SCryLobbyPacketDataHeader* pDataHeader = pSPacket->GetLobbyPacketDataHeader();
1614 pDataHeader->lobbyPacketType = m_decodePacketType[pDataHeader->lobbyPacketType];
1617 ESocketError CCryLobby::Send(CCryLobbyPacket* pPacket, const TNetAddress& to, CryLobbyConnectionID connectionID, CryLobbySendID* pSendID)
1619 #if USE_LOBBY_REMOTE_CONNECTIONS
1620 CCrySharedLobbyPacket* pSPacket = (CCrySharedLobbyPacket*)pPacket;
1621 ESocketError ret = eSE_Ok;
1623 EncodePacketDataHeader(pSPacket);
1625 if (pSPacket->GetReliable())
1627 if (connectionID == CryLobbyInvalidConnectionID)
1629 connectionID = FindConnection(to);
1631 if (connectionID == CryLobbyInvalidConnectionID)
1633 connectionID = CreateConnection(to);
1637 if (connectionID != CryLobbyInvalidConnectionID)
1639 SConnection* pConnection = &m_connection[connectionID];
1641 if ((pConnection->state == eCLCS_Connected) || (pConnection->state == eCLCS_Pending))
1643 if (AddPacketToReliableBuildPacket(connectionID, pSPacket))
1645 if (pConnection->dataQueue.Empty())
1647 AddReliablePacketToSendQueue(connectionID, &pConnection->reliableBuildPacket);
1649 SConnection::SData& data = pConnection->dataQueue.Front();
1651 SECURE_NET_LOG("[lobby] Send reliable connection " PRFORMAT_LCINFO " counter %d size %d", PRARG_LCINFO(connectionID, pConnection->addr), data.counter, data.dataSize);
1653 LogPacketsInBuffer((uint8*)MemGetPtr(data.data), data.dataSize);
1655 // Data hasn't been acknowledged so try sending again
1656 SSocketService* pSocketService = GetCorrectSocketServiceForAddr(pConnection->addr);
1657 if (pSocketService->m_socket)
1659 if (pSocketService->m_socket->Send(EncryptPacket((uint8*)MemGetPtr(data.data), data.dataSize), data.dataSize, pConnection->addr) != eSE_Ok)
1661 SECURE_NET_LOG("[Lobby] Failed to send setting connection " PRFORMAT_LCINFO " to eCLCS_NotConnected", PRARG_LCINFO(connectionID, pConnection->addr));
1662 pConnection->state = eCLCS_NotConnected;
1667 if (pSendID)
1669 *pSendID = CryLobbyCreateSendID(connectionID, pConnection->counterOut);
1672 else
1674 ret = eSE_MiscFatalError;
1678 else
1680 ret = eSE_MiscFatalError;
1683 else
1685 SSocketService* pSocketService = GetCorrectSocketServiceForAddr(to);
1687 if (pSocketService->m_socket)
1689 uint8* pBuffer = pSPacket->GetWriteBuffer();
1690 uint32 bufferSize = pSPacket->GetWriteBufferPos();
1692 pSPacket->SetWriteBufferPos(0);
1693 pSPacket->WritePacketHeader();
1694 pSPacket->WriteDataHeader();
1695 pSPacket->SetWriteBufferPos(bufferSize);
1697 if (pSendID)
1699 *pSendID = CryLobbyInvalidSendID;
1702 ret = pSocketService->m_socket->Send(EncryptPacket(pBuffer, bufferSize), bufferSize, to);
1704 else
1706 ret = eSE_MiscFatalError;
1710 DecodePacketDataHeader(pSPacket);
1712 return ret;
1713 #else // USE_LOBBY_REMOTE_CONNECTIONS
1714 return eSE_MiscFatalError;
1715 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1718 ESocketError CCryLobby::SendVoice(CCryLobbyPacket* pPacket, const TNetAddress& to)
1720 #if USE_LOBBY_REMOTE_CONNECTIONS
1721 SSocketService* pSocketService = GetCorrectSocketService(m_service);
1723 if (pSocketService->m_socket)
1725 CCrySharedLobbyPacket* pSPacket = (CCrySharedLobbyPacket*)pPacket;
1726 uint8* pBuffer = pSPacket->GetWriteBuffer();
1727 uint32 bufferSize = pSPacket->GetWriteBufferPos();
1729 EncodePacketDataHeader(pSPacket);
1731 pSPacket->SetWriteBufferPos(0);
1732 pSPacket->WritePacketHeader();
1733 pSPacket->WriteDataHeader();
1734 pSPacket->SetWriteBufferPos(bufferSize);
1736 DecodePacketDataHeader(pSPacket);
1738 return pSocketService->m_socket->SendVoice(EncryptPacket(pBuffer, bufferSize), bufferSize, to);
1740 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1742 return eSE_MiscFatalError;
1745 void CCryLobby::UpdateConnectionPing(CryLobbyConnectionID connectionID, CryPing ping)
1747 #if USE_LOBBY_REMOTE_CONNECTIONS
1748 SConnection* pConnection = &m_connection[connectionID];
1750 pConnection->ping.times[pConnection->ping.currentTime] = ping;
1751 pConnection->ping.currentTime = (pConnection->ping.currentTime + 1) % NUM_LOBBY_PINGS;
1753 uint32 numValidPings = 0;
1754 CryPingAccumulator totalTime = 0;
1756 for (uint32 i = 0; i < NUM_LOBBY_PINGS; ++i)
1758 if (pConnection->ping.times[i] != CRYLOBBY_INVALID_PING)
1760 totalTime += pConnection->ping.times[i];
1761 ++numValidPings;
1765 if (numValidPings)
1767 pConnection->ping.aveTime = (CryPing)(totalTime / numValidPings);
1769 else
1771 pConnection->ping.aveTime = CRYLOBBY_INVALID_PING;
1773 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1776 CryPing CCryLobby::GetConnectionPing(CryLobbyConnectionID connectionID)
1778 #if USE_LOBBY_REMOTE_CONNECTIONS
1779 if ((connectionID != CryLobbyInvalidConnectionID) && (connectionID < MAX_LOBBY_CONNECTIONS))
1781 return m_connection[connectionID].ping.aveTime;
1783 #endif // USE_LOBBY_REMOTE_CONNECTIONS
1785 return CRYLOBBY_INVALID_PING;
1788 bool CCryLobby::GetNextPacketFromBuffer(const uint8* pData, uint32 dataSize, uint32& dataPos, CCryLobbyPacket* pPacket)
1790 CCrySharedLobbyPacket* pSPacket = (CCrySharedLobbyPacket*)pPacket;
1792 if (dataPos == 0)
1794 pSPacket->SetReadBuffer(pData, dataSize);
1795 pSPacket->SetReadBufferPos(0);
1796 pSPacket->ReadPacketHeader();
1797 dataPos = CryLobbyPacketReliablePacketHeaderSize;
1800 if (dataPos < dataSize)
1802 SCryLobbyPacketDataHeader* pDataHeader = pSPacket->GetLobbyPacketDataHeader();
1804 pSPacket->SetReadBuffer(pData + dataPos - CryLobbyPacketReliablePacketHeaderSize, dataSize - (dataPos - CryLobbyPacketReliablePacketHeaderSize));
1805 pSPacket->SetReadBufferPos(CryLobbyPacketReliablePacketHeaderSize);
1806 pSPacket->ReadDataHeader();
1807 pSPacket->SetReadBuffer(pData + dataPos - CryLobbyPacketReliablePacketHeaderSize, pDataHeader->dataSize + CryLobbyPacketReliableHeaderSize);
1808 pSPacket->SetReadBufferPos(CryLobbyPacketReliableHeaderSize + pDataHeader->dataSize);
1809 dataPos += CryLobbyPacketReliableDataHeaderSize + pDataHeader->dataSize;
1810 return true;
1813 return false;
1816 void CCryLobby::ProcessPacket(const TNetAddress& addr, CryLobbyConnectionID connectionID, CCryLobbyPacket* pPacket)
1818 #if USE_LOBBY_REMOTE_CONNECTIONS
1819 SConnection* pConnection = (connectionID != CryLobbyInvalidConnectionID) ? &m_connection[connectionID] : NULL;
1821 switch (pPacket->StartRead())
1823 case eLobbyPT_Ack:
1824 if (pConnection)
1826 uint8 counterIn = pPacket->ReadUINT8();
1828 if (!pConnection->dataQueue.Empty())
1830 SConnection::SData& qdata = pConnection->dataQueue.Front();
1832 if (counterIn == qdata.counter)
1834 #if !defined(NO_NETWORK_SECURITY_LOGS)
1835 const uint8 qDataCounter = qdata.counter;
1836 #endif
1837 // Other end has received the packet we are trying to send
1838 OnSendComplete(addr);
1839 SECURE_NET_LOG("[lobby] Got ack on connection " PRFORMAT_LCINFO " counterIn=%u, qDataCounter=%u", PRARG_LCINFO(connectionID, pConnection->addr), counterIn, qDataCounter);
1844 break;
1846 case eLobbyPT_ConnectionRequest:
1848 #if RESET_CONNECTED_CONNECTION
1849 uint64 cookie = pPacket->ReadUINT64();
1850 #endif
1852 if (connectionID == CryLobbyInvalidConnectionID)
1854 connectionID = CreateConnection(addr);
1856 else
1858 pConnection = &m_connection[connectionID];
1860 if (pConnection->state == eCLCS_Freeing)
1862 SECURE_NET_LOG("[Lobby] Connection Request on existing Freeing connection " PRFORMAT_LCINFO, PRARG_LCINFO(connectionID, pConnection->addr));
1863 uint8 refCount = pConnection->refCount;
1864 FreeConnection(connectionID);
1865 connectionID = CreateConnection(addr);
1866 NetLog("[Lobby] setting refCount back to %u for resetted connection", refCount);
1867 pConnection = &m_connection[connectionID];
1868 pConnection->refCount = refCount;
1870 #if RESET_CONNECTED_CONNECTION
1871 else
1873 if ((pConnection->recvCookie != cookie) && (pConnection->recvCookie != INVALID_CONNECTION_COOKIE))
1875 SECURE_NET_LOG("[Lobby] Connection Request on existing connected connection, current cookie %llx new cookie %llx Freeing connection " PRFORMAT_LCINFO, pConnection->recvCookie, cookie, PRARG_LCINFO(connectionID, pConnection->addr));
1876 CCryMatchMaking* pMatchMaking = (CCryMatchMaking*)GetMatchMaking();
1877 if (pMatchMaking)
1879 pMatchMaking->ResetConnection(connectionID);
1882 uint8 refCount = pConnection->refCount;
1884 FreeConnection(connectionID);
1885 connectionID = CreateConnection(addr);
1887 if (connectionID != CryLobbyInvalidConnectionID)
1889 NetLog("[Lobby] setting refCount back to %u for resetted connection", refCount);
1891 pConnection = &m_connection[connectionID];
1892 pConnection->refCount = refCount;
1896 #endif
1899 if (connectionID != CryLobbyInvalidConnectionID)
1901 pConnection = &m_connection[connectionID];
1903 const uint32 MaxBufferSize = CryLobbyPacketHeaderSize
1904 #if RESET_CONNECTED_CONNECTION
1905 + CryLobbyPacketUINT64Size;
1906 #endif // RESET_CONNECTED_CONNECTION
1908 uint8 buffer[MaxBufferSize];
1909 CCrySharedLobbyPacket resultPacket;
1911 #if RESET_CONNECTED_CONNECTION
1912 pConnection->recvCookie = cookie;
1913 #endif
1915 pConnection->state = eCLCS_Connected;
1917 resultPacket.SetWriteBuffer(buffer, MaxBufferSize);
1918 resultPacket.StartWrite(eLobbyPT_ConnectionRequestResult, false);
1919 #if RESET_CONNECTED_CONNECTION
1920 SECURE_NET_LOG("[Lobby] Sending cookie %llx with connection " PRFORMAT_LCINFO, pConnection->sendCookie, PRARG_LCINFO(connectionID, pConnection->addr));
1921 resultPacket.WriteUINT64(pConnection->sendCookie);
1922 #endif
1924 if (Send(&resultPacket, pConnection->addr, connectionID, NULL) != eSE_Ok)
1926 SECURE_NET_LOG("[Lobby] Failed to send setting connection " PRFORMAT_LCINFO " to eCLCS_NotConnected", PRARG_LCINFO(connectionID, pConnection->addr));
1927 pConnection->state = eCLCS_NotConnected;
1931 break;
1934 case eLobbyPT_ConnectionRequestResult:
1935 if (pConnection)
1937 pConnection->state = eCLCS_Connected;
1938 #if RESET_CONNECTED_CONNECTION
1939 pConnection->recvCookie = pPacket->ReadUINT64();
1940 SECURE_NET_LOG("[Lobby] Setting recvCookie %llx for connection " PRFORMAT_LCINFO, pConnection->recvCookie, PRARG_LCINFO(connectionID, pConnection->addr));
1941 #endif
1944 break;
1946 case eLobbyPT_Ping:
1947 if (pConnection)
1949 CTimeValue currentTime = gEnv->pTimer->GetAsyncTime();
1950 CTimeValue recvTime = pPacket->GetRecvTime();
1951 uint64 timeDelayed = (currentTime - recvTime).GetMilliSecondsAsInt64();
1952 const uint32 MaxBufferSize = CryLobbyPacketHeaderSize + CryLobbyPacketUINT64Size;
1953 uint8 buffer[MaxBufferSize];
1954 CCrySharedLobbyPacket pongPacket;
1956 pongPacket.SetWriteBuffer(buffer, MaxBufferSize);
1957 uint64 time = pPacket->ReadUINT64() + timeDelayed;
1959 pongPacket.StartWrite(eLobbyPT_Pong, false);
1960 pongPacket.WriteUINT64(time);
1962 if (Send(&pongPacket, pConnection->addr, connectionID, NULL) != eSE_Ok)
1964 SECURE_NET_LOG("[Lobby] Failed to send setting connection " PRFORMAT_LCINFO " to eCLCS_NotConnected", PRARG_LCINFO(connectionID, pConnection->addr));
1965 pConnection->state = eCLCS_NotConnected;
1969 break;
1971 case eLobbyPT_Pong:
1972 if (pConnection)
1974 CTimeValue recvTime = pPacket->GetRecvTime();
1975 uint64 sendTime = pPacket->ReadUINT64();
1976 uint64 pingTime = recvTime.GetMilliSecondsAsInt64() - sendTime;
1977 if (pingTime > CRYLOBBY_INVALID_PING)
1979 pingTime = CRYLOBBY_INVALID_PING;
1982 UpdateConnectionPing(connectionID, (CryPing)pingTime);
1985 break;
1987 case eLobbyPT_InvalidPackeType:
1988 if (pConnection)
1990 pConnection->state = eCLCS_NotConnected;
1993 break;
1995 default:
1996 if (m_services[m_service])
1998 // Give packet to the current service
1999 m_services[m_service]->OnPacket(addr, pPacket);
2002 break;
2004 #endif // USE_LOBBY_REMOTE_CONNECTIONS
2007 void CCryLobby::OnPacket(const TNetAddress& addr, const uint8* pData, uint32 length)
2009 #if USE_LOBBY_REMOTE_CONNECTIONS
2010 CryLobbyConnectionID connectionID = FindConnection(addr);
2011 SConnection* pConnection = (connectionID != CryLobbyInvalidConnectionID) ? &m_connection[connectionID] : NULL;
2013 if (pData[0] == GetLobbyPacketID())
2015 m_cachedPacketBuffer.WritePacket(addr, pData, length);
2018 if (pConnection)
2020 pConnection->timeSinceRecv = 0;
2022 #endif // USE_LOBBY_REMOTE_CONNECTIONS
2025 void CCryLobby::ProcessCachedPacketBuffer(void)
2027 #if USE_LOBBY_REMOTE_CONNECTIONS
2028 while (m_cachedPacketBuffer.PacketsAvailable())
2030 CTimeValue recvTime;
2031 TNetAddress addr;
2032 const uint8* pData;
2033 uint32 length;
2034 m_cachedPacketBuffer.ReadPacket(recvTime, addr, pData, length);
2036 CryLobbyConnectionID connectionID = FindConnection(addr);
2037 SConnection* pConnection = (connectionID != CryLobbyInvalidConnectionID) ? &m_connection[connectionID] : NULL;
2039 const uint8* pDecodedData;
2040 CCrySharedLobbyPacket packet;
2041 SCryLobbyPacketHeader* pPacketHeader = packet.GetLobbyPacketHeader();
2042 SCryLobbyPacketDataHeader* pDataHeader = packet.GetLobbyPacketDataHeader();
2043 bool processPacket = true;
2045 pDecodedData = DecryptPacket(pData, length);
2047 packet.SetReadBuffer(pDecodedData, length);
2048 packet.SetReadBufferPos(0);
2049 packet.ReadPacketHeader();
2050 pPacketHeader->recvTime = recvTime;
2052 if (packet.GetReliable())
2054 if (pConnection && ((pConnection->state == eCLCS_Pending) || (pConnection->state == eCLCS_Connected)))
2056 SECURE_NET_LOG("[lobby] OnPacket reliable connection " PRFORMAT_LCINFO " size %u", PRARG_LCINFO(connectionID, pConnection->addr), length);
2058 if (((uint8)(pConnection->counterIn - pPacketHeader->counterOut)) == CONNECTION_COUNTER_MAX)
2060 // This is a new packet
2061 NetLog("[lobby] New packet counter %d", pPacketHeader->counterOut);
2063 pConnection->counterIn = pPacketHeader->counterOut;
2065 if (!pConnection->dataQueue.Empty())
2067 SConnection::SData& qdata = pConnection->dataQueue.Front();
2069 if (pPacketHeader->counterIn == qdata.counter)
2071 #if !defined(NO_NETWORK_SECURITY_LOGS)
2072 const uint8 qDataCounter = qdata.counter;
2073 #endif
2074 // Other end has received the packet we are trying to send
2075 OnSendComplete(addr);
2076 SECURE_NET_LOG("[lobby] Got ack(first) on connection " PRFORMAT_LCINFO " counterIn=%u, qDataCounter=%u", PRARG_LCINFO(connectionID, pConnection->addr), pPacketHeader->counterIn, qDataCounter);
2080 else
2082 processPacket = false;
2083 NetLog("[lobby] Repeat packet counter %d", pPacketHeader->counterOut);
2086 const uint32 MaxBufferSize = CryLobbyPacketUnReliableHeaderSize + CryLobbyPacketUINT8Size;
2087 uint8 buffer[MaxBufferSize];
2088 CCryLobbyPacket ackPacket;
2090 ackPacket.SetWriteBuffer(buffer, MaxBufferSize);
2091 ackPacket.StartWrite(eLobbyPT_Ack, false);
2092 ackPacket.WriteUINT8(pPacketHeader->counterOut);
2094 Send(&ackPacket, addr, connectionID, NULL);
2096 NetLog("[lobby] Send ack (counter=%u)", pPacketHeader->counterOut);
2098 else
2100 NetLog("[lobby] OnPacket reliable packet for non connected connection " PRFORMAT_LCINFO " size %u ignoring", PRARG_LCINFO(connectionID, addr), length);
2102 processPacket = false;
2104 // We don't have a valid connection for this reliable packet.
2105 // This will most likely happen if we have disconnected but the other end doesn't know and is trying to disconnect from us.
2106 // If this is one of the packet types that is kept and still sent after a disconnect send back an ack to stop the other end sending.
2107 uint32 dataPos = 0;
2108 bool sendAck = false;
2110 while (GetNextPacketFromBuffer(pDecodedData, length, dataPos, &packet))
2112 #if !defined(EXCLUDE_NORMAL_LOG)
2113 uint32 encodedPacketType = pDataHeader->lobbyPacketType;
2114 #endif
2115 DecodePacketDataHeader(&packet);
2117 if (KeepPacketAfterDisconnect(pDataHeader->lobbyPacketType))
2119 sendAck = true;
2120 NetLog(" Ignoring packet %u (%u) size %u Still needs ack", pDataHeader->lobbyPacketType, encodedPacketType, pDataHeader->dataSize);
2122 else
2124 NetLog(" Ignoring packet %u (%u) size %u Doesn't need ack", pDataHeader->lobbyPacketType, encodedPacketType, pDataHeader->dataSize);
2128 if (sendAck)
2130 const uint32 MaxBufferSize = CryLobbyPacketUnReliableHeaderSize + CryLobbyPacketUINT8Size;
2131 uint8 buffer[MaxBufferSize];
2132 CCryLobbyPacket ackPacket;
2134 ackPacket.SetWriteBuffer(buffer, MaxBufferSize);
2135 ackPacket.StartWrite(eLobbyPT_Ack, false);
2136 ackPacket.WriteUINT8(pPacketHeader->counterOut);
2138 Send(&ackPacket, addr, connectionID, NULL);
2140 NetLog("[lobby] Send ack for non connected connection (counter=%u)", pPacketHeader->counterOut);
2145 if (processPacket)
2147 if (packet.GetReliable())
2149 uint32 dataPos = 0;
2151 while (GetNextPacketFromBuffer(pDecodedData, length, dataPos, &packet))
2153 #if !defined(EXCLUDE_NORMAL_LOG)
2154 uint32 encodedPacketType = pDataHeader->lobbyPacketType;
2155 #endif
2156 DecodePacketDataHeader(&packet);
2157 NetLog(" Process packet %d (%d) size %d", pDataHeader->lobbyPacketType, encodedPacketType, pDataHeader->dataSize);
2158 ProcessPacket(addr, connectionID, &packet);
2161 else
2163 packet.ReadDataHeader();
2164 DecodePacketDataHeader(&packet);
2165 ProcessPacket(addr, connectionID, &packet);
2170 m_cachedPacketBuffer.Reset();
2171 #endif // USE_LOBBY_REMOTE_CONNECTIONS
2174 void CCryLobby::OnError(const TNetAddress& addr, ESocketError error)
2176 #if USE_LOBBY_REMOTE_CONNECTIONS
2177 CryLobbyConnectionID c;
2178 CryLobbySendID sendID = CryLobbyInvalidSendID;
2180 if (ConnectionFromAddress(&c, addr))
2182 SConnection* connection = &m_connection[c];
2184 while (!connection->dataQueue.Empty())
2186 SConnection::SData& data = connection->dataQueue.Front();
2188 sendID = CryLobbyCreateSendID(c, data.counter);
2190 MemFree(data.data);
2192 if (m_services[m_service])
2194 m_services[m_service]->OnError(addr, error, sendID);
2197 SECURE_NET_LOG("[lobby] Socket error %d on connection " PRFORMAT_LCINFO " free send data counter %u", error, PRARG_LCINFO(c, connection->addr), data.counter);
2199 connection->dataQueue.Pop();
2202 connection->state = eCLCS_NotConnected;
2204 else
2206 if (m_services[m_service])
2208 m_services[m_service]->OnError(addr, error, sendID);
2211 #endif // USE_LOBBY_REMOTE_CONNECTIONS
2214 void CCryLobby::OnSendComplete(const TNetAddress& addr)
2216 #if USE_LOBBY_REMOTE_CONNECTIONS
2217 CryLobbyConnectionID c;
2218 CryLobbySendID sendID = CryLobbyInvalidSendID;
2220 if (ConnectionFromAddress(&c, addr))
2222 SConnection* connection = &m_connection[c];
2224 if (!connection->dataQueue.Empty())
2226 SConnection::SData& data = connection->dataQueue.Front();
2228 sendID = CryLobbyCreateSendID(c, data.counter);
2230 SECURE_NET_LOG("[lobby] Send complete on connection " PRFORMAT_LCINFO " free send data counter %d", PRARG_LCINFO(c, connection->addr), data.counter);
2231 LogPacketsInBuffer((uint8*)MemGetPtr(data.data), data.dataSize);
2233 MemFree(data.data);
2235 connection->dataQueue.Pop();
2239 if (m_services[m_service])
2241 m_services[m_service]->OnSendComplete(addr, sendID);
2243 #endif // USE_LOBBY_REMOTE_CONNECTIONS
2246 #if NETWORK_HOST_MIGRATION
2247 uint8 CCryLobby::GetActiveConnections(void)
2249 uint8 count = 0;
2251 for (uint32 index = 0; index < MAX_LOBBY_CONNECTIONS; ++index)
2253 if (m_connection[index].used && (m_connection[index].state == eCLCS_Connected))
2255 ++count;
2259 return count;
2261 #endif
2263 void CCryLobby::RegisterEventInterest(ECryLobbySystemEvent eventOfInterest, CryLobbyEventCallback cb, void* pUserData)
2265 SEventCBData newEvent;
2267 newEvent.cb = cb;
2268 newEvent.pUserData = pUserData;
2269 newEvent.event = eventOfInterest;
2271 m_callbacks.push_back(newEvent);
2274 void CCryLobby::UnregisterEventInterest(ECryLobbySystemEvent eventOfInterest, CryLobbyEventCallback cb, void* pUserData)
2276 SEventCBData newEvent;
2278 newEvent.cb = cb;
2279 newEvent.pUserData = pUserData;
2280 newEvent.event = eventOfInterest;
2282 stl::find_and_erase(m_callbacks, newEvent);
2285 void CCryLobby::DispatchEvent(ECryLobbySystemEvent evnt, UCryLobbyEventData data)
2287 EventCBList::iterator callbackItem;
2289 for (callbackItem = m_callbacks.begin(); callbackItem != m_callbacks.end(); ++callbackItem)
2291 if (callbackItem->event == evnt)
2293 callbackItem->cb(data, callbackItem->pUserData);
2298 void CCryLobby::GetConfigurationInformation(SConfigurationParams* infos, uint32 infoCnt)
2300 if (m_configCB)
2302 m_configCB(GetLobbyServiceType(), infos, infoCnt);
2306 ICryTCPServicePtr CCryLobbyService::GetTCPService(const char* pService)
2308 #if USE_CRY_TCPSERVICE
2309 if (m_pTCPServiceFactory)
2311 return m_pTCPServiceFactory->GetTCPService(pService);
2313 #endif // USE_CRY_TCPSERVICE
2314 return NULL;
2317 ICryTCPServicePtr CCryLobbyService::GetTCPService(const char* pServer, uint16 port, const char* pUrlPrefix)
2319 #if USE_CRY_TCPSERVICE
2320 if (m_pTCPServiceFactory)
2322 return m_pTCPServiceFactory->GetTCPService(pServer, port, pUrlPrefix);
2324 #endif // USE_CRY_TCPSERVICE
2325 return NULL;
2328 bool CCryLobbyService::GetFlag(ECryLobbyServiceFlag flag)
2330 return (m_lobbyServiceFlags & flag) == flag;
2333 // Description:
2334 // Is the given flag true for the lobby service of the given type?
2335 // Arguments:
2336 // service - lobby service to be queried
2337 // flag - flag to be queried
2338 // Return:
2339 // True if the flag is true.
2340 bool CCryLobby::GetLobbyServiceFlag(ECryLobbyService service, ECryLobbyServiceFlag flag)
2342 bool result = false;
2344 if (m_services[service])
2346 result = m_services[service]->GetFlag(flag);
2349 return result;
2352 CCryLobbyService::CCryLobbyService(CCryLobby* pLobby, ECryLobbyService service)
2353 : m_pLobby(pLobby)
2354 , m_service(service)
2355 #if USE_CRY_TCPSERVICE
2356 , m_pTCPServiceFactory(NULL)
2357 #endif // USE_CRY_TCPSERVICE
2359 m_lobbyServiceFlags = eCLSF_AllowMultipleSessions | eCLSF_SupportHostMigration;
2360 ZeroMemory(&m_tasks, sizeof(m_tasks));
2363 CCryLobbyService::~CCryLobbyService()
2368 ECryLobbyError CCryLobbyService::Initialise(ECryLobbyServiceFeatures features, CryLobbyServiceCallback pCB)
2370 if (features & eCLSO_Base)
2372 LOBBY_AUTO_LOCK;
2374 for (uint32 i = 0; i < MAX_LOBBY_TASKS; i++)
2376 m_tasks[i].used = false;
2380 return eCLE_Success;
2383 ECryLobbyError CCryLobbyService::Terminate(ECryLobbyServiceFeatures features, CryLobbyServiceCallback pCB)
2385 if (features & eCLSO_Base)
2387 LOBBY_AUTO_LOCK;
2389 FROM_GAME_TO_LOBBY(&CCryLobbyService::FreeSocketNT, this);
2392 return eCLE_Success;
2395 void CCryLobbyService::CreateSocketNT(void)
2397 m_pLobby->InternalSocketCreate(m_service);
2400 void CCryLobbyService::FreeSocketNT(void)
2402 m_pLobby->InternalSocketFree(m_service);
2405 ECryLobbyError CCryLobbyService::StartTask(uint32 eTask, uint32 user, bool startRunning, CryLobbyServiceTaskID* pLSTaskID, CryLobbyTaskID* pLTaskID, void* pCb, void* pCbArg)
2407 CryLobbyTaskID lobbyTaskID = m_pLobby->CreateTask();
2409 if (lobbyTaskID != CryLobbyInvalidTaskID)
2411 for (uint32 i = 0; i < MAX_LOBBY_TASKS; i++)
2413 STask* pTask = GetTask(i);
2415 if (!pTask->used)
2417 pTask->user = user;
2418 pTask->lTaskID = lobbyTaskID;
2419 pTask->error = eCLE_Success;
2420 pTask->startedTask = eTask;
2421 pTask->pCB = pCb;
2422 pTask->pCBArg = pCbArg;
2423 pTask->used = true;
2424 pTask->running = startRunning;
2426 if (pLSTaskID)
2428 *pLSTaskID = i;
2431 if (pLTaskID)
2433 *pLTaskID = lobbyTaskID;
2436 for (uint32 j = 0; j < MAX_LOBBY_TASK_DATAS; j++)
2438 pTask->dataMem[j] = TMemInvalidHdl;
2439 pTask->dataNum[j] = 0;
2442 return eCLE_Success;
2446 m_pLobby->ReleaseTask(lobbyTaskID);
2449 return eCLE_TooManyTasks;
2452 void CCryLobbyService::FreeTask(CryLobbyServiceTaskID lsTaskID)
2454 STask* pTask = GetTask(lsTaskID);
2456 m_pLobby->ReleaseTask(pTask->lTaskID);
2458 for (uint32 i = 0; i < MAX_LOBBY_TASK_DATAS; i++)
2460 if (pTask->dataMem[i] != TMemInvalidHdl)
2462 m_pLobby->MemFree(pTask->dataMem[i]);
2463 pTask->dataMem[i] = TMemInvalidHdl;
2467 pTask->used = false;
2470 void CCryLobbyService::CancelTask(CryLobbyTaskID lTaskID)
2472 LOBBY_AUTO_LOCK;
2474 CryLogAlways("[Lobby]Try cancel task %u", lTaskID);
2476 if (lTaskID != CryLobbyInvalidTaskID)
2478 for (uint32 i = 0; i < MAX_LOBBY_TASKS; i++)
2480 STask* pTask = GetTask(i);
2482 CRY_ASSERT_MESSAGE(pTask, "CCryLobby: Task base pointers not setup");
2484 if (pTask->used && (pTask->lTaskID == lTaskID))
2486 CryLogAlways("[Lobby] Task %u canceled", lTaskID);
2487 pTask->pCB = NULL;
2488 break;
2494 void CCryLobbyService::UpdateTaskError(CryLobbyServiceTaskID lsTaskID, ECryLobbyError error)
2496 STask* pTask = GetTask(lsTaskID);
2498 if (pTask->error == eCLE_Success)
2500 pTask->error = error;
2504 void CCryLobbyService::StartTaskRunning(CryLobbyServiceTaskID lsTaskID)
2506 LOBBY_AUTO_LOCK;
2508 STask* pTask = GetTask(lsTaskID);
2510 if (pTask->used)
2512 pTask->running = true;
2514 switch (pTask->startedTask)
2516 case eT_GetUserPrivileges:
2517 StopTaskRunning(lsTaskID);
2518 break;
2523 void CCryLobbyService::StopTaskRunning(CryLobbyServiceTaskID lsTaskID)
2525 STask* pTask = GetTask(lsTaskID);
2527 if (pTask->used)
2529 pTask->running = false;
2531 TO_GAME_FROM_LOBBY(&CCryLobbyService::EndTask, this, lsTaskID);
2535 void CCryLobbyService::EndTask(CryLobbyServiceTaskID lsTaskID)
2537 LOBBY_AUTO_LOCK;
2539 STask* pTask = GetTask(lsTaskID);
2541 if (pTask->used)
2543 if (pTask->pCB)
2545 switch (pTask->startedTask)
2547 case eT_GetUserPrivileges:
2548 if (!m_pLobby->GetInternalSocket(m_service))
2550 UpdateTaskError(lsTaskID, eCLE_InternalError);
2553 ((CryLobbyPrivilegeCallback)pTask->pCB)(pTask->lTaskID, pTask->error, 0, pTask->pCBArg);
2554 break;
2558 if (pTask->error != eCLE_Success)
2560 NetLog("[Lobby] Lobby Service EndTask %u Result %d", pTask->startedTask, pTask->error);
2563 FreeTask(lsTaskID);
2567 ECryLobbyError CCryLobbyService::GetUserPrivileges(uint32 user, CryLobbyTaskID* pTaskID, CryLobbyPrivilegeCallback pCB, void* pCBArg)
2569 ECryLobbyError error;
2570 CryLobbyServiceTaskID tid;
2572 LOBBY_AUTO_LOCK;
2574 error = StartTask(eT_GetUserPrivileges, user, false, &tid, pTaskID, (void*)pCB, pCBArg);
2576 if (error == eCLE_Success)
2578 FROM_GAME_TO_LOBBY(&CCryLobbyService::StartTaskRunning, this, tid);
2581 return error;
2584 void CCryLobbyService::GetSocketPorts(uint16& connectPort, uint16& listenPort)
2586 listenPort = CLobbyCVars::Get().lobbyDefaultPort;
2587 connectPort = CLobbyCVars::Get().lobbyDefaultPort;
2590 void CCryLobbyService::MakeAddrPCCompatible(TNetAddress& addr)
2594 void CCryLobby::MakeAddrPCCompatible(TNetAddress& addr)
2596 m_services[m_service]->MakeAddrPCCompatible(addr);
2599 void CCryLobby::MakeConnectionPCCompatible(CryLobbyConnectionID connectionID)
2601 if (connectionID != CryLobbyInvalidConnectionID)
2603 m_services[m_service]->MakeAddrPCCompatible(m_connection[connectionID].addr);
2607 CCryLobby::SSocketService* CCryLobby::GetCorrectSocketServiceForAddr(const TNetAddress& addr)
2609 return &m_socketServices[GetCorrectSocketServiceTypeForAddr(addr)];
2612 ECryLobbyService CCryLobby::GetCorrectSocketServiceTypeForAddr(const TNetAddress& addr)
2614 const SIPv4Addr* pIPv4Addr = stl::get_if<SIPv4Addr>(&addr);
2616 if (pIPv4Addr && (pIPv4Addr->lobbyService != eCLS_NumServices))
2618 return ECryLobbyService(pIPv4Addr->lobbyService);
2621 return m_service;
2624 CCryLobby::SSocketService* CCryLobby::GetCorrectSocketService(ECryLobbyService serviceType)
2626 //Note that there will always be a 2 sockets no matter which services are initialised
2627 return &m_socketServices[serviceType];
2630 uint16 CCryLobby::GetInternalSocketPort(ECryLobbyService service)
2632 SSocketService* pSocketService = GetCorrectSocketService(service);
2634 return pSocketService->m_socketListenPort;
2637 IDatagramSocketPtr CCryLobby::GetInternalSocket(ECryLobbyService service)
2639 SSocketService* pSocketService = GetCorrectSocketService(service);
2641 return pSocketService->m_socket;
2644 const SCryLobbyParameters& CCryLobby::GetLobbyParameters() const
2646 return m_serviceParams[m_service];
2649 uint32 CCryLobby::TimeSincePacketInMS(CryLobbyConnectionID c) const
2651 #if USE_LOBBY_REMOTE_CONNECTIONS
2652 if (c != CryLobbyInvalidConnectionID)
2654 if (m_connection[c].used)
2656 return m_connection[c].timeSinceRecv;
2659 #endif // USE_LOBBY_REMOTE_CONNECTIONS
2661 return 0;
2664 void CCryLobby::ForceTimeoutConnection(CryLobbyConnectionID c)
2666 #if USE_LOBBY_REMOTE_CONNECTIONS
2667 if (c != CryLobbyInvalidConnectionID)
2669 if (m_connection[c].used)
2671 m_connection[c].timeSinceRecv = LOBBY_FORCE_DISCONNECT_TIMER;
2674 #endif // USE_LOBBY_REMOTE_CONNECTIONS
2677 const TNetAddress* CCryLobby::GetNetAddress(CryLobbyConnectionID c) const
2679 const TNetAddress* pAddress = NULL;
2681 if ((c != CryLobbyInvalidConnectionID) && (c < MAX_LOBBY_CONNECTIONS))
2683 if (m_connection[c].used)
2685 pAddress = &(m_connection[c].addr);
2689 return pAddress;
2692 ECryLobbyError CCryLobbyService::CreateTaskParamMem(CryLobbyServiceTaskID lsTaskID, uint32 param, const void* pParamData, size_t paramDataSize)
2694 STask* pTask = &m_tasks[lsTaskID];
2696 CRY_ASSERT_MESSAGE(pTask, "CCryLobbyService: Task base pointers not setup");
2698 if (paramDataSize > 0)
2700 pTask->dataMem[param] = m_pLobby->MemAlloc(paramDataSize);
2701 void* p = m_pLobby->MemGetPtr(pTask->dataMem[param]);
2703 if (p)
2705 if (pParamData)
2707 memcpy(p, pParamData, paramDataSize);
2710 else
2712 return eCLE_OutOfMemory;
2716 return eCLE_Success;
2719 const uint8* CCryLobby::EncryptPacket(const uint8* buffer, uint32 length)
2721 #if ENCRYPT_LOBBY_PACKETS
2722 if (gEnv->pNetwork)
2724 m_tempEncryptionBuffer[0] = buffer[0];
2726 gEnv->pNetwork->EncryptBuffer(m_cipher, m_tempEncryptionBuffer + 1, buffer + 1, length - 1);
2728 return m_tempEncryptionBuffer;
2730 else
2731 #endif
2733 return buffer;
2737 const uint8* CCryLobby::DecryptPacket(const uint8* buffer, uint32 length)
2739 #if ENCRYPT_LOBBY_PACKETS
2740 if (gEnv->pNetwork)
2742 m_tempDecryptionBuffer[0] = buffer[0];
2744 gEnv->pNetwork->DecryptBuffer(m_cipher, m_tempDecryptionBuffer + 1, buffer + 1, length - 1);
2746 return m_tempDecryptionBuffer;
2748 else
2749 #endif
2751 return buffer;
2755 bool CCryLobby::DecodeAddress(const TNetAddress& address, uint32* pIP, uint16* pPort)
2757 bool decoded = true;
2759 const SIPv4Addr* pIPv4Addr = stl::get_if<SIPv4Addr>(&address);
2760 if (pIPv4Addr != NULL)
2762 *pIP = pIPv4Addr->addr;
2763 *pPort = pIPv4Addr->port;
2765 else
2767 const TLocalNetAddress* pLocalAddr = stl::get_if<TLocalNetAddress>(&address);
2768 if (pLocalAddr != NULL)
2770 *pIP = LOOPBACK_ADDRESS;
2771 *pPort = *pLocalAddr;
2773 else
2775 *pIP = *pPort = 0;
2776 decoded = false;
2780 return decoded;
2783 void CCryLobby::DecodeAddress(uint32 ip, uint16 port, char* ipstring, bool ignorePort)
2785 if (ignorePort)
2787 sprintf(ipstring, "%u.%u.%u.%u", ((ip >> 24) & 0xff), ((ip >> 16) & 0xff), ((ip >> 8) & 0xff), (ip & 0xff));
2789 else
2791 sprintf(ipstring, "%u.%u.%u.%u:%u", ((ip >> 24) & 0xff), ((ip >> 16) & 0xff), ((ip >> 8) & 0xff), (ip & 0xff), port);
2795 void CCryLobby::DecodeAddress(const TNetAddress& address, char* ipstring, bool ignorePort)
2797 uint32 ip;
2798 uint16 port;
2800 if (DecodeAddress(address, &ip, &port))
2802 DecodeAddress(ip, port, ipstring, ignorePort);
2804 else
2806 sprintf(ipstring, "<UNKNOWN>");
2810 bool CCryLobby::ConvertAddr(const TNetAddress& addrIn, CRYSOCKADDR_IN* pSockAddr)
2812 if (gEnv->pNetwork)
2814 return ((INetworkPrivate*)gEnv->pNetwork)->ConvertAddr(addrIn, pSockAddr);
2817 return false;
2820 bool CCryLobby::ConvertAddr(const TNetAddress& addrIn, CRYSOCKADDR* pSockAddr, int* addrLen)
2822 if (gEnv->pNetwork)
2824 return ((INetworkPrivate*)gEnv->pNetwork)->ConvertAddr(addrIn, pSockAddr, addrLen);
2827 return false;
2830 ISocketIOManager* CCryLobby::GetExternalSocketIOManager()
2832 if (gEnv->pNetwork)
2834 return &((INetworkPrivate*)gEnv->pNetwork)->GetExternalSocketIOManager();
2837 return NULL;
2840 ISocketIOManager* CCryLobby::GetInternalSocketIOManager()
2842 if (gEnv->pNetwork)
2844 return &((INetworkPrivate*)gEnv->pNetwork)->GetInternalSocketIOManager();
2847 return NULL;
2850 CNetAddressResolver* CCryLobby::GetResolver()
2852 if (gEnv->pNetwork)
2854 return ((INetworkPrivate*)gEnv->pNetwork)->GetResolver();
2857 return NULL;
2860 const CNetCVars* CCryLobby::GetNetCVars()
2862 if (gEnv->pNetwork)
2864 return &((INetworkPrivate*)gEnv->pNetwork)->GetCVars();
2867 return NULL;
2870 uint8 CCryLobby::GetLobbyPacketID()
2872 if (gEnv->pNetwork)
2874 return ((INetworkPrivate*)gEnv->pNetwork)->FrameIDToHeader(eH_CryLobby);
2877 return 0;
2880 #if NETWORK_HOST_MIGRATION
2881 THostMigrationEventListenerContainer* CCryLobby::GetHostMigrationListeners()
2883 return &m_hostMigrationListeners;
2885 #endif
2887 void CCryLobby::AddHostMigrationEventListener(IHostMigrationEventListener* pListener, const char* pWho, uint32 priority)
2889 #if NETWORK_HOST_MIGRATION
2890 for (THostMigrationEventListenerContainer::iterator it = m_hostMigrationListeners.begin(); it != m_hostMigrationListeners.end(); ++it)
2892 if (it->second.m_pListener == pListener)
2894 // The listener is already registered
2895 return;
2899 SHostMigrationEventListenerInfo info(pListener, pWho);
2900 m_hostMigrationListeners.insert(std::pair<EListenerPriorityType, SHostMigrationEventListenerInfo>((EListenerPriorityType)priority, info));
2901 #endif
2904 void CCryLobby::RemoveHostMigrationEventListener(IHostMigrationEventListener* pListener)
2906 #if NETWORK_HOST_MIGRATION
2907 for (THostMigrationEventListenerContainer::iterator it = m_hostMigrationListeners.begin(); it != m_hostMigrationListeners.end(); ++it)
2909 if (it->second.m_pListener == pListener)
2911 m_hostMigrationListeners.erase(it);
2912 return;
2915 #endif
2918 CCryLobby::CMemAllocator::CMemAllocator()
2920 #ifdef USE_GLOBAL_BUCKET_ALLOCATOR
2921 m_bucketAllocator.EnableExpandCleanups(false);
2922 #endif
2923 m_pGeneralHeap = CryGetIMemoryManager()->CreateGeneralExpandingMemoryHeap(LOBBY_GENERAL_HEAP_SIZE, LOBBY_GENERAL_HEAP_SIZE, "CryLobby General");
2924 m_totalBucketAllocated = 0;
2925 m_totalGeneralHeapAllocated = 0;
2926 m_MaxBucketAllocated = 0;
2927 m_MaxGeneralHeapAllocated = 0;
2930 CCryLobby::CMemAllocator::~CMemAllocator()
2932 PrintStats();
2934 if (m_pGeneralHeap)
2936 m_pGeneralHeap->Release();
2940 TMemHdl CCryLobby::CMemAllocator::MemAlloc(size_t sz)
2942 void* p = NULL;
2944 if (sz <= m_bucketAllocator.MaxSize)
2946 p = m_bucketAllocator.allocate(sz);
2948 if (p == NULL)
2950 CryFatalError("Lobby Allocation For %" PRISIZE_T " Failed - Suggest increasing the bucket allocator size!!!!", sz);
2953 m_totalBucketAllocated += m_bucketAllocator.getSize(p);
2955 if (m_totalBucketAllocated > m_MaxBucketAllocated)
2957 m_MaxBucketAllocated = m_totalBucketAllocated;
2960 else
2962 p = m_pGeneralHeap->Malloc(sz, "Lobby");
2964 if (p == NULL)
2966 CryFatalError("Lobby Allocation For %" PRISIZE_T " Failed - Suggest increasing the general heap size!!!!", sz);
2969 m_totalGeneralHeapAllocated += m_pGeneralHeap->UsableSize(p);
2971 if (m_totalGeneralHeapAllocated > m_MaxGeneralHeapAllocated)
2973 m_MaxGeneralHeapAllocated = m_totalGeneralHeapAllocated;
2977 return p;
2980 void CCryLobby::CMemAllocator::MemFree(TMemHdl h)
2982 void* p = MemGetPtr(h);
2984 if (m_bucketAllocator.IsInAddressRange(p))
2986 m_totalBucketAllocated -= m_bucketAllocator.getSize(p);
2987 m_bucketAllocator.deallocate(p);
2989 else
2991 m_totalGeneralHeapAllocated -= m_pGeneralHeap->UsableSize(p);
2992 m_pGeneralHeap->Free(p);
2996 void* CCryLobby::CMemAllocator::MemGetPtr(TMemHdl h)
2998 return h;
3001 TMemHdl CCryLobby::CMemAllocator::MemGetHdl(void* ptr)
3003 return ptr;
3006 void CCryLobby::CMemAllocator::PrintStats()
3008 NetLog("CryLobby Memory Stats");
3009 NetLog("Current Bucket Allocated %" PRISIZE_T " Maximum Bucket Allocated %" PRISIZE_T, m_totalBucketAllocated, m_MaxBucketAllocated);
3010 NetLog("Current General Heap Allocated %" PRISIZE_T " Maximum General Heap Allocated %" PRISIZE_T, m_totalGeneralHeapAllocated, m_MaxGeneralHeapAllocated);