From 0167391b301d64ba20b5e27950c239d14b9a3706 Mon Sep 17 00:00:00 2001 From: kaetemi Date: Tue, 21 Feb 2023 23:53:40 +0800 Subject: [PATCH] Implement QUIC receive and send for server, draft, ref ryzom/ryzomcore#628 --- nel/include/nel/misc/types_nl.h | 2 - .../src/frontend_service/client_host.cpp | 5 + .../server/src/frontend_service/client_host.h | 17 ++- .../src/frontend_service/fe_receive_sub.cpp | 37 ++++-- .../src/frontend_service/fe_receive_sub.h | 2 +- .../src/frontend_service/fe_receive_task.cpp | 2 +- .../src/frontend_service/fe_receive_task.h | 6 +- .../src/frontend_service/fe_send_sub.cpp | 11 +- .../server/src/frontend_service/fe_send_sub.h | 12 +- .../src/frontend_service/quic_transceiver.cpp | 69 ++++++----- .../src/frontend_service/quic_transceiver.h | 117 ++++++++++++++++-- 11 files changed, 215 insertions(+), 65 deletions(-) diff --git a/nel/include/nel/misc/types_nl.h b/nel/include/nel/misc/types_nl.h index 6e0dfec890..850654b2ba 100644 --- a/nel/include/nel/misc/types_nl.h +++ b/nel/include/nel/misc/types_nl.h @@ -189,8 +189,6 @@ # define NL_CPP11 #endif -#define null nullptr - #ifdef NL_CPP14 #define NL_ALIGNLIKE(type) alignas(alignof(type)) #else diff --git a/ryzom/server/src/frontend_service/client_host.cpp b/ryzom/server/src/frontend_service/client_host.cpp index 053cfe2b79..0f815f0927 100644 --- a/ryzom/server/src/frontend_service/client_host.cpp +++ b/ryzom/server/src/frontend_service/client_host.cpp @@ -436,6 +436,11 @@ CClientHost::~CClientHost() { //REMOVE_PROPERTY_FROM_EMITER( _Id, uint16, "AvailImpulseBitsize" ); //_Id = CEntityId::Unknown; + + if (QuicUser.get() && QuicUser->ClientHost == this) + { + QuicUser->ClientHost = nullptr; + } } diff --git a/ryzom/server/src/frontend_service/client_host.h b/ryzom/server/src/frontend_service/client_host.h index 1105131f8d..038e183065 100644 --- a/ryzom/server/src/frontend_service/client_host.h +++ b/ryzom/server/src/frontend_service/client_host.h @@ -34,11 +34,11 @@ #include "game_share/ryzom_entity_id.h" #include "game_share/entity_types.h" #include "game_share/welcome_service_itf.h" +#include "quic_transceiver.h" #include #include - const uint32 FirstClientId = 1; const uint16 InvalidClientId = 0xFFFF; @@ -49,7 +49,6 @@ namespace NLNET struct TPairState; - /** * CClientIdPool */ @@ -108,7 +107,7 @@ class CClientHost { public: /// Constructor - CClientHost( const NLNET::CInetAddress& addr, TClientId id ) : + CClientHost( const NLNET::CInetAddress& addr, CQuicUserContext *quicUser, TClientId id ) : Uid (0xFFFFFFFF), InstanceId(0xFFFFFFFF), StartupRole(WS::TUserRole::ur_player), @@ -145,12 +144,17 @@ class CClientHost // //AvailableImpulseBitsize( "AvailImpulseBitsize", MaxImpulseBitSizes[2] ), NbActionsSentAtCycle(0), - QuitId(0) + QuitId(0), + QuicUser(quicUser) { IdTranslator.setId( id ); ImpulseEncoder.setClientHost( this ); ConnectionState = Synchronize; initClientBandwidth(); + if (quicUser) + { + quicUser->ClientHost = this; + } } /// Destructor @@ -495,6 +499,8 @@ class CClientHost /// Quit Id uint32 QuitId; + CQuicUserContextPtr QuicUser; + private: /// Client IP and port @@ -591,7 +597,7 @@ class CLimboClient { public: CLimboClient( CClientHost* client ) : - AddrFrom(client->address()), Uid(client->Uid), UserName(client->UserName), UserPriv(client->UserPriv), UserExtended(client->UserExtended), + AddrFrom(client->address()), QuicUser(client->QuicUser), Uid(client->Uid), UserName(client->UserName), UserPriv(client->UserPriv), UserExtended(client->UserExtended), LanguageId(client->LanguageId), QuitId(client->QuitId) { // Set limbo timeout start @@ -600,6 +606,7 @@ class CLimboClient } NLNET::CInetAddress AddrFrom; + CQuicUserContextPtr QuicUser; TUid Uid; std::string UserName, UserPriv, UserExtended, LanguageId; uint32 QuitId; diff --git a/ryzom/server/src/frontend_service/fe_receive_sub.cpp b/ryzom/server/src/frontend_service/fe_receive_sub.cpp index 4dee96f6b1..11d3586331 100644 --- a/ryzom/server/src/frontend_service/fe_receive_sub.cpp +++ b/ryzom/server/src/frontend_service/fe_receive_sub.cpp @@ -133,13 +133,14 @@ void CFeReceiveSub::init( uint16 firstAcceptableFrontendPort, uint16 lastAccepta _ReceiveThread = IThread::create(_ReceiveTask); nlassert(_ReceiveThread != NULL); _ReceiveThread->start(); + uint16 udpPort = _ReceiveTask->DataSock->localAddr().port(); // Start QUIC transceiver nlinfo("FERECV: Starting QUIC transceiver"); - m_QuicTransceiver = new CQuicTransceiver(firstAcceptableFrontendPort - 5000, lastAcceptableFrontendPort - 5000, dgrammaxlength); + m_QuicTransceiver = new CQuicTransceiver(dgrammaxlength); m_CurrentQuicReadQueue = &m_Queues[3]; m_QuicTransceiver->swapWriteQueue(&m_Queues[2]); - m_QuicTransceiver->start(); + m_QuicTransceiver->start((udpPort ? udpPort : firstAcceptableFrontendPort) - 5000); // Setup current message placeholder _CurrentInMsg = new TReceivedMessage(); @@ -245,24 +246,31 @@ void CFeReceiveSub::readIncomingData() } // Read queue of messages received from clients - _CurrentInMsg->AddrFrom.setNull(); // FIXME: QUIC + _CurrentInMsg->AddrFrom.setNull(); while (!m_CurrentQuicReadQueue->empty()) { // nlinfo( "Read queue size = %u", _CurrentReadQueue->size() ); m_CurrentQuicReadQueue->front(_CurrentInMsg->data()); m_CurrentQuicReadQueue->pop(); nlassert(!m_CurrentQuicReadQueue->empty()); - m_CurrentQuicReadQueue->front(_CurrentInMsg->VAddrFrom); + uint8 *buffer; + uint32 size; + m_CurrentQuicReadQueue->front(buffer, size); + nlassert(size == sizeof(_CurrentInMsg->QuicUser)); + memcpy(&_CurrentInMsg->QuicUser, buffer, size); + CQuicUserContextRelease(_CurrentInMsg->QuicUser); // Decrease ref count after handling message m_CurrentQuicReadQueue->pop(); - // _CurrentInMsg->vectorToAddress(); // FIXME: QUIC + + // Use token address for user mapping, since it'll stay constant + _CurrentInMsg->AddrFrom = _CurrentInMsg->QuicUser->TokenAddr; #ifndef MEASURE_RECEIVE_TASK handleIncomingMsg(); #endif } - // _CurrentInMsg->AddrFrom.setNull(); // FIXME: QUIC // Read queue of messages received from clients + _CurrentInMsg->QuicUser = nullptr; while (!m_CurrentReadQueue->empty()) { // nlinfo( "Read queue size = %u", m_CurrentReadQueue->size() ); @@ -341,6 +349,13 @@ void CFeReceiveSub::handleIncomingMsg() #ifndef SIMUL_CLIENTS //nldebug( "FERECV: Handling incoming message" ); + + if (_CurrentInMsg->QuicUser) + { + // TODO: Bypass _ClientMap lookup + // _CurrentInMsg->QuicUser->ClientHost + // _CurrentInMsg->QuicUser->ClientHost->QuicUser + } // Retrieve client info or add one THostMap::iterator ihm = _ClientMap.find( _CurrentInMsg->AddrFrom ); @@ -404,7 +419,7 @@ bool CFeReceiveSub::acceptUserIdConnection( TUid userId ) /* * Add client */ -CClientHost *CFeReceiveSub::addClient( const NLNET::CInetAddress& addrfrom, TUid userId, const string &userName, const string &userPriv, const std::string & userExtended, const std::string & languageId, const NLNET::CLoginCookie &cookie, uint32 instanceId, uint8 authorizedCharSlot, bool sendCLConnect ) +CClientHost *CFeReceiveSub::addClient( const NLNET::CInetAddress& addrfrom, CQuicUserContext *quicUser, TUid userId, const string &userName, const string &userPriv, const std::string & userExtended, const std::string & languageId, const NLNET::CLoginCookie &cookie, uint32 instanceId, uint8 authorizedCharSlot, bool sendCLConnect ) { MEM_DELTA_MULTI_LAST2(Client,AddClient); if ( ! acceptUserIdConnection( userId ) ) @@ -430,7 +445,7 @@ CClientHost *CFeReceiveSub::addClient( const NLNET::CInetAddress& addrfrom, TUid THostMap::iterator cmPreviousEnd = _ClientMap.end(); { MEM_DELTA_MULTI2(CClientHost,New); - clienthost = new CClientHost( addrfrom, clientid ); + clienthost = new CClientHost( addrfrom, quicUser, clientid ); } nlassert( clienthost ); nlinfo( "Adding client %u (uid %u name %s priv '%s') at %s", clientid, userId, userName.c_str(), userPriv.c_str(), addrfrom.asIPString().c_str() ); @@ -462,7 +477,7 @@ CClientHost *CFeReceiveSub::addClient( const NLNET::CInetAddress& addrfrom, TUid clienthost->AuthorizedCharSlot = authorizedCharSlot; clienthost->initSendCycle( false ); - CFrontEndService::instance()->sendSub()->setSendBufferAddress( clientid, &addrfrom ); + CFrontEndService::instance()->sendSub()->setSendBufferAddress( clientid, &addrfrom, quicUser ); //This must be commented out when the GPMS always activates slot 0 //CFrontEndService::instance()->PrioSub.Prioritizer.addEntitySeenByClient( clientid, 0 ); @@ -572,7 +587,7 @@ CClientHost *CFeReceiveSub::exitFromLimboMode( const CLimboClient& lc ) { nldebug( "Restoring user %u from limbo mode", lc.Uid ); - CClientHost *client = addClient( lc.AddrFrom, lc.Uid, lc.UserName, lc.UserPriv, lc.UserExtended, lc.LanguageId, lc.LoginCookie, 0xF, false ); + CClientHost *client = addClient(lc.AddrFrom, lc.QuicUser.get(), lc.Uid, lc.UserName, lc.UserPriv, lc.UserExtended, lc.LanguageId, lc.LoginCookie, 0xF, false); NLMISC::TGameCycle tick = CTickEventHandler::getGameCycle(); client->setFirstSentPacket( client->sendNumber()+1, tick ); client->setSynchronizeState(); @@ -935,7 +950,7 @@ void CFeReceiveSub::handleReceivedMsg( CClientHost *clienthost ) // ALWAYS REMOVE CLIENT FROM LIMBO! LimboClients.erase(uid); - clienthost = addClient( _CurrentInMsg->AddrFrom, uid, userName, userPriv, userExtended, languageId, lc, instanceId, (uint8)charSlot ); + clienthost = addClient( _CurrentInMsg->AddrFrom, _CurrentInMsg->QuicUser, uid, userName, userPriv, userExtended, languageId, lc, instanceId, (uint8)charSlot ); // Check if the addition worked if ( clienthost != NULL ) diff --git a/ryzom/server/src/frontend_service/fe_receive_sub.h b/ryzom/server/src/frontend_service/fe_receive_sub.h index 600705febd..bfbde1d0f5 100644 --- a/ryzom/server/src/frontend_service/fe_receive_sub.h +++ b/ryzom/server/src/frontend_service/fe_receive_sub.h @@ -122,7 +122,7 @@ class CFeReceiveSub void release(); /// Add client - CClientHost *addClient( const NLNET::CInetAddress& addrfrom, TUid userId, const std::string &userName, const std::string &userPriv, const std::string & userExtended, const std::string & languageId, const NLNET::CLoginCookie &cookie, uint32 instanceId, uint8 authorisedCharSlot, bool sendCLConnect=true ); + CClientHost *addClient( const NLNET::CInetAddress& addrfrom, CQuicUserContext *quicUser, TUid userId, const std::string &userName, const std::string &userPriv, const std::string & userExtended, const std::string & languageId, const NLNET::CLoginCookie &cookie, uint32 instanceId, uint8 authorisedCharSlot, bool sendCLConnect=true ); /// Add to the list of clients which will be removed by addr at the three cycles later (leaving the time to send an impulsion to the client) void addToRemoveList( TClientId clientid ) { _ClientsToRemove.push_back( std::make_pair(clientid,3) ); } diff --git a/ryzom/server/src/frontend_service/fe_receive_task.cpp b/ryzom/server/src/frontend_service/fe_receive_task.cpp index d6e0ae9e2d..522b56f561 100644 --- a/ryzom/server/src/frontend_service/fe_receive_task.cpp +++ b/ryzom/server/src/frontend_service/fe_receive_task.cpp @@ -56,7 +56,7 @@ volatile uint32 CFEReceiveTask::LastUDPPacketReceived = 0; */ /// Constructor -TReceivedMessage::TReceivedMessage() +TReceivedMessage::TReceivedMessage() : QuicUser(nullptr) { VAddrFrom.resize(sizeof(sockaddr_in6)); } diff --git a/ryzom/server/src/frontend_service/fe_receive_task.h b/ryzom/server/src/frontend_service/fe_receive_task.h index 837243d5e8..1a11d3e80d 100644 --- a/ryzom/server/src/frontend_service/fe_receive_task.h +++ b/ryzom/server/src/frontend_service/fe_receive_task.h @@ -34,6 +34,7 @@ const uint32 MsgHeaderSize = 1; +class CQuicUserContext; /** * Placeholder for received messages @@ -85,6 +86,9 @@ struct TReceivedMessage /// Placeholder vector for address info std::vector VAddrFrom; + + /// QUIC user context, no need to refcount since it's already held in the FIFO readout + CQuicUserContext *QuicUser; }; @@ -108,7 +112,7 @@ class CFEReceiveTask : public NLMISC::IRunnable virtual void run(); /// Set new write queue (thread-safe because mutexed) - CBufFIFO *swapWriteQueue(NLMISC::CBufFIFO *writeQueue); + NLMISC::CBufFIFO *swapWriteQueue(NLMISC::CBufFIFO *writeQueue); /// Require exit (thread-safe because atomic assignment) void requireExit() { _ExitRequired = true; } diff --git a/ryzom/server/src/frontend_service/fe_send_sub.cpp b/ryzom/server/src/frontend_service/fe_send_sub.cpp index 9260d7e93e..1d5214d7fe 100644 --- a/ryzom/server/src/frontend_service/fe_send_sub.cpp +++ b/ryzom/server/src/frontend_service/fe_send_sub.cpp @@ -331,8 +331,15 @@ inline void CFeSendSub::CSendBuffer::sendOutBox( NLNET::CUdpSock *datasock ) { if ( OutBox.length() != 0 ) { - sendUDP( datasock, OutBox.buffer(), OutBox.length(), &DestAddress ); - //nlinfo( "Sent %u bytes to %s", OutBox.length(), DestAddress.asString().c_str() ); + if (QuicUser.get()) + { + QuicUser->Transceiver->sendDatagram(QuicUser.get(), OutBox.buffer(), OutBox.length()); + } + else + { + sendUDP(datasock, OutBox.buffer(), OutBox.length(), &DestAddress); + //nlinfo( "Sent %u bytes to %s", OutBox.length(), DestAddress.asString().c_str() ); + } } #ifdef MEASURE_SENDING diff --git a/ryzom/server/src/frontend_service/fe_send_sub.h b/ryzom/server/src/frontend_service/fe_send_sub.h index 968623e4e3..3698cd562e 100644 --- a/ryzom/server/src/frontend_service/fe_send_sub.h +++ b/ryzom/server/src/frontend_service/fe_send_sub.h @@ -51,6 +51,7 @@ class CFeSendSub /// Destination address NLNET::CInetAddress DestAddress; + CQuicUserContextPtr QuicUser; /// Used (connected) or not volatile TSBState SBState; @@ -59,13 +60,14 @@ class CFeSendSub TOutBox OutBox; /// Default constructor - CSendBuffer() : SBState(false), OutBox(false, 512) {} // prealloc 512 bytes to avoid bitmemstream reallocation + CSendBuffer() : SBState(false), OutBox(false, 512), QuicUser(nullptr) {} // prealloc 512 bytes to avoid bitmemstream reallocation /// Set the new address. state should be SBReady or SBNotReady only. - void setAddress( const NLNET::CInetAddress *addr, TSBState state ) + void setAddress( const NLNET::CInetAddress *addr, CQuicUserContext *quicUser, TSBState state ) { // Copy the address (just a link would not work) DestAddress = *addr; + QuicUser = quicUser; SBState = state; } @@ -127,11 +129,11 @@ class CFeSendSub volatile uint32 &sendCounter() { return _SendCounter; } /// Set the address for send buffer, to match a connected client - void setSendBufferAddress( TClientId id, const NLNET::CInetAddress *addr ) + void setSendBufferAddress( TClientId id, const NLNET::CInetAddress *addr, CQuicUserContext *quicUser ) { // We set the address for both, but we can't enable the buffer yet - ((*_CurrentFillingBuffers)[id]).setAddress( addr, false /*true*/ ); - ((*_CurrentFlushingBuffers)[id]).setAddress( addr, false ); + ((*_CurrentFillingBuffers)[id]).setAddress( addr, quicUser, false /*true*/ ); + ((*_CurrentFlushingBuffers)[id]).setAddress( addr, quicUser, false ); //_BuffersToEnable.insert( id ); // OBSOLETE: now it is enabled/disabled in CFeSendSub::fillPrioritizedActions } diff --git a/ryzom/server/src/frontend_service/quic_transceiver.cpp b/ryzom/server/src/frontend_service/quic_transceiver.cpp index 45d0d98230..249cde305b 100644 --- a/ryzom/server/src/frontend_service/quic_transceiver.cpp +++ b/ryzom/server/src/frontend_service/quic_transceiver.cpp @@ -30,6 +30,7 @@ #include #define MsQuic m->Api +#define null nullptr using namespace NLMISC; using namespace NLNET; @@ -49,7 +50,7 @@ class CAtomicFlagLock { m_Flag.clear(std::memory_order_release); } - + private: std::atomic_flag &m_Flag; }; @@ -59,7 +60,7 @@ class CAtomicFlagLockYield { public: CAtomicFlagLockYield(std::atomic_flag &flag) - : m_Flag(flag) + : m_Flag(flag) { while (m_Flag.test_and_set(std::memory_order_acquire)) std::this_thread::yield(); @@ -84,7 +85,7 @@ class CQuicTransceiverImpl std::atomic_flag BufferMutex = ATOMIC_FLAG_INIT; NLMISC::CBufFIFO *Buffer = null; - + std::atomic Listening; // Some salt for generating the token address @@ -141,7 +142,7 @@ void CQuicTransceiver::start(uint16 port) { nlwarning("QUIC API not available"); } - + static const char *protocolName = "ryzomcore4"; static const QUIC_BUFFER alpn = { sizeof(protocolName) - 1, (uint8_t *)protocolName }; @@ -251,11 +252,9 @@ QUIC_STATUS CQuicTransceiverImpl::listenerCallback(HQUIC listener, void *context // Create user context CQuicUserContext *user = new CQuicUserContext(); user->Transceiver = self; - user->TokenAddr = self->generateTokenAddr(); - TReceivedMessage msg; - msg.AddrFrom = user->TokenAddr; - msg.addressToVector(); - user->VTokenAddr = msg.VAddrFrom; + user->TokenAddr = self->generateTokenAddr(); // ev->NEW_CONNECTION.Info->RemoteAddress // Could change on migration, so don't expose it for now (OK in the future) + user->Connection = ev->NEW_CONNECTION.Connection; + user->increaseRef(); // They're in. MsQuic->SetCallbackHandler(ev->NEW_CONNECTION.Connection, CQuicTransceiverImpl::connectionCallback, (void *)user); status = MsQuic->ConnectionSetConfiguration(ev->NEW_CONNECTION.Connection, m->Configuration); @@ -297,7 +296,8 @@ QUIC_STATUS CQuicTransceiverImpl::connectionCallback(HQUIC connection, void *con nlinfo("Shutdown initiated by peer"); status = QUIC_STATUS_SUCCESS; break; - case QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE: + case QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE: { + CQuicUserContextRelease releaseUser(user); // Hopefully we only get QUIC_CONNECTION_EVENT_SHUTDOWN_COMPLETE once! nlinfo("Shutdown complete"); nlassert(!ev->SHUTDOWN_COMPLETE.AppCloseInProgress); // Only applicable on client, but assert to be sure if (!ev->SHUTDOWN_COMPLETE.AppCloseInProgress) @@ -305,9 +305,9 @@ QUIC_STATUS CQuicTransceiverImpl::connectionCallback(HQUIC connection, void *con MsQuic->ConnectionClose(connection); } // TODO: Report to the boss - delete user; status = QUIC_STATUS_SUCCESS; break; + } case QUIC_CONNECTION_EVENT_DATAGRAM_RECEIVED: nlinfo("Datagram received"); // YES PLEASE @@ -339,14 +339,6 @@ QUIC_STATUS CQuicTransceiverImpl::connectionCallback(HQUIC connection, void *con CInetAddress CQuicTransceiver::generateTokenAddr() { - // TODO: We could wrap a pointer and refcount CQuicUserContext somehow - // But it'll need to be correctly released from the receive sub - - // That way we can entirely bypass stupid lookup tables and get the real user context - // As well as get the connection context when sending - - // Use the same address trick to signal that it's a QUIC connection and not a real address - uint64 addrA = m->AddrA++; uint32 addrB = m->AddrB++; addrA = NLMISC::wangHash64(addrA ^ m->SaltA0) ^ m->SaltA1; @@ -363,12 +355,6 @@ CInetAddress CQuicTransceiver::generateTokenAddr() CInetAddress res(false); res.fromSockAddrInet6(&sa); return res; - - // This make a copy of the shared ptr into a memory block - //uint8 alignas(std::shared_ptr) memory[sizeof(std::shared_ptr)]; - //std::shared_ptr *ptr = new (memory) std::shared_ptr(user); - - // Can do the same with NLMISC::CSmartPtr } bool CQuicTransceiver::listening() @@ -376,11 +362,17 @@ bool CQuicTransceiver::listening() return m->Listening.load(std::memory_order_acquire); } -void CQuicTransceiver::datagramReceived(const CQuicUserContext *user, const uint8 *buffer, uint32 length) +void CQuicTransceiver::datagramReceived(CQuicUserContext *user, const uint8 *buffer, uint32 length) { - CAtomicFlagLock(m->BufferMutex); - m->Buffer->push(buffer, length); - m->Buffer->push(user->VTokenAddr); + // Increase reference for FIFO copy + user->increaseRef(); + + // Locked block + { + CAtomicFlagLockYield(m->BufferMutex); + m->Buffer->push(buffer, length); + m->Buffer->push((uint8 *)&user, sizeof(user)); // Pointer + } } NLMISC::CBufFIFO *CQuicTransceiver::swapWriteQueue(NLMISC::CBufFIFO *writeQueue) @@ -391,6 +383,18 @@ NLMISC::CBufFIFO *CQuicTransceiver::swapWriteQueue(NLMISC::CBufFIFO *writeQueue) return previous; } +void CQuicTransceiver::sendDatagram(CQuicUserContext *user, const uint8 *buffer, uint32 size) +{ + QUIC_BUFFER buf; + buf.Buffer = (uint8 *)buffer; + buf.Length = size; + QUIC_STATUS status = MsQuic->DatagramSend((HQUIC)user->Connection, &buf, 1, QUIC_SEND_FLAG_NONE, (void *)user); + if (QUIC_FAILED(status)) + { + nlwarning("MsQuic->ConnectionSendDatagram failed with status %d", status); + } +} + #else class CQuicTransceiverImpl @@ -427,7 +431,7 @@ bool CQuicTransceiver::listening() return false; } -void CQuicTransceiver::datagramReceived(const CQuicUserContext *user, const uint8 *buffer, uint32 length) +void CQuicTransceiver::datagramReceived(CQuicUserContext *user, const uint8 *buffer, uint32 length) { // LOCK // m->Buffer->push(buffer, length); @@ -442,6 +446,11 @@ NLMISC::CBufFIFO *CQuicTransceiver::swapWriteQueue(NLMISC::CBufFIFO *writeQueue) return previous; } +void CQuicTransceiver::sendDatagram(CQuicUserContext *user, const uint8 *buffer, uint32 size) +{ + +} + #endif /* end of file */ diff --git a/ryzom/server/src/frontend_service/quic_transceiver.h b/ryzom/server/src/frontend_service/quic_transceiver.h index 4770cb82b0..905afb816f 100644 --- a/ryzom/server/src/frontend_service/quic_transceiver.h +++ b/ryzom/server/src/frontend_service/quic_transceiver.h @@ -23,18 +23,118 @@ #include "fe_receive_task.h" +class CClientHost; + class CQuicTransceiverImpl; +class CQuicTransceiver; -struct CQuicUserContext +// User context for quic messages +class CQuicUserContext { +public: + // Manual reference count + void increaseRef() + { + m_RefCount.fetch_add(1, std::memory_order_relaxed); + } + + void decreaseRef() + { + if (m_RefCount.fetch_sub(1, std::memory_order_release) == 1) + { + delete this; + } + } + +public: + // Reference to QUIC context (immutable) CQuicTransceiver *Transceiver; - // Not a real address, just a token to identify the connection + // Reference to the internal connection (immutable) + void *Connection; + + // Not a real address, just a token to identify the connection (immutable) // Give everyone an IPv6 in unique local network fdd5:d66b:8698::/48 // The addresses are a sequential hash sequence, so should be unique for a very very long time // They should not be used for security purposes - CInetAddress TokenAddr; - std::vector VTokenAddr; + NLNET::CInetAddress TokenAddr; + + // Reference to the client host (game state) (owned by service main thread) + CClientHost *ClientHost = nullptr; + +private: + std::atomic_int m_RefCount = 0; +}; + +// Utility to decrease reference count, does not increase count +// This is to ensure that the reference count is decreased even when exceptions get thrown +class CQuicUserContextRelease +{ +public: + CQuicUserContextRelease(CQuicUserContext *user) + : m_User(user) + { + } + + ~CQuicUserContextRelease() + { + if (m_User) + m_User->decreaseRef(); + } + + CQuicUserContextRelease(const CQuicUserContextRelease &) = delete; + CQuicUserContextRelease &operator=(const CQuicUserContextRelease &) = delete; + +private: + CQuicUserContext *m_User; +}; + +// Regular reference counting +class CQuicUserContextPtr +{ +public: + CQuicUserContextPtr(CQuicUserContext *user) + : m_User(user) + { + if (m_User) + m_User->increaseRef(); + } + + ~CQuicUserContextPtr() + { + if (m_User) + m_User->decreaseRef(); + } + + CQuicUserContextPtr(const CQuicUserContextPtr &other) + : m_User(other.m_User) + { + if (m_User) + m_User->increaseRef(); + } + + CQuicUserContextPtr &operator=(const CQuicUserContextPtr &other) + { + if (m_User) + m_User->decreaseRef(); + m_User = other.m_User; + if (m_User) + m_User->increaseRef(); + return *this; + } + + CQuicUserContext *operator->() const + { + return m_User; + } + + CQuicUserContext *get() const + { + return m_User; + } + +private: + CQuicUserContext *m_User; }; class CQuicTransceiver @@ -58,9 +158,12 @@ class CQuicTransceiver /// Check if still listening bool listening(); + /// Send a datagram, fancier than a telegram, but not as reliable + void sendDatagram(CQuicUserContext *user, const uint8 *buffer, uint32 size); + private: friend CQuicTransceiverImpl; - + /// Internal implementation specific std::unique_ptr m; @@ -68,10 +171,10 @@ class CQuicTransceiver uint32 m_MsgSize; /// Received datagram - void datagramReceived(const CQuicUserContext *user, const uint8 *buffer, uint32 length); + void datagramReceived(CQuicUserContext *user, const uint8 *buffer, uint32 length); /// Generates a token address to identify the connection with existing code - CInetAddress generateTokenAddr(); + NLNET::CInetAddress generateTokenAddr(); // public: // /// Constructor