From fea263729484ccecff3a598c3623ed40f7ac3ee9 Mon Sep 17 00:00:00 2001 From: Glenn Fiedler Date: Mon, 25 Dec 2023 17:33:09 -0500 Subject: [PATCH] remove old src --- yojimbo.cpp | 75 --- yojimbo.h | 76 --- yojimbo_adapter.h | 127 ---- yojimbo_address.cpp | 340 ---------- yojimbo_address.h | 260 -------- yojimbo_allocator.cpp | 192 ------ yojimbo_allocator.h | 308 --------- yojimbo_base_client.cpp | 278 -------- yojimbo_base_client.h | 165 ----- yojimbo_base_server.cpp | 331 ---------- yojimbo_base_server.h | 141 ----- yojimbo_bit_array.h | 153 ----- yojimbo_channel.cpp | 464 -------------- yojimbo_channel.h | 267 -------- yojimbo_client.cpp | 287 --------- yojimbo_client.h | 116 ---- yojimbo_client_interface.h | 263 -------- yojimbo_config.h | 221 ------- yojimbo_connection.cpp | 371 ----------- yojimbo_connection.h | 90 --- yojimbo_constants.h | 51 -- yojimbo_message.h | 611 ------------------ yojimbo_network_info.h | 50 -- yojimbo_network_simulator.cpp | 173 ----- yojimbo_network_simulator.h | 197 ------ yojimbo_platform.cpp | 201 ------ yojimbo_platform.h | 102 --- yojimbo_queue.h | 194 ------ yojimbo_reliable_ordered_channel.cpp | 766 ----------------------- yojimbo_reliable_ordered_channel.h | 381 ----------- yojimbo_sequence_buffer.h | 277 -------- yojimbo_serialize.h | 181 ------ yojimbo_server.cpp | 267 -------- yojimbo_server.h | 102 --- yojimbo_server_interface.h | 288 --------- yojimbo_unreliable_unordered_channel.cpp | 243 ------- yojimbo_unreliable_unordered_channel.h | 91 --- yojimbo_utils.cpp | 44 -- yojimbo_utils.h | 174 ----- 39 files changed, 8918 deletions(-) delete mode 100644 yojimbo.cpp delete mode 100644 yojimbo.h delete mode 100644 yojimbo_adapter.h delete mode 100644 yojimbo_address.cpp delete mode 100644 yojimbo_address.h delete mode 100644 yojimbo_allocator.cpp delete mode 100644 yojimbo_allocator.h delete mode 100644 yojimbo_base_client.cpp delete mode 100644 yojimbo_base_client.h delete mode 100644 yojimbo_base_server.cpp delete mode 100644 yojimbo_base_server.h delete mode 100644 yojimbo_bit_array.h delete mode 100644 yojimbo_channel.cpp delete mode 100644 yojimbo_channel.h delete mode 100644 yojimbo_client.cpp delete mode 100644 yojimbo_client.h delete mode 100644 yojimbo_client_interface.h delete mode 100644 yojimbo_config.h delete mode 100644 yojimbo_connection.cpp delete mode 100644 yojimbo_connection.h delete mode 100644 yojimbo_constants.h delete mode 100644 yojimbo_message.h delete mode 100644 yojimbo_network_info.h delete mode 100644 yojimbo_network_simulator.cpp delete mode 100644 yojimbo_network_simulator.h delete mode 100644 yojimbo_platform.cpp delete mode 100644 yojimbo_platform.h delete mode 100644 yojimbo_queue.h delete mode 100644 yojimbo_reliable_ordered_channel.cpp delete mode 100644 yojimbo_reliable_ordered_channel.h delete mode 100644 yojimbo_sequence_buffer.h delete mode 100644 yojimbo_serialize.h delete mode 100644 yojimbo_server.cpp delete mode 100644 yojimbo_server.h delete mode 100644 yojimbo_server_interface.h delete mode 100644 yojimbo_unreliable_unordered_channel.cpp delete mode 100644 yojimbo_unreliable_unordered_channel.h delete mode 100644 yojimbo_utils.cpp delete mode 100644 yojimbo_utils.h diff --git a/yojimbo.cpp b/yojimbo.cpp deleted file mode 100644 index c17b4a4a..00000000 --- a/yojimbo.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "yojimbo.h" -#include "yojimbo_utils.h" - -#ifdef _MSC_VER -#define SODIUM_STATIC -#endif // #ifdef _MSC_VER - -#include - -static yojimbo::Allocator * g_defaultAllocator = NULL; - -namespace yojimbo -{ - Allocator & GetDefaultAllocator() - { - yojimbo_assert( g_defaultAllocator ); - return *g_defaultAllocator; - } -} - -extern "C" int netcode_init(); -extern "C" int reliable_init(); -extern "C" void netcode_term(); -extern "C" void reliable_term(); - -#define NETCODE_OK 1 -#define RELIABLE_OK 1 - -bool InitializeYojimbo() -{ - g_defaultAllocator = new yojimbo::DefaultAllocator(); - - if ( netcode_init() != NETCODE_OK ) - return false; - - if ( reliable_init() != RELIABLE_OK ) - return false; - - return sodium_init() != -1; -} - -void ShutdownYojimbo() -{ - reliable_term(); - - netcode_term(); - - yojimbo_assert( g_defaultAllocator ); - delete g_defaultAllocator; - g_defaultAllocator = NULL; -} diff --git a/yojimbo.h b/yojimbo.h deleted file mode 100644 index b440cc84..00000000 --- a/yojimbo.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_H -#define YOJIMBO_H - -#include "serialize.h" -#include "yojimbo_config.h" -#include "yojimbo_constants.h" -#include "yojimbo_bit_array.h" -#include "yojimbo_utils.h" -#include "yojimbo_queue.h" -#include "yojimbo_sequence_buffer.h" -#include "yojimbo_address.h" -#include "yojimbo_serialize.h" -#include "yojimbo_message.h" -#include "yojimbo_channel.h" -#include "yojimbo_reliable_ordered_channel.h" -#include "yojimbo_unreliable_unordered_channel.h" -#include "yojimbo_connection.h" -#include "yojimbo_network_simulator.h" -#include "yojimbo_adapter.h" -#include "yojimbo_network_info.h" -#include "yojimbo_server_interface.h" -#include "yojimbo_base_server.h" -#include "yojimbo_server.h" -#include "yojimbo_client_interface.h" -#include "yojimbo_base_client.h" -#include "yojimbo_client.h" - -/** @file */ - -/// The library namespace. - -namespace yojimbo -{ - using namespace serialize; -} - -/** - Initialize the yojimbo library. - Call this before calling any yojimbo library functions. - @returns True if the library was successfully initialized, false otherwise. - */ - -bool InitializeYojimbo(); - -/** - Shutdown the yojimbo library. - Call this after you finish using the library and it will run some checks for you (for example, checking for memory leaks in debug build). - */ - -void ShutdownYojimbo(); - -#endif // #ifndef YOJIMBO_H diff --git a/yojimbo_adapter.h b/yojimbo_adapter.h deleted file mode 100644 index 7c0065f3..00000000 --- a/yojimbo_adapter.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_ADAPTOR_H -#define YOJIMBO_ADAPTOR_H - -#include "yojimbo_config.h" - -namespace yojimbo -{ - /** - Specifies the message factory and callbacks for clients and servers. - An instance of this class is passed into the client and server constructors. - You can share the same adapter across a client/server pair if you have local multiplayer, eg. loopback. - */ - - class Adapter - { - public: - - virtual ~Adapter() {} - - /** - Override this function to specify your own custom allocator class. - @param allocator The base allocator that must be used to allocate your allocator instance. - @param memory The block of memory backing your allocator. - @param bytes The number of bytes of memory available to your allocator. - @returns A pointer to the allocator instance you created. - */ - - virtual Allocator * CreateAllocator( Allocator & allocator, void * memory, size_t bytes ) - { - return YOJIMBO_NEW( allocator, TLSF_Allocator, memory, bytes ); - } - - /** - You must override this method to create the message factory used by the client and server. - @param allocator The allocator that must be used to create your message factory instance via YOJIMBO_NEW - @returns The message factory pointer you created. - - */ - - virtual MessageFactory * CreateMessageFactory( Allocator & allocator ) - { - (void) allocator; - yojimbo_assert( false ); - return NULL; - } - - /** - Override this callback to process packets sent from client to server over loopback. - @param clientIndex The client index in range [0,maxClients-1] - @param packetData The packet data (raw) to be sent to the server. - @param packetBytes The number of packet bytes in the server. - @param packetSequence The sequence number of the packet. - @see Client::ConnectLoopback - */ - - virtual void ClientSendLoopbackPacket( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) - { - (void) clientIndex; - (void) packetData; - (void) packetBytes; - (void) packetSequence; - yojimbo_assert( false ); - } - - /** - Override this callback to process packets sent from client to server over loopback. - @param clientIndex The client index in range [0,maxClients-1] - @param packetData The packet data (raw) to be sent to the server. - @param packetBytes The number of packet bytes in the server. - @param packetSequence The sequence number of the packet. - @see Server::ConnectLoopbackClient - */ - - virtual void ServerSendLoopbackPacket( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) - { - (void) clientIndex; - (void) packetData; - (void) packetBytes; - (void) packetSequence; - yojimbo_assert( false ); - } - - /** - Override this to get a callback when a client connects on the server. - */ - - virtual void OnServerClientConnected( int clientIndex ) - { - (void) clientIndex; - } - - /** - Override this to get a callback when a client disconnects from the server. - */ - - virtual void OnServerClientDisconnected( int clientIndex ) - { - (void) clientIndex; - } - }; -} - -#endif // #ifndef YOJIMBO_ADAPTOR_H diff --git a/yojimbo_address.cpp b/yojimbo_address.cpp deleted file mode 100644 index 22d411ca..00000000 --- a/yojimbo_address.cpp +++ /dev/null @@ -1,340 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "yojimbo_address.h" -#include "yojimbo_platform.h" - -#if YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_WINDOWS - - #define NOMINMAX - #define _WINSOCK_DEPRECATED_NO_WARNINGS - #include - #include - #include - #pragma comment( lib, "WS2_32.lib" ) - - #ifdef SetPort - #undef SetPort - #endif // #ifdef SetPort - -#elif YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_MAC || YOJIMBO_PLATFORM == YOJIMBO_PLATFORM_UNIX - - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - -#else - - #error yojimbo unknown platform! - -#endif - -#include -#include - -namespace yojimbo -{ - Address::Address() - { - Clear(); - } - - Address::Address( uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port ) - : m_type( ADDRESS_IPV4 ) - { - - m_address.ipv4[0] = a; - m_address.ipv4[1] = b; - m_address.ipv4[2] = c; - m_address.ipv4[3] = d; - m_port = port; - } - - Address::Address( const uint8_t address[], uint16_t port ) - : m_type( ADDRESS_IPV4 ) - { - for ( int i = 0; i < 4; ++i ) - m_address.ipv4[i] = address[i]; - m_port = port; - } - - Address::Address( uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h, uint16_t port ) - : m_type( ADDRESS_IPV6 ) - { - m_address.ipv6[0] = a; - m_address.ipv6[1] = b; - m_address.ipv6[2] = c; - m_address.ipv6[3] = d; - m_address.ipv6[4] = e; - m_address.ipv6[5] = f; - m_address.ipv6[6] = g; - m_address.ipv6[7] = h; - m_port = port; - } - - Address::Address( const uint16_t address[], uint16_t port ) - : m_type( ADDRESS_IPV6 ) - { - for ( int i = 0; i < 8; ++i ) - m_address.ipv6[i] = address[i]; - m_port = port; - } - - Address::Address( const char * address ) - { - Parse( address ); - } - - Address::Address( const char * address, uint16_t port ) - { - Parse( address ); - m_port = port; - } - - void Address::Parse( const char * address_in ) - { - // first try to parse as an IPv6 address: - // 1. if the first character is '[' then it's probably an ipv6 in form "[addr6]:portnum" - // 2. otherwise try to parse as raw IPv6 address, parse using inet_pton - - yojimbo_assert( address_in ); - - char buffer[MaxAddressLength]; - char * address = buffer; - strncpy( address, address_in, MaxAddressLength - 1 ); - address[MaxAddressLength-1] = '\0'; - - int addressLength = (int) strlen( address ); - m_port = 0; - if ( address[0] == '[' ) - { - const int base_index = addressLength - 1; - for ( int i = 0; i < 6; ++i ) // note: no need to search past 6 characters as ":65535" is longest port value - { - const int index = base_index - i; - if ( index < 3 ) - break; - if ( address[index] == ':' ) - { - m_port = uint16_t( atoi( &address[index + 1] ) ); - address[index-1] = '\0'; - } - } - address += 1; - } - struct in6_addr sockaddr6; - if ( inet_pton( AF_INET6, address, &sockaddr6 ) == 1 ) - { - int i; - for ( i = 0; i < 8; ++i ) - { - m_address.ipv6[i] = ntohs( ( (uint16_t*) &sockaddr6 ) [i] ); - } - m_type = ADDRESS_IPV6; - return; - } - - // otherwise it's probably an IPv4 address: - // 1. look for ":portnum", if found save the portnum and strip it out - // 2. parse remaining ipv4 address via inet_pton - - addressLength = (int) strlen( address ); - const int base_index = addressLength - 1; - for ( int i = 0; i < 6; ++i ) - { - const int index = base_index - i; - if ( index < 0 ) - break; - if ( address[index] == ':' ) - { - m_port = (uint16_t) atoi( &address[index+1] ); - address[index] = '\0'; - } - } - - struct sockaddr_in sockaddr4; - if ( inet_pton( AF_INET, address, &sockaddr4.sin_addr ) == 1 ) - { - m_type = ADDRESS_IPV4; - m_address.ipv4[3] = (uint8_t) ( ( sockaddr4.sin_addr.s_addr & 0xFF000000 ) >> 24 ); - m_address.ipv4[2] = (uint8_t) ( ( sockaddr4.sin_addr.s_addr & 0x00FF0000 ) >> 16 ); - m_address.ipv4[1] = (uint8_t) ( ( sockaddr4.sin_addr.s_addr & 0x0000FF00 ) >> 8 ); - m_address.ipv4[0] = (uint8_t) ( ( sockaddr4.sin_addr.s_addr & 0x000000FF ) ); - } - else - { - // Not a valid IPv4 address. Set address as invalid. - Clear(); - } - } - - void Address::Clear() - { - m_type = ADDRESS_NONE; - memset( &m_address, 0, sizeof( m_address ) ); - m_port = 0; - } - - const uint8_t * Address::GetAddress4() const - { - yojimbo_assert( m_type == ADDRESS_IPV4 ); - return m_address.ipv4; - } - - const uint16_t * Address::GetAddress6() const - { - yojimbo_assert( m_type == ADDRESS_IPV6 ); - return m_address.ipv6; - } - - void Address::SetPort( uint16_t port ) - { - m_port = port; - } - - uint16_t Address::GetPort() const - { - return m_port; - } - - AddressType Address::GetType() const - { - return m_type; - } - - const char * Address::ToString( char buffer[], int bufferSize ) const - { - yojimbo_assert( bufferSize >= MaxAddressLength ); - - if ( m_type == ADDRESS_IPV4 ) - { - const uint8_t a = m_address.ipv4[0]; - const uint8_t b = m_address.ipv4[1]; - const uint8_t c = m_address.ipv4[2]; - const uint8_t d = m_address.ipv4[3]; - if ( m_port != 0 ) - snprintf( buffer, bufferSize, "%d.%d.%d.%d:%d", a, b, c, d, m_port ); - else - snprintf( buffer, bufferSize, "%d.%d.%d.%d", a, b, c, d ); - return buffer; - } - else if ( m_type == ADDRESS_IPV6 ) - { - if ( m_port == 0 ) - { - uint16_t address6[8]; - for ( int i = 0; i < 8; ++i ) - address6[i] = ntohs( ((uint16_t*) &m_address.ipv6)[i] ); - inet_ntop( AF_INET6, address6, buffer, bufferSize ); - return buffer; - } - else - { - char addressString[INET6_ADDRSTRLEN]; - uint16_t address6[8]; - for ( int i = 0; i < 8; ++i ) - address6[i] = ntohs( ((uint16_t*) &m_address.ipv6)[i] ); - inet_ntop( AF_INET6, address6, addressString, INET6_ADDRSTRLEN ); - snprintf( buffer, bufferSize, "[%s]:%d", addressString, m_port ); - return buffer; - } - } - else - { - snprintf( buffer, bufferSize, "%s", "NONE" ); - return buffer; - } - } - - bool Address::IsValid() const - { - return m_type != ADDRESS_NONE; - } - - bool Address::IsLinkLocal() const - { - return m_type == ADDRESS_IPV6 && m_address.ipv6[0] == 0xfe80; - } - - bool Address::IsSiteLocal() const - { - return m_type == ADDRESS_IPV6 && m_address.ipv6[0] == 0xfec0; - } - - bool Address::IsMulticast() const - { - return m_type == ADDRESS_IPV6 && m_address.ipv6[0] == 0xff00; - } - - bool Address::IsLoopback() const - { - return ( m_type == ADDRESS_IPV4 && m_address.ipv4[0] == 127 - && m_address.ipv4[1] == 0 - && m_address.ipv4[2] == 0 - && m_address.ipv4[3] == 1 ) - || - ( m_type == ADDRESS_IPV6 && m_address.ipv6[0] == 0 - && m_address.ipv6[1] == 0 - && m_address.ipv6[2] == 0 - && m_address.ipv6[3] == 0 - && m_address.ipv6[4] == 0 - && m_address.ipv6[5] == 0 - && m_address.ipv6[6] == 0 - && m_address.ipv6[7] == 0x0001 ); - } - - bool Address::IsGlobalUnicast() const - { - return m_type == ADDRESS_IPV6 && m_address.ipv6[0] != 0xfe80 - && m_address.ipv6[0] != 0xfec0 - && m_address.ipv6[0] != 0xff00 - && !IsLoopback(); - } - - bool Address::operator ==( const Address & other ) const - { - if ( m_type != other.m_type ) - return false; - if ( m_port != other.m_port ) - return false; - if ( m_type == ADDRESS_IPV4 && memcmp( m_address.ipv4, other.m_address.ipv4, sizeof( m_address.ipv4 ) ) == 0 ) - return true; - else if ( m_type == ADDRESS_IPV6 && memcmp( m_address.ipv6, other.m_address.ipv6, sizeof( m_address.ipv6 ) ) == 0 ) - return true; - else - return false; - } - - bool Address::operator !=( const Address & other ) const - { - return !( *this == other ); - } -} diff --git a/yojimbo_address.h b/yojimbo_address.h deleted file mode 100644 index 1c83614c..00000000 --- a/yojimbo_address.h +++ /dev/null @@ -1,260 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_ADDRESS_H -#define YOJIMBO_ADDRESS_H - -#include "yojimbo_config.h" -#include - -namespace yojimbo -{ - /** - Address type. - @see Address::GetType. - */ - - enum AddressType - { - ADDRESS_NONE, ///< Not an address. Set by the default constructor. - ADDRESS_IPV4, ///< An IPv4 address, eg: "146.95.129.237" - ADDRESS_IPV6 ///< An IPv6 address, eg: "48d9:4a08:b543:ae31:89d8:3226:b92c:cbba" - }; - - /** - An IP address and port number. - Supports both IPv4 and IPv6 addresses. - Identifies where a packet came from, and where a packet should be sent. - */ - - class Address - { - AddressType m_type; ///< The address type: IPv4 or IPv6. - union - { - uint8_t ipv4[4]; ///< IPv4 address data. Valid if type is ADDRESS_IPV4. - uint16_t ipv6[8]; ///< IPv6 address data. Valid if type is ADDRESS_IPV6. - } m_address; - uint16_t m_port; ///< The IP port. Valid for IPv4 and IPv6 address types. - - public: - - /** - Address default constructor. - Designed for convenience so you can have address members of classes and initialize them via assignment. - An address created by the default constructor will have address type set to ADDRESS_NONE. Address::IsValid will return false. - @see IsValid - */ - - Address(); - - /** - Create an IPv4 address. - IMPORTANT: Pass in port in local byte order. The address class handles the conversion to network order for you. - @param a The first field of the IPv4 address. - @param b The second field of the IPv4 address. - @param c The third field of the IPv4 address. - @param d The fourth field of the IPv4 address. - @param port The IPv4 port (local byte order). - */ - - Address( uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint16_t port = 0 ); - - /** - Create an IPv4 address. - @param address Array of four address fields for the IPv4 address. - @param port The port number (local byte order). - */ - - Address( const uint8_t address[], uint16_t port = 0 ); - - /** - Create an IPv6 address. - IMPORTANT: Pass in address fields and the port in local byte order. The address class handles the conversion to network order for you. - @param a First field of the IPv6 address (local byte order). - @param b Second field of the IPv6 address (local byte order). - @param c Third field of the IPv6 address (local byte order). - @param d Fourth field of the IPv6 address (local byte order). - @param e Fifth field of the IPv6 address (local byte order). - @param f Sixth field of the IPv6 address (local byte order). - @param g Seventh field of the IPv6 address (local byte order). - @param h Eighth field of the IPv6 address (local byte order). - @param port The port number (local byte order). - */ - - Address( uint16_t a, uint16_t b, uint16_t c, uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h, uint16_t port = 0 ); - - /** - Create an IPv6 address. - IMPORTANT: Pass in address fields and the port in local byte order. The address class handles the conversion to network order for you. - @param address Array of 8 16 bit address fields for the IPv6 address (local byte order). - @param port The IPv6 port (local byte order). - */ - - Address( const uint16_t address[], uint16_t port = 0 ); - - /** - Parse a string to an address. - This versions supports parsing a port included in the address string. For example, "127.0.0.1:4000" and "[::1]:40000". - Parsing is performed via inet_pton once the port # has been extracted from the string, so you may specify any IPv4 or IPv6 address formatted in any valid way, and it should work as you expect. - Depending on the type of data in the string the address will become ADDRESS_TYPE_IPV4 or ADDRESS_TYPE_IPV6. - If the string is not recognized as a valid address, the address type is set to ADDRESS_TYPE_NONE, causing Address::IsValid to return false. Please check that after creating an address from a string. - @param address The string to parse to create the address. - @see Address::IsValid - @see Address::GetType - */ - - explicit Address( const char * address ); - - /** - Parse a string to an address. - This versions overrides any port read in the address with the port parameter. This lets you parse "127.0.0.1" and "[::1]" and pass in the port you want programmatically. - Parsing is performed via inet_pton once the port # has been extracted from the string, so you may specify any IPv4 or IPv6 address formatted in any valid way, and it should work as you expect. - Depending on the type of data in the string the address will become ADDRESS_TYPE_IPV4 or ADDRESS_TYPE_IPV6. - If the string is not recognized as a valid address, the address type is set to ADDRESS_TYPE_NONE, causing Address::IsValid to return false. Please check that after creating an address from a string. - @param address The string to parse to create the address. - @param port Overrides the port number read from the string (if any). - @see Address::IsValid - @see Address::GetType - */ - - explicit Address( const char * address, uint16_t port ); - - /** - Clear the address. - The address type is set to ADDRESS_TYPE_NONE. - After this function is called Address::IsValid will return false. - */ - - void Clear(); - - /** - Get the IPv4 address data. - @returns The IPv4 address as an array of bytes. - */ - - const uint8_t * GetAddress4() const; - - /** - Get the IPv6 address data. - @returns the IPv6 address data as an array of uint16_t (local byte order). - */ - - const uint16_t * GetAddress6() const; - - /** - Set the port. - This is useful when you want to programmatically set a server port, eg. try to open a server on ports 40000, 40001, etc... - @param port The port number (local byte order). Works for both IPv4 and IPv6 addresses. - */ - - void SetPort( uint16_t port ); - - /** - Get the port number. - @returns The port number (local byte order). - */ - - uint16_t GetPort() const; - - /** - Get the address type. - @returns The address type: ADDRESS_NONE, ADDRESS_IPV4 or ADDRESS_IPV6. - */ - - AddressType GetType() const; - - /** - Convert the address to a string. - @param buffer The buffer the address will be written to. - @param bufferSize The size of the buffer in bytes. Must be at least MaxAddressLength. - */ - - const char * ToString( char buffer[], int bufferSize ) const; - - /** - True if the address is valid. - A valid address is any address with a type other than ADDRESS_TYPE_NONE. - @returns True if the address is valid, false otherwise. - */ - - bool IsValid() const; - - /** - Is this a loopback address? - Corresponds to an IPv4 address of "127.0.0.1", or an IPv6 address of "::1". - @returns True if this is the loopback address. - */ - - bool IsLoopback() const; - - /** - Is this an IPv6 link local address? - Corresponds to the first field of the address being 0xfe80 - @returns True if this address is a link local IPv6 address. - */ - - bool IsLinkLocal() const; - - /** - Is this an IPv6 site local address? - Corresponds to the first field of the address being 0xfec0 - @returns True if this address is a site local IPv6 address. - */ - - bool IsSiteLocal() const; - - /** - Is this an IPv6 multicast address? - Corresponds to the first field of the IPv6 address being 0xff00 - @returns True if this address is a multicast IPv6 address. - */ - - bool IsMulticast() const; - - /** - Is this in IPv6 global unicast address? - Corresponds to any IPv6 address that is not any of the following: Link Local, Site Local, Multicast or Loopback. - @returns True if this is a global unicast IPv6 address. - */ - - bool IsGlobalUnicast() const; - - bool operator ==( const Address & other ) const; - - bool operator !=( const Address & other ) const; - - protected: - - /** - Helper function to parse an address string. - Used by the constructors that take a string parameter. - @param address The string to parse. - */ - - void Parse( const char * address ); - }; -} - -#endif // #ifndef YOJIMBO_ADDRESS_H diff --git a/yojimbo_allocator.cpp b/yojimbo_allocator.cpp deleted file mode 100644 index f7329cc4..00000000 --- a/yojimbo_allocator.cpp +++ /dev/null @@ -1,192 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "yojimbo_config.h" -#include "yojimbo_allocator.h" - -#if YOJIMBO_DEBUG_MEMORY_LEAKS -#include -#endif // #if YOJIMBO_DEBUG_MEMORY_LEAKS - -#include "tlsf/tlsf.h" - -namespace yojimbo -{ - Allocator::Allocator() - { - m_errorLevel = ALLOCATOR_ERROR_NONE; - } - - Allocator::~Allocator() - { -#if YOJIMBO_DEBUG_MEMORY_LEAKS - if ( m_alloc_map.size() ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "you leaked memory!\n\n" ); - typedef std::map::iterator itor_type; - for ( itor_type i = m_alloc_map.begin(); i != m_alloc_map.end(); ++i ) - { - void * p = i->first; - AllocatorEntry entry = i->second; - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "leaked block %p (%d bytes) - %s:%d\n", p, (int) entry.size, entry.file, entry.line ); - } - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "\n" ); - yojimbo_assert( false && "Leaks detected, see log" ); - } -#endif // #if YOJIMBO_DEBUG_MEMORY_LEAKS - } - - void Allocator::SetErrorLevel( AllocatorErrorLevel errorLevel ) - { - if ( m_errorLevel == ALLOCATOR_ERROR_NONE && errorLevel != ALLOCATOR_ERROR_NONE ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "allocator went into error state: %s\n", GetAllocatorErrorString( errorLevel ) ); - } - m_errorLevel = errorLevel; - } - - void Allocator::TrackAlloc( void * p, size_t size, const char * file, int line ) - { -#if YOJIMBO_DEBUG_MEMORY_LEAKS - - yojimbo_assert( m_alloc_map.find( p ) == m_alloc_map.end() ); - - AllocatorEntry entry; - entry.size = size; - entry.file = file; - entry.line = line; - m_alloc_map[p] = entry; - -#else // #if YOJIMBO_DEBUG_MEMORY_LEAKS - - (void) p; - (void) size; - (void) file; - (void) line; - -#endif // #if YOJIMBO_DEBUG_MEMORY_LEAKS - } - - void Allocator::TrackFree( void * p, const char * file, int line ) - { - (void) p; - (void) file; - (void) line; -#if YOJIMBO_DEBUG_MEMORY_LEAKS - yojimbo_assert( m_alloc_map.find( p ) != m_alloc_map.end() ); - m_alloc_map.erase( p ); -#endif // #if YOJIMBO_DEBUG_MEMORY_LEAKS - } - - // ============================================= - - void * DefaultAllocator::Allocate( size_t size, const char * file, int line ) - { - void * p = malloc( size ); - - if ( !p ) - { - SetErrorLevel( ALLOCATOR_ERROR_OUT_OF_MEMORY ); - return NULL; - } - - TrackAlloc( p, size, file, line ); - - return p; - } - - void DefaultAllocator::Free( void * p, const char * file, int line ) - { - if ( !p ) - return; - - TrackFree( p, file, line ); - - free( p ); - } - - // ============================================= - - static void * AlignPointerUp( void * memory, int align ) - { - yojimbo_assert( ( align & ( align - 1 ) ) == 0 ); - uintptr_t p = (uintptr_t) memory; - return (void*) ( ( p + ( align - 1 ) ) & ~( align - 1 ) ); - } - - static void * AlignPointerDown( void * memory, int align ) - { - yojimbo_assert( ( align & ( align - 1 ) ) == 0 ); - uintptr_t p = (uintptr_t) memory; - return (void*) ( p - ( p & ( align - 1 ) ) ); - } - - TLSF_Allocator::TLSF_Allocator( void * memory, size_t size ) - { - yojimbo_assert( size > 0 ); - - SetErrorLevel( ALLOCATOR_ERROR_NONE ); - - const int AlignBytes = 8; - - uint8_t * aligned_memory_start = (uint8_t*) AlignPointerUp( memory, AlignBytes ); - uint8_t * aligned_memory_finish = (uint8_t*) AlignPointerDown( ( (uint8_t*) memory ) + size, AlignBytes ); - - yojimbo_assert( aligned_memory_start < aligned_memory_finish ); - - size_t aligned_memory_size = aligned_memory_finish - aligned_memory_start; - - m_tlsf = tlsf_create_with_pool( aligned_memory_start, aligned_memory_size ); - } - - TLSF_Allocator::~TLSF_Allocator() - { - tlsf_destroy( m_tlsf ); - } - - void * TLSF_Allocator::Allocate( size_t size, const char * file, int line ) - { - void * p = tlsf_memalign( m_tlsf, 16, size ); - - if ( !p ) - { - SetErrorLevel( ALLOCATOR_ERROR_OUT_OF_MEMORY ); - return NULL; - } - - TrackAlloc( p, size, file, line ); - - return p; - } - - void TLSF_Allocator::Free( void * p, const char * file, int line ) - { - if ( !p ) - return; - - TrackFree( p, file, line ); - - tlsf_free( m_tlsf, p ); - } -} diff --git a/yojimbo_allocator.h b/yojimbo_allocator.h deleted file mode 100644 index 400e7300..00000000 --- a/yojimbo_allocator.h +++ /dev/null @@ -1,308 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_ALLOCATOR_H -#define YOJIMBO_ALLOCATOR_H - -#include "yojimbo_config.h" -#include "yojimbo_platform.h" - -#include -#include -#if YOJIMBO_DEBUG_MEMORY_LEAKS -#include -#endif // YOJIMBO_DEBUG_MEMORY_LEAKS - -typedef void* tlsf_t; - -namespace yojimbo -{ - /** - Get the default allocator. - Use this allocator when you just want to use malloc/free, but in the form of a yojimbo allocator. - This allocator instance is created inside InitializeYojimbo and destroyed in ShutdownYojimbo. - In debug build, it will automatically check for memory leaks and print them out for you when you shutdown the library. - @returns The default allocator instances backed by malloc and free. - */ - - class Allocator & GetDefaultAllocator(); - - /// Macro for creating a new object instance with a yojimbo allocator. - #define YOJIMBO_NEW( a, T, ... ) ( new ( (a).Allocate( sizeof(T), __FILE__, __LINE__ ) ) T(__VA_ARGS__) ) - - /// Macro for deleting an object created with a yojimbo allocator. - #define YOJIMBO_DELETE( a, T, p ) do { if (p) { (p)->~T(); (a).Free( p, __FILE__, __LINE__ ); p = NULL; } } while (0) - - /// Macro for allocating a block of memory with a yojimbo allocator. - #define YOJIMBO_ALLOCATE( a, bytes ) (a).Allocate( (bytes), __FILE__, __LINE__ ) - - /// Macro for freeing a block of memory created with a yojimbo allocator. - #define YOJIMBO_FREE( a, p ) do { if ( p ) { (a).Free( p, __FILE__, __LINE__ ); p = NULL; } } while(0) - - /// Allocator error level. - enum AllocatorErrorLevel - { - ALLOCATOR_ERROR_NONE = 0, ///< No error. All is well. - ALLOCATOR_ERROR_OUT_OF_MEMORY ///< The allocator is out of memory! - }; - - /// Helper function to convert an allocator error to a user friendly string. - inline const char * GetAllocatorErrorString( AllocatorErrorLevel error ) - { - switch ( error ) - { - case ALLOCATOR_ERROR_NONE: return "none"; - case ALLOCATOR_ERROR_OUT_OF_MEMORY: return "out of memory"; - default: - yojimbo_assert( false ); - return "(unknown)"; - } - } - -#if YOJIMBO_DEBUG_MEMORY_LEAKS - - /** - Debug structure used to track allocations and find memory leaks. - Active in debug build only. Disabled in release builds for performance reasons. - */ - - struct AllocatorEntry - { - size_t size; ///< The size of the allocation in bytes. - const char * file; ///< Filename of the source code file that made the allocation. - int line; ///< Line number in the source code where the allocation was made. - }; - -#endif // #if YOJIMBO_DEBUG_MEMORY_LEAKS - - /** - Functionality common to all allocators. - Extend this class to hook up your own allocator to yojimbo. - IMPORTANT: This allocator is not yet thread safe. Only call it from one thread! - */ - - class Allocator - { - public: - - /** - Allocator constructor. - Sets the error level to ALLOCATOR_ERROR_NONE. - */ - - Allocator(); - - /** - Allocator destructor. - Make sure all allocations made from this allocator are freed before you destroy this allocator. - In debug build, validates this is true walks the map of allocator entries. Any outstanding entries are considered memory leaks and printed to stdout. - */ - - virtual ~Allocator(); - - /** - Allocate a block of memory. - IMPORTANT: Don't call this directly. Use the YOJIMBO_NEW or YOJIMBO_ALLOCATE macros instead, because they automatically pass in the source filename and line number for you. - @param size The size of the block of memory to allocate (bytes). - @param file The source code filename that is performing the allocation. Used for tracking allocations and reporting on memory leaks. - @param line The line number in the source code file that is performing the allocation. - @returns A block of memory of the requested size, or NULL if the allocation could not be performed. If NULL is returned, the error level is set to ALLOCATION_ERROR_FAILED_TO_ALLOCATE. - @see Allocator::Free - @see Allocator::GetErrorLevel - */ - - virtual void * Allocate( size_t size, const char * file, int line ) = 0; - - /** - Free a block of memory. - IMPORTANT: Don't call this directly. Use the YOJIMBO_DELETE or YOJIMBO_FREE macros instead, because they automatically pass in the source filename and line number for you. - @param p Pointer to the block of memory to free. Must be non-NULL block of memory that was allocated with this allocator. Will assert otherwise. - @param file The source code filename that is performing the free. Used for tracking allocations and reporting on memory leaks. - @param line The line number in the source code file that is performing the free. - @see Allocator::Allocate - @see Allocator::GetErrorLevel - */ - - virtual void Free( void * p, const char * file, int line ) = 0; - - /** - Get the allocator error level. - Use this function to check if an allocation has failed. This is used in the client/server to disconnect a client with a failed allocation. - @returns The allocator error level. - */ - - AllocatorErrorLevel GetErrorLevel() const { return m_errorLevel; } - - /** - Clear the allocator error level back to default. - */ - - void ClearError() { m_errorLevel = ALLOCATOR_ERROR_NONE; } - - protected: - - /** - Set the error level. - For correct client/server behavior when an allocation fails, please make sure you call this method to set the error level to ALLOCATOR_ERROR_FAILED_TO_ALLOCATE. - @param error The allocator error level to set. - */ - - void SetErrorLevel( AllocatorErrorLevel errorLevel ); - - /** - Call this function to track an allocation made by your derived allocator class. - In debug build, tracked allocations are automatically checked for leaks when the allocator is destroyed. - @param p Pointer to the memory that was allocated. - @param size The size of the allocation in bytes. - @param file The source code file that performed the allocation. - @param line The line number in the source file where the allocation was performed. - */ - - void TrackAlloc( void * p, size_t size, const char * file, int line ); - - /** - Call this function to track a free made by your derived allocator class. - In debug build, any allocation tracked without a corresponding free is considered a memory leak when the allocator is destroyed. - @param p Pointer to the memory that was allocated. - @param file The source code file that is calling in to free the memory. - @param line The line number in the source file where the free is being called from. - */ - - void TrackFree( void * p, const char * file, int line ); - - AllocatorErrorLevel m_errorLevel; ///< The allocator error level. - -#if YOJIMBO_DEBUG_MEMORY_LEAKS - std::map m_alloc_map; ///< Debug only data structure used to find and report memory leaks. -#endif // #if YOJIMBO_DEBUG_MEMORY_LEAKS - - private: - - Allocator( const Allocator & other ); - - Allocator & operator = ( const Allocator & other ); - }; - - /** - The default allocator implementation based around malloc and free. - */ - - class DefaultAllocator : public Allocator - { - public: - - /** - Default constructor. - */ - - DefaultAllocator() {} - - /** - Allocates a block of memory using "malloc". - IMPORTANT: Don't call this directly. Use the YOJIMBO_NEW or YOJIMBO_ALLOCATE macros instead, because they automatically pass in the source filename and line number for you. - @param size The size of the block of memory to allocate (bytes). - @param file The source code filename that is performing the allocation. Used for tracking allocations and reporting on memory leaks. - @param line The line number in the source code file that is performing the allocation. - @returns A block of memory of the requested size, or NULL if the allocation could not be performed. If NULL is returned, the error level is set to ALLOCATION_ERROR_FAILED_TO_ALLOCATE. - */ - - void * Allocate( size_t size, const char * file, int line ); - - /** - Free a block of memory by calling "free". - IMPORTANT: Don't call this directly. Use the YOJIMBO_DELETE or YOJIMBO_FREE macros instead, because they automatically pass in the source filename and line number for you. - @param p Pointer to the block of memory to free. Must be non-NULL block of memory that was allocated with this allocator. Will assert otherwise. - @param file The source code filename that is performing the free. Used for tracking allocations and reporting on memory leaks. - @param line The line number in the source code file that is performing the free. - */ - - void Free( void * p, const char * file, int line ); - - private: - - DefaultAllocator( const DefaultAllocator & other ); - - DefaultAllocator & operator = ( const DefaultAllocator & other ); - }; - - /** - An allocator built on the TLSF allocator implementation by Matt Conte. Thanks Matt! - This is a fast allocator that supports multiple heaps. It's used inside the yojimbo server to silo allocations for each client to their own heap. - See https://github.com/mattconte/tlsf for details on this allocator implementation. - */ - - class TLSF_Allocator : public Allocator - { - public: - - /** - TLSF allocator constructor. - If you want to integrate your own allocator with yojimbo for use with the client and server, this class is a good template to start from. - Make sure your constructor has the same signature as this one, and it will work with the YOJIMBO_SERVER_ALLOCATOR and YOJIMBO_CLIENT_ALLOCATOR helper macros. - @param memory Block of memory in which the allocator will work. This block must remain valid while this allocator exists. The allocator does not assume ownership of it, you must free it elsewhere, if necessary. - @param bytes The size of the block of memory (bytes). The maximum amount of memory you can allocate will be less, due to allocator overhead. - */ - - TLSF_Allocator( void * memory, size_t bytes ); - - /** - TLSF allocator destructor. - Checks for memory leaks in debug build. Free all memory allocated by this allocator before destroying. - */ - - ~TLSF_Allocator(); - - /** - Allocates a block of memory using TLSF. - IMPORTANT: Don't call this directly. Use the YOJIMBO_NEW or YOJIMBO_ALLOCATE macros instead, because they automatically pass in the source filename and line number for you. - @param size The size of the block of memory to allocate (bytes). - @param file The source code filename that is performing the allocation. Used for tracking allocations and reporting on memory leaks. - @param line The line number in the source code file that is performing the allocation. - @returns A block of memory of the requested size, or NULL if the allocation could not be performed. If NULL is returned, the error level is set to ALLOCATION_ERROR_FAILED_TO_ALLOCATE. - */ - - void * Allocate( size_t size, const char * file, int line ); - - /** - Free a block of memory using TLSF. - IMPORTANT: Don't call this directly. Use the YOJIMBO_DELETE or YOJIMBO_FREE macros instead, because they automatically pass in the source filename and line number for you. - @param p Pointer to the block of memory to free. Must be non-NULL block of memory that was allocated with this allocator. Will assert otherwise. - @param file The source code filename that is performing the free. Used for tracking allocations and reporting on memory leaks. - @param line The line number in the source code file that is performing the free. - @see Allocator::Allocate - @see Allocator::GetError - */ - - void Free( void * p, const char * file, int line ); - - private: - - tlsf_t m_tlsf; ///< The TLSF allocator instance backing this allocator. - - TLSF_Allocator( const TLSF_Allocator & other ); - TLSF_Allocator & operator = ( const TLSF_Allocator & other ); - }; -} - -#endif // # YOJIMBO_PLATFORM_H diff --git a/yojimbo_base_client.cpp b/yojimbo_base_client.cpp deleted file mode 100644 index ec477bc8..00000000 --- a/yojimbo_base_client.cpp +++ /dev/null @@ -1,278 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "yojimbo_base_client.h" -#include "yojimbo_allocator.h" -#include "yojimbo_connection.h" -#include "yojimbo_network_simulator.h" -#include "yojimbo_adapter.h" -#include "reliable.h" - -namespace yojimbo -{ - BaseClient::BaseClient( Allocator & allocator, const ClientServerConfig & config, Adapter & adapter, double time ) : m_config( config ) - { - m_allocator = &allocator; - m_adapter = &adapter; - m_time = time; - m_context = NULL; - m_clientMemory = NULL; - m_clientAllocator = NULL; - m_endpoint = NULL; - m_connection = NULL; - m_messageFactory = NULL; - m_networkSimulator = NULL; - m_clientState = CLIENT_STATE_DISCONNECTED; - m_clientIndex = -1; - m_packetBuffer = (uint8_t*) YOJIMBO_ALLOCATE( allocator, config.maxPacketSize ); - } - - BaseClient::~BaseClient() - { - // IMPORTANT: Please disconnect the client before destroying it - yojimbo_assert( m_clientState <= CLIENT_STATE_DISCONNECTED ); - YOJIMBO_FREE( *m_allocator, m_packetBuffer ); - m_allocator = NULL; - } - - void BaseClient::Disconnect() - { - SetClientState( CLIENT_STATE_DISCONNECTED ); - } - - void BaseClient::AdvanceTime( double time ) - { - m_time = time; - if ( m_endpoint ) - { - m_connection->AdvanceTime( time ); - if ( m_connection->GetErrorLevel() != CONNECTION_ERROR_NONE ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_DEBUG, "connection error. disconnecting client\n" ); - Disconnect(); - return; - } - reliable_endpoint_update( m_endpoint, m_time ); - int numAcks; - const uint16_t * acks = reliable_endpoint_get_acks( m_endpoint, &numAcks ); - m_connection->ProcessAcks( acks, numAcks ); - reliable_endpoint_clear_acks( m_endpoint ); - } - NetworkSimulator * networkSimulator = GetNetworkSimulator(); - if ( networkSimulator ) - { - networkSimulator->AdvanceTime( time ); - } - } - - void BaseClient::SetLatency( float milliseconds ) - { - if ( m_networkSimulator ) - { - m_networkSimulator->SetLatency( milliseconds ); - } - } - - void BaseClient::SetJitter( float milliseconds ) - { - if ( m_networkSimulator ) - { - m_networkSimulator->SetJitter( milliseconds ); - } - } - - void BaseClient::SetPacketLoss( float percent ) - { - if ( m_networkSimulator ) - { - m_networkSimulator->SetPacketLoss( percent ); - } - } - - void BaseClient::SetDuplicates( float percent ) - { - if ( m_networkSimulator ) - { - m_networkSimulator->SetDuplicates( percent ); - } - } - - void BaseClient::SetClientState( ClientState clientState ) - { - m_clientState = clientState; - } - - void BaseClient::CreateInternal() - { - yojimbo_assert( m_allocator ); - yojimbo_assert( m_adapter ); - yojimbo_assert( m_clientMemory == NULL ); - yojimbo_assert( m_clientAllocator == NULL ); - yojimbo_assert( m_messageFactory == NULL ); - m_clientMemory = (uint8_t*) YOJIMBO_ALLOCATE( *m_allocator, m_config.clientMemory ); - m_clientAllocator = m_adapter->CreateAllocator( *m_allocator, m_clientMemory, m_config.clientMemory ); - m_messageFactory = m_adapter->CreateMessageFactory( *m_clientAllocator ); - m_connection = YOJIMBO_NEW( *m_clientAllocator, Connection, *m_clientAllocator, *m_messageFactory, m_config, m_time ); - yojimbo_assert( m_connection ); - if ( m_config.networkSimulator ) - { - m_networkSimulator = YOJIMBO_NEW( *m_clientAllocator, NetworkSimulator, *m_clientAllocator, m_config.maxSimulatorPackets, m_time ); - } - reliable_config_t reliable_config; - reliable_default_config( &reliable_config ); - strcpy( reliable_config.name, "client endpoint" ); - reliable_config.context = (void*) this; - reliable_config.max_packet_size = m_config.maxPacketSize; - reliable_config.fragment_above = m_config.fragmentPacketsAbove; - reliable_config.max_fragments = m_config.maxPacketFragments; - reliable_config.fragment_size = m_config.packetFragmentSize; - reliable_config.ack_buffer_size = m_config.ackedPacketsBufferSize; - reliable_config.received_packets_buffer_size = m_config.receivedPacketsBufferSize; - reliable_config.fragment_reassembly_buffer_size = m_config.packetReassemblyBufferSize; - reliable_config.rtt_smoothing_factor = m_config.rttSmoothingFactor; - reliable_config.transmit_packet_function = BaseClient::StaticTransmitPacketFunction; - reliable_config.process_packet_function = BaseClient::StaticProcessPacketFunction; - reliable_config.allocator_context = m_clientAllocator; - reliable_config.allocate_function = BaseClient::StaticAllocateFunction; - reliable_config.free_function = BaseClient::StaticFreeFunction; - m_endpoint = reliable_endpoint_create( &reliable_config, m_time ); - reliable_endpoint_reset( m_endpoint ); - } - - void BaseClient::DestroyInternal() - { - yojimbo_assert( m_allocator ); - if ( m_endpoint ) - { - reliable_endpoint_destroy( m_endpoint ); - m_endpoint = NULL; - } - YOJIMBO_DELETE( *m_clientAllocator, NetworkSimulator, m_networkSimulator ); - YOJIMBO_DELETE( *m_clientAllocator, Connection, m_connection ); - YOJIMBO_DELETE( *m_clientAllocator, MessageFactory, m_messageFactory ); - YOJIMBO_DELETE( *m_allocator, Allocator, m_clientAllocator ); - YOJIMBO_FREE( *m_allocator, m_clientMemory ); - } - - void BaseClient::StaticTransmitPacketFunction( void * context, int index, uint16_t packetSequence, uint8_t * packetData, int packetBytes ) - { - (void) index; - BaseClient * client = (BaseClient*) context; - client->TransmitPacketFunction( packetSequence, packetData, packetBytes ); - } - - int BaseClient::StaticProcessPacketFunction( void * context, int index, uint16_t packetSequence, uint8_t * packetData, int packetBytes ) - { - (void) index; - BaseClient * client = (BaseClient*) context; - return client->ProcessPacketFunction( packetSequence, packetData, packetBytes ); - } - - void * BaseClient::StaticAllocateFunction( void * context, uint64_t bytes ) - { - yojimbo_assert( context ); - Allocator * allocator = (Allocator*) context; - return YOJIMBO_ALLOCATE( *allocator, bytes ); - } - - void BaseClient::StaticFreeFunction( void * context, void * pointer ) - { - yojimbo_assert( context ); - yojimbo_assert( pointer ); - Allocator * allocator = (Allocator*) context; - YOJIMBO_FREE( *allocator, pointer ); - } - - Message * BaseClient::CreateMessage( int type ) - { - yojimbo_assert( m_messageFactory ); - return m_messageFactory->CreateMessage( type ); - } - - uint8_t * BaseClient::AllocateBlock( int bytes ) - { - return (uint8_t*) YOJIMBO_ALLOCATE( *m_clientAllocator, bytes ); - } - - void BaseClient::AttachBlockToMessage( Message * message, uint8_t * block, int bytes ) - { - yojimbo_assert( message ); - yojimbo_assert( block ); - yojimbo_assert( bytes > 0 ); - yojimbo_assert( message->IsBlockMessage() ); - BlockMessage * blockMessage = (BlockMessage*) message; - blockMessage->AttachBlock( *m_clientAllocator, block, bytes ); - } - - void BaseClient::FreeBlock( uint8_t * block ) - { - YOJIMBO_FREE( *m_clientAllocator, block ); - } - - bool BaseClient::CanSendMessage( int channelIndex ) const - { - yojimbo_assert( m_connection ); - return m_connection->CanSendMessage( channelIndex ); - } - - bool BaseClient::HasMessagesToSend( int channelIndex ) const - { - yojimbo_assert( m_connection ); - return m_connection->HasMessagesToSend( channelIndex ); - } - - void BaseClient::SendMessage( int channelIndex, Message * message ) - { - yojimbo_assert( m_connection ); - m_connection->SendMessage( channelIndex, message, GetContext() ); - } - - Message * BaseClient::ReceiveMessage( int channelIndex ) - { - yojimbo_assert( m_connection ); - return m_connection->ReceiveMessage( channelIndex ); - } - - void BaseClient::ReleaseMessage( Message * message ) - { - yojimbo_assert( m_connection ); - m_connection->ReleaseMessage( message ); - } - - void BaseClient::GetNetworkInfo( NetworkInfo & info ) const - { - memset( &info, 0, sizeof( info ) ); - if ( m_connection ) - { - yojimbo_assert( m_endpoint ); - const uint64_t * counters = reliable_endpoint_counters( m_endpoint ); - info.numPacketsSent = counters[RELIABLE_ENDPOINT_COUNTER_NUM_PACKETS_SENT]; - info.numPacketsReceived = counters[RELIABLE_ENDPOINT_COUNTER_NUM_PACKETS_RECEIVED]; - info.numPacketsAcked = counters[RELIABLE_ENDPOINT_COUNTER_NUM_PACKETS_ACKED]; - info.RTT = reliable_endpoint_rtt( m_endpoint ); - info.packetLoss = reliable_endpoint_packet_loss( m_endpoint ); - reliable_endpoint_bandwidth( m_endpoint, &info.sentBandwidth, &info.receivedBandwidth, &info.ackedBandwidth ); - } - } -} diff --git a/yojimbo_base_client.h b/yojimbo_base_client.h deleted file mode 100644 index bbaf31ac..00000000 --- a/yojimbo_base_client.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_BASE_CLIENT_H -#define YOJIMBO_BASE_CLIENT_H - -#include "yojimbo_config.h" -#include "yojimbo_platform.h" -#include "yojimbo_client_interface.h" - -struct reliable_endpoint_t; - -namespace yojimbo -{ - /** - Functionality that is common across all client implementations. - */ - - class BaseClient : public ClientInterface - { - public: - - /** - Base client constructor. - @param allocator The allocator for all memory used by the client. - @param config The base client/server configuration. - @param time The current time in seconds. See ClientInterface::AdvanceTime - @param allocator The adapter to the game program. Specifies allocators, message factory to use etc. - */ - - explicit BaseClient( class Allocator & allocator, const ClientServerConfig & config, class Adapter & adapter, double time ); - - ~BaseClient(); - - void SetContext( void * context ) { yojimbo_assert( IsDisconnected() ); m_context = context; } - - void Disconnect(); - - void AdvanceTime( double time ); - - bool IsConnecting() const { return m_clientState == CLIENT_STATE_CONNECTING; } - - bool IsConnected() const { return m_clientState == CLIENT_STATE_CONNECTED; } - - bool IsDisconnected() const { return m_clientState <= CLIENT_STATE_DISCONNECTED; } - - bool ConnectionFailed() const { return m_clientState == CLIENT_STATE_ERROR; } - - ClientState GetClientState() const { return m_clientState; } - - int GetClientIndex() const { return m_clientIndex; } - - double GetTime() const { return m_time; } - - void SetLatency( float milliseconds ); - - void SetJitter( float milliseconds ); - - void SetPacketLoss( float percent ); - - void SetDuplicates( float percent ); - - Message * CreateMessage( int type ); - - uint8_t * AllocateBlock( int bytes ); - - void AttachBlockToMessage( Message * message, uint8_t * block, int bytes ); - - void FreeBlock( uint8_t * block ); - - bool CanSendMessage( int channelIndex ) const; - - bool HasMessagesToSend( int channelIndex ) const; - - void SendMessage( int channelIndex, Message * message ); - - Message * ReceiveMessage( int channelIndex ); - - void ReleaseMessage( Message * message ); - - void GetNetworkInfo( NetworkInfo & info ) const; - - protected: - - uint8_t * GetPacketBuffer() { return m_packetBuffer; } - - void * GetContext() { return m_context; } - - Adapter & GetAdapter() { yojimbo_assert( m_adapter ); return *m_adapter; } - - void CreateInternal(); - - void DestroyInternal(); - - void SetClientState( ClientState clientState ); - - class Allocator & GetClientAllocator() { yojimbo_assert( m_clientAllocator ); return *m_clientAllocator; } - - class MessageFactory & GetMessageFactory() { yojimbo_assert( m_messageFactory ); return *m_messageFactory; } - - class NetworkSimulator * GetNetworkSimulator() { return m_networkSimulator; } - - reliable_endpoint_t * GetEndpoint() { return m_endpoint; } - - class Connection & GetConnection() { yojimbo_assert( m_connection ); return *m_connection; } - - virtual void TransmitPacketFunction( uint16_t packetSequence, uint8_t * packetData, int packetBytes ) = 0; - - virtual int ProcessPacketFunction( uint16_t packetSequence, uint8_t * packetData, int packetBytes ) = 0; - - static void StaticTransmitPacketFunction( void * context, int index, uint16_t packetSequence, uint8_t * packetData, int packetBytes ); - - static int StaticProcessPacketFunction( void * context, int index, uint16_t packetSequence, uint8_t * packetData, int packetBytes ); - - static void * StaticAllocateFunction( void * context, uint64_t bytes ); - - static void StaticFreeFunction( void * context, void * pointer ); - - private: - - ClientServerConfig m_config; ///< The client/server configuration. - Allocator * m_allocator; ///< The allocator passed to the client on creation. - Adapter * m_adapter; ///< The adapter specifies the allocator to use, and the message factory class. - void * m_context; ///< Context lets the user pass information to packet serialize functions. - uint8_t * m_clientMemory; ///< The memory backing the client allocator. Allocated from m_allocator. - Allocator * m_clientAllocator; ///< The client allocator. Everything allocated between connect and disconnected is allocated and freed via this allocator. - reliable_endpoint_t * m_endpoint; ///< reliable endpoint. - MessageFactory * m_messageFactory; ///< The client message factory. Created and destroyed on each connection attempt. - Connection * m_connection; ///< The client connection for exchanging messages with the server. - NetworkSimulator * m_networkSimulator; ///< The network simulator used to simulate packet loss, latency, jitter etc. Optional. - ClientState m_clientState; ///< The current client state. See ClientInterface::GetClientState - int m_clientIndex; ///< The client slot index on the server [0,maxClients-1]. -1 if not connected. - double m_time; ///< The current client time. See ClientInterface::AdvanceTime - uint8_t * m_packetBuffer; ///< Buffer used to read and write packets. - - private: - - BaseClient( const BaseClient & other ); - - const BaseClient & operator = ( const BaseClient & other ); - }; -} - -#endif // #ifndef YOJIMBO_BASE_CLIENT_H diff --git a/yojimbo_base_server.cpp b/yojimbo_base_server.cpp deleted file mode 100644 index 7d49c9db..00000000 --- a/yojimbo_base_server.cpp +++ /dev/null @@ -1,331 +0,0 @@ -#include "yojimbo_base_server.h" -#include "yojimbo_adapter.h" -#include "yojimbo_network_simulator.h" -#include "yojimbo_connection.h" -#include "yojimbo_network_info.h" -#include "reliable.h" - -namespace yojimbo -{ - BaseServer::BaseServer( Allocator & allocator, const ClientServerConfig & config, Adapter & adapter, double time ) : m_config( config ) - { - m_allocator = &allocator; - m_adapter = &adapter; - m_context = NULL; - m_time = time; - m_running = false; - m_maxClients = 0; - m_globalMemory = NULL; - m_globalAllocator = NULL; - for ( int i = 0; i < MaxClients; ++i ) - { - m_clientMemory[i] = NULL; - m_clientAllocator[i] = NULL; - m_clientMessageFactory[i] = NULL; - m_clientConnection[i] = NULL; - m_clientEndpoint[i] = NULL; - } - m_networkSimulator = NULL; - m_packetBuffer = NULL; - } - - BaseServer::~BaseServer() - { - // IMPORTANT: Please stop the server before destroying it! - yojimbo_assert( !IsRunning () ); - m_allocator = NULL; - } - - void BaseServer::SetContext( void * context ) - { - yojimbo_assert( !IsRunning() ); - m_context = context; - } - - void BaseServer::Start( int maxClients ) - { - Stop(); - m_running = true; - m_maxClients = maxClients; - yojimbo_assert( !m_globalMemory ); - yojimbo_assert( !m_globalAllocator ); - m_globalMemory = (uint8_t*) YOJIMBO_ALLOCATE( *m_allocator, m_config.serverGlobalMemory ); - m_globalAllocator = m_adapter->CreateAllocator( *m_allocator, m_globalMemory, m_config.serverGlobalMemory ); - yojimbo_assert( m_globalAllocator ); - if ( m_config.networkSimulator ) - { - m_networkSimulator = YOJIMBO_NEW( *m_globalAllocator, NetworkSimulator, *m_globalAllocator, m_config.maxSimulatorPackets, m_time ); - } - for ( int i = 0; i < m_maxClients; ++i ) - { - yojimbo_assert( !m_clientMemory[i] ); - yojimbo_assert( !m_clientAllocator[i] ); - - m_clientMemory[i] = (uint8_t*) YOJIMBO_ALLOCATE( *m_allocator, m_config.serverPerClientMemory ); - m_clientAllocator[i] = m_adapter->CreateAllocator( *m_allocator, m_clientMemory[i], m_config.serverPerClientMemory ); - yojimbo_assert( m_clientAllocator[i] ); - - m_clientMessageFactory[i] = m_adapter->CreateMessageFactory( *m_clientAllocator[i] ); - yojimbo_assert( m_clientMessageFactory[i] ); - - m_clientConnection[i] = YOJIMBO_NEW( *m_clientAllocator[i], Connection, *m_clientAllocator[i], *m_clientMessageFactory[i], m_config, m_time ); - yojimbo_assert( m_clientConnection[i] ); - - reliable_config_t reliable_config; - reliable_default_config( &reliable_config ); - strcpy( reliable_config.name, "server endpoint" ); - reliable_config.context = (void*) this; - reliable_config.index = i; - reliable_config.max_packet_size = m_config.maxPacketSize; - reliable_config.fragment_above = m_config.fragmentPacketsAbove; - reliable_config.max_fragments = m_config.maxPacketFragments; - reliable_config.fragment_size = m_config.packetFragmentSize; - reliable_config.ack_buffer_size = m_config.ackedPacketsBufferSize; - reliable_config.received_packets_buffer_size = m_config.receivedPacketsBufferSize; - reliable_config.fragment_reassembly_buffer_size = m_config.packetReassemblyBufferSize; - reliable_config.rtt_smoothing_factor = m_config.rttSmoothingFactor; - reliable_config.transmit_packet_function = BaseServer::StaticTransmitPacketFunction; - reliable_config.process_packet_function = BaseServer::StaticProcessPacketFunction; - reliable_config.allocator_context = &GetGlobalAllocator(); - reliable_config.allocate_function = BaseServer::StaticAllocateFunction; - reliable_config.free_function = BaseServer::StaticFreeFunction; - m_clientEndpoint[i] = reliable_endpoint_create( &reliable_config, m_time ); - reliable_endpoint_reset( m_clientEndpoint[i] ); - } - m_packetBuffer = (uint8_t*) YOJIMBO_ALLOCATE( *m_globalAllocator, m_config.maxPacketSize ); - } - - void BaseServer::Stop() - { - if ( IsRunning() ) - { - YOJIMBO_FREE( *m_globalAllocator, m_packetBuffer ); - yojimbo_assert( m_globalMemory ); - yojimbo_assert( m_globalAllocator ); - YOJIMBO_DELETE( *m_globalAllocator, NetworkSimulator, m_networkSimulator ); - for ( int i = 0; i < m_maxClients; ++i ) - { - yojimbo_assert( m_clientMemory[i] ); - yojimbo_assert( m_clientAllocator[i] ); - yojimbo_assert( m_clientMessageFactory[i] ); - yojimbo_assert( m_clientEndpoint[i] ); - reliable_endpoint_destroy( m_clientEndpoint[i] ); m_clientEndpoint[i] = NULL; - YOJIMBO_DELETE( *m_clientAllocator[i], Connection, m_clientConnection[i] ); - YOJIMBO_DELETE( *m_clientAllocator[i], MessageFactory, m_clientMessageFactory[i] ); - YOJIMBO_DELETE( *m_allocator, Allocator, m_clientAllocator[i] ); - YOJIMBO_FREE( *m_allocator, m_clientMemory[i] ); - } - YOJIMBO_DELETE( *m_allocator, Allocator, m_globalAllocator ); - YOJIMBO_FREE( *m_allocator, m_globalMemory ); - } - m_running = false; - m_maxClients = 0; - m_packetBuffer = NULL; - } - - void BaseServer::AdvanceTime( double time ) - { - m_time = time; - if ( IsRunning() ) - { - for ( int i = 0; i < m_maxClients; ++i ) - { - m_clientConnection[i]->AdvanceTime( time ); - if ( m_clientConnection[i]->GetErrorLevel() != CONNECTION_ERROR_NONE ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "client %d connection is in error state. disconnecting client\n", m_clientConnection[i]->GetErrorLevel() ); - DisconnectClient( i ); - continue; - } - reliable_endpoint_update( m_clientEndpoint[i], m_time ); - int numAcks; - const uint16_t * acks = reliable_endpoint_get_acks( m_clientEndpoint[i], &numAcks ); - m_clientConnection[i]->ProcessAcks( acks, numAcks ); - reliable_endpoint_clear_acks( m_clientEndpoint[i] ); - } - NetworkSimulator * networkSimulator = GetNetworkSimulator(); - if ( networkSimulator ) - { - networkSimulator->AdvanceTime( time ); - } - } - } - - void BaseServer::SetLatency( float milliseconds ) - { - if ( m_networkSimulator ) - { - m_networkSimulator->SetLatency( milliseconds ); - } - } - - void BaseServer::SetJitter( float milliseconds ) - { - if ( m_networkSimulator ) - { - m_networkSimulator->SetJitter( milliseconds ); - } - } - - void BaseServer::SetPacketLoss( float percent ) - { - if ( m_networkSimulator ) - { - m_networkSimulator->SetPacketLoss( percent ); - } - } - - void BaseServer::SetDuplicates( float percent ) - { - if ( m_networkSimulator ) - { - m_networkSimulator->SetDuplicates( percent ); - } - } - - Message * BaseServer::CreateMessage( int clientIndex, int type ) - { - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - yojimbo_assert( m_clientMessageFactory[clientIndex] ); - return m_clientMessageFactory[clientIndex]->CreateMessage( type ); - } - - uint8_t * BaseServer::AllocateBlock( int clientIndex, int bytes ) - { - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - yojimbo_assert( m_clientAllocator[clientIndex] ); - return (uint8_t*) YOJIMBO_ALLOCATE( *m_clientAllocator[clientIndex], bytes ); - } - - void BaseServer::AttachBlockToMessage( int clientIndex, Message * message, uint8_t * block, int bytes ) - { - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - yojimbo_assert( message ); - yojimbo_assert( block ); - yojimbo_assert( bytes > 0 ); - yojimbo_assert( message->IsBlockMessage() ); - BlockMessage * blockMessage = (BlockMessage*) message; - blockMessage->AttachBlock( *m_clientAllocator[clientIndex], block, bytes ); - } - - void BaseServer::FreeBlock( int clientIndex, uint8_t * block ) - { - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - YOJIMBO_FREE( *m_clientAllocator[clientIndex], block ); - } - - bool BaseServer::CanSendMessage( int clientIndex, int channelIndex ) const - { - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - yojimbo_assert( m_clientConnection[clientIndex] ); - return m_clientConnection[clientIndex]->CanSendMessage( channelIndex ); - } - - bool BaseServer::HasMessagesToSend( int clientIndex, int channelIndex ) const - { - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - yojimbo_assert( m_clientConnection[clientIndex] ); - return m_clientConnection[clientIndex]->HasMessagesToSend( channelIndex ); - } - - void BaseServer::SendMessage( int clientIndex, int channelIndex, Message * message ) - { - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - yojimbo_assert( m_clientConnection[clientIndex] ); - return m_clientConnection[clientIndex]->SendMessage( channelIndex, message, GetContext() ); - } - - Message * BaseServer::ReceiveMessage( int clientIndex, int channelIndex ) - { - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - yojimbo_assert( m_clientConnection[clientIndex] ); - return m_clientConnection[clientIndex]->ReceiveMessage( channelIndex ); - } - - void BaseServer::ReleaseMessage( int clientIndex, Message * message ) - { - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - yojimbo_assert( m_clientConnection[clientIndex] ); - m_clientConnection[clientIndex]->ReleaseMessage( message ); - } - - void BaseServer::GetNetworkInfo( int clientIndex, NetworkInfo & info ) const - { - yojimbo_assert( IsRunning() ); - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - memset( &info, 0, sizeof( info ) ); - if ( IsClientConnected( clientIndex ) ) - { - yojimbo_assert( m_clientEndpoint[clientIndex] ); - const uint64_t * counters = reliable_endpoint_counters( m_clientEndpoint[clientIndex] ); - info.numPacketsSent = counters[RELIABLE_ENDPOINT_COUNTER_NUM_PACKETS_SENT]; - info.numPacketsReceived = counters[RELIABLE_ENDPOINT_COUNTER_NUM_PACKETS_RECEIVED]; - info.numPacketsAcked = counters[RELIABLE_ENDPOINT_COUNTER_NUM_PACKETS_ACKED]; - info.RTT = reliable_endpoint_rtt( m_clientEndpoint[clientIndex] ); - info.packetLoss = reliable_endpoint_packet_loss( m_clientEndpoint[clientIndex] ); - reliable_endpoint_bandwidth( m_clientEndpoint[clientIndex], &info.sentBandwidth, &info.receivedBandwidth, &info.ackedBandwidth ); - } - } - - MessageFactory & BaseServer::GetClientMessageFactory( int clientIndex ) - { - yojimbo_assert( IsRunning() ); - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - return *m_clientMessageFactory[clientIndex]; - } - - reliable_endpoint_t * BaseServer::GetClientEndpoint( int clientIndex ) - { - yojimbo_assert( IsRunning() ); - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - return m_clientEndpoint[clientIndex]; - } - - Connection & BaseServer::GetClientConnection( int clientIndex ) - { - yojimbo_assert( IsRunning() ); - yojimbo_assert( clientIndex >= 0 ); - yojimbo_assert( clientIndex < m_maxClients ); - yojimbo_assert( m_clientConnection[clientIndex] ); - return *m_clientConnection[clientIndex]; - } - - void BaseServer::StaticTransmitPacketFunction( void * context, int index, uint16_t packetSequence, uint8_t * packetData, int packetBytes ) - { - BaseServer * server = (BaseServer*) context; - server->TransmitPacketFunction( index, packetSequence, packetData, packetBytes ); - } - - int BaseServer::StaticProcessPacketFunction( void * context, int index, uint16_t packetSequence, uint8_t * packetData, int packetBytes ) - { - BaseServer * server = (BaseServer*) context; - return server->ProcessPacketFunction( index, packetSequence, packetData, packetBytes ); - } - - void * BaseServer::StaticAllocateFunction( void * context, uint64_t bytes ) - { - yojimbo_assert( context ); - Allocator * allocator = (Allocator*) context; - return YOJIMBO_ALLOCATE( *allocator, bytes ); - } - - void BaseServer::StaticFreeFunction( void * context, void * pointer ) - { - yojimbo_assert( context ); - yojimbo_assert( pointer ); - Allocator * allocator = (Allocator*) context; - YOJIMBO_FREE( *allocator, pointer ); - } -} diff --git a/yojimbo_base_server.h b/yojimbo_base_server.h deleted file mode 100644 index f1ae113d..00000000 --- a/yojimbo_base_server.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_BASE_SERVER_H -#define YOJIMBO_BASE_SERVER_H - -#include "yojimbo_config.h" -#include "yojimbo_allocator.h" -#include "yojimbo_server_interface.h" - -struct reliable_endpoint_t; - -namespace yojimbo -{ - /** - Common functionality across all server implementations. - */ - - class BaseServer : public ServerInterface - { - public: - - BaseServer( Allocator & allocator, const ClientServerConfig & config, class Adapter & adapter, double time ); - - ~BaseServer(); - - void SetContext( void * context ); - - void Start( int maxClients ); - - void Stop(); - - void AdvanceTime( double time ); - - bool IsRunning() const { return m_running; } - - int GetMaxClients() const { return m_maxClients; } - - double GetTime() const { return m_time; } - - void SetLatency( float milliseconds ); - - void SetJitter( float milliseconds ); - - void SetPacketLoss( float percent ); - - void SetDuplicates( float percent ); - - Message * CreateMessage( int clientIndex, int type ); - - uint8_t * AllocateBlock( int clientIndex, int bytes ); - - void AttachBlockToMessage( int clientIndex, Message * message, uint8_t * block, int bytes ); - - void FreeBlock( int clientIndex, uint8_t * block ); - - bool CanSendMessage( int clientIndex, int channelIndex ) const; - - bool HasMessagesToSend( int clientIndex, int channelIndex ) const; - - void SendMessage( int clientIndex, int channelIndex, Message * message ); - - Message * ReceiveMessage( int clientIndex, int channelIndex ); - - void ReleaseMessage( int clientIndex, Message * message ); - - void GetNetworkInfo( int clientIndex, NetworkInfo & info ) const; - - protected: - - uint8_t * GetPacketBuffer() { return m_packetBuffer; } - - void * GetContext() { return m_context; } - - Adapter & GetAdapter() { yojimbo_assert( m_adapter ); return *m_adapter; } - - Allocator & GetGlobalAllocator() { yojimbo_assert( m_globalAllocator ); return *m_globalAllocator; } - - class MessageFactory & GetClientMessageFactory( int clientIndex ); - - class NetworkSimulator * GetNetworkSimulator() { return m_networkSimulator; } - - reliable_endpoint_t * GetClientEndpoint( int clientIndex ); - - class Connection & GetClientConnection( int clientIndex ); - - virtual void TransmitPacketFunction( int clientIndex, uint16_t packetSequence, uint8_t * packetData, int packetBytes ) = 0; - - virtual int ProcessPacketFunction( int clientIndex, uint16_t packetSequence, uint8_t * packetData, int packetBytes ) = 0; - - static void StaticTransmitPacketFunction( void * context, int index, uint16_t packetSequence, uint8_t * packetData, int packetBytes ); - - static int StaticProcessPacketFunction( void * context,int index, uint16_t packetSequence, uint8_t * packetData, int packetBytes ); - - static void * StaticAllocateFunction( void * context, uint64_t bytes ); - - static void StaticFreeFunction( void * context, void * pointer ); - - private: - - ClientServerConfig m_config; ///< Base client/server config. - Allocator * m_allocator; ///< Allocator passed in to constructor. - Adapter * m_adapter; ///< The adapter specifies the allocator to use, and the message factory class. - void * m_context; ///< Optional serialization context. - int m_maxClients; ///< Maximum number of clients supported. - bool m_running; ///< True if server is currently running, eg. after "Start" is called, before "Stop". - double m_time; ///< Current server time in seconds. - uint8_t * m_globalMemory; ///< The block of memory backing the global allocator. Allocated with m_allocator. - uint8_t * m_clientMemory[MaxClients]; ///< The block of memory backing the per-client allocators. Allocated with m_allocator. - Allocator * m_globalAllocator; ///< The global allocator. Used for allocations that don't belong to a specific client. - Allocator * m_clientAllocator[MaxClients]; ///< Array of per-client allocator. These are used for allocations related to connected clients. - MessageFactory * m_clientMessageFactory[MaxClients]; ///< Array of per-client message factories. This silos message allocations per-client slot. - Connection * m_clientConnection[MaxClients]; ///< Array of per-client connection classes. This is how messages are exchanged with clients. - reliable_endpoint_t * m_clientEndpoint[MaxClients]; ///< Array of per-client reliable endpoints. - NetworkSimulator * m_networkSimulator; ///< The network simulator used to simulate packet loss, latency, jitter etc. Optional. - uint8_t * m_packetBuffer; ///< Buffer used when writing packets. - }; -} - -#endif // #ifndef YOJIMBO_BASE_SERVER_H diff --git a/yojimbo_bit_array.h b/yojimbo_bit_array.h deleted file mode 100644 index b08aa5ba..00000000 --- a/yojimbo_bit_array.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_BIT_ARRAY_H -#define YOJIMBO_BIT_ARRAY_H - -#include "yojimbo_config.h" -#include "yojimbo_allocator.h" - -namespace yojimbo -{ - class Allocator; - - /** - A simple bit array class. - You can create a bit array with a number of bits, set, clear and test if each bit is set. - */ - - class BitArray - { - public: - - /** - The bit array constructor. - @param allocator The allocator to use. - @param size The number of bits in the bit array. - All bits are initially set to zero. - */ - - BitArray( Allocator & allocator, int size ) - { - yojimbo_assert( size > 0 ); - m_allocator = &allocator; - m_size = size; - m_bytes = 8 * ( ( size / 64 ) + ( ( size % 64 ) ? 1 : 0 ) ); - yojimbo_assert( m_bytes > 0 ); - m_data = (uint64_t*) YOJIMBO_ALLOCATE( allocator, m_bytes ); - Clear(); - } - - /** - The bit array destructor. - */ - - ~BitArray() - { - yojimbo_assert( m_data ); - yojimbo_assert( m_allocator ); - YOJIMBO_FREE( *m_allocator, m_data ); - m_allocator = NULL; - } - - /** - Clear all bit values to zero. - */ - - void Clear() - { - yojimbo_assert( m_data ); - memset( m_data, 0, m_bytes ); - } - - /** - Set a bit to 1. - @param index The index of the bit. - */ - - void SetBit( int index ) - { - yojimbo_assert( index >= 0 ); - yojimbo_assert( index < m_size ); - const int data_index = index >> 6; - const int bit_index = index & ( (1<<6) - 1 ); - yojimbo_assert( bit_index >= 0 ); - yojimbo_assert( bit_index < 64 ); - m_data[data_index] |= uint64_t(1) << bit_index; - } - - /** - Clear a bit to 0. - @param index The index of the bit. - */ - - void ClearBit( int index ) - { - yojimbo_assert( index >= 0 ); - yojimbo_assert( index < m_size ); - const int data_index = index >> 6; - const int bit_index = index & ( (1<<6) - 1 ); - m_data[data_index] &= ~( uint64_t(1) << bit_index ); - } - - /** - Get the value of the bit. - Returns 1 if the bit is set, 0 if the bit is not set. - @param index The index of the bit. - */ - - uint64_t GetBit( int index ) const - { - yojimbo_assert( index >= 0 ); - yojimbo_assert( index < m_size ); - const int data_index = index >> 6; - const int bit_index = index & ( (1<<6) - 1 ); - yojimbo_assert( bit_index >= 0 ); - yojimbo_assert( bit_index < 64 ); - return ( m_data[data_index] >> bit_index ) & 1; - } - - /** - Gets the size of the bit array, in number of bits. - @returns The number of bits. - */ - - int GetSize() const - { - return m_size; - } - - private: - - Allocator * m_allocator; ///< Allocator passed in to the constructor. - int m_size; ///< The size of the bit array in bits. - int m_bytes; ///< The size of the bit array in bytes. - uint64_t * m_data; ///< The data backing the bit array is an array of 64 bit integer values. - - BitArray( const BitArray & other ); - BitArray & operator = ( const BitArray & other ); - }; -} - -#endif // #ifndef YOJIMBO_BIT_ARRAY_H diff --git a/yojimbo_channel.cpp b/yojimbo_channel.cpp deleted file mode 100644 index 2d34129b..00000000 --- a/yojimbo_channel.cpp +++ /dev/null @@ -1,464 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "yojimbo_channel.h" - -namespace yojimbo -{ - void ChannelPacketData::Initialize() - { - channelIndex = 0; - blockMessage = 0; - messageFailedToSerialize = 0; - message.numMessages = 0; - initialized = 1; - } - - void ChannelPacketData::Free( MessageFactory & messageFactory ) - { - yojimbo_assert( initialized ); - Allocator & allocator = messageFactory.GetAllocator(); - if ( !blockMessage ) - { - if ( message.numMessages > 0 ) - { - for ( int i = 0; i < message.numMessages; ++i ) - { - if ( message.messages[i] ) - { - messageFactory.ReleaseMessage( message.messages[i] ); - } - } - YOJIMBO_FREE( allocator, message.messages ); - } - } - else - { - if ( block.message ) - { - messageFactory.ReleaseMessage( block.message ); - block.message = NULL; - } - YOJIMBO_FREE( allocator, block.fragmentData ); - } - initialized = 0; - } - - template bool SerializeOrderedMessages( Stream & stream, - MessageFactory & messageFactory, - int & numMessages, - Message ** & messages, - int maxMessagesPerPacket ) - { - const int maxMessageType = messageFactory.GetNumTypes() - 1; - - bool hasMessages = Stream::IsWriting && numMessages != 0; - - serialize_bool( stream, hasMessages ); - - if ( hasMessages ) - { - serialize_int( stream, numMessages, 1, maxMessagesPerPacket ); - - int * messageTypes = (int*) alloca( sizeof( int ) * numMessages ); - - uint16_t * messageIds = (uint16_t*) alloca( sizeof( uint16_t ) * numMessages ); - - memset( messageTypes, 0, sizeof( int ) * numMessages ); - memset( messageIds, 0, sizeof( uint16_t ) * numMessages ); - - if ( Stream::IsWriting ) - { - yojimbo_assert( messages ); - - for ( int i = 0; i < numMessages; ++i ) - { - yojimbo_assert( messages[i] ); - messageTypes[i] = messages[i]->GetType(); - messageIds[i] = messages[i]->GetId(); - } - } - else - { - Allocator & allocator = messageFactory.GetAllocator(); - - messages = (Message**) YOJIMBO_ALLOCATE( allocator, sizeof( Message* ) * numMessages ); - - for ( int i = 0; i < numMessages; ++i ) - { - messages[i] = NULL; - } - } - - serialize_bits( stream, messageIds[0], 16 ); - - for ( int i = 1; i < numMessages; ++i ) - serialize_sequence_relative( stream, messageIds[i-1], messageIds[i] ); - - for ( int i = 0; i < numMessages; ++i ) - { - if ( maxMessageType > 0 ) - { - serialize_int( stream, messageTypes[i], 0, maxMessageType ); - } - else - { - messageTypes[i] = 0; - } - - if ( Stream::IsReading ) - { - messages[i] = messageFactory.CreateMessage( messageTypes[i] ); - - if ( !messages[i] ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to create message of type %d (SerializeOrderedMessages)\n", messageTypes[i] ); - return false; - } - - messages[i]->SetId( messageIds[i] ); - } - - yojimbo_assert( messages[i] ); - - if ( !messages[i]->SerializeInternal( stream ) ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to serialize message of type %d (SerializeOrderedMessages)\n", messageTypes[i] ); - return false; - } - } - } - - return true; - } - - template bool SerializeUnorderedMessages( Stream & stream, - MessageFactory & messageFactory, - int & numMessages, - Message ** & messages, - int maxMessagesPerPacket, - int maxBlockSize ) - { - const int maxMessageType = messageFactory.GetNumTypes() - 1; - - bool hasMessages = Stream::IsWriting && numMessages != 0; - - serialize_bool( stream, hasMessages ); - - if ( hasMessages ) - { - serialize_int( stream, numMessages, 1, maxMessagesPerPacket ); - - int * messageTypes = (int*) alloca( sizeof( int ) * numMessages ); - - memset( messageTypes, 0, sizeof( int ) * numMessages ); - - if ( Stream::IsWriting ) - { - yojimbo_assert( messages ); - - for ( int i = 0; i < numMessages; ++i ) - { - yojimbo_assert( messages[i] ); - messageTypes[i] = messages[i]->GetType(); - } - } - else - { - Allocator & allocator = messageFactory.GetAllocator(); - - messages = (Message**) YOJIMBO_ALLOCATE( allocator, sizeof( Message* ) * numMessages ); - - for ( int i = 0; i < numMessages; ++i ) - messages[i] = NULL; - } - - for ( int i = 0; i < numMessages; ++i ) - { - if ( maxMessageType > 0 ) - { - serialize_int( stream, messageTypes[i], 0, maxMessageType ); - } - else - { - messageTypes[i] = 0; - } - - if ( Stream::IsReading ) - { - messages[i] = messageFactory.CreateMessage( messageTypes[i] ); - - if ( !messages[i] ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to create message type %d (SerializeUnorderedMessages)\n", messageTypes[i] ); - return false; - } - } - - yojimbo_assert( messages[i] ); - - if ( !messages[i]->SerializeInternal( stream ) ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to serialize message type %d (SerializeUnorderedMessages)\n", messageTypes[i] ); - return false; - } - - if ( messages[i]->IsBlockMessage() ) - { - BlockMessage * blockMessage = (BlockMessage*) messages[i]; - if ( !SerializeMessageBlock( stream, messageFactory, blockMessage, maxBlockSize ) ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to serialize message block (SerializeUnorderedMessages)\n" ); - return false; - } - } - } - } - - return true; - } - - template bool SerializeBlockFragment( Stream & stream, - MessageFactory & messageFactory, - ChannelPacketData::BlockData & block, - const ChannelConfig & channelConfig ) - { - const int maxMessageType = messageFactory.GetNumTypes() - 1; - - if (Stream::IsReading) - { - block.message = NULL; - block.fragmentData = NULL; - } - - serialize_bits( stream, block.messageId, 16 ); - - if ( channelConfig.GetMaxFragmentsPerBlock() > 1 ) - { - serialize_int( stream, block.numFragments, 1, channelConfig.GetMaxFragmentsPerBlock() ); - } - else - { - if ( Stream::IsReading ) - block.numFragments = 1; - } - - if ( block.numFragments > 1 ) - { - serialize_int( stream, block.fragmentId, 0, block.numFragments - 1 ); - } - else - { - if ( Stream::IsReading ) - block.fragmentId = 0; - } - - serialize_int( stream, block.fragmentSize, 1, channelConfig.blockFragmentSize ); - - if ( Stream::IsReading ) - { - block.fragmentData = (uint8_t*) YOJIMBO_ALLOCATE( messageFactory.GetAllocator(), block.fragmentSize ); - - if ( !block.fragmentData ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to serialize block fragment (SerializeBlockFragment)\n" ); - return false; - } - } - - serialize_bytes( stream, block.fragmentData, block.fragmentSize ); - - if ( block.fragmentId == 0 ) - { - // block message - - if ( maxMessageType > 0 ) - { - serialize_int( stream, block.messageType, 0, maxMessageType ); - } - else - { - block.messageType = 0; - } - - if ( Stream::IsReading ) - { - Message * message = messageFactory.CreateMessage( block.messageType ); - - if ( !message ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to create block message type %d (SerializeBlockFragment)\n", block.messageType ); - return false; - } - - if ( !message->IsBlockMessage() ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: received block fragment attached to non-block message (SerializeBlockFragment)\n" ); - return false; - } - - block.message = (BlockMessage*) message; - } - - yojimbo_assert( block.message ); - - if ( !block.message->SerializeInternal( stream ) ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to serialize block message of type %d (SerializeBlockFragment)\n", block.messageType ); - return false; - } - } - - return true; - } - - template bool ChannelPacketData::Serialize( Stream & stream, - MessageFactory & messageFactory, - const ChannelConfig * channelConfigs, - int numChannels ) - { - yojimbo_assert( initialized ); - -#if YOJIMBO_DEBUG_MESSAGE_BUDGET - int startBits = stream.GetBitsProcessed(); -#endif // #if YOJIMBO_DEBUG_MESSAGE_BUDGET - - if ( numChannels > 1 ) - serialize_int( stream, channelIndex, 0, numChannels - 1 ); - else - channelIndex = 0; - - const ChannelConfig & channelConfig = channelConfigs[channelIndex]; - - serialize_bool( stream, blockMessage ); - - if ( !blockMessage ) - { - switch ( channelConfig.type ) - { - case CHANNEL_TYPE_RELIABLE_ORDERED: - { - if ( !SerializeOrderedMessages( stream, messageFactory, message.numMessages, message.messages, channelConfig.maxMessagesPerPacket ) ) - { - messageFailedToSerialize = 1; - return true; - } - } - break; - - case CHANNEL_TYPE_UNRELIABLE_UNORDERED: - { - if ( !SerializeUnorderedMessages( stream, - messageFactory, - message.numMessages, - message.messages, - channelConfig.maxMessagesPerPacket, - channelConfig.maxBlockSize ) ) - { - messageFailedToSerialize = 1; - return true; - } - } - break; - } - -#if YOJIMBO_DEBUG_MESSAGE_BUDGET - if ( channelConfig.packetBudget > 0 ) - { - yojimbo_assert( stream.GetBitsProcessed() - startBits <= channelConfig.packetBudget * 8 ); - } -#endif // #if YOJIMBO_DEBUG_MESSAGE_BUDGET - } - else - { - if ( channelConfig.disableBlocks ) - return false; - - if ( !SerializeBlockFragment( stream, messageFactory, block, channelConfig ) ) - return false; - } - - return true; - } - - bool ChannelPacketData::SerializeInternal( ReadStream & stream, MessageFactory & messageFactory, const ChannelConfig * channelConfigs, int numChannels ) - { - return Serialize( stream, messageFactory, channelConfigs, numChannels ); - } - - bool ChannelPacketData::SerializeInternal( WriteStream & stream, MessageFactory & messageFactory, const ChannelConfig * channelConfigs, int numChannels ) - { - return Serialize( stream, messageFactory, channelConfigs, numChannels ); - } - - bool ChannelPacketData::SerializeInternal( MeasureStream & stream, MessageFactory & messageFactory, const ChannelConfig * channelConfigs, int numChannels ) - { - return Serialize( stream, messageFactory, channelConfigs, numChannels ); - } - - // ------------------------------------------------------------------------------------ - - Channel::Channel( Allocator & allocator, MessageFactory & messageFactory, const ChannelConfig & config, int channelIndex, double time ) : m_config( config ) - { - yojimbo_assert( channelIndex >= 0 ); - yojimbo_assert( channelIndex < MaxChannels ); - m_channelIndex = channelIndex; - m_allocator = &allocator; - m_messageFactory = &messageFactory; - m_errorLevel = CHANNEL_ERROR_NONE; - m_time = time; - ResetCounters(); - } - - uint64_t Channel::GetCounter( int index ) const - { - yojimbo_assert( index >= 0 ); - yojimbo_assert( index < CHANNEL_COUNTER_NUM_COUNTERS ); - return m_counters[index]; - } - - void Channel::ResetCounters() - { - memset( m_counters, 0, sizeof( m_counters ) ); - } - - int Channel::GetChannelIndex() const - { - return m_channelIndex; - } - - void Channel::SetErrorLevel( ChannelErrorLevel errorLevel ) - { - if ( errorLevel != m_errorLevel && errorLevel != CHANNEL_ERROR_NONE ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "channel went into error state: %s\n", GetChannelErrorString( errorLevel ) ); - } - m_errorLevel = errorLevel; - } - - ChannelErrorLevel Channel::GetErrorLevel() const - { - return m_errorLevel; - } -} diff --git a/yojimbo_channel.h b/yojimbo_channel.h deleted file mode 100644 index 55b35055..00000000 --- a/yojimbo_channel.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_CHANNEL_H -#define YOJIMBO_CHANNEL_H - -#include "yojimbo_config.h" -#include "yojimbo_message.h" - -namespace yojimbo -{ - struct ChannelPacketData - { - uint32_t channelIndex : 16; - uint32_t initialized : 1; - uint32_t blockMessage : 1; - uint32_t messageFailedToSerialize : 1; - - struct MessageData - { - int numMessages; - Message ** messages; - }; - - struct BlockData - { - BlockMessage * message; - uint8_t * fragmentData; - uint64_t messageId : 16; - uint64_t fragmentId : 16; - uint64_t fragmentSize : 16; - uint64_t numFragments : 16; - int messageType; - }; - - union - { - MessageData message; - BlockData block; - }; - - void Initialize(); - - void Free( MessageFactory & messageFactory ); - - template bool Serialize( Stream & stream, MessageFactory & messageFactory, const ChannelConfig * channelConfigs, int numChannels ); - - bool SerializeInternal( ReadStream & stream, MessageFactory & messageFactory, const ChannelConfig * channelConfigs, int numChannels ); - - bool SerializeInternal( WriteStream & stream, MessageFactory & messageFactory, const ChannelConfig * channelConfigs, int numChannels ); - - bool SerializeInternal( MeasureStream & stream, MessageFactory & messageFactory, const ChannelConfig * channelConfigs, int numChannels ); - }; - - /** - Channel counters provide insight into the number of times an action was performed by a channel. - They are intended for use in a telemetry system, eg. reported to some backend logging system to track behavior in a production environment. - */ - - enum ChannelCounters - { - CHANNEL_COUNTER_MESSAGES_SENT, ///< Number of messages sent over this channel. - CHANNEL_COUNTER_MESSAGES_RECEIVED, ///< Number of messages received over this channel. - CHANNEL_COUNTER_NUM_COUNTERS ///< The number of channel counters. - }; - - /** - Channel error level. - If the channel gets into an error state, it sets an error state on the corresponding connection. See yojimbo::CONNECTION_ERROR_CHANNEL. - This way if any channel on a client/server connection gets into a bad state, that client is automatically kicked from the server. - @see Client - @see Server - @see Connection - */ - - enum ChannelErrorLevel - { - CHANNEL_ERROR_NONE = 0, ///< No error. All is well. - CHANNEL_ERROR_DESYNC, ///< This channel has desynced. This means that the connection protocol has desynced and cannot recover. The client should be disconnected. - CHANNEL_ERROR_SEND_QUEUE_FULL, ///< The user tried to send a message but the send queue was full. This will assert out in development, but in production it sets this error on the channel. - CHANNEL_ERROR_BLOCKS_DISABLED, ///< The channel received a packet containing data for blocks, but this channel is configured to disable blocks. See ChannelConfig::disableBlocks. - CHANNEL_ERROR_FAILED_TO_SERIALIZE, ///< Serialize read failed for a message sent to this channel. Check your message serialize functions, one of them is returning false on serialize read. This can also be caused by a desync in message read and write. - CHANNEL_ERROR_OUT_OF_MEMORY, ///< The channel tried to allocate some memory but couldn't. - }; - - /// Helper function to convert a channel error to a user friendly string. - - inline const char * GetChannelErrorString( ChannelErrorLevel error ) - { - switch ( error ) - { - case CHANNEL_ERROR_NONE: return "none"; - case CHANNEL_ERROR_DESYNC: return "desync"; - case CHANNEL_ERROR_SEND_QUEUE_FULL: return "send queue full"; - case CHANNEL_ERROR_OUT_OF_MEMORY: return "out of memory"; - case CHANNEL_ERROR_BLOCKS_DISABLED: return "blocks disabled"; - case CHANNEL_ERROR_FAILED_TO_SERIALIZE: return "failed to serialize"; - default: - yojimbo_assert( false ); - return "(unknown)"; - } - } - - /// Common functionality shared across all channel types. - - class Channel - { - public: - - /** - Channel constructor. - */ - - Channel( Allocator & allocator, MessageFactory & messageFactory, const ChannelConfig & config, int channelIndex, double time ); - - /** - Channel destructor. - */ - - virtual ~Channel() {} - - /** - Reset the channel. - */ - - virtual void Reset() = 0; - - /** - Returns true if a message can be sent over this channel. - */ - - virtual bool CanSendMessage() const = 0; - - /** - Are there any messages in the send queue? - @returns True if there is at least one message in the send queue. - */ - - virtual bool HasMessagesToSend() const = 0; - - /** - Queue a message to be sent across this channel. - @param message The message to be sent. - */ - - virtual void SendMessage( Message * message, void *context) = 0; - - /** - Pops the next message off the receive queue if one is available. - @returns A pointer to the received message, NULL if there are no messages to receive. The caller owns the message object returned by this function and is responsible for releasing it via Message::Release. - */ - - virtual Message * ReceiveMessage() = 0; - - /** - Advance channel time. - Called by Connection::AdvanceTime for each channel configured on the connection. - */ - - virtual void AdvanceTime( double time ) = 0; - - /** - Get channel packet data for this channel. - @param packetData The channel packet data to be filled [out] - @param packetSequence The sequence number of the packet being generated. - @param availableBits The maximum number of bits of packet data the channel is allowed to write. - @returns The number of bits of packet data written by the channel. - @see ConnectionPacket - @see Connection::GeneratePacket - */ - - virtual int GetPacketData( void *context, ChannelPacketData & packetData, uint16_t packetSequence, int availableBits) = 0; - - /** - Process packet data included in a connection packet. - @param packetData The channel packet data to process. - @param packetSequence The sequence number of the connection packet that contains the channel packet data. - @see ConnectionPacket - @see Connection::ProcessPacket - */ - - virtual void ProcessPacketData( const ChannelPacketData & packetData, uint16_t packetSequence ) = 0; - - /** - Process a connection packet ack. - Depending on the channel type: - 1. Acks messages and block fragments so they stop being included in outgoing connection packets (reliable-ordered channel), - 2. Does nothing at all (unreliable-unordered). - @param sequence The sequence number of the connection packet that was acked. - */ - - virtual void ProcessAck( uint16_t sequence ) = 0; - - public: - - /** - Get the channel error level. - @returns The channel error level. - */ - - ChannelErrorLevel GetErrorLevel() const; - - /** - Gets the channel index. - @returns The channel index in [0,numChannels-1]. - */ - - int GetChannelIndex() const; - - /** - Get a counter value. - @param index The index of the counter to retrieve. See ChannelCounters. - @returns The value of the counter. - @see ResetCounters - */ - - uint64_t GetCounter( int index ) const; - - /** - Resets all counter values to zero. - */ - - void ResetCounters(); - - protected: - - /** - Set the channel error level. - All errors go through this function to make debug logging easier. - */ - - void SetErrorLevel( ChannelErrorLevel errorLevel ); - - protected: - - const ChannelConfig m_config; ///< Channel configuration data. - Allocator * m_allocator; ///< Allocator for allocations matching life cycle of this channel. - int m_channelIndex; ///< The channel index in [0,numChannels-1]. - double m_time; ///< The current time. - ChannelErrorLevel m_errorLevel; ///< The channel error level. - MessageFactory * m_messageFactory; ///< Message factory for creating and destroying messages. - uint64_t m_counters[CHANNEL_COUNTER_NUM_COUNTERS]; ///< Counters for unit testing, stats etc. - }; -} - -#endif // #ifndef YOJIMBO_CHANNEL_H diff --git a/yojimbo_client.cpp b/yojimbo_client.cpp deleted file mode 100644 index 67223b1d..00000000 --- a/yojimbo_client.cpp +++ /dev/null @@ -1,287 +0,0 @@ -#include "yojimbo_client.h" -#include "yojimbo_connection.h" -#include "yojimbo_network_simulator.h" -#include "yojimbo_adapter.h" -#include "netcode.h" -#include "reliable.h" - -namespace yojimbo -{ - Client::Client( Allocator & allocator, const Address & address, const ClientServerConfig & config, Adapter & adapter, double time ) - : BaseClient( allocator, config, adapter, time ), m_config( config ), m_address( address ) - { - m_clientId = 0; - m_client = NULL; - m_boundAddress = m_address; - } - - Client::~Client() - { - // IMPORTANT: Please disconnect the client before destroying it - yojimbo_assert( m_client == NULL ); - } - - void Client::InsecureConnect( const uint8_t privateKey[], uint64_t clientId, const Address & address ) - { - InsecureConnect( privateKey, clientId, &address, 1 ); - } - - void Client::InsecureConnect( const uint8_t privateKey[], uint64_t clientId, const Address serverAddresses[], int numServerAddresses ) - { - yojimbo_assert( serverAddresses ); - yojimbo_assert( numServerAddresses > 0 ); - yojimbo_assert( numServerAddresses <= NETCODE_MAX_SERVERS_PER_CONNECT ); - Disconnect(); - CreateInternal(); - m_clientId = clientId; - CreateClient( m_address ); - if ( !m_client ) - { - Disconnect(); - return; - } - uint8_t connectToken[NETCODE_CONNECT_TOKEN_BYTES]; - if ( !GenerateInsecureConnectToken( connectToken, privateKey, clientId, serverAddresses, numServerAddresses ) ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to generate insecure connect token\n" ); - SetClientState( CLIENT_STATE_ERROR ); - return; - } - netcode_client_connect( m_client, connectToken ); - SetClientState( CLIENT_STATE_CONNECTING ); - } - - bool Client::GenerateInsecureConnectToken( uint8_t * connectToken, - const uint8_t privateKey[], - uint64_t clientId, - const Address serverAddresses[], - int numServerAddresses ) - { - char serverAddressStrings[NETCODE_MAX_SERVERS_PER_CONNECT][MaxAddressLength]; - const char * serverAddressStringPointers[NETCODE_MAX_SERVERS_PER_CONNECT]; - for ( int i = 0; i < numServerAddresses; ++i ) - { - serverAddresses[i].ToString( serverAddressStrings[i], MaxAddressLength ); - serverAddressStringPointers[i] = serverAddressStrings[i]; - } - - uint8_t userData[256]; - memset( &userData, 0, sizeof(userData) ); - - return netcode_generate_connect_token( numServerAddresses, - serverAddressStringPointers, - serverAddressStringPointers, - m_config.timeout, - m_config.timeout, - clientId, - m_config.protocolId, - (uint8_t*)privateKey, - &userData[0], - connectToken ) == NETCODE_OK; - } - - void Client::Connect( uint64_t clientId, uint8_t * connectToken ) - { - yojimbo_assert( connectToken ); - Disconnect(); - CreateInternal(); - m_clientId = clientId; - CreateClient( m_address ); - netcode_client_connect( m_client, connectToken ); - if ( netcode_client_state( m_client ) > NETCODE_CLIENT_STATE_DISCONNECTED ) - { - SetClientState( CLIENT_STATE_CONNECTING ); - } - else - { - Disconnect(); - } - } - - void Client::Disconnect() - { - BaseClient::Disconnect(); - DestroyClient(); - DestroyInternal(); - m_clientId = 0; - } - - void Client::SendPackets() - { - if ( !IsConnected() ) - return; - yojimbo_assert( m_client ); - uint8_t * packetData = GetPacketBuffer(); - int packetBytes; - uint16_t packetSequence = reliable_endpoint_next_packet_sequence( GetEndpoint() ); - if ( GetConnection().GeneratePacket( GetContext(), packetSequence, packetData, m_config.maxPacketSize, packetBytes ) ) - { - reliable_endpoint_send_packet( GetEndpoint(), packetData, packetBytes ); - } - } - - void Client::ReceivePackets() - { - if ( !IsConnected() ) - return; - yojimbo_assert( m_client ); - while ( true ) - { - int packetBytes; - uint64_t packetSequence; - uint8_t * packetData = netcode_client_receive_packet( m_client, &packetBytes, &packetSequence ); - if ( !packetData ) - break; - reliable_endpoint_receive_packet( GetEndpoint(), packetData, packetBytes ); - netcode_client_free_packet( m_client, packetData ); - } - } - - void Client::AdvanceTime( double time ) - { - BaseClient::AdvanceTime( time ); - if ( m_client ) - { - netcode_client_update( m_client, time ); - const int state = netcode_client_state( m_client ); - if ( state < NETCODE_CLIENT_STATE_DISCONNECTED ) - { - Disconnect(); - SetClientState( CLIENT_STATE_ERROR ); - } - else if ( state == NETCODE_CLIENT_STATE_DISCONNECTED ) - { - Disconnect(); - SetClientState( CLIENT_STATE_DISCONNECTED ); - } - else if ( state == NETCODE_CLIENT_STATE_SENDING_CONNECTION_REQUEST || state == NETCODE_CLIENT_STATE_SENDING_CONNECTION_RESPONSE ) - { - SetClientState( CLIENT_STATE_CONNECTING ); - } - else - { - SetClientState( CLIENT_STATE_CONNECTED ); - } - NetworkSimulator * networkSimulator = GetNetworkSimulator(); - if ( networkSimulator && networkSimulator->IsActive() ) - { - uint8_t ** packetData = (uint8_t**) alloca( sizeof( uint8_t*) * m_config.maxSimulatorPackets ); - int * packetBytes = (int*) alloca( sizeof(int) * m_config.maxSimulatorPackets ); - int numPackets = networkSimulator->ReceivePackets( m_config.maxSimulatorPackets, packetData, packetBytes, NULL ); - for ( int i = 0; i < numPackets; ++i ) - { - netcode_client_send_packet( m_client, (uint8_t*) packetData[i], packetBytes[i] ); - YOJIMBO_FREE( networkSimulator->GetAllocator(), packetData[i] ); - } - } - } - } - - int Client::GetClientIndex() const - { - return m_client ? netcode_client_index( m_client ) : -1; - } - - void Client::ConnectLoopback( int clientIndex, uint64_t clientId, int maxClients ) - { - Disconnect(); - CreateInternal(); - m_clientId = clientId; - CreateClient( m_address ); - netcode_client_connect_loopback( m_client, clientIndex, maxClients ); - SetClientState( CLIENT_STATE_CONNECTED ); - } - - void Client::DisconnectLoopback() - { - netcode_client_disconnect_loopback( m_client ); - BaseClient::Disconnect(); - DestroyClient(); - DestroyInternal(); - m_clientId = 0; - } - - bool Client::IsLoopback() const - { - return netcode_client_loopback( m_client ) != 0; - } - - void Client::ProcessLoopbackPacket( const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) - { - netcode_client_process_loopback_packet( m_client, packetData, packetBytes, packetSequence ); - } - - void Client::CreateClient( const Address & address ) - { - DestroyClient(); - char addressString[MaxAddressLength]; - address.ToString( addressString, MaxAddressLength ); - - struct netcode_client_config_t netcodeConfig; - netcode_default_client_config(&netcodeConfig); - netcodeConfig.allocator_context = &GetClientAllocator(); - netcodeConfig.allocate_function = StaticAllocateFunction; - netcodeConfig.free_function = StaticFreeFunction; - netcodeConfig.callback_context = this; - netcodeConfig.state_change_callback = StaticStateChangeCallbackFunction; - netcodeConfig.send_loopback_packet_callback = StaticSendLoopbackPacketCallbackFunction; - m_client = netcode_client_create(addressString, &netcodeConfig, GetTime()); - - if ( m_client ) - { - m_boundAddress.SetPort( netcode_client_get_port( m_client ) ); - } - } - - void Client::DestroyClient() - { - if ( m_client ) - { - m_boundAddress = m_address; - netcode_client_destroy( m_client ); - m_client = NULL; - } - } - - void Client::StateChangeCallbackFunction( int previous, int current ) - { - (void) previous; - (void) current; - } - - void Client::StaticStateChangeCallbackFunction( void * context, int previous, int current ) - { - Client * client = (Client*) context; - client->StateChangeCallbackFunction( previous, current ); - } - - void Client::TransmitPacketFunction( uint16_t packetSequence, uint8_t * packetData, int packetBytes ) - { - (void) packetSequence; - NetworkSimulator * networkSimulator = GetNetworkSimulator(); - if ( networkSimulator && networkSimulator->IsActive() ) - { - networkSimulator->SendPacket( 0, packetData, packetBytes ); - } - else - { - netcode_client_send_packet( m_client, packetData, packetBytes ); - } - } - - int Client::ProcessPacketFunction( uint16_t packetSequence, uint8_t * packetData, int packetBytes ) - { - return (int) GetConnection().ProcessPacket( GetContext(), packetSequence, packetData, packetBytes ); - } - - void Client::SendLoopbackPacketCallbackFunction( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) - { - GetAdapter().ClientSendLoopbackPacket( clientIndex, packetData, packetBytes, packetSequence ); - } - - void Client::StaticSendLoopbackPacketCallbackFunction( void * context, int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) - { - Client * client = (Client*) context; - client->SendLoopbackPacketCallbackFunction( clientIndex, packetData, packetBytes, packetSequence ); - } -} diff --git a/yojimbo_client.h b/yojimbo_client.h deleted file mode 100644 index 39583f3f..00000000 --- a/yojimbo_client.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_CLIENT_H -#define YOJIMBO_CLIENT_H - -#include "yojimbo_config.h" -#include "yojimbo_address.h" -#include "yojimbo_base_client.h" - -struct netcode_client_t; - -namespace yojimbo -{ - /** - Client implementation - */ - - class Client : public BaseClient - { - public: - - /** - The client constructor. - @param allocator The allocator for all memory used by the client. - @param address The address the client should bind to. - @param config The client/server configuration. - @param time The current time in seconds. See ClientInterface::AdvanceTime - */ - - explicit Client( Allocator & allocator, const Address & address, const ClientServerConfig & config, Adapter & adapter, double time ); - - ~Client(); - - void InsecureConnect( const uint8_t privateKey[], uint64_t clientId, const Address & address ); - - void InsecureConnect( const uint8_t privateKey[], uint64_t clientId, const Address serverAddresses[], int numServerAddresses ); - - void Connect( uint64_t clientId, uint8_t * connectToken ); - - void Disconnect(); - - void SendPackets(); - - void ReceivePackets(); - - void AdvanceTime( double time ); - - int GetClientIndex() const; - - uint64_t GetClientId() const { return m_clientId; } - - void ConnectLoopback( int clientIndex, uint64_t clientId, int maxClients ); - - void DisconnectLoopback(); - - bool IsLoopback() const; - - void ProcessLoopbackPacket( const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); - - const Address & GetAddress() const { return m_boundAddress; } - - private: - - bool GenerateInsecureConnectToken( uint8_t * connectToken, - const uint8_t privateKey[], - uint64_t clientId, - const Address serverAddresses[], - int numServerAddresses ); - - void CreateClient( const Address & address ); - - void DestroyClient(); - - void StateChangeCallbackFunction( int previous, int current ); - - static void StaticStateChangeCallbackFunction( void * context, int previous, int current ); - - void TransmitPacketFunction( uint16_t packetSequence, uint8_t * packetData, int packetBytes ); - - int ProcessPacketFunction( uint16_t packetSequence, uint8_t * packetData, int packetBytes ); - - void SendLoopbackPacketCallbackFunction( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); - - static void StaticSendLoopbackPacketCallbackFunction( void * context, int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); - - ClientServerConfig m_config; ///< Client/server configuration. - netcode_client_t * m_client; ///< netcode client data. - Address m_address; ///< Original address passed to ctor. - Address m_boundAddress; ///< Address after socket bind, eg. with valid port - uint64_t m_clientId; ///< The globally unique client id (set on each call to connect) - }; -} - -#endif // #ifndef YOJIMBO_CLIENT_H diff --git a/yojimbo_client_interface.h b/yojimbo_client_interface.h deleted file mode 100644 index 88b0c927..00000000 --- a/yojimbo_client_interface.h +++ /dev/null @@ -1,263 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_CLIENT_INTERFACE_H -#define YOJIMBO_CLIENT_INTERFACE_H - -#include "yojimbo_config.h" -#include "yojimbo_network_info.h" - -// fucking windows =p -#ifdef SendMessage -#undef SendMessage -#endif - -namespace yojimbo -{ - /** - The set of client states. - */ - - enum ClientState - { - CLIENT_STATE_ERROR = -1, - CLIENT_STATE_DISCONNECTED = 0, - CLIENT_STATE_CONNECTING, - CLIENT_STATE_CONNECTED, - }; - - /** - The common interface for all clients. - */ - - class ClientInterface - { - public: - - virtual ~ClientInterface() {} - - /** - Set the context for reading and writing packets. - This is optional. It lets you pass in a pointer to some structure that you want to have available when reading and writing packets via Stream::GetContext. - Typical use case is to pass in an array of min/max ranges for values determined by some data that is loaded from a toolchain vs. being known at compile time. - If you do use a context, make sure the same context data is set on client and server, and include a checksum of the context data in the protocol id. - */ - - virtual void SetContext( void * context ) = 0; - - /** - Disconnect from the server. - */ - - virtual void Disconnect() = 0; - - /** - Send packets to server. - */ - - virtual void SendPackets() = 0; - - /** - Receive packets from the server. - */ - - virtual void ReceivePackets() = 0; - - /** - Advance client time. - Call this at the end of each frame to advance the client time forward. - IMPORTANT: Please use a double for your time value so it maintains sufficient accuracy as time increases. - */ - - virtual void AdvanceTime( double time ) = 0; - - /** - Is the client connecting to a server? - This is true while the client is negotiation connection with a server. - @returns true if the client is currently connecting to, but is not yet connected to a server. - */ - - virtual bool IsConnecting() const = 0; - - /** - Is the client connected to a server? - This is true once a client successfully finishes connection negotiatio, and connects to a server. It is false while connecting to a server. - @returns true if the client is connected to a server. - */ - - virtual bool IsConnected() const = 0; - - /** - Is the client in a disconnected state? - A disconnected state corresponds to the client being in the disconnected, or in an error state. Both are logically "disconnected". - @returns true if the client is disconnected. - */ - - virtual bool IsDisconnected() const = 0; - - /** - Is the client in an error state? - When the client disconnects because of an error, it enters into this error state. - @returns true if the client is in an error state. - */ - - virtual bool ConnectionFailed() const = 0; - - /** - Get the current client state. - */ - - virtual ClientState GetClientState() const = 0; - - /** - Get the client index. - The client index is the slot number that the client is occupying on the server. - @returns The client index in [0,maxClients-1], where maxClients is the number of client slots allocated on the server in Server::Start. - */ - - virtual int GetClientIndex() const = 0; - - /** - Get the client id. - The client id is a unique identifier of this client. - @returns The client id. - */ - - virtual uint64_t GetClientId() const = 0; - - /** - Get the current client time. - @see Client::AdvanceTime - */ - - virtual double GetTime() const = 0; - - /** - Create a message of the specified type. - @param type The type of the message to create. The message types corresponds to the message factory created by the adapter set on this client. - */ - - virtual class Message * CreateMessage( int type ) = 0; - - /** - Helper function to allocate a data block. - This is typically used to create blocks of data to attach to block messages. See BlockMessage for details. - @param bytes The number of bytes to allocate. - @returns The pointer to the data block. This must be attached to a message via Client::AttachBlockToMessage, or freed via Client::FreeBlock. - */ - - virtual uint8_t * AllocateBlock( int bytes ) = 0; - - /** - Attach data block to message. - @param message The message to attach the block to. This message must be derived from BlockMessage. - @param block Pointer to the block of data to attach. Must be created via Client::AllocateBlock. - @param bytes Length of the block of data in bytes. - */ - - virtual void AttachBlockToMessage( Message * message, uint8_t * block, int bytes ) = 0; - - /** - Free a block of memory. - @param block The block of memory created by Client::AllocateBlock. - */ - - virtual void FreeBlock( uint8_t * block ) = 0; - - /** - Can we send a message on a channel? - @param channelIndex The channel index in range [0,numChannels-1]. - @returns True if a message can be sent over the channel, false otherwise. - */ - - virtual bool CanSendMessage( int channelIndex ) const = 0; - - /** - Send a message on a channel. - @param channelIndex The channel index in range [0,numChannels-1]. - @param message The message to send. - */ - - virtual void SendMessage( int channelIndex, Message * message ) = 0; - - /** - Receive a message from a channel. - @param channelIndex The channel index in range [0,numChannels-1]. - @returns The message received, or NULL if no message is available. Make sure to release this message by calling Client::ReleaseMessage. - */ - - virtual Message * ReceiveMessage( int channelIndex ) = 0; - - /** - Release a message. - Call this for messages received by Client::ReceiveMessage. - @param message The message to release. - */ - - virtual void ReleaseMessage( Message * message ) = 0; - - /** - Get client network info. - Call this to receive information about the client network connection to the server, eg. round trip time, packet loss %, # of packets sent and so on. - @param info The struct to be filled with network info [out]. - */ - - virtual void GetNetworkInfo( NetworkInfo & info ) const = 0; - - /** - Connect to server over loopback. - This allows you to have local clients connected to a server, for example for integrated server or singleplayer. - @param clientIndex The index of the client. - @param clientId The unique client id. - @param maxClients The maximum number of clients supported by the server. - */ - - virtual void ConnectLoopback( int clientIndex, uint64_t clientId, int maxClients ) = 0; - - /** - Disconnect from server over loopback. - */ - - virtual void DisconnectLoopback() = 0; - - /** - Is this a loopback client? - @returns true if the client is a loopback client, false otherwise. - */ - - virtual bool IsLoopback() const = 0; - - /** - Process loopback packet. - Use this to pass packets from a server directly to the loopback client. - @param packetData The packet data to process. - @param packetBytes The number of bytes of packet data. - @param packetSequence The packet sequence number. - */ - - virtual void ProcessLoopbackPacket( const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) = 0; - }; -} - -#endif // #ifndef YOJIMBO_CLIENT_INTERFACE_H diff --git a/yojimbo_config.h b/yojimbo_config.h deleted file mode 100644 index 541d1a30..00000000 --- a/yojimbo_config.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_CONFIG_H -#define YOJIMBO_CONFIG_H - -#include "yojimbo_constants.h" - -#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS -#endif - -#define YOJIMBO_MAJOR_VERSION 1 -#define YOJIMBO_MINOR_VERSION 0 -#define YOJIMBO_PATCH_VERSION 0 - -#if !defined(YOJIMBO_DEBUG) && !defined(YOJIMBO_RELEASE) -#if defined(NDEBUG) -#define YOJIMBO_RELEASE -#else -#define YOJIMBO_DEBUG -#endif -#elif defined(YOJIMBO_DEBUG) && defined(YOJIMBO_RELEASE) -#error Can only define one of debug & release -#endif - -#ifndef YOJIMBO_DEFAULT_TIMEOUT -#define YOJIMBO_DEFAULT_TIMEOUT 10 -#endif - -#ifdef _MSC_VER -#pragma warning( disable : 4127 ) -#pragma warning( disable : 4244 ) -#endif // #ifdef _MSC_VER - -#define YOJIMBO_PLATFORM_WINDOWS 1 -#define YOJIMBO_PLATFORM_MAC 2 -#define YOJIMBO_PLATFORM_UNIX 3 - -#if defined(_WIN32) -#define YOJIMBO_PLATFORM YOJIMBO_PLATFORM_WINDOWS -#elif defined(__APPLE__) -#define YOJIMBO_PLATFORM YOJIMBO_PLATFORM_MAC -#else -#define YOJIMBO_PLATFORM YOJIMBO_PLATFORM_UNIX -#endif - -#ifdef YOJIMBO_DEBUG - -#define YOJIMBO_DEBUG_MEMORY_LEAKS 1 -#define YOJIMBO_DEBUG_MESSAGE_LEAKS 1 -#define YOJIMBO_DEBUG_MESSAGE_BUDGET 1 - -#else // #ifdef YOJIMBO_DEBUG - -#define YOJIMBO_DEBUG_MEMORY_LEAKS 0 -#define YOJIMBO_DEBUG_MESSAGE_LEAKS 0 -#define YOJIMBO_DEBUG_MESSAGE_BUDGET 0 - -#endif // #ifdef YOJIMBO_DEBUG - -#define YOJIMBO_ENABLE_LOGGING 1 - -namespace yojimbo -{ - using namespace serialize; - - /// Determines the reliability and ordering guarantees for a channel. - - enum ChannelType - { - CHANNEL_TYPE_RELIABLE_ORDERED, ///< Messages are received reliably and in the same order they were sent. - CHANNEL_TYPE_UNRELIABLE_UNORDERED ///< Messages are sent unreliably. Messages may arrive out of order, or not at all. - }; - - /** - Configuration properties for a message channel. - - Channels let you specify different reliability and ordering guarantees for messages sent across a connection. - - They may be configured as one of two types: reliable-ordered or unreliable-unordered. - - Reliable ordered channels guarantee that messages (see Message) are received reliably and in the same order they were sent. - This channel type is designed for control messages and RPCs sent between the client and server. - - Unreliable unordered channels are like UDP. There is no guarantee that messages will arrive, and messages may arrive out of order. - This channel type is designed for data that is time critical and should not be resent if dropped, like snapshots of world state sent rapidly - from server to client, or cosmetic events such as effects and sounds. - - Both channel types support blocks of data attached to messages (see BlockMessage), but their treatment of blocks is quite different. - - Reliable ordered channels are designed for blocks that must be received reliably and in-order with the rest of the messages sent over the channel. - Examples of these sort of blocks include the initial state of a level, or server configuration data sent down to a client on connect. These blocks - are sent by splitting them into fragments and resending each fragment until the other side has received the entire block. This allows for sending - blocks of data larger that maximum packet size quickly and reliably even under packet loss. - - Unreliable-unordered channels send blocks as-is without splitting them up into fragments. The idea is that transport level packet fragmentation - should be used on top of the generated packet to split it up into into smaller packets that can be sent across typical Internet MTU (<1500 bytes). - Because of this, you need to make sure that the maximum block size for an unreliable-unordered channel fits within the maximum packet size. - - Channels are typically configured as part of a ConnectionConfig, which is included inside the ClientServerConfig that is passed into the Client and Server constructors. - */ - - struct ChannelConfig - { - ChannelType type; ///< Channel type: reliable-ordered or unreliable-unordered. - bool disableBlocks; ///< Disables blocks being sent across this channel. - int sentPacketBufferSize; ///< Number of packet entries in the sent packet sequence buffer. Please consider your packet send rate and make sure you have at least a few seconds worth of entries in this buffer. - int messageSendQueueSize; ///< Number of messages in the send queue for this channel. - int messageReceiveQueueSize; ///< Number of messages in the receive queue for this channel. - int maxMessagesPerPacket; ///< Maximum number of messages to include in each packet. Will write up to this many messages, provided the messages fit into the channel packet budget and the number of bytes remaining in the packet. - int packetBudget; ///< Maximum amount of message data to write to the packet for this channel (bytes). Specifying -1 means the channel can use up to the rest of the bytes remaining in the packet. - int maxBlockSize; ///< The size of the largest block that can be sent across this channel (bytes). - int blockFragmentSize; ///< Blocks are split up into fragments of this size (bytes). Reliable-ordered channel only. - float messageResendTime; ///< Minimum delay between message resends (seconds). Avoids sending the same message too frequently. Reliable-ordered channel only. - float blockFragmentResendTime; ///< Minimum delay between block fragment resends (seconds). Avoids sending the same fragment too frequently. Reliable-ordered channel only. - - ChannelConfig() : type ( CHANNEL_TYPE_RELIABLE_ORDERED ) - { - disableBlocks = false; - sentPacketBufferSize = 1024; - messageSendQueueSize = 1024; - messageReceiveQueueSize = 1024; - maxMessagesPerPacket = 256; - packetBudget = -1; - maxBlockSize = 256 * 1024; - blockFragmentSize = 1024; - messageResendTime = 0.1f; - blockFragmentResendTime = 0.25f; - } - - int GetMaxFragmentsPerBlock() const - { - return maxBlockSize / blockFragmentSize; - } - }; - - /** - Configures connection properties and the set of channels for sending and receiving messages. - Specifies the maximum packet size to generate, and the number of message channels, and the per-channel configuration data. See ChannelConfig for details. - Typically configured as part of a ClientServerConfig which is passed into Client and Server constructors. - */ - - struct ConnectionConfig - { - int numChannels; ///< Number of message channels in [1,MaxChannels]. Each message channel must have a corresponding configuration below. - int maxPacketSize; ///< The maximum size of packets generated to transmit messages between client and server (bytes). - ChannelConfig channel[MaxChannels]; ///< Per-channel configuration. See ChannelConfig for details. - - ConnectionConfig() - { - numChannels = 1; - maxPacketSize = 8 * 1024; - } - }; - - /** - Configuration shared between client and server. - Passed to Client and Server constructors to configure their behavior. - Please make sure that the message configuration is identical between client and server. - */ - - struct ClientServerConfig : public ConnectionConfig - { - uint64_t protocolId; ///< Clients can only connect to servers with the same protocol id. Use this for versioning. - int timeout; ///< Timeout value in seconds. Set to negative value to disable timeouts (for debugging only). - int clientMemory; ///< Memory allocated inside Client for packets, messages and stream allocations (bytes) - int serverGlobalMemory; ///< Memory allocated inside Server for global connection request and challenge response packets (bytes) - int serverPerClientMemory; ///< Memory allocated inside Server for packets, messages and stream allocations per-client (bytes) - bool networkSimulator; ///< If true then a network simulator is created for simulating latency, jitter, packet loss and duplicates. - int maxSimulatorPackets; ///< Maximum number of packets that can be stored in the network simulator. Additional packets are dropped. - int fragmentPacketsAbove; ///< Packets above this size (bytes) are split apart into fragments and reassembled on the other side. - int packetFragmentSize; ///< Size of each packet fragment (bytes). - int maxPacketFragments; ///< Maximum number of fragments a packet can be split up into. - int packetReassemblyBufferSize; ///< Number of packet entries in the fragmentation reassembly buffer. - int ackedPacketsBufferSize; ///< Number of packet entries in the acked packet buffer. Consider your packet send rate and aim to have at least a few seconds worth of entries. - int receivedPacketsBufferSize; ///< Number of packet entries in the received packet sequence buffer. Consider your packet send rate and aim to have at least a few seconds worth of entries. - float rttSmoothingFactor; ///< Round-Trip Time (RTT) smoothing factor over time. - - ClientServerConfig() - { - protocolId = 0; - timeout = YOJIMBO_DEFAULT_TIMEOUT; - clientMemory = 10 * 1024 * 1024; - serverGlobalMemory = 10 * 1024 * 1024; - serverPerClientMemory = 10 * 1024 * 1024; - networkSimulator = true; - maxSimulatorPackets = 4 * 1024; - fragmentPacketsAbove = 1024; - packetFragmentSize = 1024; - maxPacketFragments = (int) ceil( maxPacketSize / packetFragmentSize ); - packetReassemblyBufferSize = 64; - ackedPacketsBufferSize = 256; - receivedPacketsBufferSize = 256; - rttSmoothingFactor = 0.0025f; - } - }; -} - -#endif // # YOJIMBO_CONFIG_H diff --git a/yojimbo_connection.cpp b/yojimbo_connection.cpp deleted file mode 100644 index bcd4e117..00000000 --- a/yojimbo_connection.cpp +++ /dev/null @@ -1,371 +0,0 @@ -#include "yojimbo_connection.h" -#include "yojimbo_reliable_ordered_channel.h" -#include "yojimbo_unreliable_unordered_channel.h" - -namespace yojimbo -{ - struct ConnectionPacket - { - int numChannelEntries; - ChannelPacketData * channelEntry; - MessageFactory * messageFactory; - - ConnectionPacket() - { - messageFactory = NULL; - numChannelEntries = 0; - channelEntry = NULL; - } - - ~ConnectionPacket() - { - if ( messageFactory ) - { - for ( int i = 0; i < numChannelEntries; ++i ) - { - channelEntry[i].Free( *messageFactory ); - } - YOJIMBO_FREE( messageFactory->GetAllocator(), channelEntry ); - messageFactory = NULL; - } - } - - bool AllocateChannelData( MessageFactory & _messageFactory, int numEntries ) - { - yojimbo_assert( numEntries > 0 ); - yojimbo_assert( numEntries <= MaxChannels ); - messageFactory = &_messageFactory; - Allocator & allocator = messageFactory->GetAllocator(); - channelEntry = (ChannelPacketData*) YOJIMBO_ALLOCATE( allocator, sizeof( ChannelPacketData ) * numEntries ); - if ( channelEntry == NULL ) - return false; - for ( int i = 0; i < numEntries; ++i ) - { - channelEntry[i].Initialize(); - } - numChannelEntries = numEntries; - return true; - } - - template bool Serialize( Stream & stream, MessageFactory & messageFactory, const ConnectionConfig & connectionConfig ) - { - const int numChannels = connectionConfig.numChannels; - serialize_int( stream, numChannelEntries, 0, connectionConfig.numChannels ); -#if YOJIMBO_DEBUG_MESSAGE_BUDGET - yojimbo_assert( stream.GetBitsProcessed() <= ConservativePacketHeaderBits ); -#endif // #if YOJIMBO_DEBUG_MESSAGE_BUDGET - if ( numChannelEntries > 0 ) - { - if ( Stream::IsReading ) - { - if ( !AllocateChannelData( messageFactory, numChannelEntries ) ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to allocate channel data (ConnectionPacket)\n" ); - return false; - } - for ( int i = 0; i < numChannelEntries; ++i ) - { - yojimbo_assert( channelEntry[i].messageFailedToSerialize == 0 ); - } - } - for ( int i = 0; i < numChannelEntries; ++i ) - { - yojimbo_assert( channelEntry[i].messageFailedToSerialize == 0 ); - if ( !channelEntry[i].SerializeInternal( stream, messageFactory, connectionConfig.channel, numChannels ) ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to serialize channel %d\n", i ); - return false; - } - } - } - return true; - } - - bool SerializeInternal( ReadStream & stream, MessageFactory & _messageFactory, const ConnectionConfig & connectionConfig ) - { - return Serialize( stream, _messageFactory, connectionConfig ); - } - - bool SerializeInternal( WriteStream & stream, MessageFactory & _messageFactory, const ConnectionConfig & connectionConfig ) - { - return Serialize( stream, _messageFactory, connectionConfig ); - } - - bool SerializeInternal( MeasureStream & stream, MessageFactory & _messageFactory, const ConnectionConfig & connectionConfig ) - { - return Serialize( stream, _messageFactory, connectionConfig ); - } - - private: - - ConnectionPacket( const ConnectionPacket & other ); - - const ConnectionPacket & operator = ( const ConnectionPacket & other ); - }; - - // ------------------------------------------------------------------------------ - - Connection::Connection( Allocator & allocator, MessageFactory & messageFactory, const ConnectionConfig & connectionConfig, double time ) - : m_connectionConfig( connectionConfig ) - { - m_allocator = &allocator; - m_messageFactory = &messageFactory; - m_errorLevel = CONNECTION_ERROR_NONE; - memset( m_channel, 0, sizeof( m_channel ) ); - yojimbo_assert( m_connectionConfig.numChannels >= 1 ); - yojimbo_assert( m_connectionConfig.numChannels <= MaxChannels ); - for ( int channelIndex = 0; channelIndex < m_connectionConfig.numChannels; ++channelIndex ) - { - switch ( m_connectionConfig.channel[channelIndex].type ) - { - case CHANNEL_TYPE_RELIABLE_ORDERED: - { - m_channel[channelIndex] = YOJIMBO_NEW( *m_allocator, - ReliableOrderedChannel, - *m_allocator, - messageFactory, - m_connectionConfig.channel[channelIndex], - channelIndex, - time ); - } - break; - - case CHANNEL_TYPE_UNRELIABLE_UNORDERED: - { - m_channel[channelIndex] = YOJIMBO_NEW( *m_allocator, - UnreliableUnorderedChannel, - *m_allocator, - messageFactory, - m_connectionConfig.channel[channelIndex], - channelIndex, - time ); - } - break; - - default: - yojimbo_assert( !"unknown channel type" ); - } - } - } - - Connection::~Connection() - { - yojimbo_assert( m_allocator ); - Reset(); - for ( int i = 0; i < m_connectionConfig.numChannels; ++i ) - { - YOJIMBO_DELETE( *m_allocator, Channel, m_channel[i] ); - } - m_allocator = NULL; - } - - void Connection::Reset() - { - m_errorLevel = CONNECTION_ERROR_NONE; - for ( int i = 0; i < m_connectionConfig.numChannels; ++i ) - { - m_channel[i]->Reset(); - } - } - - bool Connection::CanSendMessage( int channelIndex ) const - { - yojimbo_assert( channelIndex >= 0 ); - yojimbo_assert( channelIndex < m_connectionConfig.numChannels ); - return m_channel[channelIndex]->CanSendMessage(); - } - - bool Connection::HasMessagesToSend( int channelIndex ) const { - yojimbo_assert( channelIndex >= 0 ); - yojimbo_assert( channelIndex < m_connectionConfig.numChannels ); - return m_channel[channelIndex]->HasMessagesToSend(); - } - - void Connection::SendMessage( int channelIndex, Message * message, void *context) - { - yojimbo_assert( channelIndex >= 0 ); - yojimbo_assert( channelIndex < m_connectionConfig.numChannels ); - return m_channel[channelIndex]->SendMessage( message, context ); - } - - Message * Connection::ReceiveMessage( int channelIndex ) - { - yojimbo_assert( channelIndex >= 0 ); - yojimbo_assert( channelIndex < m_connectionConfig.numChannels ); - return m_channel[channelIndex]->ReceiveMessage(); - } - - void Connection::ReleaseMessage( Message * message ) - { - yojimbo_assert( message ); - m_messageFactory->ReleaseMessage( message ); - } - - static int WritePacket( void * context, - MessageFactory & messageFactory, - const ConnectionConfig & connectionConfig, - ConnectionPacket & packet, - uint8_t * buffer, - int bufferSize ) - { - WriteStream stream( buffer, bufferSize ); - - stream.SetContext( context ); - - stream.SetAllocator( &messageFactory.GetAllocator() ); - - if ( !packet.SerializeInternal( stream, messageFactory, connectionConfig ) ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: serialize connection packet failed (write packet)\n" ); - return 0; - } - - stream.Flush(); - - return stream.GetBytesProcessed(); - } - - bool Connection::GeneratePacket( void * context, uint16_t packetSequence, uint8_t * packetData, int maxPacketBytes, int & packetBytes ) - { - ConnectionPacket packet; - - if ( m_connectionConfig.numChannels > 0 ) - { - int numChannelsWithData = 0; - bool channelHasData[MaxChannels]; - memset( channelHasData, 0, sizeof( channelHasData ) ); - ChannelPacketData channelData[MaxChannels]; - - int availableBits = maxPacketBytes * 8 - ConservativePacketHeaderBits; - - for ( int channelIndex = 0; channelIndex < m_connectionConfig.numChannels; ++channelIndex ) - { - int packetDataBits = m_channel[channelIndex]->GetPacketData( context, channelData[channelIndex], packetSequence, availableBits ); - if ( packetDataBits > 0 ) - { - availableBits -= ConservativeChannelHeaderBits; - availableBits -= packetDataBits; - channelHasData[channelIndex] = true; - numChannelsWithData++; - } - } - - if ( numChannelsWithData > 0 ) - { - if ( !packet.AllocateChannelData( *m_messageFactory, numChannelsWithData ) ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to allocate channel data\n" ); - return false; - } - - int index = 0; - - for ( int channelIndex = 0; channelIndex < m_connectionConfig.numChannels; ++channelIndex ) - { - if ( channelHasData[channelIndex] ) - { - memcpy( &packet.channelEntry[index], &channelData[channelIndex], sizeof( ChannelPacketData ) ); - index++; - } - } - } - } - - packetBytes = WritePacket( context, *m_messageFactory, m_connectionConfig, packet, packetData, maxPacketBytes ); - - return true; - } - - static bool ReadPacket( void * context, - MessageFactory & messageFactory, - const ConnectionConfig & connectionConfig, - ConnectionPacket & packet, - const uint8_t * buffer, - int bufferSize ) - { - yojimbo_assert( buffer ); - yojimbo_assert( bufferSize > 0 ); - - ReadStream stream( buffer, bufferSize ); - - stream.SetContext( context ); - - stream.SetAllocator( &messageFactory.GetAllocator() ); - - if ( !packet.SerializeInternal( stream, messageFactory, connectionConfig ) ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: serialize connection packet failed (read packet)\n" ); - return false; - } - - return true; - } - - bool Connection::ProcessPacket( void * context, uint16_t packetSequence, const uint8_t * packetData, int packetBytes ) - { - if ( m_errorLevel != CONNECTION_ERROR_NONE ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_DEBUG, "failed to read packet because connection is in error state\n" ); - return false; - } - - ConnectionPacket packet; - - if ( !ReadPacket( context, *m_messageFactory, m_connectionConfig, packet, packetData, packetBytes ) ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to read packet\n" ); - m_errorLevel = CONNECTION_ERROR_READ_PACKET_FAILED; - return false; - } - - for ( int i = 0; i < packet.numChannelEntries; ++i ) - { - const int channelIndex = packet.channelEntry[i].channelIndex; - yojimbo_assert( channelIndex >= 0 ); - yojimbo_assert( channelIndex <= m_connectionConfig.numChannels ); - m_channel[channelIndex]->ProcessPacketData( packet.channelEntry[i], packetSequence ); - if ( m_channel[channelIndex]->GetErrorLevel() != CHANNEL_ERROR_NONE ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_DEBUG, "failed to read packet because channel %d is in error state\n", channelIndex ); - return false; - } - } - - return true; - } - - void Connection::ProcessAcks( const uint16_t * acks, int numAcks ) - { - for ( int i = 0; i < numAcks; ++i ) - { - for ( int channelIndex = 0; channelIndex < m_connectionConfig.numChannels; ++channelIndex ) - { - m_channel[channelIndex]->ProcessAck( acks[i] ); - } - } - } - - void Connection::AdvanceTime( double time ) - { - for ( int i = 0; i < m_connectionConfig.numChannels; ++i ) - { - m_channel[i]->AdvanceTime( time ); - - if ( m_channel[i]->GetErrorLevel() != CHANNEL_ERROR_NONE ) - { - m_errorLevel = CONNECTION_ERROR_CHANNEL; - return; - } - } - if ( m_allocator->GetErrorLevel() != ALLOCATOR_ERROR_NONE ) - { - m_errorLevel = CONNECTION_ERROR_ALLOCATOR; - return; - } - if ( m_messageFactory->GetErrorLevel() != MESSAGE_FACTORY_ERROR_NONE ) - { - m_errorLevel = CONNECTION_ERROR_MESSAGE_FACTORY; - return; - } - } -} diff --git a/yojimbo_connection.h b/yojimbo_connection.h deleted file mode 100644 index 410546c4..00000000 --- a/yojimbo_connection.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_CONNECTION_H -#define YOJIMBO_CONNECTION_H - -#include "yojimbo_config.h" -#include "yojimbo_allocator.h" -#include "yojimbo_message.h" -#include "yojimbo_channel.h" - -namespace yojimbo -{ - /// Connection error level. - - enum ConnectionErrorLevel - { - CONNECTION_ERROR_NONE = 0, ///< No error. All is well. - CONNECTION_ERROR_CHANNEL, ///< A channel is in an error state. - CONNECTION_ERROR_ALLOCATOR, ///< The allocator is an error state. - CONNECTION_ERROR_MESSAGE_FACTORY, ///< The message factory is in an error state. - CONNECTION_ERROR_READ_PACKET_FAILED, ///< Failed to read packet. Received an invalid packet? - }; - - /** - Sends and receives messages across a set of user defined channels. - */ - - class Connection - { - public: - - Connection( Allocator & allocator, MessageFactory & messageFactory, const ConnectionConfig & connectionConfig, double time ); - - ~Connection(); - - void Reset(); - - bool CanSendMessage( int channelIndex ) const; - - bool HasMessagesToSend( int channelIndex ) const; - - void SendMessage( int channelIndex, Message * message, void *context = 0); - - Message * ReceiveMessage( int channelIndex ); - - void ReleaseMessage( Message * message ); - - bool GeneratePacket( void * context, uint16_t packetSequence, uint8_t * packetData, int maxPacketBytes, int & packetBytes ); - - bool ProcessPacket( void * context, uint16_t packetSequence, const uint8_t * packetData, int packetBytes ); - - void ProcessAcks( const uint16_t * acks, int numAcks ); - - void AdvanceTime( double time ); - - ConnectionErrorLevel GetErrorLevel() { return m_errorLevel; } - - private: - - Allocator * m_allocator; ///< Allocator passed in to the connection constructor. - MessageFactory * m_messageFactory; ///< Message factory for creating and destroying messages. - ConnectionConfig m_connectionConfig; ///< Connection configuration. - Channel * m_channel[MaxChannels]; ///< Array of connection channels. Array size corresponds to m_connectionConfig.numChannels - ConnectionErrorLevel m_errorLevel; ///< The connection error level. - }; -} - -#endif // #ifndef YOJIMBO_CONNECTION_H diff --git a/yojimbo_constants.h b/yojimbo_constants.h deleted file mode 100644 index 3833c631..00000000 --- a/yojimbo_constants.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_CONSTANTS_H -#define YOJIMBO_CONSTANTS_H - -#include "serialize.h" - -namespace yojimbo -{ - const int MaxClients = 64; ///< The maximum number of clients supported by this library. You can increase this if you want, but this library is designed around patterns that work best for [2,64] player games. If your game has less than 64 clients, reducing this will save memory. - - const int MaxChannels = 64; ///< The maximum number of message channels supported by this library. If you need less than 64 channels per-packet, reducing this will save memory. - - const int KeyBytes = 32; ///< Size of encryption key for dedicated client/server in bytes. Must be equal to key size for libsodium encryption primitive. Do not change. - - const int ConnectTokenBytes = 2048; ///< Size of the encrypted connect token data return from the matchmaker. Must equal size of NETCODE_CONNECT_TOKEN_BYTE (2048). - - const int ConservativeMessageHeaderBits = 32; ///< Conservative number of bits per-message header. - - const int ConservativeFragmentHeaderBits = 64; ///< Conservative number of bits per-fragment header. - - const int ConservativeChannelHeaderBits = 32; ///< Conservative number of bits per-channel header. - - const int ConservativePacketHeaderBits = 16; ///< Conservative number of bits per-packet header. - - const int MaxAddressLength = 256; ///< The maximum length of an address when converted to a string (includes terminating NULL). @see Address::ToString -} - -#endif // #ifndef YOJIMBO_CONSTANTS_H diff --git a/yojimbo_message.h b/yojimbo_message.h deleted file mode 100644 index e5bf6480..00000000 --- a/yojimbo_message.h +++ /dev/null @@ -1,611 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_MESSAGE_H -#define YOJIMBO_MESSAGE_H - -#include "yojimbo_config.h" -#include "yojimbo_serialize.h" -#include "yojimbo_allocator.h" - -namespace yojimbo -{ - /** - A reference counted object that can be serialized to a bitstream. - - Messages are objects that are sent between client and server across the connection. They are carried inside the ConnectionPacket generated by the Connection class. Messages can be sent reliable-ordered, or unreliable-unordered, depending on the configuration of the channel they are sent over. - - To use messages, create your own set of message classes by inheriting from this class (or from BlockMessage, if you want to attach data blocks to your message), then setup an enum of all your message types and derive a message factory class to create your message instances by type. - - There are macros to help make defining your message factory painless: - - YOJIMBO_MESSAGE_FACTORY_START - YOJIMBO_DECLARE_MESSAGE_TYPE - YOJIMBO_MESSAGE_FACTORY_FINISH - - Once you have a message factory, register it with your declared inside your client and server classes using: - - YOJIMBO_MESSAGE_FACTORY - - which overrides the Client::CreateMessageFactory and Server::CreateMessageFactory methods so the client and server classes use your message factory type. - - See shared.h for an example showing you how to do this, and the functional tests inside tests/test.cpp for examples showing how how to send and receive messages. - - @see BlockMessage - @see MessageFactory - @see Connection - */ - - class Message : public Serializable - { - public: - - /** - Message constructor. - Don't call this directly, use a message factory instead. - @param blockMessage 1 if this is a block message, 0 otherwise. - @see MessageFactory::Create - */ - - Message( int blockMessage = 0 ) : m_refCount(1), m_id(0), m_type(0), m_blockMessage( blockMessage ) {} - - /** - Set the message id. - When messages are sent over a reliable-ordered channel, the message id starts at 0 and increases with each message sent over that channel. - When messages are sent over an unreliable-unordered channel, the message id is set to the sequence number of the packet it was delivered in. - @param id The message id. - */ - - void SetId( uint16_t id ) { m_id = id; } - - /** - Get the message id. - @returns The message id. - */ - - int GetId() const { return m_id; } - - /** - Get the message type. - This corresponds to the type enum value used to create the message in the message factory. - @returns The message type. - @see MessageFactory. - */ - - int GetType() const { return m_type; } - - /** - Get the reference count on the message. - Messages start with a reference count of 1 when they are created. This is decreased when they are released. - When the reference count reaches 0, the message is destroyed. - @returns The reference count on the message. - */ - - int GetRefCount() const { return m_refCount; } - - /** - Is this a block message? - Block messages are of type BlockMessage and can have a data block attached to the message. - @returns True if this is a block message, false otherwise. - @see BlockMessage. - */ - - bool IsBlockMessage() const { return m_blockMessage; } - - /** - Virtual serialize function (read). - Reads the message in from a bitstream. - Don't override this method directly, instead, use the YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS macro in your derived message class to redirect it to a templated serialize method. - This way you can implement serialization for your packets in a single method and the C++ compiler takes care of generating specialized read, write and measure implementations for you. - See shared.h for examples of this. - */ - - virtual bool SerializeInternal( ReadStream & stream ) = 0; - - /** - Virtual serialize function (write). - Write the message to a bitstream. - Don't override this method directly, instead, use the YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS macro in your derived message class to redirect it to a templated serialize method. - This way you can implement serialization for your packets in a single method and the C++ compiler takes care of generating specialized read, write and measure implementations for you. - See shared.h for examples of this. - */ - - virtual bool SerializeInternal( WriteStream & stream ) = 0; - - /** - Virtual serialize function (measure). - Measure how many bits this message would take to write. This is used when working out how many messages will fit within the channel packet budget. - Don't override this method directly, instead, use the YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS macro in your derived message class to redirect it to a templated serialize method. - This way you can implement serialization for your packets in a single method and the C++ compiler takes care of generating specialized read, write and measure implementations for you. - See shared.h for examples of this. - */ - - virtual bool SerializeInternal ( MeasureStream & stream ) = 0; - - protected: - - /** - Set the message type. - Called by the message factory after it creates a message. - @param type The message type. - */ - - void SetType( int type ) { m_type = type; } - - /** - Add a reference to the message. - This is called when a message is included in a packet and added to the receive queue. - This way we don't have to pass messages by value (more efficient) and messages get cleaned up when they are delivered and no packets refer to them. - */ - - void Acquire() { yojimbo_assert( m_refCount > 0 ); m_refCount++; } - - /** - Remove a reference from the message. - Message are deleted when the number of references reach zero. Messages have reference count of 1 after creation. - */ - - void Release() { yojimbo_assert( m_refCount > 0 ); m_refCount--; } - - /** - Message destructor. - @see MessageFactory::Release - */ - - virtual ~Message() - { - yojimbo_assert( m_refCount == 0 ); - } - - private: - - friend class MessageFactory; - - Message( const Message & other ); - - const Message & operator = ( const Message & other ); - - int m_refCount; ///< Number of references on this message object. Starts at 1. Message is destroyed when it reaches 0. - uint32_t m_id : 16; ///< The message id. For messages sent over reliable-ordered channels, this starts at 0 and increases with each message sent. For unreliable-unordered channels this is set to the sequence number of the packet the message was included in. - uint32_t m_type : 15; ///< The message type. Corresponds to the type integer used when the message was created though the message factory. - uint32_t m_blockMessage : 1; ///< 1 if this is a block message. 0 otherwise. If 1 then you can cast the Message* to BlockMessage*. Lightweight RTTI. - }; - - /** - A message which can have a block of data attached to it. - @see ChannelConfig - */ - - class BlockMessage : public Message - { - public: - - /** - Block message constructor. - Don't call this directly, use a message factory instead. - @see MessageFactory::CreateMessage - */ - - explicit BlockMessage() : Message( 1 ), m_allocator(NULL), m_blockData(NULL), m_blockSize(0) {} - - /** - Attach a block to this message. - You can only attach one block. This method will assert if a block is already attached. - @see Client::AttachBlockToMessage - @see Server::AttachBlockToMessage - */ - - void AttachBlock( Allocator & allocator, uint8_t * blockData, int blockSize ) - { - yojimbo_assert( blockData ); - yojimbo_assert( blockSize > 0 ); - yojimbo_assert( !m_blockData ); - m_allocator = &allocator; - m_blockData = blockData; - m_blockSize = blockSize; - } - - /** - Detach the block from this message. - By doing this you are responsible for copying the block pointer and allocator and making sure the block is freed. - This could be used for example, if you wanted to copy off the block and store it somewhere, without the cost of copying it. - @see Client::DetachBlockFromMessage - @see Server::DetachBlockFromMessage - */ - - void DetachBlock() - { - m_allocator = NULL; - m_blockData = NULL; - m_blockSize = 0; - } - - /** - Get the allocator used to allocate the block. - @returns The allocator for the block. NULL if no block is attached to this message. - */ - - Allocator * GetAllocator() - { - return m_allocator; - } - - /** - Get the block data pointer. - @returns The block data pointer. NULL if no block is attached. - */ - - uint8_t * GetBlockData() - { - return m_blockData; - } - - /** - Get a constant pointer to the block data. - @returns A constant pointer to the block data. NULL if no block is attached. - */ - - const uint8_t * GetBlockData() const - { - return m_blockData; - } - - /** - Get the size of the block attached to this message. - @returns The size of the block (bytes). 0 if no block is attached. - */ - - int GetBlockSize() const - { - return m_blockSize; - } - - /** - Templated serialize function for the block message. Doesn't do anything. The block data is serialized elsewhere. - You can override the serialize methods on a block message to implement your own serialize function. It's just like a regular message with a block attached to it. - @see ConnectionPacket - @see ChannelPacketData - @see ReliableOrderedChannel - @see UnreliableUnorderedChannel - */ - - template bool Serialize( Stream & stream ) { (void) stream; return true; } - - YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS() - - protected: - - /** - If a block was attached to the message, it is freed here. - */ - - ~BlockMessage() - { - if ( m_allocator ) - { - YOJIMBO_FREE( *m_allocator, m_blockData ); - m_blockSize = 0; - m_allocator = NULL; - } - } - - private: - - Allocator * m_allocator; ///< Allocator for the block attached to the message. NULL if no block is attached. - uint8_t * m_blockData; ///< The block data. NULL if no block is attached. - int m_blockSize; ///< The block size (bytes). 0 if no block is attached. - }; - - /** - Message factory error level. - */ - - enum MessageFactoryErrorLevel - { - MESSAGE_FACTORY_ERROR_NONE, ///< No error. All is well. - MESSAGE_FACTORY_ERROR_FAILED_TO_ALLOCATE_MESSAGE, ///< Failed to allocate a message. Typically this means we ran out of memory on the allocator backing the message factory. - }; - - /** - Defines the set of message types that can be created. - - You can derive a message factory yourself to create your own message types, or you can use these helper macros to do it for you: - - YOJIMBO_MESSAGE_FACTORY_START - YOJIMBO_DECLARE_MESSAGE_TYPE - YOJIMBO_MESSAGE_FACTORY_FINISH - - See shared.h for an example showing how to use the macros. - */ - - class MessageFactory - { - public: - - /** - Message factory allocator. - Pass in the number of message types for the message factory from the derived class. - @param allocator The allocator used to create messages. - @param numTypes The number of message types. Valid types are in [0,numTypes-1]. - */ - - MessageFactory( Allocator & allocator, int numTypes ) - { - m_allocator = &allocator; - m_numTypes = numTypes; - m_errorLevel = MESSAGE_FACTORY_ERROR_NONE; - } - - /** - Message factory destructor. - Checks for message leaks if YOJIMBO_DEBUG_MESSAGE_LEAKS is defined and not equal to zero. This is on by default in debug build. - */ - - virtual ~MessageFactory() - { - yojimbo_assert( m_allocator ); - - m_allocator = NULL; - - #if YOJIMBO_DEBUG_MESSAGE_LEAKS - if ( allocated_messages.size() ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "you leaked messages!\n" ); - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "%d messages leaked\n", (int) allocated_messages.size() ); - typedef std::map::iterator itor_type; - for ( itor_type i = allocated_messages.begin(); i != allocated_messages.end(); ++i ) - { - Message * message = (Message*) i->first; - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "leaked message %p (type %d, refcount %d)\n", message, message->GetType(), message->GetRefCount() ); - } - exit(1); - } - #endif // #if YOJIMBO_DEBUG_MESSAGE_LEAKS - } - - /** - Create a message by type. - IMPORTANT: Check the message pointer returned by this call. It can be NULL if there is no memory to create a message! - Messages returned from this function have one reference added to them. When you are finished with the message, pass it to MessageFactory::Release. - @param type The message type in [0,numTypes-1]. - @returns The allocated message, or NULL if the message could not be allocated. If the message allocation fails, the message factory error level is set to MESSAGE_FACTORY_ERROR_FAILED_TO_ALLOCATE_MESSAGE. - @see MessageFactory::AddRef - @see MessageFactory::ReleaseMessage - */ - - Message * CreateMessage( int type ) - { - yojimbo_assert( type >= 0 ); - yojimbo_assert( type < m_numTypes ); - Message * message = CreateMessageInternal( type ); - if ( !message ) - { - m_errorLevel = MESSAGE_FACTORY_ERROR_FAILED_TO_ALLOCATE_MESSAGE; - return NULL; - } - #if YOJIMBO_DEBUG_MESSAGE_LEAKS - allocated_messages[message] = 1; - yojimbo_assert( allocated_messages.find( message ) != allocated_messages.end() ); - #endif // #if YOJIMBO_DEBUG_MESSAGE_LEAKS - return message; - } - - /** - Add a reference to a message. - @param message The message to add a reference to. - @see MessageFactory::Create - @see MessageFactory::Release - */ - - void AcquireMessage( Message * message ) - { - yojimbo_assert( message ); - if ( message ) - message->Acquire(); - } - - /** - Remove a reference from a message. - Messages have 1 reference when created. When the reference count reaches 0, they are destroyed. - @see MessageFactory::Create - @see MessageFactory::AddRef - */ - - void ReleaseMessage( Message * message ) - { - yojimbo_assert( message ); - if ( !message ) - { - return; - } - message->Release(); - if ( message->GetRefCount() == 0 ) - { - #if YOJIMBO_DEBUG_MESSAGE_LEAKS - yojimbo_assert( allocated_messages.find( message ) != allocated_messages.end() ); - allocated_messages.erase( message ); - #endif // #if YOJIMBO_DEBUG_MESSAGE_LEAKS - yojimbo_assert( m_allocator ); - YOJIMBO_DELETE( *m_allocator, Message, message ); - } - } - - /** - Get the number of message types supported by this message factory. - @returns The number of message types. - */ - - int GetNumTypes() const - { - return m_numTypes; - } - - /** - Get the allocator used to create messages. - @returns The allocator. - */ - - Allocator & GetAllocator() - { - yojimbo_assert( m_allocator ); - return *m_allocator; - } - - /** - Get the error level. - When used with a client or server, an error level on a message factory other than MESSAGE_FACTORY_ERROR_NONE triggers a client disconnect. - */ - - MessageFactoryErrorLevel GetErrorLevel() const - { - return m_errorLevel; - } - - /** - Clear the error level back to no error. - */ - - void ClearErrorLevel() - { - m_errorLevel = MESSAGE_FACTORY_ERROR_NONE; - } - - protected: - - /** - This method is overridden to create messages by type. - @param type The type of message to be created. - @returns The message created. Its reference count is 1. - */ - - virtual Message * CreateMessageInternal( int type ) { (void) type; return NULL; } - - /** - Set the message type of a message. - @param message The message object. - @param type The message type to set. - */ - - void SetMessageType( Message * message, int type ) { message->SetType( type ); } - - private: - - #if YOJIMBO_DEBUG_MESSAGE_LEAKS - std::map allocated_messages; ///< The set of allocated messages for this factory. Used to track down message leaks. - #endif // #if YOJIMBO_DEBUG_MESSAGE_LEAKS - - Allocator * m_allocator; ///< The allocator used to create messages. - - int m_numTypes; ///< The number of message types. - - MessageFactoryErrorLevel m_errorLevel; ///< The message factory error level. - }; -} - -/** - Start a definition of a new message factory. - This is a helper macro to make declaring your own message factory class easier. - @param factory_class The name of the message factory class to generate. - @param num_message_types The number of message types for this factory. - See shared.h for an example of usage. - */ - -#define YOJIMBO_MESSAGE_FACTORY_START( factory_class, num_message_types ) \ - \ - class factory_class : public yojimbo::MessageFactory \ - { \ - public: \ - factory_class( yojimbo::Allocator & allocator ) : MessageFactory( allocator, num_message_types ) {} \ - yojimbo::Message * CreateMessageInternal( int type ) \ - { \ - yojimbo::Message * message; \ - yojimbo::Allocator & allocator = GetAllocator(); \ - (void) allocator; \ - switch ( type ) \ - { \ - -/** - Add a message type to a message factory. - This is a helper macro to make declaring your own message factory class easier. - @param message_type The message type value. This is typically an enum value. - @param message_class The message class to instantiate when a message of this type is created. - See shared.h for an example of usage. - */ - -#define YOJIMBO_DECLARE_MESSAGE_TYPE( message_type, message_class ) \ - \ - case message_type: \ - message = YOJIMBO_NEW( allocator, message_class, ); \ - if ( !message ) \ - return NULL; \ - SetMessageType( message, message_type ); \ - return message; - -/** - Finish the definition of a new message factory. - This is a helper macro to make declaring your own message factory class easier. - See shared.h for an example of usage. - */ - -#define YOJIMBO_MESSAGE_FACTORY_FINISH() \ - \ - default: return NULL; \ - } \ - } \ - }; - -/** - Helper function to serialize a block attached to a message. Used by channel implementations. - */ - -template bool SerializeMessageBlock( Stream & stream, yojimbo::MessageFactory & messageFactory, yojimbo::BlockMessage * blockMessage, int maxBlockSize ) -{ - int blockSize = Stream::IsWriting ? blockMessage->GetBlockSize() : 0; - - serialize_int( stream, blockSize, 1, maxBlockSize ); - - uint8_t * blockData; - - if ( Stream::IsReading ) - { - yojimbo::Allocator & allocator = messageFactory.GetAllocator(); - blockData = (uint8_t*) YOJIMBO_ALLOCATE( allocator, blockSize ); - if ( !blockData ) - { - yojimbo_printf( YOJIMBO_LOG_LEVEL_ERROR, "error: failed to allocate message block (SerializeMessageBlock)\n" ); - return false; - } - blockMessage->AttachBlock( allocator, blockData, blockSize ); - } - else - { - blockData = blockMessage->GetBlockData(); - } - - serialize_bytes( stream, blockData, blockSize ); - - return true; -} - -#endif // #ifndef YOJIMBO_MESSAGE_H diff --git a/yojimbo_network_info.h b/yojimbo_network_info.h deleted file mode 100644 index 7195a192..00000000 --- a/yojimbo_network_info.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_NETWORK_INFO_H -#define YOJIMBO_NETWORK_INFO_H - -#include "yojimbo_config.h" - -namespace yojimbo -{ - /** - Network information for a connection. - Contains statistics like round trip time (RTT), packet loss %, bandwidth estimates, number of packets sent, received and acked. - */ - - struct NetworkInfo - { - float RTT; ///< Round trip time estimate (milliseconds). - float packetLoss; ///< Packet loss percent. - float sentBandwidth; ///< Sent bandwidth (kbps). - float receivedBandwidth; ///< Received bandwidth (kbps). - float ackedBandwidth; ///< Acked bandwidth (kbps). - uint64_t numPacketsSent; ///< Number of packets sent. - uint64_t numPacketsReceived; ///< Number of packets received. - uint64_t numPacketsAcked; ///< Number of packets acked. - }; -} - -#endif // #ifndef YOJIMBO_NETWORK_INFO_H diff --git a/yojimbo_network_simulator.cpp b/yojimbo_network_simulator.cpp deleted file mode 100644 index 7d36727f..00000000 --- a/yojimbo_network_simulator.cpp +++ /dev/null @@ -1,173 +0,0 @@ -#include "yojimbo_network_simulator.h" -#include "yojimbo_platform.h" -#include "yojimbo_utils.h" - -namespace yojimbo -{ - NetworkSimulator::NetworkSimulator( Allocator & allocator, int numPackets, double time ) - { - yojimbo_assert( numPackets > 0 ); - m_allocator = &allocator; - m_currentIndex = 0; - m_time = time; - m_latency = 0.0f; - m_jitter = 0.0f; - m_packetLoss = 0.0f; - m_duplicates = 0.0f; - m_active = false; - m_numPacketEntries = numPackets; - m_packetEntries = (PacketEntry*) YOJIMBO_ALLOCATE( allocator, sizeof( PacketEntry ) * numPackets ); - yojimbo_assert( m_packetEntries ); - memset( m_packetEntries, 0, sizeof( PacketEntry ) * numPackets ); - } - - NetworkSimulator::~NetworkSimulator() - { - yojimbo_assert( m_allocator ); - yojimbo_assert( m_packetEntries ); - yojimbo_assert( m_numPacketEntries > 0 ); - DiscardPackets(); - YOJIMBO_FREE( *m_allocator, m_packetEntries ); - m_numPacketEntries = 0; - m_allocator = NULL; - } - - void NetworkSimulator::SetLatency( float milliseconds ) - { - m_latency = milliseconds; - UpdateActive(); - } - - void NetworkSimulator::SetJitter( float milliseconds ) - { - m_jitter = milliseconds; - UpdateActive(); - } - - void NetworkSimulator::SetPacketLoss( float percent ) - { - m_packetLoss = percent; - UpdateActive(); - } - - void NetworkSimulator::SetDuplicates( float percent ) - { - m_duplicates = percent; - UpdateActive(); - } - - bool NetworkSimulator::IsActive() const - { - return m_active; - } - - void NetworkSimulator::UpdateActive() - { - bool previous = m_active; - m_active = m_latency != 0.0f || m_jitter != 0.0f || m_packetLoss != 0.0f || m_duplicates != 0.0f; - if ( previous && !m_active ) - { - DiscardPackets(); - } - } - - void NetworkSimulator::SendPacket( int to, uint8_t * packetData, int packetBytes ) - { - yojimbo_assert( m_allocator ); - yojimbo_assert( packetData ); - yojimbo_assert( packetBytes > 0 ); - - if ( yojimbo_random_float( 0.0f, 100.0f ) <= m_packetLoss ) - { - return; - } - - PacketEntry & packetEntry = m_packetEntries[m_currentIndex]; - - if ( packetEntry.packetData ) - { - YOJIMBO_FREE( *m_allocator, packetEntry.packetData ); - packetEntry = PacketEntry(); - } - - double delay = m_latency / 1000.0; - - if ( m_jitter > 0 ) - delay += yojimbo_random_float( -m_jitter, +m_jitter ) / 1000.0; - - packetEntry.to = to; - packetEntry.packetData = (uint8_t*) YOJIMBO_ALLOCATE( *m_allocator, packetBytes ); - memcpy( packetEntry.packetData, packetData, packetBytes ); - packetEntry.packetBytes = packetBytes; - packetEntry.deliveryTime = m_time + delay; - m_currentIndex = ( m_currentIndex + 1 ) % m_numPacketEntries; - - if ( yojimbo_random_float( 0.0f, 100.0f ) <= m_duplicates ) - { - PacketEntry & nextPacketEntry = m_packetEntries[m_currentIndex]; - nextPacketEntry.to = to; - nextPacketEntry.packetData = (uint8_t*) YOJIMBO_ALLOCATE( *m_allocator, packetBytes ); - memcpy( nextPacketEntry.packetData, packetData, packetBytes ); - nextPacketEntry.packetBytes = packetBytes; - nextPacketEntry.deliveryTime = m_time + delay + yojimbo_random_float( 0, +1.0 ); - m_currentIndex = ( m_currentIndex + 1 ) % m_numPacketEntries; - } - } - - int NetworkSimulator::ReceivePackets( int maxPackets, uint8_t * packetData[], int packetBytes[], int to[] ) - { - if ( !IsActive() ) - return 0; - - int numPackets = 0; - - for ( int i = 0; i < yojimbo_min( m_numPacketEntries, maxPackets ); ++i ) - { - if ( !m_packetEntries[i].packetData ) - continue; - - if ( m_packetEntries[i].deliveryTime < m_time ) - { - packetData[numPackets] = m_packetEntries[i].packetData; - packetBytes[numPackets] = m_packetEntries[i].packetBytes; - if ( to ) - { - to[numPackets] = m_packetEntries[i].to; - } - m_packetEntries[i].packetData = NULL; - numPackets++; - } - } - - return numPackets; - } - - void NetworkSimulator::DiscardPackets() - { - for ( int i = 0; i < m_numPacketEntries; ++i ) - { - PacketEntry & packetEntry = m_packetEntries[i]; - if ( !packetEntry.packetData ) - continue; - YOJIMBO_FREE( *m_allocator, packetEntry.packetData ); - packetEntry = PacketEntry(); - } - } - - void NetworkSimulator::DiscardClientPackets( int clientIndex ) - { - for ( int i = 0; i < m_numPacketEntries; ++i ) - { - PacketEntry & packetEntry = m_packetEntries[i]; - if ( !packetEntry.packetData || packetEntry.to != clientIndex ) - continue; - YOJIMBO_FREE( *m_allocator, packetEntry.packetData ); - packetEntry = PacketEntry(); - } - } - - void NetworkSimulator::AdvanceTime( double time ) - { - m_time = time; - } -} diff --git a/yojimbo_network_simulator.h b/yojimbo_network_simulator.h deleted file mode 100644 index 6df477a4..00000000 --- a/yojimbo_network_simulator.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_NETWORK_SIMULATOR_H -#define YOJIMBO_NETWORK_SIMULATOR_H - -#include "yojimbo_config.h" -#include "yojimbo_allocator.h" - -namespace yojimbo -{ - /** - Simulates packet loss, latency, jitter and duplicate packets. - This is useful during development, so your game is tested and played under real world conditions, instead of ideal LAN conditions. - This simulator works on packet send. This means that if you want 125ms of latency (round trip), you must to add 125/2 = 62.5ms of latency to each side. - */ - - class NetworkSimulator - { - public: - - /** - Create a network simulator. - Initial network conditions are set to: - Latency: 0ms - Jitter: 0ms - Packet Loss: 0% - Duplicates: 0% - @param allocator The allocator to use. - @param numPackets The maximum number of packets that can be stored in the simulator at any time. - @param time The initial time value in seconds. - */ - - NetworkSimulator( Allocator & allocator, int numPackets, double time ); - - /** - Network simulator destructor. - Any packet data still in the network simulator is destroyed. - */ - - ~NetworkSimulator(); - - /** - Set the latency in milliseconds. - This latency is added on packet send. To simulate a round trip time of 100ms, add 50ms of latency to both sides of the connection. - @param milliseconds The latency to add in milliseconds. - */ - - void SetLatency( float milliseconds ); - - /** - Set the packet jitter in milliseconds. - Jitter is applied +/- this amount in milliseconds. To be truly effective, jitter must be applied together with some latency. - @param milliseconds The amount of jitter to add in milliseconds (+/-). - */ - - void SetJitter( float milliseconds ); - - /** - Set the amount of packet loss to apply on send. - @param percent The packet loss percentage. 0% = no packet loss. 100% = all packets are dropped. - */ - - void SetPacketLoss( float percent ); - - /** - Set percentage chance of packet duplicates. - If the duplicate chance succeeds, a duplicate packet is added to the queue with a random delay of up to 1 second. - @param percent The percentage chance of a packet duplicate being sent. 0% = no duplicate packets. 100% = all packets have a duplicate sent. - */ - - void SetDuplicates( float percent ); - - /** - Is the network simulator active? - The network simulator is active when packet loss, latency, duplicates or jitter are non-zero values. - This is used by the transport to know whether it should shunt packets through the simulator, or send them directly to the network. This is a minor optimization. - */ - - bool IsActive() const; - - /** - Queue a packet to send. - IMPORTANT: Ownership of the packet data pointer is *not* transferred to the network simulator. It makes a copy of the data instead. - @param to The slot index the packet should be sent to. - @param packetData The packet data. - @param packetBytes The packet size (bytes). - */ - - void SendPacket( int to, uint8_t * packetData, int packetBytes ); - - /** - Receive packets sent to any address. - IMPORTANT: You take ownership of the packet data you receive and are responsible for freeing it. See NetworkSimulator::GetAllocator. - @param maxPackets The maximum number of packets to receive. - @param packetData Array of packet data pointers to be filled [out]. - @param packetBytes Array of packet sizes to be filled [out]. - @param to Array of to indices to be filled [out]. - @returns The number of packets received. - */ - - int ReceivePackets( int maxPackets, uint8_t * packetData[], int packetBytes[], int to[] ); - - /** - Discard all packets in the network simulator. - This is useful if the simulator needs to be reset and used for another purpose. - */ - - void DiscardPackets(); - - /** - Discard packets sent to a particular client index. - This is called when a client disconnects from the server. - */ - - void DiscardClientPackets( int clientIndex ); - - /** - Advance network simulator time. - You must pump this regularly otherwise the network simulator won't work. - @param time The current time value. Please make sure you use double values for time so you retain sufficient precision as time increases. - */ - - void AdvanceTime( double time ); - - /** - Get the allocator to use to free packet data. - @returns The allocator that packet data is allocated with. - */ - - Allocator & GetAllocator() { yojimbo_assert( m_allocator ); return *m_allocator; } - - protected: - - /** - Helper function to update the active flag whenever network settings are changed. - Active is set to true if any of the network conditions are non-zero. This allows you to quickly check if the network simulator is active and would actually do something. - */ - - void UpdateActive(); - - private: - - Allocator * m_allocator; ///< The allocator passed in to the constructor. It's used to allocate and free packet data. - float m_latency; ///< Latency in milliseconds - float m_jitter; ///< Jitter in milliseconds +/- - float m_packetLoss; ///< Packet loss percentage. - float m_duplicates; ///< Duplicate packet percentage - bool m_active; ///< True if network simulator is active, eg. if any of the network settings above are enabled. - - /// A packet buffered in the network simulator. - - struct PacketEntry - { - PacketEntry() - { - to = 0; - deliveryTime = 0.0; - packetData = NULL; - packetBytes = 0; - } - - int to; ///< To index this packet should be sent to (for server -> client packets). - double deliveryTime; ///< Delivery time for this packet (seconds). - uint8_t * packetData; ///< Packet data (owns this pointer). - int packetBytes; ///< Size of packet in bytes. - }; - - double m_time; ///< Current time from last call to advance time. - int m_currentIndex; ///< Current index in the packet entry array. New packets are inserted here. - int m_numPacketEntries; ///< Number of elements in the packet entry array. - PacketEntry * m_packetEntries; ///< Pointer to dynamically allocated packet entries. This is where buffered packets are stored. - }; -} - -#endif // #ifndef YOJIMBO_NETWORK_SIMULATOR_H diff --git a/yojimbo_platform.cpp b/yojimbo_platform.cpp deleted file mode 100644 index 14ca12e7..00000000 --- a/yojimbo_platform.cpp +++ /dev/null @@ -1,201 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "yojimbo_platform.h" -#include "netcode.h" -#include "reliable.h" -#include -#include - -static void default_assert_handler( const char * condition, const char * function, const char * file, int line ) -{ - // We use YOJIMBO_LOG_LEVEL_NONE because it's lower than YOJIMBO_LOG_LEVEL_ERROR, so even if you suppress errors (by setting - // yojimbo_log_level(YOJIMBO_LOG_LEVEL_NONE)), this will still be logged. - yojimbo_printf( YOJIMBO_LOG_LEVEL_NONE, "assert failed: ( %s ), function %s, file %s, line %d\n", condition, function, file, line ); - #if defined( __GNUC__ ) - __builtin_trap(); - #elif defined( _MSC_VER ) - __debugbreak(); - #endif -} - -static int log_level = 0; -static int (*printf_function)( const char *, ... ) = printf; -void (*yojimbo_assert_function)( const char *, const char *, const char * file, int line ) = default_assert_handler; - -void yojimbo_log_level( int level ) -{ - log_level = level; - netcode_log_level( level ); - reliable_log_level( level ); -} - -void yojimbo_set_printf_function( int (*function)( const char *, ... ) ) -{ - yojimbo_assert( function ); - printf_function = function; - netcode_set_printf_function( function ); - reliable_set_printf_function( function ); -} - -void yojimbo_set_assert_function( void (*function)( const char *, const char *, const char * file, int line ) ) -{ - yojimbo_assert_function = function; - netcode_set_assert_function( function ); - reliable_set_assert_function( function ); -} - -#if YOJIMBO_ENABLE_LOGGING - -void yojimbo_printf( int level, const char * format, ... ) -{ - if ( level > log_level ) - return; - va_list args; - va_start( args, format ); - char buffer[4*1024]; - vsnprintf( buffer, sizeof(buffer), format, args ); - printf_function( "%s", buffer ); - va_end( args ); -} - -#else // #if YOJIMBO_ENABLE_LOGGING - -void yojimbo_printf( int level, const char * format, ... ) -{ - (void) level; - (void) format; -} - -#endif // #if YOJIMBO_ENABLE_LOGGING - -#if __APPLE__ - -// =============================== -// MacOS -// =============================== - -#include -#include -#include - -void yojimbo_sleep( double time ) -{ - usleep( (int) ( time * 1000000 ) ); -} - -double yojimbo_time() -{ - static uint64_t start = 0; - - static mach_timebase_info_data_t timebase_info; - - if ( start == 0 ) - { - mach_timebase_info( &timebase_info ); - start = mach_absolute_time(); - return 0.0; - } - - uint64_t current = mach_absolute_time(); - - if ( current < start ) - current = start; - - return ( double( current - start ) * double( timebase_info.numer ) / double( timebase_info.denom ) ) / 1000000000.0; -} - -#elif __linux - -// =============================== -// Linux -// =============================== - -#include -#include - -void yojimbo_sleep( double time ) -{ - usleep( (int) ( time * 1000000 ) ); -} - -double yojimbo_time() -{ - static double start = -1; - - if ( start == -1 ) - { - timespec ts; - clock_gettime( CLOCK_MONOTONIC_RAW, &ts ); - start = ts.tv_sec + double( ts.tv_nsec ) / 1000000000.0; - return 0.0; - } - - timespec ts; - clock_gettime( CLOCK_MONOTONIC_RAW, &ts ); - double current = ts.tv_sec + double( ts.tv_nsec ) / 1000000000.0; - if ( current < start ) - current = start; - return current - start; -} - -#elif defined(_WIN32) - -// =============================== -// Windows -// =============================== - -#define NOMINMAX -#include - -void yojimbo_sleep( double time ) -{ - const int milliseconds = time * 1000; - Sleep( milliseconds ); -} - -static bool timer_initialized = false; -static LARGE_INTEGER timer_frequency; -static LARGE_INTEGER timer_start; - -double yojimbo_time() -{ - if ( !timer_initialized ) - { - QueryPerformanceFrequency( &timer_frequency ); - QueryPerformanceCounter( &timer_start ); - timer_initialized = true; - } - LARGE_INTEGER now; - QueryPerformanceCounter( &now ); - if ( now.QuadPart < timer_start.QuadPart ) - now.QuadPart = timer_start.QuadPart; - return double( now.QuadPart - timer_start.QuadPart ) / double( timer_frequency.QuadPart ); -} - -#else - -#error unsupported platform! - -#endif diff --git a/yojimbo_platform.h b/yojimbo_platform.h deleted file mode 100644 index 099d7560..00000000 --- a/yojimbo_platform.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_PLATFORM_H -#define YOJIMBO_PLATFORM_H - -#include "yojimbo_config.h" - -/** - Sleep for approximately this number of seconds. - @param time number of seconds to sleep for. - */ - -void yojimbo_sleep( double time ); - -/** - Get a high precision time in seconds since the application has started. - Please store time in doubles so you retain sufficient precision as time increases. - @returns Time value in seconds. - */ - -double yojimbo_time(); - -#define YOJIMBO_LOG_LEVEL_NONE 0 -#define YOJIMBO_LOG_LEVEL_ERROR 1 -#define YOJIMBO_LOG_LEVEL_INFO 2 -#define YOJIMBO_LOG_LEVEL_DEBUG 3 - -/** - Set the yojimbo log level. - Valid log levels are: YOJIMBO_LOG_LEVEL_NONE, YOJIMBO_LOG_LEVEL_ERROR, YOJIMBO_LOG_LEVEL_INFO and YOJIMBO_LOG_LEVEL_DEBUG - @param level The log level to set. Initially set to YOJIMBO_LOG_LEVEL_NONE. - */ - -void yojimbo_log_level( int level ); - -/** - Printf function used by yojimbo to emit logs. - This function internally calls the printf callback set by the user. - @see yojimbo_set_printf_function - */ - -void yojimbo_printf( int level, const char * format, ... ); - -extern void (*yojimbo_assert_function)( const char *, const char *, const char * file, int line ); - -/** - Assert function used by yojimbo. - This assert function lets the user override the assert presentation. - @see yojimbo_set_assert_functio - */ - -#ifdef YOJIMBO_DEBUG -#define yojimbo_assert( condition ) \ -do \ -{ \ - if ( !(condition) ) \ - { \ - yojimbo_assert_function( #condition, __FUNCTION__, __FILE__, __LINE__ ); \ - exit(1); \ - } \ -} while(0) -#else -#define yojimbo_assert( ignore ) ((void)0) -#endif - -/** - Call this to set the printf function to use for logging. - @param function The printf callback function. - */ - -void yojimbo_set_printf_function( int (*function)( const char * /*format*/, ... ) ); - -/** - Call this to set the function to call when an assert triggers. - @param function The assert callback function. - */ - -void yojimbo_set_assert_function( void (*function)( const char * /*condition*/, const char * /*function*/, const char * /*file*/, int /*line*/ ) ); - -#endif // # YOJIMBO_PLATFORM_H diff --git a/yojimbo_queue.h b/yojimbo_queue.h deleted file mode 100644 index 67f7b1d1..00000000 --- a/yojimbo_queue.h +++ /dev/null @@ -1,194 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_QUEUE_H -#define YOJIMBO_QUEUE_H - -#include "yojimbo_config.h" - -namespace yojimbo -{ - /** - A simple templated queue. - This is a FIFO queue. First entry in, first entry out. - */ - - template class Queue - { - public: - - /** - Queue constructor. - @param allocator The allocator to use. - @param size The maximum number of entries in the queue. - */ - - Queue( Allocator & allocator, int size ) - { - yojimbo_assert( size > 0 ); - m_arraySize = size; - m_startIndex = 0; - m_numEntries = 0; - m_allocator = &allocator; - m_entries = (T*) YOJIMBO_ALLOCATE( allocator, sizeof(T) * size ); - memset( m_entries, 0, sizeof(T) * size ); - } - - /** - Queue destructor. - */ - - ~Queue() - { - yojimbo_assert( m_allocator ); - - YOJIMBO_FREE( *m_allocator, m_entries ); - - m_arraySize = 0; - m_startIndex = 0; - m_numEntries = 0; - - m_allocator = NULL; - } - - /** - Clear all entries in the queue and reset back to default state. - */ - - void Clear() - { - m_numEntries = 0; - m_startIndex = 0; - } - - /** - Pop a value off the queue. - IMPORTANT: This will assert if the queue is empty. Check Queue::IsEmpty or Queue::GetNumEntries first! - @returns The value popped off the queue. - */ - - T Pop() - { - yojimbo_assert( !IsEmpty() ); - const T & entry = m_entries[m_startIndex]; - m_startIndex = ( m_startIndex + 1 ) % m_arraySize; - m_numEntries--; - return entry; - } - - /** - Push a value on to the queue. - @param value The value to push onto the queue. - IMPORTANT: Will assert if the queue is already full. Check Queue::IsFull before calling this! - */ - - void Push( const T & value ) - { - yojimbo_assert( !IsFull() ); - const int index = ( m_startIndex + m_numEntries ) % m_arraySize; - m_entries[index] = value; - m_numEntries++; - } - - /** - Random access for entries in the queue. - @param index The index into the queue. 0 is the oldest entry, Queue::GetNumEntries() - 1 is the newest. - @returns The value in the queue at the index. - */ - - T & operator [] ( int index ) - { - yojimbo_assert( !IsEmpty() ); - yojimbo_assert( index >= 0 ); - yojimbo_assert( index < m_numEntries ); - return m_entries[ ( m_startIndex + index ) % m_arraySize ]; - } - - /** - Random access for entries in the queue (const version). - @param index The index into the queue. 0 is the oldest entry, Queue::GetNumEntries() - 1 is the newest. - @returns The value in the queue at the index. - */ - - const T & operator [] ( int index ) const - { - yojimbo_assert( !IsEmpty() ); - yojimbo_assert( index >= 0 ); - yojimbo_assert( index < m_numEntries ); - return m_entries[ ( m_startIndex + index ) % m_arraySize ]; - } - - /** - Get the size of the queue. - This is the maximum number of values that can be pushed on the queue. - @returns The size of the queue. - */ - - int GetSize() const - { - return m_arraySize; - } - - /** - Is the queue currently full? - @returns True if the queue is full. False otherwise. - */ - - bool IsFull() const - { - return m_numEntries == m_arraySize; - } - - /** - Is the queue currently empty? - @returns True if there are no entries in the queue. - */ - - bool IsEmpty() const - { - return m_numEntries == 0; - } - - /** - Get the number of entries in the queue. - @returns The number of entries in the queue in [0,GetSize()]. - */ - - int GetNumEntries() const - { - return m_numEntries; - } - - private: - - - Allocator * m_allocator; ///< The allocator passed in to the constructor. - T * m_entries; ///< Array of entries backing the queue (circular buffer). - int m_arraySize; ///< The size of the array, in number of entries. This is the "size" of the queue. - int m_startIndex; ///< The start index for the queue. This is the next value that gets popped off. - int m_numEntries; ///< The number of entries currently stored in the queue. - }; -} - -#endif // #ifndef YOJIMBO_QUEUE_H diff --git a/yojimbo_reliable_ordered_channel.cpp b/yojimbo_reliable_ordered_channel.cpp deleted file mode 100644 index a2d745c8..00000000 --- a/yojimbo_reliable_ordered_channel.cpp +++ /dev/null @@ -1,766 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "yojimbo_reliable_ordered_channel.h" -#include "yojimbo_utils.h" - -namespace yojimbo -{ - ReliableOrderedChannel::ReliableOrderedChannel( Allocator & allocator, MessageFactory & messageFactory, const ChannelConfig & config, int channelIndex, double time ) - : Channel( allocator, messageFactory, config, channelIndex, time ) - { - yojimbo_assert( config.type == CHANNEL_TYPE_RELIABLE_ORDERED ); - - yojimbo_assert( ( 65536 % config.sentPacketBufferSize ) == 0 ); - yojimbo_assert( ( 65536 % config.messageSendQueueSize ) == 0 ); - yojimbo_assert( ( 65536 % config.messageReceiveQueueSize ) == 0 ); - - m_sentPackets = YOJIMBO_NEW( *m_allocator, SequenceBuffer, *m_allocator, m_config.sentPacketBufferSize ); - m_messageSendQueue = YOJIMBO_NEW( *m_allocator, SequenceBuffer, *m_allocator, m_config.messageSendQueueSize ); - m_messageReceiveQueue = YOJIMBO_NEW( *m_allocator, SequenceBuffer, *m_allocator, m_config.messageReceiveQueueSize ); - m_sentPacketMessageIds = (uint16_t*) YOJIMBO_ALLOCATE( *m_allocator, sizeof( uint16_t ) * m_config.maxMessagesPerPacket * m_config.sentPacketBufferSize ); - - if ( !config.disableBlocks ) - { - m_sendBlock = YOJIMBO_NEW( *m_allocator, SendBlockData, *m_allocator, m_config.GetMaxFragmentsPerBlock() ); - m_receiveBlock = YOJIMBO_NEW( *m_allocator, ReceiveBlockData, *m_allocator, m_config.maxBlockSize, m_config.GetMaxFragmentsPerBlock() ); - } - else - { - m_sendBlock = NULL; - m_receiveBlock = NULL; - } - - Reset(); - } - - ReliableOrderedChannel::~ReliableOrderedChannel() - { - Reset(); - - YOJIMBO_DELETE( *m_allocator, SendBlockData, m_sendBlock ); - YOJIMBO_DELETE( *m_allocator, ReceiveBlockData, m_receiveBlock ); - YOJIMBO_DELETE( *m_allocator, SequenceBuffer, m_sentPackets ); - YOJIMBO_DELETE( *m_allocator, SequenceBuffer, m_messageSendQueue ); - YOJIMBO_DELETE( *m_allocator, SequenceBuffer, m_messageReceiveQueue ); - - YOJIMBO_FREE( *m_allocator, m_sentPacketMessageIds ); - - m_sentPacketMessageIds = NULL; - } - - void ReliableOrderedChannel::Reset() - { - SetErrorLevel( CHANNEL_ERROR_NONE ); - - m_sendMessageId = 0; - m_receiveMessageId = 0; - m_oldestUnackedMessageId = 0; - - for ( int i = 0; i < m_messageSendQueue->GetSize(); ++i ) - { - MessageSendQueueEntry * entry = m_messageSendQueue->GetAtIndex( i ); - if ( entry && entry->message ) - m_messageFactory->ReleaseMessage( entry->message ); - } - - for ( int i = 0; i < m_messageReceiveQueue->GetSize(); ++i ) - { - MessageReceiveQueueEntry * entry = m_messageReceiveQueue->GetAtIndex( i ); - if ( entry && entry->message ) - m_messageFactory->ReleaseMessage( entry->message ); - } - - m_sentPackets->Reset(); - m_messageSendQueue->Reset(); - m_messageReceiveQueue->Reset(); - - if ( m_sendBlock ) - { - m_sendBlock->Reset(); - } - - if ( m_receiveBlock ) - { - m_receiveBlock->Reset(); - if ( m_receiveBlock->blockMessage ) - { - m_messageFactory->ReleaseMessage( m_receiveBlock->blockMessage ); - m_receiveBlock->blockMessage = NULL; - } - } - - ResetCounters(); - } - -#undef SendMessage - - bool ReliableOrderedChannel::CanSendMessage() const - { - yojimbo_assert( m_messageSendQueue ); - return m_messageSendQueue->Available( m_sendMessageId ); - } - - void ReliableOrderedChannel::SendMessage( Message * message, void *context ) - { - yojimbo_assert( message ); - - yojimbo_assert( CanSendMessage() ); - - if ( GetErrorLevel() != CHANNEL_ERROR_NONE ) - { - m_messageFactory->ReleaseMessage( message ); - return; - } - - if ( !CanSendMessage() ) - { - // Increase your send queue size! - SetErrorLevel( CHANNEL_ERROR_SEND_QUEUE_FULL ); - m_messageFactory->ReleaseMessage( message ); - return; - } - - yojimbo_assert( !( message->IsBlockMessage() && m_config.disableBlocks ) ); - - if ( message->IsBlockMessage() && m_config.disableBlocks ) - { - // You tried to send a block message, but block messages are disabled for this channel! - SetErrorLevel( CHANNEL_ERROR_BLOCKS_DISABLED ); - m_messageFactory->ReleaseMessage( message ); - return; - } - - message->SetId( m_sendMessageId ); - - MessageSendQueueEntry * entry = m_messageSendQueue->Insert( m_sendMessageId ); - - yojimbo_assert( entry ); - - entry->block = message->IsBlockMessage(); - entry->message = message; - entry->measuredBits = 0; - entry->timeLastSent = -1.0; - - if ( message->IsBlockMessage() ) - { - yojimbo_assert( ((BlockMessage*)message)->GetBlockSize() > 0 ); - yojimbo_assert( ((BlockMessage*)message)->GetBlockSize() <= m_config.maxBlockSize ); - } - - MeasureStream measureStream; - measureStream.SetContext( context ); - measureStream.SetAllocator( &m_messageFactory->GetAllocator() ); - message->SerializeInternal( measureStream ); - entry->measuredBits = measureStream.GetBitsProcessed(); - m_counters[CHANNEL_COUNTER_MESSAGES_SENT]++; - m_sendMessageId++; - } - - Message * ReliableOrderedChannel::ReceiveMessage() - { - if ( GetErrorLevel() != CHANNEL_ERROR_NONE ) - return NULL; - - MessageReceiveQueueEntry * entry = m_messageReceiveQueue->Find( m_receiveMessageId ); - if ( !entry ) - return NULL; - - Message * message = entry->message; - yojimbo_assert( message ); - yojimbo_assert( message->GetId() == m_receiveMessageId ); - m_messageReceiveQueue->Remove( m_receiveMessageId ); - m_counters[CHANNEL_COUNTER_MESSAGES_RECEIVED]++; - m_receiveMessageId++; - - return message; - } - - void ReliableOrderedChannel::AdvanceTime( double time ) - { - m_time = time; - } - - int ReliableOrderedChannel::GetPacketData( void *context, ChannelPacketData & packetData, uint16_t packetSequence, int availableBits ) - { - if ( !HasMessagesToSend() ) - return 0; - - if ( SendingBlockMessage() ) - { - if (m_config.blockFragmentSize * 8 > availableBits) - return 0; - - uint16_t messageId; - uint16_t fragmentId; - int fragmentBytes; - int numFragments; - int messageType; - - uint8_t * fragmentData = GetFragmentToSend( messageId, fragmentId, fragmentBytes, numFragments, messageType ); - - if ( fragmentData ) - { - const int fragmentBits = GetFragmentPacketData( packetData, messageId, fragmentId, fragmentData, fragmentBytes, numFragments, messageType ); - AddFragmentPacketEntry( messageId, fragmentId, packetSequence ); - return fragmentBits; - } - } - else - { - int numMessageIds = 0; - uint16_t * messageIds = (uint16_t*) alloca( m_config.maxMessagesPerPacket * sizeof( uint16_t ) ); - const int messageBits = GetMessagesToSend( messageIds, numMessageIds, availableBits, context ); - - if ( numMessageIds > 0 ) - { - GetMessagePacketData( packetData, messageIds, numMessageIds ); - AddMessagePacketEntry( messageIds, numMessageIds, packetSequence ); - return messageBits; - } - } - - return 0; - } - - bool ReliableOrderedChannel::HasMessagesToSend() const - { - return m_oldestUnackedMessageId != m_sendMessageId; - } - - int ReliableOrderedChannel::GetMessagesToSend( uint16_t * messageIds, int & numMessageIds, int availableBits, void *context ) - { - yojimbo_assert( HasMessagesToSend() ); - - numMessageIds = 0; - - if ( m_config.packetBudget > 0 ) - availableBits = yojimbo_min( m_config.packetBudget * 8, availableBits ); - - const int giveUpBits = 4 * 8; - const int messageTypeBits = bits_required( 0, m_messageFactory->GetNumTypes() - 1 ); - const int messageLimit = yojimbo_min( m_config.messageSendQueueSize, m_config.messageReceiveQueueSize ); - uint16_t previousMessageId = 0; - int usedBits = ConservativeMessageHeaderBits; - int giveUpCounter = 0; - const int maxBits = availableBits; - - for ( int i = 0; i < messageLimit; ++i ) - { - if ( availableBits - usedBits < giveUpBits ) - break; - - if ( giveUpCounter > m_config.messageSendQueueSize ) - break; - - uint16_t messageId = m_oldestUnackedMessageId + i; - MessageSendQueueEntry * entry = m_messageSendQueue->Find( messageId ); - if ( !entry ) - continue; - - if ( entry->block ) - break; - - // Increase your max packet size! - yojimbo_assert( entry->measuredBits <= maxBits ); - - if ( entry->timeLastSent + m_config.messageResendTime <= m_time && availableBits >= (int) entry->measuredBits ) - { - int messageBits = entry->measuredBits + messageTypeBits; - - if ( numMessageIds == 0 ) - { - messageBits += 16; - } - else - { - MeasureStream stream; - stream.SetContext( context ); - stream.SetAllocator( &m_messageFactory->GetAllocator() ); - serialize_sequence_relative_internal( stream, previousMessageId, messageId ); - messageBits += stream.GetBitsProcessed(); - } - - if ( usedBits + messageBits > availableBits ) - { - giveUpCounter++; - continue; - } - - usedBits += messageBits; - messageIds[numMessageIds++] = messageId; - previousMessageId = messageId; - entry->timeLastSent = m_time; - } - - if ( numMessageIds == m_config.maxMessagesPerPacket ) - break; - } - - return usedBits; - } - - void ReliableOrderedChannel::GetMessagePacketData( ChannelPacketData & packetData, const uint16_t * messageIds, int numMessageIds ) - { - yojimbo_assert( messageIds ); - - packetData.Initialize(); - packetData.channelIndex = GetChannelIndex(); - packetData.message.numMessages = numMessageIds; - - if ( numMessageIds == 0 ) - return; - - packetData.message.messages = (Message**) YOJIMBO_ALLOCATE( m_messageFactory->GetAllocator(), sizeof( Message* ) * numMessageIds ); - - for ( int i = 0; i < numMessageIds; ++i ) - { - MessageSendQueueEntry * entry = m_messageSendQueue->Find( messageIds[i] ); - yojimbo_assert( entry ); - yojimbo_assert( entry->message ); - yojimbo_assert( entry->message->GetRefCount() > 0 ); - packetData.message.messages[i] = entry->message; - m_messageFactory->AcquireMessage( packetData.message.messages[i] ); - } - } - - void ReliableOrderedChannel::AddMessagePacketEntry( const uint16_t * messageIds, int numMessageIds, uint16_t sequence ) - { - SentPacketEntry * sentPacket = m_sentPackets->Insert( sequence, true ); - yojimbo_assert( sentPacket ); - if ( sentPacket ) - { - sentPacket->acked = 0; - sentPacket->block = 0; - sentPacket->timeSent = m_time; - sentPacket->messageIds = &m_sentPacketMessageIds[ ( sequence % m_config.sentPacketBufferSize ) * m_config.maxMessagesPerPacket ]; - sentPacket->numMessageIds = numMessageIds; - for ( int i = 0; i < numMessageIds; ++i ) - { - sentPacket->messageIds[i] = messageIds[i]; - } - } - } - - void ReliableOrderedChannel::ProcessPacketMessages( int numMessages, Message ** messages ) - { - const uint16_t minMessageId = m_receiveMessageId; - const uint16_t maxMessageId = m_receiveMessageId + m_config.messageReceiveQueueSize - 1; - - for ( int i = 0; i < (int) numMessages; ++i ) - { - Message * message = messages[i]; - - yojimbo_assert( message ); - - const uint16_t messageId = message->GetId(); - - if ( yojimbo_sequence_less_than( messageId, minMessageId ) ) - continue; - - if ( yojimbo_sequence_greater_than( messageId, maxMessageId ) ) - { - // Did you forget to dequeue messages on the receiver? - SetErrorLevel( CHANNEL_ERROR_DESYNC ); - return; - } - - if ( m_messageReceiveQueue->Find( messageId ) ) - continue; - - yojimbo_assert( !m_messageReceiveQueue->GetAtIndex( m_messageReceiveQueue->GetIndex( messageId ) ) ); - - MessageReceiveQueueEntry * entry = m_messageReceiveQueue->Insert( messageId ); - if ( !entry ) - { - // For some reason we can't insert the message in the receive queue - SetErrorLevel( CHANNEL_ERROR_DESYNC ); - return; - } - - entry->message = message; - - m_messageFactory->AcquireMessage( message ); - } - } - - void ReliableOrderedChannel::ProcessPacketData( const ChannelPacketData & packetData, uint16_t packetSequence ) - { - if ( m_errorLevel != CHANNEL_ERROR_NONE ) - return; - - if ( packetData.messageFailedToSerialize ) - { - // A message failed to serialize read for some reason, eg. mismatched read/write. - SetErrorLevel( CHANNEL_ERROR_FAILED_TO_SERIALIZE ); - return; - } - - (void)packetSequence; - - if ( packetData.blockMessage ) - { - ProcessPacketFragment( packetData.block.messageType, - packetData.block.messageId, - packetData.block.numFragments, - packetData.block.fragmentId, - packetData.block.fragmentData, - packetData.block.fragmentSize, - packetData.block.message ); - } - else - { - ProcessPacketMessages( packetData.message.numMessages, packetData.message.messages ); - } - } - - void ReliableOrderedChannel::ProcessAck( uint16_t ack ) - { - SentPacketEntry * sentPacketEntry = m_sentPackets->Find( ack ); - if ( !sentPacketEntry ) - return; - - yojimbo_assert( !sentPacketEntry->acked ); - - for ( int i = 0; i < (int) sentPacketEntry->numMessageIds; ++i ) - { - const uint16_t messageId = sentPacketEntry->messageIds[i]; - MessageSendQueueEntry * sendQueueEntry = m_messageSendQueue->Find( messageId ); - if ( sendQueueEntry ) - { - yojimbo_assert( sendQueueEntry->message ); - yojimbo_assert( sendQueueEntry->message->GetId() == messageId ); - m_messageFactory->ReleaseMessage( sendQueueEntry->message ); - m_messageSendQueue->Remove( messageId ); - UpdateOldestUnackedMessageId(); - } - } - - if ( !m_config.disableBlocks && sentPacketEntry->block && m_sendBlock->active && m_sendBlock->blockMessageId == sentPacketEntry->blockMessageId ) - { - const int messageId = sentPacketEntry->blockMessageId; - const int fragmentId = sentPacketEntry->blockFragmentId; - - if ( !m_sendBlock->ackedFragment->GetBit( fragmentId ) ) - { - m_sendBlock->ackedFragment->SetBit( fragmentId ); - m_sendBlock->numAckedFragments++; - if ( m_sendBlock->numAckedFragments == m_sendBlock->numFragments ) - { - m_sendBlock->active = false; - MessageSendQueueEntry * sendQueueEntry = m_messageSendQueue->Find( messageId ); - yojimbo_assert( sendQueueEntry ); - m_messageFactory->ReleaseMessage( sendQueueEntry->message ); - m_messageSendQueue->Remove( messageId ); - UpdateOldestUnackedMessageId(); - } - } - } - } - - void ReliableOrderedChannel::UpdateOldestUnackedMessageId() - { - const uint16_t stopMessageId = m_messageSendQueue->GetSequence(); - - while ( true ) - { - if ( m_oldestUnackedMessageId == stopMessageId || m_messageSendQueue->Find( m_oldestUnackedMessageId ) ) - { - break; - } - ++m_oldestUnackedMessageId; - } - - yojimbo_assert( !yojimbo_sequence_greater_than( m_oldestUnackedMessageId, stopMessageId ) ); - } - - bool ReliableOrderedChannel::SendingBlockMessage() - { - yojimbo_assert( HasMessagesToSend() ); - - MessageSendQueueEntry * entry = m_messageSendQueue->Find( m_oldestUnackedMessageId ); - - return entry ? entry->block : false; - } - - uint8_t * ReliableOrderedChannel::GetFragmentToSend( uint16_t & messageId, uint16_t & fragmentId, int & fragmentBytes, int & numFragments, int & messageType ) - { - MessageSendQueueEntry * entry = m_messageSendQueue->Find( m_oldestUnackedMessageId ); - - yojimbo_assert( entry ); - yojimbo_assert( entry->block ); - - BlockMessage * blockMessage = (BlockMessage*) entry->message; - - yojimbo_assert( blockMessage ); - - messageId = blockMessage->GetId(); - - const int blockSize = blockMessage->GetBlockSize(); - - if ( !m_sendBlock->active ) - { - // start sending this block - - m_sendBlock->active = true; - m_sendBlock->blockSize = blockSize; - m_sendBlock->blockMessageId = messageId; - m_sendBlock->numFragments = (int) ceil( blockSize / float( m_config.blockFragmentSize ) ); - m_sendBlock->numAckedFragments = 0; - - const int MaxFragmentsPerBlock = m_config.GetMaxFragmentsPerBlock(); - - yojimbo_assert( m_sendBlock->numFragments > 0 ); - yojimbo_assert( m_sendBlock->numFragments <= MaxFragmentsPerBlock ); - - m_sendBlock->ackedFragment->Clear(); - - for ( int i = 0; i < MaxFragmentsPerBlock; ++i ) - m_sendBlock->fragmentSendTime[i] = -1.0; - } - - numFragments = m_sendBlock->numFragments; - - // find the next fragment to send (there may not be one) - - fragmentId = 0xFFFF; - - for ( int i = 0; i < m_sendBlock->numFragments; ++i ) - { - if ( !m_sendBlock->ackedFragment->GetBit( i ) && m_sendBlock->fragmentSendTime[i] + m_config.blockFragmentResendTime < m_time ) - { - fragmentId = uint16_t( i ); - break; - } - } - - if ( fragmentId == 0xFFFF ) - return NULL; - - // allocate and return a copy of the fragment data - - messageType = blockMessage->GetType(); - - fragmentBytes = m_config.blockFragmentSize; - - const int fragmentRemainder = blockSize % m_config.blockFragmentSize; - - if ( fragmentRemainder && fragmentId == m_sendBlock->numFragments - 1 ) - fragmentBytes = fragmentRemainder; - - uint8_t * fragmentData = (uint8_t*) YOJIMBO_ALLOCATE( m_messageFactory->GetAllocator(), fragmentBytes ); - - if ( fragmentData ) - { - memcpy( fragmentData, blockMessage->GetBlockData() + fragmentId * m_config.blockFragmentSize, fragmentBytes ); - - m_sendBlock->fragmentSendTime[fragmentId] = m_time; - } - - return fragmentData; - } - - int ReliableOrderedChannel::GetFragmentPacketData( ChannelPacketData & packetData, - uint16_t messageId, - uint16_t fragmentId, - uint8_t * fragmentData, - int fragmentSize, - int numFragments, - int messageType ) - { - packetData.Initialize(); - - packetData.channelIndex = GetChannelIndex(); - - packetData.blockMessage = 1; - - packetData.block.fragmentData = fragmentData; - packetData.block.messageId = messageId; - packetData.block.fragmentId = fragmentId; - packetData.block.fragmentSize = fragmentSize; - packetData.block.numFragments = numFragments; - packetData.block.messageType = messageType; - - const int messageTypeBits = bits_required( 0, m_messageFactory->GetNumTypes() - 1 ); - - int fragmentBits = ConservativeFragmentHeaderBits + fragmentSize * 8; - - if ( fragmentId == 0 ) - { - MessageSendQueueEntry * entry = m_messageSendQueue->Find( packetData.block.messageId ); - - yojimbo_assert( entry ); - yojimbo_assert( entry->message ); - - packetData.block.message = (BlockMessage*) entry->message; - - m_messageFactory->AcquireMessage( packetData.block.message ); - - fragmentBits += entry->measuredBits + messageTypeBits; - } - else - { - packetData.block.message = NULL; - } - - return fragmentBits; - } - - void ReliableOrderedChannel::AddFragmentPacketEntry( uint16_t messageId, uint16_t fragmentId, uint16_t sequence ) - { - SentPacketEntry * sentPacket = m_sentPackets->Insert( sequence, true ); - yojimbo_assert( sentPacket ); - if ( sentPacket ) - { - sentPacket->numMessageIds = 0; - sentPacket->messageIds = NULL; - sentPacket->timeSent = m_time; - sentPacket->acked = 0; - sentPacket->block = 1; - sentPacket->blockMessageId = messageId; - sentPacket->blockFragmentId = fragmentId; - } - } - - void ReliableOrderedChannel::ProcessPacketFragment( int messageType, - uint16_t messageId, - int numFragments, - uint16_t fragmentId, - const uint8_t * fragmentData, - int fragmentBytes, - BlockMessage * blockMessage ) - { - yojimbo_assert( !m_config.disableBlocks ); - - if ( fragmentData ) - { - const uint16_t expectedMessageId = m_messageReceiveQueue->GetSequence(); - if ( messageId != expectedMessageId ) - return; - - // start receiving a new block - - if ( !m_receiveBlock->active ) - { - yojimbo_assert( numFragments >= 0 ); - yojimbo_assert( numFragments <= m_config.GetMaxFragmentsPerBlock() ); - - m_receiveBlock->active = true; - m_receiveBlock->numFragments = numFragments; - m_receiveBlock->numReceivedFragments = 0; - m_receiveBlock->messageId = messageId; - m_receiveBlock->blockSize = 0; - m_receiveBlock->receivedFragment->Clear(); - } - - // validate fragment - - if ( fragmentId >= m_receiveBlock->numFragments ) - { - // The fragment id is out of range. - SetErrorLevel( CHANNEL_ERROR_DESYNC ); - return; - } - - if ( numFragments != m_receiveBlock->numFragments ) - { - // The number of fragments is out of range. - SetErrorLevel( CHANNEL_ERROR_DESYNC ); - return; - } - - // receive the fragment - - if ( !m_receiveBlock->receivedFragment->GetBit( fragmentId ) ) - { - m_receiveBlock->receivedFragment->SetBit( fragmentId ); - - memcpy( m_receiveBlock->blockData + fragmentId * m_config.blockFragmentSize, fragmentData, fragmentBytes ); - - if ( fragmentId == 0 ) - { - m_receiveBlock->messageType = messageType; - } - - if ( fragmentId == m_receiveBlock->numFragments - 1 ) - { - m_receiveBlock->blockSize = ( m_receiveBlock->numFragments - 1 ) * m_config.blockFragmentSize + fragmentBytes; - - if ( m_receiveBlock->blockSize > (uint32_t) m_config.maxBlockSize ) - { - // The block size is outside range - SetErrorLevel( CHANNEL_ERROR_DESYNC ); - return; - } - } - - m_receiveBlock->numReceivedFragments++; - - if ( fragmentId == 0 ) - { - // save block message (sent with fragment 0) - m_receiveBlock->blockMessage = blockMessage; - m_messageFactory->AcquireMessage( m_receiveBlock->blockMessage ); - } - - if ( m_receiveBlock->numReceivedFragments == m_receiveBlock->numFragments ) - { - // finished receiving block - - if ( m_messageReceiveQueue->GetAtIndex( m_messageReceiveQueue->GetIndex( messageId ) ) ) - { - // Did you forget to dequeue messages on the receiver? - SetErrorLevel( CHANNEL_ERROR_DESYNC ); - return; - } - - blockMessage = m_receiveBlock->blockMessage; - - yojimbo_assert( blockMessage ); - - uint8_t * blockData = (uint8_t*) YOJIMBO_ALLOCATE( m_messageFactory->GetAllocator(), m_receiveBlock->blockSize ); - - if ( !blockData ) - { - // Not enough memory to allocate block data - SetErrorLevel( CHANNEL_ERROR_OUT_OF_MEMORY ); - return; - } - - memcpy( blockData, m_receiveBlock->blockData, m_receiveBlock->blockSize ); - - blockMessage->AttachBlock( m_messageFactory->GetAllocator(), blockData, m_receiveBlock->blockSize ); - - blockMessage->SetId( messageId ); - - MessageReceiveQueueEntry * entry = m_messageReceiveQueue->Insert( messageId ); - yojimbo_assert( entry ); - entry->message = blockMessage; - m_receiveBlock->active = false; - m_receiveBlock->blockMessage = NULL; - } - } - } - } -} diff --git a/yojimbo_reliable_ordered_channel.h b/yojimbo_reliable_ordered_channel.h deleted file mode 100644 index 4c06acb5..00000000 --- a/yojimbo_reliable_ordered_channel.h +++ /dev/null @@ -1,381 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_RELIABLE_ORDERED_CHANNEL_H -#define YOJIMBO_RELIABLE_ORDERED_CHANNEL_H - -#include "yojimbo_config.h" -#include "yojimbo_channel.h" -#include "yojimbo_bit_array.h" -#include "yojimbo_sequence_buffer.h" - -namespace yojimbo -{ - /** - Messages sent across this channel are guaranteed to arrive in the order they were sent. - This channel type is best used for control messages and RPCs. - Messages sent over this channel are included in connection packets until one of those packets is acked. Messages are acked individually and remain in the send queue until acked. - Blocks attached to messages sent over this channel are split up into fragments. Each fragment of the block is included in a connection packet until one of those packets are acked. Eventually, all fragments are received on the other side, and block is reassembled and attached to the message. - Only one message block may be in flight over the network at any time, so blocks stall out message delivery slightly. Therefore, only use blocks for large data that won't fit inside a single connection packet where you actually need the channel to split it up into fragments. If your block fits inside a packet, just serialize it inside your message serialize via serialize_bytes instead. - */ - - class ReliableOrderedChannel : public Channel - { - public: - - /** - Reliable ordered channel constructor. - @param allocator The allocator to use. - @param messageFactory Message factory for creating and destroying messages. - @param config The configuration for this channel. - @param channelIndex The channel index in [0,numChannels-1]. - */ - - ReliableOrderedChannel( Allocator & allocator, MessageFactory & messageFactory, const ChannelConfig & config, int channelIndex, double time ); - - /** - Reliable ordered channel destructor. - Any messages still in the send or receive queues will be released. - */ - - ~ReliableOrderedChannel(); - - void Reset(); - - bool CanSendMessage() const; - - void SendMessage( Message * message, void *context ); - - Message * ReceiveMessage(); - - void AdvanceTime( double time ); - - int GetPacketData( void *context, ChannelPacketData & packetData, uint16_t packetSequence, int availableBits ); - - void ProcessPacketData( const ChannelPacketData & packetData, uint16_t packetSequence ); - - void ProcessAck( uint16_t ack ); - - /** - Are there any unacked messages in the send queue? - Messages are acked individually and remain in the send queue until acked. - @returns True if there is at least one unacked message in the send queue. - */ - - bool HasMessagesToSend() const; - - /** - Get messages to include in a packet. - Messages are measured to see how many bits they take, and only messages that fit within the channel packet budget will be included. See ChannelConfig::packetBudget. - Takes care not to send messages too rapidly by respecting ChannelConfig::messageResendTime for each message, and to only include messages that that the receiver is able to buffer in their receive queue. In other words, won't run ahead of the receiver. - @param messageIds Array of message ids to be filled [out]. Fills up to ChannelConfig::maxMessagesPerPacket messages, make sure your array is at least this size. - @param numMessageIds The number of message ids written to the array. - @param remainingPacketBits Number of bits remaining in the packet. Considers this as a hard limit when determining how many messages can fit into the packet. - @returns Estimate of the number of bits required to serialize the messages (upper bound). - @see GetMessagePacketData - */ - - int GetMessagesToSend( uint16_t * messageIds, int & numMessageIds, int remainingPacketBits, void *context ); - - /** - Fill channel packet data with messages. - This is the payload function to fill packet data while sending regular messages (without blocks attached). - Messages have references added to them when they are added to the packet. They also have a reference while they are stored in a send or receive queue. Messages are cleaned up when they are no longer in a queue, and no longer referenced by any packets. - @param packetData The packet data to fill [out] - @param messageIds Array of message ids identifying which messages to add to the packet from the message send queue. - @param numMessageIds The number of message ids in the array. - @see GetMessagesToSend - */ - - void GetMessagePacketData( ChannelPacketData & packetData, const uint16_t * messageIds, int numMessageIds ); - - /** - Add a packet entry for the set of messages included in a packet. - This lets us look up the set of messages that were included in that packet later on when it is acked, so we can ack those messages individually. - @param messageIds The set of message ids that were included in the packet. - @param numMessageIds The number of message ids in the array. - @param sequence The sequence number of the connection packet the messages were included in. - */ - - void AddMessagePacketEntry( const uint16_t * messageIds, int numMessageIds, uint16_t sequence ); - - /** - Process messages included in a packet. - Any messages that have not already been received are added to the message receive queue. Messages that are added to the receive queue have a reference added. See Message::AddRef. - @param numMessages The number of messages to process. - @param messages Array of pointers to messages. - */ - - void ProcessPacketMessages( int numMessages, Message ** messages ); - - /** - Track the oldest unacked message id in the send queue. - Because messages are acked individually, the send queue is not a true queue and may have holes. - Because of this it is necessary to periodically walk forward from the previous oldest unacked message id, to find the current oldest unacked message id. - This lets us know our starting point for considering messages to include in the next packet we send. - @see GetMessagesToSend - */ - - void UpdateOldestUnackedMessageId(); - - /** - True if we are currently sending a block message. - Block messages are treated differently to regular messages. - Regular messages are small so we try to fit as many into the packet we can. See ReliableChannelData::GetMessagesToSend. - Blocks attached to block messages are usually larger than the maximum packet size or channel budget, so they are split up fragments. - While in the mode of sending a block message, each channel packet data generated has exactly one fragment from the current block in it. Fragments keep getting included in packets until all fragments of that block are acked. - @returns True if currently sending a block message over the network, false otherwise. - @see BlockMessage - @see GetFragmentToSend - */ - - bool SendingBlockMessage(); - - /** - Get the next block fragment to send. - The next block fragment is selected by scanning left to right over the set of fragments in the block, skipping over any fragments that have already been acked or have been sent within ChannelConfig::fragmentResendTime. - @param messageId The id of the message that the block is attached to [out]. - @param fragmentId The id of the fragment to send [out]. - @param fragmentBytes The size of the fragment in bytes. - @param numFragments The total number of fragments in this block. - @param messageType The type of message the block is attached to. See MessageFactory. - @returns Pointer to the fragment data. - */ - - uint8_t * GetFragmentToSend( uint16_t & messageId, uint16_t & fragmentId, int & fragmentBytes, int & numFragments, int & messageType ); - - /** - Fill the packet data with block and fragment data. - This is the payload function that fills the channel packet data while we are sending a block message. - @param packetData The packet data to fill [out] - @param messageId The id of the message that the block is attached to. - @param fragmentId The id of the block fragment being sent. - @param fragmentData The fragment data. - @param fragmentSize The size of the fragment data (bytes). - @param numFragments The number of fragments in the block. - @param messageType The type of message the block is attached to. - @returns An estimate of the number of bits required to serialize the block message and fragment data (upper bound). - */ - - int GetFragmentPacketData( ChannelPacketData & packetData, - uint16_t messageId, - uint16_t fragmentId, - uint8_t * fragmentData, - int fragmentSize, - int numFragments, - int messageType ); - - /** - Adds a packet entry for the fragment. - This lets us look up the fragment that was in the packet later on when it is acked, so we can ack that block fragment. - @param messageId The message id that the block was attached to. - @param fragmentId The fragment id. - @param sequence The sequence number of the packet the fragment was included in. - */ - - void AddFragmentPacketEntry( uint16_t messageId, uint16_t fragmentId, uint16_t sequence ); - - /** - Process a packet fragment. - The fragment is added to the set of received fragments for the block. When all packet fragments are received, that block is reconstructed, attached to the block message and added to the message receive queue. - @param messageType The type of the message this block fragment is attached to. This is used to make sure this message type actually allows blocks to be attached to it. - @param messageId The id of the message the block fragment belongs to. - @param numFragments The number of fragments in the block. - @param fragmentId The id of the fragment in [0,numFragments-1]. - @param fragmentData The fragment data. - @param fragmentBytes The size of the fragment data in bytes. - @param blockMessage Pointer to the block message. Passed this in only with the first fragment (0), pass NULL for all other fragments. - */ - - void ProcessPacketFragment( int messageType, - uint16_t messageId, - int numFragments, - uint16_t fragmentId, - const uint8_t * fragmentData, - int fragmentBytes, - BlockMessage * blockMessage ); - - protected: - - /** - An entry in the send queue of the reliable-ordered channel. - Messages stay into the send queue until acked. Each message is acked individually, so there can be "holes" in the message send queue. - */ - - struct MessageSendQueueEntry - { - Message * message; ///< Pointer to the message. When inserted in the send queue the message has one reference. It is released when the message is acked and removed from the send queue. - double timeLastSent; ///< The time the message was last sent. Used to implement ChannelConfig::messageResendTime. - uint32_t measuredBits : 31; ///< The number of bits the message takes up in a bit stream. - uint32_t block : 1; ///< 1 if this is a block message. Block messages are treated differently to regular messages when sent over a reliable-ordered channel. - }; - - /** - An entry in the receive queue of the reliable-ordered channel. - */ - - struct MessageReceiveQueueEntry - { - Message * message; ///< The message pointer. Has at a reference count of at least 1 while in the receive queue. Ownership of the message is passed back to the caller when the message is dequeued. - }; - - /** - Maps packet level acks to messages and fragments for the reliable-ordered channel. - */ - - struct SentPacketEntry - { - double timeSent; ///< The time the packet was sent. Used to estimate round trip time. - uint16_t * messageIds; ///< Pointer to an array of message ids. Dynamically allocated because the user can configure the maximum number of messages in a packet per-channel with ChannelConfig::maxMessagesPerPacket. - uint32_t numMessageIds : 16; ///< The number of message ids in in the array. - uint32_t acked : 1; ///< 1 if this packet has been acked. - uint64_t block : 1; ///< 1 if this packet contains a fragment of a block message. - uint64_t blockMessageId : 16; ///< The block message id. Valid only if "block" is 1. - uint64_t blockFragmentId : 16; ///< The block fragment id. Valid only if "block" is 1. - }; - - /** - Internal state for a block being sent across the reliable ordered channel. - Stores the block data and tracks which fragments have been acked. The block send completes when all fragments have been acked. - IMPORTANT: Although there can be multiple block messages in the message send and receive queues, only one data block can be in flights over the wire at a time. - */ - - struct SendBlockData - { - SendBlockData( Allocator & allocator, int maxFragmentsPerBlock ) - { - m_allocator = &allocator; - ackedFragment = YOJIMBO_NEW( allocator, BitArray, allocator, maxFragmentsPerBlock ); - fragmentSendTime = (double*) YOJIMBO_ALLOCATE( allocator, sizeof( double) * maxFragmentsPerBlock ); - yojimbo_assert( ackedFragment ); - yojimbo_assert( fragmentSendTime ); - Reset(); - } - - ~SendBlockData() - { - YOJIMBO_DELETE( *m_allocator, BitArray, ackedFragment ); - YOJIMBO_FREE( *m_allocator, fragmentSendTime ); - } - - void Reset() - { - active = false; - numFragments = 0; - numAckedFragments = 0; - blockMessageId = 0; - blockSize = 0; - } - - bool active; ///< True if we are currently sending a block. - int blockSize; ///< The size of the block (bytes). - int numFragments; ///< Number of fragments in the block being sent. - int numAckedFragments; ///< Number of acked fragments in the block being sent. - uint16_t blockMessageId; ///< The message id the block is attached to. - BitArray * ackedFragment; ///< Has fragment n been received? - double * fragmentSendTime; ///< Last time fragment was sent. - - private: - - Allocator * m_allocator; ///< Allocator used to create the block data. - - SendBlockData( const SendBlockData & other ); - - SendBlockData & operator = ( const SendBlockData & other ); - }; - - /** - Internal state for a block being received across the reliable ordered channel. - Stores the fragments received over the network for the block, and completes once all fragments have been received. - IMPORTANT: Although there can be multiple block messages in the message send and receive queues, only one data block can be in flight over the wire at a time. - */ - - struct ReceiveBlockData - { - ReceiveBlockData( Allocator & allocator, int maxBlockSize, int maxFragmentsPerBlock ) - { - m_allocator = &allocator; - receivedFragment = YOJIMBO_NEW( allocator, BitArray, allocator, maxFragmentsPerBlock ); - blockData = (uint8_t*) YOJIMBO_ALLOCATE( allocator, maxBlockSize ); - yojimbo_assert( receivedFragment && blockData ); - blockMessage = NULL; - Reset(); - } - - ~ReceiveBlockData() - { - YOJIMBO_DELETE( *m_allocator, BitArray, receivedFragment ); - YOJIMBO_FREE( *m_allocator, blockData ); - } - - void Reset() - { - active = false; - numFragments = 0; - numReceivedFragments = 0; - messageId = 0; - messageType = 0; - blockSize = 0; - } - - bool active; ///< True if we are currently receiving a block. - int numFragments; ///< The number of fragments in this block - int numReceivedFragments; ///< The number of fragments received. - uint16_t messageId; ///< The message id corresponding to the block. - int messageType; ///< Message type of the block being received. - uint32_t blockSize; ///< Block size in bytes. - BitArray * receivedFragment; ///< Has fragment n been received? - uint8_t * blockData; ///< Block data for receive. - BlockMessage * blockMessage; ///< Block message (sent with fragment 0). - - private: - - Allocator * m_allocator; ///< Allocator used to free the data on shutdown. - - ReceiveBlockData( const ReceiveBlockData & other ); - - ReceiveBlockData & operator = ( const ReceiveBlockData & other ); - }; - - private: - - uint16_t m_sendMessageId; ///< Id of the next message to be added to the send queue. - uint16_t m_receiveMessageId; ///< Id of the next message to be added to the receive queue. - uint16_t m_oldestUnackedMessageId; ///< Id of the oldest unacked message in the send queue. - SequenceBuffer * m_sentPackets; ///< Stores information per sent connection packet about messages and block data included in each packet. Used to walk from connection packet level acks to message and data block fragment level acks. - SequenceBuffer * m_messageSendQueue; ///< Message send queue. - SequenceBuffer * m_messageReceiveQueue; ///< Message receive queue. - uint16_t * m_sentPacketMessageIds; ///< Array of n message ids per sent connection packet. Allows the maximum number of messages per-packet to be allocated dynamically. - SendBlockData * m_sendBlock; ///< Data about the block being currently sent. - ReceiveBlockData * m_receiveBlock; ///< Data about the block being currently received. - - private: - - ReliableOrderedChannel( const ReliableOrderedChannel & other ); - - ReliableOrderedChannel & operator = ( const ReliableOrderedChannel & other ); - }; -} - -#endif // #ifndef YOJIMBO_RELIABLE_ORDERED_CHANNEL_H diff --git a/yojimbo_sequence_buffer.h b/yojimbo_sequence_buffer.h deleted file mode 100644 index a8e30c82..00000000 --- a/yojimbo_sequence_buffer.h +++ /dev/null @@ -1,277 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_SEQUENCE_BUFFER_H -#define YOJIMBO_SEQUENCE_BUFFER_H - -#include "yojimbo_config.h" -#include "yojimbo_serialize.h" -#include "yojimbo_utils.h" - -namespace yojimbo -{ - /** - Data structure that stores data indexed by sequence number. - Entries may or may not exist. If they don't exist the sequence value for the entry at that index is set to 0xFFFFFFFF. - This provides a constant time lookup for an entry by sequence number. If the entry at sequence modulo buffer size doesn't have the same sequence number, that sequence number is not stored. - This is incredibly useful and is used as the foundation of the packet level ack system and the reliable message send and receive queues. - @see Connection - */ - - template class SequenceBuffer - { - public: - - /** - Sequence buffer constructor. - @param allocator The allocator to use. - @param size The size of the sequence buffer. - */ - - SequenceBuffer( Allocator & allocator, int size ) - { - yojimbo_assert( size > 0 ); - m_size = size; - m_sequence = 0; - m_allocator = &allocator; - m_entry_sequence = (uint32_t*) YOJIMBO_ALLOCATE( allocator, sizeof( uint32_t ) * size ); - m_entries = (T*) YOJIMBO_ALLOCATE( allocator, sizeof(T) * size ); - Reset(); - } - - /** - Sequence buffer destructor. - */ - - ~SequenceBuffer() - { - yojimbo_assert( m_allocator ); - YOJIMBO_FREE( *m_allocator, m_entries ); - YOJIMBO_FREE( *m_allocator, m_entry_sequence ); - m_allocator = NULL; - } - - /** - Reset the sequence buffer. - Removes all entries from the sequence buffer and restores it to initial state. - */ - - void Reset() - { - m_sequence = 0; - memset( m_entry_sequence, 0xFF, sizeof( uint32_t ) * m_size ); - } - - /** - Insert an entry in the sequence buffer. - IMPORTANT: If another entry exists at the sequence modulo buffer size, it is overwritten. - @param sequence The sequence number. - @param guaranteed_order Whether sequence is always the newest value (when sending) or can be out of order (when receiving). - @returns The sequence buffer entry, which you must fill with your data. NULL if a sequence buffer entry could not be added for your sequence number (if the sequence number is too old for example). - */ - - T * Insert( uint16_t sequence, bool guaranteed_order = false ) - { - if ( yojimbo_sequence_greater_than( sequence + 1, m_sequence ) || guaranteed_order ) - { - RemoveEntries( m_sequence, sequence ); - m_sequence = sequence + 1; - } - else if ( yojimbo_sequence_less_than( sequence, m_sequence - m_size ) ) - { - return NULL; - } - const int index = sequence % m_size; - m_entry_sequence[index] = sequence; - return &m_entries[index]; - } - - /** - Remove an entry from the sequence buffer. - @param sequence The sequence number of the entry to remove. - */ - - void Remove( uint16_t sequence ) - { - m_entry_sequence[ sequence % m_size ] = 0xFFFFFFFF; - } - - /** - Is the entry corresponding to the sequence number available? eg. Currently unoccupied. - This works because older entries are automatically set back to unoccupied state as the sequence buffer advances forward. - @param sequence The sequence number. - @returns True if the sequence buffer entry is available, false if it is already occupied. - */ - - bool Available( uint16_t sequence ) const - { - return m_entry_sequence[ sequence % m_size ] == 0xFFFFFFFF; - } - - /** - Does an entry exist for a sequence number? - @param sequence The sequence number. - @returns True if an entry exists for this sequence number. - */ - - bool Exists( uint16_t sequence ) const - { - return m_entry_sequence[ sequence % m_size ] == uint32_t( sequence ); - } - - /** - Get the entry corresponding to a sequence number. - @param sequence The sequence number. - @returns The entry if it exists. NULL if no entry is in the buffer for this sequence number. - */ - - T * Find( uint16_t sequence ) - { - const int index = sequence % m_size; - if ( m_entry_sequence[index] == uint32_t( sequence ) ) - return &m_entries[index]; - else - return NULL; - } - - /** - Get the entry corresponding to a sequence number (const version). - @param sequence The sequence number. - @returns The entry if it exists. NULL if no entry is in the buffer for this sequence number. - */ - - const T * Find( uint16_t sequence ) const - { - const int index = sequence % m_size; - if ( m_entry_sequence[index] == uint32_t( sequence ) ) - return &m_entries[index]; - else - return NULL; - } - - /** - Get the entry at the specified index. - Use this to iterate across entries in the sequence buffer. - @param index The entry index in [0,GetSize()-1]. - @returns The entry if it exists. NULL if no entry is in the buffer at the specified index. - */ - - T * GetAtIndex( int index ) - { - yojimbo_assert( index >= 0 ); - yojimbo_assert( index < m_size ); - return m_entry_sequence[index] != 0xFFFFFFFF ? &m_entries[index] : NULL; - } - - /** - Get the entry at the specified index (const version). - Use this to iterate across entries in the sequence buffer. - @param index The entry index in [0,GetSize()-1]. - @returns The entry if it exists. NULL if no entry is in the buffer at the specified index. - */ - - const T * GetAtIndex( int index ) const - { - yojimbo_assert( index >= 0 ); - yojimbo_assert( index < m_size ); - return m_entry_sequence[index] != 0xFFFFFFFF ? &m_entries[index] : NULL; - } - - /** - Get the most recent sequence number added to the buffer. - This sequence number can wrap around, so if you are at 65535 and add an entry for sequence 0, then 0 becomes the new "most recent" sequence number. - @returns The most recent sequence number. - @see yojimbo::sequence_greater_than - @see yojimbo::sequence_less_than - */ - - uint16_t GetSequence() const - { - return m_sequence; - } - - /** - Get the entry index for a sequence number. - This is simply the sequence number modulo the sequence buffer size. - @param sequence The sequence number. - @returns The sequence buffer index corresponding of the sequence number. - */ - - int GetIndex( uint16_t sequence ) const - { - return sequence % m_size; - } - - /** - Get the size of the sequence buffer. - @returns The size of the sequence buffer (number of entries). - */ - - int GetSize() const - { - return m_size; - } - - protected: - - /** - Helper function to remove entries. - This is used to remove old entries as we advance the sequence buffer forward. - Otherwise, if when entries are added with holes (eg. receive buffer for packets or messages, where not all sequence numbers are added to the buffer because we have high packet loss), - and we are extremely unlucky, we can have old sequence buffer entries from the previous sequence # wrap around still in the buffer, which corrupts our internal connection state. - This actually happened in the soak test at high packet loss levels (>90%). It took me days to track it down :) - */ - - void RemoveEntries( int start_sequence, int finish_sequence ) - { - if ( finish_sequence < start_sequence ) - finish_sequence += 65535; - yojimbo_assert( finish_sequence >= start_sequence ); - if ( finish_sequence - start_sequence < m_size ) - { - for ( int sequence = start_sequence; sequence <= finish_sequence; ++sequence ) - m_entry_sequence[sequence % m_size] = 0xFFFFFFFF; - } - else - { - for ( int i = 0; i < m_size; ++i ) - m_entry_sequence[i] = 0xFFFFFFFF; - } - } - - private: - - Allocator * m_allocator; ///< The allocator passed in to the constructor. - int m_size; ///< The size of the sequence buffer. - uint16_t m_sequence; ///< The most recent sequence number added to the buffer. - uint32_t * m_entry_sequence; ///< Array of sequence numbers corresponding to each sequence buffer entry for fast lookup. Set to 0xFFFFFFFF if no entry exists at that index. - T * m_entries; ///< The sequence buffer entries. This is where the data is stored per-entry. Separate from the sequence numbers for fast lookup (hot/cold split) when the data per-sequence number is relatively large. - - SequenceBuffer( const SequenceBuffer & other ); - - SequenceBuffer & operator = ( const SequenceBuffer & other ); - }; -} - -#endif // #ifndef YOJIMBO_SEQUENCE_BUFFER_H diff --git a/yojimbo_serialize.h b/yojimbo_serialize.h deleted file mode 100644 index d6fe8038..00000000 --- a/yojimbo_serialize.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_SERIALIZE_H -#define YOJIMBO_SERIALIZE_H - -#include "yojimbo_config.h" -#include "yojimbo_platform.h" - -namespace yojimbo -{ - template bool serialize_ack_relative_internal( Stream & stream, uint16_t sequence, uint16_t & ack ) - { - int ack_delta = 0; - bool ack_in_range = false; - if ( Stream::IsWriting ) - { - if ( ack < sequence ) - { - ack_delta = sequence - ack; - } - else - { - ack_delta = (int)sequence + 65536 - ack; - } - yojimbo_assert( ack_delta > 0 ); - yojimbo_assert( uint16_t( sequence - ack_delta ) == ack ); - ack_in_range = ack_delta <= 64; - } - serialize_bool( stream, ack_in_range ); - if ( ack_in_range ) - { - serialize_int( stream, ack_delta, 1, 64 ); - if ( Stream::IsReading ) - { - ack = sequence - ack_delta; - } - } - else - { - serialize_bits( stream, ack, 16 ); - } - return true; - } - - /** - Serialize an ack relative to the current sequence number (read/write/measure). - This is a helper macro to make writing unified serialize functions easier. - Serialize macros returns false on error so we don't need to use exceptions for error handling on read. This is an important safety measure because packet data comes from the network and may be malicious. - IMPORTANT: This macro must be called inside a templated serialize function with template \. The serialize method must have a bool return value. - @param stream The stream object. May be a read, write or measure stream. - @param sequence The current sequence number. - @param ack The ack sequence number, which is typically near the current sequence number. - */ - - #define serialize_ack_relative( stream, sequence, ack ) \ - do \ - { \ - if ( !yojimbo::serialize_ack_relative_internal( stream, sequence, ack ) ) \ - { \ - return false; \ - } \ - } while (0) - - template bool serialize_sequence_relative_internal( Stream & stream, uint16_t sequence1, uint16_t & sequence2 ) - { - if ( Stream::IsWriting ) - { - uint32_t a = sequence1; - uint32_t b = sequence2 + ( ( sequence1 > sequence2 ) ? 65536 : 0 ); - serialize_int_relative( stream, a, b ); - } - else - { - uint32_t a = sequence1; - uint32_t b = 0; - serialize_int_relative( stream, a, b ); - if ( b >= 65536 ) - { - b -= 65536; - } - sequence2 = uint16_t( b ); - } - - return true; - } - - /** - Serialize a sequence number relative to another (read/write/measure). - This is a helper macro to make writing unified serialize functions easier. - Serialize macros returns false on error so we don't need to use exceptions for error handling on read. This is an important safety measure because packet data comes from the network and may be malicious. - IMPORTANT: This macro must be called inside a templated serialize function with template \. The serialize method must have a bool return value. - @param stream The stream object. May be a read, write or measure stream. - @param sequence1 The first sequence number to serialize relative to. - @param sequence2 The second sequence number to be encoded relative to the first. - */ - - #define serialize_sequence_relative( stream, sequence1, sequence2 ) \ - do \ - { \ - if ( !yojimbo::serialize_sequence_relative_internal( stream, sequence1, sequence2 ) ) \ - { \ - return false; \ - } \ - } while (0) - - /** - Interface for an object that knows how to read, write and measure how many bits it would take up in a bit stream. - IMPORTANT: Instead of overriding the serialize virtual methods method directly, use the YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS macro in your derived class to override and redirect them to your templated serialize method. - This way you can implement read and write for your messages in a single method and the C++ compiler takes care of generating specialized read, write and measure implementations for you. - See tests/shared.h for some examples of this. - @see ReadStream - @see WriteStream - @see MeasureStream - */ - - class Serializable - { - public: - - virtual ~Serializable() {} - - /** - Virtual serialize function (read). - Reads the object in from a bitstream. - @param stream The stream to read from. - */ - - virtual bool SerializeInternal( class ReadStream & stream ) = 0; - - /** - Virtual serialize function (write). - Writes the object to a bitstream. - @param stream The stream to write to. - */ - - virtual bool SerializeInternal( class WriteStream & stream ) = 0; - - /** - Virtual serialize function (measure). - Quickly measures how many bits the object would take if it were written to a bit stream. - @param stream The read stream. - */ - - virtual bool SerializeInternal( class MeasureStream & stream ) = 0; - }; - - /** - Helper macro to define virtual serialize functions for read, write and measure that call into the templated serialize function. - This helps avoid writing boilerplate code, which is nice when you have lots of hand coded message types. - See tests/shared.h for examples of usage. - */ - - #define YOJIMBO_VIRTUAL_SERIALIZE_FUNCTIONS() \ - bool SerializeInternal( class yojimbo::ReadStream & stream ) { return Serialize( stream ); }; \ - bool SerializeInternal( class yojimbo::WriteStream & stream ) { return Serialize( stream ); }; \ - bool SerializeInternal( class yojimbo::MeasureStream & stream ) { return Serialize( stream ); }; -} - -#endif // #ifndef YOJIMBO_SERIALIZE_H diff --git a/yojimbo_server.cpp b/yojimbo_server.cpp deleted file mode 100644 index 4eea531d..00000000 --- a/yojimbo_server.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "yojimbo_server.h" -#include "yojimbo_connection.h" -#include "yojimbo_adapter.h" -#include "yojimbo_network_simulator.h" -#include "reliable.h" -#include "netcode.h" - -namespace yojimbo -{ - Server::Server( Allocator & allocator, const uint8_t privateKey[], const Address & address, const ClientServerConfig & config, Adapter & adapter, double time ) - : BaseServer( allocator, config, adapter, time ) - { - yojimbo_assert( KeyBytes == NETCODE_KEY_BYTES ); - memcpy( m_privateKey, privateKey, NETCODE_KEY_BYTES ); - m_address = address; - m_boundAddress = address; - m_config = config; - m_server = NULL; - } - - Server::~Server() - { - // IMPORTANT: Please stop the server before destroying it! - yojimbo_assert( !m_server ); - } - - void Server::Start( int maxClients ) - { - if ( IsRunning() ) - Stop(); - - BaseServer::Start( maxClients ); - - char addressString[MaxAddressLength]; - m_address.ToString( addressString, MaxAddressLength ); - - struct netcode_server_config_t netcodeConfig; - netcode_default_server_config(&netcodeConfig); - netcodeConfig.protocol_id = m_config.protocolId; - memcpy(netcodeConfig.private_key, m_privateKey, NETCODE_KEY_BYTES); - netcodeConfig.allocator_context = &GetGlobalAllocator(); - netcodeConfig.allocate_function = StaticAllocateFunction; - netcodeConfig.free_function = StaticFreeFunction; - netcodeConfig.callback_context = this; - netcodeConfig.connect_disconnect_callback = StaticConnectDisconnectCallbackFunction; - netcodeConfig.send_loopback_packet_callback = StaticSendLoopbackPacketCallbackFunction; - - m_server = netcode_server_create(addressString, &netcodeConfig, GetTime()); - - if ( !m_server ) - { - Stop(); - return; - } - - netcode_server_start( m_server, maxClients ); - - m_boundAddress.SetPort( netcode_server_get_port( m_server ) ); - } - - void Server::Stop() - { - if ( m_server ) - { - m_boundAddress = m_address; - netcode_server_stop( m_server ); - netcode_server_destroy( m_server ); - m_server = NULL; - } - BaseServer::Stop(); - } - - void Server::DisconnectClient( int clientIndex ) - { - yojimbo_assert( m_server ); - netcode_server_disconnect_client( m_server, clientIndex ); - } - - void Server::DisconnectAllClients() - { - yojimbo_assert( m_server ); - netcode_server_disconnect_all_clients( m_server ); - } - - void Server::SendPackets() - { - if ( m_server ) - { - const int maxClients = GetMaxClients(); - for ( int i = 0; i < maxClients; ++i ) - { - if ( IsClientConnected( i ) ) - { - uint8_t * packetData = GetPacketBuffer(); - int packetBytes; - uint16_t packetSequence = reliable_endpoint_next_packet_sequence( GetClientEndpoint(i) ); - if ( GetClientConnection(i).GeneratePacket( GetContext(), packetSequence, packetData, m_config.maxPacketSize, packetBytes ) ) - { - reliable_endpoint_send_packet( GetClientEndpoint(i), packetData, packetBytes ); - } - } - } - } - } - - void Server::ReceivePackets() - { - if ( m_server ) - { - const int maxClients = GetMaxClients(); - for ( int clientIndex = 0; clientIndex < maxClients; ++clientIndex ) - { - while ( true ) - { - int packetBytes; - uint64_t packetSequence; - uint8_t * packetData = netcode_server_receive_packet( m_server, clientIndex, &packetBytes, &packetSequence ); - if ( !packetData ) - break; - reliable_endpoint_receive_packet( GetClientEndpoint( clientIndex ), packetData, packetBytes ); - netcode_server_free_packet( m_server, packetData ); - } - } - } - } - - void Server::AdvanceTime( double time ) - { - if ( m_server ) - { - netcode_server_update( m_server, time ); - } - BaseServer::AdvanceTime( time ); - NetworkSimulator * networkSimulator = GetNetworkSimulator(); - if ( networkSimulator && networkSimulator->IsActive() ) - { - uint8_t ** packetData = (uint8_t**) alloca( sizeof( uint8_t*) * m_config.maxSimulatorPackets ); - int * packetBytes = (int*) alloca( sizeof(int) * m_config.maxSimulatorPackets ); - int * to = (int*) alloca( sizeof(int) * m_config.maxSimulatorPackets ); - int numPackets = networkSimulator->ReceivePackets( m_config.maxSimulatorPackets, packetData, packetBytes, to ); - for ( int i = 0; i < numPackets; ++i ) - { - netcode_server_send_packet( m_server, to[i], (uint8_t*) packetData[i], packetBytes[i] ); - YOJIMBO_FREE( networkSimulator->GetAllocator(), packetData[i] ); - } - } - } - - bool Server::IsClientConnected( int clientIndex ) const - { - return netcode_server_client_connected( m_server, clientIndex ) != 0; - } - - uint64_t Server::GetClientId( int clientIndex ) const - { - return netcode_server_client_id( m_server, clientIndex ); - } - - netcode_address_t * Server::GetClientAddress( int clientIndex ) const - { - return netcode_server_client_address( m_server, clientIndex ); - } - - int Server::GetNumConnectedClients() const - { - return netcode_server_num_connected_clients( m_server ); - } - - void Server::ConnectLoopbackClient( int clientIndex, uint64_t clientId, const uint8_t * userData ) - { - netcode_server_connect_loopback_client( m_server, clientIndex, clientId, userData ); - } - - void Server::DisconnectLoopbackClient( int clientIndex ) - { - netcode_server_disconnect_loopback_client( m_server, clientIndex ); - } - - bool Server::IsLoopbackClient( int clientIndex ) const - { - return netcode_server_client_loopback( m_server, clientIndex ) != 0; - } - - void Server::ProcessLoopbackPacket( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) - { - netcode_server_process_loopback_packet( m_server, clientIndex, packetData, packetBytes, packetSequence ); - } - - void Server::TransmitPacketFunction( int clientIndex, uint16_t packetSequence, uint8_t * packetData, int packetBytes ) - { - (void) packetSequence; - NetworkSimulator * networkSimulator = GetNetworkSimulator(); - if ( networkSimulator && networkSimulator->IsActive() ) - { - networkSimulator->SendPacket( clientIndex, packetData, packetBytes ); - } - else - { - netcode_server_send_packet( m_server, clientIndex, packetData, packetBytes ); - } - } - - int Server::ProcessPacketFunction( int clientIndex, uint16_t packetSequence, uint8_t * packetData, int packetBytes ) - { - return (int) GetClientConnection(clientIndex).ProcessPacket( GetContext(), packetSequence, packetData, packetBytes ); - } - - void Server::ConnectDisconnectCallbackFunction( int clientIndex, int connected ) - { - if ( connected == 0 ) - { - GetAdapter().OnServerClientDisconnected( clientIndex ); - reliable_endpoint_reset( GetClientEndpoint( clientIndex ) ); - GetClientConnection( clientIndex ).Reset(); - NetworkSimulator * networkSimulator = GetNetworkSimulator(); - if ( networkSimulator && networkSimulator->IsActive() ) - { - networkSimulator->DiscardClientPackets( clientIndex ); - } - } - else - { - GetAdapter().OnServerClientConnected( clientIndex ); - } - } - - void Server::SendLoopbackPacketCallbackFunction( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) - { - GetAdapter().ServerSendLoopbackPacket( clientIndex, packetData, packetBytes, packetSequence ); - } - - void Server::StaticConnectDisconnectCallbackFunction( void * context, int clientIndex, int connected ) - { - Server * server = (Server*) context; - server->ConnectDisconnectCallbackFunction( clientIndex, connected ); - } - - void Server::StaticSendLoopbackPacketCallbackFunction( void * context, int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) - { - Server * server = (Server*) context; - server->SendLoopbackPacketCallbackFunction( clientIndex, packetData, packetBytes, packetSequence ); - } -} diff --git a/yojimbo_server.h b/yojimbo_server.h deleted file mode 100644 index 33247b23..00000000 --- a/yojimbo_server.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_SERVER_H -#define YOJIMBO_SERVER_H - -#include "yojimbo_config.h" -#include "yojimbo_base_server.h" -#include "yojimbo_address.h" - -struct netcode_server_t; - -namespace yojimbo -{ - /** - Server implementation. - */ - - class Server : public BaseServer - { - public: - - Server( Allocator & allocator, const uint8_t privateKey[], const Address & address, const ClientServerConfig & config, Adapter & adapter, double time ); - - ~Server(); - - void Start( int maxClients ); - - void Stop(); - - void DisconnectClient( int clientIndex ); - - void DisconnectAllClients(); - - void SendPackets(); - - void ReceivePackets(); - - void AdvanceTime( double time ); - - bool IsClientConnected( int clientIndex ) const; - - uint64_t GetClientId( int clientIndex ) const; - - netcode_address_t * GetClientAddress( int clientIndex ) const; - - int GetNumConnectedClients() const; - - void ConnectLoopbackClient( int clientIndex, uint64_t clientId, const uint8_t * userData ); - - void DisconnectLoopbackClient( int clientIndex ); - - bool IsLoopbackClient( int clientIndex ) const; - - void ProcessLoopbackPacket( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); - - const Address & GetAddress() const { return m_boundAddress; } - - private: - - void TransmitPacketFunction( int clientIndex, uint16_t packetSequence, uint8_t * packetData, int packetBytes ); - - int ProcessPacketFunction( int clientIndex, uint16_t packetSequence, uint8_t * packetData, int packetBytes ); - - void ConnectDisconnectCallbackFunction( int clientIndex, int connected ); - - void SendLoopbackPacketCallbackFunction( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); - - static void StaticConnectDisconnectCallbackFunction( void * context, int clientIndex, int connected ); - - static void StaticSendLoopbackPacketCallbackFunction( void * context, int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ); - - ClientServerConfig m_config; - netcode_server_t * m_server; - Address m_address; // original address passed to ctor - Address m_boundAddress; // address after socket bind, eg. valid port - uint8_t m_privateKey[KeyBytes]; - }; -} - -#endif // #ifndef YOJIMBO_SERVER_H diff --git a/yojimbo_server_interface.h b/yojimbo_server_interface.h deleted file mode 100644 index a5b278b4..00000000 --- a/yojimbo_server_interface.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_SERVER_INTERFACE_H -#define YOJIMBO_SERVER_INTERFACE_H - -#include "yojimbo_config.h" - -struct netcode_address_t; - -// fucking windows =p -#ifdef SendMessage -#undef SendMessage -#endif - -namespace yojimbo -{ - /** - The server interface. - */ - - class ServerInterface - { - public: - - virtual ~ServerInterface() {} - - /** - Set the context for reading and writing packets. - This is optional. It lets you pass in a pointer to some structure that you want to have available when reading and writing packets via Stream::GetContext. - Typical use case is to pass in an array of min/max ranges for values determined by some data that is loaded from a toolchain vs. being known at compile time. - If you do use a context, make sure the same context data is set on client and server, and include a checksum of the context data in the protocol id. - */ - - virtual void SetContext( void * context ) = 0; - - /** - Start the server and allocate client slots. - Each client that connects to this server occupies one of the client slots allocated by this function. - @param maxClients The number of client slots to allocate. Must be in range [1,MaxClients] - @see Server::Stop - */ - - virtual void Start( int maxClients ) = 0; - - /** - Stop the server and free client slots. - Any clients that are connected at the time you call stop will be disconnected. - When the server is stopped, clients cannot connect to the server. - @see Server::Start. - */ - - virtual void Stop() = 0; - - /** - Disconnect the client at the specified client index. - @param clientIndex The index of the client to disconnect in range [0,maxClients-1], where maxClients is the number of client slots allocated in Server::Start. - @see Server::IsClientConnected - */ - - virtual void DisconnectClient( int clientIndex ) = 0; - - /** - Disconnect all clients from the server. - Client slots remain allocated as per the last call to Server::Start, they are simply made available for new clients to connect. - */ - - virtual void DisconnectAllClients() = 0; - - /** - Send packets to connected clients. - This function drives the sending of packets that transmit messages to clients. - */ - - virtual void SendPackets() = 0; - - /** - Receive packets from connected clients. - This function drives the procesing of messages included in packets received from connected clients. - */ - - virtual void ReceivePackets() = 0; - - /** - Advance server time. - Call this at the end of each frame to advance the server time forward. - IMPORTANT: Please use a double for your time value so it maintains sufficient accuracy as time increases. - */ - - virtual void AdvanceTime( double time ) = 0; - - /** - Is the server running? - The server is running after you have called Server::Start. It is not running before the first server start, and after you call Server::Stop. - Clients can only connect to the server while it is running. - @returns true if the server is currently running. - */ - - virtual bool IsRunning() const = 0; - - /** - Get the maximum number of clients that can connect to the server. - Corresponds to the maxClients parameter passed into the last call to Server::Start. - @returns The maximum number of clients that can connect to the server. In other words, the number of client slots. - */ - - virtual int GetMaxClients() const = 0; - - /** - Is a client connected to a client slot? - @param clientIndex the index of the client slot in [0,maxClients-1], where maxClients corresponds to the value passed into the last call to Server::Start. - @returns True if the client is connected. - */ - - virtual bool IsClientConnected( int clientIndex ) const = 0; - - /** - Get the unique id of the client - @param clientIndex the index of the client slot in [0,maxClients-1], where maxClients corresponds to the value passed into the last call to Server::Start. - @returns The unique id of the client. - */ - - virtual uint64_t GetClientId( int clientIndex ) const = 0; - - /** - Get the address of the client - @param clientIndex the index of the client slot in [0,maxClients-1], where maxClients corresponds to the value passed into the last call to Server::Start. - @returns The address of the client. - */ - - virtual netcode_address_t * GetClientAddress( int clientIndex ) const = 0; - - /** - Get the number of clients that are currently connected to the server. - @returns the number of connected clients. - */ - - virtual int GetNumConnectedClients() const = 0; - - /** - Gets the current server time. - @see Server::AdvanceTime - */ - - virtual double GetTime() const = 0; - - /** - Create a message of the specified type for a specific client. - @param clientIndex The index of the client this message belongs to. Determines which client heap is used to allocate the message. - @param type The type of the message to create. The message types corresponds to the message factory created by the adapter set on the server. - */ - - virtual class Message * CreateMessage( int clientIndex, int type ) = 0; - - /** - Helper function to allocate a data block. - This is typically used to create blocks of data to attach to block messages. See BlockMessage for details. - @param clientIndex The index of the client this message belongs to. Determines which client heap is used to allocate the data. - @param bytes The number of bytes to allocate. - @returns The pointer to the data block. This must be attached to a message via Client::AttachBlockToMessage, or freed via Client::FreeBlock. - */ - - virtual uint8_t * AllocateBlock( int clientIndex, int bytes ) = 0; - - /** - Attach data block to message. - @param clientIndex The index of the client this block belongs to. - @param message The message to attach the block to. This message must be derived from BlockMessage. - @param block Pointer to the block of data to attach. Must be created via Client::AllocateBlock. - @param bytes Length of the block of data in bytes. - */ - - virtual void AttachBlockToMessage( int clientIndex, Message * message, uint8_t * block, int bytes ) = 0; - - /** - Free a block of memory. - @param clientIndex The index of the client this block belongs to. - @param block The block of memory created by Client::AllocateBlock. - */ - - virtual void FreeBlock( int clientIndex, uint8_t * block ) = 0; - - /** - Can we send a message to a particular client on a channel? - @param clientIndex The index of the client to send a message to. - @param channelIndex The channel index in range [0,numChannels-1]. - @returns True if a message can be sent over the channel, false otherwise. - */ - - virtual bool CanSendMessage( int clientIndex, int channelIndex ) const = 0; - - /** - Send a message to a client over a channel. - @param clientIndex The index of the client to send a message to. - @param channelIndex The channel index in range [0,numChannels-1]. - @param message The message to send. - */ - - virtual void SendMessage( int clientIndex, int channelIndex, Message * message ) = 0; - - /** - Receive a message from a client over a channel. - @param clientIndex The index of the client to receive messages from. - @param channelIndex The channel index in range [0,numChannels-1]. - @returns The message received, or NULL if no message is available. Make sure to release this message by calling Server::ReleaseMessage. - */ - - virtual Message * ReceiveMessage( int clientIndex, int channelIndex ) = 0; - - /** - Release a message. - Call this for messages received by Server::ReceiveMessage. - @param clientIndex The index of the client that the message belongs to. - @param message The message to release. - */ - - virtual void ReleaseMessage( int clientIndex, class Message * message ) = 0; - - /** - Get client network info. - Call this to receive information about the client network connection, eg. round trip time, packet loss %, # of packets sent and so on. - @param clientIndex The index of the client. - @param info The struct to be filled with network info [out]. - */ - - virtual void GetNetworkInfo( int clientIndex, struct NetworkInfo & info ) const = 0; - - /** - Connect a loopback client. - This allows you to have local clients connected to a server, for example for integrated server or singleplayer. - @param clientIndex The index of the client. - @param clientId The unique client id. - @param userData User data for this client. Optional. Pass NULL if not needed. - */ - - virtual void ConnectLoopbackClient( int clientIndex, uint64_t clientId, const uint8_t * userData ) = 0; - - /** - Disconnect a loopback client. - Loopback clients are not disconnected by regular Disconnect or DisconnectAllClient calls. You need to call this function instead. - @param clientIndex The index of the client to disconnect. Must already be a connected loopback client. - */ - - virtual void DisconnectLoopbackClient( int clientIndex ) = 0; - - /** - Is this client a loopback client? - @param clientIndex The client index. - @returns true if the client is a connected loopback client, false otherwise. - */ - - virtual bool IsLoopbackClient( int clientIndex ) const = 0; - - /** - Process loopback packet. - Use this to pass packets from a client directly to the loopback client slot on the server. - @param clientIndex The client index. Must be an already connected loopback client. - @param packetData The packet data to process. - @param packetBytes The number of bytes of packet data. - @param packetSequence The packet sequence number. - */ - - virtual void ProcessLoopbackPacket( int clientIndex, const uint8_t * packetData, int packetBytes, uint64_t packetSequence ) = 0; - }; -} - -#endif // #ifndef YOJIMBO_SERVER_INTERFACE_H diff --git a/yojimbo_unreliable_unordered_channel.cpp b/yojimbo_unreliable_unordered_channel.cpp deleted file mode 100644 index 2811c3b5..00000000 --- a/yojimbo_unreliable_unordered_channel.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "yojimbo_unreliable_unordered_channel.h" -#include "yojimbo_utils.h" - -namespace yojimbo -{ - UnreliableUnorderedChannel::UnreliableUnorderedChannel( Allocator & allocator, - MessageFactory & messageFactory, - const ChannelConfig & config, - int channelIndex, - double time ) - : Channel( allocator, - messageFactory, - config, - channelIndex, - time ) - { - yojimbo_assert( config.type == CHANNEL_TYPE_UNRELIABLE_UNORDERED ); - m_messageSendQueue = YOJIMBO_NEW( *m_allocator, Queue, *m_allocator, m_config.messageSendQueueSize ); - m_messageReceiveQueue = YOJIMBO_NEW( *m_allocator, Queue, *m_allocator, m_config.messageReceiveQueueSize ); - Reset(); - } - - UnreliableUnorderedChannel::~UnreliableUnorderedChannel() - { - Reset(); - YOJIMBO_DELETE( *m_allocator, Queue, m_messageSendQueue ); - YOJIMBO_DELETE( *m_allocator, Queue, m_messageReceiveQueue ); - } - - void UnreliableUnorderedChannel::Reset() - { - SetErrorLevel( CHANNEL_ERROR_NONE ); - - for ( int i = 0; i < m_messageSendQueue->GetNumEntries(); ++i ) - m_messageFactory->ReleaseMessage( (*m_messageSendQueue)[i] ); - - for ( int i = 0; i < m_messageReceiveQueue->GetNumEntries(); ++i ) - m_messageFactory->ReleaseMessage( (*m_messageReceiveQueue)[i] ); - - m_messageSendQueue->Clear(); - m_messageReceiveQueue->Clear(); - - ResetCounters(); - } - - bool UnreliableUnorderedChannel::CanSendMessage() const - { - yojimbo_assert( m_messageSendQueue ); - return !m_messageSendQueue->IsFull(); - } - - bool UnreliableUnorderedChannel::HasMessagesToSend() const - { - yojimbo_assert( m_messageSendQueue ); - return !m_messageSendQueue->IsEmpty(); - } - - void UnreliableUnorderedChannel::SendMessage( Message * message, void *context ) - { - yojimbo_assert( message ); - yojimbo_assert( CanSendMessage() ); - (void)context; - - if ( GetErrorLevel() != CHANNEL_ERROR_NONE ) - { - m_messageFactory->ReleaseMessage( message ); - return; - } - - if ( !CanSendMessage() ) - { - SetErrorLevel( CHANNEL_ERROR_SEND_QUEUE_FULL ); - m_messageFactory->ReleaseMessage( message ); - return; - } - - yojimbo_assert( !( message->IsBlockMessage() && m_config.disableBlocks ) ); - - if ( message->IsBlockMessage() && m_config.disableBlocks ) - { - SetErrorLevel( CHANNEL_ERROR_BLOCKS_DISABLED ); - m_messageFactory->ReleaseMessage( message ); - return; - } - - if ( message->IsBlockMessage() ) - { - yojimbo_assert( ((BlockMessage*)message)->GetBlockSize() > 0 ); - yojimbo_assert( ((BlockMessage*)message)->GetBlockSize() <= m_config.maxBlockSize ); - } - - m_messageSendQueue->Push( message ); - - m_counters[CHANNEL_COUNTER_MESSAGES_SENT]++; - } - - Message * UnreliableUnorderedChannel::ReceiveMessage() - { - if ( GetErrorLevel() != CHANNEL_ERROR_NONE ) - return NULL; - - if ( m_messageReceiveQueue->IsEmpty() ) - return NULL; - - m_counters[CHANNEL_COUNTER_MESSAGES_RECEIVED]++; - - return m_messageReceiveQueue->Pop(); - } - - void UnreliableUnorderedChannel::AdvanceTime( double time ) - { - (void) time; - } - - int UnreliableUnorderedChannel::GetPacketData( void *context, ChannelPacketData & packetData, uint16_t packetSequence, int availableBits ) - { - (void) packetSequence; - - if ( m_messageSendQueue->IsEmpty() ) - return 0; - - if ( m_config.packetBudget > 0 ) - availableBits = yojimbo_min( m_config.packetBudget * 8, availableBits ); - - const int giveUpBits = 4 * 8; - - const int messageTypeBits = bits_required( 0, m_messageFactory->GetNumTypes() - 1 ); - - int usedBits = ConservativeMessageHeaderBits; - int numMessages = 0; - Message ** messages = (Message**) alloca( sizeof( Message* ) * m_config.maxMessagesPerPacket ); - - while ( true ) - { - if ( m_messageSendQueue->IsEmpty() ) - break; - - if ( availableBits - usedBits < giveUpBits ) - break; - - if ( numMessages == m_config.maxMessagesPerPacket ) - break; - - Message * message = m_messageSendQueue->Pop(); - - yojimbo_assert( message ); - - MeasureStream measureStream; - measureStream.SetContext( context ); - measureStream.SetAllocator( &m_messageFactory->GetAllocator() ); - message->SerializeInternal( measureStream ); - - if ( message->IsBlockMessage() ) - { - BlockMessage * blockMessage = (BlockMessage*) message; - SerializeMessageBlock( measureStream, *m_messageFactory, blockMessage, m_config.maxBlockSize ); - } - - const int messageBits = messageTypeBits + measureStream.GetBitsProcessed(); - - if ( usedBits + messageBits > availableBits ) - { - m_messageFactory->ReleaseMessage( message ); - continue; - } - - usedBits += messageBits; - - yojimbo_assert( usedBits <= availableBits ); - - messages[numMessages++] = message; - } - - if ( numMessages == 0 ) - return 0; - - Allocator & allocator = m_messageFactory->GetAllocator(); - - packetData.Initialize(); - packetData.channelIndex = GetChannelIndex(); - packetData.message.numMessages = numMessages; - packetData.message.messages = (Message**) YOJIMBO_ALLOCATE( allocator, sizeof( Message* ) * numMessages ); - for ( int i = 0; i < numMessages; ++i ) - { - packetData.message.messages[i] = messages[i]; - } - - return usedBits; - } - - void UnreliableUnorderedChannel::ProcessPacketData( const ChannelPacketData & packetData, uint16_t packetSequence ) - { - if ( m_errorLevel != CHANNEL_ERROR_NONE ) - return; - - if ( packetData.messageFailedToSerialize ) - { - SetErrorLevel( CHANNEL_ERROR_FAILED_TO_SERIALIZE ); - return; - } - - for ( int i = 0; i < (int) packetData.message.numMessages; ++i ) - { - Message * message = packetData.message.messages[i]; - yojimbo_assert( message ); - message->SetId( packetSequence ); - if ( !m_messageReceiveQueue->IsFull() ) - { - m_messageFactory->AcquireMessage( message ); - m_messageReceiveQueue->Push( message ); - } - } - } - - void UnreliableUnorderedChannel::ProcessAck( uint16_t ack ) - { - (void) ack; - } -} diff --git a/yojimbo_unreliable_unordered_channel.h b/yojimbo_unreliable_unordered_channel.h deleted file mode 100644 index bc529ed4..00000000 --- a/yojimbo_unreliable_unordered_channel.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_UNRELIABLE_UNORDERED_CHANNEL_H -#define YOJIMBO_UNRELIABLE_UNORDERED_CHANNEL_H - -#include "yojimbo_config.h" -#include "yojimbo_channel.h" -#include "yojimbo_queue.h" - -namespace yojimbo -{ - /** - Messages sent across this channel are not guaranteed to arrive, and may be received in a different order than they were sent. - This channel type is best used for time critical data like snapshots and object state. - */ - - class UnreliableUnorderedChannel : public Channel - { - public: - - /** - Reliable ordered channel constructor. - @param allocator The allocator to use. - @param messageFactory Message factory for creating and destroying messages. - @param config The configuration for this channel. - @param channelIndex The channel index in [0,numChannels-1]. - */ - - UnreliableUnorderedChannel( Allocator & allocator, MessageFactory & messageFactory, const ChannelConfig & config, int channelIndex, double time ); - - /** - Unreliable unordered channel destructor. - Any messages still in the send or receive queues will be released. - */ - - ~UnreliableUnorderedChannel(); - - void Reset(); - - bool CanSendMessage() const; - - bool HasMessagesToSend() const; - - void SendMessage( Message * message, void *context ); - - Message * ReceiveMessage(); - - void AdvanceTime( double time ); - - int GetPacketData( void *context, ChannelPacketData & packetData, uint16_t packetSequence, int availableBits ); - - void ProcessPacketData( const ChannelPacketData & packetData, uint16_t packetSequence ); - - void ProcessAck( uint16_t ack ); - - protected: - - Queue * m_messageSendQueue; ///< Message send queue. - Queue * m_messageReceiveQueue; ///< Message receive queue. - - private: - - UnreliableUnorderedChannel( const UnreliableUnorderedChannel & other ); - - UnreliableUnorderedChannel & operator = ( const UnreliableUnorderedChannel & other ); - }; -} - -#endif // #ifndef YOJIMBO_UNRELIABLE_UNORDERED_CHANNEL_H diff --git a/yojimbo_utils.cpp b/yojimbo_utils.cpp deleted file mode 100644 index cdd33054..00000000 --- a/yojimbo_utils.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "yojimbo_config.h" - -#include - -extern "C" void netcode_random_bytes( uint8_t*, int ); - -void yojimbo_random_bytes( uint8_t * data, int bytes ) -{ - netcode_random_bytes( data, bytes ); -} - -void yojimbo_print_bytes( const char * label, const uint8_t * data, int data_bytes ) -{ - printf( "%s: ", label ); - for ( int i = 0; i < data_bytes; ++i ) - { - printf( "0x%02x,", (int) data[i] ); - } - printf( " (%d bytes)\n", data_bytes ); -} diff --git a/yojimbo_utils.h b/yojimbo_utils.h deleted file mode 100644 index 73a261ee..00000000 --- a/yojimbo_utils.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - Yojimbo Client/Server Network Library. - - Copyright © 2016 - 2024, Mas Bandwidth LLC. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer - in the documentation and/or other materials provided with the distribution. - - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef YOJIMBO_UTILS_H -#define YOJIMBO_UTILS_H - -#include "yojimbo_config.h" - -/** - Template function to get the minimum of two values. - @param a The first value. - @param b The second value. - @returns The minimum of a and b. - */ - -template const T & yojimbo_min( const T & a, const T & b ) -{ - return ( a < b ) ? a : b; -} - -/** - Template function to get the maximum of two values. - @param a The first value. - @param b The second value. - @returns The maximum of a and b. - */ - -template const T & yojimbo_max( const T & a, const T & b ) -{ - return ( a > b ) ? a : b; -} - -/** - Template function to clamp a value. - @param value The value to be clamped. - @param a The minimum value. - @param b The minimum value. - @returns The clamped value in [a,b]. - */ - -template T yojimbo_clamp( const T & value, const T & a, const T & b ) -{ - if ( value < a ) - return a; - else if ( value > b ) - return b; - else - return value; -} - -/** - Swap two values. - @param a First value. - @param b Second value. - */ - -template void yojimbo_swap( T & a, T & b ) -{ - T tmp = a; - a = b; - b = tmp; -}; - -/** - Get the absolute value. - - @param value The input value. - - @returns The absolute value. - */ - -template T yojimbo_abs( const T & value ) -{ - return ( value < 0 ) ? -value : value; -} - -/** - Generate cryptographically secure random data. - @param data The buffer to store the random data. - @param bytes The number of bytes of random data to generate. - */ - -void yojimbo_random_bytes( uint8_t * data, int bytes ); - -/** - Generate a random integer between a and b (inclusive). - IMPORTANT: This is not a cryptographically secure random. It's used only for test functions and in the network simulator. - @param a The minimum integer value to generate. - @param b The maximum integer value to generate. - @returns A pseudo random integer value in [a,b]. - */ - -inline int yojimbo_random_int( int a, int b ) -{ - yojimbo_assert( a < b ); - int result = a + rand() % ( b - a + 1 ); - yojimbo_assert( result >= a ); - yojimbo_assert( result <= b ); - return result; -} - -/** - Generate a random float between a and b. - IMPORTANT: This is not a cryptographically secure random. It's used only for test functions and in the network simulator. - @param a The minimum integer value to generate. - @param b The maximum integer value to generate. - @returns A pseudo random float value in [a,b]. - */ - -inline float yojimbo_random_float( float a, float b ) -{ - yojimbo_assert( a < b ); - float random = ( (float) rand() ) / (float) RAND_MAX; - float diff = b - a; - float r = random * diff; - return a + r; -} - -/** - Compares two 16 bit sequence numbers and returns true if the first one is greater than the second (considering wrapping). - IMPORTANT: This is not the same as s1 > s2! - Greater than is defined specially to handle wrapping sequence numbers. - If the two sequence numbers are close together, it is as normal, but they are far apart, it is assumed that they have wrapped around. - Thus, sequence_greater_than( 1, 0 ) returns true, and so does sequence_greater_than( 0, 65535 )! - @param s1 The first sequence number. - @param s2 The second sequence number. - @returns True if the s1 is greater than s2, with sequence number wrapping considered. - */ - -inline bool yojimbo_sequence_greater_than( uint16_t s1, uint16_t s2 ) -{ - return ( ( s1 > s2 ) && ( s1 - s2 <= 32768 ) ) || - ( ( s1 < s2 ) && ( s2 - s1 > 32768 ) ); -} - -/** - Compares two 16 bit sequence numbers and returns true if the first one is less than the second (considering wrapping). - IMPORTANT: This is not the same as s1 < s2! - Greater than is defined specially to handle wrapping sequence numbers. - If the two sequence numbers are close together, it is as normal, but they are far apart, it is assumed that they have wrapped around. - Thus, sequence_less_than( 0, 1 ) returns true, and so does sequence_greater_than( 65535, 0 )! - @param s1 The first sequence number. - @param s2 The second sequence number. - @returns True if the s1 is less than s2, with sequence number wrapping considered. - */ - -inline bool yojimbo_sequence_less_than( uint16_t s1, uint16_t s2 ) -{ - return yojimbo_sequence_greater_than( s2, s1 ); -} - - -#endif // # YOJIMBO_UTILS_H