diff --git a/CMakeLists.txt b/CMakeLists.txt index c54b9abfd..72374090a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,20 +180,11 @@ ELSE (OPENGL_FOUND) SET(OPENGL_glu_LIBRARY glu32) ENDIF (OPENGL_FOUND) -# ADD_DEFINITIONS(-DBT_USE_FREEGLUT) #FIND_PACKAGE(GLU) -OPTION(BUILD_BULLET2_DEMOS "Set when you want to build the Bullet 2 demos" ON) -IF(BUILD_BULLET2_DEMOS) - - - IF(EXISTS ${BULLET_PHYSICS_SOURCE_DIR}/examples AND IS_DIRECTORY ${BULLET_PHYSICS_SOURCE_DIR}/examples) - SUBDIRS(examples) - ENDIF() -ENDIF(BUILD_BULLET2_DEMOS) IF (APPLE) FIND_LIBRARY(COCOA_LIBRARY Cocoa) @@ -207,6 +198,7 @@ IF(BUILD_BULLET3) IF(_CURRENT_OSX_VERSION VERSION_LESS 10.9) MESSAGE("Mac OSX below 10.9 has no OpenGL 3 support so please disable the BUILD_OPENGL3_DEMOS option") #unset(BUILD_OPENGL3_DEMOS CACHE) + OPTION(BUILD_OPENGL3_DEMOS "Set when you want to build the OpenGL3+ demos" OFF) ELSE() OPTION(BUILD_OPENGL3_DEMOS "Set when you want to build the OpenGL3+ demos" ON) @@ -222,8 +214,20 @@ IF(BUILD_OPENGL3_DEMOS) IF(EXISTS ${BULLET_PHYSICS_SOURCE_DIR}/Demos3 AND IS_DIRECTORY ${BULLET_PHYSICS_SOURCE_DIR}/Demos3) SUBDIRS(Demos3) ENDIF() +ELSE() + ADD_DEFINITIONS(-DNO_OPENGL3) ENDIF(BUILD_OPENGL3_DEMOS) +OPTION(BUILD_BULLET2_DEMOS "Set when you want to build the Bullet 2 demos" ON) +IF(BUILD_BULLET2_DEMOS) + + IF(EXISTS ${BULLET_PHYSICS_SOURCE_DIR}/examples AND IS_DIRECTORY ${BULLET_PHYSICS_SOURCE_DIR}/examples) + SUBDIRS(examples) + ENDIF() +ENDIF(BUILD_BULLET2_DEMOS) + + + OPTION(BUILD_EXTRAS "Set when you want to build the extras" ON) IF(BUILD_EXTRAS) SUBDIRS(Extras) diff --git a/build3/premake4.lua b/build3/premake4.lua index 797e5c4f4..53c087357 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -30,6 +30,11 @@ description = "Dynamically load OpenGL (instead of static/dynamic linking)" } + newoption + { + trigger = "noopengl3", + description = "Don't compile any OpenGL3+ code" + } newoption { @@ -37,7 +42,7 @@ description = "Use Midi controller to control parameters" } --- _OPTIONS["midi"] = "1"; +-- --_OPTIONS["midi"] = "1"; newoption { @@ -111,6 +116,10 @@ dofile ("findOpenCL.lua") dofile ("findDirectX11.lua") dofile ("findOpenGLGlewGlut.lua") + + if (not findOpenGL3()) then + defines {"NO_OPENGL3"} + end language "C++" @@ -122,7 +131,11 @@ include "../examples/HelloWorld" include "../examples/BasicDemo" - + if _OPTIONS["enet"] then + include "../examples/ThirdPartyLibs/enet" + include "../test/enet/client" + include "../test/enet/server" + end if not _OPTIONS["without-gtest"] then include "../test/gtest-1.7.0" diff --git a/build3/premake4_osx32 b/build3/premake4_osx32 new file mode 100755 index 000000000..5f5156216 Binary files /dev/null and b/build3/premake4_osx32 differ diff --git a/examples/ExampleBrowser/ExampleEntries.cpp b/examples/ExampleBrowser/ExampleEntries.cpp index 2b2b745e9..b37a7c433 100644 --- a/examples/ExampleBrowser/ExampleEntries.cpp +++ b/examples/ExampleBrowser/ExampleEntries.cpp @@ -33,9 +33,10 @@ #include "../RollingFrictionDemo/RollingFrictionDemo.h" #ifdef B3_USE_CLEW +#ifndef NO_OPENGL3 #include "../OpenCL/broadphase/PairBench.h" #include "../OpenCL/rigidbody/GpuConvexScene.h" - +#endif #endif //B3_USE_CLEW @@ -193,6 +194,7 @@ static ExampleEntry gDefaultExamples[]= }; #ifdef B3_USE_CLEW +#ifndef NO_OPENGL3 static ExampleEntry gOpenCLExamples[]= { ExampleEntry(0,"OpenCL (experimental)"), @@ -201,6 +203,7 @@ static ExampleEntry gOpenCLExamples[]= ExampleEntry(1,"Pair Bench", "Benchmark of overlapping pair search using OpenCL.", PairBenchOpenCLCreateFunc), }; +#endif #endif // static btAlignedObjectArray gAdditionalRegisteredExamples; @@ -223,11 +226,13 @@ ExampleEntries::~ExampleEntries() void ExampleEntries::initOpenCLExampleEntries() { #ifdef B3_USE_CLEW +#ifndef NO_OPENGL3 int numDefaultEntries = sizeof(gOpenCLExamples)/sizeof(ExampleEntry); for (int i=0;im_allExamples.push_back(gOpenCLExamples[i]); } +#endif #endif //B3_USE_CLEW } diff --git a/examples/ExampleBrowser/OpenGLExampleBrowser.cpp b/examples/ExampleBrowser/OpenGLExampleBrowser.cpp index ce75cf208..773813a73 100644 --- a/examples/ExampleBrowser/OpenGLExampleBrowser.cpp +++ b/examples/ExampleBrowser/OpenGLExampleBrowser.cpp @@ -2,7 +2,9 @@ #include "LinearMath/btQuickprof.h" #include "../OpenGLWindow/OpenGLInclude.h" #include "../OpenGLWindow/SimpleOpenGL2App.h" +#ifndef NO_OPENGL3 #include "../OpenGLWindow/SimpleOpenGL3App.h" +#endif #include "../CommonInterfaces/CommonRenderInterface.h" #ifdef __APPLE__ #include "../OpenGLWindow/MacOpenGLWindow.h" @@ -60,7 +62,10 @@ static b3AlignedObjectArray allNames; static class ExampleEntries* gAllExamples=0; bool sUseOpenGL2 = false; bool drawGUI=true; +#ifndef USE_OPENGL3 extern bool useShadowMap; +#endif + static bool visualWireframe=false; static bool renderVisualGeometry=true; static bool renderGrid = true; @@ -150,12 +155,12 @@ void MyKeyboardCallback(int key, int state) { pauseSimulation = !pauseSimulation; } - +#ifndef NO_OPENGL3 if (key=='s' && state) { useShadowMap=!useShadowMap; } - +#endif if (key==B3G_ESCAPE && s_window) { s_window->setRequestExit(); @@ -598,10 +603,12 @@ bool OpenGLExampleBrowser::init(int argc, char* argv[]) int width = 1024; int height=768; - +#ifndef NO_OPENGL3 SimpleOpenGL3App* simpleApp=0; sUseOpenGL2 =args.CheckCmdLineFlag("opengl2"); - +#else + sUseOpenGL2 = true; +#endif const char* appTitle = "Bullet Physics ExampleBrowser"; #if defined (_DEBUG) || defined (DEBUG) const char* optMode = "Debug build (slow)"; @@ -615,19 +622,22 @@ bool OpenGLExampleBrowser::init(int argc, char* argv[]) sprintf(title,"%s using limited OpenGL2 fallback. %s", appTitle,optMode); s_app = new SimpleOpenGL2App(title,width,height); s_app->m_renderer = new SimpleOpenGL2Renderer(width,height); - } else + } +#ifndef NO_OPENGL3 + else { char title[1024]; sprintf(title,"%s using OpenGL3+. %s", appTitle,optMode); simpleApp = new SimpleOpenGL3App(title,width,height); s_app = simpleApp; } +#endif char* gVideoFileName = 0; args.GetCmdLineArgument("mp4",gVideoFileName); - + #ifndef NO_OPENGL3 if (gVideoFileName) simpleApp->dumpFramesToVideo(gVideoFileName); - + #endif s_instancingRenderer = s_app->m_renderer; s_window = s_app->m_window; @@ -658,11 +668,14 @@ bool OpenGLExampleBrowser::init(int argc, char* argv[]) if (sUseOpenGL2 ) { gwenRenderer = new Gwen::Renderer::OpenGL_DebugFont(); - } else + } +#ifndef NO_OPENGL3 + else { sth_stash* fontstash=simpleApp->getFontStash(); gwenRenderer = new GwenOpenGL3CoreRenderer(simpleApp->m_primRenderer,fontstash,width,height,s_window->getRetinaScale(),myTexLoader); } +#endif // gui->init(width,height,gwenRenderer,s_window->getRetinaScale()); diff --git a/examples/ExampleBrowser/premake4.lua b/examples/ExampleBrowser/premake4.lua index de359e4ff..101a4c6e0 100644 --- a/examples/ExampleBrowser/premake4.lua +++ b/examples/ExampleBrowser/premake4.lua @@ -93,7 +93,7 @@ } - if (hasCL) then + if (hasCL and findOpenGL3()) then files { "../OpenCL/broadphase/*", "../OpenCL/CommonOpenCL/*", diff --git a/examples/Importers/ImportURDFDemo/ImportURDFSetup.cpp b/examples/Importers/ImportURDFDemo/ImportURDFSetup.cpp index 06fb8bd79..a3160a799 100644 --- a/examples/Importers/ImportURDFDemo/ImportURDFSetup.cpp +++ b/examples/Importers/ImportURDFDemo/ImportURDFSetup.cpp @@ -106,6 +106,7 @@ ImportUrdfSetup::ImportUrdfSetup(struct GUIHelperInterface* helper, int option, do { result = fscanf(f,"%s",fileName); + b3Printf("urdf_files.txt entry %s",fileName); if (result==1) { gFileNameArray.push_back(fileName); diff --git a/examples/OpenGLWindow/GLInstancingRenderer.cpp b/examples/OpenGLWindow/GLInstancingRenderer.cpp index faae50d41..1ac543995 100644 --- a/examples/OpenGLWindow/GLInstancingRenderer.cpp +++ b/examples/OpenGLWindow/GLInstancingRenderer.cpp @@ -1,3 +1,4 @@ +#ifndef NO_OPENGL3 /* Copyright (c) 2012 Advanced Micro Devices, Inc. @@ -1641,3 +1642,4 @@ int GLInstancingRenderer::getInstanceCapacity() const { return m_data->m_maxNumObjectCapacity; } +#endif //NO_OPENGL3 diff --git a/examples/OpenGLWindow/GLPrimitiveRenderer.cpp b/examples/OpenGLWindow/GLPrimitiveRenderer.cpp index cff4bd52e..60328514e 100644 --- a/examples/OpenGLWindow/GLPrimitiveRenderer.cpp +++ b/examples/OpenGLWindow/GLPrimitiveRenderer.cpp @@ -1,3 +1,4 @@ +#ifndef NO_OPENGL3 #include "GLPrimitiveRenderer.h" #include "GLPrimInternalData.h" @@ -319,4 +320,5 @@ void GLPrimitiveRenderer::setScreenSize(int width, int height) m_screenWidth = width; m_screenHeight = height; -} \ No newline at end of file +} +#endif diff --git a/examples/OpenGLWindow/GLRenderToTexture.cpp b/examples/OpenGLWindow/GLRenderToTexture.cpp index 3ca338eba..89e044ce3 100644 --- a/examples/OpenGLWindow/GLRenderToTexture.cpp +++ b/examples/OpenGLWindow/GLRenderToTexture.cpp @@ -1,3 +1,4 @@ +#ifndef NO_OPENGL3 ///See http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/ @@ -132,4 +133,5 @@ GLRenderToTexture::~GLRenderToTexture() glDeleteFramebuffers(1, &m_framebufferName); } } +#endif diff --git a/examples/OpenGLWindow/MacOpenGLWindow.mm b/examples/OpenGLWindow/MacOpenGLWindow.mm index 66c672ab1..4f2019570 100644 --- a/examples/OpenGLWindow/MacOpenGLWindow.mm +++ b/examples/OpenGLWindow/MacOpenGLWindow.mm @@ -2,8 +2,8 @@ #define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED #import -#include -#include +#include "OpenGLInclude.h" + #include @@ -107,16 +107,16 @@ float loop; { (*m_resizeCallback)(width,height); } - + #ifndef NO_OPENGL3 NSRect backingBounds = [self convertRectToBacking:[self bounds]]; GLsizei backingPixelWidth = (GLsizei)(backingBounds.size.width), backingPixelHeight = (GLsizei)(backingBounds.size.height); // Set viewport glViewport(0, 0, backingPixelWidth, backingPixelHeight); - - // glViewport(0,0,(GLsizei)width,(GLsizei)height); - + #else + glViewport(0,0,(GLsizei)width,(GLsizei)height); +#endif } [m_context setView: self]; @@ -140,7 +140,7 @@ float loop; - +#ifndef NO_OPENGL3 if (openglVersion==3) { NSOpenGLPixelFormatAttribute attrs[] = @@ -156,6 +156,7 @@ float loop; // Init GL context fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes: (NSOpenGLPixelFormatAttribute*)attrs]; } else +#endif { NSOpenGLPixelFormatAttribute attrs[] = { @@ -437,8 +438,11 @@ void MacOpenGLWindow::createWindow(const b3gWindowConstructionInfo& ci) TransformProcessType(&psn, kProcessTransformToForegroundApplication); SetFrontProcess(&psn); */ - +#ifndef NO_OPENGL3 m_retinaScaleFactor = [m_internalData->m_myview convertSizeToBacking:sz].width; +#else + m_retinaScaleFactor=1.f; +#endif [m_internalData->m_myApp finishLaunching]; [pool release]; diff --git a/examples/OpenGLWindow/OpenGLInclude.h b/examples/OpenGLWindow/OpenGLInclude.h index fee6a3095..19219a188 100644 --- a/examples/OpenGLWindow/OpenGLInclude.h +++ b/examples/OpenGLWindow/OpenGLInclude.h @@ -24,7 +24,7 @@ subject to the following restrictions: //#include //#include //#import -#ifdef USE_OPENGL2 +#if defined (USE_OPENGL2) || defined (NO_OPENGL3) #include #else #include diff --git a/examples/OpenGLWindow/opengl_fontstashcallbacks.cpp b/examples/OpenGLWindow/opengl_fontstashcallbacks.cpp index 35250ce2e..18db74692 100644 --- a/examples/OpenGLWindow/opengl_fontstashcallbacks.cpp +++ b/examples/OpenGLWindow/opengl_fontstashcallbacks.cpp @@ -1,3 +1,4 @@ +#ifndef NO_OPENGL3 #include "opengl_fontstashcallbacks.h" #include "../OpenGLWindow/GLPrimitiveRenderer.h" #include "../OpenGLWindow/GLPrimInternalData.h" @@ -250,3 +251,5 @@ void dumpTextureToPng(int textureWidth, int textureHeight, const char* fileName) free(pixels); } +#endif + diff --git a/examples/ThirdPartyLibs/enet/callbacks.c b/examples/ThirdPartyLibs/enet/callbacks.c new file mode 100644 index 000000000..f94128256 --- /dev/null +++ b/examples/ThirdPartyLibs/enet/callbacks.c @@ -0,0 +1,47 @@ +/** + @file callbacks.c + @brief ENet callback functions +*/ +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +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 (); +} + +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); +} + diff --git a/examples/ThirdPartyLibs/enet/compress.c b/examples/ThirdPartyLibs/enet/compress.c new file mode 100644 index 000000000..784489a78 --- /dev/null +++ b/examples/ThirdPartyLibs/enet/compress.c @@ -0,0 +1,654 @@ +/** + @file compress.c + @brief An adaptive order-2 PPM range coder +*/ +#define ENET_BUILDING_LIB 1 +#include +#include "enet/enet.h" + +typedef struct _ENetSymbol +{ + /* binary indexed tree of symbols */ + enet_uint8 value; + enet_uint8 count; + enet_uint16 under; + enet_uint16 left, right; + + /* context defined by this symbol */ + enet_uint16 symbols; + enet_uint16 escapes; + enet_uint16 total; + enet_uint16 parent; +} ENetSymbol; + +/* adaptation constants tuned aggressively for small packet sizes rather than large file compression */ +enum +{ + ENET_RANGE_CODER_TOP = 1<<24, + ENET_RANGE_CODER_BOTTOM = 1<<16, + + ENET_CONTEXT_SYMBOL_DELTA = 3, + ENET_CONTEXT_SYMBOL_MINIMUM = 1, + ENET_CONTEXT_ESCAPE_MINIMUM = 1, + + ENET_SUBCONTEXT_ORDER = 2, + ENET_SUBCONTEXT_SYMBOL_DELTA = 2, + ENET_SUBCONTEXT_ESCAPE_DELTA = 5 +}; + +/* context exclusion roughly halves compression speed, so disable for now */ +#undef ENET_CONTEXT_EXCLUSION + +typedef struct _ENetRangeCoder +{ + /* only allocate enough symbols for reasonable MTUs, would need to be larger for large file compression */ + ENetSymbol symbols[4096]; +} ENetRangeCoder; + +void * +enet_range_coder_create (void) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) enet_malloc (sizeof (ENetRangeCoder)); + if (rangeCoder == NULL) + return NULL; + + return rangeCoder; +} + +void +enet_range_coder_destroy (void * context) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + if (rangeCoder == NULL) + return; + + enet_free (rangeCoder); +} + +#define ENET_SYMBOL_CREATE(symbol, value_, count_) \ +{ \ + symbol = & rangeCoder -> symbols [nextSymbol ++]; \ + symbol -> value = value_; \ + symbol -> count = count_; \ + symbol -> under = count_; \ + symbol -> left = 0; \ + symbol -> right = 0; \ + symbol -> symbols = 0; \ + symbol -> escapes = 0; \ + symbol -> total = 0; \ + symbol -> parent = 0; \ +} + +#define ENET_CONTEXT_CREATE(context, escapes_, minimum) \ +{ \ + ENET_SYMBOL_CREATE (context, 0, 0); \ + (context) -> escapes = escapes_; \ + (context) -> total = escapes_ + 256*minimum; \ + (context) -> symbols = 0; \ +} + +static enet_uint16 +enet_symbol_rescale (ENetSymbol * symbol) +{ + enet_uint16 total = 0; + for (;;) + { + symbol -> count -= symbol->count >> 1; + symbol -> under = symbol -> count; + if (symbol -> left) + symbol -> under += enet_symbol_rescale (symbol + symbol -> left); + total += symbol -> under; + if (! symbol -> right) break; + symbol += symbol -> right; + } + return total; +} + +#define ENET_CONTEXT_RESCALE(context, minimum) \ +{ \ + (context) -> total = (context) -> symbols ? enet_symbol_rescale ((context) + (context) -> symbols) : 0; \ + (context) -> escapes -= (context) -> escapes >> 1; \ + (context) -> total += (context) -> escapes + 256*minimum; \ +} + +#define ENET_RANGE_CODER_OUTPUT(value) \ +{ \ + if (outData >= outEnd) \ + return 0; \ + * outData ++ = value; \ +} + +#define ENET_RANGE_CODER_ENCODE(under, count, total) \ +{ \ + encodeRange /= (total); \ + encodeLow += (under) * encodeRange; \ + encodeRange *= (count); \ + for (;;) \ + { \ + if((encodeLow ^ (encodeLow + encodeRange)) >= ENET_RANGE_CODER_TOP) \ + { \ + if(encodeRange >= ENET_RANGE_CODER_BOTTOM) break; \ + encodeRange = -encodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \ + } \ + ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \ + encodeRange <<= 8; \ + encodeLow <<= 8; \ + } \ +} + +#define ENET_RANGE_CODER_FLUSH \ +{ \ + while (encodeLow) \ + { \ + ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \ + encodeLow <<= 8; \ + } \ +} + +#define ENET_RANGE_CODER_FREE_SYMBOLS \ +{ \ + if (nextSymbol >= sizeof (rangeCoder -> symbols) / sizeof (ENetSymbol) - ENET_SUBCONTEXT_ORDER ) \ + { \ + nextSymbol = 0; \ + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); \ + predicted = 0; \ + order = 0; \ + } \ +} + +#define ENET_CONTEXT_ENCODE(context, symbol_, value_, under_, count_, update, minimum) \ +{ \ + under_ = value*minimum; \ + count_ = minimum; \ + if (! (context) -> symbols) \ + { \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + (context) -> symbols = symbol_ - (context); \ + } \ + else \ + { \ + ENetSymbol * node = (context) + (context) -> symbols; \ + for (;;) \ + { \ + if (value_ < node -> value) \ + { \ + node -> under += update; \ + if (node -> left) { node += node -> left; continue; } \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> left = symbol_ - node; \ + } \ + else \ + if (value_ > node -> value) \ + { \ + under_ += node -> under; \ + if (node -> right) { node += node -> right; continue; } \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> right = symbol_ - node; \ + } \ + else \ + { \ + count_ += node -> count; \ + under_ += node -> under - node -> count; \ + node -> under += update; \ + node -> count += update; \ + symbol_ = node; \ + } \ + break; \ + } \ + } \ +} + +#ifdef ENET_CONTEXT_EXCLUSION +static const ENetSymbol emptyContext = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +#define ENET_CONTEXT_WALK(context, body) \ +{ \ + const ENetSymbol * node = (context) + (context) -> symbols; \ + const ENetSymbol * stack [256]; \ + size_t stackSize = 0; \ + while (node -> left) \ + { \ + stack [stackSize ++] = node; \ + node += node -> left; \ + } \ + for (;;) \ + { \ + body; \ + if (node -> right) \ + { \ + node += node -> right; \ + while (node -> left) \ + { \ + stack [stackSize ++] = node; \ + node += node -> left; \ + } \ + } \ + else \ + if (stackSize <= 0) \ + break; \ + else \ + node = stack [-- stackSize]; \ + } \ +} + +#define ENET_CONTEXT_ENCODE_EXCLUDE(context, value_, under, total, minimum) \ +ENET_CONTEXT_WALK(context, { \ + if (node -> value != value_) \ + { \ + enet_uint16 parentCount = rangeCoder -> symbols [node -> parent].count + minimum; \ + if (node -> value < value_) \ + under -= parentCount; \ + total -= parentCount; \ + } \ +}) +#endif + +size_t +enet_range_coder_compress (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + enet_uint8 * outStart = outData, * outEnd = & outData [outLimit]; + const enet_uint8 * inData, * inEnd; + enet_uint32 encodeLow = 0, encodeRange = ~0; + ENetSymbol * root; + enet_uint16 predicted = 0; + size_t order = 0, nextSymbol = 0; + + if (rangeCoder == NULL || inBufferCount <= 0 || inLimit <= 0) + return 0; + + inData = (const enet_uint8 *) inBuffers -> data; + inEnd = & inData [inBuffers -> dataLength]; + inBuffers ++; + inBufferCount --; + + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); + + for (;;) + { + ENetSymbol * subcontext, * symbol; +#ifdef ENET_CONTEXT_EXCLUSION + const ENetSymbol * childContext = & emptyContext; +#endif + enet_uint8 value; + enet_uint16 count, under, * parent = & predicted, total; + if (inData >= inEnd) + { + if (inBufferCount <= 0) + break; + inData = (const enet_uint8 *) inBuffers -> data; + inEnd = & inData [inBuffers -> dataLength]; + inBuffers ++; + inBufferCount --; + } + value = * inData ++; + + for (subcontext = & rangeCoder -> symbols [predicted]; + subcontext != root; +#ifdef ENET_CONTEXT_EXCLUSION + childContext = subcontext, +#endif + subcontext = & rangeCoder -> symbols [subcontext -> parent]) + { + ENET_CONTEXT_ENCODE (subcontext, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + total = subcontext -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA) + ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, 0); +#endif + if (count > 0) + { + ENET_RANGE_CODER_ENCODE (subcontext -> escapes + under, count, total); + } + else + { + if (subcontext -> escapes > 0 && subcontext -> escapes < total) + ENET_RANGE_CODER_ENCODE (0, subcontext -> escapes, total); + subcontext -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA; + subcontext -> total += ENET_SUBCONTEXT_ESCAPE_DELTA; + } + subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (subcontext, 0); + if (count > 0) goto nextInput; + } + + ENET_CONTEXT_ENCODE (root, symbol, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + total = root -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA) + ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, ENET_CONTEXT_SYMBOL_MINIMUM); +#endif + ENET_RANGE_CODER_ENCODE (root -> escapes + under, count, total); + root -> total += ENET_CONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM); + + nextInput: + if (order >= ENET_SUBCONTEXT_ORDER) + predicted = rangeCoder -> symbols [predicted].parent; + else + order ++; + ENET_RANGE_CODER_FREE_SYMBOLS; + } + + ENET_RANGE_CODER_FLUSH; + + return (size_t) (outData - outStart); +} + +#define ENET_RANGE_CODER_SEED \ +{ \ + if (inData < inEnd) decodeCode |= * inData ++ << 24; \ + if (inData < inEnd) decodeCode |= * inData ++ << 16; \ + if (inData < inEnd) decodeCode |= * inData ++ << 8; \ + if (inData < inEnd) decodeCode |= * inData ++; \ +} + +#define ENET_RANGE_CODER_READ(total) ((decodeCode - decodeLow) / (decodeRange /= (total))) + +#define ENET_RANGE_CODER_DECODE(under, count, total) \ +{ \ + decodeLow += (under) * decodeRange; \ + decodeRange *= (count); \ + for (;;) \ + { \ + if((decodeLow ^ (decodeLow + decodeRange)) >= ENET_RANGE_CODER_TOP) \ + { \ + if(decodeRange >= ENET_RANGE_CODER_BOTTOM) break; \ + decodeRange = -decodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \ + } \ + decodeCode <<= 8; \ + if (inData < inEnd) \ + decodeCode |= * inData ++; \ + decodeRange <<= 8; \ + decodeLow <<= 8; \ + } \ +} + +#define ENET_CONTEXT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, createRoot, visitNode, createRight, createLeft) \ +{ \ + under_ = 0; \ + count_ = minimum; \ + if (! (context) -> symbols) \ + { \ + createRoot; \ + } \ + else \ + { \ + ENetSymbol * node = (context) + (context) -> symbols; \ + for (;;) \ + { \ + enet_uint16 after = under_ + node -> under + (node -> value + 1)*minimum, before = node -> count + minimum; \ + visitNode; \ + if (code >= after) \ + { \ + under_ += node -> under; \ + if (node -> right) { node += node -> right; continue; } \ + createRight; \ + } \ + else \ + if (code < after - before) \ + { \ + node -> under += update; \ + if (node -> left) { node += node -> left; continue; } \ + createLeft; \ + } \ + else \ + { \ + value_ = node -> value; \ + count_ += node -> count; \ + under_ = after - before; \ + node -> under += update; \ + node -> count += update; \ + symbol_ = node; \ + } \ + break; \ + } \ + } \ +} + +#define ENET_CONTEXT_TRY_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \ +ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, return 0, exclude (node -> value, after, before), return 0, return 0) + +#define ENET_CONTEXT_ROOT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \ +ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, \ + { \ + value_ = code / minimum; \ + under_ = code - code%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + (context) -> symbols = symbol_ - (context); \ + }, \ + exclude (node -> value, after, before), \ + { \ + value_ = node->value + 1 + (code - after)/minimum; \ + under_ = code - (code - after)%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> right = symbol_ - node; \ + }, \ + { \ + value_ = node->value - 1 - (after - before - code - 1)/minimum; \ + under_ = code - (after - before - code - 1)%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> left = symbol_ - node; \ + }) \ + +#ifdef ENET_CONTEXT_EXCLUSION +typedef struct _ENetExclude +{ + enet_uint8 value; + enet_uint16 under; +} ENetExclude; + +#define ENET_CONTEXT_DECODE_EXCLUDE(context, total, minimum) \ +{ \ + enet_uint16 under = 0; \ + nextExclude = excludes; \ + ENET_CONTEXT_WALK (context, { \ + under += rangeCoder -> symbols [node -> parent].count + minimum; \ + nextExclude -> value = node -> value; \ + nextExclude -> under = under; \ + nextExclude ++; \ + }); \ + total -= under; \ +} + +#define ENET_CONTEXT_EXCLUDED(value_, after, before) \ +{ \ + size_t low = 0, high = nextExclude - excludes; \ + for(;;) \ + { \ + size_t mid = (low + high) >> 1; \ + const ENetExclude * exclude = & excludes [mid]; \ + if (value_ < exclude -> value) \ + { \ + if (low + 1 < high) \ + { \ + high = mid; \ + continue; \ + } \ + if (exclude > excludes) \ + after -= exclude [-1].under; \ + } \ + else \ + { \ + if (value_ > exclude -> value) \ + { \ + if (low + 1 < high) \ + { \ + low = mid; \ + continue; \ + } \ + } \ + else \ + before = 0; \ + after -= exclude -> under; \ + } \ + break; \ + } \ +} +#endif + +#define ENET_CONTEXT_NOT_EXCLUDED(value_, after, before) + +size_t +enet_range_coder_decompress (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + enet_uint8 * outStart = outData, * outEnd = & outData [outLimit]; + const enet_uint8 * inEnd = & inData [inLimit]; + enet_uint32 decodeLow = 0, decodeCode = 0, decodeRange = ~0; + ENetSymbol * root; + enet_uint16 predicted = 0; + size_t order = 0, nextSymbol = 0; +#ifdef ENET_CONTEXT_EXCLUSION + ENetExclude excludes [256]; + ENetExclude * nextExclude = excludes; +#endif + + if (rangeCoder == NULL || inLimit <= 0) + return 0; + + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); + + ENET_RANGE_CODER_SEED; + + for (;;) + { + ENetSymbol * subcontext, * symbol, * patch; +#ifdef ENET_CONTEXT_EXCLUSION + const ENetSymbol * childContext = & emptyContext; +#endif + enet_uint8 value = 0; + enet_uint16 code, under, count, bottom, * parent = & predicted, total; + + for (subcontext = & rangeCoder -> symbols [predicted]; + subcontext != root; +#ifdef ENET_CONTEXT_EXCLUSION + childContext = subcontext, +#endif + subcontext = & rangeCoder -> symbols [subcontext -> parent]) + { + if (subcontext -> escapes <= 0) + continue; + total = subcontext -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, 0); +#endif + if (subcontext -> escapes >= total) + continue; + code = ENET_RANGE_CODER_READ (total); + if (code < subcontext -> escapes) + { + ENET_RANGE_CODER_DECODE (0, subcontext -> escapes, total); + continue; + } + code -= subcontext -> escapes; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + { + ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_EXCLUDED); + } + else +#endif + { + ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_NOT_EXCLUDED); + } + bottom = symbol - rangeCoder -> symbols; + ENET_RANGE_CODER_DECODE (subcontext -> escapes + under, count, total); + subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (subcontext, 0); + goto patchContexts; + } + + total = root -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, ENET_CONTEXT_SYMBOL_MINIMUM); +#endif + code = ENET_RANGE_CODER_READ (total); + if (code < root -> escapes) + { + ENET_RANGE_CODER_DECODE (0, root -> escapes, total); + break; + } + code -= root -> escapes; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + { + ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_EXCLUDED); + } + else +#endif + { + ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_NOT_EXCLUDED); + } + bottom = symbol - rangeCoder -> symbols; + ENET_RANGE_CODER_DECODE (root -> escapes + under, count, total); + root -> total += ENET_CONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM); + + patchContexts: + for (patch = & rangeCoder -> symbols [predicted]; + patch != subcontext; + patch = & rangeCoder -> symbols [patch -> parent]) + { + ENET_CONTEXT_ENCODE (patch, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + if (count <= 0) + { + patch -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA; + patch -> total += ENET_SUBCONTEXT_ESCAPE_DELTA; + } + patch -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || patch -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (patch, 0); + } + * parent = bottom; + + ENET_RANGE_CODER_OUTPUT (value); + + if (order >= ENET_SUBCONTEXT_ORDER) + predicted = rangeCoder -> symbols [predicted].parent; + else + order ++; + ENET_RANGE_CODER_FREE_SYMBOLS; + } + + return (size_t) (outData - outStart); +} + +/** @defgroup host ENet host functions + @{ +*/ + +/** Sets the packet compressor the host should use to the default range coder. + @param host host to enable the range coder for + @returns 0 on success, < 0 on failure +*/ +int +enet_host_compress_with_range_coder (ENetHost * host) +{ + ENetCompressor compressor; + memset (& compressor, 0, sizeof (compressor)); + compressor.context = enet_range_coder_create(); + if (compressor.context == NULL) + return -1; + compressor.compress = enet_range_coder_compress; + compressor.decompress = enet_range_coder_decompress; + compressor.destroy = enet_range_coder_destroy; + enet_host_compress (host, & compressor); + return 0; +} + +/** @} */ + + diff --git a/examples/ThirdPartyLibs/enet/host.c b/examples/ThirdPartyLibs/enet/host.c new file mode 100644 index 000000000..d0ee595cf --- /dev/null +++ b/examples/ThirdPartyLibs/enet/host.c @@ -0,0 +1,491 @@ +/** + @file host.c + @brief ENet host management functions +*/ +#define ENET_BUILDING_LIB 1 +#include +#include +#include "enet/enet.h" + +/** @defgroup host ENet host functions + @{ +*/ + +/** 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 || (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); + + if (address != NULL) + 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; +#ifdef WIN32 + host -> randomSeed += (enet_uint32) timeGetTime(); +#else + host -> randomSeed += (enet_uint32) time(NULL); +#endif + 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 -> 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 (& currentPeer -> acknowledgements); + enet_list_clear (& currentPeer -> sentReliableCommands); + enet_list_clear (& currentPeer -> sentUnreliableCommands); + enet_list_clear (& currentPeer -> outgoingReliableCommands); + enet_list_clear (& currentPeer -> outgoingUnreliableCommands); + enet_list_clear (& currentPeer -> dispatchedCommands); + + enet_peer_reset (currentPeer); + } + + return host; +} + +/** 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 < & currentPeer -> 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; +} + +/** 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); +} + +/** 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 (), + elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch, + peersTotal = 0, + dataTotal = 0, + peersRemaining, + bandwidth, + throttle = 0, + bandwidthLimit = 0; + int needsAdjustment; + ENetPeer * peer; + ENetProtocol command; + + if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) + return; + + 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; + + ++ peersTotal; + dataTotal += peer -> outgoingDataTotal; + } + + if (peersTotal == 0) + return; + + peersRemaining = peersTotal; + needsAdjustment = 1; + + if (host -> outgoingBandwidth == 0) + bandwidth = ~0; + else + bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000; + + 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; + + + needsAdjustment = 1; + -- peersRemaining; + bandwidth -= peerBandwidth; + dataTotal -= peerBandwidth; + } + } + + if (peersRemaining > 0) + 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; + } + + if (host -> recalculateBandwidthLimits) + { + host -> recalculateBandwidthLimits = 0; + + peersRemaining = peersTotal; + 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); + } + } + + host -> bandwidthThrottleEpoch = timeCurrent; + + for (peer = host -> peers; + peer < & host -> peers [host -> peerCount]; + ++ peer) + { + peer -> incomingDataTotal = 0; + peer -> outgoingDataTotal = 0; + } +} + +/** @} */ diff --git a/examples/ThirdPartyLibs/enet/include/enet/callbacks.h b/examples/ThirdPartyLibs/enet/include/enet/callbacks.h new file mode 100644 index 000000000..340a4a989 --- /dev/null +++ b/examples/ThirdPartyLibs/enet/include/enet/callbacks.h @@ -0,0 +1,27 @@ +/** + @file callbacks.h + @brief ENet callbacks +*/ +#ifndef __ENET_CALLBACKS_H__ +#define __ENET_CALLBACKS_H__ + +#include + +typedef struct _ENetCallbacks +{ + void * (ENET_CALLBACK * malloc) (size_t size); + void (ENET_CALLBACK * free) (void * memory); + void (ENET_CALLBACK * no_memory) (void); +} ENetCallbacks; + +/** @defgroup callbacks ENet internal callbacks + @{ + @ingroup private +*/ +extern void * enet_malloc (size_t); +extern void enet_free (void *); + +/** @} */ + +#endif /* __ENET_CALLBACKS_H__ */ + diff --git a/examples/ThirdPartyLibs/enet/include/enet/enet.h b/examples/ThirdPartyLibs/enet/include/enet/enet.h new file mode 100644 index 000000000..5f9d5403c --- /dev/null +++ b/examples/ThirdPartyLibs/enet/include/enet/enet.h @@ -0,0 +1,571 @@ +/** + @file enet.h + @brief ENet public header file +*/ +#ifndef __ENET_ENET_H__ +#define __ENET_ENET_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#ifdef WIN32 +#include "enet/win32.h" +#else +#include "enet/unix.h" +#endif + +#include "enet/types.h" +#include "enet/protocol.h" +#include "enet/list.h" +#include "enet/callbacks.h" + +#define ENET_VERSION_MAJOR 1 +#define ENET_VERSION_MINOR 3 +#define ENET_VERSION_PATCH 7 +#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch)) +#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH) + +typedef enet_uint32 ENetVersion; + +struct _ENetHost; +struct _ENetEvent; +struct _ENetPacket; + +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) +} 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 +} ENetSocketOption; + +typedef enum _ENetSocketShutdown +{ + ENET_SOCKET_SHUTDOWN_READ = 0, + ENET_SOCKET_SHUTDOWN_WRITE = 1, + ENET_SOCKET_SHUTDOWN_READ_WRITE = 2 +} ENetSocketShutdown; + +enum +{ + ENET_HOST_ANY = 0, /**< specifies the default server host */ + ENET_HOST_BROADCAST = 0xFFFFFFFF, /**< specifies a subnet-wide broadcast */ + + ENET_PORT_ANY = 0 /**< specifies that a port should be automatically chosen */ +}; + +/** + * 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 +{ + enet_uint32 host; + enet_uint16 port; +} ENetAddress; + +/** + * 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 +{ + /** packet must be received by the target peer and resend attempts should be + * made until the packet is delivered */ + ENET_PACKET_FLAG_RELIABLE = (1 << 0), + /** packet will not be sequenced with other packets + * not supported for reliable packets + */ + ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1), + /** packet will not allocate data, and user must supply it instead */ + ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2), + /** packet will be fragmented using unreliable (instead of reliable) sends + * if it exceeds the MTU */ + ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3), + + /** whether the packet has been sent from all queues it has been entered into */ + ENET_PACKET_FLAG_SENT = (1<<8) +} ENetPacketFlag; + +typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *); + +/** + * 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 + + @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; + +#ifndef ENET_BUFFER_MAXIMUM +#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS) +#endif + +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_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_uint32 outgoingDataTotal; + enet_uint32 lastSendTime; + enet_uint32 lastReceiveTime; + enet_uint32 nextTimeout; + enet_uint32 earliestTimeout; + enet_uint32 packetLossEpoch; + enet_uint32 packetsSent; + enet_uint32 packetsLost; + 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; +} 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, struct _ENetEvent * 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_compress_with_range_coder() + @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 */ +} 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_pper_disconnect, if + * a peer has timed out, or if a connection request intialized by + * enet_host_connect 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 +} 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; + +/** @defgroup global ENet global functions + @{ +*/ + +/** + 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-overriden 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); + +/** @} */ + +/** @defgroup private ENet private implementation functions */ + +/** + Returns the wall-time in milliseconds. Its initial value is unspecified + unless otherwise set. + */ +ENET_API enet_uint32 enet_time_get (void); +/** + Sets the current wall-time in milliseconds. + */ +ENET_API void enet_time_set (enet_uint32); + +/** @defgroup socket ENet socket functions + @{ +*/ +ENET_API ENetSocket enet_socket_create (ENetSocketType); +ENET_API int enet_socket_bind (ENetSocket, const 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_uint32); +ENET_API int enet_socket_set_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); + +/** @} */ + +/** @defgroup Address ENet address functions + @{ +*/ +/** 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 ENetPacket * enet_packet_create (const void *, size_t, enet_uint32); +ENET_API void enet_packet_destroy (ENetPacket *); +ENET_API int enet_packet_resize (ENetPacket *, size_t); +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 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 int enet_host_compress_with_range_coder (ENetHost * host); +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 *); + +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 *, ENetPacket *, 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 *); + +ENET_API void * enet_range_coder_create (void); +ENET_API void enet_range_coder_destroy (void *); +ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t); +ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t); + +extern size_t enet_protocol_command_size (enet_uint8); + +#ifdef __cplusplus +} +#endif + +#endif /* __ENET_ENET_H__ */ + diff --git a/examples/ThirdPartyLibs/enet/include/enet/list.h b/examples/ThirdPartyLibs/enet/include/enet/list.h new file mode 100644 index 000000000..d7b260084 --- /dev/null +++ b/examples/ThirdPartyLibs/enet/include/enet/list.h @@ -0,0 +1,43 @@ +/** + @file list.h + @brief ENet list management +*/ +#ifndef __ENET_LIST_H__ +#define __ENET_LIST_H__ + +#include + +typedef struct _ENetListNode +{ + struct _ENetListNode * next; + struct _ENetListNode * previous; +} ENetListNode; + +typedef ENetListNode * ENetListIterator; + +typedef struct _ENetList +{ + ENetListNode sentinel; +} ENetList; + +extern void enet_list_clear (ENetList *); + +extern ENetListIterator enet_list_insert (ENetListIterator, void *); +extern void * enet_list_remove (ENetListIterator); +extern ENetListIterator enet_list_move (ENetListIterator, void *, void *); + +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) + +#endif /* __ENET_LIST_H__ */ + diff --git a/examples/ThirdPartyLibs/enet/include/enet/protocol.h b/examples/ThirdPartyLibs/enet/include/enet/protocol.h new file mode 100644 index 000000000..f8a27d8e1 --- /dev/null +++ b/examples/ThirdPartyLibs/enet/include/enet/protocol.h @@ -0,0 +1,199 @@ +/** + @file protocol.h + @brief ENet protocol +*/ +#ifndef __ENET_PROTOCOL_H__ +#define __ENET_PROTOCOL_H__ + +#include "enet/types.h" + +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 = 32768, + ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1, + ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255, + ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF, + ENET_PROTOCOL_MAXIMUM_PACKET_SIZE = 1024 * 1024 * 1024, + 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__) +#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 + +#endif /* __ENET_PROTOCOL_H__ */ + diff --git a/examples/ThirdPartyLibs/enet/include/enet/time.h b/examples/ThirdPartyLibs/enet/include/enet/time.h new file mode 100644 index 000000000..c82a54603 --- /dev/null +++ b/examples/ThirdPartyLibs/enet/include/enet/time.h @@ -0,0 +1,18 @@ +/** + @file time.h + @brief ENet time constants and macros +*/ +#ifndef __ENET_TIME_H__ +#define __ENET_TIME_H__ + +#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)) + +#endif /* __ENET_TIME_H__ */ + diff --git a/examples/ThirdPartyLibs/enet/include/enet/types.h b/examples/ThirdPartyLibs/enet/include/enet/types.h new file mode 100644 index 000000000..ab010a4b1 --- /dev/null +++ b/examples/ThirdPartyLibs/enet/include/enet/types.h @@ -0,0 +1,13 @@ +/** + @file types.h + @brief type definitions for ENet +*/ +#ifndef __ENET_TYPES_H__ +#define __ENET_TYPES_H__ + +typedef unsigned char enet_uint8; /**< unsigned 8-bit type */ +typedef unsigned short enet_uint16; /**< unsigned 16-bit type */ +typedef unsigned int enet_uint32; /**< unsigned 32-bit type */ + +#endif /* __ENET_TYPES_H__ */ + diff --git a/examples/ThirdPartyLibs/enet/include/enet/unix.h b/examples/ThirdPartyLibs/enet/include/enet/unix.h new file mode 100644 index 000000000..087015e51 --- /dev/null +++ b/examples/ThirdPartyLibs/enet/include/enet/unix.h @@ -0,0 +1,45 @@ +/** + @file unix.h + @brief ENet Unix header +*/ +#ifndef __ENET_UNIX_H__ +#define __ENET_UNIX_H__ + +#include +#include +#include +#include +#include + +typedef int ENetSocket; + +enum +{ + 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_CLEAR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_UNIX_H__ */ + diff --git a/examples/ThirdPartyLibs/enet/include/enet/utility.h b/examples/ThirdPartyLibs/enet/include/enet/utility.h new file mode 100644 index 000000000..e48a476be --- /dev/null +++ b/examples/ThirdPartyLibs/enet/include/enet/utility.h @@ -0,0 +1,12 @@ +/** + @file utility.h + @brief ENet utility header +*/ +#ifndef __ENET_UTILITY_H__ +#define __ENET_UTILITY_H__ + +#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y)) +#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y)) + +#endif /* __ENET_UTILITY_H__ */ + diff --git a/examples/ThirdPartyLibs/enet/include/enet/win32.h b/examples/ThirdPartyLibs/enet/include/enet/win32.h new file mode 100644 index 000000000..0e1cf0c5a --- /dev/null +++ b/examples/ThirdPartyLibs/enet/include/enet/win32.h @@ -0,0 +1,58 @@ +/** + @file win32.h + @brief ENet Win32 header +*/ +#ifndef __ENET_WIN32_H__ +#define __ENET_WIN32_H__ + +#ifdef ENET_BUILDING_LIB +#pragma warning (disable: 4996) // 'strncpy' was declared deprecated +#pragma warning (disable: 4267) // size_t to int conversion +#pragma warning (disable: 4244) // 64bit to 32bit int +#pragma warning (disable: 4018) // signed/unsigned mismatch +#endif + +#include +#include + +typedef SOCKET ENetSocket; + +enum +{ + 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 + +#if defined ENET_DLL +#if defined ENET_BUILDING_LIB +#define ENET_API __declspec( dllexport ) +#else +#define ENET_API __declspec( dllimport ) +#endif /* ENET_BUILDING_LIB */ +#else /* !ENET_DLL */ +#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_CLEAR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + +#endif /* __ENET_WIN32_H__ */ + + diff --git a/examples/ThirdPartyLibs/enet/list.c b/examples/ThirdPartyLibs/enet/list.c new file mode 100644 index 000000000..1c1a8dfaa --- /dev/null +++ b/examples/ThirdPartyLibs/enet/list.c @@ -0,0 +1,75 @@ +/** + @file list.c + @brief ENet linked list functions +*/ +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +/** + @defgroup list ENet linked list utility functions + @ingroup private + @{ +*/ +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, + 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; +} + +/** @} */ diff --git a/examples/ThirdPartyLibs/enet/packet.c b/examples/ThirdPartyLibs/enet/packet.c new file mode 100644 index 000000000..9a997be4e --- /dev/null +++ b/examples/ThirdPartyLibs/enet/packet.c @@ -0,0 +1,165 @@ +/** + @file packet.c + @brief ENet packet management functions +*/ +#include +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +/** @defgroup Packet ENet packet functions + @{ +*/ + +/** Creates a packet that may be sent to a peer. + @param dataContents initial contents of the packet's data; the packet's data will remain uninitialized if dataContents 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 = (ENetPacket *) enet_malloc (sizeof (ENetPacket)); + if (packet == NULL) + return NULL; + + if (flags & ENET_PACKET_FLAG_NO_ALLOCATE) + packet -> data = (enet_uint8 *) data; + else + if (dataLength <= 0) + packet -> data = NULL; + else + { + packet -> data = (enet_uint8 *) enet_malloc (dataLength); + if (packet -> data == NULL) + { + enet_free (packet); + return NULL; + } + + 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; +} + +/** 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) (packet); + if (! (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE) && + packet -> data != NULL) + enet_free (packet -> data); + enet_free (packet); +} + +/** Attempts to resize the data in the packet to length specified in the + dataLength parameter + @param packet packet to resize + @param dataLength new size for the packet data + @returns 0 on success, < 0 on failure +*/ +int +enet_packet_resize (ENetPacket * packet, size_t dataLength) +{ + enet_uint8 * newData; + + if (dataLength <= packet -> dataLength || (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE)) + { + packet -> dataLength = dataLength; + + return 0; + } + + newData = (enet_uint8 *) enet_malloc (dataLength); + if (newData == NULL) + return -1; + + memcpy (newData, packet -> data, packet -> dataLength); + enet_free (packet -> data); + + packet -> data = newData; + packet -> dataLength = dataLength; + + return 0; +} + +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, + * dataEnd = & data [buffers -> dataLength]; + + while (data < dataEnd) + { + crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++]; + } + + ++ buffers; + } + + return ENET_HOST_TO_NET_32 (~ crc); +} + +/** @} */ diff --git a/examples/ThirdPartyLibs/enet/peer.c b/examples/ThirdPartyLibs/enet/peer.c new file mode 100644 index 000000000..a86d793d8 --- /dev/null +++ b/examples/ThirdPartyLibs/enet/peer.c @@ -0,0 +1,959 @@ +/** + @file peer.c + @brief ENet peer management functions +*/ +#include +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +/** @defgroup peer ENet peer functions + @{ +*/ + +/** 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; +} + +/** 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 > ENET_PROTOCOL_MAXIMUM_PACKET_SIZE) + 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; +} + +/** 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); + + 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; +} + +/** 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) +{ + peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID; + peer -> connectID = 0; + + peer -> state = ENET_PEER_STATE_DISCONNECTED; + + peer -> incomingBandwidth = 0; + peer -> outgoingBandwidth = 0; + peer -> incomingBandwidthThrottleEpoch = 0; + peer -> outgoingBandwidthThrottleEpoch = 0; + peer -> incomingDataTotal = 0; + peer -> outgoingDataTotal = 0; + peer -> lastSendTime = 0; + peer -> lastReceiveTime = 0; + peer -> nextTimeout = 0; + peer -> earliestTimeout = 0; + peer -> packetLossEpoch = 0; + peer -> packetsSent = 0; + peer -> packetsLost = 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; + + 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 + guarenteed 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) + 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, + 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, + 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, ENetPacket * packet, 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; + + if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) + goto freePacket; + + 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 freePacket; + } + + 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 freePacket; + + 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 freePacket; + } + } + 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 freePacket; + + 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 freePacket; + } + } + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + currentCommand = enet_list_end (& channel -> incomingUnreliableCommands); + break; + + default: + goto freePacket; + } + + 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; + + 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; + +freePacket: + 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; +} + +/** @} */ diff --git a/examples/ThirdPartyLibs/enet/premake4.lua b/examples/ThirdPartyLibs/enet/premake4.lua new file mode 100644 index 000000000..522db3431 --- /dev/null +++ b/examples/ThirdPartyLibs/enet/premake4.lua @@ -0,0 +1,31 @@ + project "enet" + + kind "StaticLib" + + if os.is("Windows") then + defines { "WIN32" } + files{"win32.c"} + end + if os.is("Linux") then + defines {"HAS_SOCKLEN_T"} + files {"unix.c",} + end + if os.is("MacOSX") then + files{"unix.c"} + end + + targetdir "../../../lib" + + includedirs { + ".","include" + } + files { + "callbacks.c", + "compress.c", + "host.c", + "list.c", + "packet.c", + "peer.c", + "protocol.c", + "**.h" + } diff --git a/examples/ThirdPartyLibs/enet/protocol.c b/examples/ThirdPartyLibs/enet/protocol.c new file mode 100644 index 000000000..d6cc33a49 --- /dev/null +++ b/examples/ThirdPartyLibs/enet/protocol.c @@ -0,0 +1,1899 @@ +/** + @file protocol.c + @brief ENet protocol functions +*/ +#include +#include +#define ENET_BUILDING_LIB 1 +#include "enet/utility.h" +#include "enet/time.h" +#include "enet/enet.h" + +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 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: + peer -> state = 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; +} + +static void +enet_protocol_dispatch_state (ENetHost * host, ENetPeer * peer, ENetPeerState state) +{ + peer -> state = state; + + if (! peer -> needsDispatch) + { + enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList); + + peer -> needsDispatch = 1; + } +} + +static void +enet_protocol_notify_connect (ENetHost * host, ENetPeer * peer, ENetEvent * event) +{ + host -> recalculateBandwidthLimits = 1; + + if (event != NULL) + { + peer -> state = ENET_PEER_STATE_CONNECTED; + + 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_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; +} + +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; + ENetPeer * currentPeer; + 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 && + currentPeer -> address.host == host -> receivedAddress.host && + currentPeer -> address.port == host -> receivedAddress.port && + currentPeer -> connectID == command -> connect.connectID) + return NULL; + } + + 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; + + if (channelCount > host -> channelLimit) + channelCount = host -> channelLimit; + currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); + if (currentPeer -> channels == NULL) + return NULL; + currentPeer -> channelCount = channelCount; + currentPeer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT; + currentPeer -> connectID = command -> connect.connectID; + currentPeer -> address = host -> receivedAddress; + currentPeer -> outgoingPeerID = ENET_NET_TO_HOST_16 (command -> connect.outgoingPeerID); + currentPeer -> incomingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.incomingBandwidth); + currentPeer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> connect.outgoingBandwidth); + currentPeer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleInterval); + currentPeer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleAcceleration); + currentPeer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleDeceleration); + currentPeer -> eventData = ENET_NET_TO_HOST_32 (command -> connect.data); + + incomingSessionID = command -> connect.incomingSessionID == 0xFF ? currentPeer -> outgoingSessionID : command -> connect.incomingSessionID; + incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + if (incomingSessionID == currentPeer -> outgoingSessionID) + incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + currentPeer -> outgoingSessionID = incomingSessionID; + + outgoingSessionID = command -> connect.outgoingSessionID == 0xFF ? currentPeer -> incomingSessionID : command -> connect.outgoingSessionID; + outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + if (outgoingSessionID == currentPeer -> incomingSessionID) + outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + currentPeer -> incomingSessionID = outgoingSessionID; + + for (channel = currentPeer -> channels; + channel < & currentPeer -> 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; + + currentPeer -> mtu = mtu; + + if (host -> outgoingBandwidth == 0 && + currentPeer -> incomingBandwidth == 0) + currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + else + if (host -> outgoingBandwidth == 0 || + currentPeer -> incomingBandwidth == 0) + currentPeer -> windowSize = (ENET_MAX (host -> outgoingBandwidth, currentPeer -> incomingBandwidth) / + ENET_PEER_WINDOW_SIZE_SCALE) * + ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; + else + currentPeer -> windowSize = (ENET_MIN (host -> outgoingBandwidth, currentPeer -> incomingBandwidth) / + 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; + + 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 (currentPeer -> incomingPeerID); + verifyCommand.verifyConnect.incomingSessionID = incomingSessionID; + verifyCommand.verifyConnect.outgoingSessionID = outgoingSessionID; + verifyCommand.verifyConnect.mtu = ENET_HOST_TO_NET_32 (currentPeer -> 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 (currentPeer -> packetThrottleInterval); + verifyCommand.verifyConnect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration); + verifyCommand.verifyConnect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration); + verifyCommand.verifyConnect.connectID = currentPeer -> connectID; + + enet_peer_queue_outgoing_command (currentPeer, & verifyCommand, NULL, 0, 0); + + return currentPeer; +} + +static int +enet_protocol_handle_send_reliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + ENetPacket * packet; + 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 > ENET_PROTOCOL_MAXIMUM_PACKET_SIZE || + * currentData < host -> receivedData || + * currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + packet = enet_packet_create ((const enet_uint8 *) command + sizeof (ENetProtocolSendReliable), + dataLength, + ENET_PACKET_FLAG_RELIABLE); + if (packet == NULL || + enet_peer_queue_incoming_command (peer, command, packet, 0) == NULL) + return -1; + + return 0; +} + +static int +enet_protocol_handle_send_unsequenced (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + ENetPacket * packet; + 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 > ENET_PROTOCOL_MAXIMUM_PACKET_SIZE || + * 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; + + packet = enet_packet_create ((const enet_uint8 *) command + sizeof (ENetProtocolSendUnsequenced), + dataLength, + ENET_PACKET_FLAG_UNSEQUENCED); + if (packet == NULL || + enet_peer_queue_incoming_command (peer, command, packet, 0) == NULL) + return -1; + + peer -> unsequencedWindow [index / 32] |= 1 << (index % 32); + + return 0; +} + +static int +enet_protocol_handle_send_unreliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) +{ + ENetPacket * packet; + 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 > ENET_PROTOCOL_MAXIMUM_PACKET_SIZE || + * currentData < host -> receivedData || + * currentData > & host -> receivedData [host -> receivedDataLength]) + return -1; + + packet = enet_packet_create ((const enet_uint8 *) command + sizeof (ENetProtocolSendUnreliable), + dataLength, + 0); + if (packet == NULL || + enet_peer_queue_incoming_command (peer, command, packet, 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 > ENET_PROTOCOL_MAXIMUM_PACKET_SIZE || + * 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 > ENET_PROTOCOL_MAXIMUM_PACKET_SIZE || + 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; + ENetPacket * packet = enet_packet_create (NULL, totalLength, ENET_PACKET_FLAG_RELIABLE); + if (packet == NULL) + return -1; + + hostCommand.header.reliableSequenceNumber = startSequenceNumber; + + startCommand = enet_peer_queue_incoming_command (peer, & hostCommand, packet, 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; +} + +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 > ENET_PROTOCOL_MAXIMUM_PACKET_SIZE || + * 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 > ENET_PROTOCOL_MAXIMUM_PACKET_SIZE || + 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) + { + ENetPacket * packet = enet_packet_create (NULL, totalLength, ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT); + if (packet == NULL) + return -1; + + startCommand = enet_peer_queue_incoming_command (peer, command, packet, 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; +} + +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; + + 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 -> outgoingBandwidth == 0) + peer -> windowSize = ENET_PROTOCOL_MAXIMUM_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; +} + +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) + 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) + peer -> state = 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; +} + +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; +} + +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 || + ((host -> receivedAddress.host != peer -> address.host || + host -> receivedAddress.port != peer -> address.port) && + 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)], + 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; + } + + 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) + 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, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: + if (enet_protocol_handle_send_unreliable (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: + if (enet_protocol_handle_send_unsequenced (host, peer, command, & currentData)) + goto commandError; + break; + + case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: + if (enet_protocol_handle_send_fragment (host, peer, command, & currentData)) + 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, & currentData)) + 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; +} + +static int +enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event) +{ + for (;;) + { + int receivedLength; + ENetBuffer buffer; + + buffer.data = host -> packetData [0]; + buffer.dataLength = sizeof (host -> packetData [0]); + + receivedLength = enet_socket_receive (host -> socket, + & host -> receivedAddress, + & buffer, + 1); + + 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, 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; +} + +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; + + 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; + + command -> header.command = ENET_PROTOCOL_COMMAND_ACKNOWLEDGE; + command -> header.channelID = acknowledgement -> command.header.channelID; + command -> acknowledge.receivedReliableSequenceNumber = ENET_HOST_TO_NET_16 (acknowledgement -> command.header.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; +} + +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, + 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); +} + +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 (host, peer, event); + + return 1; + } + + if (outgoingCommand -> packet != NULL) + peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; + + ++ peer -> packetsLost; + + outgoingCommand -> roundTripTimeout *= 2; + + 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; +} + +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_WINDOW_SIZE - 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; + + ++ command; + ++ buffer; + } + + host -> commandCount = command - host -> commands; + host -> bufferCount = buffer - host -> buffers; + + return canPing; +} + +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 (& currentPeer -> acknowledgements)) + enet_protocol_send_acknowledgements (host, currentPeer); + + if (checkForTimeouts != 0 && + ! enet_list_empty (& currentPeer -> 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 (& currentPeer -> outgoingReliableCommands) || + enet_protocol_send_reliable_outgoing_commands (host, currentPeer)) && + enet_list_empty (& currentPeer -> 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 (& currentPeer -> 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 +#ifdef WIN32 + printf ( +#else + fprintf (stderr, +#endif + "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 (& currentPeer -> outgoingReliableCommands), enet_list_size (& currentPeer -> outgoingUnreliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> 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 +#ifdef WIN32 + printf ( +#else + fprintf (stderr, +#endif + "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, & currentPeer -> address, host -> buffers, host -> bufferCount); + + enet_protocol_remove_sent_unreliable_commands (currentPeer); + + if (sentLength < 0) + return -1; + + host -> totalSentData += sentLength; + host -> totalSentPackets ++; + } + + return 0; +} + +/** 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: + perror ("Error dispatching incoming packets"); + + 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: + perror ("Error sending outgoing packets"); + + return -1; + + default: + break; + } + + switch (enet_protocol_receive_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: + perror ("Error receiving incoming packets"); + + return -1; + + default: + break; + } + + switch (enet_protocol_send_outgoing_commands (host, event, 1)) + { + case 1: + return 1; + + case -1: + perror ("Error sending outgoing packets"); + + return -1; + + default: + break; + } + + if (event != NULL) + { + switch (enet_protocol_dispatch_incoming_commands (host, event)) + { + case 1: + return 1; + + case -1: + perror ("Error dispatching incoming packets"); + + return -1; + + default: + break; + } + } + + host -> serviceTime = enet_time_get (); + + if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout)) + return 0; + + waitCondition = ENET_SOCKET_WAIT_RECEIVE; + + if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0) + return -1; + + host -> serviceTime = enet_time_get (); + } while (waitCondition == ENET_SOCKET_WAIT_RECEIVE); + + return 0; +} + diff --git a/examples/ThirdPartyLibs/enet/unix.c b/examples/ThirdPartyLibs/enet/unix.c new file mode 100644 index 000000000..d425b4b8a --- /dev/null +++ b/examples/ThirdPartyLibs/enet/unix.c @@ -0,0 +1,475 @@ +/** + @file unix.c + @brief ENet Unix system specific functions +*/ +#ifndef WIN32 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +#ifdef __APPLE__ +#ifdef HAS_POLL +#undef HAS_POLL +#endif +#ifndef HAS_FCNTL +#define HAS_FCNTL 1 +#endif +#ifndef HAS_INET_PTON +#define HAS_INET_PTON 1 +#endif +#ifndef HAS_INET_NTOP +#define HAS_INET_NTOP 1 +#endif +#ifndef HAS_MSGHDR_FLAGS +#define HAS_MSGHDR_FLAGS 1 +#endif +#ifndef HAS_SOCKLEN_T +#define HAS_SOCKLEN_T 1 +#endif +#endif + +#ifdef HAS_FCNTL +#include +#endif + +#ifdef HAS_POLL +#include +#endif + +#ifndef HAS_SOCKLEN_T +typedef int socklen_t; +#endif + +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif + +static enet_uint32 timeBase = 0; + +int +enet_initialize (void) +{ + return 0; +} + +void +enet_deinitialize (void) +{ +} + +enet_uint32 +enet_time_get (void) +{ + struct timeval timeVal; + + gettimeofday (& timeVal, NULL); + + return timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - timeBase; +} + +void +enet_time_set (enet_uint32 newTimeBase) +{ + struct timeval timeVal; + + gettimeofday (& timeVal, NULL); + + timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase; +} + +int +enet_address_set_host (ENetAddress * address, const char * name) +{ + struct hostent * hostEntry = NULL; +#ifdef HAS_GETHOSTBYNAME_R + struct hostent hostData; + char buffer [2048]; + int errnum; + +#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); +#else + hostEntry = gethostbyname_r (name, & hostData, buffer, sizeof (buffer), & errnum); +#endif +#else + hostEntry = gethostbyname (name); +#endif + + if (hostEntry == NULL || + hostEntry -> h_addrtype != AF_INET) + { +#ifdef HAS_INET_PTON + if (! inet_pton (AF_INET, name, & address -> host)) +#else + if (! inet_aton (name, (struct in_addr *) & address -> host)) +#endif + return -1; + return 0; + } + + address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; + + return 0; +} + +int +enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) +{ +#ifdef HAS_INET_NTOP + if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL) +#else + char * addr = inet_ntoa (* (struct in_addr *) & address -> host); + if (addr != NULL) + strncpy (name, addr, nameLength); + else +#endif + return -1; + return 0; +} + +int +enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) +{ + struct in_addr in; + struct hostent * hostEntry = NULL; +#ifdef HAS_GETHOSTBYADDR_R + struct hostent hostData; + char buffer [2048]; + int errnum; + + in.s_addr = address -> host; + +#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & hostEntry, & errnum); +#else + hostEntry = gethostbyaddr_r ((char *) & in, sizeof (struct in_addr), AF_INET, & hostData, buffer, sizeof (buffer), & errnum); +#endif +#else + in.s_addr = address -> host; + + hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); +#endif + + if (hostEntry == NULL) + return enet_address_get_host_ip (address, name, nameLength); + + strncpy (name, hostEntry -> h_name, nameLength); + + return 0; +} + +int +enet_socket_bind (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + + if (address != NULL) + { + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + else + { + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + } + + return bind (socket, + (struct sockaddr *) & sin, + sizeof (struct sockaddr_in)); +} + +int +enet_socket_listen (ENetSocket socket, int backlog) +{ + return listen (socket, backlog < 0 ? SOMAXCONN : backlog); +} + +ENetSocket +enet_socket_create (ENetSocketType type) +{ + return socket (PF_INET, 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: +#ifdef HAS_FCNTL + result = fcntl (socket, F_SETFL, O_NONBLOCK | fcntl (socket, F_GETFL)); +#else + result = ioctl (socket, FIONBIO, & value); +#endif + 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; + + default: + break; + } + return result == -1 ? -1 : 0; +} + +int +enet_socket_connect (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + int result; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)); + if (result == -1 && errno == EINPROGRESS) + return 0; + + return result; +} + +ENetSocket +enet_socket_accept (ENetSocket socket, ENetAddress * address) +{ + int result; + struct sockaddr_in sin; + socklen_t sinLength = sizeof (struct sockaddr_in); + + 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 = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + 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_in sin; + int sentLength; + + memset (& msgHdr, 0, sizeof (struct msghdr)); + + if (address != NULL) + { + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + msgHdr.msg_name = & sin; + msgHdr.msg_namelen = sizeof (struct sockaddr_in); + } + + 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; +} + +int +enet_socket_receive (ENetSocket socket, + ENetAddress * address, + ENetBuffer * buffers, + size_t bufferCount) +{ + struct msghdr msgHdr; + struct sockaddr_in sin; + int recvLength; + + memset (& msgHdr, 0, sizeof (struct msghdr)); + + if (address != NULL) + { + msgHdr.msg_name = & sin; + msgHdr.msg_namelen = sizeof (struct sockaddr_in); + } + + 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; + } + +#ifdef HAS_MSGHDR_FLAGS + if (msgHdr.msg_flags & MSG_TRUNC) + return -1; +#endif + + if (address != NULL) + { + address -> host = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return recvLength; +} + +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_uint32 timeout) +{ +#ifdef HAS_POLL + 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) + 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; +#else + 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; +#endif +} + +#endif + diff --git a/examples/ThirdPartyLibs/enet/win32.c b/examples/ThirdPartyLibs/enet/win32.c new file mode 100644 index 000000000..dcc0791bd --- /dev/null +++ b/examples/ThirdPartyLibs/enet/win32.c @@ -0,0 +1,368 @@ +/** + @file win32.c + @brief ENet Win32 system specific functions +*/ +#ifdef WIN32 + +#include +#define ENET_BUILDING_LIB 1 +#include "enet/enet.h" + +static enet_uint32 timeBase = 0; + +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_uint32 +enet_time_get (void) +{ + return (enet_uint32) timeGetTime () - timeBase; +} + +void +enet_time_set (enet_uint32 newTimeBase) +{ + timeBase = (enet_uint32) timeGetTime () - newTimeBase; +} + +int +enet_address_set_host (ENetAddress * address, const char * name) +{ + struct hostent * hostEntry; + + hostEntry = gethostbyname (name); + if (hostEntry == NULL || + hostEntry -> h_addrtype != AF_INET) + { + unsigned long host = inet_addr (name); + if (host == INADDR_NONE) + return -1; + address -> host = host; + return 0; + } + + address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0]; + + return 0; +} + +int +enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) +{ + char * addr = inet_ntoa (* (struct in_addr *) & address -> host); + if (addr == NULL) + return -1; + strncpy (name, addr, nameLength); + return 0; +} + +int +enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) +{ + struct in_addr in; + struct hostent * hostEntry; + + in.s_addr = address -> host; + + hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); + if (hostEntry == NULL) + return enet_address_get_host_ip (address, name, nameLength); + + strncpy (name, hostEntry -> h_name, nameLength); + + return 0; +} + +int +enet_socket_bind (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + + if (address != NULL) + { + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + else + { + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + } + + return bind (socket, + (struct sockaddr *) & sin, + sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 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_INET, 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; + + default: + break; + } + return result == SOCKET_ERROR ? -1 : 0; +} + +int +enet_socket_connect (ENetSocket socket, const ENetAddress * address) +{ + struct sockaddr_in sin; + int result; + + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + + result = connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)); + if (result == SOCKET_ERROR && WSAGetLastError () != WSAEWOULDBLOCK) + return -1; + + return 0; +} + +ENetSocket +enet_socket_accept (ENetSocket socket, ENetAddress * address) +{ + SOCKET result; + struct sockaddr_in sin; + int sinLength = sizeof (struct sockaddr_in); + + 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 = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + 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_in sin; + DWORD sentLength; + + if (address != NULL) + { + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + + if (WSASendTo (socket, + (LPWSABUF) buffers, + (DWORD) bufferCount, + & sentLength, + 0, + address != NULL ? (struct sockaddr *) & sin : NULL, + address != NULL ? sizeof (struct sockaddr_in) : 0, + NULL, + NULL) == SOCKET_ERROR) + { + if (WSAGetLastError () == WSAEWOULDBLOCK) + return 0; + + return -1; + } + + return (int) sentLength; +} + +int +enet_socket_receive (ENetSocket socket, + ENetAddress * address, + ENetBuffer * buffers, + size_t bufferCount) +{ + INT sinLength = sizeof (struct sockaddr_in); + DWORD flags = 0, + recvLength; + struct sockaddr_in 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 = (enet_uint32) sin.sin_addr.s_addr; + address -> port = ENET_NET_TO_HOST_16 (sin.sin_port); + } + + return (int) recvLength; +} + +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_uint32 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; +} + +#endif + diff --git a/examples/Vehicles/Hinge2Vehicle.cpp b/examples/Vehicles/Hinge2Vehicle.cpp index 1ed665190..9d72ad57c 100644 --- a/examples/Vehicles/Hinge2Vehicle.cpp +++ b/examples/Vehicles/Hinge2Vehicle.cpp @@ -301,13 +301,11 @@ Hinge2Vehicle::~Hinge2Vehicle() } -extern float shadowMapWorldSize; void Hinge2Vehicle::initPhysics() { m_guiHelper->setUpAxis(1); - shadowMapWorldSize = 10; btCollisionShape* groundShape = new btBoxShape(btVector3(50,3,50)); m_collisionShapes.push_back(groundShape); diff --git a/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp b/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp index dac2711e4..d42f00a63 100644 --- a/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp +++ b/src/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp @@ -105,11 +105,12 @@ btDefaultCollisionConfiguration::btDefaultCollisionConfiguration(const btDefault int maxSize = sizeof(btConvexConvexAlgorithm); int maxSize2 = sizeof(btConvexConcaveCollisionAlgorithm); int maxSize3 = sizeof(btCompoundCollisionAlgorithm); + int maxSize4 = sizeof(btCompoundCompoundCollisionAlgorithm); int collisionAlgorithmMaxElementSize = btMax(maxSize,constructionInfo.m_customCollisionAlgorithmMaxElementSize); collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize2); collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize3); - + collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize4); if (constructionInfo.m_persistentManifoldPool) { diff --git a/test/GwenOpenGLTest/OpenGLSample.cpp b/test/GwenOpenGLTest/OpenGLSample.cpp index 3f1452f34..af7781fdf 100644 --- a/test/GwenOpenGLTest/OpenGLSample.cpp +++ b/test/GwenOpenGLTest/OpenGLSample.cpp @@ -2,6 +2,7 @@ #include "Gwen/Gwen.h" #include "Gwen/Skins/Simple.h" +#include "../OpenGLWindow/OpenGLInclude.h" #include "UnitTest.h" @@ -22,9 +23,10 @@ extern unsigned char OpenSansData[]; #endif//__APPLE__ #include "OpenGLWindow/opengl_fontstashcallbacks.h" - +#ifndef NO_OPENGL3 #include "OpenGLWindow/GwenOpenGL3CoreRenderer.h" #include "OpenGLWindow/GLPrimitiveRenderer.h" +#endif #include Gwen::Controls::Canvas* pCanvas = NULL; @@ -79,10 +81,12 @@ static void MyResizeCallback( float width, float height) sWidth = width; sHeight = height; // printf("resize(%d,%d)\n",sWidth,sHeight); +#ifndef NO_OPENGL3 if (primRenderer) { primRenderer->setScreenSize(width,height); } +#endif if (gwenRenderer) { gwenRenderer->Resize(width,height); @@ -96,7 +100,7 @@ static void MyResizeCallback( float width, float height) int droidRegular;//, droidItalic, droidBold, droidJapanese, dejavu; - +#ifndef NO_OPENGL3 sth_stash* initFont(GLPrimitiveRenderer* primRenderer) { GLint err; @@ -217,7 +221,7 @@ sth_stash* initFont(GLPrimitiveRenderer* primRenderer) return stash; } - +#endif void keyCallback(int key, int value) { printf("key = %d, value = %d\n", key,value); @@ -308,7 +312,11 @@ int main() b3gDefaultOpenGLWindow* window = new b3gDefaultOpenGLWindow(); window->setKeyboardCallback(keyCallback); b3gWindowConstructionInfo wci; - wci.m_openglVersion = 2; +#ifndef NO_OPENGL3 + wci.m_openglVersion = 3; +#else + wci.m_openglVersion = 2; +#endif wci.m_width = sWidth; wci.m_height = sHeight; // wci.m_resizeCallback = MyResizeCallback; @@ -333,7 +341,7 @@ int main() sprintf(title,"Gwen with OpenGL %d\n",wci.m_openglVersion); } window->setWindowTitle(title); - +#ifndef NO_OPENGL3 if (majorGlVersion>=3 && wci.m_openglVersion>=3) { float retinaScale = 1.f; @@ -363,6 +371,7 @@ int main() gwenRenderer = new GwenOpenGL3CoreRenderer(primRenderer,font,sWidth,sHeight,retinaScale); } else +#endif { //OpenGL 2.x gwenRenderer = new Gwen::Renderer::OpenGL_DebugFont(); diff --git a/test/enet/client/main.cpp b/test/enet/client/main.cpp new file mode 100644 index 000000000..2c0696869 --- /dev/null +++ b/test/enet/client/main.cpp @@ -0,0 +1,179 @@ + + + + + + +#include +#include +#include + + +int main(int argc, char* argv[]) +{ + printf("starting client (and server)\n"); + + if (enet_initialize () != 0) + { + fprintf (stderr, "An error occurred while initializing ENet.\n"); + return EXIT_FAILURE; + } + atexit (enet_deinitialize); + + ENetAddress selfaddress; + selfaddress.host = ENET_HOST_ANY; + /* Bind the server to port 1111. */ + selfaddress.port = 1111; + + ENetHost * client=0; + while (!client) + { + client = enet_host_create (&selfaddress/* create a client host */, + 32 /* only 32 connections */, + 2 /* allow up 2 channels to be used, 0 and 1 */, + 0/*57600 / 8 56K modem with 56 Kbps downstream bandwidth */, + 0 /* 14400 / 8 56K modem with 14 Kbps upstream bandwidth */); + if (client == NULL) + { + selfaddress.port++; + } + } + if (client == NULL) + { + fprintf (stderr, + "An error occurred while trying to create an ENet client host.\n"); + exit (EXIT_FAILURE); + } + + + + ENetAddress dedicatedserveraddress; + ENetEvent event; + ENetPeer* dedicatedpeer=0; + ENetPeer* natpeer=0; + + /* Connect to some.server.net:1234. */ + enet_address_set_host (& dedicatedserveraddress, "localhost"); + dedicatedserveraddress.port = 1234; + /* Initiate the connection, allocating the two channels 0 and 1. */ + dedicatedpeer = enet_host_connect (client, & dedicatedserveraddress, 2, 0); + if (dedicatedpeer == NULL) + { + fprintf (stderr, "No available peers for initiating an ENet connection.\n"); + exit (EXIT_FAILURE); + } + /* Wait up to 5 seconds for the connection attempt to succeed. */ + if (enet_host_service (client, & event, 5000) > 0 && + event.type == ENET_EVENT_TYPE_CONNECT) + { + char servername[1024]; + enet_address_get_host(&dedicatedserveraddress,servername, 1024); + char serverinfo[1024]; + + sprintf(serverinfo,"Connection to %s:%d succeeded", servername,dedicatedserveraddress.port); + puts (serverinfo); + + /////.... + + /* Wait up to 1000 milliseconds for an event. */ + while (enet_host_service (client, & event, 1000000000) > 0) + { + if (natpeer) + { + /* Create a reliable packet of size 7 containing "packet\0" */ + ENetPacket * packet = enet_packet_create ("packet", + strlen ("packet") + 1, + ENET_PACKET_FLAG_RELIABLE); + /* Extend the packet so and append the string "foo", so it now */ + /* contains "packetfoo\0" */ + enet_packet_resize (packet, strlen ("packetfoo") + 1); + strcpy ((char*)& packet -> data [strlen ("packet")], "foo"); + /* Send the packet to the peer over channel id 0. */ + /* One could also broadcast the packet by */ + /* enet_host_broadcast (host, 0, packet); */ + enet_peer_send (natpeer, 0, packet); + } + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + printf ("A new client connected from %x:%u.\n", + event.peer -> address.host, + event.peer -> address.port); + /* Store any relevant client information here. */ + event.peer -> data = (char*)"Client information"; + break; + case ENET_EVENT_TYPE_RECEIVE: + printf ("A packet of length %u containing %s was received from %s on channel %u.\n", + event.packet -> dataLength, + event.packet -> data, + event.peer -> data, + event.channelID); + /* Clean up the packet now that we're done using it. */ + + if (event.packet->dataLength==sizeof(ENetAddress)) + { + ENetAddress* address = (ENetAddress*)event.packet->data; + printf("received other client's address from server, connecting...\n"); + natpeer = enet_host_connect (client, address, 2, 0); + if (natpeer== NULL) + { + fprintf (stderr, "No available peers for initiating an ENet connection.\n"); + exit (EXIT_FAILURE); + } + /* Wait up to 5 seconds for the connection attempt to succeed. */ + if (enet_host_service (client, & event, 5000) > 0 && + event.type == ENET_EVENT_TYPE_CONNECT) + { + puts ("Connection to natpeer succeeded."); + } else + { + enet_peer_reset (natpeer); + puts ("Connection to natpeer failed."); + natpeer=0; + exit(0); + } + + } + + enet_packet_destroy (event.packet); + break; + + case ENET_EVENT_TYPE_DISCONNECT: + printf ("%s disconected.\n", event.peer -> data); + /* Reset the peer's client information. */ + event.peer -> data = NULL; + } + } + /* One could just use enet_host_service() instead. */ + enet_host_flush (client);//host); + } + else + { + /* Either the 5 seconds are up or a disconnect event was */ + /* received. Reset the peer in the event the 5 seconds */ + /* had run out without any significant event. */ + enet_peer_reset (dedicatedpeer); + puts ("Connection to some.server.net:1234 failed."); + } + + + + + + + enet_host_destroy(client); + + return 0; +} + + + + + + + + + + + + diff --git a/test/enet/client/premake4.lua b/test/enet/client/premake4.lua new file mode 100644 index 000000000..0e38fd6cd --- /dev/null +++ b/test/enet/client/premake4.lua @@ -0,0 +1,25 @@ + + +project ("Test_enet_client") + + language "C++" + + kind "ConsoleApp" + targetdir "../../../bin" + includedirs {"../../../examples/ThirdPartyLibs/enet/include"} + + if os.is("Windows") then + defines { "WIN32" } + links {"Ws2_32","Winmm"} + end + if os.is("Linux") then + end + if os.is("MacOSX") then + end + + links {"enet"} + + files { + "main.cpp", + } + diff --git a/test/enet/server/main.cpp b/test/enet/server/main.cpp new file mode 100644 index 000000000..ded38f2a7 --- /dev/null +++ b/test/enet/server/main.cpp @@ -0,0 +1,112 @@ + +#include +#include +#include + + +ENetPeer* mypeers[2]={0,0}; +ENetAddress clientAddresses[2]; +int numpeers=0; + +int main(int argc, char* argv[]) +{ + fprintf(stderr,"starting enet dedicated server\n"); + + if (enet_initialize () != 0) + { + fprintf (stderr, "An error occurred while initializing ENet.\n"); + return EXIT_FAILURE; + } + atexit (enet_deinitialize); + + ENetAddress address; + ENetHost * server; + /* Bind the server to the default localhost. */ + /* A specific host address can be specified by */ + /* enet_address_set_host (& address, "x.x.x.x"); */ + address.host = ENET_HOST_ANY; + /* Bind the server to port 1234. */ + address.port = 1234; + server = enet_host_create (& address /* the address to bind the server host to */, + 32 /* allow up to 32 clients and/or outgoing connections */, + 2 /* allow up to 2 channels to be used, 0 and 1 */, + 0 /* assume any amount of incoming bandwidth */, + 0 /* assume any amount of outgoing bandwidth */); + if (server == NULL) + { + fprintf (stderr, + "An error occurred while trying to create an ENet server host.\n"); + exit (EXIT_FAILURE); + } + + + ENetEvent event; + + /* Wait up to 10000000 milliseconds for an event. */ + while (enet_host_service (server, & event, 10000000) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + char clientname[1024]; + enet_address_get_host(&event.peer -> address,clientname, 1024); + printf ("A new client connected from %s:%u.\n", + clientname, + event.peer -> address.port); + /* Store any relevant client information here. */ + event.peer -> data = (char*)"Client information"; + if (numpeers<2) + { + clientAddresses[numpeers] = event.peer->address; + mypeers[numpeers] = event.peer; + } + numpeers++; + if (numpeers==2) + { + printf("exchanging addresses for NAT punchthrough\n"); + //exchange the address info + for (int i=0;i<2;i++) + { + int sz = sizeof(ENetAddress); + /* Create a reliable packet of size 7 containing "packet\0" */ + ENetPacket * packet = enet_packet_create (&clientAddresses[i], + sz, + ENET_PACKET_FLAG_RELIABLE); + enet_peer_send (mypeers[1-i], 0, packet); + + + } + //prepare for the next pair of clients to connect/NAT punchthrough + numpeers=0; + } + + break; + case ENET_EVENT_TYPE_RECEIVE: + printf ("A packet of length %u containing %s was received from %s on channel %u.\n", + event.packet -> dataLength, + event.packet -> data, + event.peer -> data, + event.channelID); + /* Clean up the packet now that we're done using it. */ + enet_packet_destroy (event.packet); + + break; + + case ENET_EVENT_TYPE_DISCONNECT: + printf ("%s disconected.\n", event.peer -> data); + /* Reset the peer's client information. */ + event.peer -> data = NULL; + } + } + + + + + + + enet_host_destroy(server); + printf("server exited, press key\n"); + getchar(); + + return 0; +} diff --git a/test/enet/server/premake4.lua b/test/enet/server/premake4.lua new file mode 100644 index 000000000..84fd143d6 --- /dev/null +++ b/test/enet/server/premake4.lua @@ -0,0 +1,26 @@ + + +project ("Test_enet_server") + + language "C++" + + kind "ConsoleApp" + targetdir "../../../bin" + includedirs {"../../../examples/ThirdPartyLibs/enet/include"} + + if os.is("Windows") then + defines { "WIN32" } + + links {"Ws2_32","Winmm"} + end + if os.is("Linux") then + end + if os.is("MacOSX") then + end + + links {"enet"} + + files { + "main.cpp", + } +