From 042671b146c541badefd7cf66c881bae67c93b54 Mon Sep 17 00:00:00 2001 From: Anonymous275 Date: Sun, 10 May 2020 23:37:29 +0300 Subject: [PATCH] Major rewrite of the network --- CMakeLists.txt | 12 +- Resources.cpp | 162 - include/enet.hpp | 5909 ----------------- Compressor.cpp => src/Compressor.cpp | 0 CoreNetwork.cpp => src/CoreNetwork.cpp | 8 +- Discord.cpp => src/Discord.cpp | 3 +- GameStart.cpp => src/GameStart.cpp | 7 +- .../Network 2.0/GlobalHandler.cpp | 175 +- src/Network 2.0/VehicleData.cpp | 62 + src/Network 2.0/VehicleEvent.cpp | 96 + src/Resources.cpp | 161 + Security.cpp => src/Security.cpp | 0 UpdateCheck.cpp => src/UpdateCheck.cpp | 0 VehicleNetwork.cpp => src/VehicleNetwork.cpp | 4 +- {curl => src/curl}/curl.h | 4 +- {curl => src/curl}/curlbuild.h | 0 {curl => src/curl}/curlrules.h | 0 {curl => src/curl}/curlver.h | 0 {curl => src/curl}/easy.h | 0 {curl => src/curl}/mprintf.h | 0 {curl => src/curl}/multi.h | 0 {curl => src/curl}/stdcheaders.h | 0 {curl => src/curl}/system.h | 0 {curl => src/curl}/typecheck-gcc.h | 0 http.cpp => src/http.cpp | 0 {include => src/include}/discord_register.h | 0 {include => src/include}/discord_rpc.h | 0 src/include/enet.h | 5906 ++++++++++++++++ {include => src/include}/zconf.h | 0 {include => src/include}/zlib.h | 0 main.cpp => src/main.cpp | 16 +- 31 files changed, 6314 insertions(+), 6211 deletions(-) delete mode 100644 Resources.cpp delete mode 100644 include/enet.hpp rename Compressor.cpp => src/Compressor.cpp (100%) rename CoreNetwork.cpp => src/CoreNetwork.cpp (95%) rename Discord.cpp => src/Discord.cpp (98%) rename GameStart.cpp => src/GameStart.cpp (89%) rename proxy.cpp => src/Network 2.0/GlobalHandler.cpp (61%) create mode 100644 src/Network 2.0/VehicleData.cpp create mode 100644 src/Network 2.0/VehicleEvent.cpp create mode 100644 src/Resources.cpp rename Security.cpp => src/Security.cpp (100%) rename UpdateCheck.cpp => src/UpdateCheck.cpp (100%) rename VehicleNetwork.cpp => src/VehicleNetwork.cpp (98%) rename {curl => src/curl}/curl.h (99%) rename {curl => src/curl}/curlbuild.h (100%) rename {curl => src/curl}/curlrules.h (100%) rename {curl => src/curl}/curlver.h (100%) rename {curl => src/curl}/easy.h (100%) rename {curl => src/curl}/mprintf.h (100%) rename {curl => src/curl}/multi.h (100%) rename {curl => src/curl}/stdcheaders.h (100%) rename {curl => src/curl}/system.h (100%) rename {curl => src/curl}/typecheck-gcc.h (100%) rename http.cpp => src/http.cpp (100%) rename {include => src/include}/discord_register.h (100%) rename {include => src/include}/discord_rpc.h (100%) create mode 100644 src/include/enet.h rename {include => src/include}/zconf.h (100%) rename {include => src/include}/zlib.h (100%) rename main.cpp => src/main.cpp (92%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 748d4bf..ce50494 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,14 +1,14 @@ cmake_minimum_required(VERSION 3.15) set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /O2") - -include_directories(${PROJECT_SOURCE_DIR}/include) -include_directories(${PROJECT_SOURCE_DIR}/curl) - project(BeamMP-Launcher) - set(CMAKE_CXX_STANDARD 14) -add_executable(BeamMP-Launcher main.cpp VehicleNetwork.cpp proxy.cpp Security.cpp http.cpp Discord.cpp UpdateCheck.cpp CoreNetwork.cpp Resources.cpp Compressor.cpp VehicleNetwork.cpp GameStart.cpp) +file(GLOB source_files + "src/*.cpp" "src/include/*.h" + "src/include/*.hpp" "src/curl/*.h" + "src/Network 2.0/*.cpp" "src/Network 2.0/*.h") + +add_executable(BeamMP-Launcher ${source_files}) target_link_libraries(BeamMP-Launcher discord-rpc libcurl_a zlibstatic) \ No newline at end of file diff --git a/Resources.cpp b/Resources.cpp deleted file mode 100644 index 66282b2..0000000 --- a/Resources.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/// -/// Created by Anonymous275 on 4/11/2020 -/// - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#include -#include -#include - -namespace fs = std::experimental::filesystem; -void Exit(const std::string& Msg); -extern bool MPDEV; -std::string UlStatus = "Ulstart"; -std::string MStatus = " "; - -std::vector Split(const std::string& String,const std::string& delimiter){ - std::vector Val; - size_t pos = 0; - std::string token,s = String; - while ((pos = s.find(delimiter)) != std::string::npos) { - token = s.substr(0, pos); - Val.push_back(token); - s.erase(0, pos + delimiter.length()); - } - Val.push_back(s); - return Val; -} -void ProxyThread(const std::string& IP, int port); -void SyncResources(const std::string&IP,int Port){ - if(MPDEV)std::cout << "Called" << std::endl; - std::string FileList; - struct stat info{}; - if(stat( "Resources", &info) != 0){ - _wmkdir(L"Resources"); - } - - WSADATA wsaData; - SOCKET SendingSocket; - SOCKADDR_IN ServerAddr, ThisSenderInfo; - int RetCode; - int BytesSent, nlen; - - WSAStartup(MAKEWORD(2,2), &wsaData); - - - SendingSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - - if(SendingSocket == INVALID_SOCKET) - { - if(MPDEV)printf("Client: socket() failed! Error code: %d\n", WSAGetLastError()); - WSACleanup(); - return; - } - - ServerAddr.sin_family = AF_INET; - - ServerAddr.sin_port = htons(Port); - - ServerAddr.sin_addr.s_addr = inet_addr(IP.c_str()); - - RetCode = connect(SendingSocket, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr)); - - if(RetCode != 0) - { - if(MPDEV)printf("Client: connect() failed! Error code: %ld\n", WSAGetLastError()); - closesocket(SendingSocket); - WSACleanup(); - return; - } - - getsockname(SendingSocket, (SOCKADDR *)&ServerAddr, (int *)sizeof(ServerAddr)); - BytesSent = send(SendingSocket, "a", 1, 0); - - int iResult; - char recvbuf[65535]; - int recvbuflen = 65535; - - do { - iResult = recv(SendingSocket, recvbuf, recvbuflen, 0); - if (iResult > 0) { - std::string File, Data = recvbuf,Response,toSend; - Data.resize(iResult); - std::vector list = Split(Data,";"); - std::vector FileNames(list.begin(),list.begin() + (list.size()/2)); - std::vector FileSizes(list.begin() + (list.size()/2), list.end()); - list.clear(); - Data.clear(); - Data.resize(recvbuflen); - int index = 0; - for(const std::string& a : FileNames){ - if(a.empty() || a.length() < 2)continue; - if(stat(a.c_str(),&info)==0){ - if(fs::file_size(a)==std::stoi(FileSizes.at(index))){ - index++; - continue; - }else remove(a.c_str()); - } - - std::ofstream LFS; - LFS.open(a.c_str()); - LFS.close(); - toSend = "b"+a; - //std::cout << a << std::endl; - send(SendingSocket, toSend.c_str(), toSend.length(), 0); - LFS.open (a.c_str(), std::ios_base::app | std::ios::binary); - do{ - iResult = recv(SendingSocket, recvbuf, recvbuflen, 0); - if(iResult < 0){File.clear(); break;} - Data.resize(iResult); - memcpy(&Data[0],recvbuf,iResult); - if(Data.find("Cannot Open") != std::string::npos){File.clear();break;} - LFS << Data; - float per = LFS.tellp()/std::stof(FileSizes.at(index))*100; - std::string Percent = std::to_string(truncf(per*10)/10); - UlStatus="UlDownloading Resource: "+a.substr(a.find_last_of('/'))+" ("+Percent.substr(0,Percent.find('.')+2)+"%)"; - //std::cout << UlStatus << std::endl; - }while(LFS.tellp() != std::stoi(FileSizes.at(index))); - LFS.close(); - File.clear(); - } - - toSend = "M"; - send(SendingSocket, toSend.c_str(), toSend.length(), 0); - iResult = recv(SendingSocket, recvbuf, recvbuflen, 0); - if(iResult < 0)break; - Data.resize(iResult); - memcpy(&Data[0],recvbuf,iResult); - MStatus = "M" + Data; - break; - } - else if (iResult == 0) - if(MPDEV)printf("Connection closing...\n"); - else { - if(MPDEV)printf("(Resources) recv failed with error: %d\n", WSAGetLastError()); - closesocket(SendingSocket); - break; - } - }while (iResult > 0); - if(BytesSent == SOCKET_ERROR) - if(MPDEV)printf("Client: send() error %d.\n", WSAGetLastError()); - - - - if( shutdown(SendingSocket, SD_SEND) != 0) - if(MPDEV)printf("Client: Well, there is something wrong with the shutdown() The error code: %d\n", WSAGetLastError()); - - - if(closesocket(SendingSocket) != 0) - if(MPDEV)printf("Client: Cannot close \"SendingSocket\" socket. Error code: %d\n", WSAGetLastError()); - - - if(WSACleanup() != 0) - if(MPDEV)printf("Client: WSACleanup() failed!...\n"); - - UlStatus = "Uldone"; - std::cout << "Done!" << std::endl; - ProxyThread(IP,Port); -} \ No newline at end of file diff --git a/include/enet.hpp b/include/enet.hpp deleted file mode 100644 index db5f095..0000000 --- a/include/enet.hpp +++ /dev/null @@ -1,5909 +0,0 @@ -/** - * include/enet.h - a Single-Header auto-generated variant of enet.h library. - * - * Usage: - * #define ENET_IMPLEMENTATION exactly in ONE source file right BEFORE including the library, like: - * - * #define ENET_IMPLEMENTATION - * #include - * - * License: - * The MIT License (MIT) - * - * Copyright (c) 2002-2016 Lee Salzman - * Copyright (c) 2017-2018 Vladyslav Hrytsenko, Dominik Madarász - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - */ -#ifndef ENET_INCLUDE_H -#define ENET_INCLUDE_H - -#include -#include -#include -#include -#define _WINSOCK_DEPRECATED_NO_WARNINGS -#define ENET_VERSION_MAJOR 2 -#define ENET_VERSION_MINOR 2 -#define ENET_VERSION_PATCH 0 -#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) -#define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF) -#define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF) -#define ENET_VERSION_GET_PATCH(version) ((version)&0xFF) -#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH) -#define ENET_TIME_OVERFLOW 86400000 -#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) -#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) -#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) -#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) - -// =======================================================================// -// ! -// ! System differences -// ! -// =======================================================================// - -#if defined(_WIN32) -#if defined(_MSC_VER) && defined(ENET_IMPLEMENTATION) -#pragma warning (disable: 4267) // size_t to int conversion -#pragma warning (disable: 4244) // 64bit to 32bit int -#pragma warning (disable: 4018) // signed/unsigned mismatch -#pragma warning (disable: 4146) // unary minus operator applied to unsigned type -#endif - -#ifndef ENET_NO_PRAGMA_LINK -#pragma comment(lib, "ws2_32.lib") -#pragma comment(lib, "winmm.lib") -#endif - -#if _MSC_VER >= 1910 -/* It looks like there were changes as of Visual Studio 2017 and there are no 32/64 bit - versions of _InterlockedExchange[operation], only InterlockedExchange[operation] - (without leading underscore), so we have to distinguish between compiler versions */ -#define NOT_UNDERSCORED_INTERLOCKED_EXCHANGE -#endif - -#ifdef __GNUC__ -#if (_WIN32_WINNT < 0x0501) - #undef _WIN32_WINNT - #define _WIN32_WINNT 0x0501 - #endif -#endif - -#include -#include -#include - -#include - -#if defined(_WIN32) && defined(_MSC_VER) -#if _MSC_VER < 1900 -typedef struct timespec { - long tv_sec; - long tv_nsec; - }; -#endif -#define CLOCK_MONOTONIC 0 -#endif - -typedef SOCKET ENetSocket; -#define ENET_SOCKET_NULL INVALID_SOCKET - -#define ENET_HOST_TO_NET_16(value) (htons(value)) -#define ENET_HOST_TO_NET_32(value) (htonl(value)) - -#define ENET_NET_TO_HOST_16(value) (ntohs(value)) -#define ENET_NET_TO_HOST_32(value) (ntohl(value)) - -typedef struct { - size_t dataLength; - void * data; -} ENetBuffer; - -#define ENET_CALLBACK __cdecl - -#ifdef ENET_DLL -#ifdef ENET_IMPLEMENTATION - #define ENET_API __declspec( dllexport ) - #else - #define ENET_API __declspec( dllimport ) - #endif // ENET_IMPLEMENTATION -#else -#define ENET_API extern -#endif // ENET_DLL - -typedef fd_set ENetSocketSet; - -#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO(&(sockset)) -#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET(socket, &(sockset)) -#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR(socket, &(sockset)) -#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET(socket, &(sockset)) -#else -#include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - #include - - #ifdef __APPLE__ - #include - #include - #include - #endif - - #ifndef MSG_NOSIGNAL - #define MSG_NOSIGNAL 0 - #endif - - #ifdef MSG_MAXIOVLEN - #define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN - #endif - - typedef int ENetSocket; - - #define ENET_SOCKET_NULL -1 - - #define ENET_HOST_TO_NET_16(value) (htons(value)) /**< macro that converts host to net byte-order of a 16-bit value */ - #define ENET_HOST_TO_NET_32(value) (htonl(value)) /**< macro that converts host to net byte-order of a 32-bit value */ - - #define ENET_NET_TO_HOST_16(value) (ntohs(value)) /**< macro that converts net to host byte-order of a 16-bit value */ - #define ENET_NET_TO_HOST_32(value) (ntohl(value)) /**< macro that converts net to host byte-order of a 32-bit value */ - - typedef struct { - void * data; - size_t dataLength; - } ENetBuffer; - - #define ENET_CALLBACK - #define ENET_API extern - - typedef fd_set ENetSocketSet; - - #define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO(&(sockset)) - #define ENET_SOCKETSET_ADD(sockset, socket) FD_SET(socket, &(sockset)) - #define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR(socket, &(sockset)) - #define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET(socket, &(sockset)) -#endif - -#ifndef ENET_BUFFER_MAXIMUM -#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) -#endif - -#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) -#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) - -#define ENET_IPV6 1 -#define ENET_HOST_ANY in6addr_any -#define ENET_HOST_BROADCAST 0xFFFFFFFFU -#define ENET_PORT_ANY 0 - -#ifdef __cplusplus -extern "C" { -#endif - -// =======================================================================// -// ! -// ! Basic stuff -// ! -// =======================================================================// - -typedef uint8_t enet_uint8; /**< unsigned 8-bit type */ -typedef uint16_t enet_uint16; /**< unsigned 16-bit type */ -typedef uint32_t enet_uint32; /**< unsigned 32-bit type */ -typedef uint64_t enet_uint64; /**< unsigned 64-bit type */ - -typedef enet_uint32 ENetVersion; - -typedef struct _ENetCallbacks { - void *(ENET_CALLBACK *malloc) (size_t size); - void (ENET_CALLBACK *free) (void *memory); - void (ENET_CALLBACK *no_memory) (void); -} ENetCallbacks; - -extern void *enet_malloc(size_t); -extern void enet_free(void *); - -// =======================================================================// -// ! -// ! List -// ! -// =======================================================================// - -typedef struct _ENetListNode { - struct _ENetListNode *next; - struct _ENetListNode *previous; -} ENetListNode; - -typedef ENetListNode *ENetListIterator; - -typedef struct _ENetList { - ENetListNode sentinel; -} ENetList; - -extern ENetListIterator enet_list_insert(ENetListIterator, void *); -extern ENetListIterator enet_list_move(ENetListIterator, void *, void *); - -extern void *enet_list_remove(ENetListIterator); -extern void enet_list_clear(ENetList *); -extern size_t enet_list_size(ENetList *); - -#define enet_list_begin(list) ((list)->sentinel.next) -#define enet_list_end(list) (&(list)->sentinel) -#define enet_list_empty(list) (enet_list_begin(list) == enet_list_end(list)) -#define enet_list_next(iterator) ((iterator)->next) -#define enet_list_previous(iterator) ((iterator)->previous) -#define enet_list_front(list) ((void *)(list)->sentinel.next) -#define enet_list_back(list) ((void *)(list)->sentinel.previous) - - -// =======================================================================// -// ! -// ! Protocol -// ! -// =======================================================================// - -enum { - ENET_PROTOCOL_MINIMUM_MTU = 576, - ENET_PROTOCOL_MAXIMUM_MTU = 4096, - ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32, - ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096, - ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536, - ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, - ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, - ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF, - ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024 -}; - -typedef enum _ENetProtocolCommand { - ENET_PROTOCOL_COMMAND_NONE = 0, - ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, - ENET_PROTOCOL_COMMAND_CONNECT = 2, - ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, - ENET_PROTOCOL_COMMAND_DISCONNECT = 4, - ENET_PROTOCOL_COMMAND_PING = 5, - ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, - ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, - ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, - ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, - ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, - ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, - ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, - ENET_PROTOCOL_COMMAND_COUNT = 13, - - ENET_PROTOCOL_COMMAND_MASK = 0x0F -} ENetProtocolCommand; - -typedef enum _ENetProtocolFlag { - ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), - ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), - - ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), - ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), - ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, - - ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), - ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 -} ENetProtocolFlag; - -#ifdef _MSC_VER -#pragma pack(push, 1) -#define ENET_PACKED -#elif defined(__GNUC__) || defined(__clang__) -#define ENET_PACKED __attribute__ ((packed)) - #else - #define ENET_PACKED -#endif - -typedef struct _ENetProtocolHeader { - enet_uint16 peerID; - enet_uint16 sentTime; -} ENET_PACKED ENetProtocolHeader; - -typedef struct _ENetProtocolCommandHeader { - enet_uint8 command; - enet_uint8 channelID; - enet_uint16 reliableSequenceNumber; -} ENET_PACKED ENetProtocolCommandHeader; - -typedef struct _ENetProtocolAcknowledge { - ENetProtocolCommandHeader header; - enet_uint16 receivedReliableSequenceNumber; - enet_uint16 receivedSentTime; -} ENET_PACKED ENetProtocolAcknowledge; - -typedef struct _ENetProtocolConnect { - ENetProtocolCommandHeader header; - enet_uint16 outgoingPeerID; - enet_uint8 incomingSessionID; - enet_uint8 outgoingSessionID; - enet_uint32 mtu; - enet_uint32 windowSize; - enet_uint32 channelCount; - enet_uint32 incomingBandwidth; - enet_uint32 outgoingBandwidth; - enet_uint32 packetThrottleInterval; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; - enet_uint32 connectID; - enet_uint32 data; -} ENET_PACKED ENetProtocolConnect; - -typedef struct _ENetProtocolVerifyConnect { - ENetProtocolCommandHeader header; - enet_uint16 outgoingPeerID; - enet_uint8 incomingSessionID; - enet_uint8 outgoingSessionID; - enet_uint32 mtu; - enet_uint32 windowSize; - enet_uint32 channelCount; - enet_uint32 incomingBandwidth; - enet_uint32 outgoingBandwidth; - enet_uint32 packetThrottleInterval; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; - enet_uint32 connectID; -} ENET_PACKED ENetProtocolVerifyConnect; - -typedef struct _ENetProtocolBandwidthLimit { - ENetProtocolCommandHeader header; - enet_uint32 incomingBandwidth; - enet_uint32 outgoingBandwidth; -} ENET_PACKED ENetProtocolBandwidthLimit; - -typedef struct _ENetProtocolThrottleConfigure { - ENetProtocolCommandHeader header; - enet_uint32 packetThrottleInterval; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; -} ENET_PACKED ENetProtocolThrottleConfigure; - -typedef struct _ENetProtocolDisconnect { - ENetProtocolCommandHeader header; - enet_uint32 data; -} ENET_PACKED ENetProtocolDisconnect; - -typedef struct _ENetProtocolPing { - ENetProtocolCommandHeader header; -} ENET_PACKED ENetProtocolPing; - -typedef struct _ENetProtocolSendReliable { - ENetProtocolCommandHeader header; - enet_uint16 dataLength; -} ENET_PACKED ENetProtocolSendReliable; - -typedef struct _ENetProtocolSendUnreliable { - ENetProtocolCommandHeader header; - enet_uint16 unreliableSequenceNumber; - enet_uint16 dataLength; -} ENET_PACKED ENetProtocolSendUnreliable; - -typedef struct _ENetProtocolSendUnsequenced { - ENetProtocolCommandHeader header; - enet_uint16 unsequencedGroup; - enet_uint16 dataLength; -} ENET_PACKED ENetProtocolSendUnsequenced; - -typedef struct _ENetProtocolSendFragment { - ENetProtocolCommandHeader header; - enet_uint16 startSequenceNumber; - enet_uint16 dataLength; - enet_uint32 fragmentCount; - enet_uint32 fragmentNumber; - enet_uint32 totalLength; - enet_uint32 fragmentOffset; -} ENET_PACKED ENetProtocolSendFragment; - -typedef union _ENetProtocol { - ENetProtocolCommandHeader header; - ENetProtocolAcknowledge acknowledge; - ENetProtocolConnect connect; - ENetProtocolVerifyConnect verifyConnect; - ENetProtocolDisconnect disconnect; - ENetProtocolPing ping; - ENetProtocolSendReliable sendReliable; - ENetProtocolSendUnreliable sendUnreliable; - ENetProtocolSendUnsequenced sendUnsequenced; - ENetProtocolSendFragment sendFragment; - ENetProtocolBandwidthLimit bandwidthLimit; - ENetProtocolThrottleConfigure throttleConfigure; -} ENET_PACKED ENetProtocol; - -#ifdef _MSC_VER -#pragma pack(pop) -#endif - -// =======================================================================// -// ! -// ! General ENet structs/enums -// ! -// =======================================================================// - -typedef enum _ENetSocketType { - ENET_SOCKET_TYPE_STREAM = 1, - ENET_SOCKET_TYPE_DATAGRAM = 2 -} ENetSocketType; - -typedef enum _ENetSocketWait { - ENET_SOCKET_WAIT_NONE = 0, - ENET_SOCKET_WAIT_SEND = (1 << 0), - ENET_SOCKET_WAIT_RECEIVE = (1 << 1), - ENET_SOCKET_WAIT_INTERRUPT = (1 << 2) -} ENetSocketWait; - -typedef enum _ENetSocketOption { - ENET_SOCKOPT_NONBLOCK = 1, - ENET_SOCKOPT_BROADCAST = 2, - ENET_SOCKOPT_RCVBUF = 3, - ENET_SOCKOPT_SNDBUF = 4, - ENET_SOCKOPT_REUSEADDR = 5, - ENET_SOCKOPT_RCVTIMEO = 6, - ENET_SOCKOPT_SNDTIMEO = 7, - ENET_SOCKOPT_ERROR = 8, - ENET_SOCKOPT_NODELAY = 9, - ENET_SOCKOPT_IPV6_V6ONLY = 10, -} ENetSocketOption; - -typedef enum _ENetSocketShutdown { - ENET_SOCKET_SHUTDOWN_READ = 0, - ENET_SOCKET_SHUTDOWN_WRITE = 1, - ENET_SOCKET_SHUTDOWN_READ_WRITE = 2 -} ENetSocketShutdown; - -/** - * Portable internet address structure. - * - * The host must be specified in network byte-order, and the port must be in host - * byte-order. The constant ENET_HOST_ANY may be used to specify the default - * server host. The constant ENET_HOST_BROADCAST may be used to specify the - * broadcast address (255.255.255.255). This makes sense for enet_host_connect, - * but not for enet_host_create. Once a server responds to a broadcast, the - * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. - */ -typedef struct _ENetAddress { - struct in6_addr host; - enet_uint16 port; - enet_uint16 sin6_scope_id; -} ENetAddress; - -#define in6_equal(in6_addr_a, in6_addr_b) (memcmp(&in6_addr_a, &in6_addr_b, sizeof(struct in6_addr)) == 0) - -/** - * Packet flag bit constants. - * - * The host must be specified in network byte-order, and the port must be in - * host byte-order. The constant ENET_HOST_ANY may be used to specify the - * default server host. - * - * @sa ENetPacket - */ -typedef enum _ENetPacketFlag { - ENET_PACKET_FLAG_RELIABLE = (1 << 0), /** packet must be received by the target peer and resend attempts should be made until the packet is delivered */ - ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), /** packet will not be sequenced with other packets not supported for reliable packets */ - ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2), /** packet will not allocate data, and user must supply it instead */ - ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3), /** packet will be fragmented using unreliable (instead of reliable) sends if it exceeds the MTU */ - ENET_PACKET_FLAG_SENT = (1 << 8), /** whether the packet has been sent from all queues it has been entered into */ -} ENetPacketFlag; - -typedef void (ENET_CALLBACK *ENetPacketFreeCallback)(void *); - -/** - * ENet packet structure. - * - * An ENet data packet that may be sent to or received from a peer. The shown - * fields should only be read and never modified. The data field contains the - * allocated data for the packet. The dataLength fields specifies the length - * of the allocated data. The flags field is either 0 (specifying no flags), - * or a bitwise-or of any combination of the following flags: - * - * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer and resend attempts should be made until the packet is delivered - * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets (not supported for reliable packets) - * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead - * ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable (instead of reliable) sends if it exceeds the MTU - * ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into - * @sa ENetPacketFlag - */ -typedef struct _ENetPacket { - size_t referenceCount; /**< internal use only */ - enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */ - enet_uint8 * data; /**< allocated data for packet */ - size_t dataLength; /**< length of data */ - ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */ - void * userData; /**< application private data, may be freely modified */ -} ENetPacket; - -typedef struct _ENetAcknowledgement { - ENetListNode acknowledgementList; - enet_uint32 sentTime; - ENetProtocol command; -} ENetAcknowledgement; - -typedef struct _ENetOutgoingCommand { - ENetListNode outgoingCommandList; - enet_uint16 reliableSequenceNumber; - enet_uint16 unreliableSequenceNumber; - enet_uint32 sentTime; - enet_uint32 roundTripTimeout; - enet_uint32 roundTripTimeoutLimit; - enet_uint32 fragmentOffset; - enet_uint16 fragmentLength; - enet_uint16 sendAttempts; - ENetProtocol command; - ENetPacket * packet; -} ENetOutgoingCommand; - -typedef struct _ENetIncomingCommand { - ENetListNode incomingCommandList; - enet_uint16 reliableSequenceNumber; - enet_uint16 unreliableSequenceNumber; - ENetProtocol command; - enet_uint32 fragmentCount; - enet_uint32 fragmentsRemaining; - enet_uint32 *fragments; - ENetPacket * packet; -} ENetIncomingCommand; - -typedef enum _ENetPeerState { - ENET_PEER_STATE_DISCONNECTED = 0, - ENET_PEER_STATE_CONNECTING = 1, - ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, - ENET_PEER_STATE_CONNECTION_PENDING = 3, - ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, - ENET_PEER_STATE_CONNECTED = 5, - ENET_PEER_STATE_DISCONNECT_LATER = 6, - ENET_PEER_STATE_DISCONNECTING = 7, - ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, - ENET_PEER_STATE_ZOMBIE = 9 -} ENetPeerState; - -enum { - ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024, - ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024, - ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000, - ENET_HOST_DEFAULT_MTU = 1400, - ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024, - ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024, - - ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 100, - ENET_PEER_DEFAULT_PACKET_THROTTLE = 32, - ENET_PEER_PACKET_THROTTLE_SCALE = 32, - ENET_PEER_PACKET_THROTTLE_COUNTER = 7, - ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2, - ENET_PEER_PACKET_THROTTLE_DECELERATION = 2, - ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000, - ENET_PEER_PACKET_LOSS_SCALE = (1 << 16), - ENET_PEER_PACKET_LOSS_INTERVAL = 10000, - ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024, - ENET_PEER_TIMEOUT_LIMIT = 32, - ENET_PEER_TIMEOUT_MINIMUM = 5000, - ENET_PEER_TIMEOUT_MAXIMUM = 6000, - ENET_PEER_PING_INTERVAL = 500, - ENET_PEER_UNSEQUENCED_WINDOWS = 64, - ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024, - ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32, - ENET_PEER_RELIABLE_WINDOWS = 16, - ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000, - ENET_PEER_FREE_RELIABLE_WINDOWS = 8 -}; - -typedef struct _ENetChannel { - enet_uint16 outgoingReliableSequenceNumber; - enet_uint16 outgoingUnreliableSequenceNumber; - enet_uint16 usedReliableWindows; - enet_uint16 reliableWindows[ENET_PEER_RELIABLE_WINDOWS]; - enet_uint16 incomingReliableSequenceNumber; - enet_uint16 incomingUnreliableSequenceNumber; - ENetList incomingReliableCommands; - ENetList incomingUnreliableCommands; -} ENetChannel; - -/** - * An ENet peer which data packets may be sent or received from. - * - * No fields should be modified unless otherwise specified. - */ -typedef struct _ENetPeer { - ENetListNode dispatchList; - struct _ENetHost *host; - enet_uint16 outgoingPeerID; - enet_uint16 incomingPeerID; - enet_uint32 connectID; - enet_uint8 outgoingSessionID; - enet_uint8 incomingSessionID; - ENetAddress address; /**< Internet address of the peer */ - void * data; /**< Application private data, may be freely modified */ - ENetPeerState state; - ENetChannel * channels; - size_t channelCount; /**< Number of channels allocated for communication with peer */ - enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ - enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ - enet_uint32 incomingBandwidthThrottleEpoch; - enet_uint32 outgoingBandwidthThrottleEpoch; - enet_uint32 incomingDataTotal; - enet_uint64 totalDataReceived; - enet_uint32 outgoingDataTotal; - enet_uint64 totalDataSent; - enet_uint32 lastSendTime; - enet_uint32 lastReceiveTime; - enet_uint32 nextTimeout; - enet_uint32 earliestTimeout; - enet_uint32 packetLossEpoch; - enet_uint32 packetsSent; - enet_uint64 totalPacketsSent; /**< total number of packets sent during a session */ - enet_uint32 packetsLost; - enet_uint32 totalPacketsLost; /**< total number of packets lost during a session */ - enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ - enet_uint32 packetLossVariance; - enet_uint32 packetThrottle; - enet_uint32 packetThrottleLimit; - enet_uint32 packetThrottleCounter; - enet_uint32 packetThrottleEpoch; - enet_uint32 packetThrottleAcceleration; - enet_uint32 packetThrottleDeceleration; - enet_uint32 packetThrottleInterval; - enet_uint32 pingInterval; - enet_uint32 timeoutLimit; - enet_uint32 timeoutMinimum; - enet_uint32 timeoutMaximum; - enet_uint32 lastRoundTripTime; - enet_uint32 lowestRoundTripTime; - enet_uint32 lastRoundTripTimeVariance; - enet_uint32 highestRoundTripTimeVariance; - enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */ - enet_uint32 ping; - enet_uint32 roundTripTimeVariance; - enet_uint32 mtu; - enet_uint32 windowSize; - enet_uint32 reliableDataInTransit; - enet_uint16 outgoingReliableSequenceNumber; - ENetList acknowledgements; - ENetList sentReliableCommands; - ENetList sentUnreliableCommands; - ENetList outgoingReliableCommands; - ENetList outgoingUnreliableCommands; - ENetList dispatchedCommands; - int needsDispatch; - enet_uint16 incomingUnsequencedGroup; - enet_uint16 outgoingUnsequencedGroup; - enet_uint32 unsequencedWindow[ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; - enet_uint32 eventData; - size_t totalWaitingData; -} ENetPeer; - -/** An ENet packet compressor for compressing UDP packets before socket sends or receives. */ -typedef struct _ENetCompressor { - /** Context data for the compressor. Must be non-nullptr. */ - void *context; - - /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ - size_t(ENET_CALLBACK * compress) (void *context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit); - - /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ - size_t(ENET_CALLBACK * decompress) (void *context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit); - - /** Destroys the context when compression is disabled or the host is destroyed. May be nullptr. */ - void (ENET_CALLBACK * destroy)(void *context); -} ENetCompressor; - -/** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */ -typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback)(const ENetBuffer *buffers, size_t bufferCount); - -/** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */ -typedef int (ENET_CALLBACK * ENetInterceptCallback)(struct _ENetHost *host, void *event); - -/** An ENet host for communicating with peers. - * - * No fields should be modified unless otherwise stated. - * - * @sa enet_host_create() - * @sa enet_host_destroy() - * @sa enet_host_connect() - * @sa enet_host_service() - * @sa enet_host_flush() - * @sa enet_host_broadcast() - * @sa enet_host_compress() - * @sa enet_host_channel_limit() - * @sa enet_host_bandwidth_limit() - * @sa enet_host_bandwidth_throttle() - */ -typedef struct _ENetHost { - ENetSocket socket; - ENetAddress address; /**< Internet address of the host */ - enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ - enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ - enet_uint32 bandwidthThrottleEpoch; - enet_uint32 mtu; - enet_uint32 randomSeed; - int recalculateBandwidthLimits; - ENetPeer * peers; /**< array of peers allocated for this host */ - size_t peerCount; /**< number of peers allocated for this host */ - size_t channelLimit; /**< maximum number of channels allowed for connected peers */ - enet_uint32 serviceTime; - ENetList dispatchQueue; - int continueSending; - size_t packetSize; - enet_uint16 headerFlags; - ENetProtocol commands[ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; - size_t commandCount; - ENetBuffer buffers[ENET_BUFFER_MAXIMUM]; - size_t bufferCount; - ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */ - ENetCompressor compressor; - enet_uint8 packetData[2][ENET_PROTOCOL_MAXIMUM_MTU]; - ENetAddress receivedAddress; - enet_uint8 * receivedData; - size_t receivedDataLength; - enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */ - enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */ - enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */ - enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */ - ENetInterceptCallback intercept; /**< callback the user can set to intercept received raw UDP packets */ - size_t connectedPeers; - size_t bandwidthLimitedPeers; - size_t duplicatePeers; /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */ - size_t maximumPacketSize; /**< the maximum allowable packet size that may be sent or received on a peer */ - size_t maximumWaitingData; /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */ -} ENetHost; - -/** - * An ENet event type, as specified in @ref ENetEvent. - */ -typedef enum _ENetEventType { - /** no event occurred within the specified time limit */ - ENET_EVENT_TYPE_NONE = 0, - - /** a connection request initiated by enet_host_connect has completed. - * The peer field contains the peer which successfully connected. - */ - ENET_EVENT_TYPE_CONNECT = 1, - - /** a peer has disconnected. This event is generated on a successful - * completion of a disconnect initiated by enet_peer_disconnect, if - * a peer has timed out. The peer field contains the peer - * which disconnected. The data field contains user supplied data - * describing the disconnection, or 0, if none is available. - */ - ENET_EVENT_TYPE_DISCONNECT = 2, - - /** a packet has been received from a peer. The peer field specifies the - * peer which sent the packet. The channelID field specifies the channel - * number upon which the packet was received. The packet field contains - * the packet that was received; this packet must be destroyed with - * enet_packet_destroy after use. - */ - ENET_EVENT_TYPE_RECEIVE = 3, - - /** a peer is disconnected because the host didn't receive the acknowledgment - * packet within certain maximum time out. The reason could be because of bad - * network connection or host crashed. - */ - ENET_EVENT_TYPE_DISCONNECT_TIMEOUT = 4, -} ENetEventType; - -/** - * An ENet event as returned by enet_host_service(). - * - * @sa enet_host_service - */ -typedef struct _ENetEvent { - ENetEventType type; /**< type of the event */ - ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ - enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */ - enet_uint32 data; /**< data associated with the event, if appropriate */ - ENetPacket * packet; /**< packet associated with the event, if appropriate */ -} ENetEvent; - -// =======================================================================// -// ! -// ! Public API -// ! -// =======================================================================// - -/** - * Initializes ENet globally. Must be called prior to using any functions in ENet. - * @returns 0 on success, < 0 on failure - */ -ENET_API int enet_initialize(void); - -/** - * Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored. - * - * @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use - * @param inits user-overridden callbacks where any nullptr callbacks will use ENet's defaults - * @returns 0 on success, < 0 on failure - */ -ENET_API int enet_initialize_with_callbacks(ENetVersion version, const ENetCallbacks * inits); - -/** - * Shuts down ENet globally. Should be called when a program that has initialized ENet exits. - */ -ENET_API void enet_deinitialize(void); - -/** - * Gives the linked version of the ENet library. - * @returns the version number - */ -ENET_API ENetVersion enet_linked_version(void); - -/** Returns the monotonic time in milliseconds. Its initial value is unspecified unless otherwise set. */ -ENET_API enet_uint32 enet_time_get(void); - -/** ENet socket functions */ -ENET_API ENetSocket enet_socket_create(ENetSocketType); -ENET_API int enet_socket_bind(ENetSocket, const ENetAddress *); -ENET_API int enet_socket_get_address(ENetSocket, ENetAddress *); -ENET_API int enet_socket_listen(ENetSocket, int); -ENET_API ENetSocket enet_socket_accept(ENetSocket, ENetAddress *); -ENET_API int enet_socket_connect(ENetSocket, const ENetAddress *); -ENET_API int enet_socket_send(ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); -ENET_API int enet_socket_receive(ENetSocket, ENetAddress *, ENetBuffer *, size_t); -ENET_API int enet_socket_wait(ENetSocket, enet_uint32 *, enet_uint64); -ENET_API int enet_socket_set_option(ENetSocket, ENetSocketOption, int); -ENET_API int enet_socket_get_option(ENetSocket, ENetSocketOption, int *); -ENET_API int enet_socket_shutdown(ENetSocket, ENetSocketShutdown); -ENET_API void enet_socket_destroy(ENetSocket); -ENET_API int enet_socketset_select(ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); - -/** Attempts to parse the printable form of the IP address in the parameter hostName - and sets the host field in the address parameter if successful. - @param address destination to store the parsed IP address - @param hostName IP address to parse - @retval 0 on success - @retval < 0 on failure - @returns the address of the given hostName in address on success - */ -ENET_API int enet_address_set_host_ip(ENetAddress * address, const char * hostName); - -/** Attempts to resolve the host named by the parameter hostName and sets - the host field in the address parameter if successful. - @param address destination to store resolved address - @param hostName host name to lookup - @retval 0 on success - @retval < 0 on failure - @returns the address of the given hostName in address on success - */ -ENET_API int enet_address_set_host(ENetAddress * address, const char * hostName); - -/** Gives the printable form of the IP address specified in the address parameter. - @param address address printed - @param hostName destination for name, must not be nullptr - @param nameLength maximum length of hostName. - @returns the null-terminated name of the host in hostName on success - @retval 0 on success - @retval < 0 on failure - */ -ENET_API int enet_address_get_host_ip(const ENetAddress * address, char * hostName, size_t nameLength); - -/** Attempts to do a reverse lookup of the host field in the address parameter. - @param address address used for reverse lookup - @param hostName destination for name, must not be nullptr - @param nameLength maximum length of hostName. - @returns the null-terminated name of the host in hostName on success - @retval 0 on success - @retval < 0 on failure - */ -ENET_API int enet_address_get_host(const ENetAddress * address, char * hostName, size_t nameLength); - -ENET_API enet_uint32 enet_host_get_peers_count(ENetHost *); -ENET_API enet_uint32 enet_host_get_packets_sent(ENetHost *); -ENET_API enet_uint32 enet_host_get_packets_received(ENetHost *); -ENET_API enet_uint32 enet_host_get_bytes_sent(ENetHost *); -ENET_API enet_uint32 enet_host_get_bytes_received(ENetHost *); -ENET_API enet_uint32 enet_host_get_received_data(ENetHost *, enet_uint8** data); -ENET_API enet_uint32 enet_host_get_mtu(ENetHost *); - -ENET_API enet_uint32 enet_peer_get_id(ENetPeer *); -ENET_API enet_uint32 enet_peer_get_ip(ENetPeer *, char * ip, size_t ipLength); -ENET_API enet_uint16 enet_peer_get_port(ENetPeer *); -ENET_API enet_uint32 enet_peer_get_rtt(ENetPeer *); -ENET_API enet_uint32 enet_peer_get_ping(ENetPeer *); -ENET_API enet_uint64 enet_peer_get_packets_sent(ENetPeer *); -ENET_API enet_uint32 enet_peer_get_packets_lost(ENetPeer *); -ENET_API enet_uint64 enet_peer_get_bytes_sent(ENetPeer *); -ENET_API enet_uint64 enet_peer_get_bytes_received(ENetPeer *); - -ENET_API ENetPeerState enet_peer_get_state(ENetPeer *); - -ENET_API void * enet_peer_get_data(ENetPeer *); -ENET_API void enet_peer_set_data(ENetPeer *, const void *); - -ENET_API void * enet_packet_get_data(ENetPacket *); -ENET_API enet_uint32 enet_packet_get_length(ENetPacket *); -ENET_API void enet_packet_set_free_callback(ENetPacket *, void *); - -ENET_API ENetPacket * enet_packet_create(const void *, size_t, enet_uint32); -ENET_API ENetPacket * enet_packet_create_offset(const void *, size_t, size_t, enet_uint32); -ENET_API void enet_packet_destroy(ENetPacket *); -ENET_API enet_uint32 enet_crc32(const ENetBuffer *, size_t); - -ENET_API ENetHost * enet_host_create(const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32); -ENET_API void enet_host_destroy(ENetHost *); -ENET_API ENetPeer * enet_host_connect(ENetHost *, const ENetAddress *, size_t, enet_uint32); -ENET_API int enet_host_check_events(ENetHost *, ENetEvent *); -ENET_API int enet_host_service(ENetHost *, ENetEvent *, enet_uint32); -ENET_API int enet_host_send_raw(ENetHost *, const ENetAddress *, enet_uint8 *, size_t); -ENET_API int enet_host_send_raw_ex(ENetHost *host, const ENetAddress* address, enet_uint8* data, size_t skipBytes, size_t bytesToSend); -ENET_API void enet_host_set_intercept(ENetHost *, const ENetInterceptCallback); -ENET_API void enet_host_flush(ENetHost *); -ENET_API void enet_host_broadcast(ENetHost *, enet_uint8, ENetPacket *); -ENET_API void enet_host_compress(ENetHost *, const ENetCompressor *); -ENET_API void enet_host_channel_limit(ENetHost *, size_t); -ENET_API void enet_host_bandwidth_limit(ENetHost *, enet_uint32, enet_uint32); -extern void enet_host_bandwidth_throttle(ENetHost *); -extern enet_uint64 enet_host_random_seed(void); - -ENET_API int enet_peer_send(ENetPeer *, enet_uint8, ENetPacket *); -ENET_API ENetPacket * enet_peer_receive(ENetPeer *, enet_uint8 * channelID); -ENET_API void enet_peer_ping(ENetPeer *); -ENET_API void enet_peer_ping_interval(ENetPeer *, enet_uint32); -ENET_API void enet_peer_timeout(ENetPeer *, enet_uint32, enet_uint32, enet_uint32); -ENET_API void enet_peer_reset(ENetPeer *); -ENET_API void enet_peer_disconnect(ENetPeer *, enet_uint32); -ENET_API void enet_peer_disconnect_now(ENetPeer *, enet_uint32); -ENET_API void enet_peer_disconnect_later(ENetPeer *, enet_uint32); -ENET_API void enet_peer_throttle_configure(ENetPeer *, enet_uint32, enet_uint32, enet_uint32); -extern int enet_peer_throttle(ENetPeer *, enet_uint32); -extern void enet_peer_reset_queues(ENetPeer *); -extern void enet_peer_setup_outgoing_command(ENetPeer *, ENetOutgoingCommand *); -extern ENetOutgoingCommand * enet_peer_queue_outgoing_command(ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); -extern ENetIncomingCommand * enet_peer_queue_incoming_command(ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32); -extern ENetAcknowledgement * enet_peer_queue_acknowledgement(ENetPeer *, const ENetProtocol *, enet_uint16); -extern void enet_peer_dispatch_incoming_unreliable_commands(ENetPeer *, ENetChannel *); -extern void enet_peer_dispatch_incoming_reliable_commands(ENetPeer *, ENetChannel *); -extern void enet_peer_on_connect(ENetPeer *); -extern void enet_peer_on_disconnect(ENetPeer *); - -extern size_t enet_protocol_command_size (enet_uint8); - -#ifdef __cplusplus -} -#endif - -#if defined(ENET_IMPLEMENTATION) && !defined(ENET_IMPLEMENTATION_DONE) -#define ENET_IMPLEMENTATION_DONE 1 - -#ifdef __cplusplus -extern "C" { -#endif - -// =======================================================================// -// ! -// ! Atomics -// ! -// =======================================================================// - -#if defined(_MSC_VER) - -#define ENET_AT_CASSERT_PRED(predicate) sizeof(char[2 * !!(predicate)-1]) -#define ENET_IS_SUPPORTED_ATOMIC(size) ENET_AT_CASSERT_PRED(size == 1 || size == 2 || size == 4 || size == 8) -#define ENET_ATOMIC_SIZEOF(variable) (ENET_IS_SUPPORTED_ATOMIC(sizeof(*(variable))), sizeof(*(variable))) - -__inline int64_t enet_at_atomic_read(char *ptr, size_t size) -{ - switch (size) { - case 1: - return _InterlockedExchangeAdd8((volatile char *)ptr, 0); - case 2: - return _InterlockedExchangeAdd16((volatile SHORT *)ptr, 0); - case 4: -#ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE - return InterlockedExchangeAdd((volatile LONG *)ptr, 0); -#else - return _InterlockedExchangeAdd((volatile LONG *)ptr, 0); -#endif - case 8: -#ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE - return InterlockedExchangeAdd64((volatile LONGLONG *)ptr, 0); -#else - return _InterlockedExchangeAdd64((volatile LONGLONG *)ptr, 0); -#endif - default: - return 0xbad13bad; /* never reached */ - } -} - -__inline int64_t enet_at_atomic_write(char *ptr, int64_t value, size_t size) -{ - switch (size) { - case 1: - return _InterlockedExchange8((volatile char *)ptr, (char)value); - case 2: - return _InterlockedExchange16((volatile SHORT *)ptr, (SHORT)value); - case 4: -#ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE - return InterlockedExchange((volatile LONG *)ptr, (LONG)value); -#else - return _InterlockedExchange((volatile LONG *)ptr, (LONG)value); -#endif - case 8: -#ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE - return InterlockedExchange64((volatile LONGLONG *)ptr, (LONGLONG)value); -#else - return _InterlockedExchange64((volatile LONGLONG *)ptr, (LONGLONG)value); -#endif - default: - return 0xbad13bad; /* never reached */ - } -} - -__inline int64_t enet_at_atomic_cas(char *ptr, int64_t new_val, int64_t old_val, size_t size) -{ - switch (size) { - case 1: - return _InterlockedCompareExchange8((volatile char *)ptr, (char)new_val, (char)old_val); - case 2: - return _InterlockedCompareExchange16((volatile SHORT *)ptr, (SHORT)new_val, - (SHORT)old_val); - case 4: -#ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE - return InterlockedCompareExchange((volatile LONG *)ptr, (LONG)new_val, (LONG)old_val); -#else - return _InterlockedCompareExchange((volatile LONG *)ptr, (LONG)new_val, (LONG)old_val); -#endif - case 8: -#ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE - return InterlockedCompareExchange64((volatile LONGLONG *)ptr, (LONGLONG)new_val, - (LONGLONG)old_val); -#else - return _InterlockedCompareExchange64((volatile LONGLONG *)ptr, (LONGLONG)new_val, - (LONGLONG)old_val); -#endif - default: - return 0xbad13bad; /* never reached */ - } -} - -__inline int64_t enet_at_atomic_inc(char *ptr, int64_t delta, size_t data_size) -{ - switch (data_size) { - case 1: - return _InterlockedExchangeAdd8((volatile char *)ptr, (char)delta); - case 2: - return _InterlockedExchangeAdd16((volatile SHORT *)ptr, (SHORT)delta); - case 4: -#ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE - return InterlockedExchangeAdd((volatile LONG *)ptr, (LONG)delta); -#else - return _InterlockedExchangeAdd((volatile LONG *)ptr, (LONG)delta); -#endif - case 8: -#ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE - return InterlockedExchangeAdd64((volatile LONGLONG *)ptr, (LONGLONG)delta); -#else - return _InterlockedExchangeAdd64((volatile LONGLONG *)ptr, (LONGLONG)delta); -#endif - default: - return 0xbad13bad; /* never reached */ - } -} - -#define ENET_ATOMIC_READ(variable) enet_at_atomic_read((char *)(variable), ENET_ATOMIC_SIZEOF(variable)) -#define ENET_ATOMIC_WRITE(variable, new_val) \ - enet_at_atomic_write((char *)(variable), (int64_t)(new_val), ENET_ATOMIC_SIZEOF(variable)) -#define ENET_ATOMIC_CAS(variable, old_value, new_val) \ - enet_at_atomic_cas((char *)(variable), (int64_t)(new_val), (int64_t)(old_value), \ - ENET_ATOMIC_SIZEOF(variable)) -#define ENET_ATOMIC_INC(variable) enet_at_atomic_inc((char *)(variable), 1, ENET_ATOMIC_SIZEOF(variable)) -#define ENET_ATOMIC_DEC(variable) enet_at_atomic_inc((char *)(variable), -1, ENET_ATOMIC_SIZEOF(variable)) -#define ENET_ATOMIC_INC_BY(variable, delta) \ - enet_at_atomic_inc((char *)(variable), (delta), ENET_ATOMIC_SIZEOF(variable)) -#define ENET_ATOMIC_DEC_BY(variable, delta) \ - enet_at_atomic_inc((char *)(variable), -(delta), ENET_ATOMIC_SIZEOF(variable)) - -#elif defined(__GNUC__) || defined(__clang__) - -#if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) - #define AT_HAVE_ATOMICS - #endif - - /* We want to use __atomic built-ins if possible because the __sync primitives are - deprecated, because the __atomic build-ins allow us to use ENET_ATOMIC_WRITE on - uninitialized memory without running into undefined behavior, and because the - __atomic versions generate more efficient code since we don't need to rely on - CAS when we don't actually want it. - - Note that we use acquire-release memory order (like mutexes do). We could use - sequentially consistent memory order but that has lower performance and is - almost always unneeded. */ - #ifdef AT_HAVE_ATOMICS - #define ENET_ATOMIC_READ(ptr) __atomic_load_n((ptr), __ATOMIC_ACQUIRE) - #define ENET_ATOMIC_WRITE(ptr, value) __atomic_store_n((ptr), (value), __ATOMIC_RELEASE) - - #ifndef typeof - #define typeof __typeof__ - #endif - - /* clang_analyzer doesn't know that CAS writes to memory so it complains about - potentially lost data. Replace the code with the equivalent non-sync code. */ - #ifdef __clang_analyzer__ - - #define ENET_ATOMIC_CAS(ptr, old_value, new_value) \ - ({ \ - typeof(*(ptr)) ENET_ATOMIC_CAS_old_actual_ = (*(ptr)); \ - if (ATOMIC_CAS_old_actual_ == (old_value)) { \ - *(ptr) = new_value; \ - } \ - ENET_ATOMIC_CAS_old_actual_; \ - }) - - #else - - /* Could use __auto_type instead of typeof but that shouldn't work in C++. - The ({ }) syntax is a GCC extension called statement expression. It lets - us return a value out of the macro. - - TODO We should return bool here instead of the old value to avoid the ABA - problem. */ - #define ENET_ATOMIC_CAS(ptr, old_value, new_value) \ - ({ \ - typeof(*(ptr)) ENET_ATOMIC_CAS_expected_ = (old_value); \ - __atomic_compare_exchange_n((ptr), &ENET_ATOMIC_CAS_expected_, (new_value), false, \ - __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE); \ - ENET_ATOMIC_CAS_expected_; \ - }) - - #endif /* __clang_analyzer__ */ - - #define ENET_ATOMIC_INC(ptr) __atomic_fetch_add((ptr), 1, __ATOMIC_ACQ_REL) - #define ENET_ATOMIC_DEC(ptr) __atomic_fetch_sub((ptr), 1, __ATOMIC_ACQ_REL) - #define ENET_ATOMIC_INC_BY(ptr, delta) __atomic_fetch_add((ptr), (delta), __ATOMIC_ACQ_REL) - #define ENET_ATOMIC_DEC_BY(ptr, delta) __atomic_fetch_sub((ptr), (delta), __ATOMIC_ACQ_REL) - - #else - - #define ENET_ATOMIC_READ(variable) __sync_fetch_and_add(variable, 0) - #define ENET_ATOMIC_WRITE(variable, new_val) \ - (void) __sync_val_compare_and_swap((variable), *(variable), (new_val)) - #define ENET_ATOMIC_CAS(variable, old_value, new_val) \ - __sync_val_compare_and_swap((variable), (old_value), (new_val)) - #define ENET_ATOMIC_INC(variable) __sync_fetch_and_add((variable), 1) - #define ENET_ATOMIC_DEC(variable) __sync_fetch_and_sub((variable), 1) - #define ENET_ATOMIC_INC_BY(variable, delta) __sync_fetch_and_add((variable), (delta), 1) - #define ENET_ATOMIC_DEC_BY(variable, delta) __sync_fetch_and_sub((variable), (delta), 1) - - #endif /* AT_HAVE_ATOMICS */ - - #undef AT_HAVE_ATOMICS - -#endif /* defined(_MSC_VER) */ - - -// =======================================================================// -// ! -// ! Callbacks -// ! -// =======================================================================// - -static ENetCallbacks callbacks = { malloc, free, abort }; - -int enet_initialize_with_callbacks(ENetVersion version, const ENetCallbacks *inits) { - if (version < ENET_VERSION_CREATE(1, 3, 0)) { - return -1; - } - - if (inits->malloc != nullptr || inits->free != nullptr) { - if (inits->malloc == nullptr || inits->free == nullptr) { - return -1; - } - - callbacks.malloc = inits->malloc; - callbacks.free = inits->free; - } - - if (inits->no_memory != nullptr) { - callbacks.no_memory = inits->no_memory; - } - - return enet_initialize(); -} - -ENetVersion enet_linked_version(void) { - return ENET_VERSION; -} - -void * enet_malloc(size_t size) { - void *memory = callbacks.malloc(size); - - if (memory == nullptr) { - callbacks.no_memory(); - } - - return memory; -} - -void enet_free(void *memory) { - callbacks.free(memory); -} - -// =======================================================================// -// ! -// ! List -// ! -// =======================================================================// - -void enet_list_clear(ENetList *list) { - list->sentinel.next = &list->sentinel; - list->sentinel.previous = &list->sentinel; -} - -ENetListIterator enet_list_insert(ENetListIterator position, void *data) { - ENetListIterator result = (ENetListIterator)data; - - result->previous = position->previous; - result->next = position; - - result->previous->next = result; - position->previous = result; - - return result; -} - -void *enet_list_remove(ENetListIterator position) { - position->previous->next = position->next; - position->next->previous = position->previous; - - return position; -} - -ENetListIterator enet_list_move(ENetListIterator position, void *dataFirst, void *dataLast) { - ENetListIterator first = (ENetListIterator)dataFirst; - ENetListIterator last = (ENetListIterator)dataLast; - - first->previous->next = last->next; - last->next->previous = first->previous; - - first->previous = position->previous; - last->next = position; - - first->previous->next = first; - position->previous = last; - - return first; -} - -size_t enet_list_size(ENetList *list) { - size_t size = 0; - ENetListIterator position; - - for (position = enet_list_begin(list); position != enet_list_end(list); position = enet_list_next(position)) { - ++size; - } - - return size; -} - -// =======================================================================// -// ! -// ! Packet -// ! -// =======================================================================// - -/** - * Creates a packet that may be sent to a peer. - * @param data initial contents of the packet's data; the packet's data will remain uninitialized if data is nullptr. - * @param dataLength size of the data allocated for this packet - * @param flags flags for this packet as described for the ENetPacket structure. - * @returns the packet on success, nullptr on failure - */ -ENetPacket *enet_packet_create(const void *data, size_t dataLength, enet_uint32 flags) { - ENetPacket *packet; - if (flags & ENET_PACKET_FLAG_NO_ALLOCATE) { - packet = (ENetPacket *)enet_malloc(sizeof (ENetPacket)); - if (packet == nullptr) { - return nullptr; - } - - packet->data = (enet_uint8 *)data; - } - else { - packet = (ENetPacket *)enet_malloc(sizeof (ENetPacket) + dataLength); - if (packet == nullptr) { - return nullptr; - } - - packet->data = (enet_uint8 *)packet + sizeof(ENetPacket); - - if (data != nullptr) { - memcpy(packet->data, data, dataLength); - } - } - - packet->referenceCount = 0; - packet->flags = flags; - packet->dataLength = dataLength; - packet->freeCallback = nullptr; - packet->userData = nullptr; - - return packet; -} - -ENetPacket *enet_packet_create_offset(const void *data, size_t dataLength, size_t dataOffset, enet_uint32 flags) { - ENetPacket *packet; - if (flags & ENET_PACKET_FLAG_NO_ALLOCATE) { - packet = (ENetPacket *)enet_malloc(sizeof (ENetPacket)); - if (packet == nullptr) { - return nullptr; - } - - packet->data = (enet_uint8 *)data; - } - else { - packet = (ENetPacket *)enet_malloc(sizeof (ENetPacket) + dataLength + dataOffset); - if (packet == nullptr) { - return nullptr; - } - - packet->data = (enet_uint8 *)packet + sizeof(ENetPacket); - - if (data != nullptr) { - memcpy(packet->data + dataOffset, data, dataLength); - } - } - - packet->referenceCount = 0; - packet->flags = flags; - packet->dataLength = dataLength + dataOffset; - packet->freeCallback = nullptr; - packet->userData = nullptr; - - return packet; -} - -/** - * Destroys the packet and deallocates its data. - * @param packet packet to be destroyed - */ -void enet_packet_destroy(ENetPacket *packet) { - if (packet == nullptr) { - return; - } - - if (packet->freeCallback != nullptr) { - (*packet->freeCallback)((void *)packet); - } - - enet_free(packet); -} - -static int initializedCRC32 = 0; -static enet_uint32 crcTable[256]; - -static enet_uint32 reflect_crc(int val, int bits) { - int result = 0, bit; - - for (bit = 0; bit < bits; bit++) { - if (val & 1) { result |= 1 << (bits - 1 - bit); } - val >>= 1; - } - - return result; -} - -static void initialize_crc32(void) { - int byte; - - for (byte = 0; byte < 256; ++byte) { - enet_uint32 crc = reflect_crc(byte, 8) << 24; - int offset; - - for (offset = 0; offset < 8; ++offset) { - if (crc & 0x80000000) { - crc = (crc << 1) ^ 0x04c11db7; - } else { - crc <<= 1; - } - } - - crcTable[byte] = reflect_crc(crc, 32); - } - - initializedCRC32 = 1; -} - -enet_uint32 enet_crc32(const ENetBuffer *buffers, size_t bufferCount) { - enet_uint32 crc = 0xFFFFFFFF; - - if (!initializedCRC32) { initialize_crc32(); } - - while (bufferCount-- > 0) { - const enet_uint8 *data = (const enet_uint8 *)buffers->data; - const enet_uint8 *dataEnd = &data[buffers->dataLength]; - - while (data < dataEnd) { - crc = (crc >> 8) ^ crcTable[(crc & 0xFF) ^ *data++]; - } - - ++buffers; - } - - return ENET_HOST_TO_NET_32(~crc); -} - -// =======================================================================// -// ! -// ! Protocol -// ! -// =======================================================================// - -static size_t commandSizes[ENET_PROTOCOL_COMMAND_COUNT] = { - 0, - sizeof(ENetProtocolAcknowledge), - sizeof(ENetProtocolConnect), - sizeof(ENetProtocolVerifyConnect), - sizeof(ENetProtocolDisconnect), - sizeof(ENetProtocolPing), - sizeof(ENetProtocolSendReliable), - sizeof(ENetProtocolSendUnreliable), - sizeof(ENetProtocolSendFragment), - sizeof(ENetProtocolSendUnsequenced), - sizeof(ENetProtocolBandwidthLimit), - sizeof(ENetProtocolThrottleConfigure), - sizeof(ENetProtocolSendFragment) -}; - -size_t enet_protocol_command_size(enet_uint8 commandNumber) { - return commandSizes[commandNumber & ENET_PROTOCOL_COMMAND_MASK]; -} - -static void enet_protocol_change_state(ENetHost *host, ENetPeer *peer, ENetPeerState state) { - if (state == ENET_PEER_STATE_CONNECTED || state == ENET_PEER_STATE_DISCONNECT_LATER) { - enet_peer_on_connect(peer); - } else { - enet_peer_on_disconnect(peer); - } - - peer->state = state; -} - -static void enet_protocol_dispatch_state(ENetHost *host, ENetPeer *peer, ENetPeerState state) { - enet_protocol_change_state(host, peer, state); - - if (!peer->needsDispatch) { - enet_list_insert(enet_list_end(&host->dispatchQueue), &peer->dispatchList); - peer->needsDispatch = 1; - } -} - -static int enet_protocol_dispatch_incoming_commands(ENetHost *host, ENetEvent *event) { - while (!enet_list_empty(&host->dispatchQueue)) { - ENetPeer *peer = (ENetPeer *) enet_list_remove(enet_list_begin(&host->dispatchQueue)); - peer->needsDispatch = 0; - - switch (peer->state) { - case ENET_PEER_STATE_CONNECTION_PENDING: - case ENET_PEER_STATE_CONNECTION_SUCCEEDED: - enet_protocol_change_state(host, peer, ENET_PEER_STATE_CONNECTED); - - event->type = ENET_EVENT_TYPE_CONNECT; - event->peer = peer; - event->data = peer->eventData; - - return 1; - - case ENET_PEER_STATE_ZOMBIE: - host->recalculateBandwidthLimits = 1; - - event->type = ENET_EVENT_TYPE_DISCONNECT; - event->peer = peer; - event->data = peer->eventData; - - enet_peer_reset(peer); - - return 1; - - case ENET_PEER_STATE_CONNECTED: - if (enet_list_empty(&peer->dispatchedCommands)) { - continue; - } - - event->packet = enet_peer_receive(peer, &event->channelID); - if (event->packet == nullptr) { - continue; - } - - event->type = ENET_EVENT_TYPE_RECEIVE; - event->peer = peer; - - if (!enet_list_empty(&peer->dispatchedCommands)) { - peer->needsDispatch = 1; - enet_list_insert(enet_list_end(&host->dispatchQueue), &peer->dispatchList); - } - - return 1; - - default: - break; - } - } - - return 0; -} /* enet_protocol_dispatch_incoming_commands */ - -static void enet_protocol_notify_connect(ENetHost *host, ENetPeer *peer, ENetEvent *event) { - host->recalculateBandwidthLimits = 1; - - if (event != nullptr) { - enet_protocol_change_state(host, peer, ENET_PEER_STATE_CONNECTED); - - peer->totalDataSent = 0; - peer->totalDataReceived = 0; - peer->totalPacketsSent = 0; - peer->totalPacketsLost = 0; - - event->type = ENET_EVENT_TYPE_CONNECT; - event->peer = peer; - event->data = peer->eventData; - } else { - enet_protocol_dispatch_state(host, peer, peer->state == ENET_PEER_STATE_CONNECTING ? ENET_PEER_STATE_CONNECTION_SUCCEEDED : ENET_PEER_STATE_CONNECTION_PENDING); - } -} - -static void enet_protocol_notify_disconnect(ENetHost *host, ENetPeer *peer, ENetEvent *event) { - if (peer->state >= ENET_PEER_STATE_CONNECTION_PENDING) { - host->recalculateBandwidthLimits = 1; - } - - if (peer->state != ENET_PEER_STATE_CONNECTING && peer->state < ENET_PEER_STATE_CONNECTION_SUCCEEDED) { - enet_peer_reset(peer); - } else if (event != nullptr) { - event->type = ENET_EVENT_TYPE_DISCONNECT; - event->peer = peer; - event->data = 0; - - enet_peer_reset(peer); - } else { - peer->eventData = 0; - enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); - } -} - -static void enet_protocol_notify_disconnect_timeout (ENetHost * host, ENetPeer * peer, ENetEvent * event) { - if (peer->state >= ENET_PEER_STATE_CONNECTION_PENDING) { - host->recalculateBandwidthLimits = 1; - } - - if (peer->state != ENET_PEER_STATE_CONNECTING && peer->state < ENET_PEER_STATE_CONNECTION_SUCCEEDED) { - enet_peer_reset (peer); - } - else if (event != nullptr) { - event->type = ENET_EVENT_TYPE_DISCONNECT_TIMEOUT; - event->peer = peer; - event->data = 0; - - enet_peer_reset(peer); - } - else { - peer->eventData = 0; - enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); - } -} - -static void enet_protocol_remove_sent_unreliable_commands(ENetPeer *peer) { - ENetOutgoingCommand *outgoingCommand; - - while (!enet_list_empty(&peer->sentUnreliableCommands)) { - outgoingCommand = (ENetOutgoingCommand *) enet_list_front(&peer->sentUnreliableCommands); - enet_list_remove(&outgoingCommand->outgoingCommandList); - - if (outgoingCommand->packet != nullptr) { - --outgoingCommand->packet->referenceCount; - - if (outgoingCommand->packet->referenceCount == 0) { - outgoingCommand->packet->flags |= ENET_PACKET_FLAG_SENT; - enet_packet_destroy(outgoingCommand->packet); - } - } - - enet_free(outgoingCommand); - } -} - -static ENetProtocolCommand enet_protocol_remove_sent_reliable_command(ENetPeer *peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID) { - ENetOutgoingCommand *outgoingCommand = nullptr; - ENetListIterator currentCommand; - ENetProtocolCommand commandNumber; - int wasSent = 1; - - for (currentCommand = enet_list_begin(&peer->sentReliableCommands); - currentCommand != enet_list_end(&peer->sentReliableCommands); - currentCommand = enet_list_next(currentCommand) - ) { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - - if (outgoingCommand->reliableSequenceNumber == reliableSequenceNumber && outgoingCommand->command.header.channelID == channelID) { - break; - } - } - - if (currentCommand == enet_list_end(&peer->sentReliableCommands)) { - for (currentCommand = enet_list_begin(&peer->outgoingReliableCommands); - currentCommand != enet_list_end(&peer->outgoingReliableCommands); - currentCommand = enet_list_next(currentCommand) - ) { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - - if (outgoingCommand->sendAttempts < 1) { return ENET_PROTOCOL_COMMAND_NONE; } - if (outgoingCommand->reliableSequenceNumber == reliableSequenceNumber && outgoingCommand->command.header.channelID == channelID) { - break; - } - } - - if (currentCommand == enet_list_end(&peer->outgoingReliableCommands)) { - return ENET_PROTOCOL_COMMAND_NONE; - } - - wasSent = 0; - } - - if (outgoingCommand == nullptr) { - return ENET_PROTOCOL_COMMAND_NONE; - } - - if (channelID < peer->channelCount) { - ENetChannel *channel = &peer->channels[channelID]; - enet_uint16 reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - if (channel->reliableWindows[reliableWindow] > 0) { - --channel->reliableWindows[reliableWindow]; - if (!channel->reliableWindows[reliableWindow]) { - channel->usedReliableWindows &= ~(1 << reliableWindow); - } - } - } - - commandNumber = (ENetProtocolCommand) (outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK); - enet_list_remove(&outgoingCommand->outgoingCommandList); - - if (outgoingCommand->packet != nullptr) { - if (wasSent) { - peer->reliableDataInTransit -= outgoingCommand->fragmentLength; - } - - --outgoingCommand->packet->referenceCount; - - if (outgoingCommand->packet->referenceCount == 0) { - outgoingCommand->packet->flags |= ENET_PACKET_FLAG_SENT; - enet_packet_destroy(outgoingCommand->packet); - } - } - - enet_free(outgoingCommand); - - if (enet_list_empty(&peer->sentReliableCommands)) { - return commandNumber; - } - - outgoingCommand = (ENetOutgoingCommand *) enet_list_front(&peer->sentReliableCommands); - peer->nextTimeout = outgoingCommand->sentTime + outgoingCommand->roundTripTimeout; - - return commandNumber; -} /* enet_protocol_remove_sent_reliable_command */ - -static ENetPeer * enet_protocol_handle_connect(ENetHost *host, ENetProtocolHeader *header, ENetProtocol *command) { - enet_uint8 incomingSessionID, outgoingSessionID; - enet_uint32 mtu, windowSize; - ENetChannel *channel; - size_t channelCount, duplicatePeers = 0; - ENetPeer *currentPeer, *peer = nullptr; - ENetProtocol verifyCommand; - - channelCount = ENET_NET_TO_HOST_32(command->connect.channelCount); - - if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) { - return nullptr; - } - - for (currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { - if (currentPeer->state == ENET_PEER_STATE_DISCONNECTED) { - if (peer == nullptr) { - peer = currentPeer; - } - } else if (currentPeer->state != ENET_PEER_STATE_CONNECTING && in6_equal(currentPeer->address.host, host->receivedAddress.host)) { - if (currentPeer->address.port == host->receivedAddress.port && currentPeer->connectID == command->connect.connectID) { - return nullptr; - } - - ++duplicatePeers; - } - } - - if (peer == nullptr || duplicatePeers >= host->duplicatePeers) { - return nullptr; - } - - if (channelCount > host->channelLimit) { - channelCount = host->channelLimit; - } - peer->channels = (ENetChannel *) enet_malloc(channelCount * sizeof(ENetChannel)); - if (peer->channels == nullptr) { - return nullptr; - } - peer->channelCount = channelCount; - peer->state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT; - peer->connectID = command->connect.connectID; - peer->address = host->receivedAddress; - peer->outgoingPeerID = ENET_NET_TO_HOST_16(command->connect.outgoingPeerID); - peer->incomingBandwidth = ENET_NET_TO_HOST_32(command->connect.incomingBandwidth); - peer->outgoingBandwidth = ENET_NET_TO_HOST_32(command->connect.outgoingBandwidth); - peer->packetThrottleInterval = ENET_NET_TO_HOST_32(command->connect.packetThrottleInterval); - peer->packetThrottleAcceleration = ENET_NET_TO_HOST_32(command->connect.packetThrottleAcceleration); - peer->packetThrottleDeceleration = ENET_NET_TO_HOST_32(command->connect.packetThrottleDeceleration); - peer->eventData = ENET_NET_TO_HOST_32(command->connect.data); - - incomingSessionID = command->connect.incomingSessionID == 0xFF ? peer->outgoingSessionID : command->connect.incomingSessionID; - incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); - if (incomingSessionID == peer->outgoingSessionID) { - incomingSessionID = (incomingSessionID + 1) - & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); - } - peer->outgoingSessionID = incomingSessionID; - - outgoingSessionID = command->connect.outgoingSessionID == 0xFF ? peer->incomingSessionID : command->connect.outgoingSessionID; - outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); - if (outgoingSessionID == peer->incomingSessionID) { - outgoingSessionID = (outgoingSessionID + 1) - & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); - } - peer->incomingSessionID = outgoingSessionID; - - for (channel = peer->channels; channel < &peer->channels[channelCount]; ++channel) { - channel->outgoingReliableSequenceNumber = 0; - channel->outgoingUnreliableSequenceNumber = 0; - channel->incomingReliableSequenceNumber = 0; - channel->incomingUnreliableSequenceNumber = 0; - - enet_list_clear(&channel->incomingReliableCommands); - enet_list_clear(&channel->incomingUnreliableCommands); - - channel->usedReliableWindows = 0; - memset(channel->reliableWindows, 0, sizeof(channel->reliableWindows)); - } - - mtu = ENET_NET_TO_HOST_32(command->connect.mtu); - - if (mtu < ENET_PROTOCOL_MINIMUM_MTU) { - mtu = ENET_PROTOCOL_MINIMUM_MTU; - } else if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) { - mtu = ENET_PROTOCOL_MAXIMUM_MTU; - } - - peer->mtu = mtu; - - if (host->outgoingBandwidth == 0 && peer->incomingBandwidth == 0) { - peer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - } else if (host->outgoingBandwidth == 0 || peer->incomingBandwidth == 0) { - peer->windowSize = (ENET_MAX(host->outgoingBandwidth, peer->incomingBandwidth) / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - } else { - peer->windowSize = (ENET_MIN(host->outgoingBandwidth, peer->incomingBandwidth) / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - } - - if (peer->windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) { - peer->windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - } else if (peer->windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) { - peer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - } - - if (host->incomingBandwidth == 0) { - windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - } else { - windowSize = (host->incomingBandwidth / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - } - - if (windowSize > ENET_NET_TO_HOST_32(command->connect.windowSize)) { - windowSize = ENET_NET_TO_HOST_32(command->connect.windowSize); - } - - if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) { - windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - } else if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) { - windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - } - - verifyCommand.header.command = ENET_PROTOCOL_COMMAND_VERIFY_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - verifyCommand.header.channelID = 0xFF; - verifyCommand.verifyConnect.outgoingPeerID = ENET_HOST_TO_NET_16(peer->incomingPeerID); - verifyCommand.verifyConnect.incomingSessionID = incomingSessionID; - verifyCommand.verifyConnect.outgoingSessionID = outgoingSessionID; - verifyCommand.verifyConnect.mtu = ENET_HOST_TO_NET_32(peer->mtu); - verifyCommand.verifyConnect.windowSize = ENET_HOST_TO_NET_32(windowSize); - verifyCommand.verifyConnect.channelCount = ENET_HOST_TO_NET_32(channelCount); - verifyCommand.verifyConnect.incomingBandwidth = ENET_HOST_TO_NET_32(host->incomingBandwidth); - verifyCommand.verifyConnect.outgoingBandwidth = ENET_HOST_TO_NET_32(host->outgoingBandwidth); - verifyCommand.verifyConnect.packetThrottleInterval = ENET_HOST_TO_NET_32(peer->packetThrottleInterval); - verifyCommand.verifyConnect.packetThrottleAcceleration = ENET_HOST_TO_NET_32(peer->packetThrottleAcceleration); - verifyCommand.verifyConnect.packetThrottleDeceleration = ENET_HOST_TO_NET_32(peer->packetThrottleDeceleration); - verifyCommand.verifyConnect.connectID = peer->connectID; - - enet_peer_queue_outgoing_command(peer, &verifyCommand, nullptr, 0, 0); - return peer; -} /* enet_protocol_handle_connect */ - -static int enet_protocol_handle_send_reliable(ENetHost *host, ENetPeer *peer, const ENetProtocol *command, enet_uint8 **currentData) { - size_t dataLength; - - if (command->header.channelID >= peer->channelCount || (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER)) { - return -1; - } - - dataLength = ENET_NET_TO_HOST_16(command->sendReliable.dataLength); - *currentData += dataLength; - - if (dataLength > host->maximumPacketSize || *currentData < host->receivedData || *currentData > &host->receivedData[host->receivedDataLength]) { - return -1; - } - - if (enet_peer_queue_incoming_command(peer, command, (const enet_uint8 *) command + sizeof(ENetProtocolSendReliable), dataLength, ENET_PACKET_FLAG_RELIABLE, 0) == nullptr) { - return -1; - } - - return 0; -} - -static int enet_protocol_handle_send_unsequenced(ENetHost *host, ENetPeer *peer, const ENetProtocol *command, enet_uint8 **currentData) { - enet_uint32 unsequencedGroup, index; - size_t dataLength; - - if (command->header.channelID >= peer->channelCount || (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER)) { - return -1; - } - - dataLength = ENET_NET_TO_HOST_16(command->sendUnsequenced.dataLength); - *currentData += dataLength; - if (dataLength > host->maximumPacketSize || *currentData < host->receivedData || *currentData > &host->receivedData[host->receivedDataLength]) { - return -1; - } - - unsequencedGroup = ENET_NET_TO_HOST_16(command->sendUnsequenced.unsequencedGroup); - index = unsequencedGroup % ENET_PEER_UNSEQUENCED_WINDOW_SIZE; - - if (unsequencedGroup < peer->incomingUnsequencedGroup) { - unsequencedGroup += 0x10000; - } - - if (unsequencedGroup >= (enet_uint32) peer->incomingUnsequencedGroup + ENET_PEER_FREE_UNSEQUENCED_WINDOWS * ENET_PEER_UNSEQUENCED_WINDOW_SIZE) { - return 0; - } - - unsequencedGroup &= 0xFFFF; - - if (unsequencedGroup - index != peer->incomingUnsequencedGroup) { - peer->incomingUnsequencedGroup = unsequencedGroup - index; - memset(peer->unsequencedWindow, 0, sizeof(peer->unsequencedWindow)); - } else if (peer->unsequencedWindow[index / 32] & (1 << (index % 32))) { - return 0; - } - - if (enet_peer_queue_incoming_command(peer, command, (const enet_uint8 *) command + sizeof(ENetProtocolSendUnsequenced), dataLength, ENET_PACKET_FLAG_UNSEQUENCED,0) == nullptr) { - return -1; - } - - peer->unsequencedWindow[index / 32] |= 1 << (index % 32); - - return 0; -} /* enet_protocol_handle_send_unsequenced */ - -static int enet_protocol_handle_send_unreliable(ENetHost *host, ENetPeer *peer, const ENetProtocol *command, - enet_uint8 **currentData) { - size_t dataLength; - - if (command->header.channelID >= peer->channelCount || - (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER)) - { - return -1; - } - - dataLength = ENET_NET_TO_HOST_16(command->sendUnreliable.dataLength); - *currentData += dataLength; - if (dataLength > host->maximumPacketSize || *currentData < host->receivedData || *currentData > &host->receivedData[host->receivedDataLength]) { - return -1; - } - - if (enet_peer_queue_incoming_command(peer, command, (const enet_uint8 *) command + sizeof(ENetProtocolSendUnreliable), dataLength, 0, 0) == nullptr) { - return -1; - } - - return 0; -} - -static int enet_protocol_handle_send_fragment(ENetHost *host, ENetPeer *peer, const ENetProtocol *command, enet_uint8 **currentData) { - enet_uint32 fragmentNumber, fragmentCount, fragmentOffset, fragmentLength, startSequenceNumber, totalLength; - ENetChannel *channel; - enet_uint16 startWindow, currentWindow; - ENetListIterator currentCommand; - ENetIncomingCommand *startCommand = nullptr; - - if (command->header.channelID >= peer->channelCount || (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER)) { - return -1; - } - - fragmentLength = ENET_NET_TO_HOST_16(command->sendFragment.dataLength); - *currentData += fragmentLength; - if (fragmentLength > host->maximumPacketSize || *currentData < host->receivedData || *currentData > &host->receivedData[host->receivedDataLength]) { - return -1; - } - - channel = &peer->channels[command->header.channelID]; - startSequenceNumber = ENET_NET_TO_HOST_16(command->sendFragment.startSequenceNumber); - startWindow = startSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - currentWindow = channel->incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - - if (startSequenceNumber < channel->incomingReliableSequenceNumber) { - startWindow += ENET_PEER_RELIABLE_WINDOWS; - } - - if (startWindow < currentWindow || startWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) { - return 0; - } - - fragmentNumber = ENET_NET_TO_HOST_32(command->sendFragment.fragmentNumber); - fragmentCount = ENET_NET_TO_HOST_32(command->sendFragment.fragmentCount); - fragmentOffset = ENET_NET_TO_HOST_32(command->sendFragment.fragmentOffset); - totalLength = ENET_NET_TO_HOST_32(command->sendFragment.totalLength); - - if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT || - fragmentNumber >= fragmentCount || - totalLength > host->maximumPacketSize || - fragmentOffset >= totalLength || - fragmentLength > totalLength - fragmentOffset - ) { - return -1; - } - - for (currentCommand = enet_list_previous(enet_list_end(&channel->incomingReliableCommands)); - currentCommand != enet_list_end(&channel->incomingReliableCommands); - currentCommand = enet_list_previous(currentCommand) - ) { - ENetIncomingCommand *incomingCommand = (ENetIncomingCommand *) currentCommand; - - if (startSequenceNumber >= channel->incomingReliableSequenceNumber) { - if (incomingCommand->reliableSequenceNumber < channel->incomingReliableSequenceNumber) { - continue; - } - } else if (incomingCommand->reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { - break; - } - - if (incomingCommand->reliableSequenceNumber <= startSequenceNumber) { - if (incomingCommand->reliableSequenceNumber < startSequenceNumber) { - break; - } - - if ((incomingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK) != - ENET_PROTOCOL_COMMAND_SEND_FRAGMENT || - totalLength != incomingCommand->packet->dataLength || - fragmentCount != incomingCommand->fragmentCount - ) { - return -1; - } - - startCommand = incomingCommand; - break; - } - } - - if (startCommand == nullptr) { - ENetProtocol hostCommand = *command; - hostCommand.header.reliableSequenceNumber = startSequenceNumber; - startCommand = enet_peer_queue_incoming_command(peer, &hostCommand, nullptr, totalLength, ENET_PACKET_FLAG_RELIABLE, fragmentCount); - if (startCommand == nullptr) { - return -1; - } - } - - if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) { - --startCommand->fragmentsRemaining; - startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); - - if (fragmentOffset + fragmentLength > startCommand->packet->dataLength) { - fragmentLength = startCommand->packet->dataLength - fragmentOffset; - } - - memcpy(startCommand->packet->data + fragmentOffset, (enet_uint8 *) command + sizeof(ENetProtocolSendFragment), fragmentLength); - - if (startCommand->fragmentsRemaining <= 0) { - enet_peer_dispatch_incoming_reliable_commands(peer, channel); - } - } - - return 0; -} /* enet_protocol_handle_send_fragment */ - -static int enet_protocol_handle_send_unreliable_fragment(ENetHost *host, ENetPeer *peer, const ENetProtocol *command, enet_uint8 **currentData) { - enet_uint32 fragmentNumber, fragmentCount, fragmentOffset, fragmentLength, reliableSequenceNumber, startSequenceNumber, totalLength; - enet_uint16 reliableWindow, currentWindow; - ENetChannel *channel; - ENetListIterator currentCommand; - ENetIncomingCommand *startCommand = nullptr; - - if (command->header.channelID >= peer->channelCount || (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER)) { - return -1; - } - - fragmentLength = ENET_NET_TO_HOST_16(command->sendFragment.dataLength); - *currentData += fragmentLength; - if (fragmentLength > host->maximumPacketSize || *currentData < host->receivedData || *currentData > &host->receivedData[host->receivedDataLength]) { - return -1; - } - - channel = &peer->channels[command->header.channelID]; - reliableSequenceNumber = command->header.reliableSequenceNumber; - startSequenceNumber = ENET_NET_TO_HOST_16(command->sendFragment.startSequenceNumber); - - reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - currentWindow = channel->incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - - if (reliableSequenceNumber < channel->incomingReliableSequenceNumber) { - reliableWindow += ENET_PEER_RELIABLE_WINDOWS; - } - - if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) { - return 0; - } - - if (reliableSequenceNumber == channel->incomingReliableSequenceNumber && startSequenceNumber <= channel->incomingUnreliableSequenceNumber) { - return 0; - } - - fragmentNumber = ENET_NET_TO_HOST_32(command->sendFragment.fragmentNumber); - fragmentCount = ENET_NET_TO_HOST_32(command->sendFragment.fragmentCount); - fragmentOffset = ENET_NET_TO_HOST_32(command->sendFragment.fragmentOffset); - totalLength = ENET_NET_TO_HOST_32(command->sendFragment.totalLength); - - if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT || - fragmentNumber >= fragmentCount || - totalLength > host->maximumPacketSize || - fragmentOffset >= totalLength || - fragmentLength > totalLength - fragmentOffset - ) { - return -1; - } - - for (currentCommand = enet_list_previous(enet_list_end(&channel->incomingUnreliableCommands)); - currentCommand != enet_list_end(&channel->incomingUnreliableCommands); - currentCommand = enet_list_previous(currentCommand) - ) { - ENetIncomingCommand *incomingCommand = (ENetIncomingCommand *) currentCommand; - - if (reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { - if (incomingCommand->reliableSequenceNumber < channel->incomingReliableSequenceNumber) { - continue; - } - } else if (incomingCommand->reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { - break; - } - - if (incomingCommand->reliableSequenceNumber < reliableSequenceNumber) { - break; - } - - if (incomingCommand->reliableSequenceNumber > reliableSequenceNumber) { - continue; - } - - if (incomingCommand->unreliableSequenceNumber <= startSequenceNumber) { - if (incomingCommand->unreliableSequenceNumber < startSequenceNumber) { - break; - } - - if ((incomingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK) != - ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT || - totalLength != incomingCommand->packet->dataLength || - fragmentCount != incomingCommand->fragmentCount - ) { - return -1; - } - - startCommand = incomingCommand; - break; - } - } - - if (startCommand == nullptr) { - startCommand = enet_peer_queue_incoming_command(peer, command, nullptr, totalLength, - ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT, fragmentCount); - if (startCommand == nullptr) { - return -1; - } - } - - if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) { - --startCommand->fragmentsRemaining; - startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); - - if (fragmentOffset + fragmentLength > startCommand->packet->dataLength) { - fragmentLength = startCommand->packet->dataLength - fragmentOffset; - } - - memcpy(startCommand->packet->data + fragmentOffset, (enet_uint8 *) command + sizeof(ENetProtocolSendFragment), fragmentLength); - - if (startCommand->fragmentsRemaining <= 0) { - enet_peer_dispatch_incoming_unreliable_commands(peer, channel); - } - } - - return 0; -} /* enet_protocol_handle_send_unreliable_fragment */ - -static int enet_protocol_handle_ping(ENetHost *host, ENetPeer *peer, const ENetProtocol *command) { - if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { - return -1; - } - - return 0; -} - -static int enet_protocol_handle_bandwidth_limit(ENetHost *host, ENetPeer *peer, const ENetProtocol *command) { - if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { - return -1; - } - - if (peer->incomingBandwidth != 0) { - --host->bandwidthLimitedPeers; - } - - peer->incomingBandwidth = ENET_NET_TO_HOST_32(command->bandwidthLimit.incomingBandwidth); - peer->outgoingBandwidth = ENET_NET_TO_HOST_32(command->bandwidthLimit.outgoingBandwidth); - - if (peer->incomingBandwidth != 0) { - ++host->bandwidthLimitedPeers; - } - - if (peer->incomingBandwidth == 0 && host->outgoingBandwidth == 0) { - peer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - } else if (peer->incomingBandwidth == 0 || host->outgoingBandwidth == 0) { - peer->windowSize = (ENET_MAX(peer->incomingBandwidth, host->outgoingBandwidth) - / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - } else { - peer->windowSize = (ENET_MIN(peer->incomingBandwidth, host->outgoingBandwidth) - / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - } - - if (peer->windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) { - peer->windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - } else if (peer->windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) { - peer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - } - - return 0; -} /* enet_protocol_handle_bandwidth_limit */ - -static int enet_protocol_handle_throttle_configure(ENetHost *host, ENetPeer *peer, const ENetProtocol *command) { - if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { - return -1; - } - - peer->packetThrottleInterval = ENET_NET_TO_HOST_32(command->throttleConfigure.packetThrottleInterval); - peer->packetThrottleAcceleration = ENET_NET_TO_HOST_32(command->throttleConfigure.packetThrottleAcceleration); - peer->packetThrottleDeceleration = ENET_NET_TO_HOST_32(command->throttleConfigure.packetThrottleDeceleration); - - return 0; -} - -static int enet_protocol_handle_disconnect(ENetHost *host, ENetPeer *peer, const ENetProtocol *command) { - if (peer->state == ENET_PEER_STATE_DISCONNECTED || peer->state == ENET_PEER_STATE_ZOMBIE || - peer->state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT - ) { - return 0; - } - - enet_peer_reset_queues(peer); - - if (peer->state == ENET_PEER_STATE_CONNECTION_SUCCEEDED || peer->state == ENET_PEER_STATE_DISCONNECTING || peer->state == ENET_PEER_STATE_CONNECTING) { - enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); - } - else if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { - if (peer->state == ENET_PEER_STATE_CONNECTION_PENDING) { host->recalculateBandwidthLimits = 1; } - enet_peer_reset(peer); - } - else if (command->header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) { - enet_protocol_change_state(host, peer, ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT); - } - else { - enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); - } - - if (peer->state != ENET_PEER_STATE_DISCONNECTED) { - peer->eventData = ENET_NET_TO_HOST_32(command->disconnect.data); - } - - return 0; -} - -static int enet_protocol_handle_acknowledge(ENetHost *host, ENetEvent *event, ENetPeer *peer, const ENetProtocol *command) { - enet_uint32 roundTripTime, receivedSentTime, receivedReliableSequenceNumber; - ENetProtocolCommand commandNumber; - - if (peer->state == ENET_PEER_STATE_DISCONNECTED || peer->state == ENET_PEER_STATE_ZOMBIE) { - return 0; - } - receivedSentTime = ENET_NET_TO_HOST_16(command->acknowledge.receivedSentTime); - receivedSentTime |= host->serviceTime & 0xFFFF0000; - if ((receivedSentTime & 0x8000) > (host->serviceTime & 0x8000)) { - receivedSentTime -= 0x10000; - } - - if (ENET_TIME_LESS(host->serviceTime, receivedSentTime)) { - return 0; - } - - peer->lastReceiveTime = host->serviceTime; - peer->earliestTimeout = 0; - roundTripTime = ENET_TIME_DIFFERENCE(host->serviceTime, receivedSentTime); - - enet_peer_throttle(peer, roundTripTime); - peer->roundTripTimeVariance -= peer->roundTripTimeVariance / 4; - - peer->ping = roundTripTime; - - if (roundTripTime >= peer->roundTripTime) { - peer->roundTripTime += (roundTripTime - peer->roundTripTime) / 8; - peer->roundTripTimeVariance += (roundTripTime - peer->roundTripTime) / 4; - } else { - peer->roundTripTime -= (peer->roundTripTime - roundTripTime) / 8; - peer->roundTripTimeVariance += (peer->roundTripTime - roundTripTime) / 4; - } - - if (peer->roundTripTime < peer->lowestRoundTripTime) { - peer->lowestRoundTripTime = peer->roundTripTime; - } - - if (peer->roundTripTimeVariance > peer->highestRoundTripTimeVariance) { - peer->highestRoundTripTimeVariance = peer->roundTripTimeVariance; - } - - if (peer->packetThrottleEpoch == 0 || - ENET_TIME_DIFFERENCE(host->serviceTime, peer->packetThrottleEpoch) >= peer->packetThrottleInterval - ) { - peer->lastRoundTripTime = peer->lowestRoundTripTime; - peer->lastRoundTripTimeVariance = peer->highestRoundTripTimeVariance; - peer->lowestRoundTripTime = peer->roundTripTime; - peer->highestRoundTripTimeVariance = peer->roundTripTimeVariance; - peer->packetThrottleEpoch = host->serviceTime; - } - - receivedReliableSequenceNumber = ENET_NET_TO_HOST_16(command->acknowledge.receivedReliableSequenceNumber); - commandNumber = enet_protocol_remove_sent_reliable_command(peer, receivedReliableSequenceNumber, command->header.channelID); - - switch (peer->state) { - case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: - if (commandNumber != ENET_PROTOCOL_COMMAND_VERIFY_CONNECT) { - return -1; - } - - enet_protocol_notify_connect(host, peer, event); - break; - - case ENET_PEER_STATE_DISCONNECTING: - if (commandNumber != ENET_PROTOCOL_COMMAND_DISCONNECT) { - return -1; - } - - enet_protocol_notify_disconnect(host, peer, event); - break; - - case ENET_PEER_STATE_DISCONNECT_LATER: - if (enet_list_empty(&peer->outgoingReliableCommands) && - enet_list_empty(&peer->outgoingUnreliableCommands) && - enet_list_empty(&peer->sentReliableCommands)) - { - enet_peer_disconnect(peer, peer->eventData); - } - break; - - default: - break; - } - - return 0; -} /* enet_protocol_handle_acknowledge */ - -static int enet_protocol_handle_verify_connect(ENetHost *host, ENetEvent *event, ENetPeer *peer, const ENetProtocol *command) { - enet_uint32 mtu, windowSize; - size_t channelCount; - - if (peer->state != ENET_PEER_STATE_CONNECTING) { - return 0; - } - - channelCount = ENET_NET_TO_HOST_32(command->verifyConnect.channelCount); - - if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT || - ENET_NET_TO_HOST_32(command->verifyConnect.packetThrottleInterval) != peer->packetThrottleInterval || - ENET_NET_TO_HOST_32(command->verifyConnect.packetThrottleAcceleration) != peer->packetThrottleAcceleration || - ENET_NET_TO_HOST_32(command->verifyConnect.packetThrottleDeceleration) != peer->packetThrottleDeceleration || - command->verifyConnect.connectID != peer->connectID - ) { - peer->eventData = 0; - enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); - return -1; - } - - enet_protocol_remove_sent_reliable_command(peer, 1, 0xFF); - - if (channelCount < peer->channelCount) { - peer->channelCount = channelCount; - } - - peer->outgoingPeerID = ENET_NET_TO_HOST_16(command->verifyConnect.outgoingPeerID); - peer->incomingSessionID = command->verifyConnect.incomingSessionID; - peer->outgoingSessionID = command->verifyConnect.outgoingSessionID; - - mtu = ENET_NET_TO_HOST_32(command->verifyConnect.mtu); - - if (mtu < ENET_PROTOCOL_MINIMUM_MTU) { - mtu = ENET_PROTOCOL_MINIMUM_MTU; - } else if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) { - mtu = ENET_PROTOCOL_MAXIMUM_MTU; - } - - if (mtu < peer->mtu) { - peer->mtu = mtu; - } - - windowSize = ENET_NET_TO_HOST_32(command->verifyConnect.windowSize); - if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) { - windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - } - - if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) { - windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - } - - if (windowSize < peer->windowSize) { - peer->windowSize = windowSize; - } - - peer->incomingBandwidth = ENET_NET_TO_HOST_32(command->verifyConnect.incomingBandwidth); - peer->outgoingBandwidth = ENET_NET_TO_HOST_32(command->verifyConnect.outgoingBandwidth); - - enet_protocol_notify_connect(host, peer, event); - return 0; -} /* enet_protocol_handle_verify_connect */ - -static int enet_protocol_handle_incoming_commands(ENetHost *host, ENetEvent *event) { - ENetProtocolHeader *header; - ENetProtocol *command; - ENetPeer *peer; - enet_uint8 *currentData; - size_t headerSize; - enet_uint16 peerID, flags; - enet_uint8 sessionID; - - if (host->receivedDataLength < (size_t) &((ENetProtocolHeader *) 0)->sentTime) { - return 0; - } - - header = (ENetProtocolHeader *) host->receivedData; - - peerID = ENET_NET_TO_HOST_16(header->peerID); - sessionID = (peerID & ENET_PROTOCOL_HEADER_SESSION_MASK) >> ENET_PROTOCOL_HEADER_SESSION_SHIFT; - flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK; - peerID &= ~(ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK); - - headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof(ENetProtocolHeader) : (size_t) &((ENetProtocolHeader *) 0)->sentTime); - if (host->checksum != nullptr) { - headerSize += sizeof(enet_uint32); - } - - if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID) { - peer = nullptr; - } else if (peerID >= host->peerCount) { - return 0; - } else { - peer = &host->peers[peerID]; - - if (peer->state == ENET_PEER_STATE_DISCONNECTED || - peer->state == ENET_PEER_STATE_ZOMBIE || - ((!in6_equal(host->receivedAddress.host , peer->address.host) || - host->receivedAddress.port != peer->address.port) && - 1 /* no broadcast in ipv6 !in6_equal(peer->address.host , ENET_HOST_BROADCAST)*/) || - (peer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID && - sessionID != peer->incomingSessionID) - ) { - return 0; - } - } - - if (flags & ENET_PROTOCOL_HEADER_FLAG_COMPRESSED) { - size_t originalSize; - if (host->compressor.context == nullptr || host->compressor.decompress == nullptr) { - return 0; - } - - originalSize = host->compressor.decompress(host->compressor.context, - host->receivedData + headerSize, - host->receivedDataLength - headerSize, - host->packetData[1] + headerSize, - sizeof(host->packetData[1]) - headerSize - ); - - if (originalSize <= 0 || originalSize > sizeof(host->packetData[1]) - headerSize) { - return 0; - } - - memcpy(host->packetData[1], header, headerSize); - host->receivedData = host->packetData[1]; - host->receivedDataLength = headerSize + originalSize; - } - - if (host->checksum != nullptr) { - enet_uint32 *checksum = (enet_uint32 *) &host->receivedData[headerSize - sizeof(enet_uint32)]; - enet_uint32 desiredChecksum = *checksum; - ENetBuffer buffer; - - *checksum = peer != nullptr ? peer->connectID : 0; - - buffer.data = host->receivedData; - buffer.dataLength = host->receivedDataLength; - - if (host->checksum(&buffer, 1) != desiredChecksum) { - return 0; - } - } - - if (peer != nullptr) { - peer->address.host = host->receivedAddress.host; - peer->address.port = host->receivedAddress.port; - peer->incomingDataTotal += host->receivedDataLength; - peer->totalDataReceived += host->receivedDataLength; - } - - currentData = host->receivedData + headerSize; - - while (currentData < &host->receivedData[host->receivedDataLength]) { - enet_uint8 commandNumber; - size_t commandSize; - - command = (ENetProtocol *) currentData; - - if (currentData + sizeof(ENetProtocolCommandHeader) > &host->receivedData[host->receivedDataLength]) { - break; - } - - commandNumber = command->header.command & ENET_PROTOCOL_COMMAND_MASK; - if (commandNumber >= ENET_PROTOCOL_COMMAND_COUNT) { - break; - } - - commandSize = commandSizes[commandNumber]; - if (commandSize == 0 || currentData + commandSize > &host->receivedData[host->receivedDataLength]) { - break; - } - - currentData += commandSize; - - if (peer == nullptr && (commandNumber != ENET_PROTOCOL_COMMAND_CONNECT || currentData < &host->receivedData[host->receivedDataLength])) { - break; - } - - command->header.reliableSequenceNumber = ENET_NET_TO_HOST_16(command->header.reliableSequenceNumber); - - switch (commandNumber) { - case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE: - if (enet_protocol_handle_acknowledge(host, event, peer, command)) { - goto commandError; - } - break; - - case ENET_PROTOCOL_COMMAND_CONNECT: - if (peer != nullptr) { - goto commandError; - } - peer = enet_protocol_handle_connect(host, header, command); - if (peer == nullptr) { - goto commandError; - } - break; - - case ENET_PROTOCOL_COMMAND_VERIFY_CONNECT: - if (enet_protocol_handle_verify_connect(host, event, peer, command)) { - goto commandError; - } - break; - - case ENET_PROTOCOL_COMMAND_DISCONNECT: - if (enet_protocol_handle_disconnect(host, peer, command)) { - goto commandError; - } - break; - - case ENET_PROTOCOL_COMMAND_PING: - if (enet_protocol_handle_ping(host, peer, command)) { - goto commandError; - } - break; - - case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: - if (enet_protocol_handle_send_reliable(host, peer, command, ¤tData)) { - goto commandError; - } - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: - if (enet_protocol_handle_send_unreliable(host, peer, command, ¤tData)) { - goto commandError; - } - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: - if (enet_protocol_handle_send_unsequenced(host, peer, command, ¤tData)) { - goto commandError; - } - break; - - case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: - if (enet_protocol_handle_send_fragment(host, peer, command, ¤tData)) { - goto commandError; - } - break; - - case ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT: - if (enet_protocol_handle_bandwidth_limit(host, peer, command)) { - goto commandError; - } - break; - - case ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE: - if (enet_protocol_handle_throttle_configure(host, peer, command)) { - goto commandError; - } - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT: - if (enet_protocol_handle_send_unreliable_fragment(host, peer, command, ¤tData)) { - goto commandError; - } - break; - - default: - goto commandError; - } - - if (peer != nullptr && (command->header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0) { - enet_uint16 sentTime; - - if (!(flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)) { - break; - } - - sentTime = ENET_NET_TO_HOST_16(header->sentTime); - - switch (peer->state) { - case ENET_PEER_STATE_DISCONNECTING: - case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: - case ENET_PEER_STATE_DISCONNECTED: - case ENET_PEER_STATE_ZOMBIE: - break; - - case ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT: - if ((command->header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) { - enet_peer_queue_acknowledgement(peer, command, sentTime); - } - break; - - default: - enet_peer_queue_acknowledgement(peer, command, sentTime); - break; - } - } - } - - commandError: - if (event != nullptr && event->type != ENET_EVENT_TYPE_NONE) { - return 1; - } - - return 0; -} /* enet_protocol_handle_incoming_commands */ - -static int enet_protocol_receive_incoming_commands(ENetHost *host, ENetEvent *event) { - int packets; - - for (packets = 0; packets < 256; ++packets) { - int receivedLength; - ENetBuffer buffer; - - buffer.data = host->packetData[0]; - // buffer.dataLength = sizeof (host->packetData[0]); - buffer.dataLength = host->mtu; - - receivedLength = enet_socket_receive(host->socket, &host->receivedAddress, &buffer, 1); - - if (receivedLength == -2) - continue; - - if (receivedLength < 0) { - return -1; - } - - if (receivedLength == 0) { - return 0; - } - - host->receivedData = host->packetData[0]; - host->receivedDataLength = receivedLength; - - host->totalReceivedData += receivedLength; - host->totalReceivedPackets++; - - if (host->intercept != nullptr) { - switch (host->intercept(host, (void *)event)) { - case 1: - if (event != nullptr && event->type != ENET_EVENT_TYPE_NONE) { - return 1; - } - - continue; - - case -1: - return -1; - - default: - break; - } - } - - switch (enet_protocol_handle_incoming_commands(host, event)) { - case 1: - return 1; - - case -1: - return -1; - - default: - break; - } - } - - return -1; -} /* enet_protocol_receive_incoming_commands */ - -static void enet_protocol_send_acknowledgements(ENetHost *host, ENetPeer *peer) { - ENetProtocol *command = &host->commands[host->commandCount]; - ENetBuffer *buffer = &host->buffers[host->bufferCount]; - ENetAcknowledgement *acknowledgement; - ENetListIterator currentAcknowledgement; - enet_uint16 reliableSequenceNumber; - - currentAcknowledgement = enet_list_begin(&peer->acknowledgements); - - while (currentAcknowledgement != enet_list_end(&peer->acknowledgements)) { - if (command >= &host->commands[sizeof(host->commands) / sizeof(ENetProtocol)] || - buffer >= &host->buffers[sizeof(host->buffers) / sizeof(ENetBuffer)] || - peer->mtu - host->packetSize < sizeof(ENetProtocolAcknowledge) - ) { - host->continueSending = 1; - break; - } - - acknowledgement = (ENetAcknowledgement *) currentAcknowledgement; - currentAcknowledgement = enet_list_next(currentAcknowledgement); - - buffer->data = command; - buffer->dataLength = sizeof(ENetProtocolAcknowledge); - host->packetSize += buffer->dataLength; - - reliableSequenceNumber = ENET_HOST_TO_NET_16(acknowledgement->command.header.reliableSequenceNumber); - - command->header.command = ENET_PROTOCOL_COMMAND_ACKNOWLEDGE; - command->header.channelID = acknowledgement->command.header.channelID; - command->header.reliableSequenceNumber = reliableSequenceNumber; - command->acknowledge.receivedReliableSequenceNumber = reliableSequenceNumber; - command->acknowledge.receivedSentTime = ENET_HOST_TO_NET_16(acknowledgement->sentTime); - - if ((acknowledgement->command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) { - enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); - } - - enet_list_remove(&acknowledgement->acknowledgementList); - enet_free(acknowledgement); - - ++command; - ++buffer; - } - - host->commandCount = command - host->commands; - host->bufferCount = buffer - host->buffers; -} /* enet_protocol_send_acknowledgements */ - -static void enet_protocol_send_unreliable_outgoing_commands(ENetHost *host, ENetPeer *peer) { - ENetProtocol *command = &host->commands[host->commandCount]; - ENetBuffer *buffer = &host->buffers[host->bufferCount]; - ENetOutgoingCommand *outgoingCommand; - ENetListIterator currentCommand; - - currentCommand = enet_list_begin(&peer->outgoingUnreliableCommands); - while (currentCommand != enet_list_end(&peer->outgoingUnreliableCommands)) { - size_t commandSize; - - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - commandSize = commandSizes[outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK]; - - if (command >= &host->commands[sizeof(host->commands) / sizeof(ENetProtocol)] || - buffer + 1 >= &host->buffers[sizeof(host->buffers) / sizeof(ENetBuffer)] || - peer->mtu - host->packetSize < commandSize || - (outgoingCommand->packet != nullptr && - peer->mtu - host->packetSize < commandSize + outgoingCommand->fragmentLength) - ) { - host->continueSending = 1; - break; - } - - currentCommand = enet_list_next(currentCommand); - - if (outgoingCommand->packet != nullptr && outgoingCommand->fragmentOffset == 0) { - peer->packetThrottleCounter += ENET_PEER_PACKET_THROTTLE_COUNTER; - peer->packetThrottleCounter %= ENET_PEER_PACKET_THROTTLE_SCALE; - - if (peer->packetThrottleCounter > peer->packetThrottle) { - enet_uint16 reliableSequenceNumber = outgoingCommand->reliableSequenceNumber; - enet_uint16 unreliableSequenceNumber = outgoingCommand->unreliableSequenceNumber; - for (;;) { - --outgoingCommand->packet->referenceCount; - - if (outgoingCommand->packet->referenceCount == 0) { - enet_packet_destroy(outgoingCommand->packet); - } - - enet_list_remove(&outgoingCommand->outgoingCommandList); - enet_free(outgoingCommand); - - if (currentCommand == enet_list_end(&peer->outgoingUnreliableCommands)) { - break; - } - - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - if (outgoingCommand->reliableSequenceNumber != reliableSequenceNumber || outgoingCommand->unreliableSequenceNumber != unreliableSequenceNumber) { - break; - } - - currentCommand = enet_list_next(currentCommand); - } - - continue; - } - } - - buffer->data = command; - buffer->dataLength = commandSize; - host->packetSize += buffer->dataLength; - *command = outgoingCommand->command; - enet_list_remove(&outgoingCommand->outgoingCommandList); - - if (outgoingCommand->packet != nullptr) { - ++buffer; - - buffer->data = outgoingCommand->packet->data + outgoingCommand->fragmentOffset; - buffer->dataLength = outgoingCommand->fragmentLength; - - host->packetSize += buffer->dataLength; - - enet_list_insert(enet_list_end(&peer->sentUnreliableCommands), outgoingCommand); - } else { - enet_free(outgoingCommand); - } - - ++command; - ++buffer; - } - - host->commandCount = command - host->commands; - host->bufferCount = buffer - host->buffers; - - if (peer->state == ENET_PEER_STATE_DISCONNECT_LATER && - enet_list_empty(&peer->outgoingReliableCommands) && - enet_list_empty(&peer->outgoingUnreliableCommands) && - enet_list_empty(&peer->sentReliableCommands)) - { - enet_peer_disconnect(peer, peer->eventData); - } -} /* enet_protocol_send_unreliable_outgoing_commands */ - -static int enet_protocol_check_timeouts(ENetHost *host, ENetPeer *peer, ENetEvent *event) { - ENetOutgoingCommand *outgoingCommand; - ENetListIterator currentCommand, insertPosition; - - currentCommand = enet_list_begin(&peer->sentReliableCommands); - insertPosition = enet_list_begin(&peer->outgoingReliableCommands); - - while (currentCommand != enet_list_end(&peer->sentReliableCommands)) { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - - currentCommand = enet_list_next(currentCommand); - - if (ENET_TIME_DIFFERENCE(host->serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) { - continue; - } - - if (peer->earliestTimeout == 0 || ENET_TIME_LESS(outgoingCommand->sentTime, peer->earliestTimeout)) { - peer->earliestTimeout = outgoingCommand->sentTime; - } - - if (peer->earliestTimeout != 0 && - (ENET_TIME_DIFFERENCE(host->serviceTime, peer->earliestTimeout) >= peer->timeoutMaximum || - (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && - ENET_TIME_DIFFERENCE(host->serviceTime, peer->earliestTimeout) >= peer->timeoutMinimum)) - ) { - enet_protocol_notify_disconnect_timeout(host, peer, event); - return 1; - } - - if (outgoingCommand->packet != nullptr) { - peer->reliableDataInTransit -= outgoingCommand->fragmentLength; - } - - ++peer->packetsLost; - ++peer->totalPacketsLost; - - /* Replaced exponential backoff time with something more linear */ - /* Source: http://lists.cubik.org/pipermail/enet-discuss/2014-May/002308.html */ - outgoingCommand->roundTripTimeout = peer->roundTripTime + 4 * peer->roundTripTimeVariance; - outgoingCommand->roundTripTimeoutLimit = peer->timeoutLimit * outgoingCommand->roundTripTimeout; - - enet_list_insert(insertPosition, enet_list_remove(&outgoingCommand->outgoingCommandList)); - - if (currentCommand == enet_list_begin(&peer->sentReliableCommands) && !enet_list_empty(&peer->sentReliableCommands)) { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - peer->nextTimeout = outgoingCommand->sentTime + outgoingCommand->roundTripTimeout; - } - } - - return 0; -} /* enet_protocol_check_timeouts */ - -static int enet_protocol_send_reliable_outgoing_commands(ENetHost *host, ENetPeer *peer) { - ENetProtocol *command = &host->commands[host->commandCount]; - ENetBuffer *buffer = &host->buffers[host->bufferCount]; - ENetOutgoingCommand *outgoingCommand; - ENetListIterator currentCommand; - ENetChannel *channel; - enet_uint16 reliableWindow; - size_t commandSize; - int windowExceeded = 0, windowWrap = 0, canPing = 1; - - currentCommand = enet_list_begin(&peer->outgoingReliableCommands); - - while (currentCommand != enet_list_end(&peer->outgoingReliableCommands)) { - outgoingCommand = (ENetOutgoingCommand *) currentCommand; - - channel = outgoingCommand->command.header.channelID < peer->channelCount ? &peer->channels[outgoingCommand->command.header.channelID] : nullptr; - reliableWindow = outgoingCommand->reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - if (channel != nullptr) { - if (!windowWrap && - outgoingCommand->sendAttempts < 1 && - !(outgoingCommand->reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) && - (channel->reliableWindows[(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) - % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE || - channel->usedReliableWindows & ((((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) << reliableWindow) - | (((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) >> (ENET_PEER_RELIABLE_WINDOWS - reliableWindow)))) - ) { - windowWrap = 1; - } - - if (windowWrap) { - currentCommand = enet_list_next(currentCommand); - continue; - } - } - - if (outgoingCommand->packet != nullptr) { - if (!windowExceeded) { - enet_uint32 windowSize = (peer->packetThrottle * peer->windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE; - - if (peer->reliableDataInTransit + outgoingCommand->fragmentLength > ENET_MAX(windowSize, peer->mtu)) { - windowExceeded = 1; - } - } - if (windowExceeded) { - currentCommand = enet_list_next(currentCommand); - - continue; - } - } - - canPing = 0; - - commandSize = commandSizes[outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK]; - if (command >= &host->commands[sizeof(host->commands) / sizeof(ENetProtocol)] || - buffer + 1 >= &host->buffers[sizeof(host->buffers) / sizeof(ENetBuffer)] || - peer->mtu - host->packetSize < commandSize || - (outgoingCommand->packet != nullptr && - (enet_uint16) (peer->mtu - host->packetSize) < (enet_uint16) (commandSize + outgoingCommand->fragmentLength)) - ) { - host->continueSending = 1; - break; - } - - currentCommand = enet_list_next(currentCommand); - - if (channel != nullptr && outgoingCommand->sendAttempts < 1) { - channel->usedReliableWindows |= 1 << reliableWindow; - ++channel->reliableWindows[reliableWindow]; - } - - ++outgoingCommand->sendAttempts; - - if (outgoingCommand->roundTripTimeout == 0) { - outgoingCommand->roundTripTimeout = peer->roundTripTime + 4 * peer->roundTripTimeVariance; - outgoingCommand->roundTripTimeoutLimit = peer->timeoutLimit * outgoingCommand->roundTripTimeout; - } - - if (enet_list_empty(&peer->sentReliableCommands)) { - peer->nextTimeout = host->serviceTime + outgoingCommand->roundTripTimeout; - } - - enet_list_insert(enet_list_end(&peer->sentReliableCommands), enet_list_remove(&outgoingCommand->outgoingCommandList)); - - outgoingCommand->sentTime = host->serviceTime; - - buffer->data = command; - buffer->dataLength = commandSize; - - host->packetSize += buffer->dataLength; - host->headerFlags |= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME; - - *command = outgoingCommand->command; - - if (outgoingCommand->packet != nullptr) { - ++buffer; - buffer->data = outgoingCommand->packet->data + outgoingCommand->fragmentOffset; - buffer->dataLength = outgoingCommand->fragmentLength; - host->packetSize += outgoingCommand->fragmentLength; - peer->reliableDataInTransit += outgoingCommand->fragmentLength; - } - - ++peer->packetsSent; - ++peer->totalPacketsSent; - - ++command; - ++buffer; - } - - host->commandCount = command - host->commands; - host->bufferCount = buffer - host->buffers; - - return canPing; -} /* enet_protocol_send_reliable_outgoing_commands */ - -static int enet_protocol_send_outgoing_commands(ENetHost *host, ENetEvent *event, int checkForTimeouts) { - enet_uint8 headerData[sizeof(ENetProtocolHeader) + sizeof(enet_uint32)]; - ENetProtocolHeader *header = (ENetProtocolHeader *) headerData; - ENetPeer *currentPeer; - int sentLength; - size_t shouldCompress = 0; - host->continueSending = 1; - - while (host->continueSending) - for (host->continueSending = 0, currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { - if (currentPeer->state == ENET_PEER_STATE_DISCONNECTED || currentPeer->state == ENET_PEER_STATE_ZOMBIE) { - continue; - } - - host->headerFlags = 0; - host->commandCount = 0; - host->bufferCount = 1; - host->packetSize = sizeof(ENetProtocolHeader); - - if (!enet_list_empty(¤tPeer->acknowledgements)) { - enet_protocol_send_acknowledgements(host, currentPeer); - } - - if (checkForTimeouts != 0 && - !enet_list_empty(¤tPeer->sentReliableCommands) && - ENET_TIME_GREATER_EQUAL(host->serviceTime, currentPeer->nextTimeout) && - enet_protocol_check_timeouts(host, currentPeer, event) == 1 - ) { - if (event != nullptr && event->type != ENET_EVENT_TYPE_NONE) { - return 1; - } else { - continue; - } - } - - if ((enet_list_empty(¤tPeer->outgoingReliableCommands) || - enet_protocol_send_reliable_outgoing_commands(host, currentPeer)) && - enet_list_empty(¤tPeer->sentReliableCommands) && - ENET_TIME_DIFFERENCE(host->serviceTime, currentPeer->lastReceiveTime) >= currentPeer->pingInterval && - currentPeer->mtu - host->packetSize >= sizeof(ENetProtocolPing) - ) { - enet_peer_ping(currentPeer); - enet_protocol_send_reliable_outgoing_commands(host, currentPeer); - } - - if (!enet_list_empty(¤tPeer->outgoingUnreliableCommands)) { - enet_protocol_send_unreliable_outgoing_commands(host, currentPeer); - } - - if (host->commandCount == 0) { - continue; - } - - if (currentPeer->packetLossEpoch == 0) { - currentPeer->packetLossEpoch = host->serviceTime; - } else if (ENET_TIME_DIFFERENCE(host->serviceTime, currentPeer->packetLossEpoch) >= ENET_PEER_PACKET_LOSS_INTERVAL && currentPeer->packetsSent > 0) { - enet_uint32 packetLoss = currentPeer->packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer->packetsSent; - -#ifdef ENET_DEBUG - printf( - "peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n", currentPeer->incomingPeerID, - currentPeer->packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, - currentPeer->packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer->roundTripTime, currentPeer->roundTripTimeVariance, - currentPeer->packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, - enet_list_size(¤tPeer->outgoingReliableCommands), - enet_list_size(¤tPeer->outgoingUnreliableCommands), - currentPeer->channels != nullptr ? enet_list_size( ¤tPeer->channels->incomingReliableCommands) : 0, - currentPeer->channels != nullptr ? enet_list_size(¤tPeer->channels->incomingUnreliableCommands) : 0 - ); -#endif - - currentPeer->packetLossVariance -= currentPeer->packetLossVariance / 4; - - if (packetLoss >= currentPeer->packetLoss) { - currentPeer->packetLoss += (packetLoss - currentPeer->packetLoss) / 8; - currentPeer->packetLossVariance += (packetLoss - currentPeer->packetLoss) / 4; - } else { - currentPeer->packetLoss -= (currentPeer->packetLoss - packetLoss) / 8; - currentPeer->packetLossVariance += (currentPeer->packetLoss - packetLoss) / 4; - } - - currentPeer->packetLossEpoch = host->serviceTime; - currentPeer->packetsSent = 0; - currentPeer->packetsLost = 0; - } - - host->buffers->data = headerData; - if (host->headerFlags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME) { - header->sentTime = ENET_HOST_TO_NET_16(host->serviceTime & 0xFFFF); - host->buffers->dataLength = sizeof(ENetProtocolHeader); - } else { - host->buffers->dataLength = (size_t) &((ENetProtocolHeader *) 0)->sentTime; - } - - shouldCompress = 0; - if (host->compressor.context != nullptr && host->compressor.compress != nullptr) { - size_t originalSize = host->packetSize - sizeof(ENetProtocolHeader), - compressedSize = host->compressor.compress(host->compressor.context, &host->buffers[1], host->bufferCount - 1, originalSize, host->packetData[1], originalSize); - if (compressedSize > 0 && compressedSize < originalSize) { - host->headerFlags |= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED; - shouldCompress = compressedSize; -#ifdef ENET_DEBUG_COMPRESS - printf("peer %u: compressed %u->%u (%u%%)\n", currentPeer->incomingPeerID, originalSize, compressedSize, (compressedSize * 100) / originalSize); -#endif - } - } - - if (currentPeer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID) { - host->headerFlags |= currentPeer->outgoingSessionID << ENET_PROTOCOL_HEADER_SESSION_SHIFT; - } - header->peerID = ENET_HOST_TO_NET_16(currentPeer->outgoingPeerID | host->headerFlags); - if (host->checksum != nullptr) { - enet_uint32 *checksum = (enet_uint32 *) &headerData[host->buffers->dataLength]; - *checksum = currentPeer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer->connectID : 0; - host->buffers->dataLength += sizeof(enet_uint32); - *checksum = host->checksum(host->buffers, host->bufferCount); - } - - if (shouldCompress > 0) { - host->buffers[1].data = host->packetData[1]; - host->buffers[1].dataLength = shouldCompress; - host->bufferCount = 2; - } - - currentPeer->lastSendTime = host->serviceTime; - sentLength = enet_socket_send(host->socket, ¤tPeer->address, host->buffers, host->bufferCount); - enet_protocol_remove_sent_unreliable_commands(currentPeer); - - if (sentLength < 0) { - return -1; - } - - host->totalSentData += sentLength; - currentPeer->totalDataSent += sentLength; - host->totalSentPackets++; - } - - return 0; -} /* enet_protocol_send_outgoing_commands */ - -/** Sends any queued packets on the host specified to its designated peers. - * - * @param host host to flush - * @remarks this function need only be used in circumstances where one wishes to send queued packets earlier than in a call to enet_host_service(). - * @ingroup host - */ -void enet_host_flush(ENetHost *host) { - host->serviceTime = enet_time_get(); - enet_protocol_send_outgoing_commands(host, nullptr, 0); -} - -/** Checks for any queued events on the host and dispatches one if available. - * - * @param host host to check for events - * @param event an event structure where event details will be placed if available - * @retval > 0 if an event was dispatched - * @retval 0 if no events are available - * @retval < 0 on failure - * @ingroup host - */ -int enet_host_check_events(ENetHost *host, ENetEvent *event) { - if (event == nullptr) { return -1; } - - event->type = ENET_EVENT_TYPE_NONE; - event->peer = nullptr; - event->packet = nullptr; - - return enet_protocol_dispatch_incoming_commands(host, event); -} - -/** Waits for events on the host specified and shuttles packets between - * the host and its peers. - * - * @param host host to service - * @param event an event structure where event details will be placed if one occurs - * if event == nullptr then no events will be delivered - * @param timeout number of milliseconds that ENet should wait for events - * @retval > 0 if an event occurred within the specified time limit - * @retval 0 if no event occurred - * @retval < 0 on failure - * @remarks enet_host_service should be called fairly regularly for adequate performance - * @ingroup host - */ - -int enet_host_service(ENetHost *host, ENetEvent *event, enet_uint32 timeout) { - enet_uint32 waitCondition; - - if (event != nullptr) { - event->type = ENET_EVENT_TYPE_NONE; - event->peer = nullptr; - event->packet = nullptr; - - switch (enet_protocol_dispatch_incoming_commands(host, event)) { - case 1: - return 1; - - case -1: -#ifdef ENET_DEBUG - perror("Error dispatching incoming packets"); -#endif - - return -1; - - default: - break; - } - } - - host->serviceTime = enet_time_get(); - timeout += host->serviceTime; - - do { - if (ENET_TIME_DIFFERENCE(host->serviceTime, host->bandwidthThrottleEpoch) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) { - enet_host_bandwidth_throttle(host); - } - - switch (enet_protocol_send_outgoing_commands(host, event, 1)) { - case 1: - return 1; - - case -1: -#ifdef ENET_DEBUG - perror("Error sending outgoing packets"); -#endif - - return -1; - - default: - break; - } - - switch (enet_protocol_receive_incoming_commands(host, event)) { - case 1: - return 1; - - case -1: -#ifdef ENET_DEBUG - perror("Error receiving incoming packets"); -#endif - - return -1; - - default: - break; - } - - switch (enet_protocol_send_outgoing_commands(host, event, 1)) { - case 1: - return 1; - - case -1: -#ifdef ENET_DEBUG - perror("Error sending outgoing packets"); -#endif - - return -1; - - default: - break; - } - - if (event != nullptr) { - switch (enet_protocol_dispatch_incoming_commands(host, event)) { - case 1: - return 1; - - case -1: -#ifdef ENET_DEBUG - perror("Error dispatching incoming packets"); -#endif - - return -1; - - default: - break; - } - } - - if (ENET_TIME_GREATER_EQUAL(host->serviceTime, timeout)) { - return 0; - } - - do { - host->serviceTime = enet_time_get(); - - if (ENET_TIME_GREATER_EQUAL(host->serviceTime, timeout)) { - return 0; - } - - waitCondition = ENET_SOCKET_WAIT_RECEIVE | ENET_SOCKET_WAIT_INTERRUPT; - if (enet_socket_wait(host->socket, &waitCondition, ENET_TIME_DIFFERENCE(timeout, host->serviceTime)) != 0) { - return -1; - } - } while (waitCondition & ENET_SOCKET_WAIT_INTERRUPT); - - host->serviceTime = enet_time_get(); - } while (waitCondition & ENET_SOCKET_WAIT_RECEIVE); - - return 0; -} /* enet_host_service */ - - -// =======================================================================// -// ! -// ! Peer -// ! -// =======================================================================// - -/** Configures throttle parameter for a peer. - * - * Unreliable packets are dropped by ENet in response to the varying conditions - * of the Internet connection to the peer. The throttle represents a probability - * that an unreliable packet should not be dropped and thus sent by ENet to the peer. - * The lowest mean round trip time from the sending of a reliable packet to the - * receipt of its acknowledgement is measured over an amount of time specified by - * the interval parameter in milliseconds. If a measured round trip time happens to - * be significantly less than the mean round trip time measured over the interval, - * then the throttle probability is increased to allow more traffic by an amount - * specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE - * constant. If a measured round trip time happens to be significantly greater than - * the mean round trip time measured over the interval, then the throttle probability - * is decreased to limit traffic by an amount specified in the deceleration parameter, which - * is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant. When the throttle has - * a value of ENET_PEER_PACKET_THROTTLE_SCALE, no unreliable packets are dropped by - * ENet, and so 100% of all unreliable packets will be sent. When the throttle has a - * value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable - * packets will be sent. Intermediate values for the throttle represent intermediate - * probabilities between 0% and 100% of unreliable packets being sent. The bandwidth - * limits of the local and foreign hosts are taken into account to determine a - * sensible limit for the throttle probability above which it should not raise even in - * the best of conditions. - * - * @param peer peer to configure - * @param interval interval, in milliseconds, over which to measure lowest mean RTT; the default value is ENET_PEER_PACKET_THROTTLE_INTERVAL. - * @param acceleration rate at which to increase the throttle probability as mean RTT declines - * @param deceleration rate at which to decrease the throttle probability as mean RTT increases - */ -void enet_peer_throttle_configure(ENetPeer *peer, enet_uint32 interval, enet_uint32 acceleration, enet_uint32 deceleration) { - ENetProtocol command; - - peer->packetThrottleInterval = interval; - peer->packetThrottleAcceleration = acceleration; - peer->packetThrottleDeceleration = deceleration; - - command.header.command = ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - command.header.channelID = 0xFF; - - command.throttleConfigure.packetThrottleInterval = ENET_HOST_TO_NET_32(interval); - command.throttleConfigure.packetThrottleAcceleration = ENET_HOST_TO_NET_32(acceleration); - command.throttleConfigure.packetThrottleDeceleration = ENET_HOST_TO_NET_32(deceleration); - - enet_peer_queue_outgoing_command(peer, &command, nullptr, 0, 0); -} - -int enet_peer_throttle(ENetPeer *peer, enet_uint32 rtt) { - if (peer->lastRoundTripTime <= peer->lastRoundTripTimeVariance) { - peer->packetThrottle = peer->packetThrottleLimit; - } - else if (rtt < peer->lastRoundTripTime) { - peer->packetThrottle += peer->packetThrottleAcceleration; - - if (peer->packetThrottle > peer->packetThrottleLimit) { - peer->packetThrottle = peer->packetThrottleLimit; - } - - return 1; - } - else if (rtt > peer->lastRoundTripTime + 2 * peer->lastRoundTripTimeVariance) { - if (peer->packetThrottle > peer->packetThrottleDeceleration) { - peer->packetThrottle -= peer->packetThrottleDeceleration; - } else { - peer->packetThrottle = 0; - } - - return -1; - } - - return 0; -} - -/* Extended functionality for easier binding in other programming languages */ -enet_uint32 enet_host_get_peers_count(ENetHost *host) { - return host->connectedPeers; -} - -enet_uint32 enet_host_get_packets_sent(ENetHost *host) { - return host->totalSentPackets; -} - -enet_uint32 enet_host_get_packets_received(ENetHost *host) { - return host->totalReceivedPackets; -} - -enet_uint32 enet_host_get_bytes_sent(ENetHost *host) { - return host->totalSentData; -} - -enet_uint32 enet_host_get_bytes_received(ENetHost *host) { - return host->totalReceivedData; -} - -/** Gets received data buffer. Returns buffer length. - * @param host host to access recevie buffer - * @param data ouput parameter for recevied data - * @retval buffer length - */ -enet_uint32 enet_host_get_received_data(ENetHost *host, /*out*/ enet_uint8** data) { - *data = host->receivedData; - return host->receivedDataLength; -} - -enet_uint32 enet_host_get_mtu(ENetHost *host) { - return host->mtu; -} - -enet_uint32 enet_peer_get_id(ENetPeer *peer) { - return peer->connectID; -} - -enet_uint32 enet_peer_get_ip(ENetPeer *peer, char *ip, size_t ipLength) { - return enet_address_get_host_ip(&peer->address, ip, ipLength); -} - -enet_uint16 enet_peer_get_port(ENetPeer *peer) { - return peer->address.port; -} - -ENetPeerState enet_peer_get_state(ENetPeer *peer) { - return peer->state; -} - -enet_uint32 enet_peer_get_ping(ENetPeer *peer) { - return peer->ping; -} - -enet_uint32 enet_peer_get_rtt(ENetPeer *peer) { - return peer->roundTripTime; -} - -enet_uint64 enet_peer_get_packets_sent(ENetPeer *peer) { - return peer->totalPacketsSent; -} - -enet_uint32 enet_peer_get_packets_lost(ENetPeer *peer) { - return peer->totalPacketsLost; -} - -enet_uint64 enet_peer_get_bytes_sent(ENetPeer *peer) { - return peer->totalDataSent; -} - -enet_uint64 enet_peer_get_bytes_received(ENetPeer *peer) { - return peer->totalDataReceived; -} - -void * enet_peer_get_data(ENetPeer *peer) { - return (void *) peer->data; -} - -void enet_peer_set_data(ENetPeer *peer, const void *data) { - peer->data = (enet_uint32 *) data; -} - -void * enet_packet_get_data(ENetPacket *packet) { - return (void *) packet->data; -} - -enet_uint32 enet_packet_get_length(ENetPacket *packet) { - return packet->dataLength; -} - -void enet_packet_set_free_callback(ENetPacket *packet, void *callback) { - packet->freeCallback = (ENetPacketFreeCallback)callback; -} - -/** Queues a packet to be sent. - * @param peer destination for the packet - * @param channelID channel on which to send - * @param packet packet to send - * @retval 0 on success - * @retval < 0 on failure - */ -int enet_peer_send(ENetPeer *peer, enet_uint8 channelID, ENetPacket *packet) { - ENetChannel *channel = &peer->channels[channelID]; - ENetProtocol command; - size_t fragmentLength; - - if (peer->state != ENET_PEER_STATE_CONNECTED || channelID >= peer->channelCount || packet->dataLength > peer->host->maximumPacketSize) { - return -1; - } - - fragmentLength = peer->mtu - sizeof(ENetProtocolHeader) - sizeof(ENetProtocolSendFragment); - if (peer->host->checksum != nullptr) { - fragmentLength -= sizeof(enet_uint32); - } - - if (packet->dataLength > fragmentLength) { - enet_uint32 fragmentCount = (packet->dataLength + fragmentLength - 1) / fragmentLength, fragmentNumber, fragmentOffset; - enet_uint8 commandNumber; - enet_uint16 startSequenceNumber; - ENetList fragments; - ENetOutgoingCommand *fragment; - - if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) { - return -1; - } - - if ((packet->flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT)) == - ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT && - channel->outgoingUnreliableSequenceNumber < 0xFFFF) - { - commandNumber = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT; - startSequenceNumber = ENET_HOST_TO_NET_16(channel->outgoingUnreliableSequenceNumber + 1); - } else { - commandNumber = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - startSequenceNumber = ENET_HOST_TO_NET_16(channel->outgoingReliableSequenceNumber + 1); - } - - enet_list_clear(&fragments); - - for (fragmentNumber = 0, fragmentOffset = 0; fragmentOffset < packet->dataLength; ++fragmentNumber, fragmentOffset += fragmentLength) { - if (packet->dataLength - fragmentOffset < fragmentLength) { - fragmentLength = packet->dataLength - fragmentOffset; - } - - fragment = (ENetOutgoingCommand *) enet_malloc(sizeof(ENetOutgoingCommand)); - - if (fragment == nullptr) { - while (!enet_list_empty(&fragments)) { - fragment = (ENetOutgoingCommand *) enet_list_remove(enet_list_begin(&fragments)); - - enet_free(fragment); - } - - return -1; - } - - fragment->fragmentOffset = fragmentOffset; - fragment->fragmentLength = fragmentLength; - fragment->packet = packet; - fragment->command.header.command = commandNumber; - fragment->command.header.channelID = channelID; - - fragment->command.sendFragment.startSequenceNumber = startSequenceNumber; - - fragment->command.sendFragment.dataLength = ENET_HOST_TO_NET_16(fragmentLength); - fragment->command.sendFragment.fragmentCount = ENET_HOST_TO_NET_32(fragmentCount); - fragment->command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32(fragmentNumber); - fragment->command.sendFragment.totalLength = ENET_HOST_TO_NET_32(packet->dataLength); - fragment->command.sendFragment.fragmentOffset = ENET_NET_TO_HOST_32(fragmentOffset); - - enet_list_insert(enet_list_end(&fragments), fragment); - } - - packet->referenceCount += fragmentNumber; - - while (!enet_list_empty(&fragments)) { - fragment = (ENetOutgoingCommand *) enet_list_remove(enet_list_begin(&fragments)); - enet_peer_setup_outgoing_command(peer, fragment); - } - - return 0; - } - - command.header.channelID = channelID; - - if ((packet->flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNSEQUENCED)) == ENET_PACKET_FLAG_UNSEQUENCED) { - command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; - command.sendUnsequenced.dataLength = ENET_HOST_TO_NET_16(packet->dataLength); - } - else if (packet->flags & ENET_PACKET_FLAG_RELIABLE || channel->outgoingUnreliableSequenceNumber >= 0xFFFF) { - command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - command.sendReliable.dataLength = ENET_HOST_TO_NET_16(packet->dataLength); - } - else { - command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE; - command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16(packet->dataLength); - } - - if (enet_peer_queue_outgoing_command(peer, &command, packet, 0, packet->dataLength) == nullptr) { - return -1; - } - - return 0; -} // enet_peer_send - -/** Attempts to dequeue any incoming queued packet. - * @param peer peer to dequeue packets from - * @param channelID holds the channel ID of the channel the packet was received on success - * @returns a pointer to the packet, or nullptr if there are no available incoming queued packets - */ -ENetPacket * enet_peer_receive(ENetPeer *peer, enet_uint8 *channelID) { - ENetIncomingCommand *incomingCommand; - ENetPacket *packet; - - incomingCommand = (ENetIncomingCommand *)enet_list_remove(enet_list_begin(&peer->dispatchedCommands)); - - if (channelID != nullptr) { - *channelID = incomingCommand->command.header.channelID; - } - - packet = incomingCommand->packet; - --packet->referenceCount; - - if (incomingCommand->fragments != nullptr) { - enet_free(incomingCommand->fragments); - } - - enet_free(incomingCommand); - peer->totalWaitingData -= packet->dataLength; - - return packet; -} - -static void enet_peer_reset_outgoing_commands(ENetList *queue) { - ENetOutgoingCommand *outgoingCommand; - - while (!enet_list_empty(queue)) { - outgoingCommand = (ENetOutgoingCommand *) enet_list_remove(enet_list_begin(queue)); - - if (outgoingCommand->packet != nullptr) { - --outgoingCommand->packet->referenceCount; - - if (outgoingCommand->packet->referenceCount == 0) { - enet_packet_destroy(outgoingCommand->packet); - } - } - - enet_free(outgoingCommand); - } -} - -static void enet_peer_remove_incoming_commands(ENetList *queue, ENetListIterator startCommand, ENetListIterator endCommand) { - ENetListIterator currentCommand; - - for (currentCommand = startCommand; currentCommand != endCommand;) { - ENetIncomingCommand *incomingCommand = (ENetIncomingCommand *) currentCommand; - - currentCommand = enet_list_next(currentCommand); - enet_list_remove(&incomingCommand->incomingCommandList); - - if (incomingCommand->packet != nullptr) { - --incomingCommand->packet->referenceCount; - - if (incomingCommand->packet->referenceCount == 0) { - enet_packet_destroy(incomingCommand->packet); - } - } - - if (incomingCommand->fragments != nullptr) { - enet_free(incomingCommand->fragments); - } - - enet_free(incomingCommand); - } -} - -static void enet_peer_reset_incoming_commands(ENetList *queue) { - enet_peer_remove_incoming_commands(queue, enet_list_begin(queue), enet_list_end(queue)); -} - -void enet_peer_reset_queues(ENetPeer *peer) { - ENetChannel *channel; - - if (peer->needsDispatch) { - enet_list_remove(&peer->dispatchList); - peer->needsDispatch = 0; - } - - while (!enet_list_empty(&peer->acknowledgements)) { - enet_free(enet_list_remove(enet_list_begin(&peer->acknowledgements))); - } - - enet_peer_reset_outgoing_commands(&peer->sentReliableCommands); - enet_peer_reset_outgoing_commands(&peer->sentUnreliableCommands); - enet_peer_reset_outgoing_commands(&peer->outgoingReliableCommands); - enet_peer_reset_outgoing_commands(&peer->outgoingUnreliableCommands); - enet_peer_reset_incoming_commands(&peer->dispatchedCommands); - - if (peer->channels != nullptr && peer->channelCount > 0) { - for (channel = peer->channels; channel < &peer->channels[peer->channelCount]; ++channel) { - enet_peer_reset_incoming_commands(&channel->incomingReliableCommands); - enet_peer_reset_incoming_commands(&channel->incomingUnreliableCommands); - } - - enet_free(peer->channels); - } - - peer->channels = nullptr; - peer->channelCount = 0; -} - -void enet_peer_on_connect(ENetPeer *peer) { - if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { - if (peer->incomingBandwidth != 0) { - ++peer->host->bandwidthLimitedPeers; - } - - ++peer->host->connectedPeers; - } -} - -void enet_peer_on_disconnect(ENetPeer *peer) { - if (peer->state == ENET_PEER_STATE_CONNECTED || peer->state == ENET_PEER_STATE_DISCONNECT_LATER) { - if (peer->incomingBandwidth != 0) { - --peer->host->bandwidthLimitedPeers; - } - - --peer->host->connectedPeers; - } -} - -/** Forcefully disconnects a peer. - * @param peer peer to forcefully disconnect - * @remarks The foreign host represented by the peer is not notified of the disconnection and will timeout - * on its connection to the local host. - */ -void enet_peer_reset(ENetPeer *peer) { - enet_peer_on_disconnect(peer); - - // We don't want to reset connectID here, otherwise, we can't get it in the Disconnect event - // peer->connectID = 0; - peer->outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID; - peer->state = ENET_PEER_STATE_DISCONNECTED; - peer->incomingBandwidth = 0; - peer->outgoingBandwidth = 0; - peer->incomingBandwidthThrottleEpoch = 0; - peer->outgoingBandwidthThrottleEpoch = 0; - peer->incomingDataTotal = 0; - peer->totalDataReceived = 0; - peer->outgoingDataTotal = 0; - peer->totalDataSent = 0; - peer->lastSendTime = 0; - peer->lastReceiveTime = 0; - peer->nextTimeout = 0; - peer->earliestTimeout = 0; - peer->packetLossEpoch = 0; - peer->packetsSent = 0; - peer->totalPacketsSent = 0; - peer->packetsLost = 0; - peer->totalPacketsLost = 0; - peer->packetLoss = 0; - peer->packetLossVariance = 0; - peer->packetThrottle = ENET_PEER_DEFAULT_PACKET_THROTTLE; - peer->packetThrottleLimit = ENET_PEER_PACKET_THROTTLE_SCALE; - peer->packetThrottleCounter = 0; - peer->packetThrottleEpoch = 0; - peer->packetThrottleAcceleration = ENET_PEER_PACKET_THROTTLE_ACCELERATION; - peer->packetThrottleDeceleration = ENET_PEER_PACKET_THROTTLE_DECELERATION; - peer->packetThrottleInterval = ENET_PEER_PACKET_THROTTLE_INTERVAL; - peer->pingInterval = ENET_PEER_PING_INTERVAL; - peer->timeoutLimit = ENET_PEER_TIMEOUT_LIMIT; - peer->timeoutMinimum = ENET_PEER_TIMEOUT_MINIMUM; - peer->timeoutMaximum = ENET_PEER_TIMEOUT_MAXIMUM; - peer->lastRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; - peer->ping = 0; - peer->lowestRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; - peer->lastRoundTripTimeVariance = 0; - peer->highestRoundTripTimeVariance = 0; - peer->roundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; - peer->roundTripTimeVariance = 0; - peer->mtu = peer->host->mtu; - peer->reliableDataInTransit = 0; - peer->outgoingReliableSequenceNumber = 0; - peer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - peer->incomingUnsequencedGroup = 0; - peer->outgoingUnsequencedGroup = 0; - peer->eventData = 0; - peer->totalWaitingData = 0; - - memset(peer->unsequencedWindow, 0, sizeof(peer->unsequencedWindow)); - enet_peer_reset_queues(peer); -} - -/** Sends a ping request to a peer. - * @param peer destination for the ping request - * @remarks ping requests factor into the mean round trip time as designated by the - * roundTripTime field in the ENetPeer structure. ENet automatically pings all connected - * peers at regular intervals, however, this function may be called to ensure more - * frequent ping requests. - */ -void enet_peer_ping(ENetPeer *peer) { - ENetProtocol command; - - if (peer->state != ENET_PEER_STATE_CONNECTED) { - return; - } - - command.header.command = ENET_PROTOCOL_COMMAND_PING | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - command.header.channelID = 0xFF; - - enet_peer_queue_outgoing_command(peer, &command, nullptr, 0, 0); -} - -/** Sets the interval at which pings will be sent to a peer. - * - * Pings are used both to monitor the liveness of the connection and also to dynamically - * adjust the throttle during periods of low traffic so that the throttle has reasonable - * responsiveness during traffic spikes. - * - * @param peer the peer to adjust - * @param pingInterval the interval at which to send pings; defaults to ENET_PEER_PING_INTERVAL if 0 - */ -void enet_peer_ping_interval(ENetPeer *peer, enet_uint32 pingInterval) { - peer->pingInterval = pingInterval ? pingInterval : ENET_PEER_PING_INTERVAL; -} - -/** Sets the timeout parameters for a peer. - * - * The timeout parameter control how and when a peer will timeout from a failure to acknowledge - * reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable - * packet is not acknowledge within some multiple of the average RTT plus a variance tolerance, - * the timeout will be doubled until it reaches a set limit. If the timeout is thus at this - * limit and reliable packets have been sent but not acknowledged within a certain minimum time - * period, the peer will be disconnected. Alternatively, if reliable packets have been sent - * but not acknowledged for a certain maximum time period, the peer will be disconnected regardless - * of the current timeout limit value. - * - * @param peer the peer to adjust - * @param timeoutLimit the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0 - * @param timeoutMinimum the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0 - * @param timeoutMaximum the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0 - */ - -void enet_peer_timeout(ENetPeer *peer, enet_uint32 timeoutLimit, enet_uint32 timeoutMinimum, enet_uint32 timeoutMaximum) { - peer->timeoutLimit = timeoutLimit ? timeoutLimit : ENET_PEER_TIMEOUT_LIMIT; - peer->timeoutMinimum = timeoutMinimum ? timeoutMinimum : ENET_PEER_TIMEOUT_MINIMUM; - peer->timeoutMaximum = timeoutMaximum ? timeoutMaximum : ENET_PEER_TIMEOUT_MAXIMUM; -} - -/** Force an immediate disconnection from a peer. - * @param peer peer to disconnect - * @param data data describing the disconnection - * @remarks No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not - * guaranteed to receive the disconnect notification, and is reset immediately upon - * return from this function. - */ -void enet_peer_disconnect_now(ENetPeer *peer, enet_uint32 data) { - ENetProtocol command; - - if (peer->state == ENET_PEER_STATE_DISCONNECTED) { - return; - } - - if (peer->state != ENET_PEER_STATE_ZOMBIE && peer->state != ENET_PEER_STATE_DISCONNECTING) { - enet_peer_reset_queues(peer); - - command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; - command.header.channelID = 0xFF; - command.disconnect.data = ENET_HOST_TO_NET_32(data); - - enet_peer_queue_outgoing_command(peer, &command, nullptr, 0, 0); - enet_host_flush(peer->host); - } - - enet_peer_reset(peer); -} - -/** Request a disconnection from a peer. - * @param peer peer to request a disconnection - * @param data data describing the disconnection - * @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() - * once the disconnection is complete. - */ -void enet_peer_disconnect(ENetPeer *peer, enet_uint32 data) { - ENetProtocol command; - - if (peer->state == ENET_PEER_STATE_DISCONNECTING || - peer->state == ENET_PEER_STATE_DISCONNECTED || - peer->state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT || - peer->state == ENET_PEER_STATE_ZOMBIE - ) { - return; - } - - enet_peer_reset_queues(peer); - - command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT; - command.header.channelID = 0xFF; - command.disconnect.data = ENET_HOST_TO_NET_32(data); - - if (peer->state == ENET_PEER_STATE_CONNECTED || peer->state == ENET_PEER_STATE_DISCONNECT_LATER) { - command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - } else { - command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; - } - - enet_peer_queue_outgoing_command(peer, &command, nullptr, 0, 0); - - if (peer->state == ENET_PEER_STATE_CONNECTED || peer->state == ENET_PEER_STATE_DISCONNECT_LATER) { - enet_peer_on_disconnect(peer); - - peer->state = ENET_PEER_STATE_DISCONNECTING; - } else { - enet_host_flush(peer->host); - enet_peer_reset(peer); - } -} - -/** Request a disconnection from a peer, but only after all queued outgoing packets are sent. - * @param peer peer to request a disconnection - * @param data data describing the disconnection - * @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() - * once the disconnection is complete. - */ -void enet_peer_disconnect_later(ENetPeer *peer, enet_uint32 data) { - if ((peer->state == ENET_PEER_STATE_CONNECTED || peer->state == ENET_PEER_STATE_DISCONNECT_LATER) && - !(enet_list_empty(&peer->outgoingReliableCommands) && - enet_list_empty(&peer->outgoingUnreliableCommands) && - enet_list_empty(&peer->sentReliableCommands)) - ) { - peer->state = ENET_PEER_STATE_DISCONNECT_LATER; - peer->eventData = data; - } else { - enet_peer_disconnect(peer, data); - } -} - -ENetAcknowledgement *enet_peer_queue_acknowledgement(ENetPeer *peer, const ENetProtocol *command, enet_uint16 sentTime) { - ENetAcknowledgement *acknowledgement; - - if (command->header.channelID < peer->channelCount) { - ENetChannel *channel = &peer->channels[command->header.channelID]; - enet_uint16 reliableWindow = command->header.reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - enet_uint16 currentWindow = channel->incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - - if (command->header.reliableSequenceNumber < channel->incomingReliableSequenceNumber) { - reliableWindow += ENET_PEER_RELIABLE_WINDOWS; - } - - if (reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1 && reliableWindow <= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS) { - return nullptr; - } - } - - acknowledgement = (ENetAcknowledgement *) enet_malloc(sizeof(ENetAcknowledgement)); - if (acknowledgement == nullptr) { - return nullptr; - } - - peer->outgoingDataTotal += sizeof(ENetProtocolAcknowledge); - - acknowledgement->sentTime = sentTime; - acknowledgement->command = *command; - - enet_list_insert(enet_list_end(&peer->acknowledgements), acknowledgement); - return acknowledgement; -} - -void enet_peer_setup_outgoing_command(ENetPeer *peer, ENetOutgoingCommand *outgoingCommand) { - ENetChannel *channel = &peer->channels[outgoingCommand->command.header.channelID]; - peer->outgoingDataTotal += enet_protocol_command_size(outgoingCommand->command.header.command) + outgoingCommand->fragmentLength; - - if (outgoingCommand->command.header.channelID == 0xFF) { - ++peer->outgoingReliableSequenceNumber; - - outgoingCommand->reliableSequenceNumber = peer->outgoingReliableSequenceNumber; - outgoingCommand->unreliableSequenceNumber = 0; - } - else if (outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) { - ++channel->outgoingReliableSequenceNumber; - channel->outgoingUnreliableSequenceNumber = 0; - - outgoingCommand->reliableSequenceNumber = channel->outgoingReliableSequenceNumber; - outgoingCommand->unreliableSequenceNumber = 0; - } - else if (outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED) { - ++peer->outgoingUnsequencedGroup; - - outgoingCommand->reliableSequenceNumber = 0; - outgoingCommand->unreliableSequenceNumber = 0; - } - else { - if (outgoingCommand->fragmentOffset == 0) { - ++channel->outgoingUnreliableSequenceNumber; - } - - outgoingCommand->reliableSequenceNumber = channel->outgoingReliableSequenceNumber; - outgoingCommand->unreliableSequenceNumber = channel->outgoingUnreliableSequenceNumber; - } - - outgoingCommand->sendAttempts = 0; - outgoingCommand->sentTime = 0; - outgoingCommand->roundTripTimeout = 0; - outgoingCommand->roundTripTimeoutLimit = 0; - outgoingCommand->command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16(outgoingCommand->reliableSequenceNumber); - - switch (outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK) { - case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: - outgoingCommand->command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16(outgoingCommand->unreliableSequenceNumber); - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: - outgoingCommand->command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16(peer->outgoingUnsequencedGroup); - break; - - default: - break; - } - - if (outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) { - enet_list_insert(enet_list_end(&peer->outgoingReliableCommands), outgoingCommand); - } else { - enet_list_insert(enet_list_end(&peer->outgoingUnreliableCommands), outgoingCommand); - } -} - -ENetOutgoingCommand * enet_peer_queue_outgoing_command(ENetPeer *peer, const ENetProtocol *command, ENetPacket *packet, enet_uint32 offset, enet_uint16 length) { - ENetOutgoingCommand *outgoingCommand = (ENetOutgoingCommand *) enet_malloc(sizeof(ENetOutgoingCommand)); - - if (outgoingCommand == nullptr) { - return nullptr; - } - - outgoingCommand->command = *command; - outgoingCommand->fragmentOffset = offset; - outgoingCommand->fragmentLength = length; - outgoingCommand->packet = packet; - if (packet != nullptr) { - ++packet->referenceCount; - } - - enet_peer_setup_outgoing_command(peer, outgoingCommand); - return outgoingCommand; -} - -void enet_peer_dispatch_incoming_unreliable_commands(ENetPeer *peer, ENetChannel *channel) { - ENetListIterator droppedCommand, startCommand, currentCommand; - - for (droppedCommand = startCommand = currentCommand = enet_list_begin(&channel->incomingUnreliableCommands); - currentCommand != enet_list_end(&channel->incomingUnreliableCommands); - currentCommand = enet_list_next(currentCommand) - ) { - ENetIncomingCommand *incomingCommand = (ENetIncomingCommand *) currentCommand; - - if ((incomingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) { - continue; - } - - if (incomingCommand->reliableSequenceNumber == channel->incomingReliableSequenceNumber) { - if (incomingCommand->fragmentsRemaining <= 0) { - channel->incomingUnreliableSequenceNumber = incomingCommand->unreliableSequenceNumber; - continue; - } - - if (startCommand != currentCommand) { - enet_list_move(enet_list_end(&peer->dispatchedCommands), startCommand, enet_list_previous(currentCommand)); - - if (!peer->needsDispatch) { - enet_list_insert(enet_list_end(&peer->host->dispatchQueue), &peer->dispatchList); - peer->needsDispatch = 1; - } - - droppedCommand = currentCommand; - } else if (droppedCommand != currentCommand) { - droppedCommand = enet_list_previous(currentCommand); - } - } else { - enet_uint16 reliableWindow = incomingCommand->reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - enet_uint16 currentWindow = channel->incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - - if (incomingCommand->reliableSequenceNumber < channel->incomingReliableSequenceNumber) { - reliableWindow += ENET_PEER_RELIABLE_WINDOWS; - } - - if (reliableWindow >= currentWindow && reliableWindow < currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) { - break; - } - - droppedCommand = enet_list_next(currentCommand); - - if (startCommand != currentCommand) { - enet_list_move(enet_list_end(&peer->dispatchedCommands), startCommand, enet_list_previous(currentCommand)); - - if (!peer->needsDispatch) { - enet_list_insert(enet_list_end(&peer->host->dispatchQueue), &peer->dispatchList); - peer->needsDispatch = 1; - } - } - } - - startCommand = enet_list_next(currentCommand); - } - - if (startCommand != currentCommand) { - enet_list_move(enet_list_end(&peer->dispatchedCommands), startCommand, enet_list_previous(currentCommand)); - - if (!peer->needsDispatch) { - enet_list_insert(enet_list_end(&peer->host->dispatchQueue), &peer->dispatchList); - peer->needsDispatch = 1; - } - - droppedCommand = currentCommand; - } - - enet_peer_remove_incoming_commands(&channel->incomingUnreliableCommands,enet_list_begin(&channel->incomingUnreliableCommands), droppedCommand); -} - -void enet_peer_dispatch_incoming_reliable_commands(ENetPeer *peer, ENetChannel *channel) { - ENetListIterator currentCommand; - - for (currentCommand = enet_list_begin(&channel->incomingReliableCommands); - currentCommand != enet_list_end(&channel->incomingReliableCommands); - currentCommand = enet_list_next(currentCommand) - ) { - ENetIncomingCommand *incomingCommand = (ENetIncomingCommand *) currentCommand; - - if (incomingCommand->fragmentsRemaining > 0 || incomingCommand->reliableSequenceNumber != (enet_uint16) (channel->incomingReliableSequenceNumber + 1)) { - break; - } - - channel->incomingReliableSequenceNumber = incomingCommand->reliableSequenceNumber; - - if (incomingCommand->fragmentCount > 0) { - channel->incomingReliableSequenceNumber += incomingCommand->fragmentCount - 1; - } - } - - if (currentCommand == enet_list_begin(&channel->incomingReliableCommands)) { - return; - } - - channel->incomingUnreliableSequenceNumber = 0; - enet_list_move(enet_list_end(&peer->dispatchedCommands), enet_list_begin(&channel->incomingReliableCommands), enet_list_previous(currentCommand)); - - if (!peer->needsDispatch) { - enet_list_insert(enet_list_end(&peer->host->dispatchQueue), &peer->dispatchList); - peer->needsDispatch = 1; - } - - if (!enet_list_empty(&channel->incomingUnreliableCommands)) { - enet_peer_dispatch_incoming_unreliable_commands(peer, channel); - } -} - -ENetIncomingCommand * enet_peer_queue_incoming_command(ENetPeer *peer, const ENetProtocol *command, const void *data, size_t dataLength, enet_uint32 flags, enet_uint32 fragmentCount) { - static ENetIncomingCommand dummyCommand; - - ENetChannel *channel = &peer->channels[command->header.channelID]; - enet_uint32 unreliableSequenceNumber = 0, reliableSequenceNumber = 0; - enet_uint16 reliableWindow, currentWindow; - ENetIncomingCommand *incomingCommand; - ENetListIterator currentCommand; - ENetPacket *packet = nullptr; - - if (peer->state == ENET_PEER_STATE_DISCONNECT_LATER) { - goto discardCommand; - } - - if ((command->header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) { - reliableSequenceNumber = command->header.reliableSequenceNumber; - reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - currentWindow = channel->incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; - - if (reliableSequenceNumber < channel->incomingReliableSequenceNumber) { - reliableWindow += ENET_PEER_RELIABLE_WINDOWS; - } - - if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) { - goto discardCommand; - } - } - - switch (command->header.command & ENET_PROTOCOL_COMMAND_MASK) { - case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: - case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: - if (reliableSequenceNumber == channel->incomingReliableSequenceNumber) { - goto discardCommand; - } - - for (currentCommand = enet_list_previous(enet_list_end(&channel->incomingReliableCommands)); - currentCommand != enet_list_end(&channel->incomingReliableCommands); - currentCommand = enet_list_previous(currentCommand) - ) { - incomingCommand = (ENetIncomingCommand *) currentCommand; - - if (reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { - if (incomingCommand->reliableSequenceNumber < channel->incomingReliableSequenceNumber) { - continue; - } - } else if (incomingCommand->reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { - break; - } - - if (incomingCommand->reliableSequenceNumber <= reliableSequenceNumber) { - if (incomingCommand->reliableSequenceNumber < reliableSequenceNumber) { - break; - } - - goto discardCommand; - } - } - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: - case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT: - unreliableSequenceNumber = ENET_NET_TO_HOST_16(command->sendUnreliable.unreliableSequenceNumber); - - if (reliableSequenceNumber == channel->incomingReliableSequenceNumber && unreliableSequenceNumber <= channel->incomingUnreliableSequenceNumber) { - goto discardCommand; - } - - for (currentCommand = enet_list_previous(enet_list_end(&channel->incomingUnreliableCommands)); - currentCommand != enet_list_end(&channel->incomingUnreliableCommands); - currentCommand = enet_list_previous(currentCommand) - ) { - incomingCommand = (ENetIncomingCommand *) currentCommand; - - if ((command->header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) { - continue; - } - - if (reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { - if (incomingCommand->reliableSequenceNumber < channel->incomingReliableSequenceNumber) { - continue; - } - } else if (incomingCommand->reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { - break; - } - - if (incomingCommand->reliableSequenceNumber < reliableSequenceNumber) { - break; - } - - if (incomingCommand->reliableSequenceNumber > reliableSequenceNumber) { - continue; - } - - if (incomingCommand->unreliableSequenceNumber <= unreliableSequenceNumber) { - if (incomingCommand->unreliableSequenceNumber < unreliableSequenceNumber) { - break; - } - - goto discardCommand; - } - } - break; - - case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: - currentCommand = enet_list_end(&channel->incomingUnreliableCommands); - break; - - default: - goto discardCommand; - } - - if (peer->totalWaitingData >= peer->host->maximumWaitingData) { - goto notifyError; - } - - packet = enet_packet_create(data, dataLength, flags); - if (packet == nullptr) { - goto notifyError; - } - - incomingCommand = (ENetIncomingCommand *) enet_malloc(sizeof(ENetIncomingCommand)); - if (incomingCommand == nullptr) { - goto notifyError; - } - - incomingCommand->reliableSequenceNumber = command->header.reliableSequenceNumber; - incomingCommand->unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; - incomingCommand->command = *command; - incomingCommand->fragmentCount = fragmentCount; - incomingCommand->fragmentsRemaining = fragmentCount; - incomingCommand->packet = packet; - incomingCommand->fragments = nullptr; - - if (fragmentCount > 0) { - if (fragmentCount <= ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) { - incomingCommand->fragments = (enet_uint32 *) enet_malloc((fragmentCount + 31) / 32 * sizeof(enet_uint32)); - } - - if (incomingCommand->fragments == nullptr) { - enet_free(incomingCommand); - - goto notifyError; - } - - memset(incomingCommand->fragments, 0, (fragmentCount + 31) / 32 * sizeof(enet_uint32)); - } - - if (packet != nullptr) { - ++packet->referenceCount; - peer->totalWaitingData += packet->dataLength; - } - - enet_list_insert(enet_list_next(currentCommand), incomingCommand); - - switch (command->header.command & ENET_PROTOCOL_COMMAND_MASK) { - case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: - case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: - enet_peer_dispatch_incoming_reliable_commands(peer, channel); - break; - - default: - enet_peer_dispatch_incoming_unreliable_commands(peer, channel); - break; - } - - return incomingCommand; - - discardCommand: - if (fragmentCount > 0) { - goto notifyError; - } - - if (packet != nullptr && packet->referenceCount == 0) { - enet_packet_destroy(packet); - } - - return &dummyCommand; - - notifyError: - if (packet != nullptr && packet->referenceCount == 0) { - enet_packet_destroy(packet); - } - - return nullptr; -} /* enet_peer_queue_incoming_command */ - -// =======================================================================// -// ! -// ! Host -// ! -// =======================================================================// - -/** Creates a host for communicating to peers. - * - * @param address the address at which other peers may connect to this host. If nullptr, then no peers may connect to the host. - * @param peerCount the maximum number of peers that should be allocated for the host. - * @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT - * @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. - * @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. - * - * @returns the host on success and nullptr on failure - * - * @remarks ENet will strategically drop packets on specific sides of a connection between hosts - * to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine - * the window size of a connection which limits the amount of reliable packets that may be in transit - * at any given time. - */ -ENetHost * enet_host_create(const ENetAddress *address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) { - ENetHost *host; - ENetPeer *currentPeer; - - if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID) { - return nullptr; - } - - host = (ENetHost *) enet_malloc(sizeof(ENetHost)); - if (host == nullptr) { return nullptr; } - memset(host, 0, sizeof(ENetHost)); - - host->peers = (ENetPeer *) enet_malloc(peerCount * sizeof(ENetPeer)); - if (host->peers == nullptr) { - enet_free(host); - return nullptr; - } - - memset(host->peers, 0, peerCount * sizeof(ENetPeer)); - - host->socket = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM); - if (host->socket != ENET_SOCKET_NULL) { - enet_socket_set_option (host->socket, ENET_SOCKOPT_IPV6_V6ONLY, 0); - } - - if (host->socket == ENET_SOCKET_NULL || (address != nullptr && enet_socket_bind(host->socket, address) < 0)) { - if (host->socket != ENET_SOCKET_NULL) { - enet_socket_destroy(host->socket); - } - - enet_free(host->peers); - enet_free(host); - - return nullptr; - } - - enet_socket_set_option(host->socket, ENET_SOCKOPT_NONBLOCK, 1); - enet_socket_set_option(host->socket, ENET_SOCKOPT_BROADCAST, 1); - enet_socket_set_option(host->socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE); - enet_socket_set_option(host->socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE); - enet_socket_set_option(host->socket, ENET_SOCKOPT_IPV6_V6ONLY, 0); - - if (address != nullptr && enet_socket_get_address(host->socket, &host->address) < 0) { - host->address = *address; - } - - if (!channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) { - channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; - } else if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) { - channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; - } - - host->randomSeed = (enet_uint32) (size_t) host; - host->randomSeed += enet_host_random_seed(); - host->randomSeed = (host->randomSeed << 16) | (host->randomSeed >> 16); - host->channelLimit = channelLimit; - host->incomingBandwidth = incomingBandwidth; - host->outgoingBandwidth = outgoingBandwidth; - host->bandwidthThrottleEpoch = 0; - host->recalculateBandwidthLimits = 0; - host->mtu = ENET_HOST_DEFAULT_MTU; - host->peerCount = peerCount; - host->commandCount = 0; - host->bufferCount = 0; - host->checksum = nullptr; - host->receivedAddress.host = ENET_HOST_ANY; - host->receivedAddress.port = 0; - host->receivedData = nullptr; - host->receivedDataLength = 0; - host->totalSentData = 0; - host->totalSentPackets = 0; - host->totalReceivedData = 0; - host->totalReceivedPackets = 0; - host->connectedPeers = 0; - host->bandwidthLimitedPeers = 0; - host->duplicatePeers = ENET_PROTOCOL_MAXIMUM_PEER_ID; - host->maximumPacketSize = ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE; - host->maximumWaitingData = ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA; - host->compressor.context = nullptr; - host->compressor.compress = nullptr; - host->compressor.decompress = nullptr; - host->compressor.destroy = nullptr; - host->intercept = nullptr; - - enet_list_clear(&host->dispatchQueue); - - for (currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { - currentPeer->host = host; - currentPeer->incomingPeerID = currentPeer - host->peers; - currentPeer->outgoingSessionID = currentPeer->incomingSessionID = 0xFF; - currentPeer->data = nullptr; - - enet_list_clear(¤tPeer->acknowledgements); - enet_list_clear(¤tPeer->sentReliableCommands); - enet_list_clear(¤tPeer->sentUnreliableCommands); - enet_list_clear(¤tPeer->outgoingReliableCommands); - enet_list_clear(¤tPeer->outgoingUnreliableCommands); - enet_list_clear(¤tPeer->dispatchedCommands); - - enet_peer_reset(currentPeer); - } - - return host; -} /* enet_host_create */ - -/** Destroys the host and all resources associated with it. - * @param host pointer to the host to destroy - */ -void enet_host_destroy(ENetHost *host) { - ENetPeer *currentPeer; - - if (host == nullptr) { - return; - } - - enet_socket_destroy(host->socket); - - for (currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { - enet_peer_reset(currentPeer); - } - - if (host->compressor.context != nullptr && host->compressor.destroy) { - (*host->compressor.destroy)(host->compressor.context); - } - - enet_free(host->peers); - enet_free(host); -} - -/** Initiates a connection to a foreign host. - * @param host host seeking the connection - * @param address destination for the connection - * @param channelCount number of channels to allocate - * @param data user data supplied to the receiving host - * @returns a peer representing the foreign host on success, nullptr on failure - * @remarks The peer returned will have not completed the connection until enet_host_service() - * notifies of an ENET_EVENT_TYPE_CONNECT event for the peer. - */ -ENetPeer * enet_host_connect(ENetHost *host, const ENetAddress *address, size_t channelCount, enet_uint32 data) { - ENetPeer *currentPeer; - ENetChannel *channel; - ENetProtocol command; - - if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) { - channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; - } else if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) { - channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; - } - - for (currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { - if (currentPeer->state == ENET_PEER_STATE_DISCONNECTED) { - break; - } - } - - if (currentPeer >= &host->peers[host->peerCount]) { - return nullptr; - } - - currentPeer->channels = (ENetChannel *) enet_malloc(channelCount * sizeof(ENetChannel)); - if (currentPeer->channels == nullptr) { - return nullptr; - } - - currentPeer->channelCount = channelCount; - currentPeer->state = ENET_PEER_STATE_CONNECTING; - currentPeer->address = *address; - currentPeer->connectID = ++host->randomSeed; - - if (host->outgoingBandwidth == 0) { - currentPeer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - } else { - currentPeer->windowSize = (host->outgoingBandwidth / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - } - - if (currentPeer->windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) { - currentPeer->windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; - } else if (currentPeer->windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) { - currentPeer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - } - - for (channel = currentPeer->channels; channel < ¤tPeer->channels[channelCount]; ++channel) { - channel->outgoingReliableSequenceNumber = 0; - channel->outgoingUnreliableSequenceNumber = 0; - channel->incomingReliableSequenceNumber = 0; - channel->incomingUnreliableSequenceNumber = 0; - - enet_list_clear(&channel->incomingReliableCommands); - enet_list_clear(&channel->incomingUnreliableCommands); - - channel->usedReliableWindows = 0; - memset(channel->reliableWindows, 0, sizeof(channel->reliableWindows)); - } - - command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - command.header.channelID = 0xFF; - command.connect.outgoingPeerID = ENET_HOST_TO_NET_16(currentPeer->incomingPeerID); - command.connect.incomingSessionID = currentPeer->incomingSessionID; - command.connect.outgoingSessionID = currentPeer->outgoingSessionID; - command.connect.mtu = ENET_HOST_TO_NET_32(currentPeer->mtu); - command.connect.windowSize = ENET_HOST_TO_NET_32(currentPeer->windowSize); - command.connect.channelCount = ENET_HOST_TO_NET_32(channelCount); - command.connect.incomingBandwidth = ENET_HOST_TO_NET_32(host->incomingBandwidth); - command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32(host->outgoingBandwidth); - command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32(currentPeer->packetThrottleInterval); - command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32(currentPeer->packetThrottleAcceleration); - command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32(currentPeer->packetThrottleDeceleration); - command.connect.connectID = currentPeer->connectID; - command.connect.data = ENET_HOST_TO_NET_32(data); - - enet_peer_queue_outgoing_command(currentPeer, &command, nullptr, 0, 0); - - return currentPeer; -} /* enet_host_connect */ - -/** Queues a packet to be sent to all peers associated with the host. - * @param host host on which to broadcast the packet - * @param channelID channel on which to broadcast - * @param packet packet to broadcast - */ -void enet_host_broadcast(ENetHost *host, enet_uint8 channelID, ENetPacket *packet) { - ENetPeer *currentPeer; - - for (currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { - if (currentPeer->state != ENET_PEER_STATE_CONNECTED) { - continue; - } - - enet_peer_send(currentPeer, channelID, packet); - } - - if (packet->referenceCount == 0) { - enet_packet_destroy(packet); - } -} - -/** Sends raw data to specified address. Useful when you want to send unconnected data using host's socket. - * @param host host sending data - * @param address destination address - * @param data data pointer - * @param dataLength length of data to send - * @retval >=0 bytes sent - * @retval <0 error - * @sa enet_socket_send - */ -int enet_host_send_raw(ENetHost *host, const ENetAddress* address, enet_uint8* data, size_t dataLength) { - ENetBuffer buffer; - buffer.data = data; - buffer.dataLength = dataLength; - return enet_socket_send(host->socket, address, &buffer, 1); -} - -/** Sends raw data to specified address with extended arguments. Allows to send only part of data, handy for other programming languages. - * I.e. if you have data =- { 0, 1, 2, 3 } and call function as enet_host_send_raw_ex(data, 1, 2) then it will skip 1 byte and send 2 bytes { 1, 2 }. - * @param host host sending data - * @param address destination address - * @param data data pointer - * @param skipBytes number of bytes to skip from start of data - * @param bytesToSend number of bytes to send - * @retval >=0 bytes sent - * @retval <0 error - * @sa enet_socket_send - */ -int enet_host_send_raw_ex(ENetHost *host, const ENetAddress* address, enet_uint8* data, size_t skipBytes, size_t bytesToSend) { - ENetBuffer buffer; - buffer.data = data + skipBytes; - buffer.dataLength = bytesToSend; - return enet_socket_send(host->socket, address, &buffer, 1); -} - -/** Sets intercept callback for the host. - * @param host host to set a callback - * @param callback intercept callback - */ -void enet_host_set_intercept(ENetHost *host, const ENetInterceptCallback callback) { - host->intercept = callback; -} - -/** Sets the packet compressor the host should use to compress and decompress packets. - * @param host host to enable or disable compression for - * @param compressor callbacks for for the packet compressor; if nullptr, then compression is disabled - */ -void enet_host_compress(ENetHost *host, const ENetCompressor *compressor) { - if (host->compressor.context != nullptr && host->compressor.destroy) { - (*host->compressor.destroy)(host->compressor.context); - } - - if (compressor) { - host->compressor = *compressor; - } else { - host->compressor.context = nullptr; - } -} - -/** Limits the maximum allowed channels of future incoming connections. - * @param host host to limit - * @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT - */ -void enet_host_channel_limit(ENetHost *host, size_t channelLimit) { - if (!channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) { - channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; - } else if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) { - channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; - } - - host->channelLimit = channelLimit; -} - -/** Adjusts the bandwidth limits of a host. - * @param host host to adjust - * @param incomingBandwidth new incoming bandwidth - * @param outgoingBandwidth new outgoing bandwidth - * @remarks the incoming and outgoing bandwidth parameters are identical in function to those - * specified in enet_host_create(). - */ -void enet_host_bandwidth_limit(ENetHost *host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) { - host->incomingBandwidth = incomingBandwidth; - host->outgoingBandwidth = outgoingBandwidth; - host->recalculateBandwidthLimits = 1; -} - -void enet_host_bandwidth_throttle(ENetHost *host) { - enet_uint32 timeCurrent = enet_time_get(); - enet_uint32 elapsedTime = timeCurrent - host->bandwidthThrottleEpoch; - enet_uint32 peersRemaining = (enet_uint32) host->connectedPeers; - enet_uint32 dataTotal = ~0; - enet_uint32 bandwidth = ~0; - enet_uint32 throttle = 0; - enet_uint32 bandwidthLimit = 0; - - int needsAdjustment = host->bandwidthLimitedPeers > 0 ? 1 : 0; - ENetPeer *peer; - ENetProtocol command; - - if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) { - return; - } - - if (host->outgoingBandwidth == 0 && host->incomingBandwidth == 0) { - return; - } - - host->bandwidthThrottleEpoch = timeCurrent; - - if (peersRemaining == 0) { - return; - } - - if (host->outgoingBandwidth != 0) { - dataTotal = 0; - bandwidth = (host->outgoingBandwidth * elapsedTime) / 1000; - - for (peer = host->peers; peer < &host->peers[host->peerCount]; ++peer) { - if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { - continue; - } - - dataTotal += peer->outgoingDataTotal; - } - } - - while (peersRemaining > 0 && needsAdjustment != 0) { - needsAdjustment = 0; - - if (dataTotal <= bandwidth) { - throttle = ENET_PEER_PACKET_THROTTLE_SCALE; - } else { - throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; - } - - for (peer = host->peers; peer < &host->peers[host->peerCount]; ++peer) { - enet_uint32 peerBandwidth; - - if ((peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) || - peer->incomingBandwidth == 0 || - peer->outgoingBandwidthThrottleEpoch == timeCurrent - ) { - continue; - } - - peerBandwidth = (peer->incomingBandwidth * elapsedTime) / 1000; - if ((throttle * peer->outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth) { - continue; - } - - peer->packetThrottleLimit = (peerBandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / peer->outgoingDataTotal; - - if (peer->packetThrottleLimit == 0) { - peer->packetThrottleLimit = 1; - } - - if (peer->packetThrottle > peer->packetThrottleLimit) { - peer->packetThrottle = peer->packetThrottleLimit; - } - - peer->outgoingBandwidthThrottleEpoch = timeCurrent; - - peer->incomingDataTotal = 0; - peer->outgoingDataTotal = 0; - - needsAdjustment = 1; - --peersRemaining; - bandwidth -= peerBandwidth; - dataTotal -= peerBandwidth; - } - } - - if (peersRemaining > 0) { - if (dataTotal <= bandwidth) { - throttle = ENET_PEER_PACKET_THROTTLE_SCALE; - } else { - throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; - } - - for (peer = host->peers; - peer < &host->peers[host->peerCount]; - ++peer) - { - if ((peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) || peer->outgoingBandwidthThrottleEpoch == timeCurrent) { - continue; - } - - peer->packetThrottleLimit = throttle; - - if (peer->packetThrottle > peer->packetThrottleLimit) { - peer->packetThrottle = peer->packetThrottleLimit; - } - - peer->incomingDataTotal = 0; - peer->outgoingDataTotal = 0; - } - } - - if (host->recalculateBandwidthLimits) { - host->recalculateBandwidthLimits = 0; - - peersRemaining = (enet_uint32) host->connectedPeers; - bandwidth = host->incomingBandwidth; - needsAdjustment = 1; - - if (bandwidth == 0) { - bandwidthLimit = 0; - } else { - while (peersRemaining > 0 && needsAdjustment != 0) { - needsAdjustment = 0; - bandwidthLimit = bandwidth / peersRemaining; - - for (peer = host->peers; peer < &host->peers[host->peerCount]; ++peer) { - if ((peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) || - peer->incomingBandwidthThrottleEpoch == timeCurrent - ) { - continue; - } - - if (peer->outgoingBandwidth > 0 && peer->outgoingBandwidth >= bandwidthLimit) { - continue; - } - - peer->incomingBandwidthThrottleEpoch = timeCurrent; - - needsAdjustment = 1; - --peersRemaining; - bandwidth -= peer->outgoingBandwidth; - } - } - } - - for (peer = host->peers; peer < &host->peers[host->peerCount]; ++peer) { - if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { - continue; - } - - command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; - command.header.channelID = 0xFF; - command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32(host->outgoingBandwidth); - - if (peer->incomingBandwidthThrottleEpoch == timeCurrent) { - command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32(peer->outgoingBandwidth); - } else { - command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32(bandwidthLimit); - } - - enet_peer_queue_outgoing_command(peer, &command, nullptr, 0, 0); - } - } -} /* enet_host_bandwidth_throttle */ - -// =======================================================================// -// ! -// ! Time -// ! -// =======================================================================// - -#ifdef _WIN32 -static LARGE_INTEGER getFILETIMEoffset() { - SYSTEMTIME s; - FILETIME f; - LARGE_INTEGER t; - - s.wYear = 1970; - s.wMonth = 1; - s.wDay = 1; - s.wHour = 0; - s.wMinute = 0; - s.wSecond = 0; - s.wMilliseconds = 0; - SystemTimeToFileTime(&s, &f); - t.QuadPart = f.dwHighDateTime; - t.QuadPart <<= 32; - t.QuadPart |= f.dwLowDateTime; - return (t); -} - -int clock_gettime(int X, struct timespec *tv) { - LARGE_INTEGER t; - FILETIME f; - double microseconds; - static LARGE_INTEGER offset; - static double frequencyToMicroseconds; - static int initialized = 0; - static BOOL usePerformanceCounter = 0; - - if (!initialized) { - LARGE_INTEGER performanceFrequency; - initialized = 1; - usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency); - if (usePerformanceCounter) { - QueryPerformanceCounter(&offset); - frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.; - } else { - offset = getFILETIMEoffset(); - frequencyToMicroseconds = 10.; - } - } - if (usePerformanceCounter) { - QueryPerformanceCounter(&t); - } else { - GetSystemTimeAsFileTime(&f); - t.QuadPart = f.dwHighDateTime; - t.QuadPart <<= 32; - t.QuadPart |= f.dwLowDateTime; - } - - t.QuadPart -= offset.QuadPart; - microseconds = (double)t.QuadPart / frequencyToMicroseconds; - t.QuadPart = (LONGLONG)microseconds; - tv->tv_sec = (long)(t.QuadPart / 1000000); - tv->tv_nsec = t.QuadPart % 1000000 * 1000; - return (0); -} -#elif __APPLE__ && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 -#define CLOCK_MONOTONIC 0 - - int clock_gettime(int X, struct timespec *ts) { - clock_serv_t cclock; - mach_timespec_t mts; - - host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); - clock_get_time(cclock, &mts); - mach_port_deallocate(mach_task_self(), cclock); - - ts->tv_sec = mts.tv_sec; - ts->tv_nsec = mts.tv_nsec; - - return 0; - } -#endif - -enet_uint32 enet_time_get() { - // TODO enet uses 32 bit timestamps. We should modify it to use - // 64 bit timestamps, but this is not trivial since we'd end up - // changing half the structs in enet. For now, retain 32 bits, but - // use an offset so we don't run out of bits. Basically, the first - // call of enet_time_get() will always return 1, and follow-up calls - // indicate elapsed time since the first call. - // - // Note that we don't want to return 0 from the first call, in case - // some part of enet uses 0 as a special value (meaning time not set - // for example). - static uint64_t start_time_ns = 0; - - struct timespec ts; -#if defined(CLOCK_MONOTONIC_RAW) - clock_gettime(CLOCK_MONOTONIC_RAW, &ts); -#else - clock_gettime(CLOCK_MONOTONIC, &ts); -#endif - - static const uint64_t ns_in_s = 1000 * 1000 * 1000; - static const uint64_t ns_in_ms = 1000 * 1000; - uint64_t current_time_ns = ts.tv_nsec + (uint64_t)ts.tv_sec * ns_in_s; - - // Most of the time we just want to atomically read the start time. We - // could just use a single CAS instruction instead of this if, but it - // would be slower in the average case. - // - // Note that statics are auto-initialized to zero, and starting a thread - // implies a memory barrier. So we know that whatever thread calls this, - // it correctly sees the start_time_ns as 0 initially. - uint64_t offset_ns = ENET_ATOMIC_READ(&start_time_ns); - if (offset_ns == 0) { - // We still need to CAS, since two different threads can get here - // at the same time. - // - // We assume that current_time_ns is > 1ms. - // - // Set the value of the start_time_ns, such that the first timestamp - // is at 1ms. This ensures 0 remains a special value. - uint64_t want_value = current_time_ns - 1 * ns_in_ms; - uint64_t old_value = ENET_ATOMIC_CAS(&start_time_ns, 0, want_value); - offset_ns = old_value == 0 ? want_value : old_value; - } - - uint64_t result_in_ns = current_time_ns - offset_ns; - return (enet_uint32)(result_in_ns / ns_in_ms); -} - -// =======================================================================// -// ! -// ! Platform Specific (Unix) -// ! -// =======================================================================// - -#ifndef _WIN32 - -int enet_initialize(void) { - return 0; - } - - void enet_deinitialize(void) {} - - enet_uint64 enet_host_random_seed(void) { - return (enet_uint64) time(nullptr); - } - - int enet_address_set_host_ip(ENetAddress *address, const char *name) { - if (!inet_pton(AF_INET6, name, &address->host)) { - return -1; - } - - return 0; - } - - int enet_address_set_host(ENetAddress *address, const char *name) { - struct addrinfo hints, *resultList = nullptr, *result = nullptr; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - - if (getaddrinfo(name, nullptr, &hints, &resultList) != 0) { - return -1; - } - - for (result = resultList; result != nullptr; result = result->ai_next) { - if (result->ai_addr != nullptr && result->ai_addrlen >= sizeof(struct sockaddr_in)) { - if (result->ai_family == AF_INET) { - struct sockaddr_in * sin = (struct sockaddr_in *) result->ai_addr; - - ((uint32_t *)&address->host.s6_addr)[0] = 0; - ((uint32_t *)&address->host.s6_addr)[1] = 0; - ((uint32_t *)&address->host.s6_addr)[2] = htonl(0xffff); - ((uint32_t *)&address->host.s6_addr)[3] = sin->sin_addr.s_addr; - - freeaddrinfo(resultList); - - return 0; - } - else if(result->ai_family == AF_INET6) { - struct sockaddr_in6 * sin = (struct sockaddr_in6 *)result->ai_addr; - - address->host = sin->sin6_addr; - address->sin6_scope_id = sin->sin6_scope_id; - - freeaddrinfo(resultList); - - return 0; - } - } - } - - - if (resultList != nullptr) { - freeaddrinfo(resultList); - } - - return enet_address_set_host_ip(address, name); - } /* enet_address_set_host */ - - int enet_address_get_host_ip(const ENetAddress *address, char *name, size_t nameLength) { - if (inet_ntop(AF_INET6, &address->host, name, nameLength) == nullptr) { - return -1; - } - - return 0; - } - - int enet_address_get_host(const ENetAddress *address, char *name, size_t nameLength) { - struct sockaddr_in6 sin; - int err; - - memset(&sin, 0, sizeof(struct sockaddr_in6)); - - sin.sin6_family = AF_INET6; - sin.sin6_port = ENET_HOST_TO_NET_16 (address->port); - sin.sin6_addr = address->host; - sin.sin6_scope_id = address->sin6_scope_id; - - err = getnameinfo((struct sockaddr *) &sin, sizeof(sin), name, nameLength, nullptr, 0, NI_NAMEREQD); - if (!err) { - if (name != nullptr && nameLength > 0 && !memchr(name, '\0', nameLength)) { - return -1; - } - return 0; - } - if (err != EAI_NONAME) { - return -1; - } - - return enet_address_get_host_ip(address, name, nameLength); - } /* enet_address_get_host */ - - int enet_socket_bind(ENetSocket socket, const ENetAddress *address) { - struct sockaddr_in6 sin; - memset(&sin, 0, sizeof(struct sockaddr_in6)); - sin.sin6_family = AF_INET6; - - if (address != nullptr) { - sin.sin6_port = ENET_HOST_TO_NET_16(address->port); - sin.sin6_addr = address->host; - sin.sin6_scope_id = address->sin6_scope_id; - } else { - sin.sin6_port = 0; - sin.sin6_addr = ENET_HOST_ANY; - sin.sin6_scope_id = 0; - } - - return bind(socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in6)); - } - - int enet_socket_get_address(ENetSocket socket, ENetAddress *address) { - struct sockaddr_in6 sin; - socklen_t sinLength = sizeof(struct sockaddr_in6); - - if (getsockname(socket, (struct sockaddr *) &sin, &sinLength) == -1) { - return -1; - } - - address->host = sin.sin6_addr; - address->port = ENET_NET_TO_HOST_16(sin.sin6_port); - address->sin6_scope_id = sin.sin6_scope_id; - - return 0; - } - - int enet_socket_listen(ENetSocket socket, int backlog) { - return listen(socket, backlog < 0 ? SOMAXCONN : backlog); - } - - ENetSocket enet_socket_create(ENetSocketType type) { - return socket(PF_INET6, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); - } - - int enet_socket_set_option(ENetSocket socket, ENetSocketOption option, int value) { - int result = -1; - - switch (option) { - case ENET_SOCKOPT_NONBLOCK: - result = fcntl(socket, F_SETFL, (value ? O_NONBLOCK : 0) | (fcntl(socket, F_GETFL) & ~O_NONBLOCK)); - break; - - case ENET_SOCKOPT_BROADCAST: - result = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_REUSEADDR: - result = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_RCVBUF: - result = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_SNDBUF: - result = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_RCVTIMEO: { - struct timeval timeVal; - timeVal.tv_sec = value / 1000; - timeVal.tv_usec = (value % 1000) * 1000; - result = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeVal, sizeof(struct timeval)); - break; - } - - case ENET_SOCKOPT_SNDTIMEO: { - struct timeval timeVal; - timeVal.tv_sec = value / 1000; - timeVal.tv_usec = (value % 1000) * 1000; - result = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeVal, sizeof(struct timeval)); - break; - } - - case ENET_SOCKOPT_NODELAY: - result = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_IPV6_V6ONLY: - result = setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&value, sizeof(int)); - break; - - default: - break; - } - return result == -1 ? -1 : 0; - } /* enet_socket_set_option */ - - int enet_socket_get_option(ENetSocket socket, ENetSocketOption option, int *value) { - int result = -1; - socklen_t len; - - switch (option) { - case ENET_SOCKOPT_ERROR: - len = sizeof(int); - result = getsockopt(socket, SOL_SOCKET, SO_ERROR, value, &len); - break; - - default: - break; - } - return result == -1 ? -1 : 0; - } - - int enet_socket_connect(ENetSocket socket, const ENetAddress *address) { - struct sockaddr_in6 sin; - int result; - - memset(&sin, 0, sizeof(struct sockaddr_in6)); - - sin.sin6_family = AF_INET6; - sin.sin6_port = ENET_HOST_TO_NET_16(address->port); - sin.sin6_addr = address->host; - sin.sin6_scope_id = address->sin6_scope_id; - - result = connect(socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in6)); - if (result == -1 && errno == EINPROGRESS) { - return 0; - } - - return result; - } - - ENetSocket enet_socket_accept(ENetSocket socket, ENetAddress *address) { - int result; - struct sockaddr_in6 sin; - socklen_t sinLength = sizeof(struct sockaddr_in6); - - result = accept(socket,address != nullptr ? (struct sockaddr *) &sin : nullptr, address != nullptr ? &sinLength : nullptr); - - if (result == -1) { - return ENET_SOCKET_NULL; - } - - if (address != nullptr) { - address->host = sin.sin6_addr; - address->port = ENET_NET_TO_HOST_16 (sin.sin6_port); - address->sin6_scope_id = sin.sin6_scope_id; - } - - return result; - } - - int enet_socket_shutdown(ENetSocket socket, ENetSocketShutdown how) { - return shutdown(socket, (int) how); - } - - void enet_socket_destroy(ENetSocket socket) { - if (socket != -1) { - close(socket); - } - } - - int enet_socket_send(ENetSocket socket, const ENetAddress *address, const ENetBuffer *buffers, size_t bufferCount) { - struct msghdr msgHdr; - struct sockaddr_in6 sin; - int sentLength; - - memset(&msgHdr, 0, sizeof(struct msghdr)); - - if (address != nullptr) { - memset(&sin, 0, sizeof(struct sockaddr_in6)); - - sin.sin6_family = AF_INET6; - sin.sin6_port = ENET_HOST_TO_NET_16(address->port); - sin.sin6_addr = address->host; - sin.sin6_scope_id = address->sin6_scope_id; - - msgHdr.msg_name = &sin; - msgHdr.msg_namelen = sizeof(struct sockaddr_in6); - } - - msgHdr.msg_iov = (struct iovec *) buffers; - msgHdr.msg_iovlen = bufferCount; - - sentLength = sendmsg(socket, &msgHdr, MSG_NOSIGNAL); - - if (sentLength == -1) { - if (errno == EWOULDBLOCK) { - return 0; - } - - return -1; - } - - return sentLength; - } /* enet_socket_send */ - - int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buffers, size_t bufferCount) { - struct msghdr msgHdr; - struct sockaddr_in6 sin; - int recvLength; - - memset(&msgHdr, 0, sizeof(struct msghdr)); - - if (address != nullptr) { - msgHdr.msg_name = &sin; - msgHdr.msg_namelen = sizeof(struct sockaddr_in6); - } - - msgHdr.msg_iov = (struct iovec *) buffers; - msgHdr.msg_iovlen = bufferCount; - - recvLength = recvmsg(socket, &msgHdr, MSG_NOSIGNAL); - - if (recvLength == -1) { - if (errno == EWOULDBLOCK) { - return 0; - } - - return -1; - } - - if (msgHdr.msg_flags & MSG_TRUNC) { - return -1; - } - - if (address != nullptr) { - address->host = sin.sin6_addr; - address->port = ENET_NET_TO_HOST_16(sin.sin6_port); - address->sin6_scope_id = sin.sin6_scope_id; - } - - return recvLength; - } /* enet_socket_receive */ - - int enet_socketset_select(ENetSocket maxSocket, ENetSocketSet *readSet, ENetSocketSet *writeSet, enet_uint32 timeout) { - struct timeval timeVal; - - timeVal.tv_sec = timeout / 1000; - timeVal.tv_usec = (timeout % 1000) * 1000; - - return select(maxSocket + 1, readSet, writeSet, nullptr, &timeVal); - } - - int enet_socket_wait(ENetSocket socket, enet_uint32 *condition, enet_uint64 timeout) { - struct pollfd pollSocket; - int pollCount; - - pollSocket.fd = socket; - pollSocket.events = 0; - - if (*condition & ENET_SOCKET_WAIT_SEND) { - pollSocket.events |= POLLOUT; - } - - if (*condition & ENET_SOCKET_WAIT_RECEIVE) { - pollSocket.events |= POLLIN; - } - - pollCount = poll(&pollSocket, 1, timeout); - - if (pollCount < 0) { - if (errno == EINTR && *condition & ENET_SOCKET_WAIT_INTERRUPT) { - *condition = ENET_SOCKET_WAIT_INTERRUPT; - - return 0; - } - - return -1; - } - - *condition = ENET_SOCKET_WAIT_NONE; - - if (pollCount == 0) { - return 0; - } - - if (pollSocket.revents & POLLOUT) { - *condition |= ENET_SOCKET_WAIT_SEND; - } - - if (pollSocket.revents & POLLIN) { - *condition |= ENET_SOCKET_WAIT_RECEIVE; - } - - return 0; - } /* enet_socket_wait */ - -#endif // !_WIN32 - - -// =======================================================================// -// ! -// ! Platform Specific (Win) -// ! -// =======================================================================// - -#ifdef _WIN32 - -#ifdef __MINGW32__ -// inet_ntop/inet_pton for MinGW from http://mingw-users.1079350.n2.nabble.com/IPv6-getaddrinfo-amp-inet-ntop-td5891996.html - const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) { - if (af == AF_INET) { - struct sockaddr_in in; - memset(&in, 0, sizeof(in)); - in.sin_family = AF_INET; - memcpy(&in.sin_addr, src, sizeof(struct in_addr)); - getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, nullptr, 0, NI_NUMERICHOST); - return dst; - } - else if (af == AF_INET6) { - struct sockaddr_in6 in; - memset(&in, 0, sizeof(in)); - in.sin6_family = AF_INET6; - memcpy(&in.sin6_addr, src, sizeof(struct in_addr6)); - getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, nullptr, 0, NI_NUMERICHOST); - return dst; - } - - return nullptr; - } - - #define NS_INADDRSZ 4 - #define NS_IN6ADDRSZ 16 - #define NS_INT16SZ 2 - - int inet_pton4(const char *src, char *dst) { - uint8_t tmp[NS_INADDRSZ], *tp; - - int saw_digit = 0; - int octets = 0; - *(tp = tmp) = 0; - - int ch; - while ((ch = *src++) != '\0') - { - if (ch >= '0' && ch <= '9') - { - uint32_t n = *tp * 10 + (ch - '0'); - - if (saw_digit && *tp == 0) - return 0; - - if (n > 255) - return 0; - - *tp = n; - if (!saw_digit) - { - if (++octets > 4) - return 0; - saw_digit = 1; - } - } - else if (ch == '.' && saw_digit) - { - if (octets == 4) - return 0; - *++tp = 0; - saw_digit = 0; - } - else - return 0; - } - if (octets < 4) - return 0; - - memcpy(dst, tmp, NS_INADDRSZ); - - return 1; - } - - int inet_pton6(const char *src, char *dst) { - static const char xdigits[] = "0123456789abcdef"; - uint8_t tmp[NS_IN6ADDRSZ]; - - uint8_t *tp = (uint8_t*) memset(tmp, '\0', NS_IN6ADDRSZ); - uint8_t *endp = tp + NS_IN6ADDRSZ; - uint8_t *colonp = nullptr; - - /* Leading :: requires some special handling. */ - if (*src == ':') - { - if (*++src != ':') - return 0; - } - - const char *curtok = src; - int saw_xdigit = 0; - uint32_t val = 0; - int ch; - while ((ch = tolower(*src++)) != '\0') - { - const char *pch = strchr(xdigits, ch); - if (pch != nullptr) - { - val <<= 4; - val |= (pch - xdigits); - if (val > 0xffff) - return 0; - saw_xdigit = 1; - continue; - } - if (ch == ':') - { - curtok = src; - if (!saw_xdigit) - { - if (colonp) - return 0; - colonp = tp; - continue; - } - else if (*src == '\0') - { - return 0; - } - if (tp + NS_INT16SZ > endp) - return 0; - *tp++ = (uint8_t) (val >> 8) & 0xff; - *tp++ = (uint8_t) val & 0xff; - saw_xdigit = 0; - val = 0; - continue; - } - if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && - inet_pton4(curtok, (char*) tp) > 0) - { - tp += NS_INADDRSZ; - saw_xdigit = 0; - break; /* '\0' was seen by inet_pton4(). */ - } - return 0; - } - if (saw_xdigit) - { - if (tp + NS_INT16SZ > endp) - return 0; - *tp++ = (uint8_t) (val >> 8) & 0xff; - *tp++ = (uint8_t) val & 0xff; - } - if (colonp != nullptr) - { - /* - * Since some memmove()'s erroneously fail to handle - * overlapping regions, we'll do the shift by hand. - */ - const int n = tp - colonp; - - if (tp == endp) - return 0; - - for (int i = 1; i <= n; i++) - { - endp[-i] = colonp[n - i]; - colonp[n - i] = 0; - } - tp = endp; - } - if (tp != endp) - return 0; - - memcpy(dst, tmp, NS_IN6ADDRSZ); - - return 1; - } - - - int inet_pton(int af, const char *src, struct in6_addr *dst) { - switch (af) - { - case AF_INET: - return inet_pton4(src, (char *)dst); - case AF_INET6: - return inet_pton6(src, (char *)dst); - default: - return -1; - } - } -#endif // __MINGW__ - -int enet_initialize(void) { - WORD versionRequested = MAKEWORD(1, 1); - WSADATA wsaData; - - if (WSAStartup(versionRequested, &wsaData)) { - return -1; - } - - if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { - WSACleanup(); - return -1; - } - - timeBeginPeriod(1); - return 0; -} - -void enet_deinitialize(void) { - timeEndPeriod(1); - WSACleanup(); -} - -enet_uint64 enet_host_random_seed(void) { - return (enet_uint64) timeGetTime(); -} - -int enet_address_set_host_ip(ENetAddress *address, const char *name) { - enet_uint8 vals[4] = { 0, 0, 0, 0 }; - int i; - - for (i = 0; i < 4; ++i) { - const char *next = name + 1; - if (*name != '0') { - long val = strtol(name, (char **) &next, 10); - if (val < 0 || val > 255 || next == name || next - name > 3) { - return -1; - } - vals[i] = (enet_uint8) val; - } - - if (*next != (i < 3 ? '.' : '\0')) { - return -1; - } - name = next + 1; - } - - memcpy(&address->host, vals, sizeof(enet_uint32)); - return 0; -} - -int enet_address_set_host(ENetAddress *address, const char *name) { - struct hostent *hostEntry = nullptr; - hostEntry = gethostbyname(name); - if (hostEntry == nullptr || hostEntry->h_addrtype != AF_INET) { - if (!inet_pton(AF_INET6, name, &address->host)) { - return -1; - } - - return 0; - } - - ((enet_uint32 *)&address->host.s6_addr)[0] = 0; - ((enet_uint32 *)&address->host.s6_addr)[1] = 0; - ((enet_uint32 *)&address->host.s6_addr)[2] = htonl(0xffff); - ((enet_uint32 *)&address->host.s6_addr)[3] = *(enet_uint32 *)hostEntry->h_addr_list[0]; - - return 0; -} - -int enet_address_get_host_ip(const ENetAddress *address, char *name, size_t nameLength) { - if (inet_ntop(AF_INET6, (PVOID)&address->host, name, nameLength) == nullptr) { - return -1; - } - - return 0; -} - -int enet_address_get_host(const ENetAddress *address, char *name, size_t nameLength) { - struct in6_addr in; - struct hostent *hostEntry = nullptr; - - in = address->host; - hostEntry = gethostbyaddr((char *)&in, sizeof(struct in6_addr), AF_INET6); - - if (hostEntry == nullptr) { - return enet_address_get_host_ip(address, name, nameLength); - } else { - size_t hostLen = strlen(hostEntry->h_name); - if (hostLen >= nameLength) { - return -1; - } - memcpy(name, hostEntry->h_name, hostLen + 1); - } - - return 0; -} - -int enet_socket_bind(ENetSocket socket, const ENetAddress *address) { - struct sockaddr_in6 sin; - memset(&sin, 0, sizeof(struct sockaddr_in6)); - sin.sin6_family = AF_INET6; - - if (address != nullptr) { - sin.sin6_port = ENET_HOST_TO_NET_16 (address->port); - sin.sin6_addr = address->host; - sin.sin6_scope_id = address->sin6_scope_id; - } else { - sin.sin6_port = 0; - sin.sin6_addr = in6addr_any; - sin.sin6_scope_id = 0; - } - - return bind(socket, (struct sockaddr *) &sin, sizeof(struct sockaddr_in6)) == SOCKET_ERROR ? -1 : 0; -} - -int enet_socket_get_address(ENetSocket socket, ENetAddress *address) { - struct sockaddr_in6 sin; - int sinLength = sizeof(struct sockaddr_in6); - - if (getsockname(socket, (struct sockaddr *) &sin, &sinLength) == -1) { - return -1; - } - - address->host = sin.sin6_addr; - address->port = ENET_NET_TO_HOST_16(sin.sin6_port); - address->sin6_scope_id = sin.sin6_scope_id; - - return 0; -} - -int enet_socket_listen(ENetSocket socket, int backlog) { - return listen(socket, backlog < 0 ? SOMAXCONN : backlog) == SOCKET_ERROR ? -1 : 0; -} - -ENetSocket enet_socket_create(ENetSocketType type) { - return socket(PF_INET6, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); -} - -int enet_socket_set_option(ENetSocket socket, ENetSocketOption option, int value) { - int result = SOCKET_ERROR; - - switch (option) { - case ENET_SOCKOPT_NONBLOCK: { - u_long nonBlocking = (u_long) value; - result = ioctlsocket(socket, FIONBIO, &nonBlocking); - break; - } - - case ENET_SOCKOPT_BROADCAST: - result = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_REUSEADDR: - result = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_RCVBUF: - result = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_SNDBUF: - result = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_RCVTIMEO: - result = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_SNDTIMEO: - result = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_NODELAY: - result = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&value, sizeof(int)); - break; - - case ENET_SOCKOPT_IPV6_V6ONLY: - result = setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&value, sizeof(int)); - break; - - default: - break; - } - return result == SOCKET_ERROR ? -1 : 0; -} /* enet_socket_set_option */ - -int enet_socket_get_option(ENetSocket socket, ENetSocketOption option, int *value) { - int result = SOCKET_ERROR, len; - - switch (option) { - case ENET_SOCKOPT_ERROR: - len = sizeof(int); - result = getsockopt(socket, SOL_SOCKET, SO_ERROR, (char *)value, &len); - break; - - default: - break; - } - return result == SOCKET_ERROR ? -1 : 0; -} - -int enet_socket_connect(ENetSocket socket, const ENetAddress *address) { - struct sockaddr_in6 sin; - int result; - - memset(&sin, 0, sizeof(struct sockaddr_in6)); - - sin.sin6_family = AF_INET6; - sin.sin6_port = ENET_HOST_TO_NET_16(address->port); - sin.sin6_addr = address->host; - sin.sin6_scope_id = address->sin6_scope_id; - - result = connect(socket, (struct sockaddr *) &sin, sizeof(struct sockaddr_in6)); - if (result == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) { - return -1; - } - - return 0; -} - -ENetSocket enet_socket_accept(ENetSocket socket, ENetAddress *address) { - SOCKET result; - struct sockaddr_in6 sin; - int sinLength = sizeof(struct sockaddr_in6); - - result = accept(socket, address != nullptr ? (struct sockaddr *)&sin : nullptr, address != nullptr ? &sinLength : nullptr); - - if (result == INVALID_SOCKET) { - return ENET_SOCKET_NULL; - } - - if (address != nullptr) { - address->host = sin.sin6_addr; - address->port = ENET_NET_TO_HOST_16(sin.sin6_port); - address->sin6_scope_id = sin.sin6_scope_id; - } - - return result; -} - -int enet_socket_shutdown(ENetSocket socket, ENetSocketShutdown how) { - return shutdown(socket, (int) how) == SOCKET_ERROR ? -1 : 0; -} - -void enet_socket_destroy(ENetSocket socket) { - if (socket != INVALID_SOCKET) { - closesocket(socket); - } -} - -int enet_socket_send(ENetSocket socket, const ENetAddress *address, const ENetBuffer *buffers, size_t bufferCount) { - struct sockaddr_in6 sin; - DWORD sentLength; - - if (address != nullptr) { - memset(&sin, 0, sizeof(struct sockaddr_in6)); - - sin.sin6_family = AF_INET6; - sin.sin6_port = ENET_HOST_TO_NET_16(address->port); - sin.sin6_addr = address->host; - sin.sin6_scope_id = address->sin6_scope_id; - } - - if (WSASendTo(socket, - (LPWSABUF) buffers, - (DWORD) bufferCount, - &sentLength, - 0, - address != nullptr ? (struct sockaddr *) &sin : nullptr, - address != nullptr ? sizeof(struct sockaddr_in6) : 0, - nullptr, - nullptr) == SOCKET_ERROR - ) { - return (WSAGetLastError() == WSAEWOULDBLOCK) ? 0 : -1; - } - - return (int) sentLength; -} - -int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buffers, size_t bufferCount) { - INT sinLength = sizeof(struct sockaddr_in6); - DWORD flags = 0, recvLength; - struct sockaddr_in6 sin; - - if (WSARecvFrom(socket, - (LPWSABUF) buffers, - (DWORD) bufferCount, - &recvLength, - &flags, - address != nullptr ? (struct sockaddr *) &sin : nullptr, - address != nullptr ? &sinLength : nullptr, - nullptr, - nullptr) == SOCKET_ERROR - ) { - switch (WSAGetLastError()) { - case WSAEWOULDBLOCK: - case WSAECONNRESET: - return 0; - } - - return -1; - } - - if (flags & MSG_PARTIAL) { - return -1; - } - - if (address != nullptr) { - address->host = sin.sin6_addr; - address->port = ENET_NET_TO_HOST_16(sin.sin6_port); - address->sin6_scope_id = sin.sin6_scope_id; - } - - return (int) recvLength; -} /* enet_socket_receive */ - -int enet_socketset_select(ENetSocket maxSocket, ENetSocketSet *readSet, ENetSocketSet *writeSet, enet_uint32 timeout) { - struct timeval timeVal; - - timeVal.tv_sec = timeout / 1000; - timeVal.tv_usec = (timeout % 1000) * 1000; - - return select(maxSocket + 1, readSet, writeSet, nullptr, &timeVal); -} - -int enet_socket_wait(ENetSocket socket, enet_uint32 *condition, enet_uint64 timeout) { - fd_set readSet, writeSet; - struct timeval timeVal; - int selectCount; - - timeVal.tv_sec = timeout / 1000; - timeVal.tv_usec = (timeout % 1000) * 1000; - - FD_ZERO(&readSet); - FD_ZERO(&writeSet); - - if (*condition & ENET_SOCKET_WAIT_SEND) { - FD_SET(socket, &writeSet); - } - - if (*condition & ENET_SOCKET_WAIT_RECEIVE) { - FD_SET(socket, &readSet); - } - - selectCount = select(socket + 1, &readSet, &writeSet, nullptr, &timeVal); - - if (selectCount < 0) { - return -1; - } - - *condition = ENET_SOCKET_WAIT_NONE; - - if (selectCount == 0) { - return 0; - } - - if (FD_ISSET(socket, &writeSet)) { - *condition |= ENET_SOCKET_WAIT_SEND; - } - - if (FD_ISSET(socket, &readSet)) { - *condition |= ENET_SOCKET_WAIT_RECEIVE; - } - - return 0; -} /* enet_socket_wait */ - -#endif // _WIN32 - - -#ifdef __cplusplus -} -#endif - -#endif // ENET_IMPLEMENTATION -#endif // ENET_INCLUDE_H diff --git a/Compressor.cpp b/src/Compressor.cpp similarity index 100% rename from Compressor.cpp rename to src/Compressor.cpp diff --git a/CoreNetwork.cpp b/src/CoreNetwork.cpp similarity index 95% rename from CoreNetwork.cpp rename to src/CoreNetwork.cpp index 73eb0d9..ac909c4 100644 --- a/CoreNetwork.cpp +++ b/src/CoreNetwork.cpp @@ -10,9 +10,6 @@ extern int DEFAULT_PORT; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmissing-noreturn" - std::string HTTP_REQUEST(const std::string&url,int port); void SyncResources(const std::string& IP, int port); void Exit(const std::string& Msg); @@ -22,9 +19,10 @@ extern int ping; extern bool Terminate; extern bool TCPTerminate; extern bool MPDEV; + void StartSync(const std::string &Data){ - std::thread t1(SyncResources,Data.substr(1,Data.find(':')-1),std::stoi(Data.substr(Data.find(':')+1))); - //std::thread t1(SyncResources,"127.0.0.1",30814); + //std::thread t1(SyncResources,Data.substr(1,Data.find(':')-1),std::stoi(Data.substr(Data.find(':')+1))); + std::thread t1(SyncResources,"127.0.0.1",30814); t1.detach(); } diff --git a/Discord.cpp b/src/Discord.cpp similarity index 98% rename from Discord.cpp rename to src/Discord.cpp index d751816..6d72ec6 100644 --- a/Discord.cpp +++ b/src/Discord.cpp @@ -13,7 +13,6 @@ #include extern bool MPDEV; static const char* APPLICATION_ID = "629743237988352010"; -static int FrustrationLevel = 0; static int64_t StartTime; static int SendPresence = 1; static std::vector LocalInfo; @@ -126,7 +125,7 @@ static void discordInit() Discord_Initialize(APPLICATION_ID, &handlers, 1, NULL); } -static void Loop() +[[noreturn]] static void Loop() { char line[512]; char* space; diff --git a/GameStart.cpp b/src/GameStart.cpp similarity index 89% rename from GameStart.cpp rename to src/GameStart.cpp index f2c362b..1ec35a8 100644 --- a/GameStart.cpp +++ b/src/GameStart.cpp @@ -1,10 +1,9 @@ /// /// Created by Anonymous275 on 5/2/2020 /// -#include +#include #include #include -#include std::string QueryKey(HKEY hKey,int ID); void SystemExec(const std::string&cmd); @@ -37,5 +36,7 @@ void StartGame(const std::string&ExeDir,const std::string&Current){ std::thread RB(RollBack,Write(Current)); RB.detach(); SystemExec(ExeDir + " -nocrashreport"); - Exit("Game Closed!"); + std::cout << "\nGame Closed! launcher closing in 5 secs\n"; + std::this_thread::sleep_for(std::chrono::seconds(5)); + exit(2); } \ No newline at end of file diff --git a/proxy.cpp b/src/Network 2.0/GlobalHandler.cpp similarity index 61% rename from proxy.cpp rename to src/Network 2.0/GlobalHandler.cpp index 8e85ac9..ed34258 100644 --- a/proxy.cpp +++ b/src/Network 2.0/GlobalHandler.cpp @@ -1,37 +1,29 @@ //// //// Created by Anonymous275 on 3/3/2020. //// - #define ENET_IMPLEMENTATION + #include -#include "include/enet.hpp" #include #include #include #include #include -#include +#include + +int ClientID = -1; extern int DEFAULT_PORT; -typedef struct { - ENetHost *host; - ENetPeer *peer; -} Client; - -std::vector Split(const std::string& String,const std::string& delimiter); std::chrono::time_point PingStart,PingEnd; extern std::vector GlobalInfo; bool TCPTerminate = false; bool Terminate = false; bool CServer = true; -ENetPeer*ServerPeer; SOCKET*ClientSocket; extern bool MPDEV; int ping = 0; -[[noreturn]] void CoreNetworkThread(); - -void TCPSEND(const std::string&Data){ +void GameSend(const std::string&Data){ if(!TCPTerminate) { int iSendResult = send(*ClientSocket, (Data + "\n").c_str(), int(Data.length()) + 1, 0); if (iSendResult == SOCKET_ERROR) { @@ -45,121 +37,97 @@ void TCPSEND(const std::string&Data){ } } } -void RUDPSEND(const std::string&Data,bool Rel){ - if(!Terminate && ServerPeer != nullptr){ +void TCPSend(const std::string&Data); +void UDPSend(const std::string&Data); +void ServerSend(const std::string&Data, bool Rel){ + if(!Terminate){ char C = 0; if(Data.length() > 3)C = Data.at(0); if (C == 'O' || C == 'T')Rel = true; - enet_peer_send(ServerPeer, 0, enet_packet_create(Data.c_str(), Data.length()+1, Rel?1:8)); + + if(Rel)TCPSend(Data); + else UDPSend(Data); + if (MPDEV && Data.length() > 1000) { std::cout << "(Launcher->Server) Bytes sent: " << Data.length() << " : " << Data.substr(0, 10) << Data.substr(Data.length() - 10) << std::endl; - }else if(MPDEV){ - std::cout << "(Game->Launcher) : " << Data << std::endl; + }else if(MPDEV && C == 'Z'){ + //std::cout << "(Game->Launcher) : " << Data << std::endl; } } } void NameRespond(){ std::string Packet = "NR" + GlobalInfo.at(0)+":"+GlobalInfo.at(2); - RUDPSEND(Packet,true); + ServerSend(Packet,true); } -void AutoPing(ENetPeer*peer){ - while(!Terminate && peer != nullptr){ - RUDPSEND("p",true); +void AutoPing(){ + while(!Terminate){ + ServerSend("p",false); PingStart = std::chrono::high_resolution_clock::now(); std::this_thread::sleep_for(std::chrono::seconds (1)); } } -void RUDPParser(const std::string& Data){ +std::string UlStatus = "Ulstart"; +std::string MStatus = " "; +void ServerParser(const std::string& Data){ char Code = Data.at(0),SubCode = 0; if(Data.length() > 1)SubCode = Data.at(1); switch (Code) { + case 'P': + ClientID = std::stoi(Data.substr(1)); + break; case 'p': PingEnd = std::chrono::high_resolution_clock::now(); - ping = int(std::chrono::duration_cast(PingEnd-PingStart).count())/1000; + ping = std::chrono::duration_cast(PingEnd-PingStart).count(); return; case 'N': if(SubCode == 'R')NameRespond(); return; + case 'M': + MStatus = Data; + UlStatus = "Uldone"; + return; } - ///std::cout << "Received: " << Data << std::endl; - TCPSEND(Data); + GameSend(Data); } -void HandleEvent(ENetEvent event,Client client){ - switch (event.type){ - case ENET_EVENT_TYPE_CONNECT: - std::cout << "Connected to server!" << std::endl; - //printf("Client Connected port : %u.\n",event.peer->address.port); - event.peer->data = (void*)"Connected Server"; - break; - case ENET_EVENT_TYPE_RECEIVE: - RUDPParser((char*)event.packet->data); - enet_packet_destroy(event.packet); - break; - case ENET_EVENT_TYPE_DISCONNECT: - printf ("%s disconnected.\n", (char *)event.peer->data); - CServer = true; - Terminate = true; - event.peer->data = nullptr; - break; - - case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: - printf ("%s timeout.\n", (char *)event.peer->data); - CServer = true; - Terminate = true; - TCPSEND("TTimeout"); - event.peer->data = nullptr; - break; - case ENET_EVENT_TYPE_NONE: break; - } -} -void RUDPClientThread(const std::string& IP, int Port){ - std::condition_variable lock; - if (enet_initialize() != 0) { - std::cout << "An error occurred while initializing!\n"; - } - Client client; - ENetAddress address = {0}; - - address.host = ENET_HOST_ANY; - address.port = Port; - if(MPDEV)std::cout << "(Launcher->Server) Connecting...\n"; - - enet_address_set_host(&address, IP.c_str()); - client.host = enet_host_create(nullptr, 1, 2, 0, 0); - client.peer = enet_host_connect(client.host, &address, 2, 0); - if (client.peer == nullptr) { - if(MPDEV)std::cout << "could not connect\n"; - TCPSEND("TTimeout"); - TCPTerminate = true; - Terminate = true; - } - std::thread Ping(AutoPing,client.peer); +void TCPClientMain(const std::string& IP,int Port); +void UDPClientMain(const std::string& IP,int Port); +void NetMain(const std::string& IP, int Port){ + std::thread Ping(AutoPing); Ping.detach(); - ENetEvent event; - while (!Terminate) { - ServerPeer = client.peer; - enet_host_service(client.host, &event, 1); - HandleEvent(event,client); - } - enet_peer_disconnect(client.peer,0); - enet_host_service(client.host, &event, 1); - HandleEvent(event,client); + UDPClientMain(IP,Port); CServer = true; + Terminate = true; std::cout << "Connection Terminated!" << std::endl; } +extern SOCKET UDPSock; +extern SOCKET TCPSock; +void Reset() { + ClientSocket = nullptr; + TCPTerminate = false; + Terminate = false; + UlStatus = "Ulstart"; + MStatus = " "; + UDPSock = -1; + TCPSock = -1; +} std::string Compress(const std::string&Data); std::string Decompress(const std::string&Data); -void TCPServerThread(const std::string& IP, int Port){ - if(MPDEV)std::cout << "Proxy Started! " << IP << ":" << Port << std::endl; +void TCPGameServer(const std::string& IP, int Port){ + if(MPDEV)std::cout << "Game server Started! " << IP << ":" << Port << std::endl; do { - if(MPDEV)std::cout << "Proxy on Start" << std::endl; + Reset(); + if(CServer) { + std::thread Client(TCPClientMain, IP, Port); + Client.detach(); + } + if(MPDEV)std::cout << "Game server on Start" << std::endl; WSADATA wsaData; int iResult; SOCKET ListenSocket = INVALID_SOCKET; @@ -228,10 +196,11 @@ void TCPServerThread(const std::string& IP, int Port){ closesocket(ListenSocket); if(MPDEV)std::cout << "(Proxy) Game Connected!" << std::endl; if(CServer){ - std::thread t1(RUDPClientThread, IP, Port); + std::thread t1(NetMain, IP, Port); t1.detach(); CServer = false; } + ClientSocket = &Socket; do { //std::cout << "(Proxy) Waiting for Game Data..." << std::endl; @@ -241,23 +210,14 @@ void TCPServerThread(const std::string& IP, int Port){ buff.resize(iResult*2); memcpy(&buff[0],recvbuf,iResult); buff.resize(iResult); - /*if(MPDEV && buff.length() > 1000) { - std::string cmp = Compress(buff), dcm = Decompress(cmp); - std::cout << "Compressed Size : " << cmp.length() << std::endl; - std::cout << "Decompressed Size : " << dcm.length() << std::endl; - if (cmp == dcm) { - std::cout << "Success!" << std::endl; - } else { - std::cout << "Fail!" << std::endl; - } - }*/ - RUDPSEND(buff,false); - //std::cout << "(Game->Launcher) Data : " << buff.length() << std::endl; + + ServerSend(buff,false); + } else if (iResult == 0) { if(MPDEV)std::cout << "(Proxy) Connection closing...\n"; closesocket(Socket); WSACleanup(); - + Terminate = true; continue; } else { if(MPDEV)std::cout << "(Proxy) recv failed with error: " << WSAGetLastError() << std::endl; @@ -282,22 +242,15 @@ void TCPServerThread(const std::string& IP, int Port){ } void VehicleNetworkStart(); - +void CoreNetworkThread(); void ProxyStart(){ std::thread t1(CoreNetworkThread); if(MPDEV)std::cout << "Core Network Started!\n"; t1.join(); } -void Reset() { - ClientSocket = nullptr; - ServerPeer = nullptr; - TCPTerminate = false; - Terminate = false; -} void ProxyThread(const std::string& IP, int Port){ - Reset(); - auto*t1 = new std::thread(TCPServerThread,IP,Port); + auto*t1 = new std::thread(TCPGameServer,IP,Port); t1->detach(); /*std::thread t2(VehicleNetworkStart); t2.detach();*/ diff --git a/src/Network 2.0/VehicleData.cpp b/src/Network 2.0/VehicleData.cpp new file mode 100644 index 0000000..c43f8b4 --- /dev/null +++ b/src/Network 2.0/VehicleData.cpp @@ -0,0 +1,62 @@ +/// +/// Created by Anonymous275 on 5/8/2020 +/// + + +#include +#include +#include + +extern bool Terminate; +extern int ClientID; +SOCKET UDPSock; +sockaddr_in ToServer{}; + +void UDPSend(const std::string&Data){ + if(ClientID == -1 || UDPSock == INVALID_SOCKET)return; + std::string Packet = char(ClientID+1) + std::string(":") + Data; + int sendOk = sendto(UDPSock, Packet.c_str(), int(Packet.length()) + 1, 0, (sockaddr*)&ToServer, sizeof(ToServer)); + if (sendOk == SOCKET_ERROR)std::cout << "Error Code : " << WSAGetLastError() << std::endl; +} + +void ServerParser(const std::string& Data); +void UDPRcv(){ + char buf[4096]; + int len = 4096; + sockaddr_in FromServer{}; + int clientLength = sizeof(FromServer); + ZeroMemory(&FromServer, clientLength); + ZeroMemory(buf, len); + if(UDPSock == INVALID_SOCKET)return; + int bytesIn = recvfrom(UDPSock, buf, len, 0, (sockaddr*)&FromServer, &clientLength); + if (bytesIn == SOCKET_ERROR) + { + //std::cout << "Error receiving from Server " << WSAGetLastError() << std::endl; + return; + } + ServerParser(std::string(buf)); +} +void TCPSend(const std::string&Data); +void UDPClientMain(const std::string& IP,int Port){ + WSADATA data; + if (WSAStartup(514, &data)) //2.2 + { + std::cout << "Can't start Winsock! " << std::endl; + return; + } + + ToServer.sin_family = AF_INET; + ToServer.sin_port = htons(Port); + inet_pton(AF_INET, IP.c_str(), &ToServer.sin_addr); + UDPSock = socket(AF_INET, SOCK_DGRAM, 0); + + + TCPSend("P"); + UDPSend("p"); + while (!Terminate){ + UDPRcv(); + } + + closesocket(UDPSock); + WSACleanup(); +} \ No newline at end of file diff --git a/src/Network 2.0/VehicleEvent.cpp b/src/Network 2.0/VehicleEvent.cpp new file mode 100644 index 0000000..cafea67 --- /dev/null +++ b/src/Network 2.0/VehicleEvent.cpp @@ -0,0 +1,96 @@ +/// +/// Created by Anonymous275 on 5/8/2020 +/// + +#include +#include +#include +#include +#pragma comment (lib, "ws2_32.lib") +extern bool Terminate; +extern bool MPDEV; +SOCKET TCPSock; +void TCPSend(const std::string&Data){ + if(TCPSock == INVALID_SOCKET){ + Terminate = true; + return; + } + int BytesSent = send(TCPSock, Data.c_str(), int(Data.length())+1, 0); + if (BytesSent == 0){ + if(MPDEV)std::cout << "(TCP) Connection closing..." << std::endl; + Terminate = true; + return; + } + else if (BytesSent < 0) { + if(MPDEV)std::cout << "(TCP) send failed with error: " << WSAGetLastError() << std::endl; + closesocket(TCPSock); + Terminate = true; + return; + } +} + +void ServerParser(const std::string& Data); +void TCPRcv(){ + char buf[10240]; + int len = 10240; + ZeroMemory(buf, len); + if(TCPSock == INVALID_SOCKET){ + Terminate = true; + return; + } + int BytesRcv = recv(TCPSock, buf, len,0); + if (BytesRcv == 0){ + if(MPDEV)std::cout << "(TCP) Connection closing..." << std::endl; + Terminate = true; + return; + } + else if (BytesRcv < 0) { + if(MPDEV)std::cout << "(TCP) recv failed with error: " << WSAGetLastError() << std::endl; + closesocket(TCPSock); + Terminate = true; + return; + } + ServerParser(std::string(buf)); +} + + +void TCPClientMain(const std::string& IP,int Port){ + WSADATA wsaData; + SOCKADDR_IN ServerAddr; + int RetCode; + + WSAStartup(514, &wsaData); //2.2 + TCPSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if(TCPSock == -1) + { + printf("Client: socket failed! Error code: %d\n", WSAGetLastError()); + WSACleanup(); + return; + } + ServerAddr.sin_family = AF_INET; + ServerAddr.sin_port = htons(Port); + inet_pton(AF_INET, IP.c_str(), &ServerAddr.sin_addr); + RetCode = connect(TCPSock, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr)); + if(RetCode != 0) + { + std::cout << "Client: connect failed! Error code: " << WSAGetLastError() << std::endl; + closesocket(TCPSock); + WSACleanup(); + return; + } + getsockname(TCPSock, (SOCKADDR *)&ServerAddr, (int *)sizeof(ServerAddr)); + + while(!Terminate){ + TCPRcv(); + } + + + if( shutdown(TCPSock, SD_SEND) != 0 && MPDEV) + std::cout << "(TCP) shutdown error code: " << WSAGetLastError() << std::endl; + + if(closesocket(TCPSock) != 0 && MPDEV) + std::cout << "(TCP) Cannot close socket. Error code: " << WSAGetLastError() << std::endl; + + if(WSACleanup() != 0 && MPDEV) + std::cout << "(TCP) Client: WSACleanup() failed!..." << std::endl; +} diff --git a/src/Resources.cpp b/src/Resources.cpp new file mode 100644 index 0000000..5b7b08e --- /dev/null +++ b/src/Resources.cpp @@ -0,0 +1,161 @@ +/// +/// Created by Anonymous275 on 4/11/2020 +/// + +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include +#include +#include + +namespace fs = std::experimental::filesystem; +void Exit(const std::string& Msg); +extern bool MPDEV; + +std::vector Split(const std::string& String,const std::string& delimiter){ + std::vector Val; + size_t pos = 0; + std::string token,s = String; + while ((pos = s.find(delimiter)) != std::string::npos) { + token = s.substr(0, pos); + Val.push_back(token); + s.erase(0, pos + delimiter.length()); + } + Val.push_back(s); + return Val; +} +std::string STCPRecv(SOCKET socket){ + char buf[65535]; + int len = 65535; + ZeroMemory(buf, len); + int BytesRcv = recv(socket, buf, len,0); + if (BytesRcv == 0){ + std::cout << "(TCP) Connection closing..." << std::endl; + return ""; + } + else if (BytesRcv < 0) { + std::cout << "(TCP) recv failed with error: " << WSAGetLastError() << std::endl; + closesocket(socket); + return ""; + } + return std::string(buf); +} + +void ProxyThread(const std::string& IP, int port); +void SyncResources(const std::string&IP,int Port){ + if(MPDEV)std::cout << "Called" << std::endl; + std::string FileList; + struct stat info{}; + if(stat( "Resources", &info) != 0){ + _wmkdir(L"Resources"); + } + + /*WSADATA wsaData; + SOCKET SendingSocket; + SOCKADDR_IN ServerAddr; + int RetCode; + int BytesSent, nlen; + + WSAStartup(514, &wsaData); //2.2 + + + SendingSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if(SendingSocket == -1) + { + if(MPDEV)printf("Client: socket() failed! Error code: %d\n", WSAGetLastError()); + WSACleanup(); + return; + } + + ServerAddr.sin_family = AF_INET; + ServerAddr.sin_port = htons(Port); + inet_pton(AF_INET, IP.c_str(), &ServerAddr.sin_addr); + + RetCode = connect(SendingSocket, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr)); + + if(RetCode != 0) + { + if(MPDEV)std::cout <<"Client: connect() failed! Error code: " << WSAGetLastError() << std::endl; + closesocket(SendingSocket); + WSACleanup(); + return; + } + + getsockname(SendingSocket, (SOCKADDR *)&ServerAddr, (int *)sizeof(ServerAddr)); + BytesSent = send(SendingSocket, "a", 1, 0); + + std::string File, Response, toSend, Data = STCPRecv(SendingSocket); + std::cout << Data << std::endl; + if (!Data.empty()) { + std::vector list = Split(Data, ";"); + std::vector FileNames(list.begin(), list.begin() + (list.size() / 2)); + std::vector FileSizes(list.begin() + (list.size() / 2), list.end()); + list.clear(); + int index = 0; + for (const std::string &a : FileNames) { + if (a.empty() || a.length() < 2)continue; + if (stat(a.c_str(), &info) == 0) { + if (fs::file_size(a) == std::stoi(FileSizes.at(index))) { + index++; + continue; + } else remove(a.c_str()); + } + + std::ofstream LFS; + LFS.open(a.c_str()); + LFS.close(); + toSend = "b" + a; + send(SendingSocket, toSend.c_str(), toSend.length(), 0); + LFS.open(a.c_str(), std::ios_base::app | std::ios::binary); + do { + Data = STCPRecv(SendingSocket); + if (Data.empty()) { + File.clear(); + break; + } + + if (Data.find("Cannot Open") != std::string::npos) { + File.clear(); + break; + } + LFS << Data; + float per = LFS.tellp() / std::stof(FileSizes.at(index)) * 100; + std::string Percent = std::to_string(truncf(per * 10) / 10); + UlStatus = "UlDownloading Resource: " + a.substr(a.find_last_of('/')) + " (" + + Percent.substr(0, Percent.find('.') + 2) + "%)"; + } while (LFS.tellp() != std::stoi(FileSizes.at(index))); + LFS.close(); + File.clear(); + } + + toSend = "M"; + send(SendingSocket, toSend.c_str(), toSend.length(), 0); + Data = STCPRecv(SendingSocket); + MStatus = "M" + Data; + } + UlStatus = "Uldone"; + std::cout << "Done!" << std::endl; + + if(BytesSent == SOCKET_ERROR) + if(MPDEV)printf("Client: send() error %d.\n", WSAGetLastError()); + + + + if( shutdown(SendingSocket, SD_SEND) != 0) + if(MPDEV)printf("Client: Well, there is something wrong with the shutdown() The error code: %d\n", WSAGetLastError()); + + + if(closesocket(SendingSocket) != 0) + if(MPDEV)printf("Client: Cannot close \"SendingSocket\" socket. Error code: %d\n", WSAGetLastError()); + + + if(WSACleanup() != 0) + if(MPDEV)printf("Client: WSACleanup() failed!...\n"); +*/ + + ProxyThread(IP,Port); +} \ No newline at end of file diff --git a/Security.cpp b/src/Security.cpp similarity index 100% rename from Security.cpp rename to src/Security.cpp diff --git a/UpdateCheck.cpp b/src/UpdateCheck.cpp similarity index 100% rename from UpdateCheck.cpp rename to src/UpdateCheck.cpp diff --git a/VehicleNetwork.cpp b/src/VehicleNetwork.cpp similarity index 98% rename from VehicleNetwork.cpp rename to src/VehicleNetwork.cpp index 37c2af1..a737113 100644 --- a/VehicleNetwork.cpp +++ b/src/VehicleNetwork.cpp @@ -13,7 +13,7 @@ extern bool TCPTerminate; extern bool MPDEV; void Print(const std::string&MSG); std::queue VNTCPQueue; -void RUDPSEND(const std::string&Data,bool Rel); +//void RUDPSEND(const std::string&Data,bool Rel); #define DEFAULT_PORT "4446" void Responder(const SOCKET *CS){ @@ -135,7 +135,7 @@ void VehicleNetworkStart(){ std::cout << "Fail!" << std::endl; } } - RUDPSEND(buff,false); + //RUDPSEND(buff,false); //std::cout << "(Game->Launcher VN) Data : " << buff.length() << std::endl; } else if (iResult == 0) { if(MPDEV)std::cout << "(VN) Connection closing...\n"; diff --git a/curl/curl.h b/src/curl/curl.h similarity index 99% rename from curl/curl.h rename to src/curl/curl.h index e0d5c0f..162b606 100644 --- a/curl/curl.h +++ b/src/curl/curl.h @@ -60,8 +60,8 @@ defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)) /* The check above prevents the winsock2 inclusion if winsock.h already was included, since they can't co-exist without problems */ -#include -#include +#include +#include #endif #endif diff --git a/curl/curlbuild.h b/src/curl/curlbuild.h similarity index 100% rename from curl/curlbuild.h rename to src/curl/curlbuild.h diff --git a/curl/curlrules.h b/src/curl/curlrules.h similarity index 100% rename from curl/curlrules.h rename to src/curl/curlrules.h diff --git a/curl/curlver.h b/src/curl/curlver.h similarity index 100% rename from curl/curlver.h rename to src/curl/curlver.h diff --git a/curl/easy.h b/src/curl/easy.h similarity index 100% rename from curl/easy.h rename to src/curl/easy.h diff --git a/curl/mprintf.h b/src/curl/mprintf.h similarity index 100% rename from curl/mprintf.h rename to src/curl/mprintf.h diff --git a/curl/multi.h b/src/curl/multi.h similarity index 100% rename from curl/multi.h rename to src/curl/multi.h diff --git a/curl/stdcheaders.h b/src/curl/stdcheaders.h similarity index 100% rename from curl/stdcheaders.h rename to src/curl/stdcheaders.h diff --git a/curl/system.h b/src/curl/system.h similarity index 100% rename from curl/system.h rename to src/curl/system.h diff --git a/curl/typecheck-gcc.h b/src/curl/typecheck-gcc.h similarity index 100% rename from curl/typecheck-gcc.h rename to src/curl/typecheck-gcc.h diff --git a/http.cpp b/src/http.cpp similarity index 100% rename from http.cpp rename to src/http.cpp diff --git a/include/discord_register.h b/src/include/discord_register.h similarity index 100% rename from include/discord_register.h rename to src/include/discord_register.h diff --git a/include/discord_rpc.h b/src/include/discord_rpc.h similarity index 100% rename from include/discord_rpc.h rename to src/include/discord_rpc.h diff --git a/src/include/enet.h b/src/include/enet.h new file mode 100644 index 0000000..c5b871f --- /dev/null +++ b/src/include/enet.h @@ -0,0 +1,5906 @@ +/** + * include/enet.h - a Single-Header auto-generated variant of enet.h library. + * + * Usage: + * #define ENET_IMPLEMENTATION exactly in ONE source file right BEFORE including the library, like: + * + * #define ENET_IMPLEMENTATION + * #include + * + * License: + * The MIT License (MIT) + * + * Copyright (c) 2002-2016 Lee Salzman + * Copyright (c) 2017-2018 Vladyslav Hrytsenko, Dominik Madarász + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ +#ifndef ENET_INCLUDE_H +#define ENET_INCLUDE_H + +#include +#include +#include +#include + +#define ENET_VERSION_MAJOR 2 +#define ENET_VERSION_MINOR 2 +#define ENET_VERSION_PATCH 0 +#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) +#define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF) +#define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF) +#define ENET_VERSION_GET_PATCH(version) ((version)&0xFF) +#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH) + +#define ENET_TIME_OVERFLOW 86400000 +#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW) +#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b)) +#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b)) +#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)) + +// =======================================================================// +// ! +// ! System differences +// ! +// =======================================================================// + +#if defined(_WIN32) +#if defined(_MSC_VER) && defined(ENET_IMPLEMENTATION) +#pragma warning (disable: 4267) // size_t to int conversion + #pragma warning (disable: 4244) // 64bit to 32bit int + #pragma warning (disable: 4018) // signed/unsigned mismatch + #pragma warning (disable: 4146) // unary minus operator applied to unsigned type +#endif + +#ifndef ENET_NO_PRAGMA_LINK +#pragma comment(lib, "ws2_32.lib") +#pragma comment(lib, "winmm.lib") +#endif + +#if _MSC_VER >= 1910 +/* It looks like there were changes as of Visual Studio 2017 and there are no 32/64 bit + versions of _InterlockedExchange[operation], only InterlockedExchange[operation] + (without leading underscore), so we have to distinguish between compiler versions */ +#define NOT_UNDERSCORED_INTERLOCKED_EXCHANGE +#endif + +#ifdef __GNUC__ +#if (_WIN32_WINNT < 0x0501) + #undef _WIN32_WINNT + #define _WIN32_WINNT 0x0501 + #endif +#endif + +#include +#include +#include + +#include + +#if defined(_WIN32) && defined(_MSC_VER) +#if _MSC_VER < 1900 +typedef struct timespec { + long tv_sec; + long tv_nsec; + }; +#endif +#define CLOCK_MONOTONIC 0 +#endif + +typedef SOCKET ENetSocket; +#define ENET_SOCKET_NULL INVALID_SOCKET + +#define ENET_HOST_TO_NET_16(value) (htons(value)) +#define ENET_HOST_TO_NET_32(value) (htonl(value)) + +#define ENET_NET_TO_HOST_16(value) (ntohs(value)) +#define ENET_NET_TO_HOST_32(value) (ntohl(value)) + +typedef struct { + size_t dataLength; + void * data; +} ENetBuffer; + +#define ENET_CALLBACK __cdecl + +#ifdef ENET_DLL +#ifdef ENET_IMPLEMENTATION + #define ENET_API __declspec( dllexport ) + #else + #define ENET_API __declspec( dllimport ) + #endif // ENET_IMPLEMENTATION +#else +#define ENET_API extern +#endif // ENET_DLL + +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO(&(sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET(socket, &(sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR(socket, &(sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET(socket, &(sockset)) +#else +#include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + #ifdef __APPLE__ + #include + #include + #include + #endif + + #ifndef MSG_NOSIGNAL + #define MSG_NOSIGNAL 0 + #endif + + #ifdef MSG_MAXIOVLEN + #define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN + #endif + + typedef int ENetSocket; + + #define ENET_SOCKET_NULL -1 + + #define ENET_HOST_TO_NET_16(value) (htons(value)) /**< macro that converts host to net byte-order of a 16-bit value */ + #define ENET_HOST_TO_NET_32(value) (htonl(value)) /**< macro that converts host to net byte-order of a 32-bit value */ + + #define ENET_NET_TO_HOST_16(value) (ntohs(value)) /**< macro that converts net to host byte-order of a 16-bit value */ + #define ENET_NET_TO_HOST_32(value) (ntohl(value)) /**< macro that converts net to host byte-order of a 32-bit value */ + + typedef struct { + void * data; + size_t dataLength; + } ENetBuffer; + + #define ENET_CALLBACK + #define ENET_API extern + + typedef fd_set ENetSocketSet; + + #define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO(&(sockset)) + #define ENET_SOCKETSET_ADD(sockset, socket) FD_SET(socket, &(sockset)) + #define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR(socket, &(sockset)) + #define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET(socket, &(sockset)) +#endif + +#ifndef ENET_BUFFER_MAXIMUM +#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) +#endif + +#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#define ENET_IPV6 1 +#define ENET_HOST_ANY in6addr_any +#define ENET_HOST_BROADCAST 0xFFFFFFFFU +#define ENET_PORT_ANY 0 + +#ifdef __cplusplus +extern "C" { +#endif + +// =======================================================================// +// ! +// ! Basic stuff +// ! +// =======================================================================// + +typedef uint8_t enet_uint8; /**< unsigned 8-bit type */ +typedef uint16_t enet_uint16; /**< unsigned 16-bit type */ +typedef uint32_t enet_uint32; /**< unsigned 32-bit type */ +typedef uint64_t enet_uint64; /**< unsigned 64-bit type */ + +typedef enet_uint32 ENetVersion; + +typedef struct _ENetCallbacks { + void *(ENET_CALLBACK *malloc) (size_t size); + void (ENET_CALLBACK *free) (void *memory); + void (ENET_CALLBACK *no_memory) (void); +} ENetCallbacks; + +extern void *enet_malloc(size_t); +extern void enet_free(void *); + +// =======================================================================// +// ! +// ! List +// ! +// =======================================================================// + +typedef struct _ENetListNode { + struct _ENetListNode *next; + struct _ENetListNode *previous; +} ENetListNode; + +typedef ENetListNode *ENetListIterator; + +typedef struct _ENetList { + ENetListNode sentinel; +} ENetList; + +extern ENetListIterator enet_list_insert(ENetListIterator, void *); +extern ENetListIterator enet_list_move(ENetListIterator, void *, void *); + +extern void *enet_list_remove(ENetListIterator); +extern void enet_list_clear(ENetList *); +extern size_t enet_list_size(ENetList *); + +#define enet_list_begin(list) ((list)->sentinel.next) +#define enet_list_end(list) (&(list)->sentinel) +#define enet_list_empty(list) (enet_list_begin(list) == enet_list_end(list)) +#define enet_list_next(iterator) ((iterator)->next) +#define enet_list_previous(iterator) ((iterator)->previous) +#define enet_list_front(list) ((void *)(list)->sentinel.next) +#define enet_list_back(list) ((void *)(list)->sentinel.previous) + + +// =======================================================================// +// ! +// ! Protocol +// ! +// =======================================================================// + +enum { + ENET_PROTOCOL_MINIMUM_MTU = 576, + ENET_PROTOCOL_MAXIMUM_MTU = 4096, + ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32, + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096, + ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536, + ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, + ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, + ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF, + ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024 +}; + +typedef enum _ENetProtocolCommand { + ENET_PROTOCOL_COMMAND_NONE = 0, + ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, + ENET_PROTOCOL_COMMAND_CONNECT = 2, + ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, + ENET_PROTOCOL_COMMAND_DISCONNECT = 4, + ENET_PROTOCOL_COMMAND_PING = 5, + ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, + ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, + ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, + ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, + ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, + ENET_PROTOCOL_COMMAND_COUNT = 13, + + ENET_PROTOCOL_COMMAND_MASK = 0x0F +} ENetProtocolCommand; + +typedef enum _ENetProtocolFlag { + ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), + ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), + + ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), + ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), + ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, + + ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), + ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 +} ENetProtocolFlag; + +#ifdef _MSC_VER +#pragma pack(push, 1) +#define ENET_PACKED +#elif defined(__GNUC__) || defined(__clang__) +#define ENET_PACKED __attribute__ ((packed)) + #else + #define ENET_PACKED +#endif + +typedef struct _ENetProtocolHeader { + enet_uint16 peerID; + enet_uint16 sentTime; +} ENET_PACKED ENetProtocolHeader; + +typedef struct _ENetProtocolCommandHeader { + enet_uint8 command; + enet_uint8 channelID; + enet_uint16 reliableSequenceNumber; +} ENET_PACKED ENetProtocolCommandHeader; + +typedef struct _ENetProtocolAcknowledge { + ENetProtocolCommandHeader header; + enet_uint16 receivedReliableSequenceNumber; + enet_uint16 receivedSentTime; +} ENET_PACKED ENetProtocolAcknowledge; + +typedef struct _ENetProtocolConnect { + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; + enet_uint32 data; +} ENET_PACKED ENetProtocolConnect; + +typedef struct _ENetProtocolVerifyConnect { + ENetProtocolCommandHeader header; + enet_uint16 outgoingPeerID; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 channelCount; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 connectID; +} ENET_PACKED ENetProtocolVerifyConnect; + +typedef struct _ENetProtocolBandwidthLimit { + ENetProtocolCommandHeader header; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; +} ENET_PACKED ENetProtocolBandwidthLimit; + +typedef struct _ENetProtocolThrottleConfigure { + ENetProtocolCommandHeader header; + enet_uint32 packetThrottleInterval; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; +} ENET_PACKED ENetProtocolThrottleConfigure; + +typedef struct _ENetProtocolDisconnect { + ENetProtocolCommandHeader header; + enet_uint32 data; +} ENET_PACKED ENetProtocolDisconnect; + +typedef struct _ENetProtocolPing { + ENetProtocolCommandHeader header; +} ENET_PACKED ENetProtocolPing; + +typedef struct _ENetProtocolSendReliable { + ENetProtocolCommandHeader header; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendReliable; + +typedef struct _ENetProtocolSendUnreliable { + ENetProtocolCommandHeader header; + enet_uint16 unreliableSequenceNumber; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnreliable; + +typedef struct _ENetProtocolSendUnsequenced { + ENetProtocolCommandHeader header; + enet_uint16 unsequencedGroup; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnsequenced; + +typedef struct _ENetProtocolSendFragment { + ENetProtocolCommandHeader header; + enet_uint16 startSequenceNumber; + enet_uint16 dataLength; + enet_uint32 fragmentCount; + enet_uint32 fragmentNumber; + enet_uint32 totalLength; + enet_uint32 fragmentOffset; +} ENET_PACKED ENetProtocolSendFragment; + +typedef union _ENetProtocol { + ENetProtocolCommandHeader header; + ENetProtocolAcknowledge acknowledge; + ENetProtocolConnect connect; + ENetProtocolVerifyConnect verifyConnect; + ENetProtocolDisconnect disconnect; + ENetProtocolPing ping; + ENetProtocolSendReliable sendReliable; + ENetProtocolSendUnreliable sendUnreliable; + ENetProtocolSendUnsequenced sendUnsequenced; + ENetProtocolSendFragment sendFragment; + ENetProtocolBandwidthLimit bandwidthLimit; + ENetProtocolThrottleConfigure throttleConfigure; +} ENET_PACKED ENetProtocol; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif + +// =======================================================================// +// ! +// ! General ENet structs/enums +// ! +// =======================================================================// + +typedef enum _ENetSocketType { + ENET_SOCKET_TYPE_STREAM = 1, + ENET_SOCKET_TYPE_DATAGRAM = 2 +} ENetSocketType; + +typedef enum _ENetSocketWait { + ENET_SOCKET_WAIT_NONE = 0, + ENET_SOCKET_WAIT_SEND = (1 << 0), + ENET_SOCKET_WAIT_RECEIVE = (1 << 1), + ENET_SOCKET_WAIT_INTERRUPT = (1 << 2) +} ENetSocketWait; + +typedef enum _ENetSocketOption { + ENET_SOCKOPT_NONBLOCK = 1, + ENET_SOCKOPT_BROADCAST = 2, + ENET_SOCKOPT_RCVBUF = 3, + ENET_SOCKOPT_SNDBUF = 4, + ENET_SOCKOPT_REUSEADDR = 5, + ENET_SOCKOPT_RCVTIMEO = 6, + ENET_SOCKOPT_SNDTIMEO = 7, + ENET_SOCKOPT_ERROR = 8, + ENET_SOCKOPT_NODELAY = 9, + ENET_SOCKOPT_IPV6_V6ONLY = 10, +} ENetSocketOption; + +typedef enum _ENetSocketShutdown { + ENET_SOCKET_SHUTDOWN_READ = 0, + ENET_SOCKET_SHUTDOWN_WRITE = 1, + ENET_SOCKET_SHUTDOWN_READ_WRITE = 2 +} ENetSocketShutdown; + +/** + * Portable internet address structure. + * + * The host must be specified in network byte-order, and the port must be in host + * byte-order. The constant ENET_HOST_ANY may be used to specify the default + * server host. The constant ENET_HOST_BROADCAST may be used to specify the + * broadcast address (255.255.255.255). This makes sense for enet_host_connect, + * but not for enet_host_create. Once a server responds to a broadcast, the + * address is updated from ENET_HOST_BROADCAST to the server's actual IP address. + */ +typedef struct _ENetAddress { + struct in6_addr host; + enet_uint16 port; + enet_uint16 sin6_scope_id; +} ENetAddress; + +#define in6_equal(in6_addr_a, in6_addr_b) (memcmp(&in6_addr_a, &in6_addr_b, sizeof(struct in6_addr)) == 0) + +/** + * Packet flag bit constants. + * + * The host must be specified in network byte-order, and the port must be in + * host byte-order. The constant ENET_HOST_ANY may be used to specify the + * default server host. + * + * @sa ENetPacket + */ +typedef enum _ENetPacketFlag { + ENET_PACKET_FLAG_RELIABLE = (1 << 0), /** packet must be received by the target peer and resend attempts should be made until the packet is delivered */ + ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), /** packet will not be sequenced with other packets not supported for reliable packets */ + ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2), /** packet will not allocate data, and user must supply it instead */ + ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3), /** packet will be fragmented using unreliable (instead of reliable) sends if it exceeds the MTU */ + ENET_PACKET_FLAG_SENT = (1 << 8), /** whether the packet has been sent from all queues it has been entered into */ +} ENetPacketFlag; + +typedef void (ENET_CALLBACK *ENetPacketFreeCallback)(void *); + +/** + * ENet packet structure. + * + * An ENet data packet that may be sent to or received from a peer. The shown + * fields should only be read and never modified. The data field contains the + * allocated data for the packet. The dataLength fields specifies the length + * of the allocated data. The flags field is either 0 (specifying no flags), + * or a bitwise-or of any combination of the following flags: + * + * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer and resend attempts should be made until the packet is delivered + * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets (not supported for reliable packets) + * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead + * ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable (instead of reliable) sends if it exceeds the MTU + * ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into + * @sa ENetPacketFlag + */ +typedef struct _ENetPacket { + size_t referenceCount; /**< internal use only */ + enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */ + enet_uint8 * data; /**< allocated data for packet */ + size_t dataLength; /**< length of data */ + ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */ + void * userData; /**< application private data, may be freely modified */ +} ENetPacket; + +typedef struct _ENetAcknowledgement { + ENetListNode acknowledgementList; + enet_uint32 sentTime; + ENetProtocol command; +} ENetAcknowledgement; + +typedef struct _ENetOutgoingCommand { + ENetListNode outgoingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + enet_uint32 sentTime; + enet_uint32 roundTripTimeout; + enet_uint32 roundTripTimeoutLimit; + enet_uint32 fragmentOffset; + enet_uint16 fragmentLength; + enet_uint16 sendAttempts; + ENetProtocol command; + ENetPacket * packet; +} ENetOutgoingCommand; + +typedef struct _ENetIncomingCommand { + ENetListNode incomingCommandList; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; + ENetProtocol command; + enet_uint32 fragmentCount; + enet_uint32 fragmentsRemaining; + enet_uint32 *fragments; + ENetPacket * packet; +} ENetIncomingCommand; + +typedef enum _ENetPeerState { + ENET_PEER_STATE_DISCONNECTED = 0, + ENET_PEER_STATE_CONNECTING = 1, + ENET_PEER_STATE_ACKNOWLEDGING_CONNECT = 2, + ENET_PEER_STATE_CONNECTION_PENDING = 3, + ENET_PEER_STATE_CONNECTION_SUCCEEDED = 4, + ENET_PEER_STATE_CONNECTED = 5, + ENET_PEER_STATE_DISCONNECT_LATER = 6, + ENET_PEER_STATE_DISCONNECTING = 7, + ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 8, + ENET_PEER_STATE_ZOMBIE = 9 +} ENetPeerState; + +enum { + ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024, + ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024, + ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000, + ENET_HOST_DEFAULT_MTU = 1400, + ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024, + ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024, + + ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500, + ENET_PEER_DEFAULT_PACKET_THROTTLE = 32, + ENET_PEER_PACKET_THROTTLE_SCALE = 32, + ENET_PEER_PACKET_THROTTLE_COUNTER = 7, + ENET_PEER_PACKET_THROTTLE_ACCELERATION = 2, + ENET_PEER_PACKET_THROTTLE_DECELERATION = 2, + ENET_PEER_PACKET_THROTTLE_INTERVAL = 5000, + ENET_PEER_PACKET_LOSS_SCALE = (1 << 16), + ENET_PEER_PACKET_LOSS_INTERVAL = 10000, + ENET_PEER_WINDOW_SIZE_SCALE = 64 * 1024, + ENET_PEER_TIMEOUT_LIMIT = 32, + ENET_PEER_TIMEOUT_MINIMUM = 5000, + ENET_PEER_TIMEOUT_MAXIMUM = 30000, + ENET_PEER_PING_INTERVAL = 500, + ENET_PEER_UNSEQUENCED_WINDOWS = 64, + ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 1024, + ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32, + ENET_PEER_RELIABLE_WINDOWS = 16, + ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000, + ENET_PEER_FREE_RELIABLE_WINDOWS = 8 +}; + +typedef struct _ENetChannel { + enet_uint16 outgoingReliableSequenceNumber; + enet_uint16 outgoingUnreliableSequenceNumber; + enet_uint16 usedReliableWindows; + enet_uint16 reliableWindows[ENET_PEER_RELIABLE_WINDOWS]; + enet_uint16 incomingReliableSequenceNumber; + enet_uint16 incomingUnreliableSequenceNumber; + ENetList incomingReliableCommands; + ENetList incomingUnreliableCommands; +} ENetChannel; + +/** + * An ENet peer which data packets may be sent or received from. + * + * No fields should be modified unless otherwise specified. + */ +typedef struct _ENetPeer { + ENetListNode dispatchList; + struct _ENetHost *host; + enet_uint16 outgoingPeerID; + enet_uint16 incomingPeerID; + enet_uint32 connectID; + enet_uint8 outgoingSessionID; + enet_uint8 incomingSessionID; + ENetAddress address; /**< Internet address of the peer */ + void * data; /**< Application private data, may be freely modified */ + ENetPeerState state; + ENetChannel * channels; + size_t channelCount; /**< Number of channels allocated for communication with peer */ + enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */ + enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */ + enet_uint32 incomingBandwidthThrottleEpoch; + enet_uint32 outgoingBandwidthThrottleEpoch; + enet_uint32 incomingDataTotal; + enet_uint64 totalDataReceived; + enet_uint32 outgoingDataTotal; + enet_uint64 totalDataSent; + enet_uint32 lastSendTime; + enet_uint32 lastReceiveTime; + enet_uint32 nextTimeout; + enet_uint32 earliestTimeout; + enet_uint32 packetLossEpoch; + enet_uint32 packetsSent; + enet_uint64 totalPacketsSent; /**< total number of packets sent during a session */ + enet_uint32 packetsLost; + enet_uint32 totalPacketsLost; /**< total number of packets lost during a session */ + enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */ + enet_uint32 packetLossVariance; + enet_uint32 packetThrottle; + enet_uint32 packetThrottleLimit; + enet_uint32 packetThrottleCounter; + enet_uint32 packetThrottleEpoch; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 packetThrottleInterval; + enet_uint32 pingInterval; + enet_uint32 timeoutLimit; + enet_uint32 timeoutMinimum; + enet_uint32 timeoutMaximum; + enet_uint32 lastRoundTripTime; + enet_uint32 lowestRoundTripTime; + enet_uint32 lastRoundTripTimeVariance; + enet_uint32 highestRoundTripTimeVariance; + enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */ + enet_uint32 roundTripTimeVariance; + enet_uint32 mtu; + enet_uint32 windowSize; + enet_uint32 reliableDataInTransit; + enet_uint16 outgoingReliableSequenceNumber; + ENetList acknowledgements; + ENetList sentReliableCommands; + ENetList sentUnreliableCommands; + ENetList outgoingReliableCommands; + ENetList outgoingUnreliableCommands; + ENetList dispatchedCommands; + int needsDispatch; + enet_uint16 incomingUnsequencedGroup; + enet_uint16 outgoingUnsequencedGroup; + enet_uint32 unsequencedWindow[ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; + enet_uint32 eventData; + size_t totalWaitingData; +} ENetPeer; + +/** An ENet packet compressor for compressing UDP packets before socket sends or receives. */ +typedef struct _ENetCompressor { + /** Context data for the compressor. Must be non-NULL. */ + void *context; + + /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t(ENET_CALLBACK * compress) (void *context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit); + + /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */ + size_t(ENET_CALLBACK * decompress) (void *context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit); + + /** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */ + void (ENET_CALLBACK * destroy)(void *context); +} ENetCompressor; + +/** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */ +typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback)(const ENetBuffer *buffers, size_t bufferCount); + +/** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */ +typedef int (ENET_CALLBACK * ENetInterceptCallback)(struct _ENetHost *host, void *event); + +/** An ENet host for communicating with peers. + * + * No fields should be modified unless otherwise stated. + * + * @sa enet_host_create() + * @sa enet_host_destroy() + * @sa enet_host_connect() + * @sa enet_host_service() + * @sa enet_host_flush() + * @sa enet_host_broadcast() + * @sa enet_host_compress() + * @sa enet_host_channel_limit() + * @sa enet_host_bandwidth_limit() + * @sa enet_host_bandwidth_throttle() + */ +typedef struct _ENetHost { + ENetSocket socket; + ENetAddress address; /**< Internet address of the host */ + enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ + enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ + enet_uint32 bandwidthThrottleEpoch; + enet_uint32 mtu; + enet_uint32 randomSeed; + int recalculateBandwidthLimits; + ENetPeer * peers; /**< array of peers allocated for this host */ + size_t peerCount; /**< number of peers allocated for this host */ + size_t channelLimit; /**< maximum number of channels allowed for connected peers */ + enet_uint32 serviceTime; + ENetList dispatchQueue; + int continueSending; + size_t packetSize; + enet_uint16 headerFlags; + ENetProtocol commands[ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; + size_t commandCount; + ENetBuffer buffers[ENET_BUFFER_MAXIMUM]; + size_t bufferCount; + ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */ + ENetCompressor compressor; + enet_uint8 packetData[2][ENET_PROTOCOL_MAXIMUM_MTU]; + ENetAddress receivedAddress; + enet_uint8 * receivedData; + size_t receivedDataLength; + enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */ + ENetInterceptCallback intercept; /**< callback the user can set to intercept received raw UDP packets */ + size_t connectedPeers; + size_t bandwidthLimitedPeers; + size_t duplicatePeers; /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */ + size_t maximumPacketSize; /**< the maximum allowable packet size that may be sent or received on a peer */ + size_t maximumWaitingData; /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */ +} ENetHost; + +/** + * An ENet event type, as specified in @ref ENetEvent. + */ +typedef enum _ENetEventType { + /** no event occurred within the specified time limit */ + ENET_EVENT_TYPE_NONE = 0, + + /** a connection request initiated by enet_host_connect has completed. + * The peer field contains the peer which successfully connected. + */ + ENET_EVENT_TYPE_CONNECT = 1, + + /** a peer has disconnected. This event is generated on a successful + * completion of a disconnect initiated by enet_peer_disconnect, if + * a peer has timed out. The peer field contains the peer + * which disconnected. The data field contains user supplied data + * describing the disconnection, or 0, if none is available. + */ + ENET_EVENT_TYPE_DISCONNECT = 2, + + /** a packet has been received from a peer. The peer field specifies the + * peer which sent the packet. The channelID field specifies the channel + * number upon which the packet was received. The packet field contains + * the packet that was received; this packet must be destroyed with + * enet_packet_destroy after use. + */ + ENET_EVENT_TYPE_RECEIVE = 3, + + /** a peer is disconnected because the host didn't receive the acknowledgment + * packet within certain maximum time out. The reason could be because of bad + * network connection or host crashed. + */ + ENET_EVENT_TYPE_DISCONNECT_TIMEOUT = 4, +} ENetEventType; + +/** + * An ENet event as returned by enet_host_service(). + * + * @sa enet_host_service + */ +typedef struct _ENetEvent { + ENetEventType type; /**< type of the event */ + ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */ + enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */ + enet_uint32 data; /**< data associated with the event, if appropriate */ + ENetPacket * packet; /**< packet associated with the event, if appropriate */ +} ENetEvent; + +// =======================================================================// +// ! +// ! Public API +// ! +// =======================================================================// + +/** + * Initializes ENet globally. Must be called prior to using any functions in ENet. + * @returns 0 on success, < 0 on failure + */ +ENET_API int enet_initialize(void); + +/** + * Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored. + * + * @param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use + * @param inits user-overridden callbacks where any NULL callbacks will use ENet's defaults + * @returns 0 on success, < 0 on failure + */ +ENET_API int enet_initialize_with_callbacks(ENetVersion version, const ENetCallbacks * inits); + +/** + * Shuts down ENet globally. Should be called when a program that has initialized ENet exits. + */ +ENET_API void enet_deinitialize(void); + +/** + * Gives the linked version of the ENet library. + * @returns the version number + */ +ENET_API ENetVersion enet_linked_version(void); + +/** Returns the monotonic time in milliseconds. Its initial value is unspecified unless otherwise set. */ +ENET_API enet_uint32 enet_time_get(void); + +/** ENet socket functions */ +ENET_API ENetSocket enet_socket_create(ENetSocketType); +ENET_API int enet_socket_bind(ENetSocket, const ENetAddress *); +ENET_API int enet_socket_get_address(ENetSocket, ENetAddress *); +ENET_API int enet_socket_listen(ENetSocket, int); +ENET_API ENetSocket enet_socket_accept(ENetSocket, ENetAddress *); +ENET_API int enet_socket_connect(ENetSocket, const ENetAddress *); +ENET_API int enet_socket_send(ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); +ENET_API int enet_socket_receive(ENetSocket, ENetAddress *, ENetBuffer *, size_t); +ENET_API int enet_socket_wait(ENetSocket, enet_uint32 *, enet_uint64); +ENET_API int enet_socket_set_option(ENetSocket, ENetSocketOption, int); +ENET_API int enet_socket_get_option(ENetSocket, ENetSocketOption, int *); +ENET_API int enet_socket_shutdown(ENetSocket, ENetSocketShutdown); +ENET_API void enet_socket_destroy(ENetSocket); +ENET_API int enet_socketset_select(ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); + +/** Attempts to parse the printable form of the IP address in the parameter hostName + and sets the host field in the address parameter if successful. + @param address destination to store the parsed IP address + @param hostName IP address to parse + @retval 0 on success + @retval < 0 on failure + @returns the address of the given hostName in address on success +*/ +ENET_API int enet_address_set_host_ip(ENetAddress * address, const char * hostName); + +/** Attempts to resolve the host named by the parameter hostName and sets + the host field in the address parameter if successful. + @param address destination to store resolved address + @param hostName host name to lookup + @retval 0 on success + @retval < 0 on failure + @returns the address of the given hostName in address on success +*/ +ENET_API int enet_address_set_host(ENetAddress * address, const char * hostName); + +/** Gives the printable form of the IP address specified in the address parameter. + @param address address printed + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host_ip(const ENetAddress * address, char * hostName, size_t nameLength); + +/** Attempts to do a reverse lookup of the host field in the address parameter. + @param address address used for reverse lookup + @param hostName destination for name, must not be NULL + @param nameLength maximum length of hostName. + @returns the null-terminated name of the host in hostName on success + @retval 0 on success + @retval < 0 on failure +*/ +ENET_API int enet_address_get_host(const ENetAddress * address, char * hostName, size_t nameLength); + +ENET_API enet_uint32 enet_host_get_peers_count(ENetHost *); +ENET_API enet_uint32 enet_host_get_packets_sent(ENetHost *); +ENET_API enet_uint32 enet_host_get_packets_received(ENetHost *); +ENET_API enet_uint32 enet_host_get_bytes_sent(ENetHost *); +ENET_API enet_uint32 enet_host_get_bytes_received(ENetHost *); +ENET_API enet_uint32 enet_host_get_received_data(ENetHost *, enet_uint8** data); +ENET_API enet_uint32 enet_host_get_mtu(ENetHost *); + +ENET_API enet_uint32 enet_peer_get_id(ENetPeer *); +ENET_API enet_uint32 enet_peer_get_ip(ENetPeer *, char * ip, size_t ipLength); +ENET_API enet_uint16 enet_peer_get_port(ENetPeer *); +ENET_API enet_uint32 enet_peer_get_rtt(ENetPeer *); +ENET_API enet_uint64 enet_peer_get_packets_sent(ENetPeer *); +ENET_API enet_uint32 enet_peer_get_packets_lost(ENetPeer *); +ENET_API enet_uint64 enet_peer_get_bytes_sent(ENetPeer *); +ENET_API enet_uint64 enet_peer_get_bytes_received(ENetPeer *); + +ENET_API ENetPeerState enet_peer_get_state(ENetPeer *); + +ENET_API void * enet_peer_get_data(ENetPeer *); +ENET_API void enet_peer_set_data(ENetPeer *, const void *); + +ENET_API void * enet_packet_get_data(ENetPacket *); +ENET_API enet_uint32 enet_packet_get_length(ENetPacket *); +ENET_API void enet_packet_set_free_callback(ENetPacket *, void *); + +ENET_API ENetPacket * enet_packet_create(const void *, size_t, enet_uint32); +ENET_API ENetPacket * enet_packet_create_offset(const void *, size_t, size_t, enet_uint32); +ENET_API void enet_packet_destroy(ENetPacket *); +ENET_API enet_uint32 enet_crc32(const ENetBuffer *, size_t); + +ENET_API ENetHost * enet_host_create(const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32); +ENET_API void enet_host_destroy(ENetHost *); +ENET_API ENetPeer * enet_host_connect(ENetHost *, const ENetAddress *, size_t, enet_uint32); +ENET_API int enet_host_check_events(ENetHost *, ENetEvent *); +ENET_API int enet_host_service(ENetHost *, ENetEvent *, enet_uint32); +ENET_API int enet_host_send_raw(ENetHost *, const ENetAddress *, enet_uint8 *, size_t); +ENET_API int enet_host_send_raw_ex(ENetHost *host, const ENetAddress* address, enet_uint8* data, size_t skipBytes, size_t bytesToSend); +ENET_API void enet_host_set_intercept(ENetHost *, const ENetInterceptCallback); +ENET_API void enet_host_flush(ENetHost *); +ENET_API void enet_host_broadcast(ENetHost *, enet_uint8, ENetPacket *); +ENET_API void enet_host_compress(ENetHost *, const ENetCompressor *); +ENET_API void enet_host_channel_limit(ENetHost *, size_t); +ENET_API void enet_host_bandwidth_limit(ENetHost *, enet_uint32, enet_uint32); +extern void enet_host_bandwidth_throttle(ENetHost *); +extern enet_uint64 enet_host_random_seed(void); + +ENET_API int enet_peer_send(ENetPeer *, enet_uint8, ENetPacket *); +ENET_API ENetPacket * enet_peer_receive(ENetPeer *, enet_uint8 * channelID); +ENET_API void enet_peer_ping(ENetPeer *); +ENET_API void enet_peer_ping_interval(ENetPeer *, enet_uint32); +ENET_API void enet_peer_timeout(ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +ENET_API void enet_peer_reset(ENetPeer *); +ENET_API void enet_peer_disconnect(ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_now(ENetPeer *, enet_uint32); +ENET_API void enet_peer_disconnect_later(ENetPeer *, enet_uint32); +ENET_API void enet_peer_throttle_configure(ENetPeer *, enet_uint32, enet_uint32, enet_uint32); +extern int enet_peer_throttle(ENetPeer *, enet_uint32); +extern void enet_peer_reset_queues(ENetPeer *); +extern void enet_peer_setup_outgoing_command(ENetPeer *, ENetOutgoingCommand *); +extern ENetOutgoingCommand * enet_peer_queue_outgoing_command(ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16); +extern ENetIncomingCommand * enet_peer_queue_incoming_command(ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32); +extern ENetAcknowledgement * enet_peer_queue_acknowledgement(ENetPeer *, const ENetProtocol *, enet_uint16); +extern void enet_peer_dispatch_incoming_unreliable_commands(ENetPeer *, ENetChannel *); +extern void enet_peer_dispatch_incoming_reliable_commands(ENetPeer *, ENetChannel *); +extern void enet_peer_on_connect(ENetPeer *); +extern void enet_peer_on_disconnect(ENetPeer *); + +extern size_t enet_protocol_command_size (enet_uint8); + +#ifdef __cplusplus +} +#endif + +#if defined(ENET_IMPLEMENTATION) && !defined(ENET_IMPLEMENTATION_DONE) +#define ENET_IMPLEMENTATION_DONE 1 + +#ifdef __cplusplus +extern "C" { +#endif + +// =======================================================================// +// ! +// ! Atomics +// ! +// =======================================================================// + +#if defined(_MSC_VER) + + #define ENET_AT_CASSERT_PRED(predicate) sizeof(char[2 * !!(predicate)-1]) + #define ENET_IS_SUPPORTED_ATOMIC(size) ENET_AT_CASSERT_PRED(size == 1 || size == 2 || size == 4 || size == 8) + #define ENET_ATOMIC_SIZEOF(variable) (ENET_IS_SUPPORTED_ATOMIC(sizeof(*(variable))), sizeof(*(variable))) + + __inline int64_t enet_at_atomic_read(char *ptr, size_t size) + { + switch (size) { + case 1: + return _InterlockedExchangeAdd8((volatile char *)ptr, 0); + case 2: + return _InterlockedExchangeAdd16((volatile SHORT *)ptr, 0); + case 4: + #ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE + return InterlockedExchangeAdd((volatile LONG *)ptr, 0); + #else + return _InterlockedExchangeAdd((volatile LONG *)ptr, 0); + #endif + case 8: + #ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE + return InterlockedExchangeAdd64((volatile LONGLONG *)ptr, 0); + #else + return _InterlockedExchangeAdd64((volatile LONGLONG *)ptr, 0); + #endif + default: + return 0xbad13bad; /* never reached */ + } + } + + __inline int64_t enet_at_atomic_write(char *ptr, int64_t value, size_t size) + { + switch (size) { + case 1: + return _InterlockedExchange8((volatile char *)ptr, (char)value); + case 2: + return _InterlockedExchange16((volatile SHORT *)ptr, (SHORT)value); + case 4: + #ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE + return InterlockedExchange((volatile LONG *)ptr, (LONG)value); + #else + return _InterlockedExchange((volatile LONG *)ptr, (LONG)value); + #endif + case 8: + #ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE + return InterlockedExchange64((volatile LONGLONG *)ptr, (LONGLONG)value); + #else + return _InterlockedExchange64((volatile LONGLONG *)ptr, (LONGLONG)value); + #endif + default: + return 0xbad13bad; /* never reached */ + } + } + + __inline int64_t enet_at_atomic_cas(char *ptr, int64_t new_val, int64_t old_val, size_t size) + { + switch (size) { + case 1: + return _InterlockedCompareExchange8((volatile char *)ptr, (char)new_val, (char)old_val); + case 2: + return _InterlockedCompareExchange16((volatile SHORT *)ptr, (SHORT)new_val, + (SHORT)old_val); + case 4: + #ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE + return InterlockedCompareExchange((volatile LONG *)ptr, (LONG)new_val, (LONG)old_val); + #else + return _InterlockedCompareExchange((volatile LONG *)ptr, (LONG)new_val, (LONG)old_val); + #endif + case 8: + #ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE + return InterlockedCompareExchange64((volatile LONGLONG *)ptr, (LONGLONG)new_val, + (LONGLONG)old_val); + #else + return _InterlockedCompareExchange64((volatile LONGLONG *)ptr, (LONGLONG)new_val, + (LONGLONG)old_val); + #endif + default: + return 0xbad13bad; /* never reached */ + } + } + + __inline int64_t enet_at_atomic_inc(char *ptr, int64_t delta, size_t data_size) + { + switch (data_size) { + case 1: + return _InterlockedExchangeAdd8((volatile char *)ptr, (char)delta); + case 2: + return _InterlockedExchangeAdd16((volatile SHORT *)ptr, (SHORT)delta); + case 4: + #ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE + return InterlockedExchangeAdd((volatile LONG *)ptr, (LONG)delta); + #else + return _InterlockedExchangeAdd((volatile LONG *)ptr, (LONG)delta); + #endif + case 8: + #ifdef NOT_UNDERSCORED_INTERLOCKED_EXCHANGE + return InterlockedExchangeAdd64((volatile LONGLONG *)ptr, (LONGLONG)delta); + #else + return _InterlockedExchangeAdd64((volatile LONGLONG *)ptr, (LONGLONG)delta); + #endif + default: + return 0xbad13bad; /* never reached */ + } + } + + #define ENET_ATOMIC_READ(variable) enet_at_atomic_read((char *)(variable), ENET_ATOMIC_SIZEOF(variable)) + #define ENET_ATOMIC_WRITE(variable, new_val) \ + enet_at_atomic_write((char *)(variable), (int64_t)(new_val), ENET_ATOMIC_SIZEOF(variable)) + #define ENET_ATOMIC_CAS(variable, old_value, new_val) \ + enet_at_atomic_cas((char *)(variable), (int64_t)(new_val), (int64_t)(old_value), \ + ENET_ATOMIC_SIZEOF(variable)) + #define ENET_ATOMIC_INC(variable) enet_at_atomic_inc((char *)(variable), 1, ENET_ATOMIC_SIZEOF(variable)) + #define ENET_ATOMIC_DEC(variable) enet_at_atomic_inc((char *)(variable), -1, ENET_ATOMIC_SIZEOF(variable)) + #define ENET_ATOMIC_INC_BY(variable, delta) \ + enet_at_atomic_inc((char *)(variable), (delta), ENET_ATOMIC_SIZEOF(variable)) + #define ENET_ATOMIC_DEC_BY(variable, delta) \ + enet_at_atomic_inc((char *)(variable), -(delta), ENET_ATOMIC_SIZEOF(variable)) + +#elif defined(__GNUC__) || defined(__clang__) + + #if defined(__clang__) || (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)) + #define AT_HAVE_ATOMICS + #endif + + /* We want to use __atomic built-ins if possible because the __sync primitives are + deprecated, because the __atomic build-ins allow us to use ENET_ATOMIC_WRITE on + uninitialized memory without running into undefined behavior, and because the + __atomic versions generate more efficient code since we don't need to rely on + CAS when we don't actually want it. + + Note that we use acquire-release memory order (like mutexes do). We could use + sequentially consistent memory order but that has lower performance and is + almost always unneeded. */ + #ifdef AT_HAVE_ATOMICS + #define ENET_ATOMIC_READ(ptr) __atomic_load_n((ptr), __ATOMIC_ACQUIRE) + #define ENET_ATOMIC_WRITE(ptr, value) __atomic_store_n((ptr), (value), __ATOMIC_RELEASE) + + #ifndef typeof + #define typeof __typeof__ + #endif + + /* clang_analyzer doesn't know that CAS writes to memory so it complains about + potentially lost data. Replace the code with the equivalent non-sync code. */ + #ifdef __clang_analyzer__ + + #define ENET_ATOMIC_CAS(ptr, old_value, new_value) \ + ({ \ + typeof(*(ptr)) ENET_ATOMIC_CAS_old_actual_ = (*(ptr)); \ + if (ATOMIC_CAS_old_actual_ == (old_value)) { \ + *(ptr) = new_value; \ + } \ + ENET_ATOMIC_CAS_old_actual_; \ + }) + + #else + + /* Could use __auto_type instead of typeof but that shouldn't work in C++. + The ({ }) syntax is a GCC extension called statement expression. It lets + us return a value out of the macro. + + TODO We should return bool here instead of the old value to avoid the ABA + problem. */ + #define ENET_ATOMIC_CAS(ptr, old_value, new_value) \ + ({ \ + typeof(*(ptr)) ENET_ATOMIC_CAS_expected_ = (old_value); \ + __atomic_compare_exchange_n((ptr), &ENET_ATOMIC_CAS_expected_, (new_value), false, \ + __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE); \ + ENET_ATOMIC_CAS_expected_; \ + }) + + #endif /* __clang_analyzer__ */ + + #define ENET_ATOMIC_INC(ptr) __atomic_fetch_add((ptr), 1, __ATOMIC_ACQ_REL) + #define ENET_ATOMIC_DEC(ptr) __atomic_fetch_sub((ptr), 1, __ATOMIC_ACQ_REL) + #define ENET_ATOMIC_INC_BY(ptr, delta) __atomic_fetch_add((ptr), (delta), __ATOMIC_ACQ_REL) + #define ENET_ATOMIC_DEC_BY(ptr, delta) __atomic_fetch_sub((ptr), (delta), __ATOMIC_ACQ_REL) + + #else + + #define ENET_ATOMIC_READ(variable) __sync_fetch_and_add(variable, 0) + #define ENET_ATOMIC_WRITE(variable, new_val) \ + (void) __sync_val_compare_and_swap((variable), *(variable), (new_val)) + #define ENET_ATOMIC_CAS(variable, old_value, new_val) \ + __sync_val_compare_and_swap((variable), (old_value), (new_val)) + #define ENET_ATOMIC_INC(variable) __sync_fetch_and_add((variable), 1) + #define ENET_ATOMIC_DEC(variable) __sync_fetch_and_sub((variable), 1) + #define ENET_ATOMIC_INC_BY(variable, delta) __sync_fetch_and_add((variable), (delta), 1) + #define ENET_ATOMIC_DEC_BY(variable, delta) __sync_fetch_and_sub((variable), (delta), 1) + + #endif /* AT_HAVE_ATOMICS */ + + #undef AT_HAVE_ATOMICS + +#endif /* defined(_MSC_VER) */ + + +// =======================================================================// +// ! +// ! Callbacks +// ! +// =======================================================================// + + static ENetCallbacks callbacks = { malloc, free, abort }; + + int enet_initialize_with_callbacks(ENetVersion version, const ENetCallbacks *inits) { + if (version < ENET_VERSION_CREATE(1, 3, 0)) { + return -1; + } + + if (inits->malloc != NULL || inits->free != NULL) { + if (inits->malloc == NULL || inits->free == NULL) { + return -1; + } + + callbacks.malloc = inits->malloc; + callbacks.free = inits->free; + } + + if (inits->no_memory != NULL) { + callbacks.no_memory = inits->no_memory; + } + + return enet_initialize(); + } + + ENetVersion enet_linked_version(void) { + return ENET_VERSION; + } + + void * enet_malloc(size_t size) { + void *memory = callbacks.malloc(size); + + if (memory == NULL) { + callbacks.no_memory(); + } + + return memory; + } + + void enet_free(void *memory) { + callbacks.free(memory); + } + +// =======================================================================// +// ! +// ! List +// ! +// =======================================================================// + + void enet_list_clear(ENetList *list) { + list->sentinel.next = &list->sentinel; + list->sentinel.previous = &list->sentinel; + } + + ENetListIterator enet_list_insert(ENetListIterator position, void *data) { + ENetListIterator result = (ENetListIterator)data; + + result->previous = position->previous; + result->next = position; + + result->previous->next = result; + position->previous = result; + + return result; + } + + void *enet_list_remove(ENetListIterator position) { + position->previous->next = position->next; + position->next->previous = position->previous; + + return position; + } + + ENetListIterator enet_list_move(ENetListIterator position, void *dataFirst, void *dataLast) { + ENetListIterator first = (ENetListIterator)dataFirst; + ENetListIterator last = (ENetListIterator)dataLast; + + first->previous->next = last->next; + last->next->previous = first->previous; + + first->previous = position->previous; + last->next = position; + + first->previous->next = first; + position->previous = last; + + return first; + } + + size_t enet_list_size(ENetList *list) { + size_t size = 0; + ENetListIterator position; + + for (position = enet_list_begin(list); position != enet_list_end(list); position = enet_list_next(position)) { + ++size; + } + + return size; + } + +// =======================================================================// +// ! +// ! Packet +// ! +// =======================================================================// + + /** + * Creates a packet that may be sent to a peer. + * @param data initial contents of the packet's data; the packet's data will remain uninitialized if data is NULL. + * @param dataLength size of the data allocated for this packet + * @param flags flags for this packet as described for the ENetPacket structure. + * @returns the packet on success, NULL on failure + */ + ENetPacket *enet_packet_create(const void *data, size_t dataLength, enet_uint32 flags) { + ENetPacket *packet; + if (flags & ENET_PACKET_FLAG_NO_ALLOCATE) { + packet = (ENetPacket *)enet_malloc(sizeof (ENetPacket)); + if (packet == NULL) { + return NULL; + } + + packet->data = (enet_uint8 *)data; + } + else { + packet = (ENetPacket *)enet_malloc(sizeof (ENetPacket) + dataLength); + if (packet == NULL) { + return NULL; + } + + packet->data = (enet_uint8 *)packet + sizeof(ENetPacket); + + if (data != NULL) { + memcpy(packet->data, data, dataLength); + } + } + + packet->referenceCount = 0; + packet->flags = flags; + packet->dataLength = dataLength; + packet->freeCallback = NULL; + packet->userData = NULL; + + return packet; + } + + ENetPacket *enet_packet_create_offset(const void *data, size_t dataLength, size_t dataOffset, enet_uint32 flags) { + ENetPacket *packet; + if (flags & ENET_PACKET_FLAG_NO_ALLOCATE) { + packet = (ENetPacket *)enet_malloc(sizeof (ENetPacket)); + if (packet == NULL) { + return NULL; + } + + packet->data = (enet_uint8 *)data; + } + else { + packet = (ENetPacket *)enet_malloc(sizeof (ENetPacket) + dataLength + dataOffset); + if (packet == NULL) { + return NULL; + } + + packet->data = (enet_uint8 *)packet + sizeof(ENetPacket); + + if (data != NULL) { + memcpy(packet->data + dataOffset, data, dataLength); + } + } + + packet->referenceCount = 0; + packet->flags = flags; + packet->dataLength = dataLength + dataOffset; + packet->freeCallback = NULL; + packet->userData = NULL; + + return packet; + } + + /** + * Destroys the packet and deallocates its data. + * @param packet packet to be destroyed + */ + void enet_packet_destroy(ENetPacket *packet) { + if (packet == NULL) { + return; + } + + if (packet->freeCallback != NULL) { + (*packet->freeCallback)((void *)packet); + } + + enet_free(packet); + } + + static int initializedCRC32 = 0; + static enet_uint32 crcTable[256]; + + static enet_uint32 reflect_crc(int val, int bits) { + int result = 0, bit; + + for (bit = 0; bit < bits; bit++) { + if (val & 1) { result |= 1 << (bits - 1 - bit); } + val >>= 1; + } + + return result; + } + + static void initialize_crc32(void) { + int byte; + + for (byte = 0; byte < 256; ++byte) { + enet_uint32 crc = reflect_crc(byte, 8) << 24; + int offset; + + for (offset = 0; offset < 8; ++offset) { + if (crc & 0x80000000) { + crc = (crc << 1) ^ 0x04c11db7; + } else { + crc <<= 1; + } + } + + crcTable[byte] = reflect_crc(crc, 32); + } + + initializedCRC32 = 1; + } + + enet_uint32 enet_crc32(const ENetBuffer *buffers, size_t bufferCount) { + enet_uint32 crc = 0xFFFFFFFF; + + if (!initializedCRC32) { initialize_crc32(); } + + while (bufferCount-- > 0) { + const enet_uint8 *data = (const enet_uint8 *)buffers->data; + const enet_uint8 *dataEnd = &data[buffers->dataLength]; + + while (data < dataEnd) { + crc = (crc >> 8) ^ crcTable[(crc & 0xFF) ^ *data++]; + } + + ++buffers; + } + + return ENET_HOST_TO_NET_32(~crc); + } + +// =======================================================================// +// ! +// ! Protocol +// ! +// =======================================================================// + + static size_t commandSizes[ENET_PROTOCOL_COMMAND_COUNT] = { + 0, + sizeof(ENetProtocolAcknowledge), + sizeof(ENetProtocolConnect), + sizeof(ENetProtocolVerifyConnect), + sizeof(ENetProtocolDisconnect), + sizeof(ENetProtocolPing), + sizeof(ENetProtocolSendReliable), + sizeof(ENetProtocolSendUnreliable), + sizeof(ENetProtocolSendFragment), + sizeof(ENetProtocolSendUnsequenced), + sizeof(ENetProtocolBandwidthLimit), + sizeof(ENetProtocolThrottleConfigure), + sizeof(ENetProtocolSendFragment) + }; + + size_t enet_protocol_command_size(enet_uint8 commandNumber) { + return commandSizes[commandNumber & ENET_PROTOCOL_COMMAND_MASK]; + } + + static void enet_protocol_change_state(ENetHost *host, ENetPeer *peer, ENetPeerState state) { + if (state == ENET_PEER_STATE_CONNECTED || state == ENET_PEER_STATE_DISCONNECT_LATER) { + enet_peer_on_connect(peer); + } else { + enet_peer_on_disconnect(peer); + } + + peer->state = state; + } + + static void enet_protocol_dispatch_state(ENetHost *host, ENetPeer *peer, ENetPeerState state) { + enet_protocol_change_state(host, peer, state); + + if (!peer->needsDispatch) { + enet_list_insert(enet_list_end(&host->dispatchQueue), &peer->dispatchList); + peer->needsDispatch = 1; + } + } + + static int enet_protocol_dispatch_incoming_commands(ENetHost *host, ENetEvent *event) { + while (!enet_list_empty(&host->dispatchQueue)) { + ENetPeer *peer = (ENetPeer *) enet_list_remove(enet_list_begin(&host->dispatchQueue)); + peer->needsDispatch = 0; + + switch (peer->state) { + case ENET_PEER_STATE_CONNECTION_PENDING: + case ENET_PEER_STATE_CONNECTION_SUCCEEDED: + enet_protocol_change_state(host, peer, ENET_PEER_STATE_CONNECTED); + + event->type = ENET_EVENT_TYPE_CONNECT; + event->peer = peer; + event->data = peer->eventData; + + return 1; + + case ENET_PEER_STATE_ZOMBIE: + host->recalculateBandwidthLimits = 1; + + event->type = ENET_EVENT_TYPE_DISCONNECT; + event->peer = peer; + event->data = peer->eventData; + + enet_peer_reset(peer); + + return 1; + + case ENET_PEER_STATE_CONNECTED: + if (enet_list_empty(&peer->dispatchedCommands)) { + continue; + } + + event->packet = enet_peer_receive(peer, &event->channelID); + if (event->packet == NULL) { + continue; + } + + event->type = ENET_EVENT_TYPE_RECEIVE; + event->peer = peer; + + if (!enet_list_empty(&peer->dispatchedCommands)) { + peer->needsDispatch = 1; + enet_list_insert(enet_list_end(&host->dispatchQueue), &peer->dispatchList); + } + + return 1; + + default: + break; + } + } + + return 0; + } /* enet_protocol_dispatch_incoming_commands */ + + static void enet_protocol_notify_connect(ENetHost *host, ENetPeer *peer, ENetEvent *event) { + host->recalculateBandwidthLimits = 1; + + if (event != NULL) { + enet_protocol_change_state(host, peer, ENET_PEER_STATE_CONNECTED); + + peer->totalDataSent = 0; + peer->totalDataReceived = 0; + peer->totalPacketsSent = 0; + peer->totalPacketsLost = 0; + + event->type = ENET_EVENT_TYPE_CONNECT; + event->peer = peer; + event->data = peer->eventData; + } else { + enet_protocol_dispatch_state(host, peer, peer->state == ENET_PEER_STATE_CONNECTING ? ENET_PEER_STATE_CONNECTION_SUCCEEDED : ENET_PEER_STATE_CONNECTION_PENDING); + } + } + + static void enet_protocol_notify_disconnect(ENetHost *host, ENetPeer *peer, ENetEvent *event) { + if (peer->state >= ENET_PEER_STATE_CONNECTION_PENDING) { + host->recalculateBandwidthLimits = 1; + } + + if (peer->state != ENET_PEER_STATE_CONNECTING && peer->state < ENET_PEER_STATE_CONNECTION_SUCCEEDED) { + enet_peer_reset(peer); + } else if (event != NULL) { + event->type = ENET_EVENT_TYPE_DISCONNECT; + event->peer = peer; + event->data = 0; + + enet_peer_reset(peer); + } else { + peer->eventData = 0; + enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); + } + } + + static void enet_protocol_notify_disconnect_timeout (ENetHost * host, ENetPeer * peer, ENetEvent * event) { + if (peer->state >= ENET_PEER_STATE_CONNECTION_PENDING) { + host->recalculateBandwidthLimits = 1; + } + + if (peer->state != ENET_PEER_STATE_CONNECTING && peer->state < ENET_PEER_STATE_CONNECTION_SUCCEEDED) { + enet_peer_reset (peer); + } + else if (event != NULL) { + event->type = ENET_EVENT_TYPE_DISCONNECT_TIMEOUT; + event->peer = peer; + event->data = 0; + + enet_peer_reset(peer); + } + else { + peer->eventData = 0; + enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); + } + } + + static void enet_protocol_remove_sent_unreliable_commands(ENetPeer *peer) { + ENetOutgoingCommand *outgoingCommand; + + while (!enet_list_empty(&peer->sentUnreliableCommands)) { + outgoingCommand = (ENetOutgoingCommand *) enet_list_front(&peer->sentUnreliableCommands); + enet_list_remove(&outgoingCommand->outgoingCommandList); + + if (outgoingCommand->packet != NULL) { + --outgoingCommand->packet->referenceCount; + + if (outgoingCommand->packet->referenceCount == 0) { + outgoingCommand->packet->flags |= ENET_PACKET_FLAG_SENT; + enet_packet_destroy(outgoingCommand->packet); + } + } + + enet_free(outgoingCommand); + } + } + + static ENetProtocolCommand enet_protocol_remove_sent_reliable_command(ENetPeer *peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID) { + ENetOutgoingCommand *outgoingCommand = NULL; + ENetListIterator currentCommand; + ENetProtocolCommand commandNumber; + int wasSent = 1; + + for (currentCommand = enet_list_begin(&peer->sentReliableCommands); + currentCommand != enet_list_end(&peer->sentReliableCommands); + currentCommand = enet_list_next(currentCommand) + ) { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + if (outgoingCommand->reliableSequenceNumber == reliableSequenceNumber && outgoingCommand->command.header.channelID == channelID) { + break; + } + } + + if (currentCommand == enet_list_end(&peer->sentReliableCommands)) { + for (currentCommand = enet_list_begin(&peer->outgoingReliableCommands); + currentCommand != enet_list_end(&peer->outgoingReliableCommands); + currentCommand = enet_list_next(currentCommand) + ) { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + if (outgoingCommand->sendAttempts < 1) { return ENET_PROTOCOL_COMMAND_NONE; } + if (outgoingCommand->reliableSequenceNumber == reliableSequenceNumber && outgoingCommand->command.header.channelID == channelID) { + break; + } + } + + if (currentCommand == enet_list_end(&peer->outgoingReliableCommands)) { + return ENET_PROTOCOL_COMMAND_NONE; + } + + wasSent = 0; + } + + if (outgoingCommand == NULL) { + return ENET_PROTOCOL_COMMAND_NONE; + } + + if (channelID < peer->channelCount) { + ENetChannel *channel = &peer->channels[channelID]; + enet_uint16 reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + if (channel->reliableWindows[reliableWindow] > 0) { + --channel->reliableWindows[reliableWindow]; + if (!channel->reliableWindows[reliableWindow]) { + channel->usedReliableWindows &= ~(1 << reliableWindow); + } + } + } + + commandNumber = (ENetProtocolCommand) (outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK); + enet_list_remove(&outgoingCommand->outgoingCommandList); + + if (outgoingCommand->packet != NULL) { + if (wasSent) { + peer->reliableDataInTransit -= outgoingCommand->fragmentLength; + } + + --outgoingCommand->packet->referenceCount; + + if (outgoingCommand->packet->referenceCount == 0) { + outgoingCommand->packet->flags |= ENET_PACKET_FLAG_SENT; + enet_packet_destroy(outgoingCommand->packet); + } + } + + enet_free(outgoingCommand); + + if (enet_list_empty(&peer->sentReliableCommands)) { + return commandNumber; + } + + outgoingCommand = (ENetOutgoingCommand *) enet_list_front(&peer->sentReliableCommands); + peer->nextTimeout = outgoingCommand->sentTime + outgoingCommand->roundTripTimeout; + + return commandNumber; + } /* enet_protocol_remove_sent_reliable_command */ + + static ENetPeer * enet_protocol_handle_connect(ENetHost *host, ENetProtocolHeader *header, ENetProtocol *command) { + enet_uint8 incomingSessionID, outgoingSessionID; + enet_uint32 mtu, windowSize; + ENetChannel *channel; + size_t channelCount, duplicatePeers = 0; + ENetPeer *currentPeer, *peer = NULL; + ENetProtocol verifyCommand; + + channelCount = ENET_NET_TO_HOST_32(command->connect.channelCount); + + if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) { + return NULL; + } + + for (currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { + if (currentPeer->state == ENET_PEER_STATE_DISCONNECTED) { + if (peer == NULL) { + peer = currentPeer; + } + } else if (currentPeer->state != ENET_PEER_STATE_CONNECTING && in6_equal(currentPeer->address.host, host->receivedAddress.host)) { + if (currentPeer->address.port == host->receivedAddress.port && currentPeer->connectID == command->connect.connectID) { + return NULL; + } + + ++duplicatePeers; + } + } + + if (peer == NULL || duplicatePeers >= host->duplicatePeers) { + return NULL; + } + + if (channelCount > host->channelLimit) { + channelCount = host->channelLimit; + } + peer->channels = (ENetChannel *) enet_malloc(channelCount * sizeof(ENetChannel)); + if (peer->channels == NULL) { + return NULL; + } + peer->channelCount = channelCount; + peer->state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT; + peer->connectID = command->connect.connectID; + peer->address = host->receivedAddress; + peer->outgoingPeerID = ENET_NET_TO_HOST_16(command->connect.outgoingPeerID); + peer->incomingBandwidth = ENET_NET_TO_HOST_32(command->connect.incomingBandwidth); + peer->outgoingBandwidth = ENET_NET_TO_HOST_32(command->connect.outgoingBandwidth); + peer->packetThrottleInterval = ENET_NET_TO_HOST_32(command->connect.packetThrottleInterval); + peer->packetThrottleAcceleration = ENET_NET_TO_HOST_32(command->connect.packetThrottleAcceleration); + peer->packetThrottleDeceleration = ENET_NET_TO_HOST_32(command->connect.packetThrottleDeceleration); + peer->eventData = ENET_NET_TO_HOST_32(command->connect.data); + + incomingSessionID = command->connect.incomingSessionID == 0xFF ? peer->outgoingSessionID : command->connect.incomingSessionID; + incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + if (incomingSessionID == peer->outgoingSessionID) { + incomingSessionID = (incomingSessionID + 1) + & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + } + peer->outgoingSessionID = incomingSessionID; + + outgoingSessionID = command->connect.outgoingSessionID == 0xFF ? peer->incomingSessionID : command->connect.outgoingSessionID; + outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + if (outgoingSessionID == peer->incomingSessionID) { + outgoingSessionID = (outgoingSessionID + 1) + & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + } + peer->incomingSessionID = outgoingSessionID; + + for (channel = peer->channels; channel < &peer->channels[channelCount]; ++channel) { + channel->outgoingReliableSequenceNumber = 0; + channel->outgoingUnreliableSequenceNumber = 0; + channel->incomingReliableSequenceNumber = 0; + channel->incomingUnreliableSequenceNumber = 0; + + enet_list_clear(&channel->incomingReliableCommands); + enet_list_clear(&channel->incomingUnreliableCommands); + + channel->usedReliableWindows = 0; + memset(channel->reliableWindows, 0, sizeof(channel->reliableWindows)); + } + + mtu = ENET_NET_TO_HOST_32(command->connect.mtu); + + if (mtu < ENET_PROTOCOL_MINIMUM_MTU) { + mtu = ENET_PROTOCOL_MINIMUM_MTU; + } else if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) { + mtu = ENET_PROTOCOL_MAXIMUM_MTU; + } + + peer->mtu = mtu; + + if (host->outgoingBandwidth == 0 && peer->incomingBandwidth == 0) { + peer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + } else if (host->outgoingBandwidth == 0 || peer->incomingBandwidth == 0) { + peer->windowSize = (ENET_MAX(host->outgoingBandwidth, peer->incomingBandwidth) / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + } else { + peer->windowSize = (ENET_MIN(host->outgoingBandwidth, peer->incomingBandwidth) / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + } + + if (peer->windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) { + peer->windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + } else if (peer->windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) { + peer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + } + + if (host->incomingBandwidth == 0) { + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + } else { + windowSize = (host->incomingBandwidth / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + } + + if (windowSize > ENET_NET_TO_HOST_32(command->connect.windowSize)) { + windowSize = ENET_NET_TO_HOST_32(command->connect.windowSize); + } + + if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) { + windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + } else if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) { + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + } + + verifyCommand.header.command = ENET_PROTOCOL_COMMAND_VERIFY_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + verifyCommand.header.channelID = 0xFF; + verifyCommand.verifyConnect.outgoingPeerID = ENET_HOST_TO_NET_16(peer->incomingPeerID); + verifyCommand.verifyConnect.incomingSessionID = incomingSessionID; + verifyCommand.verifyConnect.outgoingSessionID = outgoingSessionID; + verifyCommand.verifyConnect.mtu = ENET_HOST_TO_NET_32(peer->mtu); + verifyCommand.verifyConnect.windowSize = ENET_HOST_TO_NET_32(windowSize); + verifyCommand.verifyConnect.channelCount = ENET_HOST_TO_NET_32(channelCount); + verifyCommand.verifyConnect.incomingBandwidth = ENET_HOST_TO_NET_32(host->incomingBandwidth); + verifyCommand.verifyConnect.outgoingBandwidth = ENET_HOST_TO_NET_32(host->outgoingBandwidth); + verifyCommand.verifyConnect.packetThrottleInterval = ENET_HOST_TO_NET_32(peer->packetThrottleInterval); + verifyCommand.verifyConnect.packetThrottleAcceleration = ENET_HOST_TO_NET_32(peer->packetThrottleAcceleration); + verifyCommand.verifyConnect.packetThrottleDeceleration = ENET_HOST_TO_NET_32(peer->packetThrottleDeceleration); + verifyCommand.verifyConnect.connectID = peer->connectID; + + enet_peer_queue_outgoing_command(peer, &verifyCommand, NULL, 0, 0); + return peer; + } /* enet_protocol_handle_connect */ + + static int enet_protocol_handle_send_reliable(ENetHost *host, ENetPeer *peer, const ENetProtocol *command, enet_uint8 **currentData) { + size_t dataLength; + + if (command->header.channelID >= peer->channelCount || (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER)) { + return -1; + } + + dataLength = ENET_NET_TO_HOST_16(command->sendReliable.dataLength); + *currentData += dataLength; + + if (dataLength > host->maximumPacketSize || *currentData < host->receivedData || *currentData > &host->receivedData[host->receivedDataLength]) { + return -1; + } + + if (enet_peer_queue_incoming_command(peer, command, (const enet_uint8 *) command + sizeof(ENetProtocolSendReliable), dataLength, ENET_PACKET_FLAG_RELIABLE, 0) == NULL) { + return -1; + } + + return 0; + } + + static int enet_protocol_handle_send_unsequenced(ENetHost *host, ENetPeer *peer, const ENetProtocol *command, enet_uint8 **currentData) { + enet_uint32 unsequencedGroup, index; + size_t dataLength; + + if (command->header.channelID >= peer->channelCount || (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER)) { + return -1; + } + + dataLength = ENET_NET_TO_HOST_16(command->sendUnsequenced.dataLength); + *currentData += dataLength; + if (dataLength > host->maximumPacketSize || *currentData < host->receivedData || *currentData > &host->receivedData[host->receivedDataLength]) { + return -1; + } + + unsequencedGroup = ENET_NET_TO_HOST_16(command->sendUnsequenced.unsequencedGroup); + index = unsequencedGroup % ENET_PEER_UNSEQUENCED_WINDOW_SIZE; + + if (unsequencedGroup < peer->incomingUnsequencedGroup) { + unsequencedGroup += 0x10000; + } + + if (unsequencedGroup >= (enet_uint32) peer->incomingUnsequencedGroup + ENET_PEER_FREE_UNSEQUENCED_WINDOWS * ENET_PEER_UNSEQUENCED_WINDOW_SIZE) { + return 0; + } + + unsequencedGroup &= 0xFFFF; + + if (unsequencedGroup - index != peer->incomingUnsequencedGroup) { + peer->incomingUnsequencedGroup = unsequencedGroup - index; + memset(peer->unsequencedWindow, 0, sizeof(peer->unsequencedWindow)); + } else if (peer->unsequencedWindow[index / 32] & (1 << (index % 32))) { + return 0; + } + + if (enet_peer_queue_incoming_command(peer, command, (const enet_uint8 *) command + sizeof(ENetProtocolSendUnsequenced), dataLength, ENET_PACKET_FLAG_UNSEQUENCED,0) == NULL) { + return -1; + } + + peer->unsequencedWindow[index / 32] |= 1 << (index % 32); + + return 0; + } /* enet_protocol_handle_send_unsequenced */ + + static int enet_protocol_handle_send_unreliable(ENetHost *host, ENetPeer *peer, const ENetProtocol *command, + enet_uint8 **currentData) { + size_t dataLength; + + if (command->header.channelID >= peer->channelCount || + (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER)) + { + return -1; + } + + dataLength = ENET_NET_TO_HOST_16(command->sendUnreliable.dataLength); + *currentData += dataLength; + if (dataLength > host->maximumPacketSize || *currentData < host->receivedData || *currentData > &host->receivedData[host->receivedDataLength]) { + return -1; + } + + if (enet_peer_queue_incoming_command(peer, command, (const enet_uint8 *) command + sizeof(ENetProtocolSendUnreliable), dataLength, 0, 0) == NULL) { + return -1; + } + + return 0; + } + + static int enet_protocol_handle_send_fragment(ENetHost *host, ENetPeer *peer, const ENetProtocol *command, enet_uint8 **currentData) { + enet_uint32 fragmentNumber, fragmentCount, fragmentOffset, fragmentLength, startSequenceNumber, totalLength; + ENetChannel *channel; + enet_uint16 startWindow, currentWindow; + ENetListIterator currentCommand; + ENetIncomingCommand *startCommand = NULL; + + if (command->header.channelID >= peer->channelCount || (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER)) { + return -1; + } + + fragmentLength = ENET_NET_TO_HOST_16(command->sendFragment.dataLength); + *currentData += fragmentLength; + if (fragmentLength > host->maximumPacketSize || *currentData < host->receivedData || *currentData > &host->receivedData[host->receivedDataLength]) { + return -1; + } + + channel = &peer->channels[command->header.channelID]; + startSequenceNumber = ENET_NET_TO_HOST_16(command->sendFragment.startSequenceNumber); + startWindow = startSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + currentWindow = channel->incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (startSequenceNumber < channel->incomingReliableSequenceNumber) { + startWindow += ENET_PEER_RELIABLE_WINDOWS; + } + + if (startWindow < currentWindow || startWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) { + return 0; + } + + fragmentNumber = ENET_NET_TO_HOST_32(command->sendFragment.fragmentNumber); + fragmentCount = ENET_NET_TO_HOST_32(command->sendFragment.fragmentCount); + fragmentOffset = ENET_NET_TO_HOST_32(command->sendFragment.fragmentOffset); + totalLength = ENET_NET_TO_HOST_32(command->sendFragment.totalLength); + + if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT || + fragmentNumber >= fragmentCount || + totalLength > host->maximumPacketSize || + fragmentOffset >= totalLength || + fragmentLength > totalLength - fragmentOffset + ) { + return -1; + } + + for (currentCommand = enet_list_previous(enet_list_end(&channel->incomingReliableCommands)); + currentCommand != enet_list_end(&channel->incomingReliableCommands); + currentCommand = enet_list_previous(currentCommand) + ) { + ENetIncomingCommand *incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (startSequenceNumber >= channel->incomingReliableSequenceNumber) { + if (incomingCommand->reliableSequenceNumber < channel->incomingReliableSequenceNumber) { + continue; + } + } else if (incomingCommand->reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { + break; + } + + if (incomingCommand->reliableSequenceNumber <= startSequenceNumber) { + if (incomingCommand->reliableSequenceNumber < startSequenceNumber) { + break; + } + + if ((incomingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK) != + ENET_PROTOCOL_COMMAND_SEND_FRAGMENT || + totalLength != incomingCommand->packet->dataLength || + fragmentCount != incomingCommand->fragmentCount + ) { + return -1; + } + + startCommand = incomingCommand; + break; + } + } + + if (startCommand == NULL) { + ENetProtocol hostCommand = *command; + hostCommand.header.reliableSequenceNumber = startSequenceNumber; + startCommand = enet_peer_queue_incoming_command(peer, &hostCommand, NULL, totalLength, ENET_PACKET_FLAG_RELIABLE, fragmentCount); + if (startCommand == NULL) { + return -1; + } + } + + if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) { + --startCommand->fragmentsRemaining; + startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + + if (fragmentOffset + fragmentLength > startCommand->packet->dataLength) { + fragmentLength = startCommand->packet->dataLength - fragmentOffset; + } + + memcpy(startCommand->packet->data + fragmentOffset, (enet_uint8 *) command + sizeof(ENetProtocolSendFragment), fragmentLength); + + if (startCommand->fragmentsRemaining <= 0) { + enet_peer_dispatch_incoming_reliable_commands(peer, channel); + } + } + + return 0; + } /* enet_protocol_handle_send_fragment */ + + static int enet_protocol_handle_send_unreliable_fragment(ENetHost *host, ENetPeer *peer, const ENetProtocol *command, enet_uint8 **currentData) { + enet_uint32 fragmentNumber, fragmentCount, fragmentOffset, fragmentLength, reliableSequenceNumber, startSequenceNumber, totalLength; + enet_uint16 reliableWindow, currentWindow; + ENetChannel *channel; + ENetListIterator currentCommand; + ENetIncomingCommand *startCommand = NULL; + + if (command->header.channelID >= peer->channelCount || (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER)) { + return -1; + } + + fragmentLength = ENET_NET_TO_HOST_16(command->sendFragment.dataLength); + *currentData += fragmentLength; + if (fragmentLength > host->maximumPacketSize || *currentData < host->receivedData || *currentData > &host->receivedData[host->receivedDataLength]) { + return -1; + } + + channel = &peer->channels[command->header.channelID]; + reliableSequenceNumber = command->header.reliableSequenceNumber; + startSequenceNumber = ENET_NET_TO_HOST_16(command->sendFragment.startSequenceNumber); + + reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + currentWindow = channel->incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (reliableSequenceNumber < channel->incomingReliableSequenceNumber) { + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + } + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) { + return 0; + } + + if (reliableSequenceNumber == channel->incomingReliableSequenceNumber && startSequenceNumber <= channel->incomingUnreliableSequenceNumber) { + return 0; + } + + fragmentNumber = ENET_NET_TO_HOST_32(command->sendFragment.fragmentNumber); + fragmentCount = ENET_NET_TO_HOST_32(command->sendFragment.fragmentCount); + fragmentOffset = ENET_NET_TO_HOST_32(command->sendFragment.fragmentOffset); + totalLength = ENET_NET_TO_HOST_32(command->sendFragment.totalLength); + + if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT || + fragmentNumber >= fragmentCount || + totalLength > host->maximumPacketSize || + fragmentOffset >= totalLength || + fragmentLength > totalLength - fragmentOffset + ) { + return -1; + } + + for (currentCommand = enet_list_previous(enet_list_end(&channel->incomingUnreliableCommands)); + currentCommand != enet_list_end(&channel->incomingUnreliableCommands); + currentCommand = enet_list_previous(currentCommand) + ) { + ENetIncomingCommand *incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { + if (incomingCommand->reliableSequenceNumber < channel->incomingReliableSequenceNumber) { + continue; + } + } else if (incomingCommand->reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { + break; + } + + if (incomingCommand->reliableSequenceNumber < reliableSequenceNumber) { + break; + } + + if (incomingCommand->reliableSequenceNumber > reliableSequenceNumber) { + continue; + } + + if (incomingCommand->unreliableSequenceNumber <= startSequenceNumber) { + if (incomingCommand->unreliableSequenceNumber < startSequenceNumber) { + break; + } + + if ((incomingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK) != + ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT || + totalLength != incomingCommand->packet->dataLength || + fragmentCount != incomingCommand->fragmentCount + ) { + return -1; + } + + startCommand = incomingCommand; + break; + } + } + + if (startCommand == NULL) { + startCommand = enet_peer_queue_incoming_command(peer, command, NULL, totalLength, + ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT, fragmentCount); + if (startCommand == NULL) { + return -1; + } + } + + if ((startCommand->fragments[fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) { + --startCommand->fragmentsRemaining; + startCommand->fragments[fragmentNumber / 32] |= (1 << (fragmentNumber % 32)); + + if (fragmentOffset + fragmentLength > startCommand->packet->dataLength) { + fragmentLength = startCommand->packet->dataLength - fragmentOffset; + } + + memcpy(startCommand->packet->data + fragmentOffset, (enet_uint8 *) command + sizeof(ENetProtocolSendFragment), fragmentLength); + + if (startCommand->fragmentsRemaining <= 0) { + enet_peer_dispatch_incoming_unreliable_commands(peer, channel); + } + } + + return 0; + } /* enet_protocol_handle_send_unreliable_fragment */ + + static int enet_protocol_handle_ping(ENetHost *host, ENetPeer *peer, const ENetProtocol *command) { + if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { + return -1; + } + + return 0; + } + + static int enet_protocol_handle_bandwidth_limit(ENetHost *host, ENetPeer *peer, const ENetProtocol *command) { + if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { + return -1; + } + + if (peer->incomingBandwidth != 0) { + --host->bandwidthLimitedPeers; + } + + peer->incomingBandwidth = ENET_NET_TO_HOST_32(command->bandwidthLimit.incomingBandwidth); + peer->outgoingBandwidth = ENET_NET_TO_HOST_32(command->bandwidthLimit.outgoingBandwidth); + + if (peer->incomingBandwidth != 0) { + ++host->bandwidthLimitedPeers; + } + + if (peer->incomingBandwidth == 0 && host->outgoingBandwidth == 0) { + peer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + } else if (peer->incomingBandwidth == 0 || host->outgoingBandwidth == 0) { + peer->windowSize = (ENET_MAX(peer->incomingBandwidth, host->outgoingBandwidth) + / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + } else { + peer->windowSize = (ENET_MIN(peer->incomingBandwidth, host->outgoingBandwidth) + / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + } + + if (peer->windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) { + peer->windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + } else if (peer->windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) { + peer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + } + + return 0; + } /* enet_protocol_handle_bandwidth_limit */ + + static int enet_protocol_handle_throttle_configure(ENetHost *host, ENetPeer *peer, const ENetProtocol *command) { + if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { + return -1; + } + + peer->packetThrottleInterval = ENET_NET_TO_HOST_32(command->throttleConfigure.packetThrottleInterval); + peer->packetThrottleAcceleration = ENET_NET_TO_HOST_32(command->throttleConfigure.packetThrottleAcceleration); + peer->packetThrottleDeceleration = ENET_NET_TO_HOST_32(command->throttleConfigure.packetThrottleDeceleration); + + return 0; + } + + static int enet_protocol_handle_disconnect(ENetHost *host, ENetPeer *peer, const ENetProtocol *command) { + if (peer->state == ENET_PEER_STATE_DISCONNECTED || peer->state == ENET_PEER_STATE_ZOMBIE || + peer->state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT + ) { + return 0; + } + + enet_peer_reset_queues(peer); + + if (peer->state == ENET_PEER_STATE_CONNECTION_SUCCEEDED || peer->state == ENET_PEER_STATE_DISCONNECTING || peer->state == ENET_PEER_STATE_CONNECTING) { + enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); + } + else if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { + if (peer->state == ENET_PEER_STATE_CONNECTION_PENDING) { host->recalculateBandwidthLimits = 1; } + enet_peer_reset(peer); + } + else if (command->header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) { + enet_protocol_change_state(host, peer, ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT); + } + else { + enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); + } + + if (peer->state != ENET_PEER_STATE_DISCONNECTED) { + peer->eventData = ENET_NET_TO_HOST_32(command->disconnect.data); + } + + return 0; + } + + static int enet_protocol_handle_acknowledge(ENetHost *host, ENetEvent *event, ENetPeer *peer, const ENetProtocol *command) { + enet_uint32 roundTripTime, receivedSentTime, receivedReliableSequenceNumber; + ENetProtocolCommand commandNumber; + + if (peer->state == ENET_PEER_STATE_DISCONNECTED || peer->state == ENET_PEER_STATE_ZOMBIE) { + return 0; + } + + receivedSentTime = ENET_NET_TO_HOST_16(command->acknowledge.receivedSentTime); + receivedSentTime |= host->serviceTime & 0xFFFF0000; + if ((receivedSentTime & 0x8000) > (host->serviceTime & 0x8000)) { + receivedSentTime -= 0x10000; + } + + if (ENET_TIME_LESS(host->serviceTime, receivedSentTime)) { + return 0; + } + + peer->lastReceiveTime = host->serviceTime; + peer->earliestTimeout = 0; + roundTripTime = ENET_TIME_DIFFERENCE(host->serviceTime, receivedSentTime); + + enet_peer_throttle(peer, roundTripTime); + peer->roundTripTimeVariance -= peer->roundTripTimeVariance / 4; + + if (roundTripTime >= peer->roundTripTime) { + peer->roundTripTime += (roundTripTime - peer->roundTripTime) / 8; + peer->roundTripTimeVariance += (roundTripTime - peer->roundTripTime) / 4; + } else { + peer->roundTripTime -= (peer->roundTripTime - roundTripTime) / 8; + peer->roundTripTimeVariance += (peer->roundTripTime - roundTripTime) / 4; + } + + if (peer->roundTripTime < peer->lowestRoundTripTime) { + peer->lowestRoundTripTime = peer->roundTripTime; + } + + if (peer->roundTripTimeVariance > peer->highestRoundTripTimeVariance) { + peer->highestRoundTripTimeVariance = peer->roundTripTimeVariance; + } + + if (peer->packetThrottleEpoch == 0 || + ENET_TIME_DIFFERENCE(host->serviceTime, peer->packetThrottleEpoch) >= peer->packetThrottleInterval + ) { + peer->lastRoundTripTime = peer->lowestRoundTripTime; + peer->lastRoundTripTimeVariance = peer->highestRoundTripTimeVariance; + peer->lowestRoundTripTime = peer->roundTripTime; + peer->highestRoundTripTimeVariance = peer->roundTripTimeVariance; + peer->packetThrottleEpoch = host->serviceTime; + } + + receivedReliableSequenceNumber = ENET_NET_TO_HOST_16(command->acknowledge.receivedReliableSequenceNumber); + commandNumber = enet_protocol_remove_sent_reliable_command(peer, receivedReliableSequenceNumber, command->header.channelID); + + switch (peer->state) { + case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: + if (commandNumber != ENET_PROTOCOL_COMMAND_VERIFY_CONNECT) { + return -1; + } + + enet_protocol_notify_connect(host, peer, event); + break; + + case ENET_PEER_STATE_DISCONNECTING: + if (commandNumber != ENET_PROTOCOL_COMMAND_DISCONNECT) { + return -1; + } + + enet_protocol_notify_disconnect(host, peer, event); + break; + + case ENET_PEER_STATE_DISCONNECT_LATER: + if (enet_list_empty(&peer->outgoingReliableCommands) && + enet_list_empty(&peer->outgoingUnreliableCommands) && + enet_list_empty(&peer->sentReliableCommands)) + { + enet_peer_disconnect(peer, peer->eventData); + } + break; + + default: + break; + } + + return 0; + } /* enet_protocol_handle_acknowledge */ + + static int enet_protocol_handle_verify_connect(ENetHost *host, ENetEvent *event, ENetPeer *peer, const ENetProtocol *command) { + enet_uint32 mtu, windowSize; + size_t channelCount; + + if (peer->state != ENET_PEER_STATE_CONNECTING) { + return 0; + } + + channelCount = ENET_NET_TO_HOST_32(command->verifyConnect.channelCount); + + if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT || + ENET_NET_TO_HOST_32(command->verifyConnect.packetThrottleInterval) != peer->packetThrottleInterval || + ENET_NET_TO_HOST_32(command->verifyConnect.packetThrottleAcceleration) != peer->packetThrottleAcceleration || + ENET_NET_TO_HOST_32(command->verifyConnect.packetThrottleDeceleration) != peer->packetThrottleDeceleration || + command->verifyConnect.connectID != peer->connectID + ) { + peer->eventData = 0; + enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); + return -1; + } + + enet_protocol_remove_sent_reliable_command(peer, 1, 0xFF); + + if (channelCount < peer->channelCount) { + peer->channelCount = channelCount; + } + + peer->outgoingPeerID = ENET_NET_TO_HOST_16(command->verifyConnect.outgoingPeerID); + peer->incomingSessionID = command->verifyConnect.incomingSessionID; + peer->outgoingSessionID = command->verifyConnect.outgoingSessionID; + + mtu = ENET_NET_TO_HOST_32(command->verifyConnect.mtu); + + if (mtu < ENET_PROTOCOL_MINIMUM_MTU) { + mtu = ENET_PROTOCOL_MINIMUM_MTU; + } else if (mtu > ENET_PROTOCOL_MAXIMUM_MTU) { + mtu = ENET_PROTOCOL_MAXIMUM_MTU; + } + + if (mtu < peer->mtu) { + peer->mtu = mtu; + } + + windowSize = ENET_NET_TO_HOST_32(command->verifyConnect.windowSize); + if (windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) { + windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + } + + if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) { + windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + } + + if (windowSize < peer->windowSize) { + peer->windowSize = windowSize; + } + + peer->incomingBandwidth = ENET_NET_TO_HOST_32(command->verifyConnect.incomingBandwidth); + peer->outgoingBandwidth = ENET_NET_TO_HOST_32(command->verifyConnect.outgoingBandwidth); + + enet_protocol_notify_connect(host, peer, event); + return 0; + } /* enet_protocol_handle_verify_connect */ + + static int enet_protocol_handle_incoming_commands(ENetHost *host, ENetEvent *event) { + ENetProtocolHeader *header; + ENetProtocol *command; + ENetPeer *peer; + enet_uint8 *currentData; + size_t headerSize; + enet_uint16 peerID, flags; + enet_uint8 sessionID; + + if (host->receivedDataLength < (size_t) &((ENetProtocolHeader *) 0)->sentTime) { + return 0; + } + + header = (ENetProtocolHeader *) host->receivedData; + + peerID = ENET_NET_TO_HOST_16(header->peerID); + sessionID = (peerID & ENET_PROTOCOL_HEADER_SESSION_MASK) >> ENET_PROTOCOL_HEADER_SESSION_SHIFT; + flags = peerID & ENET_PROTOCOL_HEADER_FLAG_MASK; + peerID &= ~(ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK); + + headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof(ENetProtocolHeader) : (size_t) &((ENetProtocolHeader *) 0)->sentTime); + if (host->checksum != NULL) { + headerSize += sizeof(enet_uint32); + } + + if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID) { + peer = NULL; + } else if (peerID >= host->peerCount) { + return 0; + } else { + peer = &host->peers[peerID]; + + if (peer->state == ENET_PEER_STATE_DISCONNECTED || + peer->state == ENET_PEER_STATE_ZOMBIE || + ((!in6_equal(host->receivedAddress.host , peer->address.host) || + host->receivedAddress.port != peer->address.port) && + 1 /* no broadcast in ipv6 !in6_equal(peer->address.host , ENET_HOST_BROADCAST)*/) || + (peer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID && + sessionID != peer->incomingSessionID) + ) { + return 0; + } + } + + if (flags & ENET_PROTOCOL_HEADER_FLAG_COMPRESSED) { + size_t originalSize; + if (host->compressor.context == NULL || host->compressor.decompress == NULL) { + return 0; + } + + originalSize = host->compressor.decompress(host->compressor.context, + host->receivedData + headerSize, + host->receivedDataLength - headerSize, + host->packetData[1] + headerSize, + sizeof(host->packetData[1]) - headerSize + ); + + if (originalSize <= 0 || originalSize > sizeof(host->packetData[1]) - headerSize) { + return 0; + } + + memcpy(host->packetData[1], header, headerSize); + host->receivedData = host->packetData[1]; + host->receivedDataLength = headerSize + originalSize; + } + + if (host->checksum != NULL) { + enet_uint32 *checksum = (enet_uint32 *) &host->receivedData[headerSize - sizeof(enet_uint32)]; + enet_uint32 desiredChecksum = *checksum; + ENetBuffer buffer; + + *checksum = peer != NULL ? peer->connectID : 0; + + buffer.data = host->receivedData; + buffer.dataLength = host->receivedDataLength; + + if (host->checksum(&buffer, 1) != desiredChecksum) { + return 0; + } + } + + if (peer != NULL) { + peer->address.host = host->receivedAddress.host; + peer->address.port = host->receivedAddress.port; + peer->incomingDataTotal += host->receivedDataLength; + peer->totalDataReceived += host->receivedDataLength; + } + + currentData = host->receivedData + headerSize; + + while (currentData < &host->receivedData[host->receivedDataLength]) { + enet_uint8 commandNumber; + size_t commandSize; + + command = (ENetProtocol *) currentData; + + if (currentData + sizeof(ENetProtocolCommandHeader) > &host->receivedData[host->receivedDataLength]) { + break; + } + + commandNumber = command->header.command & ENET_PROTOCOL_COMMAND_MASK; + if (commandNumber >= ENET_PROTOCOL_COMMAND_COUNT) { + break; + } + + commandSize = commandSizes[commandNumber]; + if (commandSize == 0 || currentData + commandSize > &host->receivedData[host->receivedDataLength]) { + break; + } + + currentData += commandSize; + + if (peer == NULL && (commandNumber != ENET_PROTOCOL_COMMAND_CONNECT || currentData < &host->receivedData[host->receivedDataLength])) { + break; + } + + command->header.reliableSequenceNumber = ENET_NET_TO_HOST_16(command->header.reliableSequenceNumber); + + switch (commandNumber) { + case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE: + if (enet_protocol_handle_acknowledge(host, event, peer, command)) { + goto commandError; + } + break; + + case ENET_PROTOCOL_COMMAND_CONNECT: + if (peer != NULL) { + goto commandError; + } + peer = enet_protocol_handle_connect(host, header, command); + if (peer == NULL) { + goto commandError; + } + break; + + case ENET_PROTOCOL_COMMAND_VERIFY_CONNECT: + if (enet_protocol_handle_verify_connect(host, event, peer, command)) { + goto commandError; + } + break; + + case ENET_PROTOCOL_COMMAND_DISCONNECT: + if (enet_protocol_handle_disconnect(host, peer, command)) { + goto commandError; + } + break; + + case ENET_PROTOCOL_COMMAND_PING: + if (enet_protocol_handle_ping(host, peer, command)) { + goto commandError; + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: + if (enet_protocol_handle_send_reliable(host, peer, command, ¤tData)) { + goto commandError; + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: + if (enet_protocol_handle_send_unreliable(host, peer, command, ¤tData)) { + goto commandError; + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + if (enet_protocol_handle_send_unsequenced(host, peer, command, ¤tData)) { + goto commandError; + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + if (enet_protocol_handle_send_fragment(host, peer, command, ¤tData)) { + goto commandError; + } + break; + + case ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT: + if (enet_protocol_handle_bandwidth_limit(host, peer, command)) { + goto commandError; + } + break; + + case ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE: + if (enet_protocol_handle_throttle_configure(host, peer, command)) { + goto commandError; + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT: + if (enet_protocol_handle_send_unreliable_fragment(host, peer, command, ¤tData)) { + goto commandError; + } + break; + + default: + goto commandError; + } + + if (peer != NULL && (command->header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0) { + enet_uint16 sentTime; + + if (!(flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)) { + break; + } + + sentTime = ENET_NET_TO_HOST_16(header->sentTime); + + switch (peer->state) { + case ENET_PEER_STATE_DISCONNECTING: + case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: + case ENET_PEER_STATE_DISCONNECTED: + case ENET_PEER_STATE_ZOMBIE: + break; + + case ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT: + if ((command->header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) { + enet_peer_queue_acknowledgement(peer, command, sentTime); + } + break; + + default: + enet_peer_queue_acknowledgement(peer, command, sentTime); + break; + } + } + } + + commandError: + if (event != NULL && event->type != ENET_EVENT_TYPE_NONE) { + return 1; + } + + return 0; + } /* enet_protocol_handle_incoming_commands */ + + static int enet_protocol_receive_incoming_commands(ENetHost *host, ENetEvent *event) { + int packets; + + for (packets = 0; packets < 256; ++packets) { + int receivedLength; + ENetBuffer buffer; + + buffer.data = host->packetData[0]; + // buffer.dataLength = sizeof (host->packetData[0]); + buffer.dataLength = host->mtu; + + receivedLength = enet_socket_receive(host->socket, &host->receivedAddress, &buffer, 1); + + if (receivedLength == -2) + continue; + + if (receivedLength < 0) { + return -1; + } + + if (receivedLength == 0) { + return 0; + } + + host->receivedData = host->packetData[0]; + host->receivedDataLength = receivedLength; + + host->totalReceivedData += receivedLength; + host->totalReceivedPackets++; + + if (host->intercept != NULL) { + switch (host->intercept(host, (void *)event)) { + case 1: + if (event != NULL && event->type != ENET_EVENT_TYPE_NONE) { + return 1; + } + + continue; + + case -1: + return -1; + + default: + break; + } + } + + switch (enet_protocol_handle_incoming_commands(host, event)) { + case 1: + return 1; + + case -1: + return -1; + + default: + break; + } + } + + return -1; + } /* enet_protocol_receive_incoming_commands */ + + static void enet_protocol_send_acknowledgements(ENetHost *host, ENetPeer *peer) { + ENetProtocol *command = &host->commands[host->commandCount]; + ENetBuffer *buffer = &host->buffers[host->bufferCount]; + ENetAcknowledgement *acknowledgement; + ENetListIterator currentAcknowledgement; + enet_uint16 reliableSequenceNumber; + + currentAcknowledgement = enet_list_begin(&peer->acknowledgements); + + while (currentAcknowledgement != enet_list_end(&peer->acknowledgements)) { + if (command >= &host->commands[sizeof(host->commands) / sizeof(ENetProtocol)] || + buffer >= &host->buffers[sizeof(host->buffers) / sizeof(ENetBuffer)] || + peer->mtu - host->packetSize < sizeof(ENetProtocolAcknowledge) + ) { + host->continueSending = 1; + break; + } + + acknowledgement = (ENetAcknowledgement *) currentAcknowledgement; + currentAcknowledgement = enet_list_next(currentAcknowledgement); + + buffer->data = command; + buffer->dataLength = sizeof(ENetProtocolAcknowledge); + host->packetSize += buffer->dataLength; + + reliableSequenceNumber = ENET_HOST_TO_NET_16(acknowledgement->command.header.reliableSequenceNumber); + + command->header.command = ENET_PROTOCOL_COMMAND_ACKNOWLEDGE; + command->header.channelID = acknowledgement->command.header.channelID; + command->header.reliableSequenceNumber = reliableSequenceNumber; + command->acknowledge.receivedReliableSequenceNumber = reliableSequenceNumber; + command->acknowledge.receivedSentTime = ENET_HOST_TO_NET_16(acknowledgement->sentTime); + + if ((acknowledgement->command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_DISCONNECT) { + enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE); + } + + enet_list_remove(&acknowledgement->acknowledgementList); + enet_free(acknowledgement); + + ++command; + ++buffer; + } + + host->commandCount = command - host->commands; + host->bufferCount = buffer - host->buffers; + } /* enet_protocol_send_acknowledgements */ + + static void enet_protocol_send_unreliable_outgoing_commands(ENetHost *host, ENetPeer *peer) { + ENetProtocol *command = &host->commands[host->commandCount]; + ENetBuffer *buffer = &host->buffers[host->bufferCount]; + ENetOutgoingCommand *outgoingCommand; + ENetListIterator currentCommand; + + currentCommand = enet_list_begin(&peer->outgoingUnreliableCommands); + while (currentCommand != enet_list_end(&peer->outgoingUnreliableCommands)) { + size_t commandSize; + + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + commandSize = commandSizes[outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK]; + + if (command >= &host->commands[sizeof(host->commands) / sizeof(ENetProtocol)] || + buffer + 1 >= &host->buffers[sizeof(host->buffers) / sizeof(ENetBuffer)] || + peer->mtu - host->packetSize < commandSize || + (outgoingCommand->packet != NULL && + peer->mtu - host->packetSize < commandSize + outgoingCommand->fragmentLength) + ) { + host->continueSending = 1; + break; + } + + currentCommand = enet_list_next(currentCommand); + + if (outgoingCommand->packet != NULL && outgoingCommand->fragmentOffset == 0) { + peer->packetThrottleCounter += ENET_PEER_PACKET_THROTTLE_COUNTER; + peer->packetThrottleCounter %= ENET_PEER_PACKET_THROTTLE_SCALE; + + if (peer->packetThrottleCounter > peer->packetThrottle) { + enet_uint16 reliableSequenceNumber = outgoingCommand->reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber = outgoingCommand->unreliableSequenceNumber; + for (;;) { + --outgoingCommand->packet->referenceCount; + + if (outgoingCommand->packet->referenceCount == 0) { + enet_packet_destroy(outgoingCommand->packet); + } + + enet_list_remove(&outgoingCommand->outgoingCommandList); + enet_free(outgoingCommand); + + if (currentCommand == enet_list_end(&peer->outgoingUnreliableCommands)) { + break; + } + + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + if (outgoingCommand->reliableSequenceNumber != reliableSequenceNumber || outgoingCommand->unreliableSequenceNumber != unreliableSequenceNumber) { + break; + } + + currentCommand = enet_list_next(currentCommand); + } + + continue; + } + } + + buffer->data = command; + buffer->dataLength = commandSize; + host->packetSize += buffer->dataLength; + *command = outgoingCommand->command; + enet_list_remove(&outgoingCommand->outgoingCommandList); + + if (outgoingCommand->packet != NULL) { + ++buffer; + + buffer->data = outgoingCommand->packet->data + outgoingCommand->fragmentOffset; + buffer->dataLength = outgoingCommand->fragmentLength; + + host->packetSize += buffer->dataLength; + + enet_list_insert(enet_list_end(&peer->sentUnreliableCommands), outgoingCommand); + } else { + enet_free(outgoingCommand); + } + + ++command; + ++buffer; + } + + host->commandCount = command - host->commands; + host->bufferCount = buffer - host->buffers; + + if (peer->state == ENET_PEER_STATE_DISCONNECT_LATER && + enet_list_empty(&peer->outgoingReliableCommands) && + enet_list_empty(&peer->outgoingUnreliableCommands) && + enet_list_empty(&peer->sentReliableCommands)) + { + enet_peer_disconnect(peer, peer->eventData); + } + } /* enet_protocol_send_unreliable_outgoing_commands */ + + static int enet_protocol_check_timeouts(ENetHost *host, ENetPeer *peer, ENetEvent *event) { + ENetOutgoingCommand *outgoingCommand; + ENetListIterator currentCommand, insertPosition; + + currentCommand = enet_list_begin(&peer->sentReliableCommands); + insertPosition = enet_list_begin(&peer->outgoingReliableCommands); + + while (currentCommand != enet_list_end(&peer->sentReliableCommands)) { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + currentCommand = enet_list_next(currentCommand); + + if (ENET_TIME_DIFFERENCE(host->serviceTime, outgoingCommand->sentTime) < outgoingCommand->roundTripTimeout) { + continue; + } + + if (peer->earliestTimeout == 0 || ENET_TIME_LESS(outgoingCommand->sentTime, peer->earliestTimeout)) { + peer->earliestTimeout = outgoingCommand->sentTime; + } + + if (peer->earliestTimeout != 0 && + (ENET_TIME_DIFFERENCE(host->serviceTime, peer->earliestTimeout) >= peer->timeoutMaximum || + (outgoingCommand->roundTripTimeout >= outgoingCommand->roundTripTimeoutLimit && + ENET_TIME_DIFFERENCE(host->serviceTime, peer->earliestTimeout) >= peer->timeoutMinimum)) + ) { + enet_protocol_notify_disconnect_timeout(host, peer, event); + return 1; + } + + if (outgoingCommand->packet != NULL) { + peer->reliableDataInTransit -= outgoingCommand->fragmentLength; + } + + ++peer->packetsLost; + ++peer->totalPacketsLost; + + /* Replaced exponential backoff time with something more linear */ + /* Source: http://lists.cubik.org/pipermail/enet-discuss/2014-May/002308.html */ + outgoingCommand->roundTripTimeout = peer->roundTripTime + 4 * peer->roundTripTimeVariance; + outgoingCommand->roundTripTimeoutLimit = peer->timeoutLimit * outgoingCommand->roundTripTimeout; + + enet_list_insert(insertPosition, enet_list_remove(&outgoingCommand->outgoingCommandList)); + + if (currentCommand == enet_list_begin(&peer->sentReliableCommands) && !enet_list_empty(&peer->sentReliableCommands)) { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + peer->nextTimeout = outgoingCommand->sentTime + outgoingCommand->roundTripTimeout; + } + } + + return 0; + } /* enet_protocol_check_timeouts */ + + static int enet_protocol_send_reliable_outgoing_commands(ENetHost *host, ENetPeer *peer) { + ENetProtocol *command = &host->commands[host->commandCount]; + ENetBuffer *buffer = &host->buffers[host->bufferCount]; + ENetOutgoingCommand *outgoingCommand; + ENetListIterator currentCommand; + ENetChannel *channel; + enet_uint16 reliableWindow; + size_t commandSize; + int windowExceeded = 0, windowWrap = 0, canPing = 1; + + currentCommand = enet_list_begin(&peer->outgoingReliableCommands); + + while (currentCommand != enet_list_end(&peer->outgoingReliableCommands)) { + outgoingCommand = (ENetOutgoingCommand *) currentCommand; + + channel = outgoingCommand->command.header.channelID < peer->channelCount ? &peer->channels[outgoingCommand->command.header.channelID] : NULL; + reliableWindow = outgoingCommand->reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + if (channel != NULL) { + if (!windowWrap && + outgoingCommand->sendAttempts < 1 && + !(outgoingCommand->reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) && + (channel->reliableWindows[(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) + % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE || + channel->usedReliableWindows & ((((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) << reliableWindow) + | (((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) >> (ENET_PEER_RELIABLE_WINDOWS - reliableWindow)))) + ) { + windowWrap = 1; + } + + if (windowWrap) { + currentCommand = enet_list_next(currentCommand); + continue; + } + } + + if (outgoingCommand->packet != NULL) { + if (!windowExceeded) { + enet_uint32 windowSize = (peer->packetThrottle * peer->windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE; + + if (peer->reliableDataInTransit + outgoingCommand->fragmentLength > ENET_MAX(windowSize, peer->mtu)) { + windowExceeded = 1; + } + } + if (windowExceeded) { + currentCommand = enet_list_next(currentCommand); + + continue; + } + } + + canPing = 0; + + commandSize = commandSizes[outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK]; + if (command >= &host->commands[sizeof(host->commands) / sizeof(ENetProtocol)] || + buffer + 1 >= &host->buffers[sizeof(host->buffers) / sizeof(ENetBuffer)] || + peer->mtu - host->packetSize < commandSize || + (outgoingCommand->packet != NULL && + (enet_uint16) (peer->mtu - host->packetSize) < (enet_uint16) (commandSize + outgoingCommand->fragmentLength)) + ) { + host->continueSending = 1; + break; + } + + currentCommand = enet_list_next(currentCommand); + + if (channel != NULL && outgoingCommand->sendAttempts < 1) { + channel->usedReliableWindows |= 1 << reliableWindow; + ++channel->reliableWindows[reliableWindow]; + } + + ++outgoingCommand->sendAttempts; + + if (outgoingCommand->roundTripTimeout == 0) { + outgoingCommand->roundTripTimeout = peer->roundTripTime + 4 * peer->roundTripTimeVariance; + outgoingCommand->roundTripTimeoutLimit = peer->timeoutLimit * outgoingCommand->roundTripTimeout; + } + + if (enet_list_empty(&peer->sentReliableCommands)) { + peer->nextTimeout = host->serviceTime + outgoingCommand->roundTripTimeout; + } + + enet_list_insert(enet_list_end(&peer->sentReliableCommands), enet_list_remove(&outgoingCommand->outgoingCommandList)); + + outgoingCommand->sentTime = host->serviceTime; + + buffer->data = command; + buffer->dataLength = commandSize; + + host->packetSize += buffer->dataLength; + host->headerFlags |= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME; + + *command = outgoingCommand->command; + + if (outgoingCommand->packet != NULL) { + ++buffer; + buffer->data = outgoingCommand->packet->data + outgoingCommand->fragmentOffset; + buffer->dataLength = outgoingCommand->fragmentLength; + host->packetSize += outgoingCommand->fragmentLength; + peer->reliableDataInTransit += outgoingCommand->fragmentLength; + } + + ++peer->packetsSent; + ++peer->totalPacketsSent; + + ++command; + ++buffer; + } + + host->commandCount = command - host->commands; + host->bufferCount = buffer - host->buffers; + + return canPing; + } /* enet_protocol_send_reliable_outgoing_commands */ + + static int enet_protocol_send_outgoing_commands(ENetHost *host, ENetEvent *event, int checkForTimeouts) { + enet_uint8 headerData[sizeof(ENetProtocolHeader) + sizeof(enet_uint32)]; + ENetProtocolHeader *header = (ENetProtocolHeader *) headerData; + ENetPeer *currentPeer; + int sentLength; + size_t shouldCompress = 0; + host->continueSending = 1; + + while (host->continueSending) + for (host->continueSending = 0, currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { + if (currentPeer->state == ENET_PEER_STATE_DISCONNECTED || currentPeer->state == ENET_PEER_STATE_ZOMBIE) { + continue; + } + + host->headerFlags = 0; + host->commandCount = 0; + host->bufferCount = 1; + host->packetSize = sizeof(ENetProtocolHeader); + + if (!enet_list_empty(¤tPeer->acknowledgements)) { + enet_protocol_send_acknowledgements(host, currentPeer); + } + + if (checkForTimeouts != 0 && + !enet_list_empty(¤tPeer->sentReliableCommands) && + ENET_TIME_GREATER_EQUAL(host->serviceTime, currentPeer->nextTimeout) && + enet_protocol_check_timeouts(host, currentPeer, event) == 1 + ) { + if (event != NULL && event->type != ENET_EVENT_TYPE_NONE) { + return 1; + } else { + continue; + } + } + + if ((enet_list_empty(¤tPeer->outgoingReliableCommands) || + enet_protocol_send_reliable_outgoing_commands(host, currentPeer)) && + enet_list_empty(¤tPeer->sentReliableCommands) && + ENET_TIME_DIFFERENCE(host->serviceTime, currentPeer->lastReceiveTime) >= currentPeer->pingInterval && + currentPeer->mtu - host->packetSize >= sizeof(ENetProtocolPing) + ) { + enet_peer_ping(currentPeer); + enet_protocol_send_reliable_outgoing_commands(host, currentPeer); + } + + if (!enet_list_empty(¤tPeer->outgoingUnreliableCommands)) { + enet_protocol_send_unreliable_outgoing_commands(host, currentPeer); + } + + if (host->commandCount == 0) { + continue; + } + + if (currentPeer->packetLossEpoch == 0) { + currentPeer->packetLossEpoch = host->serviceTime; + } else if (ENET_TIME_DIFFERENCE(host->serviceTime, currentPeer->packetLossEpoch) >= ENET_PEER_PACKET_LOSS_INTERVAL && currentPeer->packetsSent > 0) { + enet_uint32 packetLoss = currentPeer->packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer->packetsSent; + + #ifdef ENET_DEBUG + printf( + "peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n", currentPeer->incomingPeerID, + currentPeer->packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, + currentPeer->packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer->roundTripTime, currentPeer->roundTripTimeVariance, + currentPeer->packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, + enet_list_size(¤tPeer->outgoingReliableCommands), + enet_list_size(¤tPeer->outgoingUnreliableCommands), + currentPeer->channels != NULL ? enet_list_size( ¤tPeer->channels->incomingReliableCommands) : 0, + currentPeer->channels != NULL ? enet_list_size(¤tPeer->channels->incomingUnreliableCommands) : 0 + ); + #endif + + currentPeer->packetLossVariance -= currentPeer->packetLossVariance / 4; + + if (packetLoss >= currentPeer->packetLoss) { + currentPeer->packetLoss += (packetLoss - currentPeer->packetLoss) / 8; + currentPeer->packetLossVariance += (packetLoss - currentPeer->packetLoss) / 4; + } else { + currentPeer->packetLoss -= (currentPeer->packetLoss - packetLoss) / 8; + currentPeer->packetLossVariance += (currentPeer->packetLoss - packetLoss) / 4; + } + + currentPeer->packetLossEpoch = host->serviceTime; + currentPeer->packetsSent = 0; + currentPeer->packetsLost = 0; + } + + host->buffers->data = headerData; + if (host->headerFlags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME) { + header->sentTime = ENET_HOST_TO_NET_16(host->serviceTime & 0xFFFF); + host->buffers->dataLength = sizeof(ENetProtocolHeader); + } else { + host->buffers->dataLength = (size_t) &((ENetProtocolHeader *) 0)->sentTime; + } + + shouldCompress = 0; + if (host->compressor.context != NULL && host->compressor.compress != NULL) { + size_t originalSize = host->packetSize - sizeof(ENetProtocolHeader), + compressedSize = host->compressor.compress(host->compressor.context, &host->buffers[1], host->bufferCount - 1, originalSize, host->packetData[1], originalSize); + if (compressedSize > 0 && compressedSize < originalSize) { + host->headerFlags |= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED; + shouldCompress = compressedSize; + #ifdef ENET_DEBUG_COMPRESS + printf("peer %u: compressed %u->%u (%u%%)\n", currentPeer->incomingPeerID, originalSize, compressedSize, (compressedSize * 100) / originalSize); + #endif + } + } + + if (currentPeer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID) { + host->headerFlags |= currentPeer->outgoingSessionID << ENET_PROTOCOL_HEADER_SESSION_SHIFT; + } + header->peerID = ENET_HOST_TO_NET_16(currentPeer->outgoingPeerID | host->headerFlags); + if (host->checksum != NULL) { + enet_uint32 *checksum = (enet_uint32 *) &headerData[host->buffers->dataLength]; + *checksum = currentPeer->outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer->connectID : 0; + host->buffers->dataLength += sizeof(enet_uint32); + *checksum = host->checksum(host->buffers, host->bufferCount); + } + + if (shouldCompress > 0) { + host->buffers[1].data = host->packetData[1]; + host->buffers[1].dataLength = shouldCompress; + host->bufferCount = 2; + } + + currentPeer->lastSendTime = host->serviceTime; + sentLength = enet_socket_send(host->socket, ¤tPeer->address, host->buffers, host->bufferCount); + enet_protocol_remove_sent_unreliable_commands(currentPeer); + + if (sentLength < 0) { + return -1; + } + + host->totalSentData += sentLength; + currentPeer->totalDataSent += sentLength; + host->totalSentPackets++; + } + + return 0; + } /* enet_protocol_send_outgoing_commands */ + + /** Sends any queued packets on the host specified to its designated peers. + * + * @param host host to flush + * @remarks this function need only be used in circumstances where one wishes to send queued packets earlier than in a call to enet_host_service(). + * @ingroup host + */ + void enet_host_flush(ENetHost *host) { + host->serviceTime = enet_time_get(); + enet_protocol_send_outgoing_commands(host, NULL, 0); + } + + /** Checks for any queued events on the host and dispatches one if available. + * + * @param host host to check for events + * @param event an event structure where event details will be placed if available + * @retval > 0 if an event was dispatched + * @retval 0 if no events are available + * @retval < 0 on failure + * @ingroup host + */ + int enet_host_check_events(ENetHost *host, ENetEvent *event) { + if (event == NULL) { return -1; } + + event->type = ENET_EVENT_TYPE_NONE; + event->peer = NULL; + event->packet = NULL; + + return enet_protocol_dispatch_incoming_commands(host, event); + } + + /** Waits for events on the host specified and shuttles packets between + * the host and its peers. + * + * @param host host to service + * @param event an event structure where event details will be placed if one occurs + * if event == NULL then no events will be delivered + * @param timeout number of milliseconds that ENet should wait for events + * @retval > 0 if an event occurred within the specified time limit + * @retval 0 if no event occurred + * @retval < 0 on failure + * @remarks enet_host_service should be called fairly regularly for adequate performance + * @ingroup host + */ + int enet_host_service(ENetHost *host, ENetEvent *event, enet_uint32 timeout) { + enet_uint32 waitCondition; + + if (event != NULL) { + event->type = ENET_EVENT_TYPE_NONE; + event->peer = NULL; + event->packet = NULL; + + switch (enet_protocol_dispatch_incoming_commands(host, event)) { + case 1: + return 1; + + case -1: + #ifdef ENET_DEBUG + perror("Error dispatching incoming packets"); + #endif + + return -1; + + default: + break; + } + } + + host->serviceTime = enet_time_get(); + timeout += host->serviceTime; + + do { + if (ENET_TIME_DIFFERENCE(host->serviceTime, host->bandwidthThrottleEpoch) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) { + enet_host_bandwidth_throttle(host); + } + + switch (enet_protocol_send_outgoing_commands(host, event, 1)) { + case 1: + return 1; + + case -1: + #ifdef ENET_DEBUG + perror("Error sending outgoing packets"); + #endif + + return -1; + + default: + break; + } + + switch (enet_protocol_receive_incoming_commands(host, event)) { + case 1: + return 1; + + case -1: + #ifdef ENET_DEBUG + perror("Error receiving incoming packets"); + #endif + + return -1; + + default: + break; + } + + switch (enet_protocol_send_outgoing_commands(host, event, 1)) { + case 1: + return 1; + + case -1: + #ifdef ENET_DEBUG + perror("Error sending outgoing packets"); + #endif + + return -1; + + default: + break; + } + + if (event != NULL) { + switch (enet_protocol_dispatch_incoming_commands(host, event)) { + case 1: + return 1; + + case -1: + #ifdef ENET_DEBUG + perror("Error dispatching incoming packets"); + #endif + + return -1; + + default: + break; + } + } + + if (ENET_TIME_GREATER_EQUAL(host->serviceTime, timeout)) { + return 0; + } + + do { + host->serviceTime = enet_time_get(); + + if (ENET_TIME_GREATER_EQUAL(host->serviceTime, timeout)) { + return 0; + } + + waitCondition = ENET_SOCKET_WAIT_RECEIVE | ENET_SOCKET_WAIT_INTERRUPT; + if (enet_socket_wait(host->socket, &waitCondition, ENET_TIME_DIFFERENCE(timeout, host->serviceTime)) != 0) { + return -1; + } + } while (waitCondition & ENET_SOCKET_WAIT_INTERRUPT); + + host->serviceTime = enet_time_get(); + } while (waitCondition & ENET_SOCKET_WAIT_RECEIVE); + + return 0; + } /* enet_host_service */ + + +// =======================================================================// +// ! +// ! Peer +// ! +// =======================================================================// + + /** Configures throttle parameter for a peer. + * + * Unreliable packets are dropped by ENet in response to the varying conditions + * of the Internet connection to the peer. The throttle represents a probability + * that an unreliable packet should not be dropped and thus sent by ENet to the peer. + * The lowest mean round trip time from the sending of a reliable packet to the + * receipt of its acknowledgement is measured over an amount of time specified by + * the interval parameter in milliseconds. If a measured round trip time happens to + * be significantly less than the mean round trip time measured over the interval, + * then the throttle probability is increased to allow more traffic by an amount + * specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE + * constant. If a measured round trip time happens to be significantly greater than + * the mean round trip time measured over the interval, then the throttle probability + * is decreased to limit traffic by an amount specified in the deceleration parameter, which + * is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant. When the throttle has + * a value of ENET_PEER_PACKET_THROTTLE_SCALE, no unreliable packets are dropped by + * ENet, and so 100% of all unreliable packets will be sent. When the throttle has a + * value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable + * packets will be sent. Intermediate values for the throttle represent intermediate + * probabilities between 0% and 100% of unreliable packets being sent. The bandwidth + * limits of the local and foreign hosts are taken into account to determine a + * sensible limit for the throttle probability above which it should not raise even in + * the best of conditions. + * + * @param peer peer to configure + * @param interval interval, in milliseconds, over which to measure lowest mean RTT; the default value is ENET_PEER_PACKET_THROTTLE_INTERVAL. + * @param acceleration rate at which to increase the throttle probability as mean RTT declines + * @param deceleration rate at which to decrease the throttle probability as mean RTT increases + */ + void enet_peer_throttle_configure(ENetPeer *peer, enet_uint32 interval, enet_uint32 acceleration, enet_uint32 deceleration) { + ENetProtocol command; + + peer->packetThrottleInterval = interval; + peer->packetThrottleAcceleration = acceleration; + peer->packetThrottleDeceleration = deceleration; + + command.header.command = ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + + command.throttleConfigure.packetThrottleInterval = ENET_HOST_TO_NET_32(interval); + command.throttleConfigure.packetThrottleAcceleration = ENET_HOST_TO_NET_32(acceleration); + command.throttleConfigure.packetThrottleDeceleration = ENET_HOST_TO_NET_32(deceleration); + + enet_peer_queue_outgoing_command(peer, &command, NULL, 0, 0); + } + + int enet_peer_throttle(ENetPeer *peer, enet_uint32 rtt) { + if (peer->lastRoundTripTime <= peer->lastRoundTripTimeVariance) { + peer->packetThrottle = peer->packetThrottleLimit; + } + else if (rtt < peer->lastRoundTripTime) { + peer->packetThrottle += peer->packetThrottleAcceleration; + + if (peer->packetThrottle > peer->packetThrottleLimit) { + peer->packetThrottle = peer->packetThrottleLimit; + } + + return 1; + } + else if (rtt > peer->lastRoundTripTime + 2 * peer->lastRoundTripTimeVariance) { + if (peer->packetThrottle > peer->packetThrottleDeceleration) { + peer->packetThrottle -= peer->packetThrottleDeceleration; + } else { + peer->packetThrottle = 0; + } + + return -1; + } + + return 0; + } + + /* Extended functionality for easier binding in other programming languages */ + enet_uint32 enet_host_get_peers_count(ENetHost *host) { + return host->connectedPeers; + } + + enet_uint32 enet_host_get_packets_sent(ENetHost *host) { + return host->totalSentPackets; + } + + enet_uint32 enet_host_get_packets_received(ENetHost *host) { + return host->totalReceivedPackets; + } + + enet_uint32 enet_host_get_bytes_sent(ENetHost *host) { + return host->totalSentData; + } + + enet_uint32 enet_host_get_bytes_received(ENetHost *host) { + return host->totalReceivedData; + } + + /** Gets received data buffer. Returns buffer length. + * @param host host to access recevie buffer + * @param data ouput parameter for recevied data + * @retval buffer length + */ + enet_uint32 enet_host_get_received_data(ENetHost *host, /*out*/ enet_uint8** data) { + *data = host->receivedData; + return host->receivedDataLength; + } + + enet_uint32 enet_host_get_mtu(ENetHost *host) { + return host->mtu; + } + + enet_uint32 enet_peer_get_id(ENetPeer *peer) { + return peer->connectID; + } + + enet_uint32 enet_peer_get_ip(ENetPeer *peer, char *ip, size_t ipLength) { + return enet_address_get_host_ip(&peer->address, ip, ipLength); + } + + enet_uint16 enet_peer_get_port(ENetPeer *peer) { + return peer->address.port; + } + + ENetPeerState enet_peer_get_state(ENetPeer *peer) { + return peer->state; + } + + enet_uint32 enet_peer_get_rtt(ENetPeer *peer) { + return peer->roundTripTime; + } + + enet_uint64 enet_peer_get_packets_sent(ENetPeer *peer) { + return peer->totalPacketsSent; + } + + enet_uint32 enet_peer_get_packets_lost(ENetPeer *peer) { + return peer->totalPacketsLost; + } + + enet_uint64 enet_peer_get_bytes_sent(ENetPeer *peer) { + return peer->totalDataSent; + } + + enet_uint64 enet_peer_get_bytes_received(ENetPeer *peer) { + return peer->totalDataReceived; + } + + void * enet_peer_get_data(ENetPeer *peer) { + return (void *) peer->data; + } + + void enet_peer_set_data(ENetPeer *peer, const void *data) { + peer->data = (enet_uint32 *) data; + } + + void * enet_packet_get_data(ENetPacket *packet) { + return (void *) packet->data; + } + + enet_uint32 enet_packet_get_length(ENetPacket *packet) { + return packet->dataLength; + } + + void enet_packet_set_free_callback(ENetPacket *packet, void *callback) { + packet->freeCallback = (ENetPacketFreeCallback)callback; + } + + /** Queues a packet to be sent. + * @param peer destination for the packet + * @param channelID channel on which to send + * @param packet packet to send + * @retval 0 on success + * @retval < 0 on failure + */ + int enet_peer_send(ENetPeer *peer, enet_uint8 channelID, ENetPacket *packet) { + ENetChannel *channel = &peer->channels[channelID]; + ENetProtocol command; + size_t fragmentLength; + + if (peer->state != ENET_PEER_STATE_CONNECTED || channelID >= peer->channelCount || packet->dataLength > peer->host->maximumPacketSize) { + return -1; + } + + fragmentLength = peer->mtu - sizeof(ENetProtocolHeader) - sizeof(ENetProtocolSendFragment); + if (peer->host->checksum != NULL) { + fragmentLength -= sizeof(enet_uint32); + } + + if (packet->dataLength > fragmentLength) { + enet_uint32 fragmentCount = (packet->dataLength + fragmentLength - 1) / fragmentLength, fragmentNumber, fragmentOffset; + enet_uint8 commandNumber; + enet_uint16 startSequenceNumber; + ENetList fragments; + ENetOutgoingCommand *fragment; + + if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) { + return -1; + } + + if ((packet->flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT)) == + ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT && + channel->outgoingUnreliableSequenceNumber < 0xFFFF) + { + commandNumber = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT; + startSequenceNumber = ENET_HOST_TO_NET_16(channel->outgoingUnreliableSequenceNumber + 1); + } else { + commandNumber = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + startSequenceNumber = ENET_HOST_TO_NET_16(channel->outgoingReliableSequenceNumber + 1); + } + + enet_list_clear(&fragments); + + for (fragmentNumber = 0, fragmentOffset = 0; fragmentOffset < packet->dataLength; ++fragmentNumber, fragmentOffset += fragmentLength) { + if (packet->dataLength - fragmentOffset < fragmentLength) { + fragmentLength = packet->dataLength - fragmentOffset; + } + + fragment = (ENetOutgoingCommand *) enet_malloc(sizeof(ENetOutgoingCommand)); + + if (fragment == NULL) { + while (!enet_list_empty(&fragments)) { + fragment = (ENetOutgoingCommand *) enet_list_remove(enet_list_begin(&fragments)); + + enet_free(fragment); + } + + return -1; + } + + fragment->fragmentOffset = fragmentOffset; + fragment->fragmentLength = fragmentLength; + fragment->packet = packet; + fragment->command.header.command = commandNumber; + fragment->command.header.channelID = channelID; + + fragment->command.sendFragment.startSequenceNumber = startSequenceNumber; + + fragment->command.sendFragment.dataLength = ENET_HOST_TO_NET_16(fragmentLength); + fragment->command.sendFragment.fragmentCount = ENET_HOST_TO_NET_32(fragmentCount); + fragment->command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32(fragmentNumber); + fragment->command.sendFragment.totalLength = ENET_HOST_TO_NET_32(packet->dataLength); + fragment->command.sendFragment.fragmentOffset = ENET_NET_TO_HOST_32(fragmentOffset); + + enet_list_insert(enet_list_end(&fragments), fragment); + } + + packet->referenceCount += fragmentNumber; + + while (!enet_list_empty(&fragments)) { + fragment = (ENetOutgoingCommand *) enet_list_remove(enet_list_begin(&fragments)); + enet_peer_setup_outgoing_command(peer, fragment); + } + + return 0; + } + + command.header.channelID = channelID; + + if ((packet->flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNSEQUENCED)) == ENET_PACKET_FLAG_UNSEQUENCED) { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + command.sendUnsequenced.dataLength = ENET_HOST_TO_NET_16(packet->dataLength); + } + else if (packet->flags & ENET_PACKET_FLAG_RELIABLE || channel->outgoingUnreliableSequenceNumber >= 0xFFFF) { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.sendReliable.dataLength = ENET_HOST_TO_NET_16(packet->dataLength); + } + else { + command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE; + command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16(packet->dataLength); + } + + if (enet_peer_queue_outgoing_command(peer, &command, packet, 0, packet->dataLength) == NULL) { + return -1; + } + + return 0; + } // enet_peer_send + + /** Attempts to dequeue any incoming queued packet. + * @param peer peer to dequeue packets from + * @param channelID holds the channel ID of the channel the packet was received on success + * @returns a pointer to the packet, or NULL if there are no available incoming queued packets + */ + ENetPacket * enet_peer_receive(ENetPeer *peer, enet_uint8 *channelID) { + ENetIncomingCommand *incomingCommand; + ENetPacket *packet; + + if (enet_list_empty(&peer->dispatchedCommands)) { + return NULL; + } + + incomingCommand = (ENetIncomingCommand *) enet_list_remove(enet_list_begin(&peer->dispatchedCommands)); + + if (channelID != NULL) { + *channelID = incomingCommand->command.header.channelID; + } + + packet = incomingCommand->packet; + --packet->referenceCount; + + if (incomingCommand->fragments != NULL) { + enet_free(incomingCommand->fragments); + } + + enet_free(incomingCommand); + peer->totalWaitingData -= packet->dataLength; + + return packet; + } + + static void enet_peer_reset_outgoing_commands(ENetList *queue) { + ENetOutgoingCommand *outgoingCommand; + + while (!enet_list_empty(queue)) { + outgoingCommand = (ENetOutgoingCommand *) enet_list_remove(enet_list_begin(queue)); + + if (outgoingCommand->packet != NULL) { + --outgoingCommand->packet->referenceCount; + + if (outgoingCommand->packet->referenceCount == 0) { + enet_packet_destroy(outgoingCommand->packet); + } + } + + enet_free(outgoingCommand); + } + } + + static void enet_peer_remove_incoming_commands(ENetList *queue, ENetListIterator startCommand, ENetListIterator endCommand) { + ENetListIterator currentCommand; + + for (currentCommand = startCommand; currentCommand != endCommand;) { + ENetIncomingCommand *incomingCommand = (ENetIncomingCommand *) currentCommand; + + currentCommand = enet_list_next(currentCommand); + enet_list_remove(&incomingCommand->incomingCommandList); + + if (incomingCommand->packet != NULL) { + --incomingCommand->packet->referenceCount; + + if (incomingCommand->packet->referenceCount == 0) { + enet_packet_destroy(incomingCommand->packet); + } + } + + if (incomingCommand->fragments != NULL) { + enet_free(incomingCommand->fragments); + } + + enet_free(incomingCommand); + } + } + + static void enet_peer_reset_incoming_commands(ENetList *queue) { + enet_peer_remove_incoming_commands(queue, enet_list_begin(queue), enet_list_end(queue)); + } + + void enet_peer_reset_queues(ENetPeer *peer) { + ENetChannel *channel; + + if (peer->needsDispatch) { + enet_list_remove(&peer->dispatchList); + peer->needsDispatch = 0; + } + + while (!enet_list_empty(&peer->acknowledgements)) { + enet_free(enet_list_remove(enet_list_begin(&peer->acknowledgements))); + } + + enet_peer_reset_outgoing_commands(&peer->sentReliableCommands); + enet_peer_reset_outgoing_commands(&peer->sentUnreliableCommands); + enet_peer_reset_outgoing_commands(&peer->outgoingReliableCommands); + enet_peer_reset_outgoing_commands(&peer->outgoingUnreliableCommands); + enet_peer_reset_incoming_commands(&peer->dispatchedCommands); + + if (peer->channels != NULL && peer->channelCount > 0) { + for (channel = peer->channels; channel < &peer->channels[peer->channelCount]; ++channel) { + enet_peer_reset_incoming_commands(&channel->incomingReliableCommands); + enet_peer_reset_incoming_commands(&channel->incomingUnreliableCommands); + } + + enet_free(peer->channels); + } + + peer->channels = NULL; + peer->channelCount = 0; + } + + void enet_peer_on_connect(ENetPeer *peer) { + if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { + if (peer->incomingBandwidth != 0) { + ++peer->host->bandwidthLimitedPeers; + } + + ++peer->host->connectedPeers; + } + } + + void enet_peer_on_disconnect(ENetPeer *peer) { + if (peer->state == ENET_PEER_STATE_CONNECTED || peer->state == ENET_PEER_STATE_DISCONNECT_LATER) { + if (peer->incomingBandwidth != 0) { + --peer->host->bandwidthLimitedPeers; + } + + --peer->host->connectedPeers; + } + } + + /** Forcefully disconnects a peer. + * @param peer peer to forcefully disconnect + * @remarks The foreign host represented by the peer is not notified of the disconnection and will timeout + * on its connection to the local host. + */ + void enet_peer_reset(ENetPeer *peer) { + enet_peer_on_disconnect(peer); + + // We don't want to reset connectID here, otherwise, we can't get it in the Disconnect event + // peer->connectID = 0; + peer->outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID; + peer->state = ENET_PEER_STATE_DISCONNECTED; + peer->incomingBandwidth = 0; + peer->outgoingBandwidth = 0; + peer->incomingBandwidthThrottleEpoch = 0; + peer->outgoingBandwidthThrottleEpoch = 0; + peer->incomingDataTotal = 0; + peer->totalDataReceived = 0; + peer->outgoingDataTotal = 0; + peer->totalDataSent = 0; + peer->lastSendTime = 0; + peer->lastReceiveTime = 0; + peer->nextTimeout = 0; + peer->earliestTimeout = 0; + peer->packetLossEpoch = 0; + peer->packetsSent = 0; + peer->totalPacketsSent = 0; + peer->packetsLost = 0; + peer->totalPacketsLost = 0; + peer->packetLoss = 0; + peer->packetLossVariance = 0; + peer->packetThrottle = ENET_PEER_DEFAULT_PACKET_THROTTLE; + peer->packetThrottleLimit = ENET_PEER_PACKET_THROTTLE_SCALE; + peer->packetThrottleCounter = 0; + peer->packetThrottleEpoch = 0; + peer->packetThrottleAcceleration = ENET_PEER_PACKET_THROTTLE_ACCELERATION; + peer->packetThrottleDeceleration = ENET_PEER_PACKET_THROTTLE_DECELERATION; + peer->packetThrottleInterval = ENET_PEER_PACKET_THROTTLE_INTERVAL; + peer->pingInterval = ENET_PEER_PING_INTERVAL; + peer->timeoutLimit = ENET_PEER_TIMEOUT_LIMIT; + peer->timeoutMinimum = ENET_PEER_TIMEOUT_MINIMUM; + peer->timeoutMaximum = ENET_PEER_TIMEOUT_MAXIMUM; + peer->lastRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer->lowestRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer->lastRoundTripTimeVariance = 0; + peer->highestRoundTripTimeVariance = 0; + peer->roundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME; + peer->roundTripTimeVariance = 0; + peer->mtu = peer->host->mtu; + peer->reliableDataInTransit = 0; + peer->outgoingReliableSequenceNumber = 0; + peer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + peer->incomingUnsequencedGroup = 0; + peer->outgoingUnsequencedGroup = 0; + peer->eventData = 0; + peer->totalWaitingData = 0; + + memset(peer->unsequencedWindow, 0, sizeof(peer->unsequencedWindow)); + enet_peer_reset_queues(peer); + } + + /** Sends a ping request to a peer. + * @param peer destination for the ping request + * @remarks ping requests factor into the mean round trip time as designated by the + * roundTripTime field in the ENetPeer structure. ENet automatically pings all connected + * peers at regular intervals, however, this function may be called to ensure more + * frequent ping requests. + */ + void enet_peer_ping(ENetPeer *peer) { + ENetProtocol command; + + if (peer->state != ENET_PEER_STATE_CONNECTED) { + return; + } + + command.header.command = ENET_PROTOCOL_COMMAND_PING | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + + enet_peer_queue_outgoing_command(peer, &command, NULL, 0, 0); + } + + /** Sets the interval at which pings will be sent to a peer. + * + * Pings are used both to monitor the liveness of the connection and also to dynamically + * adjust the throttle during periods of low traffic so that the throttle has reasonable + * responsiveness during traffic spikes. + * + * @param peer the peer to adjust + * @param pingInterval the interval at which to send pings; defaults to ENET_PEER_PING_INTERVAL if 0 + */ + void enet_peer_ping_interval(ENetPeer *peer, enet_uint32 pingInterval) { + peer->pingInterval = pingInterval ? pingInterval : ENET_PEER_PING_INTERVAL; + } + + /** Sets the timeout parameters for a peer. + * + * The timeout parameter control how and when a peer will timeout from a failure to acknowledge + * reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable + * packet is not acknowledge within some multiple of the average RTT plus a variance tolerance, + * the timeout will be doubled until it reaches a set limit. If the timeout is thus at this + * limit and reliable packets have been sent but not acknowledged within a certain minimum time + * period, the peer will be disconnected. Alternatively, if reliable packets have been sent + * but not acknowledged for a certain maximum time period, the peer will be disconnected regardless + * of the current timeout limit value. + * + * @param peer the peer to adjust + * @param timeoutLimit the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0 + * @param timeoutMinimum the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0 + * @param timeoutMaximum the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0 + */ + + void enet_peer_timeout(ENetPeer *peer, enet_uint32 timeoutLimit, enet_uint32 timeoutMinimum, enet_uint32 timeoutMaximum) { + peer->timeoutLimit = timeoutLimit ? timeoutLimit : ENET_PEER_TIMEOUT_LIMIT; + peer->timeoutMinimum = timeoutMinimum ? timeoutMinimum : ENET_PEER_TIMEOUT_MINIMUM; + peer->timeoutMaximum = timeoutMaximum ? timeoutMaximum : ENET_PEER_TIMEOUT_MAXIMUM; + } + + /** Force an immediate disconnection from a peer. + * @param peer peer to disconnect + * @param data data describing the disconnection + * @remarks No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not + * guaranteed to receive the disconnect notification, and is reset immediately upon + * return from this function. + */ + void enet_peer_disconnect_now(ENetPeer *peer, enet_uint32 data) { + ENetProtocol command; + + if (peer->state == ENET_PEER_STATE_DISCONNECTED) { + return; + } + + if (peer->state != ENET_PEER_STATE_ZOMBIE && peer->state != ENET_PEER_STATE_DISCONNECTING) { + enet_peer_reset_queues(peer); + + command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + command.header.channelID = 0xFF; + command.disconnect.data = ENET_HOST_TO_NET_32(data); + + enet_peer_queue_outgoing_command(peer, &command, NULL, 0, 0); + enet_host_flush(peer->host); + } + + enet_peer_reset(peer); + } + + /** Request a disconnection from a peer. + * @param peer peer to request a disconnection + * @param data data describing the disconnection + * @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() + * once the disconnection is complete. + */ + void enet_peer_disconnect(ENetPeer *peer, enet_uint32 data) { + ENetProtocol command; + + if (peer->state == ENET_PEER_STATE_DISCONNECTING || + peer->state == ENET_PEER_STATE_DISCONNECTED || + peer->state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT || + peer->state == ENET_PEER_STATE_ZOMBIE + ) { + return; + } + + enet_peer_reset_queues(peer); + + command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT; + command.header.channelID = 0xFF; + command.disconnect.data = ENET_HOST_TO_NET_32(data); + + if (peer->state == ENET_PEER_STATE_CONNECTED || peer->state == ENET_PEER_STATE_DISCONNECT_LATER) { + command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + } else { + command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; + } + + enet_peer_queue_outgoing_command(peer, &command, NULL, 0, 0); + + if (peer->state == ENET_PEER_STATE_CONNECTED || peer->state == ENET_PEER_STATE_DISCONNECT_LATER) { + enet_peer_on_disconnect(peer); + + peer->state = ENET_PEER_STATE_DISCONNECTING; + } else { + enet_host_flush(peer->host); + enet_peer_reset(peer); + } + } + + /** Request a disconnection from a peer, but only after all queued outgoing packets are sent. + * @param peer peer to request a disconnection + * @param data data describing the disconnection + * @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() + * once the disconnection is complete. + */ + void enet_peer_disconnect_later(ENetPeer *peer, enet_uint32 data) { + if ((peer->state == ENET_PEER_STATE_CONNECTED || peer->state == ENET_PEER_STATE_DISCONNECT_LATER) && + !(enet_list_empty(&peer->outgoingReliableCommands) && + enet_list_empty(&peer->outgoingUnreliableCommands) && + enet_list_empty(&peer->sentReliableCommands)) + ) { + peer->state = ENET_PEER_STATE_DISCONNECT_LATER; + peer->eventData = data; + } else { + enet_peer_disconnect(peer, data); + } + } + + ENetAcknowledgement *enet_peer_queue_acknowledgement(ENetPeer *peer, const ENetProtocol *command, enet_uint16 sentTime) { + ENetAcknowledgement *acknowledgement; + + if (command->header.channelID < peer->channelCount) { + ENetChannel *channel = &peer->channels[command->header.channelID]; + enet_uint16 reliableWindow = command->header.reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + enet_uint16 currentWindow = channel->incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (command->header.reliableSequenceNumber < channel->incomingReliableSequenceNumber) { + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + } + + if (reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1 && reliableWindow <= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS) { + return NULL; + } + } + + acknowledgement = (ENetAcknowledgement *) enet_malloc(sizeof(ENetAcknowledgement)); + if (acknowledgement == NULL) { + return NULL; + } + + peer->outgoingDataTotal += sizeof(ENetProtocolAcknowledge); + + acknowledgement->sentTime = sentTime; + acknowledgement->command = *command; + + enet_list_insert(enet_list_end(&peer->acknowledgements), acknowledgement); + return acknowledgement; + } + + void enet_peer_setup_outgoing_command(ENetPeer *peer, ENetOutgoingCommand *outgoingCommand) { + ENetChannel *channel = &peer->channels[outgoingCommand->command.header.channelID]; + peer->outgoingDataTotal += enet_protocol_command_size(outgoingCommand->command.header.command) + outgoingCommand->fragmentLength; + + if (outgoingCommand->command.header.channelID == 0xFF) { + ++peer->outgoingReliableSequenceNumber; + + outgoingCommand->reliableSequenceNumber = peer->outgoingReliableSequenceNumber; + outgoingCommand->unreliableSequenceNumber = 0; + } + else if (outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) { + ++channel->outgoingReliableSequenceNumber; + channel->outgoingUnreliableSequenceNumber = 0; + + outgoingCommand->reliableSequenceNumber = channel->outgoingReliableSequenceNumber; + outgoingCommand->unreliableSequenceNumber = 0; + } + else if (outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED) { + ++peer->outgoingUnsequencedGroup; + + outgoingCommand->reliableSequenceNumber = 0; + outgoingCommand->unreliableSequenceNumber = 0; + } + else { + if (outgoingCommand->fragmentOffset == 0) { + ++channel->outgoingUnreliableSequenceNumber; + } + + outgoingCommand->reliableSequenceNumber = channel->outgoingReliableSequenceNumber; + outgoingCommand->unreliableSequenceNumber = channel->outgoingUnreliableSequenceNumber; + } + + outgoingCommand->sendAttempts = 0; + outgoingCommand->sentTime = 0; + outgoingCommand->roundTripTimeout = 0; + outgoingCommand->roundTripTimeoutLimit = 0; + outgoingCommand->command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16(outgoingCommand->reliableSequenceNumber); + + switch (outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK) { + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: + outgoingCommand->command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16(outgoingCommand->unreliableSequenceNumber); + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + outgoingCommand->command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16(peer->outgoingUnsequencedGroup); + break; + + default: + break; + } + + if (outgoingCommand->command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) { + enet_list_insert(enet_list_end(&peer->outgoingReliableCommands), outgoingCommand); + } else { + enet_list_insert(enet_list_end(&peer->outgoingUnreliableCommands), outgoingCommand); + } + } + + ENetOutgoingCommand * enet_peer_queue_outgoing_command(ENetPeer *peer, const ENetProtocol *command, ENetPacket *packet, enet_uint32 offset, enet_uint16 length) { + ENetOutgoingCommand *outgoingCommand = (ENetOutgoingCommand *) enet_malloc(sizeof(ENetOutgoingCommand)); + + if (outgoingCommand == NULL) { + return NULL; + } + + outgoingCommand->command = *command; + outgoingCommand->fragmentOffset = offset; + outgoingCommand->fragmentLength = length; + outgoingCommand->packet = packet; + if (packet != NULL) { + ++packet->referenceCount; + } + + enet_peer_setup_outgoing_command(peer, outgoingCommand); + return outgoingCommand; + } + + void enet_peer_dispatch_incoming_unreliable_commands(ENetPeer *peer, ENetChannel *channel) { + ENetListIterator droppedCommand, startCommand, currentCommand; + + for (droppedCommand = startCommand = currentCommand = enet_list_begin(&channel->incomingUnreliableCommands); + currentCommand != enet_list_end(&channel->incomingUnreliableCommands); + currentCommand = enet_list_next(currentCommand) + ) { + ENetIncomingCommand *incomingCommand = (ENetIncomingCommand *) currentCommand; + + if ((incomingCommand->command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) { + continue; + } + + if (incomingCommand->reliableSequenceNumber == channel->incomingReliableSequenceNumber) { + if (incomingCommand->fragmentsRemaining <= 0) { + channel->incomingUnreliableSequenceNumber = incomingCommand->unreliableSequenceNumber; + continue; + } + + if (startCommand != currentCommand) { + enet_list_move(enet_list_end(&peer->dispatchedCommands), startCommand, enet_list_previous(currentCommand)); + + if (!peer->needsDispatch) { + enet_list_insert(enet_list_end(&peer->host->dispatchQueue), &peer->dispatchList); + peer->needsDispatch = 1; + } + + droppedCommand = currentCommand; + } else if (droppedCommand != currentCommand) { + droppedCommand = enet_list_previous(currentCommand); + } + } else { + enet_uint16 reliableWindow = incomingCommand->reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + enet_uint16 currentWindow = channel->incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (incomingCommand->reliableSequenceNumber < channel->incomingReliableSequenceNumber) { + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + } + + if (reliableWindow >= currentWindow && reliableWindow < currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) { + break; + } + + droppedCommand = enet_list_next(currentCommand); + + if (startCommand != currentCommand) { + enet_list_move(enet_list_end(&peer->dispatchedCommands), startCommand, enet_list_previous(currentCommand)); + + if (!peer->needsDispatch) { + enet_list_insert(enet_list_end(&peer->host->dispatchQueue), &peer->dispatchList); + peer->needsDispatch = 1; + } + } + } + + startCommand = enet_list_next(currentCommand); + } + + if (startCommand != currentCommand) { + enet_list_move(enet_list_end(&peer->dispatchedCommands), startCommand, enet_list_previous(currentCommand)); + + if (!peer->needsDispatch) { + enet_list_insert(enet_list_end(&peer->host->dispatchQueue), &peer->dispatchList); + peer->needsDispatch = 1; + } + + droppedCommand = currentCommand; + } + + enet_peer_remove_incoming_commands(&channel->incomingUnreliableCommands,enet_list_begin(&channel->incomingUnreliableCommands), droppedCommand); + } + + void enet_peer_dispatch_incoming_reliable_commands(ENetPeer *peer, ENetChannel *channel) { + ENetListIterator currentCommand; + + for (currentCommand = enet_list_begin(&channel->incomingReliableCommands); + currentCommand != enet_list_end(&channel->incomingReliableCommands); + currentCommand = enet_list_next(currentCommand) + ) { + ENetIncomingCommand *incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (incomingCommand->fragmentsRemaining > 0 || incomingCommand->reliableSequenceNumber != (enet_uint16) (channel->incomingReliableSequenceNumber + 1)) { + break; + } + + channel->incomingReliableSequenceNumber = incomingCommand->reliableSequenceNumber; + + if (incomingCommand->fragmentCount > 0) { + channel->incomingReliableSequenceNumber += incomingCommand->fragmentCount - 1; + } + } + + if (currentCommand == enet_list_begin(&channel->incomingReliableCommands)) { + return; + } + + channel->incomingUnreliableSequenceNumber = 0; + enet_list_move(enet_list_end(&peer->dispatchedCommands), enet_list_begin(&channel->incomingReliableCommands), enet_list_previous(currentCommand)); + + if (!peer->needsDispatch) { + enet_list_insert(enet_list_end(&peer->host->dispatchQueue), &peer->dispatchList); + peer->needsDispatch = 1; + } + + if (!enet_list_empty(&channel->incomingUnreliableCommands)) { + enet_peer_dispatch_incoming_unreliable_commands(peer, channel); + } + } + + ENetIncomingCommand * enet_peer_queue_incoming_command(ENetPeer *peer, const ENetProtocol *command, const void *data, size_t dataLength, enet_uint32 flags, enet_uint32 fragmentCount) { + static ENetIncomingCommand dummyCommand; + + ENetChannel *channel = &peer->channels[command->header.channelID]; + enet_uint32 unreliableSequenceNumber = 0, reliableSequenceNumber = 0; + enet_uint16 reliableWindow, currentWindow; + ENetIncomingCommand *incomingCommand; + ENetListIterator currentCommand; + ENetPacket *packet = NULL; + + if (peer->state == ENET_PEER_STATE_DISCONNECT_LATER) { + goto discardCommand; + } + + if ((command->header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) { + reliableSequenceNumber = command->header.reliableSequenceNumber; + reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + currentWindow = channel->incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + + if (reliableSequenceNumber < channel->incomingReliableSequenceNumber) { + reliableWindow += ENET_PEER_RELIABLE_WINDOWS; + } + + if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) { + goto discardCommand; + } + } + + switch (command->header.command & ENET_PROTOCOL_COMMAND_MASK) { + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: + if (reliableSequenceNumber == channel->incomingReliableSequenceNumber) { + goto discardCommand; + } + + for (currentCommand = enet_list_previous(enet_list_end(&channel->incomingReliableCommands)); + currentCommand != enet_list_end(&channel->incomingReliableCommands); + currentCommand = enet_list_previous(currentCommand) + ) { + incomingCommand = (ENetIncomingCommand *) currentCommand; + + if (reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { + if (incomingCommand->reliableSequenceNumber < channel->incomingReliableSequenceNumber) { + continue; + } + } else if (incomingCommand->reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { + break; + } + + if (incomingCommand->reliableSequenceNumber <= reliableSequenceNumber) { + if (incomingCommand->reliableSequenceNumber < reliableSequenceNumber) { + break; + } + + goto discardCommand; + } + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT: + unreliableSequenceNumber = ENET_NET_TO_HOST_16(command->sendUnreliable.unreliableSequenceNumber); + + if (reliableSequenceNumber == channel->incomingReliableSequenceNumber && unreliableSequenceNumber <= channel->incomingUnreliableSequenceNumber) { + goto discardCommand; + } + + for (currentCommand = enet_list_previous(enet_list_end(&channel->incomingUnreliableCommands)); + currentCommand != enet_list_end(&channel->incomingUnreliableCommands); + currentCommand = enet_list_previous(currentCommand) + ) { + incomingCommand = (ENetIncomingCommand *) currentCommand; + + if ((command->header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED) { + continue; + } + + if (reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { + if (incomingCommand->reliableSequenceNumber < channel->incomingReliableSequenceNumber) { + continue; + } + } else if (incomingCommand->reliableSequenceNumber >= channel->incomingReliableSequenceNumber) { + break; + } + + if (incomingCommand->reliableSequenceNumber < reliableSequenceNumber) { + break; + } + + if (incomingCommand->reliableSequenceNumber > reliableSequenceNumber) { + continue; + } + + if (incomingCommand->unreliableSequenceNumber <= unreliableSequenceNumber) { + if (incomingCommand->unreliableSequenceNumber < unreliableSequenceNumber) { + break; + } + + goto discardCommand; + } + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + currentCommand = enet_list_end(&channel->incomingUnreliableCommands); + break; + + default: + goto discardCommand; + } + + if (peer->totalWaitingData >= peer->host->maximumWaitingData) { + goto notifyError; + } + + packet = enet_packet_create(data, dataLength, flags); + if (packet == NULL) { + goto notifyError; + } + + incomingCommand = (ENetIncomingCommand *) enet_malloc(sizeof(ENetIncomingCommand)); + if (incomingCommand == NULL) { + goto notifyError; + } + + incomingCommand->reliableSequenceNumber = command->header.reliableSequenceNumber; + incomingCommand->unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; + incomingCommand->command = *command; + incomingCommand->fragmentCount = fragmentCount; + incomingCommand->fragmentsRemaining = fragmentCount; + incomingCommand->packet = packet; + incomingCommand->fragments = NULL; + + if (fragmentCount > 0) { + if (fragmentCount <= ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) { + incomingCommand->fragments = (enet_uint32 *) enet_malloc((fragmentCount + 31) / 32 * sizeof(enet_uint32)); + } + + if (incomingCommand->fragments == NULL) { + enet_free(incomingCommand); + + goto notifyError; + } + + memset(incomingCommand->fragments, 0, (fragmentCount + 31) / 32 * sizeof(enet_uint32)); + } + + if (packet != NULL) { + ++packet->referenceCount; + peer->totalWaitingData += packet->dataLength; + } + + enet_list_insert(enet_list_next(currentCommand), incomingCommand); + + switch (command->header.command & ENET_PROTOCOL_COMMAND_MASK) { + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: + enet_peer_dispatch_incoming_reliable_commands(peer, channel); + break; + + default: + enet_peer_dispatch_incoming_unreliable_commands(peer, channel); + break; + } + + return incomingCommand; + + discardCommand: + if (fragmentCount > 0) { + goto notifyError; + } + + if (packet != NULL && packet->referenceCount == 0) { + enet_packet_destroy(packet); + } + + return &dummyCommand; + + notifyError: + if (packet != NULL && packet->referenceCount == 0) { + enet_packet_destroy(packet); + } + + return NULL; + } /* enet_peer_queue_incoming_command */ + +// =======================================================================// +// ! +// ! Host +// ! +// =======================================================================// + + /** Creates a host for communicating to peers. + * + * @param address the address at which other peers may connect to this host. If NULL, then no peers may connect to the host. + * @param peerCount the maximum number of peers that should be allocated for the host. + * @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT + * @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. + * @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth. + * + * @returns the host on success and NULL on failure + * + * @remarks ENet will strategically drop packets on specific sides of a connection between hosts + * to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine + * the window size of a connection which limits the amount of reliable packets that may be in transit + * at any given time. + */ + ENetHost * enet_host_create(const ENetAddress *address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) { + ENetHost *host; + ENetPeer *currentPeer; + + if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID) { + return NULL; + } + + host = (ENetHost *) enet_malloc(sizeof(ENetHost)); + if (host == NULL) { return NULL; } + memset(host, 0, sizeof(ENetHost)); + + host->peers = (ENetPeer *) enet_malloc(peerCount * sizeof(ENetPeer)); + if (host->peers == NULL) { + enet_free(host); + return NULL; + } + + memset(host->peers, 0, peerCount * sizeof(ENetPeer)); + + host->socket = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM); + if (host->socket != ENET_SOCKET_NULL) { + enet_socket_set_option (host->socket, ENET_SOCKOPT_IPV6_V6ONLY, 0); + } + + if (host->socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind(host->socket, address) < 0)) { + if (host->socket != ENET_SOCKET_NULL) { + enet_socket_destroy(host->socket); + } + + enet_free(host->peers); + enet_free(host); + + return NULL; + } + + enet_socket_set_option(host->socket, ENET_SOCKOPT_NONBLOCK, 1); + enet_socket_set_option(host->socket, ENET_SOCKOPT_BROADCAST, 1); + enet_socket_set_option(host->socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE); + enet_socket_set_option(host->socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE); + enet_socket_set_option(host->socket, ENET_SOCKOPT_IPV6_V6ONLY, 0); + + if (address != NULL && enet_socket_get_address(host->socket, &host->address) < 0) { + host->address = *address; + } + + if (!channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) { + channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; + } else if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) { + channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; + } + + host->randomSeed = (enet_uint32) (size_t) host; + host->randomSeed += enet_host_random_seed(); + host->randomSeed = (host->randomSeed << 16) | (host->randomSeed >> 16); + host->channelLimit = channelLimit; + host->incomingBandwidth = incomingBandwidth; + host->outgoingBandwidth = outgoingBandwidth; + host->bandwidthThrottleEpoch = 0; + host->recalculateBandwidthLimits = 0; + host->mtu = ENET_HOST_DEFAULT_MTU; + host->peerCount = peerCount; + host->commandCount = 0; + host->bufferCount = 0; + host->checksum = NULL; + host->receivedAddress.host = ENET_HOST_ANY; + host->receivedAddress.port = 0; + host->receivedData = NULL; + host->receivedDataLength = 0; + host->totalSentData = 0; + host->totalSentPackets = 0; + host->totalReceivedData = 0; + host->totalReceivedPackets = 0; + host->connectedPeers = 0; + host->bandwidthLimitedPeers = 0; + host->duplicatePeers = ENET_PROTOCOL_MAXIMUM_PEER_ID; + host->maximumPacketSize = ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE; + host->maximumWaitingData = ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA; + host->compressor.context = NULL; + host->compressor.compress = NULL; + host->compressor.decompress = NULL; + host->compressor.destroy = NULL; + host->intercept = NULL; + + enet_list_clear(&host->dispatchQueue); + + for (currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { + currentPeer->host = host; + currentPeer->incomingPeerID = currentPeer - host->peers; + currentPeer->outgoingSessionID = currentPeer->incomingSessionID = 0xFF; + currentPeer->data = NULL; + + enet_list_clear(¤tPeer->acknowledgements); + enet_list_clear(¤tPeer->sentReliableCommands); + enet_list_clear(¤tPeer->sentUnreliableCommands); + enet_list_clear(¤tPeer->outgoingReliableCommands); + enet_list_clear(¤tPeer->outgoingUnreliableCommands); + enet_list_clear(¤tPeer->dispatchedCommands); + + enet_peer_reset(currentPeer); + } + + return host; + } /* enet_host_create */ + + /** Destroys the host and all resources associated with it. + * @param host pointer to the host to destroy + */ + void enet_host_destroy(ENetHost *host) { + ENetPeer *currentPeer; + + if (host == NULL) { + return; + } + + enet_socket_destroy(host->socket); + + for (currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { + enet_peer_reset(currentPeer); + } + + if (host->compressor.context != NULL && host->compressor.destroy) { + (*host->compressor.destroy)(host->compressor.context); + } + + enet_free(host->peers); + enet_free(host); + } + + /** Initiates a connection to a foreign host. + * @param host host seeking the connection + * @param address destination for the connection + * @param channelCount number of channels to allocate + * @param data user data supplied to the receiving host + * @returns a peer representing the foreign host on success, NULL on failure + * @remarks The peer returned will have not completed the connection until enet_host_service() + * notifies of an ENET_EVENT_TYPE_CONNECT event for the peer. + */ + ENetPeer * enet_host_connect(ENetHost *host, const ENetAddress *address, size_t channelCount, enet_uint32 data) { + ENetPeer *currentPeer; + ENetChannel *channel; + ENetProtocol command; + + if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) { + channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; + } else if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) { + channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; + } + + for (currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { + if (currentPeer->state == ENET_PEER_STATE_DISCONNECTED) { + break; + } + } + + if (currentPeer >= &host->peers[host->peerCount]) { + return NULL; + } + + currentPeer->channels = (ENetChannel *) enet_malloc(channelCount * sizeof(ENetChannel)); + if (currentPeer->channels == NULL) { + return NULL; + } + + currentPeer->channelCount = channelCount; + currentPeer->state = ENET_PEER_STATE_CONNECTING; + currentPeer->address = *address; + currentPeer->connectID = ++host->randomSeed; + + if (host->outgoingBandwidth == 0) { + currentPeer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + } else { + currentPeer->windowSize = (host->outgoingBandwidth / ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + } + + if (currentPeer->windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) { + currentPeer->windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + } else if (currentPeer->windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) { + currentPeer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + } + + for (channel = currentPeer->channels; channel < ¤tPeer->channels[channelCount]; ++channel) { + channel->outgoingReliableSequenceNumber = 0; + channel->outgoingUnreliableSequenceNumber = 0; + channel->incomingReliableSequenceNumber = 0; + channel->incomingUnreliableSequenceNumber = 0; + + enet_list_clear(&channel->incomingReliableCommands); + enet_list_clear(&channel->incomingUnreliableCommands); + + channel->usedReliableWindows = 0; + memset(channel->reliableWindows, 0, sizeof(channel->reliableWindows)); + } + + command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + command.connect.outgoingPeerID = ENET_HOST_TO_NET_16(currentPeer->incomingPeerID); + command.connect.incomingSessionID = currentPeer->incomingSessionID; + command.connect.outgoingSessionID = currentPeer->outgoingSessionID; + command.connect.mtu = ENET_HOST_TO_NET_32(currentPeer->mtu); + command.connect.windowSize = ENET_HOST_TO_NET_32(currentPeer->windowSize); + command.connect.channelCount = ENET_HOST_TO_NET_32(channelCount); + command.connect.incomingBandwidth = ENET_HOST_TO_NET_32(host->incomingBandwidth); + command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32(host->outgoingBandwidth); + command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32(currentPeer->packetThrottleInterval); + command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32(currentPeer->packetThrottleAcceleration); + command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32(currentPeer->packetThrottleDeceleration); + command.connect.connectID = currentPeer->connectID; + command.connect.data = ENET_HOST_TO_NET_32(data); + + enet_peer_queue_outgoing_command(currentPeer, &command, NULL, 0, 0); + + return currentPeer; + } /* enet_host_connect */ + + /** Queues a packet to be sent to all peers associated with the host. + * @param host host on which to broadcast the packet + * @param channelID channel on which to broadcast + * @param packet packet to broadcast + */ + void enet_host_broadcast(ENetHost *host, enet_uint8 channelID, ENetPacket *packet) { + ENetPeer *currentPeer; + + for (currentPeer = host->peers; currentPeer < &host->peers[host->peerCount]; ++currentPeer) { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) { + continue; + } + + enet_peer_send(currentPeer, channelID, packet); + } + + if (packet->referenceCount == 0) { + enet_packet_destroy(packet); + } + } + + /** Sends raw data to specified address. Useful when you want to send unconnected data using host's socket. + * @param host host sending data + * @param address destination address + * @param data data pointer + * @param dataLength length of data to send + * @retval >=0 bytes sent + * @retval <0 error + * @sa enet_socket_send + */ + int enet_host_send_raw(ENetHost *host, const ENetAddress* address, enet_uint8* data, size_t dataLength) { + ENetBuffer buffer; + buffer.data = data; + buffer.dataLength = dataLength; + return enet_socket_send(host->socket, address, &buffer, 1); + } + + /** Sends raw data to specified address with extended arguments. Allows to send only part of data, handy for other programming languages. + * I.e. if you have data =- { 0, 1, 2, 3 } and call function as enet_host_send_raw_ex(data, 1, 2) then it will skip 1 byte and send 2 bytes { 1, 2 }. + * @param host host sending data + * @param address destination address + * @param data data pointer + * @param skipBytes number of bytes to skip from start of data + * @param bytesToSend number of bytes to send + * @retval >=0 bytes sent + * @retval <0 error + * @sa enet_socket_send + */ + int enet_host_send_raw_ex(ENetHost *host, const ENetAddress* address, enet_uint8* data, size_t skipBytes, size_t bytesToSend) { + ENetBuffer buffer; + buffer.data = data + skipBytes; + buffer.dataLength = bytesToSend; + return enet_socket_send(host->socket, address, &buffer, 1); + } + + /** Sets intercept callback for the host. + * @param host host to set a callback + * @param callback intercept callback + */ + void enet_host_set_intercept(ENetHost *host, const ENetInterceptCallback callback) { + host->intercept = callback; + } + + /** Sets the packet compressor the host should use to compress and decompress packets. + * @param host host to enable or disable compression for + * @param compressor callbacks for for the packet compressor; if NULL, then compression is disabled + */ + void enet_host_compress(ENetHost *host, const ENetCompressor *compressor) { + if (host->compressor.context != NULL && host->compressor.destroy) { + (*host->compressor.destroy)(host->compressor.context); + } + + if (compressor) { + host->compressor = *compressor; + } else { + host->compressor.context = NULL; + } + } + + /** Limits the maximum allowed channels of future incoming connections. + * @param host host to limit + * @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT + */ + void enet_host_channel_limit(ENetHost *host, size_t channelLimit) { + if (!channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) { + channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; + } else if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) { + channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; + } + + host->channelLimit = channelLimit; + } + + /** Adjusts the bandwidth limits of a host. + * @param host host to adjust + * @param incomingBandwidth new incoming bandwidth + * @param outgoingBandwidth new outgoing bandwidth + * @remarks the incoming and outgoing bandwidth parameters are identical in function to those + * specified in enet_host_create(). + */ + void enet_host_bandwidth_limit(ENetHost *host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) { + host->incomingBandwidth = incomingBandwidth; + host->outgoingBandwidth = outgoingBandwidth; + host->recalculateBandwidthLimits = 1; + } + + void enet_host_bandwidth_throttle(ENetHost *host) { + enet_uint32 timeCurrent = enet_time_get(); + enet_uint32 elapsedTime = timeCurrent - host->bandwidthThrottleEpoch; + enet_uint32 peersRemaining = (enet_uint32) host->connectedPeers; + enet_uint32 dataTotal = ~0; + enet_uint32 bandwidth = ~0; + enet_uint32 throttle = 0; + enet_uint32 bandwidthLimit = 0; + + int needsAdjustment = host->bandwidthLimitedPeers > 0 ? 1 : 0; + ENetPeer *peer; + ENetProtocol command; + + if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) { + return; + } + + if (host->outgoingBandwidth == 0 && host->incomingBandwidth == 0) { + return; + } + + host->bandwidthThrottleEpoch = timeCurrent; + + if (peersRemaining == 0) { + return; + } + + if (host->outgoingBandwidth != 0) { + dataTotal = 0; + bandwidth = (host->outgoingBandwidth * elapsedTime) / 1000; + + for (peer = host->peers; peer < &host->peers[host->peerCount]; ++peer) { + if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { + continue; + } + + dataTotal += peer->outgoingDataTotal; + } + } + + while (peersRemaining > 0 && needsAdjustment != 0) { + needsAdjustment = 0; + + if (dataTotal <= bandwidth) { + throttle = ENET_PEER_PACKET_THROTTLE_SCALE; + } else { + throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; + } + + for (peer = host->peers; peer < &host->peers[host->peerCount]; ++peer) { + enet_uint32 peerBandwidth; + + if ((peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) || + peer->incomingBandwidth == 0 || + peer->outgoingBandwidthThrottleEpoch == timeCurrent + ) { + continue; + } + + peerBandwidth = (peer->incomingBandwidth * elapsedTime) / 1000; + if ((throttle * peer->outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth) { + continue; + } + + peer->packetThrottleLimit = (peerBandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / peer->outgoingDataTotal; + + if (peer->packetThrottleLimit == 0) { + peer->packetThrottleLimit = 1; + } + + if (peer->packetThrottle > peer->packetThrottleLimit) { + peer->packetThrottle = peer->packetThrottleLimit; + } + + peer->outgoingBandwidthThrottleEpoch = timeCurrent; + + peer->incomingDataTotal = 0; + peer->outgoingDataTotal = 0; + + needsAdjustment = 1; + --peersRemaining; + bandwidth -= peerBandwidth; + dataTotal -= peerBandwidth; + } + } + + if (peersRemaining > 0) { + if (dataTotal <= bandwidth) { + throttle = ENET_PEER_PACKET_THROTTLE_SCALE; + } else { + throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; + } + + for (peer = host->peers; + peer < &host->peers[host->peerCount]; + ++peer) + { + if ((peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) || peer->outgoingBandwidthThrottleEpoch == timeCurrent) { + continue; + } + + peer->packetThrottleLimit = throttle; + + if (peer->packetThrottle > peer->packetThrottleLimit) { + peer->packetThrottle = peer->packetThrottleLimit; + } + + peer->incomingDataTotal = 0; + peer->outgoingDataTotal = 0; + } + } + + if (host->recalculateBandwidthLimits) { + host->recalculateBandwidthLimits = 0; + + peersRemaining = (enet_uint32) host->connectedPeers; + bandwidth = host->incomingBandwidth; + needsAdjustment = 1; + + if (bandwidth == 0) { + bandwidthLimit = 0; + } else { + while (peersRemaining > 0 && needsAdjustment != 0) { + needsAdjustment = 0; + bandwidthLimit = bandwidth / peersRemaining; + + for (peer = host->peers; peer < &host->peers[host->peerCount]; ++peer) { + if ((peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) || + peer->incomingBandwidthThrottleEpoch == timeCurrent + ) { + continue; + } + + if (peer->outgoingBandwidth > 0 && peer->outgoingBandwidth >= bandwidthLimit) { + continue; + } + + peer->incomingBandwidthThrottleEpoch = timeCurrent; + + needsAdjustment = 1; + --peersRemaining; + bandwidth -= peer->outgoingBandwidth; + } + } + } + + for (peer = host->peers; peer < &host->peers[host->peerCount]; ++peer) { + if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) { + continue; + } + + command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; + command.header.channelID = 0xFF; + command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32(host->outgoingBandwidth); + + if (peer->incomingBandwidthThrottleEpoch == timeCurrent) { + command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32(peer->outgoingBandwidth); + } else { + command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32(bandwidthLimit); + } + + enet_peer_queue_outgoing_command(peer, &command, NULL, 0, 0); + } + } + } /* enet_host_bandwidth_throttle */ + +// =======================================================================// +// ! +// ! Time +// ! +// =======================================================================// + + #ifdef _WIN32 + static LARGE_INTEGER getFILETIMEoffset() { + SYSTEMTIME s; + FILETIME f; + LARGE_INTEGER t; + + s.wYear = 1970; + s.wMonth = 1; + s.wDay = 1; + s.wHour = 0; + s.wMinute = 0; + s.wSecond = 0; + s.wMilliseconds = 0; + SystemTimeToFileTime(&s, &f); + t.QuadPart = f.dwHighDateTime; + t.QuadPart <<= 32; + t.QuadPart |= f.dwLowDateTime; + return (t); + } + + int clock_gettime(int X, struct timespec *tv) { + LARGE_INTEGER t; + FILETIME f; + double microseconds; + static LARGE_INTEGER offset; + static double frequencyToMicroseconds; + static int initialized = 0; + static BOOL usePerformanceCounter = 0; + + if (!initialized) { + LARGE_INTEGER performanceFrequency; + initialized = 1; + usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency); + if (usePerformanceCounter) { + QueryPerformanceCounter(&offset); + frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.; + } else { + offset = getFILETIMEoffset(); + frequencyToMicroseconds = 10.; + } + } + if (usePerformanceCounter) { + QueryPerformanceCounter(&t); + } else { + GetSystemTimeAsFileTime(&f); + t.QuadPart = f.dwHighDateTime; + t.QuadPart <<= 32; + t.QuadPart |= f.dwLowDateTime; + } + + t.QuadPart -= offset.QuadPart; + microseconds = (double)t.QuadPart / frequencyToMicroseconds; + t.QuadPart = (LONGLONG)microseconds; + tv->tv_sec = (long)(t.QuadPart / 1000000); + tv->tv_nsec = t.QuadPart % 1000000 * 1000; + return (0); + } + #elif __APPLE__ && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 + #define CLOCK_MONOTONIC 0 + + int clock_gettime(int X, struct timespec *ts) { + clock_serv_t cclock; + mach_timespec_t mts; + + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + + ts->tv_sec = mts.tv_sec; + ts->tv_nsec = mts.tv_nsec; + + return 0; + } + #endif + + enet_uint32 enet_time_get() { + // TODO enet uses 32 bit timestamps. We should modify it to use + // 64 bit timestamps, but this is not trivial since we'd end up + // changing half the structs in enet. For now, retain 32 bits, but + // use an offset so we don't run out of bits. Basically, the first + // call of enet_time_get() will always return 1, and follow-up calls + // indicate elapsed time since the first call. + // + // Note that we don't want to return 0 from the first call, in case + // some part of enet uses 0 as a special value (meaning time not set + // for example). + static uint64_t start_time_ns = 0; + + struct timespec ts; + #if defined(CLOCK_MONOTONIC_RAW) + clock_gettime(CLOCK_MONOTONIC_RAW, &ts); + #else + clock_gettime(CLOCK_MONOTONIC, &ts); + #endif + + static const uint64_t ns_in_s = 1000 * 1000 * 1000; + static const uint64_t ns_in_ms = 1000 * 1000; + uint64_t current_time_ns = ts.tv_nsec + (uint64_t)ts.tv_sec * ns_in_s; + + // Most of the time we just want to atomically read the start time. We + // could just use a single CAS instruction instead of this if, but it + // would be slower in the average case. + // + // Note that statics are auto-initialized to zero, and starting a thread + // implies a memory barrier. So we know that whatever thread calls this, + // it correctly sees the start_time_ns as 0 initially. + uint64_t offset_ns = ENET_ATOMIC_READ(&start_time_ns); + if (offset_ns == 0) { + // We still need to CAS, since two different threads can get here + // at the same time. + // + // We assume that current_time_ns is > 1ms. + // + // Set the value of the start_time_ns, such that the first timestamp + // is at 1ms. This ensures 0 remains a special value. + uint64_t want_value = current_time_ns - 1 * ns_in_ms; + uint64_t old_value = ENET_ATOMIC_CAS(&start_time_ns, 0, want_value); + offset_ns = old_value == 0 ? want_value : old_value; + } + + uint64_t result_in_ns = current_time_ns - offset_ns; + return (enet_uint32)(result_in_ns / ns_in_ms); + } + +// =======================================================================// +// ! +// ! Platform Specific (Unix) +// ! +// =======================================================================// + + #ifndef _WIN32 + + int enet_initialize(void) { + return 0; + } + + void enet_deinitialize(void) {} + + enet_uint64 enet_host_random_seed(void) { + return (enet_uint64) time(NULL); + } + + int enet_address_set_host_ip(ENetAddress *address, const char *name) { + if (!inet_pton(AF_INET6, name, &address->host)) { + return -1; + } + + return 0; + } + + int enet_address_set_host(ENetAddress *address, const char *name) { + struct addrinfo hints, *resultList = NULL, *result = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + + if (getaddrinfo(name, NULL, &hints, &resultList) != 0) { + return -1; + } + + for (result = resultList; result != NULL; result = result->ai_next) { + if (result->ai_addr != NULL && result->ai_addrlen >= sizeof(struct sockaddr_in)) { + if (result->ai_family == AF_INET) { + struct sockaddr_in * sin = (struct sockaddr_in *) result->ai_addr; + + ((uint32_t *)&address->host.s6_addr)[0] = 0; + ((uint32_t *)&address->host.s6_addr)[1] = 0; + ((uint32_t *)&address->host.s6_addr)[2] = htonl(0xffff); + ((uint32_t *)&address->host.s6_addr)[3] = sin->sin_addr.s_addr; + + freeaddrinfo(resultList); + + return 0; + } + else if(result->ai_family == AF_INET6) { + struct sockaddr_in6 * sin = (struct sockaddr_in6 *)result->ai_addr; + + address->host = sin->sin6_addr; + address->sin6_scope_id = sin->sin6_scope_id; + + freeaddrinfo(resultList); + + return 0; + } + } + } + + + if (resultList != NULL) { + freeaddrinfo(resultList); + } + + return enet_address_set_host_ip(address, name); + } /* enet_address_set_host */ + + int enet_address_get_host_ip(const ENetAddress *address, char *name, size_t nameLength) { + if (inet_ntop(AF_INET6, &address->host, name, nameLength) == NULL) { + return -1; + } + + return 0; + } + + int enet_address_get_host(const ENetAddress *address, char *name, size_t nameLength) { + struct sockaddr_in6 sin; + int err; + + memset(&sin, 0, sizeof(struct sockaddr_in6)); + + sin.sin6_family = AF_INET6; + sin.sin6_port = ENET_HOST_TO_NET_16 (address->port); + sin.sin6_addr = address->host; + sin.sin6_scope_id = address->sin6_scope_id; + + err = getnameinfo((struct sockaddr *) &sin, sizeof(sin), name, nameLength, NULL, 0, NI_NAMEREQD); + if (!err) { + if (name != NULL && nameLength > 0 && !memchr(name, '\0', nameLength)) { + return -1; + } + return 0; + } + if (err != EAI_NONAME) { + return -1; + } + + return enet_address_get_host_ip(address, name, nameLength); + } /* enet_address_get_host */ + + int enet_socket_bind(ENetSocket socket, const ENetAddress *address) { + struct sockaddr_in6 sin; + memset(&sin, 0, sizeof(struct sockaddr_in6)); + sin.sin6_family = AF_INET6; + + if (address != NULL) { + sin.sin6_port = ENET_HOST_TO_NET_16(address->port); + sin.sin6_addr = address->host; + sin.sin6_scope_id = address->sin6_scope_id; + } else { + sin.sin6_port = 0; + sin.sin6_addr = ENET_HOST_ANY; + sin.sin6_scope_id = 0; + } + + return bind(socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in6)); + } + + int enet_socket_get_address(ENetSocket socket, ENetAddress *address) { + struct sockaddr_in6 sin; + socklen_t sinLength = sizeof(struct sockaddr_in6); + + if (getsockname(socket, (struct sockaddr *) &sin, &sinLength) == -1) { + return -1; + } + + address->host = sin.sin6_addr; + address->port = ENET_NET_TO_HOST_16(sin.sin6_port); + address->sin6_scope_id = sin.sin6_scope_id; + + return 0; + } + + int enet_socket_listen(ENetSocket socket, int backlog) { + return listen(socket, backlog < 0 ? SOMAXCONN : backlog); + } + + ENetSocket enet_socket_create(ENetSocketType type) { + return socket(PF_INET6, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); + } + + int enet_socket_set_option(ENetSocket socket, ENetSocketOption option, int value) { + int result = -1; + + switch (option) { + case ENET_SOCKOPT_NONBLOCK: + result = fcntl(socket, F_SETFL, (value ? O_NONBLOCK : 0) | (fcntl(socket, F_GETFL) & ~O_NONBLOCK)); + break; + + case ENET_SOCKOPT_BROADCAST: + result = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_REUSEADDR: + result = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_RCVBUF: + result = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_SNDBUF: + result = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_RCVTIMEO: { + struct timeval timeVal; + timeVal.tv_sec = value / 1000; + timeVal.tv_usec = (value % 1000) * 1000; + result = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeVal, sizeof(struct timeval)); + break; + } + + case ENET_SOCKOPT_SNDTIMEO: { + struct timeval timeVal; + timeVal.tv_sec = value / 1000; + timeVal.tv_usec = (value % 1000) * 1000; + result = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeVal, sizeof(struct timeval)); + break; + } + + case ENET_SOCKOPT_NODELAY: + result = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_IPV6_V6ONLY: + result = setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&value, sizeof(int)); + break; + + default: + break; + } + return result == -1 ? -1 : 0; + } /* enet_socket_set_option */ + + int enet_socket_get_option(ENetSocket socket, ENetSocketOption option, int *value) { + int result = -1; + socklen_t len; + + switch (option) { + case ENET_SOCKOPT_ERROR: + len = sizeof(int); + result = getsockopt(socket, SOL_SOCKET, SO_ERROR, value, &len); + break; + + default: + break; + } + return result == -1 ? -1 : 0; + } + + int enet_socket_connect(ENetSocket socket, const ENetAddress *address) { + struct sockaddr_in6 sin; + int result; + + memset(&sin, 0, sizeof(struct sockaddr_in6)); + + sin.sin6_family = AF_INET6; + sin.sin6_port = ENET_HOST_TO_NET_16(address->port); + sin.sin6_addr = address->host; + sin.sin6_scope_id = address->sin6_scope_id; + + result = connect(socket, (struct sockaddr *)&sin, sizeof(struct sockaddr_in6)); + if (result == -1 && errno == EINPROGRESS) { + return 0; + } + + return result; + } + + ENetSocket enet_socket_accept(ENetSocket socket, ENetAddress *address) { + int result; + struct sockaddr_in6 sin; + socklen_t sinLength = sizeof(struct sockaddr_in6); + + result = accept(socket,address != NULL ? (struct sockaddr *) &sin : NULL, address != NULL ? &sinLength : NULL); + + if (result == -1) { + return ENET_SOCKET_NULL; + } + + if (address != NULL) { + address->host = sin.sin6_addr; + address->port = ENET_NET_TO_HOST_16 (sin.sin6_port); + address->sin6_scope_id = sin.sin6_scope_id; + } + + return result; + } + + int enet_socket_shutdown(ENetSocket socket, ENetSocketShutdown how) { + return shutdown(socket, (int) how); + } + + void enet_socket_destroy(ENetSocket socket) { + if (socket != -1) { + close(socket); + } + } + + int enet_socket_send(ENetSocket socket, const ENetAddress *address, const ENetBuffer *buffers, size_t bufferCount) { + struct msghdr msgHdr; + struct sockaddr_in6 sin; + int sentLength; + + memset(&msgHdr, 0, sizeof(struct msghdr)); + + if (address != NULL) { + memset(&sin, 0, sizeof(struct sockaddr_in6)); + + sin.sin6_family = AF_INET6; + sin.sin6_port = ENET_HOST_TO_NET_16(address->port); + sin.sin6_addr = address->host; + sin.sin6_scope_id = address->sin6_scope_id; + + msgHdr.msg_name = &sin; + msgHdr.msg_namelen = sizeof(struct sockaddr_in6); + } + + msgHdr.msg_iov = (struct iovec *) buffers; + msgHdr.msg_iovlen = bufferCount; + + sentLength = sendmsg(socket, &msgHdr, MSG_NOSIGNAL); + + if (sentLength == -1) { + if (errno == EWOULDBLOCK) { + return 0; + } + + return -1; + } + + return sentLength; + } /* enet_socket_send */ + + int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buffers, size_t bufferCount) { + struct msghdr msgHdr; + struct sockaddr_in6 sin; + int recvLength; + + memset(&msgHdr, 0, sizeof(struct msghdr)); + + if (address != NULL) { + msgHdr.msg_name = &sin; + msgHdr.msg_namelen = sizeof(struct sockaddr_in6); + } + + msgHdr.msg_iov = (struct iovec *) buffers; + msgHdr.msg_iovlen = bufferCount; + + recvLength = recvmsg(socket, &msgHdr, MSG_NOSIGNAL); + + if (recvLength == -1) { + if (errno == EWOULDBLOCK) { + return 0; + } + + return -1; + } + + if (msgHdr.msg_flags & MSG_TRUNC) { + return -1; + } + + if (address != NULL) { + address->host = sin.sin6_addr; + address->port = ENET_NET_TO_HOST_16(sin.sin6_port); + address->sin6_scope_id = sin.sin6_scope_id; + } + + return recvLength; + } /* enet_socket_receive */ + + int enet_socketset_select(ENetSocket maxSocket, ENetSocketSet *readSet, ENetSocketSet *writeSet, enet_uint32 timeout) { + struct timeval timeVal; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + return select(maxSocket + 1, readSet, writeSet, NULL, &timeVal); + } + + int enet_socket_wait(ENetSocket socket, enet_uint32 *condition, enet_uint64 timeout) { + struct pollfd pollSocket; + int pollCount; + + pollSocket.fd = socket; + pollSocket.events = 0; + + if (*condition & ENET_SOCKET_WAIT_SEND) { + pollSocket.events |= POLLOUT; + } + + if (*condition & ENET_SOCKET_WAIT_RECEIVE) { + pollSocket.events |= POLLIN; + } + + pollCount = poll(&pollSocket, 1, timeout); + + if (pollCount < 0) { + if (errno == EINTR && *condition & ENET_SOCKET_WAIT_INTERRUPT) { + *condition = ENET_SOCKET_WAIT_INTERRUPT; + + return 0; + } + + return -1; + } + + *condition = ENET_SOCKET_WAIT_NONE; + + if (pollCount == 0) { + return 0; + } + + if (pollSocket.revents & POLLOUT) { + *condition |= ENET_SOCKET_WAIT_SEND; + } + + if (pollSocket.revents & POLLIN) { + *condition |= ENET_SOCKET_WAIT_RECEIVE; + } + + return 0; + } /* enet_socket_wait */ + + #endif // !_WIN32 + + +// =======================================================================// +// ! +// ! Platform Specific (Win) +// ! +// =======================================================================// + + #ifdef _WIN32 + + #ifdef __MINGW32__ + // inet_ntop/inet_pton for MinGW from http://mingw-users.1079350.n2.nabble.com/IPv6-getaddrinfo-amp-inet-ntop-td5891996.html + const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt) { + if (af == AF_INET) { + struct sockaddr_in in; + memset(&in, 0, sizeof(in)); + in.sin_family = AF_INET; + memcpy(&in.sin_addr, src, sizeof(struct in_addr)); + getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in), dst, cnt, NULL, 0, NI_NUMERICHOST); + return dst; + } + else if (af == AF_INET6) { + struct sockaddr_in6 in; + memset(&in, 0, sizeof(in)); + in.sin6_family = AF_INET6; + memcpy(&in.sin6_addr, src, sizeof(struct in_addr6)); + getnameinfo((struct sockaddr *)&in, sizeof(struct sockaddr_in6), dst, cnt, NULL, 0, NI_NUMERICHOST); + return dst; + } + + return NULL; + } + + #define NS_INADDRSZ 4 + #define NS_IN6ADDRSZ 16 + #define NS_INT16SZ 2 + + int inet_pton4(const char *src, char *dst) { + uint8_t tmp[NS_INADDRSZ], *tp; + + int saw_digit = 0; + int octets = 0; + *(tp = tmp) = 0; + + int ch; + while ((ch = *src++) != '\0') + { + if (ch >= '0' && ch <= '9') + { + uint32_t n = *tp * 10 + (ch - '0'); + + if (saw_digit && *tp == 0) + return 0; + + if (n > 255) + return 0; + + *tp = n; + if (!saw_digit) + { + if (++octets > 4) + return 0; + saw_digit = 1; + } + } + else if (ch == '.' && saw_digit) + { + if (octets == 4) + return 0; + *++tp = 0; + saw_digit = 0; + } + else + return 0; + } + if (octets < 4) + return 0; + + memcpy(dst, tmp, NS_INADDRSZ); + + return 1; + } + + int inet_pton6(const char *src, char *dst) { + static const char xdigits[] = "0123456789abcdef"; + uint8_t tmp[NS_IN6ADDRSZ]; + + uint8_t *tp = (uint8_t*) memset(tmp, '\0', NS_IN6ADDRSZ); + uint8_t *endp = tp + NS_IN6ADDRSZ; + uint8_t *colonp = NULL; + + /* Leading :: requires some special handling. */ + if (*src == ':') + { + if (*++src != ':') + return 0; + } + + const char *curtok = src; + int saw_xdigit = 0; + uint32_t val = 0; + int ch; + while ((ch = tolower(*src++)) != '\0') + { + const char *pch = strchr(xdigits, ch); + if (pch != NULL) + { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return 0; + saw_xdigit = 1; + continue; + } + if (ch == ':') + { + curtok = src; + if (!saw_xdigit) + { + if (colonp) + return 0; + colonp = tp; + continue; + } + else if (*src == '\0') + { + return 0; + } + if (tp + NS_INT16SZ > endp) + return 0; + *tp++ = (uint8_t) (val >> 8) & 0xff; + *tp++ = (uint8_t) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, (char*) tp) > 0) + { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return 0; + } + if (saw_xdigit) + { + if (tp + NS_INT16SZ > endp) + return 0; + *tp++ = (uint8_t) (val >> 8) & 0xff; + *tp++ = (uint8_t) val & 0xff; + } + if (colonp != NULL) + { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + + if (tp == endp) + return 0; + + for (int i = 1; i <= n; i++) + { + endp[-i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return 0; + + memcpy(dst, tmp, NS_IN6ADDRSZ); + + return 1; + } + + + int inet_pton(int af, const char *src, struct in6_addr *dst) { + switch (af) + { + case AF_INET: + return inet_pton4(src, (char *)dst); + case AF_INET6: + return inet_pton6(src, (char *)dst); + default: + return -1; + } + } + #endif // __MINGW__ + + int enet_initialize(void) { + WORD versionRequested = MAKEWORD(1, 1); + WSADATA wsaData; + + if (WSAStartup(versionRequested, &wsaData)) { + return -1; + } + + if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1) { + WSACleanup(); + return -1; + } + + timeBeginPeriod(1); + return 0; + } + + void enet_deinitialize(void) { + timeEndPeriod(1); + WSACleanup(); + } + + enet_uint64 enet_host_random_seed(void) { + return (enet_uint64) timeGetTime(); + } + + int enet_address_set_host_ip(ENetAddress *address, const char *name) { + enet_uint8 vals[4] = { 0, 0, 0, 0 }; + int i; + + for (i = 0; i < 4; ++i) { + const char *next = name + 1; + if (*name != '0') { + long val = strtol(name, (char **) &next, 10); + if (val < 0 || val > 255 || next == name || next - name > 3) { + return -1; + } + vals[i] = (enet_uint8) val; + } + + if (*next != (i < 3 ? '.' : '\0')) { + return -1; + } + name = next + 1; + } + + memcpy(&address->host, vals, sizeof(enet_uint32)); + return 0; + } + + int enet_address_set_host(ENetAddress *address, const char *name) { + struct hostent *hostEntry = NULL; + hostEntry = gethostbyname(name); + + if (hostEntry == NULL || hostEntry->h_addrtype != AF_INET) { + if (!inet_pton(AF_INET6, name, &address->host)) { + return -1; + } + + return 0; + } + + ((enet_uint32 *)&address->host.s6_addr)[0] = 0; + ((enet_uint32 *)&address->host.s6_addr)[1] = 0; + ((enet_uint32 *)&address->host.s6_addr)[2] = htonl(0xffff); + ((enet_uint32 *)&address->host.s6_addr)[3] = *(enet_uint32 *)hostEntry->h_addr_list[0]; + + return 0; + } + + int enet_address_get_host_ip(const ENetAddress *address, char *name, size_t nameLength) { + if (inet_ntop(AF_INET6, (PVOID)&address->host, name, nameLength) == NULL) { + return -1; + } + + return 0; + } + + int enet_address_get_host(const ENetAddress *address, char *name, size_t nameLength) { + struct in6_addr in; + struct hostent *hostEntry = NULL; + + in = address->host; + hostEntry = gethostbyaddr((char *)&in, sizeof(struct in6_addr), AF_INET6); + + if (hostEntry == NULL) { + return enet_address_get_host_ip(address, name, nameLength); + } else { + size_t hostLen = strlen(hostEntry->h_name); + if (hostLen >= nameLength) { + return -1; + } + memcpy(name, hostEntry->h_name, hostLen + 1); + } + + return 0; + } + + int enet_socket_bind(ENetSocket socket, const ENetAddress *address) { + struct sockaddr_in6 sin; + memset(&sin, 0, sizeof(struct sockaddr_in6)); + sin.sin6_family = AF_INET6; + + if (address != NULL) { + sin.sin6_port = ENET_HOST_TO_NET_16 (address->port); + sin.sin6_addr = address->host; + sin.sin6_scope_id = address->sin6_scope_id; + } else { + sin.sin6_port = 0; + sin.sin6_addr = in6addr_any; + sin.sin6_scope_id = 0; + } + + return bind(socket, (struct sockaddr *) &sin, sizeof(struct sockaddr_in6)) == SOCKET_ERROR ? -1 : 0; + } + + int enet_socket_get_address(ENetSocket socket, ENetAddress *address) { + struct sockaddr_in6 sin; + int sinLength = sizeof(struct sockaddr_in6); + + if (getsockname(socket, (struct sockaddr *) &sin, &sinLength) == -1) { + return -1; + } + + address->host = sin.sin6_addr; + address->port = ENET_NET_TO_HOST_16(sin.sin6_port); + address->sin6_scope_id = sin.sin6_scope_id; + + return 0; + } + + int enet_socket_listen(ENetSocket socket, int backlog) { + return listen(socket, backlog < 0 ? SOMAXCONN : backlog) == SOCKET_ERROR ? -1 : 0; + } + + ENetSocket enet_socket_create(ENetSocketType type) { + return socket(PF_INET6, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); + } + + int enet_socket_set_option(ENetSocket socket, ENetSocketOption option, int value) { + int result = SOCKET_ERROR; + + switch (option) { + case ENET_SOCKOPT_NONBLOCK: { + u_long nonBlocking = (u_long) value; + result = ioctlsocket(socket, FIONBIO, &nonBlocking); + break; + } + + case ENET_SOCKOPT_BROADCAST: + result = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_REUSEADDR: + result = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_RCVBUF: + result = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_SNDBUF: + result = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_RCVTIMEO: + result = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_SNDTIMEO: + result = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_NODELAY: + result = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *)&value, sizeof(int)); + break; + + case ENET_SOCKOPT_IPV6_V6ONLY: + result = setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&value, sizeof(int)); + break; + + default: + break; + } + return result == SOCKET_ERROR ? -1 : 0; + } /* enet_socket_set_option */ + + int enet_socket_get_option(ENetSocket socket, ENetSocketOption option, int *value) { + int result = SOCKET_ERROR, len; + + switch (option) { + case ENET_SOCKOPT_ERROR: + len = sizeof(int); + result = getsockopt(socket, SOL_SOCKET, SO_ERROR, (char *)value, &len); + break; + + default: + break; + } + return result == SOCKET_ERROR ? -1 : 0; + } + + int enet_socket_connect(ENetSocket socket, const ENetAddress *address) { + struct sockaddr_in6 sin; + int result; + + memset(&sin, 0, sizeof(struct sockaddr_in6)); + + sin.sin6_family = AF_INET6; + sin.sin6_port = ENET_HOST_TO_NET_16(address->port); + sin.sin6_addr = address->host; + sin.sin6_scope_id = address->sin6_scope_id; + + result = connect(socket, (struct sockaddr *) &sin, sizeof(struct sockaddr_in6)); + if (result == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) { + return -1; + } + + return 0; + } + + ENetSocket enet_socket_accept(ENetSocket socket, ENetAddress *address) { + SOCKET result; + struct sockaddr_in6 sin; + int sinLength = sizeof(struct sockaddr_in6); + + result = accept(socket, address != NULL ? (struct sockaddr *)&sin : NULL, address != NULL ? &sinLength : NULL); + + if (result == INVALID_SOCKET) { + return ENET_SOCKET_NULL; + } + + if (address != NULL) { + address->host = sin.sin6_addr; + address->port = ENET_NET_TO_HOST_16(sin.sin6_port); + address->sin6_scope_id = sin.sin6_scope_id; + } + + return result; + } + + int enet_socket_shutdown(ENetSocket socket, ENetSocketShutdown how) { + return shutdown(socket, (int) how) == SOCKET_ERROR ? -1 : 0; + } + + void enet_socket_destroy(ENetSocket socket) { + if (socket != INVALID_SOCKET) { + closesocket(socket); + } + } + + int enet_socket_send(ENetSocket socket, const ENetAddress *address, const ENetBuffer *buffers, size_t bufferCount) { + struct sockaddr_in6 sin; + DWORD sentLength; + + if (address != NULL) { + memset(&sin, 0, sizeof(struct sockaddr_in6)); + + sin.sin6_family = AF_INET6; + sin.sin6_port = ENET_HOST_TO_NET_16(address->port); + sin.sin6_addr = address->host; + sin.sin6_scope_id = address->sin6_scope_id; + } + + if (WSASendTo(socket, + (LPWSABUF) buffers, + (DWORD) bufferCount, + &sentLength, + 0, + address != NULL ? (struct sockaddr *) &sin : NULL, + address != NULL ? sizeof(struct sockaddr_in6) : 0, + NULL, + NULL) == SOCKET_ERROR + ) { + return (WSAGetLastError() == WSAEWOULDBLOCK) ? 0 : -1; + } + + return (int) sentLength; + } + + int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buffers, size_t bufferCount) { + INT sinLength = sizeof(struct sockaddr_in6); + DWORD flags = 0, recvLength; + struct sockaddr_in6 sin; + + if (WSARecvFrom(socket, + (LPWSABUF) buffers, + (DWORD) bufferCount, + &recvLength, + &flags, + address != NULL ? (struct sockaddr *) &sin : NULL, + address != NULL ? &sinLength : NULL, + NULL, + NULL) == SOCKET_ERROR + ) { + switch (WSAGetLastError()) { + case WSAEWOULDBLOCK: + case WSAECONNRESET: + return 0; + } + + return -1; + } + + if (flags & MSG_PARTIAL) { + return -1; + } + + if (address != NULL) { + address->host = sin.sin6_addr; + address->port = ENET_NET_TO_HOST_16(sin.sin6_port); + address->sin6_scope_id = sin.sin6_scope_id; + } + + return (int) recvLength; + } /* enet_socket_receive */ + + int enet_socketset_select(ENetSocket maxSocket, ENetSocketSet *readSet, ENetSocketSet *writeSet, enet_uint32 timeout) { + struct timeval timeVal; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + return select(maxSocket + 1, readSet, writeSet, NULL, &timeVal); + } + + int enet_socket_wait(ENetSocket socket, enet_uint32 *condition, enet_uint64 timeout) { + fd_set readSet, writeSet; + struct timeval timeVal; + int selectCount; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + FD_ZERO(&readSet); + FD_ZERO(&writeSet); + + if (*condition & ENET_SOCKET_WAIT_SEND) { + FD_SET(socket, &writeSet); + } + + if (*condition & ENET_SOCKET_WAIT_RECEIVE) { + FD_SET(socket, &readSet); + } + + selectCount = select(socket + 1, &readSet, &writeSet, NULL, &timeVal); + + if (selectCount < 0) { + return -1; + } + + *condition = ENET_SOCKET_WAIT_NONE; + + if (selectCount == 0) { + return 0; + } + + if (FD_ISSET(socket, &writeSet)) { + *condition |= ENET_SOCKET_WAIT_SEND; + } + + if (FD_ISSET(socket, &readSet)) { + *condition |= ENET_SOCKET_WAIT_RECEIVE; + } + + return 0; + } /* enet_socket_wait */ + + #endif // _WIN32 + + +#ifdef __cplusplus +} +#endif + +#endif // ENET_IMPLEMENTATION +#endif // ENET_INCLUDE_H \ No newline at end of file diff --git a/include/zconf.h b/src/include/zconf.h similarity index 100% rename from include/zconf.h rename to src/include/zconf.h diff --git a/include/zlib.h b/src/include/zlib.h similarity index 100% rename from include/zlib.h rename to src/include/zlib.h diff --git a/main.cpp b/src/main.cpp similarity index 92% rename from main.cpp rename to src/main.cpp index 7adcac8..c4624ca 100644 --- a/main.cpp +++ b/src/main.cpp @@ -87,7 +87,7 @@ int main(int argc, char* argv[]){ const unsigned long long NPos = std::string::npos; struct stat info{}; - std::string ver = "0.921", link, Path = CheckDir(argv[0],ver),HTTP_Result; + std::string ver = "1.0", link, Path = CheckDir(argv[0],ver),HTTP_Result; std::thread CFU(CheckForUpdates,ver); CFU.join(); if(argc > 1){ @@ -115,7 +115,7 @@ int main(int argc, char* argv[]){ exit(-1); } } - }else MPDEV = true; + }else MPDEV = false; //Security auto*Sec = new std::thread(Check); Sec->join(); @@ -133,14 +133,12 @@ int main(int argc, char* argv[]){ Download(link,Settings); std::cout << "Download Complete!" << std::endl; } - std::cout << "Downloading mod..." << std::endl; - link = "https://beamng-mp.com/builds/client?did="+GlobalInfo.at(2); - Download(link,Path + R"(\mods\BeamMP.zip)"); - std::cout << "Download Complete!" << std::endl; - link.clear(); - std::thread Game(StartGame,ExeDir,(Path + "\\")); - Game.detach(); if(!MPDEV){ + std::cout << "Downloading mod..." << std::endl; + link = "https://beamng-mp.com/builds/client?did="+GlobalInfo.at(2); + Download(link,Path + R"(\mods\BeamMP.zip)"); + std::cout << "Download Complete!" << std::endl; + link.clear(); std::thread Game(StartGame,ExeDir,(Path + "\\")); Game.detach(); }else{