//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF //// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO //// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A //// PARTICULAR PURPOSE. //// //// Copyright (c) Microsoft Corporation. All rights reserved #pragma once #include "MeshPacketStructs.h" #include "MeshPacketStatistics.h" #include "MeshConnection.h" #include "MeshEvents.h" #include "MeshThread.h" namespace Microsoft { namespace Xbox { namespace Samples { namespace NetworkMesh { static const int WSARECV_BUFFER_SIZE = 10000; #define SKIPPED_PERCENT 5 // how much ahead do you want to skip to. #define DEFAULT_HEARTBEAT_SIZE 0 struct MESH_PACKET_INFO { Windows::Xbox::Networking::SecureDeviceAssociation^ association; std::vector packetBuffer; }; struct MESH_PACKET_THAT_NEEDS_ACK { std::shared_ptr packetInfo; uint16 messageId; }; public ref class MeshPacketManager sealed { internal: /// /// To get MeshPacketManager, call MeshManger::GetMeshPacketManager() /// /// Local console ID /// This is the sin6_port for the localSockAddress which is used to bind to the socket /// Instance of the mesh manager MeshPacketManager( uint8 localConsoleId, unsigned short portNumberToBindTo, MeshManager^ meshManager, bool dropOutOfOrderPackets ); public: /// /// Get local consoleId /// uint8 GetLocalConsoleId(); MeshPacketStatistics^ GetMeshPacketStatistics(); void UpdateDebugTimers( float timeDelta ); void SendChatMessage( Windows::Xbox::Networking::SecureDeviceAssociation^ association, Windows::Storage::Streams::IBuffer^ buffer, bool sendReliable ); /// /// gameDefinedMessageType is a 0 indexed number that the game can use to identify packet types /// gameDefinedMessageType can be no greater than 192 /// void SendCustomMessage( Windows::Xbox::Networking::SecureDeviceAssociation^ association, uint8 gameDefinedMessageType, Windows::Storage::Streams::IBuffer^ buffer, bool sendReliable ); /// /// Resend packets until ack /// void SendReliablePacketsUntilACK(); float GetDebugTimeSincePacketReceive(); float GetDebugTimeSincePacketSend(); bool GetDebugInsideWSAReceive(); bool GetDebugInsideWSASend(); uint16 GetPreviousPacketMessageId(); event Windows::Foundation::EventHandler^ OnChatMessageReceived; event Windows::Foundation::EventHandler^ OnGameCustomMessageReceived; internal: /// /// The heartbeat is handled internally and shouldn't be called by the game /// void SendHeartbeatMessageAsync( Windows::Xbox::Networking::SecureDeviceAssociation^ association, uint8 consoleId ); /// /// The hello handshake is handled internally and shouldn't be called by the game /// void SendHelloMessage( Windows::Xbox::Networking::SecureDeviceAssociation^ association, Platform::String^ consoleName, bool respondingToHello ); /// /// Sends an ACK for a message ID /// void SendAckMessage( Windows::Xbox::Networking::SecureDeviceAssociation^ association, uint16 messageIdToAck ); void DeleteAllPendingAckMeshPackets(); void SetDropOutOfOrderPackets(bool val); void SetHeartbeatSize(UINT size); UINT GetHeartbeatSize(); UINT16 IncrementPacketMessageId(); event Windows::Foundation::EventHandler^ OnHeartbeatReceived; event Windows::Foundation::EventHandler^ OnHelloReceived; event Windows::Foundation::EventHandler^ OnAckReceived; internal: /// /// The MeshManager ripples the debug event to its own OnDebugMessage so the caller can see debug events in the MeshPacketManager /// event Windows::Foundation::EventHandler^ OnDebugMessage; /// /// Called by the MeshManager when shutting down /// void Shutdown(); private: void GetPacketWithHeader( size_t packetSize, uint8 messageType, std::vector& packetBuffer, bool sendReliable ); void QueuePacketToSend( std::shared_ptr packetInfo ); void ProcessPacket( Microsoft::Xbox::Samples::NetworkMesh::MeshConnection^ meshConnection, BYTE* packetBuffer ); Platform::Array^ ConvertSenderSocketAddressToArray( BYTE* buffer, int bufferSize ); void LogMeshPacketManagerComment( Platform::String^ message ); void LogMeshPacketManagerCommentWithError( Platform::String^ message, HRESULT hr ); bool ShouldPacketBeDropped( Microsoft::Xbox::Samples::NetworkMesh::MeshPacketHeader& packet ); void RecordMessageIfSendingReliable( std::shared_ptr packetInfo ); MeshConnection^ GetMeshConnection( SOCKADDR_STORAGE senderSocketAddress ); void SendReliablePacketsToConsolesWhoHaveNotAcked(); std::vector< std::shared_ptr > GetMeshPacketsThatNeedAckCopy(); void DeleteMeshPacketWhenGotAck(uint16 messageId); void SocketReceiveWorkerThreadDoWork( Microsoft::Xbox::Samples::NetworkMesh::ProcessThreadsEventArgs^ args ); void SocketSendWorkerThreadDoWork( Microsoft::Xbox::Samples::NetworkMesh::ProcessThreadsEventArgs^ args ); void ProcessSendPacket( std::shared_ptr packetInfo ); void SetDebugTimeSincePacketReceive(float val); void SetDebugTimeSincePacketSend(float val); void SetDebugInsideWSAReceive(bool val); void SetDebugInsideWSASend(bool val); void SetPreviousPacketMessageId(uint16 val); private: SOCKET m_localSocket; SOCKADDR_IN6 m_localSockAddress; uint8 m_localConsoleId; LONG m_packetMessageId; uint16 m_previousPacketMessageId; MeshPacketStatistics^ m_meshPacketStatistics; Platform::WeakReference m_meshManager; bool m_dropOutOfOrderPackets; MeshThread^ m_socketReceiveThread; BYTE m_bufferForWSARecv[WSARECV_BUFFER_SIZE]; MeshThread^ m_socketSendThread; Concurrency::critical_section m_sendLock; std::queue< std::shared_ptr > m_packetsToSend; HANDLE m_sendWakeUpEventHandle; Concurrency::critical_section m_debugStatsLock; Concurrency::critical_section m_stateLock; float m_debugTimeSincePacketReceive; float m_debugTimeSincePacketSend; bool m_debugInsideWSAReceive; bool m_debugInsideWSASend; UINT m_heartbeatMessageSize; Concurrency::critical_section m_meshPacketsThatNeedAckLock; std::vector< std::shared_ptr > m_meshPacketsThatNeedAck; LARGE_INTEGER m_timerFrequency; LARGE_INTEGER m_timerLastSendReliablePacketsUntilACK; }; }}}}