Index: /code/trunk/cmake/LibraryConfig.cmake
===================================================================
--- /code/trunk/cmake/LibraryConfig.cmake	(revision 7458)
+++ /code/trunk/cmake/LibraryConfig.cmake	(revision 7459)
@@ -94,5 +94,5 @@
 
 FIND_PACKAGE(OGRE  1.4       REQUIRED)
-FIND_PACKAGE(ENet  1.1       REQUIRED)
+#FIND_PACKAGE(ENet  1.1       REQUIRED)
 FIND_PACKAGE(Ogg             REQUIRED)
 FIND_PACKAGE(Vorbis          REQUIRED)
@@ -177,5 +177,5 @@
   OPTION(LINK_BOOST_DYNAMIC "Link Boost dynamically on Windows" TRUE)
   OPTION(LINK_CEGUI_DYNAMIC "Link CEGUI dynamicylly on Windows" TRUE)
-  OPTION(LINK_ENET_DYNAMIC  "Link ENet dynamically on Windows" TRUE)
+  #OPTION(LINK_ENET_DYNAMIC  "Link ENet dynamically on Windows" TRUE)
   OPTION(LINK_OGRE_DYNAMIC  "Link OGRE dynamically on Windows" TRUE)
   OPTION(LINK_TCL_DYNAMIC   "Link TCL dynamically on Windows" TRUE)
@@ -190,5 +190,5 @@
   IF(DEPENDENCY_PACKAGE_ENABLE)
     MARK_AS_ADVANCED(
-      LINK_BOOST_DYNAMIC LINK_CEGUI_DYNAMIC LINK_ENET_DYNAMIC
+      LINK_BOOST_DYNAMIC LINK_CEGUI_DYNAMIC #LINK_ENET_DYNAMIC
       LINK_OGRE_DYNAMIC  LINK_TCL_DYNAMIC   LINK_ZLIB_DYNAMIC
       LINK_LUA_DYNAMIC
Index: /code/trunk/cmake/PackageConfig.cmake
===================================================================
--- /code/trunk/cmake/PackageConfig.cmake	(revision 7458)
+++ /code/trunk/cmake/PackageConfig.cmake	(revision 7459)
@@ -83,5 +83,5 @@
 SET(ENV{DBGHELP_DIR}           ${DEP_INCLUDE_DIR}/dbghelp)
 SET(ENV{DXSDK_DIR}             ${DEP_INCLUDE_DIR}/directx)
-SET(ENV{ENETDIR}               ${DEP_INCLUDE_DIR}/enet)
+#SET(ENV{ENETDIR}               ${DEP_INCLUDE_DIR}/enet)
 SET(ENV{LUA_DIR}               ${DEP_INCLUDE_DIR}/lua)
 SET(ENV{OGGDIR}                ${DEP_INCLUDE_DIR}/libogg)
Index: /code/trunk/src/CMakeLists.txt
===================================================================
--- /code/trunk/src/CMakeLists.txt	(revision 7458)
+++ /code/trunk/src/CMakeLists.txt	(revision 7459)
@@ -38,5 +38,5 @@
 # If no defines are specified, these libs get linked statically
 ADD_COMPILER_FLAGS("-DBOOST_ALL_DYN_LINK" WIN32 LINK_BOOST_DYNAMIC)
-ADD_COMPILER_FLAGS("-DENET_DLL"           WIN32 LINK_ENET_DYNAMIC)
+#ADD_COMPILER_FLAGS("-DENET_DLL"           WIN32 LINK_ENET_DYNAMIC)
 ADD_COMPILER_FLAGS("-DLUA_BUILD_AS_DLL"   WIN32 LINK_LUA_DYNAMIC)
 ADD_COMPILER_FLAGS("-DZLIB_DLL"           WIN32 LINK_ZLIB_DYNAMIC)
@@ -61,4 +61,5 @@
 # If no defines are specified, these libs get linked dynamically
 ADD_COMPILER_FLAGS("-DCEGUILUA_STATIC"             WIN32 NOT _external_shared_link)
+ADD_COMPILER_FLAGS("-DENET_DLL"                    WIN32     _external_shared_link)
 ADD_COMPILER_FLAGS("-DOGRE_GUIRENDERER_STATIC_LIB" WIN32 NOT _external_shared_link)
 ADD_COMPILER_FLAGS("-DOIS_STATIC_LIB"              WIN32 NOT _external_shared_link)
@@ -72,5 +73,5 @@
   ${OGRE_INCLUDE_DIR}
   ${CEGUI_INCLUDE_DIR}
-  ${ENET_INCLUDE_DIR}
+  #${ENET_INCLUDE_DIR}
   ${Boost_INCLUDE_DIRS}
   ${POCO_INCLUDE_DIR}
Index: /code/trunk/src/external/CMakeLists.txt
===================================================================
--- /code/trunk/src/external/CMakeLists.txt	(revision 7458)
+++ /code/trunk/src/external/CMakeLists.txt	(revision 7459)
@@ -34,4 +34,5 @@
 ADD_SUBDIRECTORY(bullet)
 ADD_SUBDIRECTORY(cpptcl)
+ADD_SUBDIRECTORY(enet)
 ADD_SUBDIRECTORY(loki)
 ADD_SUBDIRECTORY(ogreceguirenderer)
Index: /code/trunk/src/external/enet/CMakeLists.txt
===================================================================
--- /code/trunk/src/external/enet/CMakeLists.txt	(revision 7459)
+++ /code/trunk/src/external/enet/CMakeLists.txt	(revision 7459)
@@ -0,0 +1,57 @@
+ #
+ #             ORXONOX - the hottest 3D action shooter ever to exist
+ #                             > www.orxonox.net <
+ #
+ #        This program is free software; you can redistribute it and/or
+ #         modify it under the terms of the GNU General Public License
+ #        as published by the Free Software Foundation; either version 2
+ #            of the License, or (at your option) any later version.
+ #
+ #       This program is distributed in the hope that it will be useful,
+ #        but WITHOUT ANY WARRANTY; without even the implied warranty of
+ #        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ #                 GNU General Public License for more details.
+ #
+ #   You should have received a copy of the GNU General Public License along
+ #      with this program; if not, write to the Free Software Foundation,
+ #     Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ #
+
+SET_SOURCE_FILES(ENET_FILES
+    callbacks.h
+    enet.h
+    list.h
+    protocol.h
+    time.h
+    types.h
+    unix.h
+    utility.h
+    win32.h
+
+    win32.c
+
+COMPILATION_BEGIN ENetCompilation.c
+    callbacks.c
+    compress.c
+    host.c
+    list.c
+    packet.c
+    peer.c
+    protocol.c
+    unix.c
+COMPILATION_END
+)
+
+ADD_COMPILER_FLAGS("-DHAS_POLL -DHAS_FCNTL -DHAS_MSGHDR_FLAGS -DHAS_SOCKLEN_T")
+
+IF(WIN32)
+    SET(ENET_WIN_LIBS odbc32 odbccp32 winmm ws2_32)
+ENDIF()
+
+ORXONOX_ADD_LIBRARY(enet_orxonox
+    ORXONOX_EXTERNAL
+    VERSION        1.3.0
+    DEFINE_SYMBOL  "ENET_BUILDING_LIB"
+    LINK_LIBRARIES ${ENET_WIN_LIBS}
+    SOURCE_FILES   ${ENET_FILES}
+)
Index: /code/trunk/src/external/enet/ChangeLog
===================================================================
--- /code/trunk/src/external/enet/ChangeLog	(revision 7459)
+++ /code/trunk/src/external/enet/ChangeLog	(revision 7459)
@@ -0,0 +1,86 @@
+ENet 1.3.0 (June 5, 2010):
+
+* enet_host_create() now requires the channel limit to be specified as
+a parameter
+* enet_host_connect() now accepts a data parameter which is supplied 
+to the receiving receiving host in the event data field for a connect event
+* added an adaptive order-2 PPM range coder as a built-in compressor option
+which can be set with enet_host_compress_with_range_coder()
+* added support for packet compression configurable with a callback
+* improved session number handling to not rely on the packet checksum
+field, saving 4 bytes per packet unless the checksum option is used
+* removed the dependence on the rand callback for session number handling
+
+Caveats: This version is not protocol compatible with the 1.2 series or 
+earlier. The enet_host_connect and enet_host_create API functions require
+supplying additional parameters.
+
+ENet 1.2.2 (June 5, 2010):
+
+* checksum functionality is now enabled by setting a checksum callback
+inside ENetHost instead of being a configure script option
+* added totalSentData, totalSentPackets, totalReceivedData, and
+totalReceivedPackets counters inside ENetHost for getting usage
+statistics
+* added enet_host_channel_limit() for limiting the maximum number of
+channels allowed by connected peers
+* now uses dispatch queues for event dispatch rather than potentially
+unscalable array walking
+* added no_memory callback that is called when a malloc attempt fails,
+such that if no_memory returns rather than aborts (the default behavior),
+then the error is propagated to the return value of the API calls
+* now uses packed attribute for protocol structures on platforms with 
+strange alignment rules
+* improved autoconf build system contributed by Nathan Brink allowing 
+for easier building as a shared library
+
+Caveats: If you were using the compile-time option that enabled checksums,
+make sure to set the checksum callback inside ENetHost to enet_crc32 to
+regain the old behavior. The ENetCallbacks structure has added new fields,
+so make sure to clear the structure to zero before use if 
+using enet_initialize_with_callbacks().
+
+ENet 1.2.1 (November 12, 2009):
+
+* fixed bug that could cause disconnect events to be dropped
+* added thin wrapper around select() for portable usage
+* added ENET_SOCKOPT_REUSEADDR socket option
+* factored enet_socket_bind()/enet_socket_listen() out of enet_socket_create()
+* added contributed Code::Blocks build file
+
+ENet 1.2 (February 12, 2008):
+
+* fixed bug in VERIFY_CONNECT acknowledgement that could cause connect
+attempts to occasionally timeout
+* fixed acknowledgements to check both the outgoing and sent queues
+when removing acknowledged packets
+* fixed accidental bit rot in the MSVC project file
+* revised sequence number overflow handling to address some possible
+disconnect bugs
+* added enet_host_check_events() for getting only local queued events
+* factored out socket option setting into enet_socket_set_option() so
+that socket options are now set separately from enet_socket_create()
+
+Caveats: While this release is superficially protocol compatible with 1.1,
+differences in the sequence number overflow handling can potentially cause
+random disconnects.
+
+ENet 1.1 (June 6, 2007):
+
+* optional CRC32 just in case someone needs a stronger checksum than UDP 
+provides (--enable-crc32 configure option)
+* the size of packet headers are half the size they used to be (so less 
+overhead when sending small packets)
+* enet_peer_disconnect_later() that waits till all queued outgoing 
+packets get sent before issuing an actual disconnect
+* freeCallback field in individual packets for notification of when a 
+packet is about to be freed
+* ENET_PACKET_FLAG_NO_ALLOCATE for supplying pre-allocated data to a 
+packet (can be used in concert with freeCallback to support some custom 
+allocation schemes that the normal memory allocation callbacks would 
+normally not allow)
+* enet_address_get_host_ip() for printing address numbers
+* promoted the enet_socket_*() functions to be part of the API now
+* a few stability/crash fixes
+
+
Index: /code/trunk/src/external/enet/Doxyfile
===================================================================
--- /code/trunk/src/external/enet/Doxyfile	(revision 7459)
+++ /code/trunk/src/external/enet/Doxyfile	(revision 7459)
@@ -0,0 +1,993 @@
+# Doxyfile 1.2.18
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded 
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = enet
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. 
+# This could be handy for archiving the generated documentation or 
+# if some version control system is used.
+
+PROJECT_NUMBER         = 
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) 
+# base path where the generated documentation will be put. 
+# If a relative path is entered, it will be relative to the location 
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all 
+# documentation generated by doxygen is written. Doxygen will use this 
+# information to generate all constant output in the proper language. 
+# The default language is English, other supported languages are: 
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, 
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en 
+# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese, 
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian.
+
+OUTPUT_LANGUAGE        = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in 
+# documentation are documented, even if no documentation was available. 
+# Private class members and static file members will be hidden unless 
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class 
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file 
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) 
+# defined locally in source files will be included in the documentation. 
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all 
+# undocumented members of documented classes, files or namespaces. 
+# If set to NO (the default) these members will be included in the 
+# various overviews, but no documentation section is generated. 
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all 
+# undocumented classes that are normally visible in the class hierarchy. 
+# If set to NO (the default) these class will be included in the various 
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all 
+# friend (class|struct|union) declarations. 
+# If set to NO (the default) these declarations will be included in the 
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will 
+# include brief member descriptions after the members that are listed in 
+# the file and class documentation (similar to JavaDoc). 
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend 
+# the brief description of a member or function before the detailed description. 
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the 
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = NO
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then 
+# Doxygen will generate a detailed section even if there is only a brief 
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited 
+# members of a class in the documentation of that class as if those members were 
+# ordinary class members. Constructors, destructors and assignment operators of 
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full 
+# path before files name in the file list and in the header files. If set 
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag 
+# can be used to strip a user defined part of the path. Stripping is 
+# only done if one of the specified strings matches the left-hand part of 
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH        = 
+
+# The INTERNAL_DOCS tag determines if documentation 
+# that is typed after a \internal command is included. If the tag is set 
+# to NO (the default) then the documentation will be excluded. 
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct 
+# doxygen to hide any special comment blocks from generated source code 
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate 
+# file names in lower case letters. If set to YES upper case letters are also 
+# allowed. This is useful if you have classes or files whose names only differ 
+# in case and if your file system supports case sensitive file names. Windows 
+# users are adviced to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter 
+# (but less readable) file names. This can be useful is your file systems 
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen 
+# will show members with their full class and namespace scopes in the 
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen 
+# will generate a verbatim copy of the header file for each class for 
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen 
+# will put list of the files that are included by a file in the documentation 
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen 
+# will interpret the first line (until the first dot) of a JavaDoc-style 
+# comment as the brief description. If set to NO, the JavaDoc 
+# comments  will behave just like the Qt-style comments (thus requiring an 
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF      = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen 
+# treat a multi-line C++ special comment block (i.e. a block of //! or /// 
+# comments) as a brief description. This used to be the default behaviour. 
+# The new default is to treat a multi-line C++ comment block as a detailed 
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen 
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member 
+# documentation.
+
+DETAILS_AT_TOP         = YES
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented 
+# member inherits the documentation from any documented member that it 
+# reimplements.
+
+INHERIT_DOCS           = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] 
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen 
+# will sort the (detailed) documentation of file and class members 
+# alphabetically by member name. If set to NO the members will appear in 
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC 
+# tag is set to YES, then doxygen will reuse the documentation of the first 
+# member in the group (if any) for the other members of the group. By default 
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. 
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or 
+# disable (NO) the todo list. This list is created by putting \todo 
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or 
+# disable (NO) the test list. This list is created by putting \test 
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or 
+# disable (NO) the bug list. This list is created by putting \bug 
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or 
+# disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# This tag can be used to specify a number of aliases that acts 
+# as commands in the documentation. An alias has the form "name=value". 
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to 
+# put the command \sideeffect (or @sideeffect) in the documentation, which 
+# will result in a user defined paragraph with heading "Side Effects:". 
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                = 
+
+# The ENABLED_SECTIONS tag can be used to enable conditional 
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       = 
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines 
+# the initial value of a variable or define consist of for it to appear in 
+# the documentation. If the initializer consists of more lines than specified 
+# here it will be hidden. Use a value of 0 to hide initializers completely. 
+# The appearance of the initializer of individual variables and defines in the 
+# documentation can be controlled using \showinitializer or \hideinitializer 
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 
+# only. Doxygen will then generate output that is more tailored for C. 
+# For instance some of the names that are used will be different. The list 
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources 
+# only. Doxygen will then generate output that is more tailored for Java. 
+# For instance namespaces will be presented as packages, qualified scopes 
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated 
+# at the bottom of the documentation of classes and structs. If set to YES the 
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated 
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are 
+# generated by doxygen. Possible values are YES and NO. If left blank 
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings 
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will 
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that 
+# doxygen can produce. The string should contain the $file, $line, and $text 
+# tags, which will be replaced by the file and line number from which the 
+# warning originated and the warning text.
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning 
+# and error messages should be written. If left blank the output is written 
+# to stderr.
+
+WARN_LOGFILE           = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain 
+# documented source files. You may enter file names like "myfile.cpp" or 
+# directories like "/usr/src/myproject". Separate the files or directories 
+# with spaces.
+
+INPUT                  = . include/enet docs
+
+# If the value of the INPUT tag contains directories, you can use the 
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank the following patterns are tested: 
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp 
+# *.h++ *.idl *.odl
+
+FILE_PATTERNS          = *.c *.h *.dox
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories 
+# should be searched for input files as well. Possible values are YES and NO. 
+# If left blank NO is used.
+
+RECURSIVE              = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should 
+# excluded from the INPUT source files. This way you can easily exclude a 
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                = Tests
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories 
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the 
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude 
+# certain files from those directories.
+
+EXCLUDE_PATTERNS       = 
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or 
+# directories that contain example code fragments that are included (see 
+# the \include command).
+
+EXAMPLE_PATH           = 
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the 
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp 
+# and *.h) to filter out the source-files in the directories. If left 
+# blank all files are included.
+
+EXAMPLE_PATTERNS       = 
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be 
+# searched for input files to be used with the \include or \dontinclude 
+# commands irrespective of the value of the RECURSIVE tag. 
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or 
+# directories that contain image that are included in the documentation (see 
+# the \image command).
+
+IMAGE_PATH             = 
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should 
+# invoke to filter for each input file. Doxygen will invoke the filter program 
+# by executing (via popen()) the command <filter> <input-file>, where <filter> 
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an 
+# input file. Doxygen will then use the output that the filter program writes 
+# to standard output.
+
+INPUT_FILTER           = 
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 
+# INPUT_FILTER) will be used to filter the input files when producing source 
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will 
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body 
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default) 
+# then for each documented function all documented 
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default) 
+# then for each documented function all documented entities 
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index 
+# of all compounds will be generated. Enable this if the project 
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then 
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns 
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all 
+# classes will be put under the same header in the alphabetical index. 
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that 
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will 
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for 
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank 
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard header.
+
+HTML_HEADER            = 
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for 
+# each generated HTML page. If it is left blank doxygen will generate a 
+# standard footer.
+
+HTML_FOOTER            = 
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading 
+# style sheet that is used by each HTML page. It can be used to 
+# fine-tune the look of the HTML output. If the tag is left blank doxygen 
+# will generate a default style sheet
+
+HTML_STYLESHEET        = 
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, 
+# files or namespaces will be aligned in HTML using tables. If set to 
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files 
+# will be generated that can be used as input for tools like the 
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) 
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can 
+# be used to specify the file name of the resulting .chm file. You 
+# can add a path in front of the file if the result should not be 
+# written to the html output dir.
+
+CHM_FILE               = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can 
+# be used to specify the location (absolute path including file name) of 
+# the HTML help compiler (hhc.exe). If non empty doxygen will try to run 
+# the html help compiler on the generated index.hhp.
+
+HHC_LOCATION           = 
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag 
+# controls if a separate .chi index file is generated (YES) or that 
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag 
+# controls whether a binary table of contents is generated (YES) or a 
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members 
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at 
+# top of each HTML page. The value NO (the default) enables the index and 
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20]) 
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that 
+# is generated for HTML Help). For this to work a browser that supports 
+# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+, 
+# or Internet explorer 4.0+). Note that for large projects the tree generation 
+# can take a very long time. In such cases it is better to disable this feature. 
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be 
+# used to set the initial width (in pixels) of the frame in which the tree 
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will 
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to 
+# generate index for LaTeX. If left blank `makeindex' will be used as the 
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact 
+# LaTeX documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used 
+# by the printer. Possible values are: a4, a4wide, letter, legal and 
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX 
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         = 
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for 
+# the generated latex document. The header should contain everything until 
+# the first chapter. If it is left blank doxygen will generate a 
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           = 
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated 
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will 
+# contain links (just like the HTML output) instead of page references 
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of 
+# plain latex in the generated Makefile. Set this option to YES to get a 
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. 
+# command to the generated LaTeX files. This will instruct LaTeX to keep 
+# running if errors occur, instead of asking the user for help. 
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output 
+# The RTF output is optimised for Word 97 and may not look very pretty with 
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact 
+# RTF documents. This may be useful for small projects and may help to 
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated 
+# will contain hyperlink fields. The RTF file will 
+# contain links (just like the HTML output) instead of page references. 
+# This makes the output suitable for online browsing using WORD or other 
+# programs which support those fields. 
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's 
+# config file, i.e. a series of assigments. You only have to provide 
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    = 
+
+# Set optional variables used in the generation of an rtf document. 
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    = 
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will 
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. 
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be 
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to 
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output, 
+# then it will generate one additional man file for each entity 
+# documented in the real man page(s). These additional files 
+# only source the real man page, but without them the man command 
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will 
+# generate an XML file that captures the structure of 
+# the code including all documentation. Note that this 
+# feature is still experimental and incomplete at the 
+# moment.
+
+GENERATE_XML           = NO
+
+# The XML_SCHEMA tag can be used to specify an XML schema, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_SCHEMA             = 
+
+# The XML_DTD tag can be used to specify an XML DTD, 
+# which can be used by a validating XML parser to check the 
+# syntax of the XML files.
+
+XML_DTD                = 
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will 
+# generate an AutoGen Definitions (see autogen.sf.net) file 
+# that captures the structure of the code including all 
+# documentation. Note that this feature is still experimental 
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor   
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will 
+# evaluate all C-preprocessor directives found in the sources and include 
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro 
+# names in the source code. If set to NO (the default) only conditional 
+# compilation will be performed. Macro expansion can be done in a controlled 
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES 
+# then the macro expansion is limited to the macros specified with the 
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files 
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that 
+# contain include files that are not input files but should be processed by 
+# the preprocessor.
+
+INCLUDE_PATH           = 
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 
+# patterns (like *.h and *.hpp) to filter out the header-files in the 
+# directories. If left blank, the patterns specified with FILE_PATTERNS will 
+# be used.
+
+INCLUDE_FILE_PATTERNS  = 
+
+# The PREDEFINED tag can be used to specify one or more macro names that 
+# are defined before the preprocessor is started (similar to the -D option of 
+# gcc). The argument of the tag is a list of macros of the form: name 
+# or name=definition (no spaces). If the definition and the = are 
+# omitted =1 is assumed.
+
+PREDEFINED             = FORCE_DOXYGEN
+
+# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then 
+# this tag can be used to specify a list of macro names that should be expanded. 
+# The macro definition that is found in the sources will be used. 
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      = 
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then 
+# doxygen's preprocessor will remove all function-like macros that are alone 
+# on a line, have an all uppercase name, and do not end with a semicolon. Such 
+# function macros are typically used for boiler-plate code, and will confuse the 
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references   
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES               = 
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create 
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       = 
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed 
+# in the class index. If set to NO only the inherited external classes 
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed 
+# in the modules index. If set to NO, only the current project's groups will 
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script 
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool   
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will 
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or 
+# super classes. Setting the tag to NO turns the diagrams off. Note that this 
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is 
+# recommended to install and use dot, since it yield more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide 
+# inheritance and usage relations if the target is undocumented 
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is 
+# available from the path. This tool is part of Graphviz, a graph visualization 
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section 
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect inheritance relations. Setting this tag to YES will force the 
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen 
+# will generate a graph for each documented class showing the direct and 
+# indirect implementation dependencies (inheritance, containment, and 
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the 
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT 
+# tags are set to YES then doxygen will generate a graph for each documented 
+# file showing the direct and indirect include dependencies of the file with 
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and 
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each 
+# documented header file showing the documented files that directly or 
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen 
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images 
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be 
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH               = 
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that 
+# contain dot files that are included in the documentation (see the 
+# \dotfile command).
+
+DOTFILE_DIRS           = 
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_WIDTH    = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height 
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than 
+# this value, doxygen will try to truncate the graph, so that it fits within 
+# the specified constraint. Beware that most browsers cannot cope with very 
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT   = 1024
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will 
+# generate a legend page explaining the meaning of the various boxes and 
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will 
+# remove the intermedate dot files that are used to generate 
+# the various graphs.
+
+DOT_CLEANUP            = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine   
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be 
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE           = NO
+
+# The CGI_NAME tag should be the name of the CGI script that 
+# starts the search engine (doxysearch) with the correct parameters. 
+# A script with this name will be generated by doxygen.
+
+CGI_NAME               = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the 
+# cgi binaries are located. See the documentation of your http daemon for 
+# details.
+
+CGI_URL                = 
+
+# The DOC_URL tag should be the absolute URL to the directory where the 
+# documentation is located. If left blank the absolute path to the 
+# documentation, with file:// prepended to it, will be used.
+
+DOC_URL                = 
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the 
+# documentation is located. If left blank the directory on the local machine 
+# will be used.
+
+DOC_ABSPATH            = 
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary 
+# is installed.
+
+BIN_ABSPATH            = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to 
+# documentation generated for other projects. This allows doxysearch to search 
+# the documentation for these projects as well.
+
+EXT_DOC_PATHS          = 
Index: /code/trunk/src/external/enet/LICENSE
===================================================================
--- /code/trunk/src/external/enet/LICENSE	(revision 7459)
+++ /code/trunk/src/external/enet/LICENSE	(revision 7459)
@@ -0,0 +1,7 @@
+Copyright (c) 2002-2010 Lee Salzman
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: /code/trunk/src/external/enet/README
===================================================================
--- /code/trunk/src/external/enet/README	(revision 7459)
+++ /code/trunk/src/external/enet/README	(revision 7459)
@@ -0,0 +1,15 @@
+Please visit the ENet homepage at http://enet.bespin.org for installation
+and usage instructions.
+
+If you obtained this package from CVS, the quick description on how to build
+is:
+
+# Generate the build system.
+
+autoreconf -vfi
+
+# Compile and install the library.
+
+./configure && make && make install
+
+
Index: /code/trunk/src/external/enet/callbacks.c
===================================================================
--- /code/trunk/src/external/enet/callbacks.c	(revision 7459)
+++ /code/trunk/src/external/enet/callbacks.c	(revision 7459)
@@ -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);
+}
+
Index: /code/trunk/src/external/enet/callbacks.h
===================================================================
--- /code/trunk/src/external/enet/callbacks.h	(revision 7459)
+++ /code/trunk/src/external/enet/callbacks.h	(revision 7459)
@@ -0,0 +1,27 @@
+/** 
+ @file  callbacks.h
+ @brief ENet callbacks
+*/
+#ifndef __ENET_CALLBACKS_H__
+#define __ENET_CALLBACKS_H__
+
+#include <stdlib.h>
+
+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__ */
+
Index: /code/trunk/src/external/enet/compress.c
===================================================================
--- /code/trunk/src/external/enet/compress.c	(revision 7459)
+++ /code/trunk/src/external/enet/compress.c	(revision 7459)
@@ -0,0 +1,654 @@
+/** 
+ @file compress.c
+ @brief An adaptive order-2 PPM range coder
+*/
+#define ENET_BUILDING_LIB 1
+#include <string.h>
+#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;
+}
+    
+/** @} */
+    
+     
Index: /code/trunk/src/external/enet/docs/FAQ.dox
===================================================================
--- /code/trunk/src/external/enet/docs/FAQ.dox	(revision 7459)
+++ /code/trunk/src/external/enet/docs/FAQ.dox	(revision 7459)
@@ -0,0 +1,24 @@
+/**
+ @page FAQ Frequently Answered Questions
+
+@section Q1 Is ENet thread safe?
+
+ENet does not use any significant global variables, the vast majority
+of state is encapsulated in the ENetHost structure.  As such, as long
+as the application guards access to this structure, then ENet should
+operate fine in a multithreaded environment.
+   
+@section Q2 Isn't ENet just re-inventing TCP?!  What's the point?
+
+In a perfect world, that would be true.  But as many have found, using
+TCP either in lieu of or in conjunction with UDP can lead to all kinds
+of nightmares.  TCP is a good, solid protocol, however it simply isn't
+up to the task of real-time games.  Too much of TCP's implementation
+dictates a policy that isn't practical for games.  If you want to use
+TCP, then do so -- this library is for people that either don't want
+to use TCP or have tried and ended up being discouraged with the
+performance.
+
+*/
+
+
Index: /code/trunk/src/external/enet/docs/design.dox
===================================================================
--- /code/trunk/src/external/enet/docs/design.dox	(revision 7459)
+++ /code/trunk/src/external/enet/docs/design.dox	(revision 7459)
@@ -0,0 +1,126 @@
+/**
+@page Features Features and Architecture
+
+ENet evolved specifically as a UDP networking layer for the
+multiplayer first person shooter Cube. Cube necessitated low latency
+communcation with data sent out very frequently, so TCP was an
+unsuitable choice due to its high latency and stream orientation. UDP,
+however, lacks many sometimes necessary features from TCP such as
+reliability, sequencing, unrestricted packet sizes, and connection
+management. So UDP by itself was not suitable as a network protocol
+either. No suitable freely available networking libraries existed at
+the time of ENet's creation to fill this niche.
+
+UDP and TCP could have been used together in Cube to benefit somewhat
+from both of their features, however, the resulting combinations of
+protocols still leaves much to be desired. TCP lacks multiple streams
+of communication without resorting to opening many sockets and
+complicates delineation of packets due to its buffering behavior. UDP
+lacks sequencing, connection management, management of bandwidth
+resources, and imposes limitations on the size of packets. A
+significant investment is required to integrate these two protocols,
+and the end result is worse off in features and performance than the
+uniform protocol presented by ENet.
+
+ENet thus attempts to address these issues and provide a single,
+uniform protocol layered over UDP to the developer with the best
+features of UDP and TCP as well as some useful features neither
+provide, with a much cleaner integration than any resulting from a
+mixture of UDP and TCP.
+
+@section CM Connection Management
+
+ENet provides a simple connection interface over which to communicate
+with a foreign host. The liveness of the connection is actively
+monitored by pinging the foreign host at frequent intervals, and also
+monitors the network conditions from the local host to the foreign
+host such as the mean round trip time and packet loss in this fashion.
+
+@section Sequencing Sequencing
+    
+Rather than a single byte stream that complicates the delineation of
+packets, ENet presents connections as multiple, properly sequenced
+packet streams that simplify the transfer of various types of data.
+
+ENet provides sequencing for all packets by assigning to each sent
+packet a sequence number that is incremented as packets are sent. ENet
+guarentees that no packet with a higher sequence number will be
+delivered before a packet with a lower sequence number, thus ensuring
+packets are delivered exactly in the order they are sent.
+
+For unreliable packets, ENet will simply discard the lower sequence
+number packet if a packet with a higher sequence number has already
+been delivered. This allows the packets to be dispatched immediately
+as they arrive, and reduce latency of unreliable packets to an
+absolute minimum.  For reliable packets, if a higher sequence number
+packet arrives, but the preceding packets in the sequence have not yet
+arrived, ENet will stall delivery of the higher sequence number
+packets until its predecessors have arrived.
+
+@section Channels Channels
+
+Since ENet will stall delivery of reliable packets to ensure proper
+sequencing, and consequently any packets of higher sequence number
+whether reliable or unreliable, in the event the reliable packet's
+predecessors have not yet arrived, this can introduce latency into the
+delivery of other packets which may not need to be as strictly ordered
+with respect to the packet that stalled their delivery.
+
+To combat this latency and reduce the ordering restrictions on
+packets, ENet provides multiple channels of communication over a given
+connection.  Each channel is independently sequenced, and so the
+delivery status of a packet in one channel will not stall the delivery
+of other packets in another channel.
+
+@section Reliability Reliability
+
+ENet provides optional reliability of packet delivery by ensuring the
+foreign host acknowledges receipt of all reliable packets. ENet will
+attempt to resend the packet up to a reasonable amount of times, if no
+acknowledgement of the packet's receipt happens within a specified
+timeout. Retry timeouts are progressive and become more lenient with
+every failed attempt to allow for temporary turbulence in network
+conditions.
+
+@section FaR Fragmentation and Reassembly
+
+ENet will send and deliver packets regardless of size. Large packets
+are fragmented into many smaller packets of suitable size, and
+reassembled on the foreign host to recover the original packet for
+delivery. The process is entirely transparent to the developer.
+
+@section Aggregation Aggregation
+
+ENet aggregates all protocol commands, including acknowledgements and
+packet transfer, into larger protocol packets to ensure the proper
+utilization of the connection and to limit the opportunities for
+packet loss that might otherwise result in further delivery latency.
+
+@section Adaptability Adaptability
+
+ENet provides an in-flight data window for reliable packets to ensure
+connections are not overwhelmed by volumes of packets. It also
+provides a static bandwidth allocation mechanism to ensure the total
+volume of packets sent and received to a host don't exceed the host's
+capabilities. Further, ENet also provides a dynamic throttle that
+responds to deviations from normal network connections to rectify
+various types of network congestion by further limiting the volume of
+packets sent.
+
+@section Portability Portability
+    
+ENet works on Windows and any other Unix or Unix-like platform
+providing a BSD sockets interface. The library has a small and stable
+code base that can easily be extended to support other platforms and
+integrates easily.  ENet makes no assumptions about the underlying
+platform's endianess or word size.
+
+@section Freedom Freedom
+
+ENet demands no royalties and doesn't carry a viral license that would
+restrict you in how you might use it in your programs. ENet is
+licensed under a short-and-sweet MIT-style license, which gives you
+the freedom to do anything you want with it (well, almost anything).
+
+*/
+
Index: /code/trunk/src/external/enet/docs/install.dox
===================================================================
--- /code/trunk/src/external/enet/docs/install.dox	(revision 7459)
+++ /code/trunk/src/external/enet/docs/install.dox	(revision 7459)
@@ -0,0 +1,60 @@
+/**
+@page Installation Installation
+
+ENet should be trivially simple to integrate with most applications.
+First, make sure you download the latest source distribution here @ref
+SourceDistro.
+
+@section Unix Unix-like Operating Systems
+
+If you are using an ENet release, then you should simply be able to build it
+by doing the following:
+
+./configure && make && make install
+
+If you obtained the package from CVS, you must have automake and autoconf
+available to generate the build system first by doing the following command
+before using the above mentioned build procedure:
+
+autoreconf -vfi
+
+
+@subsection SolarisBSD Solaris and BSD
+
+When building ENet under Solaris, you must specify the -lsocket and
+-lnsl parameters to your compiler to ensure that the sockets library
+is linked in.
+
+@section Windows Microsoft Windows
+
+There is an included MSVC 6 project (enet.dsp) which you may use to
+build a suitable library file. Alternatively, you may simply drag all 
+the ENet source files into your main project.
+
+You will have to link to the Winsock2 libraries, so make sure to add
+ws2_32.lib and winmm.lib to your library list (Project Settings | Link |
+Object/library modules).
+
+@subsection enet.dsp Building with the included enet.dsp
+
+Load the included enet.dsp. MSVC may ask you to convert it if you
+are on a newer version of MSVC - just allow the conversion and save
+the resulting project as "enet" or similar. After you build this
+project, it will output an "enet.lib" file to either the "Debug/"
+or "Release/" directory, depending on which configuration you have
+selected to build. By default, it should produce "Debug/enet.lib".
+
+You may then copy the resulting "enet.lib" file and the header files
+found in the "include/" directory to your other projects and add it to 
+their library lists. Make sure to also link against "ws2_32.lib" and
+"winmm.lib" as described above.
+
+@subsection DLL DLL
+
+If you wish to build ENet as a DLL you must first define ENET_DLL
+within the project (Project Settings | C/C++ | Preprocessor |
+Preprocessor definitions) or, more invasively, simply define ENET_DLL
+at the top of enet.h.
+
+*/
+
Index: /code/trunk/src/external/enet/docs/license.dox
===================================================================
--- /code/trunk/src/external/enet/docs/license.dox	(revision 7459)
+++ /code/trunk/src/external/enet/docs/license.dox	(revision 7459)
@@ -0,0 +1,26 @@
+/**
+ @page License License
+ 
+Copyright (c) 2002-2010 Lee Salzman
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
Index: /code/trunk/src/external/enet/docs/mainpage.dox
===================================================================
--- /code/trunk/src/external/enet/docs/mainpage.dox	(revision 7459)
+++ /code/trunk/src/external/enet/docs/mainpage.dox	(revision 7459)
@@ -0,0 +1,75 @@
+/** @page enet
+ <center>http://enet.bespin.org</center>
+ <hr>
+
+ENet's purpose is to provide a relatively thin, simple and robust
+network communication layer on top of UDP (User Datagram Protocol).
+The primary feature it provides is optional reliable, in-order
+delivery of packets.
+
+ENet omits certain higher level networking features such as authentication, 
+lobbying, server discovery, encryption, or other similar tasks that are
+particularly application specific so that the library remains flexible,
+portable, and easily embeddable.
+
+@ref Features
+
+@ref SourceDistro
+
+@ref Installation
+
+@ref Tutorial
+
+@ref MailingList
+
+@ref IRCChannel
+
+@ref FAQ
+
+@ref License
+
+ */
+
+/**
+@page SourceDistro Source Distribution
+
+You can retrieve the source to ENet by downloading it in either .tar.gz form
+or accessing the cvs distribution directly.
+
+The most recent stable release (1.3.0) can be downloaded <a href="http://enet.bespin.org/download/enet-1.3.0.tar.gz">here</a>. 
+The last release that is protocol compatible with the 1.2 series or earlier (1.2.2) can be downloaded <a href="http://enet.bespin.org/download/enet-1.2.2.tar.gz">here</a> 
+
+To access ENet via anonymous CVS, you must use the CVSROOT
+:pserver:anonymous\@bespin.org:/var/lib/cvs/enet with an empty
+password.
+
+@code
+	$ cvs -z3 -d :pserver:anonymous@bespin.org:/var/lib/cvs/enet login
+@endcode
+	Hit the return key when prompted for a password.
+@code
+	$ cvs -z3 -d :pserver:anonymous@bespin.org:/var/lib/cvs/enet co -l .
+	$ cvs -z3 co enet
+@endcode
+
+This will create a CVS directory in the current directory, and with
+the second command will proceed to check the enet module out of CVS.
+Any problems with CVS access or request for write access should be
+sent via email to @ref MailingList.
+
+*/
+
+/**
+@page MailingList ENet Mailing List
+
+The <a href="http://lists.cubik.org/mailman/listinfo/enet-discuss">enet-discuss</a> list is for discussion of ENet, including bug reports or feature requests.
+
+*/
+
+/**
+@page IRCChannel ENet IRC Channel
+
+Join the \#enet channel on the freenode IRC network (irc.freenode.net) for real-time discussion about the ENet library.
+
+*/
+
Index: /code/trunk/src/external/enet/docs/tutorial.dox
===================================================================
--- /code/trunk/src/external/enet/docs/tutorial.dox	(revision 7459)
+++ /code/trunk/src/external/enet/docs/tutorial.dox	(revision 7459)
@@ -0,0 +1,357 @@
+/**
+@page Tutorial Tutorial
+
+@ref Initialization
+
+@ref CreateServer
+
+@ref CreateClient
+
+@ref ManageHost
+
+@ref SendingPacket
+
+@ref Disconnecting
+
+@ref Connecting
+
+@section Initialization Initialization
+
+You should include the file <enet/enet.h> when using ENet. Do not
+include <enet.h> without the directory prefix, as this may cause
+file name conflicts on some systems.
+
+Before using ENet, you must call enet_initialize() to initialize the
+library. Upon program exit, you should call enet_deinitialize() so
+that the library may clean up any used resources.
+
+@code
+#include <enet/enet.h>
+
+int 
+main (int argc, char ** argv) 
+{
+    if (enet_initialize () != 0)
+    {
+        fprintf (stderr, "An error occurred while initializing ENet.\n");
+        return EXIT_FAILURE;
+    }
+    atexit (enet_deinitialize);
+    ...
+    ...
+    ...
+}
+@endcode
+        
+@section CreateServer Creating an ENet server
+
+Servers in ENet are constructed with enet_host_create(). You must
+specify an address on which to receive data and new connections, as
+well as the maximum allowable numbers of connected peers. You may
+optionally specify the incoming and outgoing bandwidth of the server
+in bytes per second so that ENet may try to statically manage
+bandwidth resources among connected peers in addition to its dynamic
+throttling algorithm; specifying 0 for these two options will cause
+ENet to rely entirely upon its dynamic throttling algorithm to manage
+bandwidth.
+
+When done with a host, the host may be destroyed with
+enet_host_destroy().  All connected peers to the host will be reset,
+and the resources used by the host will be freed.
+
+@code
+    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);
+    }
+    ...
+    ...
+    ...
+    enet_host_destroy(server);
+@endcode
+
+@section CreateClient Creating an ENet client
+
+Clients in ENet are similarly constructed with enet_host_create() when
+no address is specified to bind the host to. Bandwidth may be
+specified for the client host as in the above example. The peer count
+controls the maximum number of connections to other server hosts that
+may be simultaneously open.
+
+@code
+    ENetHost * client;
+
+    client = enet_host_create (NULL /* create a client host */,
+                1 /* only allow 1 outgoing connection */,
+                2 /* allow up 2 channels to be used, 0 and 1 */,
+                57600 / 8 /* 56K modem with 56 Kbps downstream bandwidth */,
+                14400 / 8 /* 56K modem with 14 Kbps upstream bandwidth */);
+
+    if (client == NULL)
+    {
+        fprintf (stderr, 
+                 "An error occurred while trying to create an ENet client host.\n");
+        exit (EXIT_FAILURE);
+    }
+    ...
+    ...
+    ...
+    enet_host_destroy(client);
+@endcode
+
+@section ManageHost Managing an ENet host
+
+ENet uses a polled event model to notify the programmer of significant
+events. ENet hosts are polled for events with enet_host_service(),
+where an optional timeout value in milliseconds may be specified to
+control how long ENet will poll; if a timeout of 0 is specified,
+enet_host_service() will return immediately if there are no events to
+dispatch. enet_host_service() will return 1 if an event was dispatched
+within the specified timeout.
+
+Currently there are only four types of significant events in ENet:
+
+An event of type ENET_EVENT_TYPE_NONE is returned if no event occurred
+within the specified time limit. enet_host_service() will return 0
+with this event.
+
+An event of type ENET_EVENT_TYPE_CONNECT is returned when either a new client
+host has connected to the server host or when an attempt to establish a 
+connection with a foreign host has succeeded. Only the "peer" field of the 
+event structure is valid for this event and contains the newly connected peer.
+
+An event of type ENET_EVENT_TYPE_RECEIVE is returned when a packet is received
+from a connected peer. The "peer" field contains the peer the packet was 
+received from, "channelID" is the channel on which the packet was sent, and 
+"packet" is the packet that was sent. The packet contained in the "packet" 
+field must be destroyed with enet_packet_destroy() when you are done 
+inspecting its contents.
+
+An event of type ENET_EVENT_TYPE_DISCONNECT is returned when a connected peer
+has either explicitly disconnected or timed out. Only the "peer" field of the
+event structure is valid for this event and contains the peer that 
+disconnected. Only the "data" field of the peer is still valid on a 
+disconnect event and must be explicitly reset.
+
+@code
+    ENetEvent event;
+    
+    /* Wait up to 1000 milliseconds for an event. */
+    while (enet_host_service (client, & event, 1000) > 0)
+    {
+        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 = "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. */
+            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;
+        }
+    }
+    ...
+    ...
+    ...
+@endcode
+
+@section SendingPacket Sending a packet to an ENet peer            
+
+Packets in ENet are created with enet_packet_create(), where the size
+of the packet must be specified. Optionally, initial data may be
+specified to copy into the packet.
+
+Certain flags may also be supplied to enet_packet_create() to control
+various packet features:
+
+ENET_PACKET_FLAG_RELIABLE specifies that the packet must use reliable
+delivery.  A reliable packet is guarenteed to be delivered, and a
+number of retry attempts will be made until an acknowledgement is
+received from the foreign host the packet is sent to. If a certain
+number of retry attempts is reached without any acknowledgement, ENet
+will assume the peer has disconnected and forcefully reset the
+connection. If this flag is not specified, the packet is assumed an
+unreliable packet, and no retry attempts will be made nor
+acknowledgements generated.
+
+A packet may be resized (extended or truncated) with
+enet_packet_resize().
+
+A packet is sent to a foreign host with
+enet_peer_send(). enet_peer_send() accepts a channel id over which to
+send the packet to a given peer. Once the packet is handed over to
+ENet with enet_peer_send(), ENet will handle its deallocation and
+enet_packet_destroy() should not be used upon it.
+
+One may also use enet_host_broadcast() to send a packet to all
+connected peers on a given host over a specified channel id, as with
+enet_peer_send().
+
+Queued packets will be sent on a call to enet_host_service().
+Alternatively, enet_host_flush() will send out queued packets without
+dispatching any events.
+
+@code
+    /* 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 (& 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 (peer, 0, packet);
+    ...
+    ...
+    ...
+    /* One could just use enet_host_service() instead. */
+    enet_host_flush (host);
+@endcode
+
+@section Disconnecting Disconnecting an ENet peer
+
+Peers may be gently disconnected with enet_peer_disconnect(). A
+disconnect request will be sent to the foreign host, and ENet will
+wait for an acknowledgement from the foreign host before finally
+disconnecting. An event of type ENET_EVENT_TYPE_DISCONNECT will be
+generated once the disconnection succeeds. Normally timeouts apply to
+the disconnect acknowledgement, and so if no acknowledgement is
+received after a length of time the peer will be forcefully
+disconnected.
+
+enet_peer_reset() will forcefully disconnect a peer. The foreign host
+will get no notification of a disconnect and will time out on the
+foreign host. No event is generated.
+
+@code
+    ENetEvent event;
+    
+    enet_peer_disconnect (peer, 0);
+
+    /* Allow up to 3 seconds for the disconnect to succeed
+     * and drop any packets received packets.
+     */
+    while (enet_host_service (client, & event, 3000) > 0)
+    {
+        switch (event.type)
+        {
+        case ENET_EVENT_TYPE_RECEIVE:
+            enet_packet_destroy (event.packet);
+            break;
+
+        case ENET_EVENT_TYPE_DISCONNECT:
+            puts ("Disconnection succeeded.");
+            return;
+        ...
+        ...
+        ...
+        }
+    }
+    
+    /* We've arrived here, so the disconnect attempt didn't */
+    /* succeed yet.  Force the connection down.             */
+    enet_peer_reset (peer);
+    ...
+    ...
+    ...
+@endcode
+
+@section Connecting Connecting to an ENet host
+
+A connection to a foreign host is initiated with enet_host_connect().
+It accepts the address of a foreign host to connect to, and the number
+of channels that should be allocated for communication. If N channels
+are allocated for use, their channel ids will be numbered 0 through
+N-1.  A peer representing the connection attempt is returned, or NULL
+if there were no available peers over which to initiate the
+connection. When the connection attempt succeeds, an event of type
+ENET_EVENT_TYPE_CONNECT will be generated. If the connection attempt
+times out or otherwise fails, an event of type
+ENET_EVENT_TYPE_DISCONNECT will be generated.
+
+@code
+    ENetAddress address;
+    ENetEvent event;
+    ENetPeer *peer;
+
+    /* Connect to some.server.net:1234. */
+    enet_address_set_host (& address, "some.server.net");
+    address.port = 1234;
+
+    /* Initiate the connection, allocating the two channels 0 and 1. */
+    peer = enet_host_connect (client, & address, 2, 0);    
+    
+    if (peer == 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 some.server.net:1234 succeeded.");
+        ...
+        ...
+        ...
+    }
+    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 (peer);
+
+        puts ("Connection to some.server.net:1234 failed.");
+    }
+    ...
+    ...
+    ...
+@endcode
+*/
Index: /code/trunk/src/external/enet/enet.h
===================================================================
--- /code/trunk/src/external/enet/enet.h	(revision 7459)
+++ /code/trunk/src/external/enet/enet.h	(revision 7459)
@@ -0,0 +1,576 @@
+/** 
+ @file  enet.h
+ @brief ENet public header file
+*/
+#ifndef __ENET_ENET_H__
+#define __ENET_ENET_H__
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <stdlib.h>
+
+#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 0
+#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;
+
+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
+} ENetSocketOption;
+
+typedef struct _ENetHostAddress
+{
+   enet_uint8 addr[16];
+} ENetHostAddress;
+
+#define ENET_HOST_ANY_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }                         /**< specifies the default server host (macro for variable initialization) */
+static const ENetHostAddress ENET_HOST_ANY = ENET_HOST_ANY_INIT;                           /**< specifies the default server host (global constant variable) */
+#define ENET_IPV4MAPPED_PREFIX_INIT { { 0,0,0,0,0,0,0,0,0,0,0xff,0xff,0,0,0,0 } }          /**< specifies the IPv4-mapped IPv6 prefix (macro for variable initialization) */
+static const ENetHostAddress ENET_IPV4MAPPED_PREFIX = ENET_IPV4MAPPED_PREFIX_INIT;         /**< specifies the IPv4-mapped IPv6 prefix (global constant variable) */
+#define ENET_HOST_BROADCAST_INIT { { 0,0,0,0,0,0,0,0,0,0,0xff,0xff,0xff,0xff,0xff,0xff } } /**< specifies a IPv4 subnet-wide broadcast (macro for variable initialization) */
+static const ENetHostAddress ENET_HOST_BROADCAST = ENET_HOST_BROADCAST_INIT;               /**< specifies a IPv4 subnet-wide broadcast (global constant variable) */
+enum {
+    ENET_IPV4MAPPED_PREFIX_LEN = 12,                                                       /**< specifies the length of the IPv4-mapped IPv6 prefix */
+    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
+{
+   ENetHostAddress host;
+#ifdef WIN32
+   u_long scopeID;
+#else
+   uint32_t scopeID;
+#endif
+   enet_uint16 port;
+} ENetAddress;
+
+/**
+ * The address family type.
+ */
+typedef enum _ENetAddressFamily
+{
+    ENET_NO_ADDRESS_FAMILY = 0,
+    ENET_IPV4 = (1 << 0),
+    ENET_IPV6 = (1 << 1)
+} ENetAddressFamily;
+
+/**
+ * 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)
+} ENetPacketFlag;
+
+struct _ENetPacket;
+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 */
+} 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;
+   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   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);
+ 
+/** 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           socket4;
+   ENetSocket           socket6;
+   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 */
+} 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, ENetAddressFamily);
+ENET_API int        enet_socket_bind (ENetSocket, const ENetAddress *, ENetAddressFamily);
+ENET_API int        enet_socket_listen (ENetSocket, int);
+ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *, ENetAddressFamily);
+ENET_API int        enet_socket_connect (ENetSocket, const ENetAddress *, ENetAddressFamily);
+ENET_API int        enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t, ENetAddressFamily);
+ENET_API int        enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t, ENetAddressFamily);
+ENET_API int        enet_socket_wait (ENetSocket, ENetSocket, enet_uint32 *, enet_uint32);
+ENET_API int        enet_socket_set_option (ENetSocket, ENetSocketOption, int);
+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);
+
+/** Maps an IPv4 Address to an IPv6 address.
+    @param address IPv4 address in network byte order
+    @returns the IPv4-mapped IPv6 address in network byte order
+*/
+ENET_API ENetHostAddress enet_address_map4 (enet_uint32 address);
+
+/** Returns the Address family of an (IPv4-mapped) IPv6 address.
+    @param address IPv6 address
+    @returns address family
+*/
+ENET_API ENetAddressFamily enet_get_address_family (const ENetAddress * address);
+
+/** @} */
+
+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);
+extern 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_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__ */
+
Index: /code/trunk/src/external/enet/host.c
===================================================================
--- /code/trunk/src/external/enet/host.c	(revision 7459)
+++ /code/trunk/src/external/enet/host.c	(revision 7459)
@@ -0,0 +1,508 @@
+/** 
+ @file host.c
+ @brief ENet host management functions
+*/
+#define ENET_BUILDING_LIB 1
+#include <string.h>
+#include <time.h>
+#include "enet/enet.h"
+
+static ENetSocket
+enet_socket_create_bind (const ENetAddress * address, ENetAddressFamily family)
+{
+    ENetSocket socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM, family);
+    if (socket == ENET_SOCKET_NULL)
+        return ENET_SOCKET_NULL;
+
+    /* This is not a conditional bind anymore,
+     * because WSARecvFrom returned WSAEINVAL on the IPv6 socket.
+     * TODO: Check for it's consequences. */
+    if (enet_socket_bind (socket, address, family) < 0)
+    {
+        enet_socket_destroy (socket);
+        return ENET_SOCKET_NULL;
+    }
+
+    enet_socket_set_option (socket, ENET_SOCKOPT_NONBLOCK, 1);
+    enet_socket_set_option (socket, ENET_SOCKOPT_BROADCAST, 1);
+    enet_socket_set_option (socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE);
+    enet_socket_set_option (socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE);
+
+    return socket;
+}
+
+/** @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;
+    int family;
+
+    if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID)
+      return NULL;
+
+    host = (ENetHost *) enet_malloc (sizeof (ENetHost));
+    if (host == NULL)
+      return NULL;
+
+    host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer));
+    if (host -> peers == NULL)
+    {
+       enet_free (host);
+
+       return NULL;
+    }
+    memset (host -> peers, 0, peerCount * sizeof (ENetPeer));
+
+    family = (address == NULL || !memcmp (& address -> host, & ENET_HOST_ANY, sizeof (ENetHostAddress))) ?
+        ENET_IPV4 | ENET_IPV6 :
+        enet_get_address_family (address);
+
+    host -> socket4 = (family & ENET_IPV4) ?
+      enet_socket_create_bind (address, ENET_IPV4) :
+      ENET_SOCKET_NULL;
+    host -> socket6 = (family & ENET_IPV6) ?
+      enet_socket_create_bind (address, ENET_IPV6) :
+      ENET_SOCKET_NULL;
+
+    if (host -> socket4 == ENET_SOCKET_NULL && host -> socket6 == ENET_SOCKET_NULL)
+    {
+        enet_free (host -> peers);
+        enet_free (host);
+        return NULL;
+    }
+
+    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) time(NULL) + (enet_uint32) (size_t) host;
+    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;
+
+    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 -> socket4 != ENET_SOCKET_NULL)
+      enet_socket_destroy (host -> socket4);
+    if (host -> socket6 != ENET_SOCKET_NULL)
+      enet_socket_destroy (host -> socket6);
+
+    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;
+
+        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;
+    }
+}
+    
+/** @} */
Index: /code/trunk/src/external/enet/libenet.pc.in
===================================================================
--- /code/trunk/src/external/enet/libenet.pc.in	(revision 7459)
+++ /code/trunk/src/external/enet/libenet.pc.in	(revision 7459)
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE_NAME@
+Description: Low-latency UDP networking library supporting optional reliability
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -lenet
Index: /code/trunk/src/external/enet/list.c
===================================================================
--- /code/trunk/src/external/enet/list.c	(revision 7459)
+++ /code/trunk/src/external/enet/list.c	(revision 7459)
@@ -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;
+}
+
+/** @} */
Index: /code/trunk/src/external/enet/list.h
===================================================================
--- /code/trunk/src/external/enet/list.h	(revision 7459)
+++ /code/trunk/src/external/enet/list.h	(revision 7459)
@@ -0,0 +1,43 @@
+/** 
+ @file  list.h
+ @brief ENet list management 
+*/
+#ifndef __ENET_LIST_H__
+#define __ENET_LIST_H__
+
+#include <stdlib.h>
+
+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__ */
+
Index: /code/trunk/src/external/enet/packet.c
===================================================================
--- /code/trunk/src/external/enet/packet.c	(revision 7459)
+++ /code/trunk/src/external/enet/packet.c	(revision 7459)
@@ -0,0 +1,157 @@
+/** 
+ @file  packet.c
+ @brief ENet packet management functions
+*/
+#include <string.h>
+#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
+    {
+       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;
+
+    return packet;
+}
+
+/** Destroys the packet and deallocates its data.
+    @param packet packet to be destroyed
+*/
+void
+enet_packet_destroy (ENetPacket * packet)
+{
+    if (packet -> freeCallback != NULL)
+      (* packet -> freeCallback) (packet);
+    if (! (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE))
+      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 ()
+{
+    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);
+}
+
+/** @} */
Index: /code/trunk/src/external/enet/patches/0001-IPv6-support.patch
===================================================================
--- /code/trunk/src/external/enet/patches/0001-IPv6-support.patch	(revision 7459)
+++ /code/trunk/src/external/enet/patches/0001-IPv6-support.patch	(revision 7459)
@@ -0,0 +1,1279 @@
+From 68e3ac1c2876aedb62a77fdc7ba71e4983a6b99d Mon Sep 17 00:00:00 2001
+From: Adrian Friedli <adi@koalatux.ch>
+Date: Thu, 2 Sep 2010 14:26:42 +0200
+Subject: [PATCH] IPv6 support
+
+---
+ host.c               |   57 +++++++---
+ include/enet/enet.h  |   64 ++++++++---
+ include/enet/win32.h |    5 +
+ protocol.c           |   73 ++++++++++--
+ unix.c               |  312 ++++++++++++++++++++++++++++++--------------------
+ win32.c              |  245 ++++++++++++++++++++++++++--------------
+ 6 files changed, 506 insertions(+), 250 deletions(-)
+
+diff --git a/host.c b/host.c
+index 8bb2433..a9d157b 100644
+--- a/host.c
++++ b/host.c
+@@ -7,6 +7,30 @@
+ #include <time.h>
+ #include "enet/enet.h"
+ 
++static ENetSocket
++enet_socket_create_bind (const ENetAddress * address, ENetAddressFamily family)
++{
++    ENetSocket socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM, family);
++    if (socket == ENET_SOCKET_NULL)
++        return ENET_SOCKET_NULL;
++
++    /* This is not a conditional bind anymore,
++     * because WSARecvFrom returned WSAEINVAL on the IPv6 socket.
++     * TODO: Check for it's consequences. */
++    if (enet_socket_bind (socket, address, family) < 0)
++    {
++        enet_socket_destroy (socket);
++        return ENET_SOCKET_NULL;
++    }
++
++    enet_socket_set_option (socket, ENET_SOCKOPT_NONBLOCK, 1);
++    enet_socket_set_option (socket, ENET_SOCKOPT_BROADCAST, 1);
++    enet_socket_set_option (socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE);
++    enet_socket_set_option (socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE);
++
++    return socket;
++}
++
+ /** @defgroup host ENet host functions
+     @{
+ */
+@@ -31,6 +55,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
+ {
+     ENetHost * host;
+     ENetPeer * currentPeer;
++    int family;
+ 
+     if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID)
+       return NULL;
+@@ -48,23 +73,24 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
+     }
+     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);
++    family = (address == NULL || !memcmp (& address -> host, & ENET_HOST_ANY, sizeof (ENetHostAddress))) ?
++        ENET_IPV4 | ENET_IPV6 :
++        enet_get_address_family (address);
+ 
+-       enet_free (host -> peers);
+-       enet_free (host);
++    host -> socket4 = (family & ENET_IPV4) ?
++      enet_socket_create_bind (address, ENET_IPV4) :
++      ENET_SOCKET_NULL;
++    host -> socket6 = (family & ENET_IPV6) ?
++      enet_socket_create_bind (address, ENET_IPV6) :
++      ENET_SOCKET_NULL;
+ 
+-       return NULL;
++    if (host -> socket4 == ENET_SOCKET_NULL && host -> socket6 == ENET_SOCKET_NULL)
++    {
++        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;
+ 
+@@ -133,7 +159,10 @@ enet_host_destroy (ENetHost * host)
+ {
+     ENetPeer * currentPeer;
+ 
+-    enet_socket_destroy (host -> socket);
++    if (host -> socket4 != ENET_SOCKET_NULL)
++      enet_socket_destroy (host -> socket4);
++    if (host -> socket6 != ENET_SOCKET_NULL)
++      enet_socket_destroy (host -> socket6);
+ 
+     for (currentPeer = host -> peers;
+          currentPeer < & host -> peers [host -> peerCount];
+diff --git a/include/enet/enet.h b/include/enet/enet.h
+index 2f656d6..7b468a0 100644
+--- a/include/enet/enet.h
++++ b/include/enet/enet.h
+@@ -53,12 +53,20 @@ typedef enum _ENetSocketOption
+    ENET_SOCKOPT_REUSEADDR = 5
+ } ENetSocketOption;
+ 
+-enum
++typedef struct _ENetHostAddress
+ {
+-   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 */
++   enet_uint8 addr[16];
++} ENetHostAddress;
++
++#define ENET_HOST_ANY_INIT { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }                         /**< specifies the default server host (macro for variable initialization) */
++static const ENetHostAddress ENET_HOST_ANY = ENET_HOST_ANY_INIT;                           /**< specifies the default server host (global constant variable) */
++#define ENET_IPV4MAPPED_PREFIX_INIT { { 0,0,0,0,0,0,0,0,0,0,0xff,0xff,0,0,0,0 } }          /**< specifies the IPv4-mapped IPv6 prefix (macro for variable initialization) */
++static const ENetHostAddress ENET_IPV4MAPPED_PREFIX = ENET_IPV4MAPPED_PREFIX_INIT;         /**< specifies the IPv4-mapped IPv6 prefix (global constant variable) */
++#define ENET_HOST_BROADCAST_INIT { { 0,0,0,0,0,0,0,0,0,0,0xff,0xff,0xff,0xff,0xff,0xff } } /**< specifies a IPv4 subnet-wide broadcast (macro for variable initialization) */
++static const ENetHostAddress ENET_HOST_BROADCAST = ENET_HOST_BROADCAST_INIT;               /**< specifies a IPv4 subnet-wide broadcast (global constant variable) */
++enum {
++    ENET_IPV4MAPPED_PREFIX_LEN = 12,                                                       /**< specifies the length of the IPv4-mapped IPv6 prefix */
++    ENET_PORT_ANY              = 0                                                         /**< specifies that a port should be automatically chosen */
+ };
+ 
+ /**
+@@ -73,11 +81,26 @@ enum
+  */
+ typedef struct _ENetAddress
+ {
+-   enet_uint32 host;
++   ENetHostAddress host;
++#ifdef WIN32
++   u_long scopeID;
++#else
++   uint32_t scopeID;
++#endif
+    enet_uint16 port;
+ } ENetAddress;
+ 
+ /**
++ * The address family type.
++ */
++typedef enum _ENetAddressFamily
++{
++    ENET_NO_ADDRESS_FAMILY = 0,
++    ENET_IPV4 = (1 << 0),
++    ENET_IPV6 = (1 << 1)
++} ENetAddressFamily;
++
++/**
+  * Packet flag bit constants.
+  *
+  * The host must be specified in network byte-order, and the port must be in
+@@ -321,7 +344,8 @@ typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * b
+   */
+ typedef struct _ENetHost
+ {
+-   ENetSocket           socket;
++   ENetSocket           socket4;
++   ENetSocket           socket6;
+    ENetAddress          address;                     /**< Internet address of the host */
+    enet_uint32          incomingBandwidth;           /**< downstream bandwidth of the host */
+    enet_uint32          outgoingBandwidth;           /**< upstream bandwidth of the host */
+@@ -441,14 +465,14 @@ 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 ENetSocket enet_socket_create (ENetSocketType, ENetAddressFamily);
++ENET_API int        enet_socket_bind (ENetSocket, const ENetAddress *, ENetAddressFamily);
+ 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 ENetSocket enet_socket_accept (ENetSocket, ENetAddress *, ENetAddressFamily);
++ENET_API int        enet_socket_connect (ENetSocket, const ENetAddress *, ENetAddressFamily);
++ENET_API int        enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t, ENetAddressFamily);
++ENET_API int        enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t, ENetAddressFamily);
++ENET_API int        enet_socket_wait (ENetSocket, ENetSocket, enet_uint32 *, enet_uint32);
+ ENET_API int        enet_socket_set_option (ENetSocket, ENetSocketOption, int);
+ ENET_API void       enet_socket_destroy (ENetSocket);
+ ENET_API int        enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32);
+@@ -488,6 +512,18 @@ ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostN
+ */
+ ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength);
+ 
++/** Maps an IPv4 Address to an IPv6 address.
++    @param address IPv4 address in network byte order
++    @returns the IPv4-mapped IPv6 address in network byte order
++*/
++ENET_API ENetHostAddress enet_address_map4 (enet_uint32 address);
++
++/** Returns the Address family of an (IPv4-mapped) IPv6 address.
++    @param address IPv6 address
++    @returns address family
++*/
++ENET_API ENetAddressFamily enet_get_address_family (const ENetAddress * address);
++
+ /** @} */
+ 
+ ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32);
+diff --git a/include/enet/win32.h b/include/enet/win32.h
+index 0e1cf0c..53a7ff7 100644
+--- a/include/enet/win32.h
++++ b/include/enet/win32.h
+@@ -14,6 +14,7 @@
+ 
+ #include <stdlib.h>
+ #include <winsock2.h>
++#include <ws2tcpip.h>
+ 
+ typedef SOCKET ENetSocket;
+ 
+@@ -53,6 +54,10 @@ typedef fd_set ENetSocketSet;
+ #define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLEAR (socket, & (sockset))
+ #define ENET_SOCKETSET_CHECK(sockset, socket)  FD_ISSET (socket, & (sockset))
+ 
++#ifndef AI_ADDRCONFIG
++#define AI_ADDRCONFIG 0x0400 /* AI_ADDRCONFIG is not defined everywhere */
++#endif
++
+ #endif /* __ENET_WIN32_H__ */
+ 
+ 
+diff --git a/protocol.c b/protocol.c
+index 8e26dfb..cfef646 100644
+--- a/protocol.c
++++ b/protocol.c
+@@ -25,6 +25,22 @@ static size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] =
+     sizeof (ENetProtocolThrottleConfigure),
+ };
+ 
++ENetHostAddress
++enet_address_map4 (enet_uint32 address)
++{
++    ENetHostAddress addr = ENET_IPV4MAPPED_PREFIX_INIT;
++    ((enet_uint32 *)addr.addr)[3] = address;
++    return addr;
++}
++
++ENetAddressFamily
++enet_get_address_family (const ENetAddress * address)
++{
++    if (!memcmp(& address->host, & ENET_IPV4MAPPED_PREFIX, ENET_IPV4MAPPED_PREFIX_LEN))
++        return ENET_IPV4;
++    return ENET_IPV6;
++}
++
+ size_t
+ enet_protocol_command_size (enet_uint8 commandNumber)
+ {
+@@ -262,9 +278,9 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
+          ++ 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)
++            currentPeer -> connectID == command -> connect.connectID &&
++            !memcmp(& currentPeer -> address.host, & host -> receivedAddress.host, sizeof (ENetHostAddress)))
+           return NULL;
+     }
+ 
+@@ -848,10 +864,11 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
+ 
+        if (peer -> state == ENET_PEER_STATE_DISCONNECTED ||
+            peer -> state == ENET_PEER_STATE_ZOMBIE ||
+-           (host -> receivedAddress.host != peer -> address.host &&
+-             peer -> address.host != ENET_HOST_BROADCAST) ||
+            (peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID &&
+-            sessionID != peer -> incomingSessionID))
++            sessionID != peer -> incomingSessionID) ||
++           ( memcmp(& peer -> address.host, & host -> receivedAddress.host, sizeof (ENetHostAddress)) &&
++             memcmp(& peer -> address.host, & ENET_HOST_BROADCAST, sizeof (ENetHostAddress)) &&
++             peer -> address.host.addr[0] != 0xff ) )
+          return 0;
+     }
+  
+@@ -891,8 +908,7 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
+        
+     if (peer != NULL)
+     {
+-       peer -> address.host = host -> receivedAddress.host;
+-       peer -> address.port = host -> receivedAddress.port;
++       peer -> address = host -> receivedAddress;
+        peer -> incomingDataTotal += host -> receivedDataLength;
+     }
+     
+@@ -1021,7 +1037,7 @@ commandError:
+ }
+  
+ static int
+-enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event)
++enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event, ENetAddressFamily family)
+ {
+     for (;;)
+     {
+@@ -1031,10 +1047,11 @@ enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event)
+        buffer.data = host -> packetData [0];
+        buffer.dataLength = sizeof (host -> packetData [0]);
+ 
+-       receivedLength = enet_socket_receive (host -> socket,
++       receivedLength = enet_socket_receive (family == ENET_IPV4 ? host -> socket4 : host -> socket6,
+                                              & host -> receivedAddress,
+                                              & buffer,
+-                                             1);
++                                             1,
++                                             family);
+ 
+        if (receivedLength < 0)
+          return -1;
+@@ -1042,6 +1059,9 @@ enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event)
+        if (receivedLength == 0)
+          return 0;
+ 
++       if (enet_get_address_family (& host -> receivedAddress) != family)
++         return -1;
++
+        host -> receivedData = host -> packetData [0];
+        host -> receivedDataLength = receivedLength;
+       
+@@ -1373,6 +1393,9 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
+          currentPeer < & host -> peers [host -> peerCount];
+          ++ currentPeer)
+     {
++        ENetAddressFamily family;
++        ENetSocket socket;
++
+         if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED ||
+             currentPeer -> state == ENET_PEER_STATE_ZOMBIE)
+           continue;
+@@ -1497,7 +1520,15 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
+ 
+         currentPeer -> lastSendTime = host -> serviceTime;
+ 
+-        sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount);
++        family = enet_get_address_family (& currentPeer -> address);
++        socket = family == ENET_IPV4 ? host -> socket4 : host -> socket6;
++        if (socket == ENET_SOCKET_NULL)
++          return -1;
++        sentLength = enet_socket_send (socket,
++                                           & currentPeer -> address,
++                                           host -> buffers,
++                                           host -> bufferCount,
++                                           family);
+ 
+         enet_protocol_remove_sent_unreliable_commands (currentPeer);
+ 
+@@ -1608,7 +1639,23 @@ enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout)
+           break;
+        }
+ 
+-       switch (enet_protocol_receive_incoming_commands (host, event))
++       if (host -> socket4 != ENET_SOCKET_NULL)
++         switch (enet_protocol_receive_incoming_commands (host, event, ENET_IPV4))
++       {
++       case 1:
++          return 1;
++
++       case -1:
++          perror ("Error receiving incoming packets");
++
++          return -1;
++
++       default:
++          break;
++       }
++
++       if (host -> socket6 != ENET_SOCKET_NULL)
++         switch (enet_protocol_receive_incoming_commands (host, event, ENET_IPV6))
+        {
+        case 1:
+           return 1;
+@@ -1660,7 +1707,7 @@ enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout)
+ 
+        waitCondition = ENET_SOCKET_WAIT_RECEIVE;
+ 
+-       if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0)
++       if (enet_socket_wait (host -> socket4, host -> socket6, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0)
+          return -1;
+        
+        host -> serviceTime = enet_time_get ();
+diff --git a/unix.c b/unix.c
+index 6971541..992ecd3 100644
+--- a/unix.c
++++ b/unix.c
+@@ -71,122 +71,161 @@ enet_time_set (enet_uint32 newTimeBase)
+     timeBase = timeVal.tv_sec * 1000 + timeVal.tv_usec / 1000 - newTimeBase;
+ }
+ 
+-int
+-enet_address_set_host (ENetAddress * address, const char * name)
++static enet_uint16
++enet_af (ENetAddressFamily family)
+ {
+-    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 (family == ENET_IPV4)
++        return AF_INET;
++    if (family == ENET_IPV6)
++        return AF_INET6;
++    return 0;
++}
++
++static socklen_t
++enet_sa_size (ENetAddressFamily family)
++{
++    if (family == ENET_IPV4)
++        return sizeof (struct sockaddr_in);
++    if (family == ENET_IPV6)
++        return sizeof (struct sockaddr_in6);
++    return 0;
++}
+ 
+-    if (hostEntry == NULL ||
+-        hostEntry -> h_addrtype != AF_INET)
++static ENetAddressFamily
++enet_address_set_address (ENetAddress * address, const struct sockaddr * sin)
++{
++    memset (address, 0, sizeof (ENetAddress));
++    if (sin -> sa_family == 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_address_map4 ((((struct sockaddr_in *) sin) -> sin_addr.s_addr));
++        /* address -> scopeID = 0; */
++        address -> port = ENET_NET_TO_HOST_16 (((struct sockaddr_in *) sin) -> sin_port);
++        return ENET_IPV4;
+     }
+-
+-    address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
+-
+-    return 0;
++    if (sin -> sa_family == AF_INET6)
++    {
++        address -> host = * (ENetHostAddress *) & ((struct sockaddr_in6 *) sin) -> sin6_addr;
++        address -> scopeID = ((struct sockaddr_in6 *) sin) -> sin6_scope_id;
++        address -> port = ENET_NET_TO_HOST_16 (((struct sockaddr_in6 *) sin) -> sin6_port);
++        return ENET_IPV6;
++    }
++    return ENET_NO_ADDRESS_FAMILY;
+ }
+ 
+-int
+-enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
++static int
++enet_address_set_sin (struct sockaddr * sin, const ENetAddress * address, ENetAddressFamily family)
+ {
+-#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;
++    memset (sin, 0, enet_sa_size(family));
++    if (family == ENET_IPV4 &&
++      (enet_get_address_family (address) == ENET_IPV4 ||
++      !memcmp (& address -> host, & ENET_HOST_ANY, sizeof(ENetHostAddress))))
++    {
++        ((struct sockaddr_in *) sin) -> sin_family = AF_INET;
++        ((struct sockaddr_in *) sin) -> sin_addr = * (struct in_addr *) & address -> host.addr[12];
++        ((struct sockaddr_in *) sin) -> sin_port = ENET_HOST_TO_NET_16 (address -> port);
++        return 0;
++    }
++    else if (family == ENET_IPV6)
++    {
++        ((struct sockaddr_in6 *) sin) -> sin6_family = AF_INET6;
++        ((struct sockaddr_in6 *) sin) -> sin6_addr = * (struct in6_addr *) & address -> host;
++        ((struct sockaddr_in6 *) sin) -> sin6_scope_id = address -> scopeID;
++        ((struct sockaddr_in6 *) sin) -> sin6_port = ENET_HOST_TO_NET_16 (address -> port);
++        return 0;
++    }
++    return -1;
+ }
+ 
+ int
+-enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
++enet_address_set_host (ENetAddress * address, const char * name)
+ {
+-    struct in_addr in;
+-    struct hostent * hostEntry = NULL;
+-#ifdef HAS_GETHOSTBYADDR_R
+-    struct hostent hostData;
+-    char buffer [2048];
+-    int errnum;
++    enet_uint16 port = address -> port;
++    struct addrinfo hints;
++    struct addrinfo * result;
++    struct addrinfo * res;
+ 
+-    in.s_addr = address -> host;
++    memset(& hints, 0, sizeof (hints));
++    hints.ai_flags = AI_ADDRCONFIG;
++    hints.ai_family = AF_UNSPEC;
+ 
+-#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;
++    if ( getaddrinfo(name, NULL, &hints, &result) )
++        return -1;
+ 
+-    hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET);
+-#endif
++    for (res = result; res != NULL; res = res -> ai_next)
++    {
++        if ( enet_address_set_address(address, res -> ai_addr) != ENET_NO_ADDRESS_FAMILY )
++            break;
++    }
+ 
+-    if (hostEntry == NULL)
+-      return enet_address_get_host_ip (address, name, nameLength);
++    address -> port = port;
++    freeaddrinfo(result);
++    if (res == NULL) return -1;
+ 
+-    strncpy (name, hostEntry -> h_name, nameLength);
++    return 0;
++}
++
++static int
++enet_address_get_host_x (const ENetAddress * address, char * name, size_t nameLength, int flags)
++{
++    struct sockaddr_storage sin;
++    enet_address_set_sin((struct sockaddr *) & sin, address, ENET_IPV6);
++
++    if ( getnameinfo((struct sockaddr *) & sin, enet_sa_size (ENET_IPV6), name, nameLength, NULL, 0, flags))
++        return -1;
+ 
+     return 0;
+ }
+ 
+ int
+-enet_socket_bind (ENetSocket socket, const ENetAddress * address)
++enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
+ {
+-    struct sockaddr_in sin;
++    return enet_address_get_host_x(address, name, nameLength, NI_NUMERICHOST);
++}
+ 
+-    memset (& sin, 0, sizeof (struct sockaddr_in));
++int
++enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
++{
++    return enet_address_get_host_x(address, name, nameLength, 0);
++}
+ 
+-    sin.sin_family = AF_INET;
++int
++enet_socket_bind (ENetSocket socket, const ENetAddress * address, ENetAddressFamily family)
++{
++    struct sockaddr_storage sin;
+ 
+     if (address != NULL)
+     {
+-       sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+-       sin.sin_addr.s_addr = address -> host;
++        enet_address_set_sin((struct sockaddr *) & sin, address, family);
+     }
+     else
+     {
+-       sin.sin_port = 0;
+-       sin.sin_addr.s_addr = INADDR_ANY;
++        ENetAddress address_ = { ENET_HOST_ANY_INIT, 0, 0 };
++        enet_address_set_sin((struct sockaddr *) & sin, & address_, family);
+     }
+ 
+-    return bind (socket,
+-                 (struct sockaddr *) & sin,
+-                 sizeof (struct sockaddr_in)); 
++    return bind (socket, (struct sockaddr *) & sin, enet_sa_size(family));
+ }
+ 
+-int 
++int
+ enet_socket_listen (ENetSocket socket, int backlog)
+ {
+     return listen (socket, backlog < 0 ? SOMAXCONN : backlog);
+ }
+ 
+ ENetSocket
+-enet_socket_create (ENetSocketType type)
++enet_socket_create (ENetSocketType type, ENetAddressFamily family)
+ {
+-    return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
++    ENetSocket sock = socket (enet_af (family), type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
++
++#ifdef IPV6_V6ONLY
++    if (family == ENET_IPV6)
++    {
++        int value = 1;
++        setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, & value, sizeof (int));
++    }
++#endif /* IPV6_V6ONLY */
++
++    return sock;
+ }
+ 
+ int
+@@ -226,42 +265,36 @@ enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
+ }
+ 
+ int
+-enet_socket_connect (ENetSocket socket, const ENetAddress * address)
++enet_socket_connect (ENetSocket socket, const ENetAddress * address, ENetAddressFamily family)
+ {
+-    struct sockaddr_in sin;
+-
+-    memset (& sin, 0, sizeof (struct sockaddr_in));
++    struct sockaddr_storage sin;
++    enet_address_set_sin((struct sockaddr *) & sin, address, family);
+ 
+-    sin.sin_family = AF_INET;
+-    sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+-    sin.sin_addr.s_addr = address -> host;
+-
+-    return connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
++    return connect (socket, (struct sockaddr *) & sin, enet_sa_size (family));
+ }
+ 
+ ENetSocket
+-enet_socket_accept (ENetSocket socket, ENetAddress * address)
++enet_socket_accept (ENetSocket socket, ENetAddress * address, ENetAddressFamily family)
+ {
+     int result;
+-    struct sockaddr_in sin;
+-    socklen_t sinLength = sizeof (struct sockaddr_in);
++    struct sockaddr_storage sin;
++    socklen_t sinLength = enet_sa_size (family);
+ 
+     result = accept (socket, 
+-                     address != NULL ? (struct sockaddr *) & sin : NULL, 
++                     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);
++        enet_address_set_address(address, (struct sockaddr *) & sin);
+     }
+ 
+     return result;
+-} 
+-    
++}
++
+ void
+ enet_socket_destroy (ENetSocket socket)
+ {
+@@ -272,24 +305,20 @@ int
+ enet_socket_send (ENetSocket socket,
+                   const ENetAddress * address,
+                   const ENetBuffer * buffers,
+-                  size_t bufferCount)
++                  size_t bufferCount,
++                  ENetAddressFamily family)
+ {
+     struct msghdr msgHdr;
+-    struct sockaddr_in sin;
++    struct sockaddr_storage 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;
+-
++        enet_address_set_sin((struct sockaddr *) & sin, address, family);
+         msgHdr.msg_name = & sin;
+-        msgHdr.msg_namelen = sizeof (struct sockaddr_in);
++        msgHdr.msg_namelen = enet_sa_size (family);
+     }
+ 
+     msgHdr.msg_iov = (struct iovec *) buffers;
+@@ -312,10 +341,11 @@ int
+ enet_socket_receive (ENetSocket socket,
+                      ENetAddress * address,
+                      ENetBuffer * buffers,
+-                     size_t bufferCount)
++                     size_t bufferCount,
++                     ENetAddressFamily family)
+ {
+     struct msghdr msgHdr;
+-    struct sockaddr_in sin;
++    struct sockaddr_storage sin;
+     int recvLength;
+ 
+     memset (& msgHdr, 0, sizeof (struct msghdr));
+@@ -323,7 +353,7 @@ enet_socket_receive (ENetSocket socket,
+     if (address != NULL)
+     {
+         msgHdr.msg_name = & sin;
+-        msgHdr.msg_namelen = sizeof (struct sockaddr_in);
++        msgHdr.msg_namelen = enet_sa_size (family);
+     }
+ 
+     msgHdr.msg_iov = (struct iovec *) buffers;
+@@ -346,8 +376,7 @@ enet_socket_receive (ENetSocket socket,
+ 
+     if (address != NULL)
+     {
+-        address -> host = (enet_uint32) sin.sin_addr.s_addr;
+-        address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
++        enet_address_set_address(address, (struct sockaddr *) & sin);
+     }
+ 
+     return recvLength;
+@@ -365,22 +394,38 @@ enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocket
+ }
+ 
+ int
+-enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout)
++enet_socket_wait (ENetSocket socket4, ENetSocket socket6, enet_uint32 * condition, enet_uint32 timeout)
+ {
+ #ifdef HAS_POLL
+-    struct pollfd pollSocket;
++    struct pollfd pollSocket[2];
+     int pollCount;
+-    
+-    pollSocket.fd = socket;
+-    pollSocket.events = 0;
++
++    pollSocket[0].fd = socket4;
++    pollSocket[1].fd = socket6;
++    pollSocket[0].events = 0;
++    pollSocket[1].events = 0;
++    /* pollSocket[0].revents = 0; */
++    pollSocket[1].revents = 0;
++
++    if (pollSocket[0].fd == ENET_SOCKET_NULL)
++    {
++        pollSocket[0].fd = pollSocket[1].fd;
++        pollSocket[1].fd = ENET_SOCKET_NULL;
++    }
+ 
+     if (* condition & ENET_SOCKET_WAIT_SEND)
+-      pollSocket.events |= POLLOUT;
++    {
++        pollSocket[0].events |= POLLOUT;
++        pollSocket[1].events |= POLLOUT;
++    }
+ 
+     if (* condition & ENET_SOCKET_WAIT_RECEIVE)
+-      pollSocket.events |= POLLIN;
++    {
++        pollSocket[0].events |= POLLIN;
++        pollSocket[1].events |= POLLIN;
++    }
+ 
+-    pollCount = poll (& pollSocket, 1, timeout);
++    pollCount = poll (pollSocket, pollSocket[1].fd != ENET_SOCKET_NULL ? 2 : 1, timeout);
+ 
+     if (pollCount < 0)
+       return -1;
+@@ -390,10 +435,10 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou
+     if (pollCount == 0)
+       return 0;
+ 
+-    if (pollSocket.revents & POLLOUT)
++    if ((pollSocket[0].revents | pollSocket[1].revents) & POLLOUT)
+       * condition |= ENET_SOCKET_WAIT_SEND;
+     
+-    if (pollSocket.revents & POLLIN)
++    if ((pollSocket[0].revents | pollSocket[1].revents) & POLLIN)
+       * condition |= ENET_SOCKET_WAIT_RECEIVE;
+ 
+     return 0;
+@@ -401,6 +446,7 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou
+     fd_set readSet, writeSet;
+     struct timeval timeVal;
+     int selectCount;
++    ENetSocket maxSocket;
+ 
+     timeVal.tv_sec = timeout / 1000;
+     timeVal.tv_usec = (timeout % 1000) * 1000;
+@@ -409,12 +455,28 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou
+     FD_ZERO (& writeSet);
+ 
+     if (* condition & ENET_SOCKET_WAIT_SEND)
+-      FD_SET (socket, & writeSet);
++    {
++        if (socket4 != ENET_SOCKET_NULL)
++            FD_SET (socket4, & writeSet);
++        if (socket6 != ENET_SOCKET_NULL)
++            FD_SET (socket6, & writeSet);
++    }
+ 
+     if (* condition & ENET_SOCKET_WAIT_RECEIVE)
+-      FD_SET (socket, & readSet);
++    {
++        if (socket4 != ENET_SOCKET_NULL)
++            FD_SET (socket4, & readSet);
++        if (socket6 != ENET_SOCKET_NULL)
++            FD_SET (socket6, & readSet);
++    }
++
++    maxSocket = 0;
++    if (socket4 != ENET_SOCKET_NULL)
++        maxSocket = socket4;
++    if (socket6 != ENET_SOCKET_NULL && socket6 > maxSocket)
++        maxSocket = socket6;
+ 
+-    selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal);
++    selectCount = select (maxSocket + 1, & readSet, & writeSet, NULL, & timeVal);
+ 
+     if (selectCount < 0)
+       return -1;
+@@ -424,11 +486,13 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou
+     if (selectCount == 0)
+       return 0;
+ 
+-    if (FD_ISSET (socket, & writeSet))
+-      * condition |= ENET_SOCKET_WAIT_SEND;
++    if ( (socket4 != ENET_SOCKET_NULL && FD_ISSET (socket4, & writeSet)) ||
++        (socket6 != ENET_SOCKET_NULL && FD_ISSET (socket6, & writeSet)) )
++        * condition |= ENET_SOCKET_WAIT_SEND;
+ 
+-    if (FD_ISSET (socket, & readSet))
+-      * condition |= ENET_SOCKET_WAIT_RECEIVE;
++    if ( (socket4 != ENET_SOCKET_NULL && FD_ISSET (socket4, & readSet)) ||
++        (socket6 != ENET_SOCKET_NULL && FD_ISSET (socket6, & readSet)) )
++        * condition |= ENET_SOCKET_WAIT_RECEIVE;
+ 
+     return 0;
+ #endif
+diff --git a/win32.c b/win32.c
+index e1fae23..2607160 100644
+--- a/win32.c
++++ b/win32.c
+@@ -4,6 +4,8 @@
+ */
+ #ifdef WIN32
+ 
++#define _WIN32_WINNT 0x0501
++
+ #include <time.h>
+ #define ENET_BUILDING_LIB 1
+ #include "enet/enet.h"
+@@ -13,14 +15,14 @@ static enet_uint32 timeBase = 0;
+ int
+ enet_initialize (void)
+ {
+-    WORD versionRequested = MAKEWORD (1, 1);
++    WORD versionRequested = MAKEWORD (2, 2);
+     WSADATA wsaData;
+    
+     if (WSAStartup (versionRequested, & wsaData))
+        return -1;
+ 
+-    if (LOBYTE (wsaData.wVersion) != 1||
+-        HIBYTE (wsaData.wVersion) != 1)
++    if (LOBYTE (wsaData.wVersion) != 2||
++        HIBYTE (wsaData.wVersion) != 2)
+     {
+        WSACleanup ();
+        
+@@ -52,77 +54,139 @@ enet_time_set (enet_uint32 newTimeBase)
+     timeBase = (enet_uint32) timeGetTime () - newTimeBase;
+ }
+ 
+-int
+-enet_address_set_host (ENetAddress * address, const char * name)
++static enet_uint16
++enet_af (ENetAddressFamily family)
+ {
+-    struct hostent * hostEntry;
++    if (family == ENET_IPV4)
++        return AF_INET;
++    if (family == ENET_IPV6)
++        return AF_INET6;
++    return 0;
++}
+ 
+-    hostEntry = gethostbyname (name);
+-    if (hostEntry == NULL ||
+-        hostEntry -> h_addrtype != AF_INET)
++static socklen_t
++enet_sa_size (ENetAddressFamily family)
++{
++    if (family == ENET_IPV4)
++        return sizeof (struct sockaddr_in);
++    if (family == ENET_IPV6)
++        return sizeof (struct sockaddr_in6);
++    return 0;
++}
++
++static ENetAddressFamily
++enet_address_set_address (ENetAddress * address, const struct sockaddr * sin)
++{
++    memset (address, 0, sizeof (ENetAddress));
++    if (sin -> sa_family == AF_INET)
+     {
+-        unsigned long host = inet_addr (name);
+-        if (host == INADDR_NONE)
+-            return -1;
+-        address -> host = host;
+-        return 0;
++        address -> host = enet_address_map4 ((((struct sockaddr_in *) sin) -> sin_addr.s_addr));
++        /* address -> scopeID = 0; */
++        address -> port = ENET_NET_TO_HOST_16 (((struct sockaddr_in *) sin) -> sin_port);
++        return ENET_IPV4;
+     }
++    if (sin -> sa_family == AF_INET6)
++    {
++        address -> host = * (ENetHostAddress *) & ((struct sockaddr_in6 *) sin) -> sin6_addr;
++        address -> scopeID = ((struct sockaddr_in6 *) sin) -> sin6_scope_id;
++        address -> port = ENET_NET_TO_HOST_16 (((struct sockaddr_in6 *) sin) -> sin6_port);
++        return ENET_IPV6;
++    }
++    return ENET_NO_ADDRESS_FAMILY;
++}
+ 
+-    address -> host = * (enet_uint32 *) hostEntry -> h_addr_list [0];
+-
+-    return 0;
++static int
++enet_address_set_sin (struct sockaddr * sin, const ENetAddress * address, ENetAddressFamily family)
++{
++    memset (sin, 0, enet_sa_size(family));
++    if (family == ENET_IPV4 &&
++      (enet_get_address_family (address) == ENET_IPV4 ||
++      !memcmp (& address -> host, & ENET_HOST_ANY, sizeof(ENetHostAddress))))
++    {
++        ((struct sockaddr_in *) sin) -> sin_family = AF_INET;
++        ((struct sockaddr_in *) sin) -> sin_addr = * (struct in_addr *) & address -> host.addr[12];
++        ((struct sockaddr_in *) sin) -> sin_port = ENET_HOST_TO_NET_16 (address -> port);
++        return 0;
++    }
++    else if (family == ENET_IPV6)
++    {
++        ((struct sockaddr_in6 *) sin) -> sin6_family = AF_INET6;
++        ((struct sockaddr_in6 *) sin) -> sin6_addr = * (struct in6_addr *) & address -> host;
++        ((struct sockaddr_in6 *) sin) -> sin6_scope_id = address -> scopeID;
++        ((struct sockaddr_in6 *) sin) -> sin6_port = ENET_HOST_TO_NET_16 (address -> port);
++        return 0;
++    }
++    return -1;
+ }
+ 
+ int
+-enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
++enet_address_set_host (ENetAddress * address, const char * name)
+ {
+-    char * addr = inet_ntoa (* (struct in_addr *) & address -> host);
+-    if (addr == NULL)
++    enet_uint16 port = address -> port;
++    struct addrinfo hints;
++    struct addrinfo * result;
++    struct addrinfo * res;
++
++    memset(& hints, 0, sizeof (hints));
++    hints.ai_flags = AI_ADDRCONFIG;
++    hints.ai_family = AF_UNSPEC;
++
++    if ( getaddrinfo(name, NULL, &hints, &result) )
+         return -1;
+-    strncpy (name, addr, nameLength);
++
++    for (res = result; res != NULL; res = res -> ai_next)
++    {
++        if ( enet_address_set_address(address, res -> ai_addr) != ENET_NO_ADDRESS_FAMILY )
++            break;
++    }
++
++    address -> port = port;
++    freeaddrinfo(result);
++    if (res == NULL) return -1;
++
+     return 0;
+ }
+ 
+-int
+-enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
++static int
++enet_address_get_host_x (const ENetAddress * address, char * name, size_t nameLength, int flags)
+ {
+-    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);
++    struct sockaddr_storage sin;
++    enet_address_set_sin((struct sockaddr *) & sin, address, ENET_IPV6);
+ 
+-    strncpy (name, hostEntry -> h_name, nameLength);
++    if ( getnameinfo((struct sockaddr *) & sin, enet_sa_size (ENET_IPV6), name, nameLength, NULL, 0, flags))
++        return -1;
+ 
+     return 0;
+ }
+ 
+ int
+-enet_socket_bind (ENetSocket socket, const ENetAddress * address)
++enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
+ {
+-    struct sockaddr_in sin;
++    return enet_address_get_host_x(address, name, nameLength, NI_NUMERICHOST);
++}
+ 
+-    memset (& sin, 0, sizeof (struct sockaddr_in));
++int
++enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
++{
++    return enet_address_get_host_x(address, name, nameLength, 0);
++}
+ 
+-    sin.sin_family = AF_INET;
++int
++enet_socket_bind (ENetSocket socket, const ENetAddress * address, ENetAddressFamily family)
++{
++    struct sockaddr_storage sin;
+ 
+     if (address != NULL)
+     {
+-       sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+-       sin.sin_addr.s_addr = address -> host;
++        enet_address_set_sin((struct sockaddr *) & sin, address, family);
+     }
+     else
+     {
+-       sin.sin_port = 0;
+-       sin.sin_addr.s_addr = INADDR_ANY;
++        ENetAddress address_ = { ENET_HOST_ANY_INIT, 0, 0 };
++        enet_address_set_sin((struct sockaddr *) & sin, & address_, family);
+     }
+ 
+-    return bind (socket,
+-                 (struct sockaddr *) & sin,
+-                 sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0;
++    return bind (socket, (struct sockaddr *) & sin, enet_sa_size(family)) == SOCKET_ERROR ? -1 : 0;
+ }
+ 
+ int
+@@ -132,9 +196,10 @@ enet_socket_listen (ENetSocket socket, int backlog)
+ }
+ 
+ ENetSocket
+-enet_socket_create (ENetSocketType type)
++enet_socket_create (ENetSocketType type, ENetAddressFamily family)
+ {
+-    return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
++    ENetSocket sock = socket (enet_af (family), type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
++    return sock;
+ }
+ 
+ int
+@@ -173,28 +238,23 @@ enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value)
+ }
+ 
+ int
+-enet_socket_connect (ENetSocket socket, const ENetAddress * address)
++enet_socket_connect (ENetSocket socket, const ENetAddress * address, ENetAddressFamily family)
+ {
+-    struct sockaddr_in sin;
+-
+-    memset (& sin, 0, sizeof (struct sockaddr_in));
++    struct sockaddr_storage sin;
++    enet_address_set_sin((struct sockaddr *) & sin, address, family);
+ 
+-    sin.sin_family = AF_INET;
+-    sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+-    sin.sin_addr.s_addr = address -> host;
+-
+-    return connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0;
++    return connect (socket, (struct sockaddr *) & sin, enet_sa_size (family)) == SOCKET_ERROR ? -1 : 0;
+ }
+ 
+ ENetSocket
+-enet_socket_accept (ENetSocket socket, ENetAddress * address)
++enet_socket_accept (ENetSocket socket, ENetAddress * address, ENetAddressFamily family)
+ {
+     SOCKET result;
+-    struct sockaddr_in sin;
+-    int sinLength = sizeof (struct sockaddr_in);
++    struct sockaddr_storage sin;
++    socklen_t sinLength = enet_sa_size (family);
+ 
+     result = accept (socket, 
+-                     address != NULL ? (struct sockaddr *) & sin : NULL, 
++                     address != NULL ? (struct sockaddr *) & sin : NULL,
+                      address != NULL ? & sinLength : NULL);
+ 
+     if (result == INVALID_SOCKET)
+@@ -202,8 +262,7 @@ enet_socket_accept (ENetSocket socket, ENetAddress * address)
+ 
+     if (address != NULL)
+     {
+-        address -> host = (enet_uint32) sin.sin_addr.s_addr;
+-        address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
++        enet_address_set_address(address, (struct sockaddr *) & sin);
+     }
+ 
+     return result;
+@@ -219,18 +278,15 @@ int
+ enet_socket_send (ENetSocket socket,
+                   const ENetAddress * address,
+                   const ENetBuffer * buffers,
+-                  size_t bufferCount)
++                  size_t bufferCount,
++                  ENetAddressFamily family)
+ {
+-    struct sockaddr_in sin;
++    struct sockaddr_storage 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;
++        enet_address_set_sin((struct sockaddr *) & sin, address, family);
+     }
+ 
+     if (WSASendTo (socket, 
+@@ -239,7 +295,7 @@ enet_socket_send (ENetSocket socket,
+                    & sentLength,
+                    0,
+                    address != NULL ? (struct sockaddr *) & sin : 0,
+-                   address != NULL ? sizeof (struct sockaddr_in) : 0,
++                   address != NULL ? enet_sa_size (family) : 0,
+                    NULL,
+                    NULL) == SOCKET_ERROR)
+     {
+@@ -256,12 +312,13 @@ int
+ enet_socket_receive (ENetSocket socket,
+                      ENetAddress * address,
+                      ENetBuffer * buffers,
+-                     size_t bufferCount)
++                     size_t bufferCount,
++                     ENetAddressFamily family)
+ {
+-    INT sinLength = sizeof (struct sockaddr_in);
++    INT sinLength = enet_sa_size (family);
+     DWORD flags = 0,
+           recvLength;
+-    struct sockaddr_in sin;
++    struct sockaddr_storage sin;
+ 
+     if (WSARecvFrom (socket,
+                      (LPWSABUF) buffers,
+@@ -288,8 +345,7 @@ enet_socket_receive (ENetSocket socket,
+ 
+     if (address != NULL)
+     {
+-        address -> host = (enet_uint32) sin.sin_addr.s_addr;
+-        address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
++        enet_address_set_address(address, (struct sockaddr *) & sin);
+     }
+ 
+     return (int) recvLength;
+@@ -307,25 +363,42 @@ enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocket
+ }
+ 
+ int
+-enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout)
++enet_socket_wait (ENetSocket socket4, ENetSocket socket6, enet_uint32 * condition, enet_uint32 timeout)
+ {
+     fd_set readSet, writeSet;
+     struct timeval timeVal;
+     int selectCount;
+-    
++    ENetSocket maxSocket;
++
+     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 (socket4 != ENET_SOCKET_NULL)
++            FD_SET (socket4, & writeSet);
++        if (socket6 != ENET_SOCKET_NULL)
++            FD_SET (socket6, & writeSet);
++    }
+ 
+     if (* condition & ENET_SOCKET_WAIT_RECEIVE)
+-      FD_SET (socket, & readSet);
++    {
++        if (socket4 != ENET_SOCKET_NULL)
++            FD_SET (socket4, & readSet);
++        if (socket6 != ENET_SOCKET_NULL)
++            FD_SET (socket6, & readSet);
++    }
+ 
+-    selectCount = select (socket + 1, & readSet, & writeSet, NULL, & timeVal);
++    maxSocket = 0;
++    if (socket4 != ENET_SOCKET_NULL)
++        maxSocket = socket4;
++    if (socket6 != ENET_SOCKET_NULL && socket6 > maxSocket)
++        maxSocket = socket6;
++
++    selectCount = select (maxSocket + 1, & readSet, & writeSet, NULL, & timeVal);
+ 
+     if (selectCount < 0)
+       return -1;
+@@ -335,14 +408,16 @@ enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeou
+     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;
++    if ( (socket4 != ENET_SOCKET_NULL && FD_ISSET (socket4, & writeSet)) ||
++        (socket6 != ENET_SOCKET_NULL && FD_ISSET (socket6, & writeSet)) )
++        * condition |= ENET_SOCKET_WAIT_SEND;
++
++    if ( (socket4 != ENET_SOCKET_NULL && FD_ISSET (socket4, & readSet)) ||
++        (socket6 != ENET_SOCKET_NULL && FD_ISSET (socket6, & readSet)) )
++        * condition |= ENET_SOCKET_WAIT_RECEIVE;
+ 
+     return 0;
+-} 
++}
+ 
+ #endif
+ 
+-- 
+1.7.1
+
Index: /code/trunk/src/external/enet/peer.c
===================================================================
--- /code/trunk/src/external/enet/peer.c	(revision 7459)
+++ /code/trunk/src/external/enet/peer.c	(revision 7459)
@@ -0,0 +1,816 @@
+/** 
+ @file  peer.c
+ @brief ENet peer management functions
+*/
+#include <string.h>
+#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, on 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)
+     return -1;
+
+   fragmentLength = peer -> mtu - sizeof (ENetProtocolHeader) - sizeof (ENetProtocolSendFragment);
+
+   if (packet -> dataLength > fragmentLength)
+   {
+      enet_uint16 startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingReliableSequenceNumber + 1);
+      enet_uint32 fragmentCount = ENET_HOST_TO_NET_32 ((packet -> dataLength + fragmentLength - 1) / fragmentLength),
+             fragmentNumber,
+             fragmentOffset;
+      ENetList fragments;
+      ENetOutgoingCommand * fragment;
+
+      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 = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+         fragment -> command.header.channelID = channelID;
+         fragment -> command.sendFragment.startSequenceNumber = startSequenceNumber;
+         fragment -> command.sendFragment.dataLength = ENET_HOST_TO_NET_16 (fragmentLength);
+         fragment -> command.sendFragment.fragmentCount = 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)
+   {
+      command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+      command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
+   }
+   else
+   if (packet -> flags & ENET_PACKET_FLAG_UNSEQUENCED)
+   {
+      command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED;
+      command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup + 1);
+      command.sendUnsequenced.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
+   }
+   else 
+   if (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.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1);
+      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_reset_incoming_commands (ENetList * queue)
+{
+    ENetIncomingCommand * incomingCommand;
+
+    while (! enet_list_empty (queue))
+    {
+       incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (queue));
+
+       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);
+    }
+}
+
+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 -> 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);
+}
+
+/** 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
+    {
+       ++ 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);
+
+    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 currentCommand;
+
+    for (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_UNRELIABLE &&
+           incomingCommand -> reliableSequenceNumber != channel -> incomingReliableSequenceNumber)
+         break;
+    }
+
+    if (currentCommand == enet_list_begin (& channel -> incomingUnreliableCommands))
+      return;
+
+    enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingUnreliableCommands), enet_list_previous (currentCommand));
+
+    if (! peer -> needsDispatch)
+    {
+       enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
+
+       peer -> needsDispatch = 1;
+    }
+}
+
+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;
+
+    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;
+    }
+
+    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;
+    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:
+       unreliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendUnreliable.unreliableSequenceNumber);
+
+       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 ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE)
+            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)
+    { 
+       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;
+}
+
+/** @} */
Index: /code/trunk/src/external/enet/protocol.c
===================================================================
--- /code/trunk/src/external/enet/protocol.c	(revision 7459)
+++ /code/trunk/src/external/enet/protocol.c	(revision 7459)
@@ -0,0 +1,1718 @@
+/** 
+ @file  protocol.c
+ @brief ENet protocol functions
+*/
+#include <stdio.h>
+#include <string.h>
+#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),
+};
+
+ENetHostAddress
+enet_address_map4 (enet_uint32 address)
+{
+    ENetHostAddress addr = ENET_IPV4MAPPED_PREFIX_INIT;
+    ((enet_uint32 *)addr.addr)[3] = address;
+    return addr;
+}
+
+ENetAddressFamily
+enet_get_address_family (const ENetAddress * address)
+{
+    if (!memcmp(& address->host, & ENET_IPV4MAPPED_PREFIX, ENET_IPV4MAPPED_PREFIX_LEN))
+        return ENET_IPV4;
+    return ENET_IPV6;
+}
+
+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;
+       }
+    }
+
+    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)
+             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;
+    ENetListIterator currentCommand;
+    ENetProtocolCommand commandNumber;
+
+    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;
+    }
+
+    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)
+    {
+       peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength;
+
+       -- outgoingCommand -> packet -> referenceCount;
+
+       if (outgoingCommand -> packet -> referenceCount == 0)
+         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.port == host -> receivedAddress.port &&
+            currentPeer -> connectID == command -> connect.connectID &&
+            !memcmp(& currentPeer -> address.host, & host -> receivedAddress.host, sizeof (ENetHostAddress)))
+          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;
+
+        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_16 (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 (* 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 (* 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 (* 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 (* 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 (fragmentOffset >= totalLength ||
+        fragmentOffset + fragmentLength > totalLength ||
+        fragmentNumber >= fragmentCount)
+      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;
+       hostCommand.sendFragment.startSequenceNumber = startSequenceNumber;
+       hostCommand.sendFragment.dataLength = fragmentLength;
+       hostCommand.sendFragment.fragmentNumber = fragmentNumber;
+       hostCommand.sendFragment.fragmentCount = fragmentCount;
+       hostCommand.sendFragment.fragmentOffset = fragmentOffset;
+       hostCommand.sendFragment.totalLength = totalLength;
+
+       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_ping (ENetHost * host, ENetPeer * peer, const ENetProtocol * command)
+{
+    return 0;
+}
+
+static int
+enet_protocol_handle_bandwidth_limit (ENetHost * host, ENetPeer * peer, const ENetProtocol * command)
+{
+    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)
+{
+    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_ZOMBIE || peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT)
+      return 0;
+
+    enet_peer_reset_queues (peer);
+
+    if (peer -> state == ENET_PEER_STATE_CONNECTION_SUCCEEDED)
+        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;
+
+    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;
+    }
+   
+    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 ||
+           (peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID &&
+            sessionID != peer -> incomingSessionID) ||
+           ( memcmp(& peer -> address.host, & host -> receivedAddress.host, sizeof (ENetHostAddress)) &&
+             memcmp(& peer -> address.host, & ENET_HOST_BROADCAST, sizeof (ENetHostAddress)) &&
+             peer -> address.host.addr[0] != 0xff ) )
+         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 -> receivedAddress;
+       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 (command -> header.command & ENET_PROTOCOL_COMMAND_MASK)
+       {
+       case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE:
+          if (enet_protocol_handle_acknowledge (host, event, peer, command))
+            goto commandError;
+          break;
+
+       case ENET_PROTOCOL_COMMAND_CONNECT:
+          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;
+
+       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:
+              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, ENetAddressFamily family)
+{
+    for (;;)
+    {
+       int receivedLength;
+       ENetBuffer buffer;
+
+       buffer.data = host -> packetData [0];
+       buffer.dataLength = sizeof (host -> packetData [0]);
+
+       receivedLength = enet_socket_receive (family == ENET_IPV4 ? host -> socket4 : host -> socket6,
+                                             & host -> receivedAddress,
+                                             & buffer,
+                                             1,
+                                             family);
+
+       if (receivedLength < 0)
+         return -1;
+
+       if (receivedLength == 0)
+         return 0;
+
+       if (enet_get_address_family (& host -> receivedAddress) != family)
+         return -1;
+
+       host -> receivedData = host -> packetData [0];
+       host -> receivedDataLength = receivedLength;
+      
+       host -> totalReceivedData += receivedLength;
+       host -> totalReceivedPackets ++;
+ 
+       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 -> packet -> dataLength))
+       {
+          host -> continueSending = 1;
+
+          break;
+       }
+
+       currentCommand = enet_list_next (currentCommand);
+
+       if (outgoingCommand -> packet != NULL)
+       {
+          peer -> packetThrottleCounter += ENET_PEER_PACKET_THROTTLE_COUNTER;
+          peer -> packetThrottleCounter %= ENET_PEER_PACKET_THROTTLE_SCALE;
+          
+          if (peer -> packetThrottleCounter > peer -> packetThrottle)
+          {
+             -- outgoingCommand -> packet -> referenceCount;
+
+             if (outgoingCommand -> packet -> referenceCount == 0)
+               enet_packet_destroy (outgoingCommand -> packet);
+         
+             enet_list_remove (& outgoingCommand -> outgoingCommandList);
+             enet_free (outgoingCommand);
+           
+             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;
+          buffer -> dataLength = outgoingCommand -> packet -> dataLength;
+
+          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) >= ENET_PEER_TIMEOUT_MAXIMUM ||
+               (outgoingCommand -> roundTripTimeout >= outgoingCommand -> roundTripTimeoutLimit &&
+                 ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= ENET_PEER_TIMEOUT_MINIMUM)))
+       {
+          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 void
+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;
+
+    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 && 
+           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)))))
+         break;
+  
+       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)
+       {
+          host -> continueSending = 1;
+          
+          break;
+       }
+
+       if (outgoingCommand -> packet != NULL)
+       {
+          if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > peer -> windowSize)
+            break;
+
+          if ((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 = ENET_PEER_TIMEOUT_LIMIT * 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;
+}
+
+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)
+    {
+        ENetAddressFamily family;
+        ENetSocket socket;
+
+        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)
+          return 1;
+
+        if (! enet_list_empty (& currentPeer -> outgoingReliableCommands))
+          enet_protocol_send_reliable_outgoing_commands (host, currentPeer);
+        else
+        if (enet_list_empty (& currentPeer -> sentReliableCommands) &&
+            ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= ENET_PEER_PING_INTERVAL &&
+            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;
+
+        family = enet_get_address_family (& currentPeer -> address);
+        socket = family == ENET_IPV4 ? host -> socket4 : host -> socket6;
+        if (socket == ENET_SOCKET_NULL)
+          return -1;
+        sentLength = enet_socket_send (socket,
+                                           & currentPeer -> address,
+                                           host -> buffers,
+                                           host -> bufferCount,
+                                           family);
+
+        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;
+       }
+
+       if (host -> socket4 != ENET_SOCKET_NULL)
+         switch (enet_protocol_receive_incoming_commands (host, event, ENET_IPV4))
+       {
+       case 1:
+          return 1;
+
+       case -1:
+          perror ("Error receiving incoming packets");
+
+          return -1;
+
+       default:
+          break;
+       }
+
+       if (host -> socket6 != ENET_SOCKET_NULL)
+         switch (enet_protocol_receive_incoming_commands (host, event, ENET_IPV6))
+       {
+       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 -> socket4, host -> socket6, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0)
+         return -1;
+       
+       host -> serviceTime = enet_time_get ();
+    } while (waitCondition == ENET_SOCKET_WAIT_RECEIVE);
+
+    return 0; 
+}
+
Index: /code/trunk/src/external/enet/protocol.h
===================================================================
--- /code/trunk/src/external/enet/protocol.h	(revision 7459)
+++ /code/trunk/src/external/enet/protocol.h	(revision 7459)
@@ -0,0 +1,196 @@
+/** 
+ @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
+};
+
+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_COUNT              = 12,
+
+   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__ */
+
Index: /code/trunk/src/external/enet/time.h
===================================================================
--- /code/trunk/src/external/enet/time.h	(revision 7459)
+++ /code/trunk/src/external/enet/time.h	(revision 7459)
@@ -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__ */
+
Index: /code/trunk/src/external/enet/types.h
===================================================================
--- /code/trunk/src/external/enet/types.h	(revision 7459)
+++ /code/trunk/src/external/enet/types.h	(revision 7459)
@@ -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__ */
+
Index: /code/trunk/src/external/enet/unix.c
===================================================================
--- /code/trunk/src/external/enet/unix.c	(revision 7459)
+++ /code/trunk/src/external/enet/unix.c	(revision 7459)
@@ -0,0 +1,502 @@
+/** 
+ @file  unix.c
+ @brief ENet Unix system specific functions
+*/
+#ifndef WIN32
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#define ENET_BUILDING_LIB 1
+#include "enet/enet.h"
+
+#ifdef HAS_FCNTL
+#include <fcntl.h>
+#endif
+
+#ifdef __APPLE__
+#undef HAS_POLL
+#endif
+
+#ifdef HAS_POLL
+#include <sys/poll.h>
+#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;
+}
+
+static enet_uint16
+enet_af (ENetAddressFamily family)
+{
+    if (family == ENET_IPV4)
+        return AF_INET;
+    if (family == ENET_IPV6)
+        return AF_INET6;
+    return 0;
+}
+
+static socklen_t
+enet_sa_size (ENetAddressFamily family)
+{
+    if (family == ENET_IPV4)
+        return sizeof (struct sockaddr_in);
+    if (family == ENET_IPV6)
+        return sizeof (struct sockaddr_in6);
+    return 0;
+}
+
+static ENetAddressFamily
+enet_address_set_address (ENetAddress * address, const struct sockaddr * sin)
+{
+    memset (address, 0, sizeof (ENetAddress));
+    if (sin -> sa_family == AF_INET)
+    {
+        address -> host = enet_address_map4 ((((struct sockaddr_in *) sin) -> sin_addr.s_addr));
+        /* address -> scopeID = 0; */
+        address -> port = ENET_NET_TO_HOST_16 (((struct sockaddr_in *) sin) -> sin_port);
+        return ENET_IPV4;
+    }
+    if (sin -> sa_family == AF_INET6)
+    {
+        address -> host = * (ENetHostAddress *) & ((struct sockaddr_in6 *) sin) -> sin6_addr;
+        address -> scopeID = ((struct sockaddr_in6 *) sin) -> sin6_scope_id;
+        address -> port = ENET_NET_TO_HOST_16 (((struct sockaddr_in6 *) sin) -> sin6_port);
+        return ENET_IPV6;
+    }
+    return ENET_NO_ADDRESS_FAMILY;
+}
+
+static int
+enet_address_set_sin (struct sockaddr * sin, const ENetAddress * address, ENetAddressFamily family)
+{
+    memset (sin, 0, enet_sa_size(family));
+    if (family == ENET_IPV4 &&
+      (enet_get_address_family (address) == ENET_IPV4 ||
+      !memcmp (& address -> host, & ENET_HOST_ANY, sizeof(ENetHostAddress))))
+    {
+        ((struct sockaddr_in *) sin) -> sin_family = AF_INET;
+        ((struct sockaddr_in *) sin) -> sin_addr = * (struct in_addr *) & address -> host.addr[12];
+        ((struct sockaddr_in *) sin) -> sin_port = ENET_HOST_TO_NET_16 (address -> port);
+        return 0;
+    }
+    else if (family == ENET_IPV6)
+    {
+        ((struct sockaddr_in6 *) sin) -> sin6_family = AF_INET6;
+        ((struct sockaddr_in6 *) sin) -> sin6_addr = * (struct in6_addr *) & address -> host;
+        ((struct sockaddr_in6 *) sin) -> sin6_scope_id = address -> scopeID;
+        ((struct sockaddr_in6 *) sin) -> sin6_port = ENET_HOST_TO_NET_16 (address -> port);
+        return 0;
+    }
+    return -1;
+}
+
+int
+enet_address_set_host (ENetAddress * address, const char * name)
+{
+    enet_uint16 port = address -> port;
+    struct addrinfo hints;
+    struct addrinfo * result;
+    struct addrinfo * res;
+
+    memset(& hints, 0, sizeof (hints));
+    hints.ai_flags = AI_ADDRCONFIG;
+    hints.ai_family = AF_UNSPEC;
+
+    if ( getaddrinfo(name, NULL, &hints, &result) )
+        return -1;
+
+    for (res = result; res != NULL; res = res -> ai_next)
+    {
+        if ( enet_address_set_address(address, res -> ai_addr) != ENET_NO_ADDRESS_FAMILY )
+            break;
+    }
+
+    address -> port = port;
+    freeaddrinfo(result);
+    if (res == NULL) return -1;
+
+    return 0;
+}
+
+static int
+enet_address_get_host_x (const ENetAddress * address, char * name, size_t nameLength, int flags)
+{
+    struct sockaddr_storage sin;
+    enet_address_set_sin((struct sockaddr *) & sin, address, ENET_IPV6);
+
+    if ( getnameinfo((struct sockaddr *) & sin, enet_sa_size (ENET_IPV6), name, nameLength, NULL, 0, flags))
+        return -1;
+
+    return 0;
+}
+
+int
+enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
+{
+    return enet_address_get_host_x(address, name, nameLength, NI_NUMERICHOST);
+}
+
+int
+enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
+{
+    return enet_address_get_host_x(address, name, nameLength, 0);
+}
+
+int
+enet_socket_bind (ENetSocket socket, const ENetAddress * address, ENetAddressFamily family)
+{
+    struct sockaddr_storage sin;
+
+    if (address != NULL)
+    {
+        enet_address_set_sin((struct sockaddr *) & sin, address, family);
+    }
+    else
+    {
+        ENetAddress address_ = { ENET_HOST_ANY_INIT, 0, 0 };
+        enet_address_set_sin((struct sockaddr *) & sin, & address_, family);
+    }
+
+    return bind (socket, (struct sockaddr *) & sin, enet_sa_size(family));
+}
+
+int
+enet_socket_listen (ENetSocket socket, int backlog)
+{
+    return listen (socket, backlog < 0 ? SOMAXCONN : backlog);
+}
+
+ENetSocket
+enet_socket_create (ENetSocketType type, ENetAddressFamily family)
+{
+    ENetSocket sock = socket (enet_af (family), type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
+
+#ifdef IPV6_V6ONLY
+    if (family == ENET_IPV6)
+    {
+        int value = 1;
+        setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, & value, sizeof (int));
+    }
+#endif /* IPV6_V6ONLY */
+
+    return sock;
+}
+
+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;
+
+        default:
+            break;
+    }
+    return result == -1 ? -1 : 0;
+}
+
+int
+enet_socket_connect (ENetSocket socket, const ENetAddress * address, ENetAddressFamily family)
+{
+    struct sockaddr_storage sin;
+    enet_address_set_sin((struct sockaddr *) & sin, address, family);
+
+    return connect (socket, (struct sockaddr *) & sin, enet_sa_size (family));
+}
+
+ENetSocket
+enet_socket_accept (ENetSocket socket, ENetAddress * address, ENetAddressFamily family)
+{
+    int result;
+    struct sockaddr_storage sin;
+    socklen_t sinLength = enet_sa_size (family);
+
+    result = accept (socket, 
+                     address != NULL ? (struct sockaddr *) & sin : NULL,
+                     address != NULL ? & sinLength : NULL);
+
+    if (result == -1)
+      return ENET_SOCKET_NULL;
+
+    if (address != NULL)
+    {
+        enet_address_set_address(address, (struct sockaddr *) & sin);
+    }
+
+    return result;
+}
+
+void
+enet_socket_destroy (ENetSocket socket)
+{
+    close (socket);
+}
+
+int
+enet_socket_send (ENetSocket socket,
+                  const ENetAddress * address,
+                  const ENetBuffer * buffers,
+                  size_t bufferCount,
+                  ENetAddressFamily family)
+{
+    struct msghdr msgHdr;
+    struct sockaddr_storage sin;
+    int sentLength;
+
+    memset (& msgHdr, 0, sizeof (struct msghdr));
+
+    if (address != NULL)
+    {
+        enet_address_set_sin((struct sockaddr *) & sin, address, family);
+        msgHdr.msg_name = & sin;
+        msgHdr.msg_namelen = enet_sa_size (family);
+    }
+
+    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,
+                     ENetAddressFamily family)
+{
+    struct msghdr msgHdr;
+    struct sockaddr_storage sin;
+    int recvLength;
+
+    memset (& msgHdr, 0, sizeof (struct msghdr));
+
+    if (address != NULL)
+    {
+        msgHdr.msg_name = & sin;
+        msgHdr.msg_namelen = enet_sa_size (family);
+    }
+
+    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)
+    {
+        enet_address_set_address(address, (struct sockaddr *) & sin);
+    }
+
+    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 socket4, ENetSocket socket6, enet_uint32 * condition, enet_uint32 timeout)
+{
+#ifdef HAS_POLL
+    struct pollfd pollSocket[2];
+    int pollCount;
+
+    pollSocket[0].fd = socket4;
+    pollSocket[1].fd = socket6;
+    pollSocket[0].events = 0;
+    pollSocket[1].events = 0;
+    /* pollSocket[0].revents = 0; */
+    pollSocket[1].revents = 0;
+
+    if (pollSocket[0].fd == ENET_SOCKET_NULL)
+    {
+        pollSocket[0].fd = pollSocket[1].fd;
+        pollSocket[1].fd = ENET_SOCKET_NULL;
+    }
+
+    if (* condition & ENET_SOCKET_WAIT_SEND)
+    {
+        pollSocket[0].events |= POLLOUT;
+        pollSocket[1].events |= POLLOUT;
+    }
+
+    if (* condition & ENET_SOCKET_WAIT_RECEIVE)
+    {
+        pollSocket[0].events |= POLLIN;
+        pollSocket[1].events |= POLLIN;
+    }
+
+    pollCount = poll (pollSocket, pollSocket[1].fd != ENET_SOCKET_NULL ? 2 : 1, timeout);
+
+    if (pollCount < 0)
+      return -1;
+
+    * condition = ENET_SOCKET_WAIT_NONE;
+
+    if (pollCount == 0)
+      return 0;
+
+    if ((pollSocket[0].revents | pollSocket[1].revents) & POLLOUT)
+      * condition |= ENET_SOCKET_WAIT_SEND;
+    
+    if ((pollSocket[0].revents | pollSocket[1].revents) & POLLIN)
+      * condition |= ENET_SOCKET_WAIT_RECEIVE;
+
+    return 0;
+#else
+    fd_set readSet, writeSet;
+    struct timeval timeVal;
+    int selectCount;
+    ENetSocket maxSocket;
+
+    timeVal.tv_sec = timeout / 1000;
+    timeVal.tv_usec = (timeout % 1000) * 1000;
+
+    FD_ZERO (& readSet);
+    FD_ZERO (& writeSet);
+
+    if (* condition & ENET_SOCKET_WAIT_SEND)
+    {
+        if (socket4 != ENET_SOCKET_NULL)
+            FD_SET (socket4, & writeSet);
+        if (socket6 != ENET_SOCKET_NULL)
+            FD_SET (socket6, & writeSet);
+    }
+
+    if (* condition & ENET_SOCKET_WAIT_RECEIVE)
+    {
+        if (socket4 != ENET_SOCKET_NULL)
+            FD_SET (socket4, & readSet);
+        if (socket6 != ENET_SOCKET_NULL)
+            FD_SET (socket6, & readSet);
+    }
+
+    maxSocket = 0;
+    if (socket4 != ENET_SOCKET_NULL)
+        maxSocket = socket4;
+    if (socket6 != ENET_SOCKET_NULL && socket6 > maxSocket)
+        maxSocket = socket6;
+
+    selectCount = select (maxSocket + 1, & readSet, & writeSet, NULL, & timeVal);
+
+    if (selectCount < 0)
+      return -1;
+
+    * condition = ENET_SOCKET_WAIT_NONE;
+
+    if (selectCount == 0)
+      return 0;
+
+    if ( (socket4 != ENET_SOCKET_NULL && FD_ISSET (socket4, & writeSet)) ||
+        (socket6 != ENET_SOCKET_NULL && FD_ISSET (socket6, & writeSet)) )
+        * condition |= ENET_SOCKET_WAIT_SEND;
+
+    if ( (socket4 != ENET_SOCKET_NULL && FD_ISSET (socket4, & readSet)) ||
+        (socket6 != ENET_SOCKET_NULL && FD_ISSET (socket6, & readSet)) )
+        * condition |= ENET_SOCKET_WAIT_RECEIVE;
+
+    return 0;
+#endif
+}
+
+#endif
+
Index: /code/trunk/src/external/enet/unix.h
===================================================================
--- /code/trunk/src/external/enet/unix.h	(revision 7459)
+++ /code/trunk/src/external/enet/unix.h	(revision 7459)
@@ -0,0 +1,45 @@
+/** 
+ @file  unix.h
+ @brief ENet Unix header
+*/
+#ifndef __ENET_UNIX_H__
+#define __ENET_UNIX_H__
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <unistd.h>
+
+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__ */
+
Index: /code/trunk/src/external/enet/utility.h
===================================================================
--- /code/trunk/src/external/enet/utility.h	(revision 7459)
+++ /code/trunk/src/external/enet/utility.h	(revision 7459)
@@ -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__ */
+
Index: /code/trunk/src/external/enet/win32.c
===================================================================
--- /code/trunk/src/external/enet/win32.c	(revision 7459)
+++ /code/trunk/src/external/enet/win32.c	(revision 7459)
@@ -0,0 +1,423 @@
+/** 
+ @file  win32.c
+ @brief ENet Win32 system specific functions
+*/
+#ifdef WIN32
+
+#define _WIN32_WINNT 0x0501
+
+#include <time.h>
+#define ENET_BUILDING_LIB 1
+#include "enet/enet.h"
+
+static enet_uint32 timeBase = 0;
+
+int
+enet_initialize (void)
+{
+    WORD versionRequested = MAKEWORD (2, 2);
+    WSADATA wsaData;
+   
+    if (WSAStartup (versionRequested, & wsaData))
+       return -1;
+
+    if (LOBYTE (wsaData.wVersion) != 2||
+        HIBYTE (wsaData.wVersion) != 2)
+    {
+       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;
+}
+
+static enet_uint16
+enet_af (ENetAddressFamily family)
+{
+    if (family == ENET_IPV4)
+        return AF_INET;
+    if (family == ENET_IPV6)
+        return AF_INET6;
+    return 0;
+}
+
+static socklen_t
+enet_sa_size (ENetAddressFamily family)
+{
+    if (family == ENET_IPV4)
+        return sizeof (struct sockaddr_in);
+    if (family == ENET_IPV6)
+        return sizeof (struct sockaddr_in6);
+    return 0;
+}
+
+static ENetAddressFamily
+enet_address_set_address (ENetAddress * address, const struct sockaddr * sin)
+{
+    memset (address, 0, sizeof (ENetAddress));
+    if (sin -> sa_family == AF_INET)
+    {
+        address -> host = enet_address_map4 ((((struct sockaddr_in *) sin) -> sin_addr.s_addr));
+        /* address -> scopeID = 0; */
+        address -> port = ENET_NET_TO_HOST_16 (((struct sockaddr_in *) sin) -> sin_port);
+        return ENET_IPV4;
+    }
+    if (sin -> sa_family == AF_INET6)
+    {
+        address -> host = * (ENetHostAddress *) & ((struct sockaddr_in6 *) sin) -> sin6_addr;
+        address -> scopeID = ((struct sockaddr_in6 *) sin) -> sin6_scope_id;
+        address -> port = ENET_NET_TO_HOST_16 (((struct sockaddr_in6 *) sin) -> sin6_port);
+        return ENET_IPV6;
+    }
+    return ENET_NO_ADDRESS_FAMILY;
+}
+
+static int
+enet_address_set_sin (struct sockaddr * sin, const ENetAddress * address, ENetAddressFamily family)
+{
+    memset (sin, 0, enet_sa_size(family));
+    if (family == ENET_IPV4 &&
+      (enet_get_address_family (address) == ENET_IPV4 ||
+      !memcmp (& address -> host, & ENET_HOST_ANY, sizeof(ENetHostAddress))))
+    {
+        ((struct sockaddr_in *) sin) -> sin_family = AF_INET;
+        ((struct sockaddr_in *) sin) -> sin_addr = * (struct in_addr *) & address -> host.addr[12];
+        ((struct sockaddr_in *) sin) -> sin_port = ENET_HOST_TO_NET_16 (address -> port);
+        return 0;
+    }
+    else if (family == ENET_IPV6)
+    {
+        ((struct sockaddr_in6 *) sin) -> sin6_family = AF_INET6;
+        ((struct sockaddr_in6 *) sin) -> sin6_addr = * (struct in6_addr *) & address -> host;
+        ((struct sockaddr_in6 *) sin) -> sin6_scope_id = address -> scopeID;
+        ((struct sockaddr_in6 *) sin) -> sin6_port = ENET_HOST_TO_NET_16 (address -> port);
+        return 0;
+    }
+    return -1;
+}
+
+int
+enet_address_set_host (ENetAddress * address, const char * name)
+{
+    enet_uint16 port = address -> port;
+    struct addrinfo hints;
+    struct addrinfo * result;
+    struct addrinfo * res;
+
+    memset(& hints, 0, sizeof (hints));
+    hints.ai_flags = AI_ADDRCONFIG;
+    hints.ai_family = AF_UNSPEC;
+
+    if ( getaddrinfo(name, NULL, &hints, &result) )
+        return -1;
+
+    for (res = result; res != NULL; res = res -> ai_next)
+    {
+        if ( enet_address_set_address(address, res -> ai_addr) != ENET_NO_ADDRESS_FAMILY )
+            break;
+    }
+
+    address -> port = port;
+    freeaddrinfo(result);
+    if (res == NULL) return -1;
+
+    return 0;
+}
+
+static int
+enet_address_get_host_x (const ENetAddress * address, char * name, size_t nameLength, int flags)
+{
+    struct sockaddr_storage sin;
+    enet_address_set_sin((struct sockaddr *) & sin, address, ENET_IPV6);
+
+    if ( getnameinfo((struct sockaddr *) & sin, enet_sa_size (ENET_IPV6), name, nameLength, NULL, 0, flags))
+        return -1;
+
+    return 0;
+}
+
+int
+enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength)
+{
+    return enet_address_get_host_x(address, name, nameLength, NI_NUMERICHOST);
+}
+
+int
+enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength)
+{
+    return enet_address_get_host_x(address, name, nameLength, 0);
+}
+
+int
+enet_socket_bind (ENetSocket socket, const ENetAddress * address, ENetAddressFamily family)
+{
+    struct sockaddr_storage sin;
+
+    if (address != NULL)
+    {
+        enet_address_set_sin((struct sockaddr *) & sin, address, family);
+    }
+    else
+    {
+        ENetAddress address_ = { ENET_HOST_ANY_INIT, 0, 0 };
+        enet_address_set_sin((struct sockaddr *) & sin, & address_, family);
+    }
+
+    return bind (socket, (struct sockaddr *) & sin, enet_sa_size(family)) == 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, ENetAddressFamily family)
+{
+    ENetSocket sock = socket (enet_af (family), type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
+    return sock;
+}
+
+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;
+
+        default:
+            break;
+    }
+    return result == SOCKET_ERROR ? -1 : 0;
+}
+
+int
+enet_socket_connect (ENetSocket socket, const ENetAddress * address, ENetAddressFamily family)
+{
+    struct sockaddr_storage sin;
+    enet_address_set_sin((struct sockaddr *) & sin, address, family);
+
+    return connect (socket, (struct sockaddr *) & sin, enet_sa_size (family)) == SOCKET_ERROR ? -1 : 0;
+}
+
+ENetSocket
+enet_socket_accept (ENetSocket socket, ENetAddress * address, ENetAddressFamily family)
+{
+    SOCKET result;
+    struct sockaddr_storage sin;
+    socklen_t sinLength = enet_sa_size (family);
+
+    result = accept (socket, 
+                     address != NULL ? (struct sockaddr *) & sin : NULL,
+                     address != NULL ? & sinLength : NULL);
+
+    if (result == INVALID_SOCKET)
+      return ENET_SOCKET_NULL;
+
+    if (address != NULL)
+    {
+        enet_address_set_address(address, (struct sockaddr *) & sin);
+    }
+
+    return result;
+}
+
+void
+enet_socket_destroy (ENetSocket socket)
+{
+    closesocket (socket);
+}
+
+int
+enet_socket_send (ENetSocket socket,
+                  const ENetAddress * address,
+                  const ENetBuffer * buffers,
+                  size_t bufferCount,
+                  ENetAddressFamily family)
+{
+    struct sockaddr_storage sin;
+    DWORD sentLength;
+
+    if (address != NULL)
+    {
+        enet_address_set_sin((struct sockaddr *) & sin, address, family);
+    }
+
+    if (WSASendTo (socket, 
+                   (LPWSABUF) buffers,
+                   (DWORD) bufferCount,
+                   & sentLength,
+                   0,
+                   address != NULL ? (struct sockaddr *) & sin : 0,
+                   address != NULL ? enet_sa_size (family) : 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,
+                     ENetAddressFamily family)
+{
+    INT sinLength = enet_sa_size (family);
+    DWORD flags = 0,
+          recvLength;
+    struct sockaddr_storage 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)
+    {
+        enet_address_set_address(address, (struct sockaddr *) & sin);
+    }
+
+    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 socket4, ENetSocket socket6, enet_uint32 * condition, enet_uint32 timeout)
+{
+    fd_set readSet, writeSet;
+    struct timeval timeVal;
+    int selectCount;
+    ENetSocket maxSocket;
+
+    timeVal.tv_sec = timeout / 1000;
+    timeVal.tv_usec = (timeout % 1000) * 1000;
+
+    FD_ZERO (& readSet);
+    FD_ZERO (& writeSet);
+
+    if (* condition & ENET_SOCKET_WAIT_SEND)
+    {
+        if (socket4 != ENET_SOCKET_NULL)
+            FD_SET (socket4, & writeSet);
+        if (socket6 != ENET_SOCKET_NULL)
+            FD_SET (socket6, & writeSet);
+    }
+
+    if (* condition & ENET_SOCKET_WAIT_RECEIVE)
+    {
+        if (socket4 != ENET_SOCKET_NULL)
+            FD_SET (socket4, & readSet);
+        if (socket6 != ENET_SOCKET_NULL)
+            FD_SET (socket6, & readSet);
+    }
+
+    maxSocket = 0;
+    if (socket4 != ENET_SOCKET_NULL)
+        maxSocket = socket4;
+    if (socket6 != ENET_SOCKET_NULL && socket6 > maxSocket)
+        maxSocket = socket6;
+
+    selectCount = select (maxSocket + 1, & readSet, & writeSet, NULL, & timeVal);
+
+    if (selectCount < 0)
+      return -1;
+
+    * condition = ENET_SOCKET_WAIT_NONE;
+
+    if (selectCount == 0)
+      return 0;
+
+    if ( (socket4 != ENET_SOCKET_NULL && FD_ISSET (socket4, & writeSet)) ||
+        (socket6 != ENET_SOCKET_NULL && FD_ISSET (socket6, & writeSet)) )
+        * condition |= ENET_SOCKET_WAIT_SEND;
+
+    if ( (socket4 != ENET_SOCKET_NULL && FD_ISSET (socket4, & readSet)) ||
+        (socket6 != ENET_SOCKET_NULL && FD_ISSET (socket6, & readSet)) )
+        * condition |= ENET_SOCKET_WAIT_RECEIVE;
+
+    return 0;
+}
+
+#endif
+
Index: /code/trunk/src/external/enet/win32.h
===================================================================
--- /code/trunk/src/external/enet/win32.h	(revision 7459)
+++ /code/trunk/src/external/enet/win32.h	(revision 7459)
@@ -0,0 +1,63 @@
+/** 
+ @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 <stdlib.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+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))
+
+#ifndef AI_ADDRCONFIG
+#define AI_ADDRCONFIG 0x0400 /* AI_ADDRCONFIG is not defined everywhere */
+#endif
+
+#endif /* __ENET_WIN32_H__ */
+
+
Index: /code/trunk/src/libraries/network/CMakeLists.txt
===================================================================
--- /code/trunk/src/libraries/network/CMakeLists.txt	(revision 7458)
+++ /code/trunk/src/libraries/network/CMakeLists.txt	(revision 7459)
@@ -71,5 +71,6 @@
   LINK_LIBRARIES
     ${ZLIB_LIBRARY}
-    ${ENET_LIBRARY}
+    #${ENET_LIBRARY}
+    enet_orxonox
     ${Boost_THREAD_LIBRARY}
     util
Index: /code/trunk/src/libraries/network/ClientConnection.cc
===================================================================
--- /code/trunk/src/libraries/network/ClientConnection.cc	(revision 7458)
+++ /code/trunk/src/libraries/network/ClientConnection.cc	(revision 7459)
@@ -48,5 +48,5 @@
     this->serverAddress_ = new ENetAddress();
     //set standard address and port
-    enet_address_set_host(this->serverAddress_, "127.0.0.1");
+    enet_address_set_host(this->serverAddress_, "127.0.0.1"); // TODO: check for IPv6 and connect to ::1 instead
     serverAddress_->port = NETWORK_PORT;
   }
@@ -59,5 +59,6 @@
 
   void ClientConnection::setServerAddress( const std::string& serverAddress ) {
-    enet_address_set_host (this->serverAddress_, serverAddress.c_str());
+    if (enet_address_set_host (this->serverAddress_, serverAddress.c_str()) < 0)
+        COUT(1) << "Error: Could not resolve \"" << serverAddress << "\"." << std::endl;
   }
 
@@ -70,15 +71,23 @@
     ENetEvent event;
 
-    this->host_ = enet_host_create(NULL, NETWORK_CLIENT_MAX_CONNECTIONS, 0, 0);
+    this->host_ = enet_host_create(NULL, NETWORK_CLIENT_MAX_CONNECTIONS, 0, 0, 0);
     if ( this->host_ == NULL )
     {
-      COUT(2) << "ClientConnection: host_ == NULL" << std::endl;
+      COUT(1) << "ClientConnection: host_ == NULL" << std::endl;
       // error handling
       return false;
     }
-    this->server_ = enet_host_connect(this->host_, serverAddress_, NETWORK_CLIENT_CHANNELS);
+    assert( this->host_->socket4 != ENET_SOCKET_NULL || this->host_->socket6 != ENET_SOCKET_NULL );
+    if (this->host_->socket4 == ENET_SOCKET_NULL)
+        COUT(2) << "Warning: IPv4 Socket failed." << std::endl;
+    else if (this->host_->socket6 == ENET_SOCKET_NULL)
+        COUT(2) << "Warning: IPv6 Socket failed." << std::endl;
+    else
+        COUT(3) << "Info: Using IPv4 and IPv6 Sockets." << std::endl;
+
+    this->server_ = enet_host_connect(this->host_, serverAddress_, NETWORK_CLIENT_CHANNELS, 0);
     if ( this->server_==NULL )
     {
-      COUT(2) << "ClientConnection: server == NULL" << std::endl;
+      COUT(1) << "ClientConnection: server_ == NULL" << std::endl;
       // error handling
       return false;
Index: /code/trunk/src/libraries/network/ClientInformation.cc
===================================================================
--- /code/trunk/src/libraries/network/ClientInformation.cc	(revision 7458)
+++ /code/trunk/src/libraries/network/ClientInformation.cc	(revision 7459)
@@ -216,5 +216,5 @@
     ClientInformation *temp = head_;
     while(temp!=0){
-      if(temp->getPeer()->address.host==peer->address.host && temp->getPeer()->address.port==peer->address.port)
+      if(!memcmp(& temp->getPeer()->address, & peer->address, sizeof(peer->address)))
         break;
       temp = temp->next();
@@ -252,5 +252,5 @@
     ClientInformation *temp = head_;
     while(temp!=0){
-      if(temp->getPeer()->address.host==address->host && temp->getPeer()->address.port == address->port)
+      if(!memcmp(& temp->getPeer()->address, address, sizeof(*address)))
         break;
       temp = temp->next();
Index: /code/trunk/src/libraries/network/LANDiscoverable.cc
===================================================================
--- /code/trunk/src/libraries/network/LANDiscoverable.cc	(revision 7458)
+++ /code/trunk/src/libraries/network/LANDiscoverable.cc	(revision 7459)
@@ -64,7 +64,12 @@
     if( bActive )
     {
-      ENetAddress bindAddress = { ENET_HOST_ANY, LAN_DISCOVERY_PORT };
+      ENetAddress bindAddress;
+      memset(& bindAddress, 0, sizeof(ENetAddress));
+      bindAddress.host = ENET_HOST_ANY;
+      bindAddress.port = LAN_DISCOVERY_PORT;
       assert( this->host_ == 0 );
-      this->host_ = enet_host_create( &bindAddress, 10, 0, 0 );
+      this->host_ = enet_host_create( &bindAddress, 10, 0, 0, 0 );
+      if ( this->host_ == NULL )
+          COUT(1) << "LANDiscoverable: host_ == NULL" << std::endl;
     }
     else
@@ -89,4 +94,6 @@
       {
         case ENET_EVENT_TYPE_CONNECT:
+            COUT(4) << "Received LAN discovery connect from client " << event.peer->host->receivedAddress << std::endl;
+            break;
         case ENET_EVENT_TYPE_DISCONNECT:
         case ENET_EVENT_TYPE_NONE:
@@ -95,4 +102,5 @@
           if( strcmp( LAN_DISCOVERY_MESSAGE, (char*)event.packet->data ) == 0 )      // check for a suitable orxonox client
           {
+            COUT(3) << "Received LAN discovery message from client " << event.peer->host->receivedAddress << std::endl;
             packet::ServerInformation info;
             info.setServerName("Orxonox Server");
Index: /code/trunk/src/libraries/network/LANDiscovery.cc
===================================================================
--- /code/trunk/src/libraries/network/LANDiscovery.cc	(revision 7458)
+++ /code/trunk/src/libraries/network/LANDiscovery.cc	(revision 7459)
@@ -42,5 +42,7 @@
   LANDiscovery::LANDiscovery()
   {
-    this->host_ = enet_host_create(NULL, 10, 0, 0 );
+    this->host_ = enet_host_create(NULL, 10, 0, 0, 0 );
+    if ( this->host_ == NULL )
+        COUT(1) << "LANDiscovery: host_ == NULL" << std::endl;
   }
 
@@ -53,10 +55,21 @@
   {
     this->servers_.clear();
+    ENetPeer* peer;
     ENetAddress address;
-    enet_address_set_host(&address, "255.255.255.255");
+    memset(&address, 0, sizeof(ENetAddress));
     address.port = LAN_DISCOVERY_PORT;
 
-    ENetPeer* peer;
-    peer = enet_host_connect(this->host_, &address, 0);
+    /* TODO: check for availability of each protocol */
+    /* IPv4 */
+    address.host = ENET_HOST_BROADCAST;
+    peer = enet_host_connect(this->host_, &address, 0, 0);
+    if (peer == NULL)
+        COUT(1) << "Error: Could not send LAN discovery to IPv4 Broadcast." << std::endl;
+
+    /* IPv6 */
+    enet_address_set_host(&address, "ff02::1"); // TODO: use a multicast group
+    peer = enet_host_connect(this->host_, &address, 0, 0);
+    if (peer == NULL)
+        COUT(1) << "Error: Could not send LAN discovery to IPv6 Multicast." << std::endl;
 
     ENetEvent event;
@@ -67,5 +80,5 @@
         case ENET_EVENT_TYPE_CONNECT:
         {
-          COUT(0) << "connect from server: " << event.peer->address.host << endl;
+          COUT(4) << "Received LAN discovery connect from server " << event.peer->host->receivedAddress << std::endl;
           ENetPacket* packet = enet_packet_create(LAN_DISCOVERY_MESSAGE, strlen(LAN_DISCOVERY_MESSAGE)+1, ENET_PACKET_FLAG_RELIABLE);
           enet_peer_send(event.peer, 0, packet);
@@ -75,5 +88,5 @@
           {
             packet::ServerInformation info(&event);
-            COUT(0) << "received server information; name: " << info.getServerName() << ", IP: " << info.getServerIP() << ", RTT: " << info.getServerRTT() << endl;
+            COUT(3) << "Received LAN discovery server information; Name: " << info.getServerName() << ", Address: " << info.getServerIP() << ", RTT: " << info.getServerRTT() << endl;
             std::vector<packet::ServerInformation>::iterator it;
             for( it=this->servers_.begin(); it!=this->servers_.end(); ++it )
Index: /code/trunk/src/libraries/network/ServerConnection.cc
===================================================================
--- /code/trunk/src/libraries/network/ServerConnection.cc	(revision 7458)
+++ /code/trunk/src/libraries/network/ServerConnection.cc	(revision 7459)
@@ -44,4 +44,5 @@
   {
     this->bindAddress_ = new ENetAddress();
+    memset(this->bindAddress_, 0, sizeof(ENetAddress));
     this->bindAddress_->host = ENET_HOST_ANY;
     this->bindAddress_->port = NETWORK_PORT;
@@ -55,5 +56,6 @@
 
   void ServerConnection::setBindAddress( const std::string& bindAddress ) {
-    enet_address_set_host (this->bindAddress_, bindAddress.c_str());
+    if (enet_address_set_host (this->bindAddress_, bindAddress.c_str()) < 0)
+        COUT(1) << "Error: Could not resolve \"" << bindAddress << "\"." << std::endl;
   }
 
@@ -63,9 +65,19 @@
 
   bool ServerConnection::openListener() {
-    this->host_ = enet_host_create(this->bindAddress_, NETWORK_MAX_CONNECTIONS, 0, 0);
+    this->host_ = enet_host_create(this->bindAddress_, NETWORK_MAX_CONNECTIONS, 0, 0, 0);
     if ( this->host_ == NULL )
-      return false;
+    {
+        COUT(1) << "ServerConnection: host_ == NULL" << std::endl;
+        return false;
+    }
+    assert( this->host_->socket4 != ENET_SOCKET_NULL || this->host_->socket6 != ENET_SOCKET_NULL );
+    if (this->host_->socket4 == ENET_SOCKET_NULL)
+        COUT(2) << "Warning: IPv4 Socket failed." << std::endl;
+    else if (this->host_->socket6 == ENET_SOCKET_NULL)
+        COUT(2) << "Warning: IPv6 Socket failed." << std::endl;
     else
-      return true;
+        COUT(3) << "Info: Using IPv4 and IPv6 Sockets." << std::endl;
+
+    return true;
   }
 
Index: /code/trunk/src/libraries/network/packet/ServerInformation.cc
===================================================================
--- /code/trunk/src/libraries/network/packet/ServerInformation.cc	(revision 7458)
+++ /code/trunk/src/libraries/network/packet/ServerInformation.cc	(revision 7459)
@@ -47,9 +47,10 @@
     ServerInformation::ServerInformation(ENetEvent* event)
     {
+      char serverIP[64];
+
       // Save Server Round Trip Time
       this->serverRTT_ = event->peer->roundTripTime;
-      // Save Server IP
-      char* serverIP = new char[16];
-      enet_address_get_host_ip(&event->peer->address, serverIP, 16);
+      // Save Server Address, leave some space for scope ID
+      enet_address_get_host_ip(&event->peer->address, serverIP, 64);
       this->serverIP_ = std::string(serverIP);
       // Save ACK
@@ -83,4 +84,12 @@
   
   } // namespace packet
+
+  std::ostream& operator<<(std::ostream& out, const ENetAddress& address)
+  {
+      char addr[64];
+      if (!enet_address_get_host_ip(&address, addr, 64))
+          out << addr;
+      return out;
+  }
 } // namespace orxonox
 
Index: /code/trunk/src/libraries/network/packet/ServerInformation.h
===================================================================
--- /code/trunk/src/libraries/network/packet/ServerInformation.h	(revision 7458)
+++ /code/trunk/src/libraries/network/packet/ServerInformation.h	(revision 7459)
@@ -59,4 +59,6 @@
 
   }
+
+  _NetworkExport std::ostream& operator<<(std::ostream& out, const ENetAddress& address);
 }
 
