Added "poll group" interface.

This is used to poll many connections in a single function call.  Previously,
this was only possible if all of the connections were those accepted on the
same listen socket.  (ReceiveMessagesOnListenSocket).  But this left out at
least two important use cases with known users:

- If you create more than one listen socket (because there is more way to
  contact your service, e.g. once for P2P and another for direct IP, and
  another for relayed connections), then you could not poll all of the
  connections efficiently.
- In P2P use cases, we may initiate many connections to peers, and we want
  to poll all of them at once.

This change is relevant to: Issue #49, Issue #50, and issue #52.  (But I don't
this it really "fixes" any of them.)
This commit is contained in:
Fletcher Dunn
2019-12-05 15:51:33 -08:00
parent 8fcfe152eb
commit a9e5e86b28
10 changed files with 470 additions and 57 deletions
@@ -173,6 +173,7 @@ void ConnectionConfig::Init( ConnectionConfig *pInherit )
CUtlHashMap<uint16, CSteamNetworkConnectionBase *, std::equal_to<uint16>, Identity<uint16> > g_mapConnections;
CUtlHashMap<int, CSteamNetworkListenSocketBase *, std::equal_to<int>, Identity<int> > g_mapListenSockets;
CUtlHashMap<int, CSteamNetworkPollGroup *, std::equal_to<int>, Identity<int> > g_mapPollGroups;
static bool BConnectionStateExistsToAPI( ESteamNetworkingConnectionState eState )
{
@@ -226,13 +227,35 @@ static CSteamNetworkConnectionBase *GetConnectionByHandleForAPI( HSteamNetConnec
static CSteamNetworkListenSocketBase *GetListenSocketByHandle( HSteamListenSocket sock )
{
if ( sock == 0 )
if ( sock == k_HSteamListenSocket_Invalid )
return nullptr;
AssertMsg( !(sock & 0x80000000), "A poll group handle was used where a listen socket handle was expected" );
int idx = sock & 0xffff;
if ( !g_mapListenSockets.IsValidIndex( idx ) )
return nullptr;
CSteamNetworkListenSocketBase *pResult = g_mapListenSockets[ idx ];
Assert( pResult && pResult->m_hListenSocketSelf == sock );
if ( pResult->m_hListenSocketSelf != sock )
{
// Slot was reused, but this handle is now invalid
return nullptr;
}
return pResult;
}
static CSteamNetworkPollGroup *GetPollGroupByHandle( HSteamNetPollGroup hPollGroup )
{
if ( hPollGroup == k_HSteamNetPollGroup_Invalid )
return nullptr;
AssertMsg( (hPollGroup & 0x80000000), "A listen socket handle was used where a poll group handle was expected" );
int idx = hPollGroup & 0xffff;
if ( !g_mapPollGroups.IsValidIndex( idx ) )
return nullptr;
CSteamNetworkPollGroup *pResult = g_mapPollGroups[ idx ];
if ( pResult->m_hPollGroupSelf != hPollGroup )
{
// Slot was reused, but this handle is now invalid
return nullptr;
}
return pResult;
}
@@ -304,6 +327,18 @@ void CSteamNetworkingSockets::KillConnections()
Assert( !g_mapListenSockets.IsValidIndex( idx ) );
}
}
// Destroy all of my poll groups
FOR_EACH_HASHMAP( g_mapPollGroups, idx )
{
CSteamNetworkPollGroup *pPollGroup = g_mapPollGroups[idx];
if ( pPollGroup->m_pSteamNetworkingSocketsInterface == this )
{
DbgVerify( DestroyPollGroup( pPollGroup->m_hPollGroupSelf ) );
Assert( !g_mapPollGroups.IsValidIndex( idx ) );
}
}
}
void CSteamNetworkingSockets::Destroy()
@@ -359,9 +394,6 @@ bool CSteamNetworkingSockets::GetIdentity( SteamNetworkingIdentity *pIdentity )
return !m_identity.IsInvalid();
}
/// Certificate provision by the application. (On Steam, Steam will handle all this automatically)
#ifndef STEAMNETWORKINGSOCKETS_STEAM
bool CSteamNetworkingSockets::GetCertificateRequest( int *pcbBlob, void *pBlob, SteamNetworkingErrMsg &errMsg )
{
SteamDatagramTransportLock scopeLock( "GetCertificateRequest" );
@@ -527,8 +559,6 @@ bool CSteamNetworkingSockets::SetCertificate( const void *pCertificate, int cbCe
return true;
}
#endif
#ifdef STEAMNETWORKINGSOCKETS_OPENSOURCE
ESteamNetworkingAvailability CSteamNetworkingSockets::InitAuthentication()
{
@@ -736,14 +766,67 @@ int CSteamNetworkingSockets::ReceiveMessagesOnConnection( HSteamNetConnection hC
return pConn->APIReceiveMessages( ppOutMessages, nMaxMessages );
}
int CSteamNetworkingSockets::ReceiveMessagesOnListenSocket( HSteamListenSocket hSocket, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages )
HSteamNetPollGroup CSteamNetworkingSockets::CreatePollGroup()
{
SteamDatagramTransportLock scopeLock( "CreatePollGroup" );
CSteamNetworkPollGroup *pPollGroup = new CSteamNetworkPollGroup( this );
pPollGroup->AssignHandleAndAddToGlobalTable();
return pPollGroup->m_hPollGroupSelf;
}
bool CSteamNetworkingSockets::DestroyPollGroup( HSteamNetPollGroup hPollGroup )
{
SteamDatagramTransportLock scopeLock( "DestroyPollGroup" );
CSteamNetworkPollGroup *pPollGroup = GetPollGroupByHandle( hPollGroup );
if ( !pPollGroup )
return false;
delete pPollGroup;
return true;
}
bool CSteamNetworkingSockets::SetConnectionPollGroup( HSteamNetConnection hConn, HSteamNetPollGroup hPollGroup )
{
SteamDatagramTransportLock scopeLock( "SetConnectionPollGroup" );
CSteamNetworkConnectionBase *pConn = GetConnectionByHandleForAPI( hConn );
if ( !pConn )
return false;
// Special case for removing the poll group
if ( hPollGroup == k_HSteamNetPollGroup_Invalid )
{
pConn->RemoveFromPollGroup();
return true;
}
CSteamNetworkPollGroup *pPollGroup = GetPollGroupByHandle( hPollGroup );
if ( !pPollGroup )
return false;
pConn->SetPollGroup( pPollGroup );
return true;
}
int CSteamNetworkingSockets::ReceiveMessagesOnPollGroup( HSteamNetPollGroup hPollGroup, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages )
{
SteamDatagramTransportLock scopeLock( "ReceiveMessagesOnPollGroup" );
CSteamNetworkPollGroup *pPollGroup = GetPollGroupByHandle( hPollGroup );
if ( !pPollGroup )
return -1;
return pPollGroup->m_queueRecvMessages.RemoveMessages( ppOutMessages, nMaxMessages );
}
#ifdef STEAMNETWORKINGSOCKETS_STEAMCLIENT
int CSteamNetworkingSockets::ReceiveMessagesOnListenSocketLegacyPollGroup( HSteamListenSocket hSocket, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages )
{
SteamDatagramTransportLock scopeLock( "ReceiveMessagesOnListenSocket" );
CSteamNetworkListenSocketBase *pSock = GetListenSocketByHandle( hSocket );
if ( !pSock )
return -1;
return pSock->APIReceiveMessages( ppOutMessages, nMaxMessages );
return pSock->m_legacyPollGroup.m_queueRecvMessages.RemoveMessages( ppOutMessages, nMaxMessages );
}
#endif
bool CSteamNetworkingSockets::GetConnectionInfo( HSteamNetConnection hConn, SteamNetConnectionInfo_t *pInfo )
{
@@ -88,7 +88,6 @@ public:
virtual void SendMessages( int nMessages, SteamNetworkingMessage_t *const *pMessages, int64 *pOutMessageNumberOrResult ) override;
virtual EResult FlushMessagesOnConnection( HSteamNetConnection hConn ) override;
virtual int ReceiveMessagesOnConnection( HSteamNetConnection hConn, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) override;
virtual int ReceiveMessagesOnListenSocket( HSteamListenSocket hSocket, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) override;
virtual bool GetConnectionInfo( HSteamNetConnection hConn, SteamNetConnectionInfo_t *pInfo ) override;
virtual bool GetQuickConnectionStatus( HSteamNetConnection hConn, SteamNetworkingQuickConnectionStatus *pStats ) override;
virtual int GetDetailedConnectionStatus( HSteamNetConnection hConn, char *pszBuf, int cbBuf ) override;
@@ -96,9 +95,16 @@ public:
virtual bool CreateSocketPair( HSteamNetConnection *pOutConnection1, HSteamNetConnection *pOutConnection2, bool bUseNetworkLoopback, const SteamNetworkingIdentity *pIdentity1, const SteamNetworkingIdentity *pIdentity2 ) override;
virtual bool GetIdentity( SteamNetworkingIdentity *pIdentity ) override;
#ifndef STEAMNETWORKINGSOCKETS_STEAM
virtual HSteamNetPollGroup CreatePollGroup() override;
virtual bool DestroyPollGroup( HSteamNetPollGroup hPollGroup ) override;
virtual bool SetConnectionPollGroup( HSteamNetConnection hConn, HSteamNetPollGroup hPollGroup ) override;
virtual int ReceiveMessagesOnPollGroup( HSteamNetPollGroup hPollGroup, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) override;
virtual bool GetCertificateRequest( int *pcbBlob, void *pBlob, SteamNetworkingErrMsg &errMsg ) override;
virtual bool SetCertificate( const void *pCertificate, int cbCertificate, SteamNetworkingErrMsg &errMsg ) override;
#ifdef STEAMNETWORKINGSOCKETS_STEAMCLIENT
virtual int ReceiveMessagesOnListenSocketLegacyPollGroup( HSteamListenSocket hSocket, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages ) override;
#endif
#ifdef STEAMNETWORKINGSOCKETS_STANDALONELIB
@@ -170,6 +170,46 @@ CSteamNetworkingMessage *CSteamNetworkingMessage::New( CSteamNetworkConnectionBa
return pMsg;
}
void CSteamNetworkingMessage::LinkBefore( CSteamNetworkingMessage *pSuccessor, Links CSteamNetworkingMessage::*pMbrLinks, SteamNetworkingMessageQueue *pQueue )
{
// Make sure we're not already in a queue
UnlinkFromQueue( pMbrLinks );
// No successor?
if ( !pSuccessor )
{
LinkToQueueTail( pMbrLinks, pQueue );
return;
}
// Otherwise, the queue cannot be empty, since it at least contains the successor
Assert( pQueue->m_pFirst );
Assert( pQueue->m_pLast );
Assert( (pSuccessor->*pMbrLinks).m_pQueue == pQueue );
CSteamNetworkingMessage *pPrev = (pSuccessor->*pMbrLinks).m_pPrev;
if ( pPrev )
{
Assert( pQueue->m_pFirst != pSuccessor );
Assert( (pPrev->*pMbrLinks).m_pNext == pSuccessor );
Assert( (pPrev->*pMbrLinks).m_pQueue == pQueue );
(pPrev->*pMbrLinks).m_pNext = this;
(this->*pMbrLinks).m_pPrev = pPrev;
}
else
{
Assert( pQueue->m_pFirst == pSuccessor );
pQueue->m_pFirst = this;
(this->*pMbrLinks).m_pPrev = nullptr; // Should already be null, but let's slam it again anyway
}
// Finish up
(this->*pMbrLinks).m_pQueue = pQueue;
(this->*pMbrLinks).m_pNext = pSuccessor;
(pSuccessor->*pMbrLinks).m_pPrev = this;
}
void CSteamNetworkingMessage::LinkToQueueTail( Links CSteamNetworkingMessage::*pMbrLinks, SteamNetworkingMessageQueue *pQueue )
{
// Locate previous link that should point to us.
@@ -275,6 +315,94 @@ int SteamNetworkingMessageQueue::RemoveMessages( SteamNetworkingMessage_t **ppOu
return nMessagesReturned;
}
/////////////////////////////////////////////////////////////////////////////
//
// CSteamNetworkPollGroup
//
/////////////////////////////////////////////////////////////////////////////
CSteamNetworkPollGroup::CSteamNetworkPollGroup( CSteamNetworkingSockets *pInterface )
: m_pSteamNetworkingSocketsInterface( pInterface )
, m_hPollGroupSelf( k_HSteamListenSocket_Invalid )
{
}
CSteamNetworkPollGroup::~CSteamNetworkPollGroup()
{
FOR_EACH_VEC_BACK( m_vecConnections, i )
{
CSteamNetworkConnectionBase *pConn = m_vecConnections[i];
Assert( pConn->m_pPollGroup == this );
pConn->RemoveFromPollGroup();
Assert( m_vecConnections.Count() == i );
}
// We should not have any messages now! but if we do, unlink them
Assert( m_queueRecvMessages.empty() );
// But if we do, unlink them but leave them in the main queue.
while ( !m_queueRecvMessages.empty() )
{
CSteamNetworkingMessage *pMsg = m_queueRecvMessages.m_pFirst;
// The poll group queue is the "secondary queue"
Assert( pMsg->m_linksSecondaryQueue.m_pQueue == &m_queueRecvMessages );
// They should be in some other queue (for the connection) as the main queue.
// That owns them and make sure they get deleted!
Assert( pMsg->m_links.m_pQueue != nullptr );
// OK, do the work
pMsg->UnlinkFromQueue( &CSteamNetworkingMessage::m_linksSecondaryQueue );
// Make sure it worked.
Assert( pMsg != m_queueRecvMessages.m_pFirst );
}
// Remove us from global table, if we're in it
if ( m_hPollGroupSelf != k_HSteamNetPollGroup_Invalid )
{
int idx = m_hPollGroupSelf & 0xffff;
if ( g_mapPollGroups.IsValidIndex( idx ) && g_mapPollGroups[ idx ] == this )
{
g_mapPollGroups[ idx ] = nullptr; // Just for grins
g_mapPollGroups.Remove( idx );
}
else
{
AssertMsg( false, "Poll group handle bookkeeping bug!" );
}
m_hPollGroupSelf = k_HSteamNetPollGroup_Invalid;
}
}
void CSteamNetworkPollGroup::AssignHandleAndAddToGlobalTable()
{
Assert( m_hPollGroupSelf == k_HSteamNetPollGroup_Invalid );
// We actually don't do map "lookups". We assume the number of listen sockets
// is going to be reasonably small.
static int s_nDummy;
++s_nDummy;
int idx = g_mapPollGroups.Insert( s_nDummy, this );
Assert( idx < 0x1000 );
// Use upper 15 bits as a connection sequence number, so that listen socket handles
// are not reused within a short time period.
// (The top bit is reserved, so that listen socket handles and poll group handles
// come from a different namespace, so that we can immediately detect using the wrong
// and make that bug more obvious.)
static uint32 s_nUpperBits = 0;
s_nUpperBits += 0x10000;
if ( s_nUpperBits & 0x10000000 )
s_nUpperBits = 0x10000;
// Set the handle
m_hPollGroupSelf = HSteamNetPollGroup( idx | s_nUpperBits | 0x80000000 );
}
/////////////////////////////////////////////////////////////////////////////
//
// CSteamNetworkListenSocketBase
@@ -283,14 +411,17 @@ int SteamNetworkingMessageQueue::RemoveMessages( SteamNetworkingMessage_t **ppOu
CSteamNetworkListenSocketBase::CSteamNetworkListenSocketBase( CSteamNetworkingSockets *pSteamNetworkingSocketsInterface )
: m_pSteamNetworkingSocketsInterface( pSteamNetworkingSocketsInterface )
, m_hListenSocketSelf( k_HSteamListenSocket_Invalid )
#ifdef STEAMNETWORKINGSOCKETS_STEAMCLIENT
, m_legacyPollGroup( pSteamNetworkingSocketsInterface )
#endif
{
m_hListenSocketSelf = k_HSteamListenSocket_Invalid;
m_connectionConfig.Init( &pSteamNetworkingSocketsInterface->m_connectionConfig );
}
CSteamNetworkListenSocketBase::~CSteamNetworkListenSocketBase()
{
AssertMsg( m_mapChildConnections.Count() == 0 && !m_queueRecvMessages.m_pFirst && !m_queueRecvMessages.m_pLast, "Destroy() not used properly" );
AssertMsg( m_mapChildConnections.Count() == 0, "Destroy() not used properly" );
// Remove us from global table, if we're in it
if ( m_hListenSocketSelf != k_HSteamListenSocket_Invalid )
@@ -299,7 +430,7 @@ CSteamNetworkListenSocketBase::~CSteamNetworkListenSocketBase()
if ( g_mapListenSockets.IsValidIndex( idx ) && g_mapListenSockets[ idx ] == this )
{
g_mapListenSockets[ idx ] = nullptr; // Just for grins
g_mapListenSockets.RemoveAt( idx );
g_mapListenSockets.Remove( idx );
}
else
{
@@ -323,11 +454,14 @@ bool CSteamNetworkListenSocketBase::BInitListenSocketCommon( int nOptions, const
int idx = g_mapListenSockets.Insert( s_nDummy, this );
Assert( idx < 0x1000 );
// Use upper 16 bits as a connection sequence number, so that listen socket handles
// Use upper 15 bits as a connection sequence number, so that listen socket handles
// are not reused within a short time period.
// (The top bit is reserved, so that listen socket handles and poll group handles
// come from a different namespace, so that we can immediately detect using the wrong
// and make that bug more obvious.)
static uint32 s_nUpperBits = 0;
s_nUpperBits += 0x10000;
if ( s_nUpperBits == 0 )
if ( s_nUpperBits & 0x10000000 )
s_nUpperBits = 0x10000;
// Add it to our table of listen sockets
@@ -381,11 +515,6 @@ bool CSteamNetworkListenSocketBase::APIGetAddress( SteamNetworkingIPAddr *pAddre
return false;
}
int CSteamNetworkListenSocketBase::APIReceiveMessages( SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages )
{
return m_queueRecvMessages.RemoveMessages( ppOutMessages, nMaxMessages );
}
void CSteamNetworkListenSocketBase::AddChildConnection( CSteamNetworkConnectionBase *pConn )
{
Assert( pConn->m_pParentListenSocket == nullptr );
@@ -402,6 +531,12 @@ void CSteamNetworkListenSocketBase::AddChildConnection( CSteamNetworkConnectionB
// Connection configuration will inherit from us
pConn->m_connectionConfig.Init( &m_connectionConfig );
// If we are possibly providing an old interface that did not have poll groups,
// add the connection to the default poll group
#ifdef STEAMNETWORKINGSOCKETS_STEAMCLIENT
pConn->SetPollGroup( &m_legacyPollGroup );
#endif
}
void CSteamNetworkListenSocketBase::AboutToDestroyChildConnection( CSteamNetworkConnectionBase *pConn )
@@ -452,6 +587,7 @@ CSteamNetworkConnectionBase::CSteamNetworkConnectionBase( CSteamNetworkingSocket
m_unConnectionIDLocal = 0;
m_unConnectionIDRemote = 0;
m_pParentListenSocket = nullptr;
m_pPollGroup = nullptr;
m_hSelfInParentListenSocketMap = -1;
m_pMessagesInterface = nullptr;
m_pMessagesSession = nullptr;
@@ -520,6 +656,9 @@ void CSteamNetworkConnectionBase::FreeResources()
// Discard any messages that weren't retrieved
m_queueRecvMessages.PurgeMessages();
// If we are in a poll group, remove us from the group
RemoveFromPollGroup();
// Detach from the listen socket that owns us, if any
if ( m_pParentListenSocket )
m_pParentListenSocket->AboutToDestroyChildConnection( this );
@@ -577,6 +716,95 @@ void CSteamNetworkConnectionBase::DestroyTransport()
}
}
void CSteamNetworkConnectionBase::RemoveFromPollGroup()
{
if ( !m_pPollGroup )
return;
// Scan all of our messages, and make sure they are not in the secondary queue
for ( CSteamNetworkingMessage *pMsg = m_queueRecvMessages.m_pFirst ; pMsg ; pMsg = pMsg->m_linksSecondaryQueue.m_pNext )
{
Assert( pMsg->m_links.m_pQueue == &m_queueRecvMessages );
// It *should* be in the secondary queue of the poll group
Assert( pMsg->m_linksSecondaryQueue.m_pQueue == &m_pPollGroup->m_queueRecvMessages );
// OK, do the work
pMsg->UnlinkFromQueue( &CSteamNetworkingMessage::m_linksSecondaryQueue );
}
// Remove us from the poll group's list. DbgVerify because we should be in the list!
DbgVerify( m_pPollGroup->m_vecConnections.FindAndFastRemove( this ) );
// We're not in a poll group anymore
m_pPollGroup = nullptr;
}
void CSteamNetworkConnectionBase::SetPollGroup( CSteamNetworkPollGroup *pPollGroup )
{
// Quick early-out for no change
if ( m_pPollGroup == pPollGroup )
return;
// Clearing it?
if ( !pPollGroup )
{
RemoveFromPollGroup();
return;
}
// Scan all messages that are already queued for this connection,
// and insert them into the poll groups queue in the (approximate)
// appropriate spot. Using local timestamps should be really close
// for ordering messages between different connections. Remember
// that the API very clearly does not provide strong guarantees
// regarding ordering of messages from different connections, and
// really anybody who is expecting or relying on such guarantees
// is probably doing something wrong.
CSteamNetworkingMessage *pInsertBefore = pPollGroup->m_queueRecvMessages.m_pFirst;
for ( CSteamNetworkingMessage *pMsg = m_queueRecvMessages.m_pFirst ; pMsg ; pMsg = pMsg->m_links.m_pNext )
{
Assert( pMsg->m_links.m_pQueue == &m_queueRecvMessages );
// Unlink it from existing poll group queue, if any
if ( pMsg->m_linksSecondaryQueue.m_pQueue )
{
Assert( m_pPollGroup && pMsg->m_linksSecondaryQueue.m_pQueue == &m_pPollGroup->m_queueRecvMessages );
pMsg->UnlinkFromQueue( &CSteamNetworkingMessage::m_linksSecondaryQueue );
}
else
{
Assert( !m_pPollGroup );
}
// Scan forward in the poll group message queue, until we find the insertion point
for (;;)
{
// End of queue?
if ( !pInsertBefore )
{
pMsg->LinkToQueueTail( &CSteamNetworkingMessage::m_linksSecondaryQueue, &pPollGroup->m_queueRecvMessages );
break;
}
Assert( pInsertBefore->m_linksSecondaryQueue.m_pQueue == &pPollGroup->m_queueRecvMessages );
if ( pInsertBefore->m_usecTimeReceived > pMsg->m_usecTimeReceived )
{
pMsg->LinkBefore( pInsertBefore, &CSteamNetworkingMessage::m_linksSecondaryQueue, &pPollGroup->m_queueRecvMessages );
break;
}
pInsertBefore = pInsertBefore->m_linksSecondaryQueue.m_pNext;
}
}
m_pPollGroup = pPollGroup;
Assert( !m_pPollGroup->m_vecConnections.HasElement( this ) );
m_pPollGroup->m_vecConnections.AddToTail( this );
}
bool CSteamNetworkConnectionBase::BInitConnection( SteamNetworkingMicroseconds usecNow, int nOptions, const SteamNetworkingConfigValue_t *pOptions, SteamDatagramErrMsg &errMsg )
{
// Make sure MTU values are initialized
@@ -1977,9 +2205,9 @@ void CSteamNetworkConnectionBase::ReceivedMessage( CSteamNetworkingMessage *pMsg
// Add to end of my queue.
pMsg->LinkToQueueTail( &CSteamNetworkingMessage::m_links, &m_queueRecvMessages );
// If we are an inbound, accepted connection, link into the listen socket's queue
if ( m_pParentListenSocket )
pMsg->LinkToQueueTail( &CSteamNetworkingMessage::m_linksSecondaryQueue, &m_pParentListenSocket->m_queueRecvMessages );
// Add to the poll group, if we are in one
if ( m_pPollGroup )
pMsg->LinkToQueueTail( &CSteamNetworkingMessage::m_linksSecondaryQueue, &m_pPollGroup->m_queueRecvMessages );
}
void CSteamNetworkConnectionBase::PostConnectionStateChangedCallback( ESteamNetworkingConnectionState eOldAPIState, ESteamNetworkingConnectionState eNewAPIState )
@@ -145,6 +145,33 @@ public:
virtual void ConnectionStateChanged( ESteamNetworkingConnectionState eOldState, ESteamNetworkingConnectionState eNewState ) = 0;
};
/////////////////////////////////////////////////////////////////////////////
//
// CSteamNetworkPollGroup
//
/////////////////////////////////////////////////////////////////////////////
class CSteamNetworkPollGroup
{
public:
CSteamNetworkPollGroup( CSteamNetworkingSockets *pInterface );
~CSteamNetworkPollGroup();
/// What interface is responsible for this listen socket?
CSteamNetworkingSockets *const m_pSteamNetworkingSocketsInterface;
/// Linked list of messages received through any connection on this listen socket
SteamNetworkingMessageQueue m_queueRecvMessages;
/// Index into the global list
HSteamNetPollGroup m_hPollGroupSelf;
/// List of connections that are in this poll group
CUtlVector<CSteamNetworkConnectionBase *> m_vecConnections;
void AssignHandleAndAddToGlobalTable();
};
/////////////////////////////////////////////////////////////////////////////
//
// CSteamNetworkListenSocketBase
@@ -165,15 +192,11 @@ public:
/// This gets called on an accepted connection before it gets destroyed
virtual void AboutToDestroyChildConnection( CSteamNetworkConnectionBase *pConn );
int APIReceiveMessages( SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages );
virtual bool APIGetAddress( SteamNetworkingIPAddr *pAddress );
/// Map of child connections
CUtlHashMap<RemoteConnectionKey_t, CSteamNetworkConnectionBase *, std::equal_to<RemoteConnectionKey_t>, RemoteConnectionKey_t::Hash > m_mapChildConnections;
/// Linked list of messages received through any connection on this listen socket
SteamNetworkingMessageQueue m_queueRecvMessages;
/// Index into the global list
HSteamListenSocket m_hListenSocketSelf;
@@ -183,6 +206,11 @@ public:
/// Configuration options that will apply to all connections accepted through this listen socket
ConnectionConfig m_connectionConfig;
/// For legacy interface.
#ifdef STEAMNETWORKINGSOCKETS_STEAMCLIENT
CSteamNetworkPollGroup m_legacyPollGroup;
#endif
protected:
CSteamNetworkListenSocketBase( CSteamNetworkingSockets *pSteamNetworkingSocketsInterface );
virtual ~CSteamNetworkListenSocketBase(); // hidden destructor, don't call directly. Use Destroy()
@@ -326,6 +354,15 @@ public:
/// The listen socket through which we were accepted, if any.
CSteamNetworkListenSocketBase *m_pParentListenSocket;
/// What poll group are we assigned to?
CSteamNetworkPollGroup *m_pPollGroup;
/// Assign poll group
void SetPollGroup( CSteamNetworkPollGroup *pPollGroup );
/// Remove us from the poll group we are in (if any)
void RemoveFromPollGroup();
/// Was this connection initiated locally (we are the "client") or remotely (we are the "server")?
/// In *most* use cases, "server" cnonections have a listen socket, but not always.
bool m_bConnectionInitiatedRemotely;
@@ -761,6 +798,7 @@ inline void SendPacketContext<TStatsMsg>::CalcMaxEncryptedPayloadSize( size_t cb
extern CUtlHashMap<uint16, CSteamNetworkConnectionBase *, std::equal_to<uint16>, Identity<uint16> > g_mapConnections;
extern CUtlHashMap<int, CSteamNetworkListenSocketBase *, std::equal_to<int>, Identity<int> > g_mapListenSockets;
extern CUtlHashMap<int, CSteamNetworkPollGroup *, std::equal_to<int>, Identity<int> > g_mapPollGroups;
extern bool BCheckGlobalSpamReplyRateLimit( SteamNetworkingMicroseconds usecNow );
extern CSteamNetworkConnectionBase *GetConnectionByHandle( HSteamNetConnection sock );
@@ -83,11 +83,6 @@ STEAMNETWORKINGSOCKETS_INTERFACE int SteamAPI_ISteamNetworkingSockets_ReceiveMes
return ((ISteamNetworkingSockets*)instancePtr)->ReceiveMessagesOnConnection( hConn, ppOutMessages, nMaxMessages );
}
STEAMNETWORKINGSOCKETS_INTERFACE int SteamAPI_ISteamNetworkingSockets_ReceiveMessagesOnListenSocket( intptr_t instancePtr, HSteamListenSocket hSocket, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages )
{
return ((ISteamNetworkingSockets*)instancePtr)->ReceiveMessagesOnListenSocket( hSocket, ppOutMessages, nMaxMessages );
}
STEAMNETWORKINGSOCKETS_INTERFACE bool SteamAPI_ISteamNetworkingSockets_GetConnectionInfo( intptr_t instancePtr, HSteamNetConnection hConn, SteamNetConnectionInfo_t *pInfo )
{
return ((ISteamNetworkingSockets*)instancePtr)->GetConnectionInfo( hConn, pInfo );
@@ -78,6 +78,7 @@ public:
/// P2P channel, depending on message type)
Links m_linksSecondaryQueue;
void LinkBefore( CSteamNetworkingMessage *pSuccessor, Links CSteamNetworkingMessage::*pMbrLinks, SteamNetworkingMessageQueue *pQueue );
void LinkToQueueTail( Links CSteamNetworkingMessage::*pMbrLinks, SteamNetworkingMessageQueue *pQueue );
void UnlinkFromQueue( Links CSteamNetworkingMessage::*pMbrLinks );