diff --git a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.cpp b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.cpp index f934217..98236cd 100644 --- a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.cpp +++ b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.cpp @@ -96,12 +96,21 @@ CSteamNetworkingMessage *CSteamNetworkingMessage::New( CSteamNetworkConnectionBa // FIXME Should avoid this dynamic memory call with some sort of pooling CSteamNetworkingMessage *pMsg = new CSteamNetworkingMessage; - pMsg->m_sender = pParent->m_identityRemote; + if ( pParent ) + { + pMsg->m_sender = pParent->m_identityRemote; + pMsg->m_conn = pParent->m_hConnectionSelf; + pMsg->m_nConnUserData = pParent->GetUserData(); + } + else + { + memset( &pMsg->m_sender, 0, sizeof(pMsg->m_sender) ); + pMsg->m_conn = k_HSteamNetConnection_Invalid; + pMsg->m_nConnUserData = 0; + } pMsg->m_pData = malloc( cbSize ); pMsg->m_cbSize = cbSize; pMsg->m_nChannel = -1; - pMsg->m_conn = pParent->m_hConnectionSelf; - pMsg->m_nConnUserData = pParent->GetUserData(); pMsg->m_usecTimeReceived = usecNow; pMsg->m_nMessageNumber = nMsgNum; pMsg->m_pfnRelease = CSteamNetworkingMessage::Delete; @@ -344,6 +353,8 @@ CSteamNetworkConnectionBase::CSteamNetworkConnectionBase( CSteamNetworkingSocket m_unConnectionIDRemote = 0; m_pParentListenSocket = nullptr; m_hSelfInParentListenSocketMap = -1; + m_pMessagesInterface = nullptr; + m_pMessagesSession = nullptr; m_bCertHasIdentity = false; m_bCryptKeysValid = false; memset( m_szAppName, 0, sizeof( m_szAppName ) ); @@ -1428,6 +1439,27 @@ void CSteamNetworkConnectionBase::ReceivedMessage( const void *pData, int cbData (long long)nMsgNum, cbData ); + // Special case for internal connections used by Messages interface + if ( m_pMessagesInterface ) + { + // Are we still associated with our session? + if ( !m_pMessagesSession ) + { + // How did we get here? We should be closed, and once closed, + // we should not receive any more messages + AssertMsg2( false, "Received message for connection %s associated with Messages interface, but no session. Connection state is %d", GetDescription(), (int)GetState() ); + } + else if ( m_pMessagesSession->m_pConnection != this ) + { + AssertMsg2( false, "Connection/session linkage bookkeeping bug! %s state %d", GetDescription(), (int)GetState() ); + } + else + { + m_pMessagesSession->ReceivedMessage( pData, cbData, nMsgNum, usecNow ); + } + return; + } + // Create a message CSteamNetworkingMessage *pMsg = CSteamNetworkingMessage::New( this, cbData, nMsgNum, usecNow ); @@ -1450,8 +1482,40 @@ void CSteamNetworkConnectionBase::ConnectionStateChanged( ESteamNetworkingConnec // from the application's perspective, are not relevant ESteamNetworkingConnectionState eOldAPIState = CollapseConnectionStateToAPIState( eOldState ); ESteamNetworkingConnectionState eNewAPIState = CollapseConnectionStateToAPIState( GetState() ); - if ( eOldAPIState != eNewAPIState ) - PostConnectionStateChangedCallback( eOldAPIState, eNewAPIState ); + + // Internal connection used by the higher-level messages interface? + if ( m_pMessagesInterface ) + { + // Are we still associated with our session? + if ( m_pMessagesSession ) + { + // How did we get here? We should be closed! + if ( m_pMessagesSession->m_pConnection != this ) + { + AssertMsg2( false, "Connection/session linkage bookkeeping bug! %s state %d", GetDescription(), (int)GetState() ); + } + else + { + m_pMessagesSession->ConnectionStateChanged( eOldState, GetState() ); + } + } + else + { + // We should only detach after being closed or destroyed. + AssertMsg2( GetState() == k_ESteamNetworkingConnectionState_FinWait || GetState() == k_ESteamNetworkingConnectionState_Dead || GetState() == k_ESteamNetworkingConnectionState_None, + "Connection %s has detatched from messages session, but is in state %d", GetDescription(), (int)GetState() ); + } + } + else + { + + // Ordinary connection. Check for posting callback, if connection state has changed from + // an API perspective + if ( eOldAPIState != eNewAPIState ) + { + PostConnectionStateChangedCallback( eOldAPIState, eNewAPIState ); + } + } // Any time we switch into a state that is closed from an API perspective, // discard any unread received messages @@ -2221,7 +2285,7 @@ void CSteamNetworkConnectionPipe::ConnectionStateChanged( ESteamNetworkingConnec void CSteamNetworkConnectionPipe::PostConnectionStateChangedCallback( ESteamNetworkingConnectionState eOldAPIState, ESteamNetworkingConnectionState eNewAPIState ) { // Don't post any callbacks for the initial transitions. - if ( eNewAPIState == k_ESteamNetworkingConnectionState_Connected || eNewAPIState == k_ESteamNetworkingConnectionState_Connected ) + if ( eNewAPIState == k_ESteamNetworkingConnectionState_Connecting || eNewAPIState == k_ESteamNetworkingConnectionState_Connected ) return; // But post callbacks for these guys diff --git a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.h b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.h index 000215b..6ed0203 100644 --- a/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.h +++ b/src/steamnetworkingsockets/clientlib/steamnetworkingsockets_connections.h @@ -23,10 +23,6 @@ struct SteamNetConnectionStatusChangedCallback_t; class ISteamNetworkingSocketsSerialized; -class CMsgSteamSockets_UDP_ChallengeRequest; -class CMsgSteamSockets_UDP_ConnectRequest; -class CMsgSteamSockets_UDP_ConnectionClosed; -class CMsgSteamSockets_UDP_Stats; namespace SteamNetworkingSocketsLib { @@ -36,6 +32,7 @@ const SteamNetworkingMicroseconds k_usecFinWaitTimeout = 5*k_nMillion; typedef char ConnectionEndDebugMsg[ k_cchSteamNetworkingMaxConnectionCloseReason ]; class CSteamNetworkingSockets; +class CSteamNetworkingMessages; class CSteamNetworkConnectionBase; class CSharedSocket; struct SteamNetworkingMessageQueue; @@ -146,9 +143,19 @@ struct SteamNetworkingMessageQueue void PurgeMessages(); }; +/// Connections created through the "messages" interface are not directly exposed to the app. +// They have different mechanisms for notifying of received messages and state changes. +class ISteamNetworkingMessagesSession +{ +public: + CSteamNetworkConnectionBase *m_pConnection; // active connection, if any. Might be NULL! + virtual void ReceivedMessage( const void *pData, int cbData, int64 nMsgNum, SteamNetworkingMicroseconds usecNow ) = 0; + virtual void ConnectionStateChanged( ESteamNetworkingConnectionState eOldState, ESteamNetworkingConnectionState eNewState ) = 0; +}; + ///////////////////////////////////////////////////////////////////////////// // -// Abstract base classes +// CSteamNetworkListenSocketBase // ///////////////////////////////////////////////////////////////////////////// @@ -186,6 +193,12 @@ protected: virtual ~CSteamNetworkListenSocketBase(); // hidden destructor, don't call directly. Use Destroy() }; +///////////////////////////////////////////////////////////////////////////// +// +// CSteamNetworkConnectionBase +// +///////////////////////////////////////////////////////////////////////////// + /// Abstract interface for a connection to a remote host over any underlying /// transport. Most of the common functionality for implementing reliable /// connections on top of unreliable datagrams, connection quality measurement, @@ -304,6 +317,11 @@ public: /// Our handle in our parent's m_listAcceptedConnections (if we were accepted on a listen socket) int m_hSelfInParentListenSocketMap; + // Was this connection created as part of the "messages" interface? If so, what interface + // owns us, and if so, are we still associated with an active session? + CSteamNetworkingMessages *m_pMessagesInterface; + ISteamNetworkingMessagesSession *m_pMessagesSession; + // Linked list of received messages SteamNetworkingMessageQueue m_queueRecvMessages; @@ -438,7 +456,7 @@ protected: virtual int SendEncryptedDataChunk( const void *pChunk, int cbChunk, SteamNetworkingMicroseconds usecNow, void *pConnectionContext ) = 0; /// Called when we receive a complete message. Should allocate a message object and put it into the proper queues - virtual void ReceivedMessage( const void *pData, int cbData, int64 nMsgNum, SteamNetworkingMicroseconds usecNow ); + void ReceivedMessage( const void *pData, int cbData, int64 nMsgNum, SteamNetworkingMicroseconds usecNow ); /// Called when the state changes virtual void ConnectionStateChanged( ESteamNetworkingConnectionState eOldState );