diff --git a/INSTALL b/INSTALL index 23e5f25..7d1c323 100644 --- a/INSTALL +++ b/INSTALL @@ -1,16 +1,25 @@ Installation Instructions ************************* -Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free -Software Foundation, Inc. +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007, 2008, 2009 Free Software Foundation, Inc. -This file is free documentation; the Free Software Foundation gives -unlimited permission to copy, distribute and modify it. + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. Basic Installation ================== -These are generic installation instructions. + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses @@ -23,9 +32,9 @@ debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves -the results of its tests to speed up reconfiguring. (Caching is +the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale -cache files.) +cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail @@ -35,30 +44,37 @@ some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create -`configure' by a program called `autoconf'. You only need -`configure.ac' if you want to change it or regenerate `configure' using -a newer version of `autoconf'. +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. -The simplest way to compile this package is: + The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type - `./configure' to configure the package for your system. If you're - using `csh' on an old version of System V, you might need to type - `sh ./configure' instead to prevent `csh' from trying to execute - `configure' itself. + `./configure' to configure the package for your system. - Running `configure' takes awhile. While running, it prints some - messages telling which features it is checking for. + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with - the package. + the package, generally using the just-built uninstalled binaries. 4. Type `make install' to install the programs and any data files and - documentation. - - 5. You can remove the program binaries and object files from the + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is @@ -67,45 +83,69 @@ The simplest way to compile this package is: all sorts of other programs in order to regenerate files that came with the distribution. + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + Compilers and Options ===================== -Some systems require unusual options for compilation or linking that the -`configure' script does not know about. Run `./configure --help' for -details on some of the pertinent environment variables. + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: - ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== -You can compile the package for more than one kind of computer at the + You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their -own directory. To do this, you must use a version of `make' that -supports the `VPATH' variable, such as GNU `make'. `cd' to the +own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the -source code in the directory that `configure' is in and in `..'. +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. - If you have to use a `make' that does not support the `VPATH' -variable, you have to compile the package for one architecture at a -time in the source code directory. After you have installed the -package for one architecture, use `make distclean' before reconfiguring -for another architecture. + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. Installation Names ================== -By default, `make install' installs the package's commands under + By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving -`configure' the option `--prefix=PREFIX'. +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you @@ -116,16 +156,47 @@ Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories -you can set and what kinds of files go in them. +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. -Optional Features -================= - -Some packages pay attention to `--enable-FEATURE' options to + Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The @@ -137,14 +208,53 @@ find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + Specifying the System Type ========================== -There may be some features `configure' cannot figure out automatically, -but needs to determine by the type of machine the package will run on. -Usually, assuming the package is built to be run on the _same_ -architectures, `configure' can figure that out, but if it prints a -message saying it cannot guess the machine type, give it the + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: @@ -152,7 +262,8 @@ type, such as `sun4', or a canonical name which has the form: where SYSTEM can have one of these forms: - OS KERNEL-OS + OS + KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't @@ -170,9 +281,9 @@ eventually be run) with `--host=TYPE'. Sharing Defaults ================ -If you want to set default values for `configure' scripts to share, you -can create a site shell script called `config.site' that gives default -values for variables like `CC', `cache_file', and `prefix'. + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. @@ -181,7 +292,7 @@ A warning: not all `configure' scripts look for a site script. Defining Variables ================== -Variables not defined in a site shell script can be set in the + Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set @@ -190,21 +301,29 @@ them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is -overridden in the site shell script). Here is a another example: +overridden in the site shell script). - /bin/bash ./configure CONFIG_SHELL=/bin/bash +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: -Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent -configuration-related scripts to be executed by `/bin/bash'. + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== -`configure' recognizes the following options to control how it operates. + `configure' recognizes the following options to control how it +operates. `--help' `-h' - Print a summary of the options to `configure', and exit. + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. `--version' `-V' @@ -231,6 +350,16 @@ configuration-related scripts to be executed by `/bin/bash'. Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. diff --git a/enet/ChangeLog b/enet/ChangeLog new file mode 100644 index 0000000..b1fc200 --- /dev/null +++ b/enet/ChangeLog @@ -0,0 +1,92 @@ +ENet 1.3.1 (February 10, 2011): + +* fixed bug in tracking of reliable data in transit +* reliable data window size now scales with the throttle +* fixed bug in fragment length calculation when checksums are used + +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 + + diff --git a/enet/LICENSE b/enet/LICENSE index e9b9895..357a4e5 100644 --- a/enet/LICENSE +++ b/enet/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2002 Lee Salzman +Copyright (c) 2002-2011 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: diff --git a/enet/Makefile.am b/enet/Makefile.am index 5b9caf3..37d8005 100644 --- a/enet/Makefile.am +++ b/enet/Makefile.am @@ -1,5 +1,5 @@ lib_LIBRARIES = libenet.a -libenet_a_SOURCES = host.c list.c callbacks.c packet.c peer.c protocol.c unix.c win32.c +libenet_a_SOURCES = callbacks.c compress.c host.c list.c packet.c peer.c protocol.c unix.c win32.c INCLUDES = -Iinclude/ SUBDIRS = include diff --git a/enet/README b/enet/README index f56cfde..7f7a0ad 100644 --- a/enet/README +++ b/enet/README @@ -6,9 +6,10 @@ is: # Generate the build system. -aclocal && automake -a -c --foreign && autoconf +autoreconf -vfi # Compile and install the library. ./configure && make && make install + diff --git a/enet/callbacks.c b/enet/callbacks.c index 7f960af..f941282 100644 --- a/enet/callbacks.c +++ b/enet/callbacks.c @@ -5,12 +5,12 @@ #define ENET_BUILDING_LIB 1 #include "enet/enet.h" -static ENetCallbacks callbacks = { malloc, free, rand }; +static ENetCallbacks callbacks = { malloc, free, abort }; int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits) { - if (version != ENET_VERSION) + if (version < ENET_VERSION_CREATE (1, 3, 0)) return -1; if (inits -> malloc != NULL || inits -> free != NULL) @@ -22,8 +22,8 @@ enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits callbacks.free = inits -> free; } - if (inits -> rand != NULL) - callbacks.rand = inits -> rand; + if (inits -> no_memory != NULL) + callbacks.no_memory = inits -> no_memory; return enet_initialize (); } @@ -34,7 +34,7 @@ enet_malloc (size_t size) void * memory = callbacks.malloc (size); if (memory == NULL) - abort (); + callbacks.no_memory (); return memory; } @@ -45,9 +45,3 @@ enet_free (void * memory) callbacks.free (memory); } -int -enet_rand (void) -{ - return callbacks.rand (); -} - diff --git a/enet/compress.c b/enet/compress.c new file mode 100644 index 0000000..784489a --- /dev/null +++ b/enet/compress.c @@ -0,0 +1,654 @@ +/** + @file compress.c + @brief An adaptive order-2 PPM range coder +*/ +#define ENET_BUILDING_LIB 1 +#include +#include "enet/enet.h" + +typedef struct _ENetSymbol +{ + /* binary indexed tree of symbols */ + enet_uint8 value; + enet_uint8 count; + enet_uint16 under; + enet_uint16 left, right; + + /* context defined by this symbol */ + enet_uint16 symbols; + enet_uint16 escapes; + enet_uint16 total; + enet_uint16 parent; +} ENetSymbol; + +/* adaptation constants tuned aggressively for small packet sizes rather than large file compression */ +enum +{ + ENET_RANGE_CODER_TOP = 1<<24, + ENET_RANGE_CODER_BOTTOM = 1<<16, + + ENET_CONTEXT_SYMBOL_DELTA = 3, + ENET_CONTEXT_SYMBOL_MINIMUM = 1, + ENET_CONTEXT_ESCAPE_MINIMUM = 1, + + ENET_SUBCONTEXT_ORDER = 2, + ENET_SUBCONTEXT_SYMBOL_DELTA = 2, + ENET_SUBCONTEXT_ESCAPE_DELTA = 5 +}; + +/* context exclusion roughly halves compression speed, so disable for now */ +#undef ENET_CONTEXT_EXCLUSION + +typedef struct _ENetRangeCoder +{ + /* only allocate enough symbols for reasonable MTUs, would need to be larger for large file compression */ + ENetSymbol symbols[4096]; +} ENetRangeCoder; + +void * +enet_range_coder_create (void) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) enet_malloc (sizeof (ENetRangeCoder)); + if (rangeCoder == NULL) + return NULL; + + return rangeCoder; +} + +void +enet_range_coder_destroy (void * context) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + if (rangeCoder == NULL) + return; + + enet_free (rangeCoder); +} + +#define ENET_SYMBOL_CREATE(symbol, value_, count_) \ +{ \ + symbol = & rangeCoder -> symbols [nextSymbol ++]; \ + symbol -> value = value_; \ + symbol -> count = count_; \ + symbol -> under = count_; \ + symbol -> left = 0; \ + symbol -> right = 0; \ + symbol -> symbols = 0; \ + symbol -> escapes = 0; \ + symbol -> total = 0; \ + symbol -> parent = 0; \ +} + +#define ENET_CONTEXT_CREATE(context, escapes_, minimum) \ +{ \ + ENET_SYMBOL_CREATE (context, 0, 0); \ + (context) -> escapes = escapes_; \ + (context) -> total = escapes_ + 256*minimum; \ + (context) -> symbols = 0; \ +} + +static enet_uint16 +enet_symbol_rescale (ENetSymbol * symbol) +{ + enet_uint16 total = 0; + for (;;) + { + symbol -> count -= symbol->count >> 1; + symbol -> under = symbol -> count; + if (symbol -> left) + symbol -> under += enet_symbol_rescale (symbol + symbol -> left); + total += symbol -> under; + if (! symbol -> right) break; + symbol += symbol -> right; + } + return total; +} + +#define ENET_CONTEXT_RESCALE(context, minimum) \ +{ \ + (context) -> total = (context) -> symbols ? enet_symbol_rescale ((context) + (context) -> symbols) : 0; \ + (context) -> escapes -= (context) -> escapes >> 1; \ + (context) -> total += (context) -> escapes + 256*minimum; \ +} + +#define ENET_RANGE_CODER_OUTPUT(value) \ +{ \ + if (outData >= outEnd) \ + return 0; \ + * outData ++ = value; \ +} + +#define ENET_RANGE_CODER_ENCODE(under, count, total) \ +{ \ + encodeRange /= (total); \ + encodeLow += (under) * encodeRange; \ + encodeRange *= (count); \ + for (;;) \ + { \ + if((encodeLow ^ (encodeLow + encodeRange)) >= ENET_RANGE_CODER_TOP) \ + { \ + if(encodeRange >= ENET_RANGE_CODER_BOTTOM) break; \ + encodeRange = -encodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \ + } \ + ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \ + encodeRange <<= 8; \ + encodeLow <<= 8; \ + } \ +} + +#define ENET_RANGE_CODER_FLUSH \ +{ \ + while (encodeLow) \ + { \ + ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \ + encodeLow <<= 8; \ + } \ +} + +#define ENET_RANGE_CODER_FREE_SYMBOLS \ +{ \ + if (nextSymbol >= sizeof (rangeCoder -> symbols) / sizeof (ENetSymbol) - ENET_SUBCONTEXT_ORDER ) \ + { \ + nextSymbol = 0; \ + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); \ + predicted = 0; \ + order = 0; \ + } \ +} + +#define ENET_CONTEXT_ENCODE(context, symbol_, value_, under_, count_, update, minimum) \ +{ \ + under_ = value*minimum; \ + count_ = minimum; \ + if (! (context) -> symbols) \ + { \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + (context) -> symbols = symbol_ - (context); \ + } \ + else \ + { \ + ENetSymbol * node = (context) + (context) -> symbols; \ + for (;;) \ + { \ + if (value_ < node -> value) \ + { \ + node -> under += update; \ + if (node -> left) { node += node -> left; continue; } \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> left = symbol_ - node; \ + } \ + else \ + if (value_ > node -> value) \ + { \ + under_ += node -> under; \ + if (node -> right) { node += node -> right; continue; } \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> right = symbol_ - node; \ + } \ + else \ + { \ + count_ += node -> count; \ + under_ += node -> under - node -> count; \ + node -> under += update; \ + node -> count += update; \ + symbol_ = node; \ + } \ + break; \ + } \ + } \ +} + +#ifdef ENET_CONTEXT_EXCLUSION +static const ENetSymbol emptyContext = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +#define ENET_CONTEXT_WALK(context, body) \ +{ \ + const ENetSymbol * node = (context) + (context) -> symbols; \ + const ENetSymbol * stack [256]; \ + size_t stackSize = 0; \ + while (node -> left) \ + { \ + stack [stackSize ++] = node; \ + node += node -> left; \ + } \ + for (;;) \ + { \ + body; \ + if (node -> right) \ + { \ + node += node -> right; \ + while (node -> left) \ + { \ + stack [stackSize ++] = node; \ + node += node -> left; \ + } \ + } \ + else \ + if (stackSize <= 0) \ + break; \ + else \ + node = stack [-- stackSize]; \ + } \ +} + +#define ENET_CONTEXT_ENCODE_EXCLUDE(context, value_, under, total, minimum) \ +ENET_CONTEXT_WALK(context, { \ + if (node -> value != value_) \ + { \ + enet_uint16 parentCount = rangeCoder -> symbols [node -> parent].count + minimum; \ + if (node -> value < value_) \ + under -= parentCount; \ + total -= parentCount; \ + } \ +}) +#endif + +size_t +enet_range_coder_compress (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + enet_uint8 * outStart = outData, * outEnd = & outData [outLimit]; + const enet_uint8 * inData, * inEnd; + enet_uint32 encodeLow = 0, encodeRange = ~0; + ENetSymbol * root; + enet_uint16 predicted = 0; + size_t order = 0, nextSymbol = 0; + + if (rangeCoder == NULL || inBufferCount <= 0 || inLimit <= 0) + return 0; + + inData = (const enet_uint8 *) inBuffers -> data; + inEnd = & inData [inBuffers -> dataLength]; + inBuffers ++; + inBufferCount --; + + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); + + for (;;) + { + ENetSymbol * subcontext, * symbol; +#ifdef ENET_CONTEXT_EXCLUSION + const ENetSymbol * childContext = & emptyContext; +#endif + enet_uint8 value; + enet_uint16 count, under, * parent = & predicted, total; + if (inData >= inEnd) + { + if (inBufferCount <= 0) + break; + inData = (const enet_uint8 *) inBuffers -> data; + inEnd = & inData [inBuffers -> dataLength]; + inBuffers ++; + inBufferCount --; + } + value = * inData ++; + + for (subcontext = & rangeCoder -> symbols [predicted]; + subcontext != root; +#ifdef ENET_CONTEXT_EXCLUSION + childContext = subcontext, +#endif + subcontext = & rangeCoder -> symbols [subcontext -> parent]) + { + ENET_CONTEXT_ENCODE (subcontext, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + total = subcontext -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA) + ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, 0); +#endif + if (count > 0) + { + ENET_RANGE_CODER_ENCODE (subcontext -> escapes + under, count, total); + } + else + { + if (subcontext -> escapes > 0 && subcontext -> escapes < total) + ENET_RANGE_CODER_ENCODE (0, subcontext -> escapes, total); + subcontext -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA; + subcontext -> total += ENET_SUBCONTEXT_ESCAPE_DELTA; + } + subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (subcontext, 0); + if (count > 0) goto nextInput; + } + + ENET_CONTEXT_ENCODE (root, symbol, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + total = root -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA) + ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, ENET_CONTEXT_SYMBOL_MINIMUM); +#endif + ENET_RANGE_CODER_ENCODE (root -> escapes + under, count, total); + root -> total += ENET_CONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM); + + nextInput: + if (order >= ENET_SUBCONTEXT_ORDER) + predicted = rangeCoder -> symbols [predicted].parent; + else + order ++; + ENET_RANGE_CODER_FREE_SYMBOLS; + } + + ENET_RANGE_CODER_FLUSH; + + return (size_t) (outData - outStart); +} + +#define ENET_RANGE_CODER_SEED \ +{ \ + if (inData < inEnd) decodeCode |= * inData ++ << 24; \ + if (inData < inEnd) decodeCode |= * inData ++ << 16; \ + if (inData < inEnd) decodeCode |= * inData ++ << 8; \ + if (inData < inEnd) decodeCode |= * inData ++; \ +} + +#define ENET_RANGE_CODER_READ(total) ((decodeCode - decodeLow) / (decodeRange /= (total))) + +#define ENET_RANGE_CODER_DECODE(under, count, total) \ +{ \ + decodeLow += (under) * decodeRange; \ + decodeRange *= (count); \ + for (;;) \ + { \ + if((decodeLow ^ (decodeLow + decodeRange)) >= ENET_RANGE_CODER_TOP) \ + { \ + if(decodeRange >= ENET_RANGE_CODER_BOTTOM) break; \ + decodeRange = -decodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \ + } \ + decodeCode <<= 8; \ + if (inData < inEnd) \ + decodeCode |= * inData ++; \ + decodeRange <<= 8; \ + decodeLow <<= 8; \ + } \ +} + +#define ENET_CONTEXT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, createRoot, visitNode, createRight, createLeft) \ +{ \ + under_ = 0; \ + count_ = minimum; \ + if (! (context) -> symbols) \ + { \ + createRoot; \ + } \ + else \ + { \ + ENetSymbol * node = (context) + (context) -> symbols; \ + for (;;) \ + { \ + enet_uint16 after = under_ + node -> under + (node -> value + 1)*minimum, before = node -> count + minimum; \ + visitNode; \ + if (code >= after) \ + { \ + under_ += node -> under; \ + if (node -> right) { node += node -> right; continue; } \ + createRight; \ + } \ + else \ + if (code < after - before) \ + { \ + node -> under += update; \ + if (node -> left) { node += node -> left; continue; } \ + createLeft; \ + } \ + else \ + { \ + value_ = node -> value; \ + count_ += node -> count; \ + under_ = after - before; \ + node -> under += update; \ + node -> count += update; \ + symbol_ = node; \ + } \ + break; \ + } \ + } \ +} + +#define ENET_CONTEXT_TRY_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \ +ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, return 0, exclude (node -> value, after, before), return 0, return 0) + +#define ENET_CONTEXT_ROOT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \ +ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, \ + { \ + value_ = code / minimum; \ + under_ = code - code%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + (context) -> symbols = symbol_ - (context); \ + }, \ + exclude (node -> value, after, before), \ + { \ + value_ = node->value + 1 + (code - after)/minimum; \ + under_ = code - (code - after)%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> right = symbol_ - node; \ + }, \ + { \ + value_ = node->value - 1 - (after - before - code - 1)/minimum; \ + under_ = code - (after - before - code - 1)%minimum; \ + ENET_SYMBOL_CREATE (symbol_, value_, update); \ + node -> left = symbol_ - node; \ + }) \ + +#ifdef ENET_CONTEXT_EXCLUSION +typedef struct _ENetExclude +{ + enet_uint8 value; + enet_uint16 under; +} ENetExclude; + +#define ENET_CONTEXT_DECODE_EXCLUDE(context, total, minimum) \ +{ \ + enet_uint16 under = 0; \ + nextExclude = excludes; \ + ENET_CONTEXT_WALK (context, { \ + under += rangeCoder -> symbols [node -> parent].count + minimum; \ + nextExclude -> value = node -> value; \ + nextExclude -> under = under; \ + nextExclude ++; \ + }); \ + total -= under; \ +} + +#define ENET_CONTEXT_EXCLUDED(value_, after, before) \ +{ \ + size_t low = 0, high = nextExclude - excludes; \ + for(;;) \ + { \ + size_t mid = (low + high) >> 1; \ + const ENetExclude * exclude = & excludes [mid]; \ + if (value_ < exclude -> value) \ + { \ + if (low + 1 < high) \ + { \ + high = mid; \ + continue; \ + } \ + if (exclude > excludes) \ + after -= exclude [-1].under; \ + } \ + else \ + { \ + if (value_ > exclude -> value) \ + { \ + if (low + 1 < high) \ + { \ + low = mid; \ + continue; \ + } \ + } \ + else \ + before = 0; \ + after -= exclude -> under; \ + } \ + break; \ + } \ +} +#endif + +#define ENET_CONTEXT_NOT_EXCLUDED(value_, after, before) + +size_t +enet_range_coder_decompress (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit) +{ + ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context; + enet_uint8 * outStart = outData, * outEnd = & outData [outLimit]; + const enet_uint8 * inEnd = & inData [inLimit]; + enet_uint32 decodeLow = 0, decodeCode = 0, decodeRange = ~0; + ENetSymbol * root; + enet_uint16 predicted = 0; + size_t order = 0, nextSymbol = 0; +#ifdef ENET_CONTEXT_EXCLUSION + ENetExclude excludes [256]; + ENetExclude * nextExclude = excludes; +#endif + + if (rangeCoder == NULL || inLimit <= 0) + return 0; + + ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); + + ENET_RANGE_CODER_SEED; + + for (;;) + { + ENetSymbol * subcontext, * symbol, * patch; +#ifdef ENET_CONTEXT_EXCLUSION + const ENetSymbol * childContext = & emptyContext; +#endif + enet_uint8 value = 0; + enet_uint16 code, under, count, bottom, * parent = & predicted, total; + + for (subcontext = & rangeCoder -> symbols [predicted]; + subcontext != root; +#ifdef ENET_CONTEXT_EXCLUSION + childContext = subcontext, +#endif + subcontext = & rangeCoder -> symbols [subcontext -> parent]) + { + if (subcontext -> escapes <= 0) + continue; + total = subcontext -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, 0); +#endif + if (subcontext -> escapes >= total) + continue; + code = ENET_RANGE_CODER_READ (total); + if (code < subcontext -> escapes) + { + ENET_RANGE_CODER_DECODE (0, subcontext -> escapes, total); + continue; + } + code -= subcontext -> escapes; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + { + ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_EXCLUDED); + } + else +#endif + { + ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_NOT_EXCLUDED); + } + bottom = symbol - rangeCoder -> symbols; + ENET_RANGE_CODER_DECODE (subcontext -> escapes + under, count, total); + subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (subcontext, 0); + goto patchContexts; + } + + total = root -> total; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, ENET_CONTEXT_SYMBOL_MINIMUM); +#endif + code = ENET_RANGE_CODER_READ (total); + if (code < root -> escapes) + { + ENET_RANGE_CODER_DECODE (0, root -> escapes, total); + break; + } + code -= root -> escapes; +#ifdef ENET_CONTEXT_EXCLUSION + if (childContext -> total > 0) + { + ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_EXCLUDED); + } + else +#endif + { + ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_NOT_EXCLUDED); + } + bottom = symbol - rangeCoder -> symbols; + ENET_RANGE_CODER_DECODE (root -> escapes + under, count, total); + root -> total += ENET_CONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM); + + patchContexts: + for (patch = & rangeCoder -> symbols [predicted]; + patch != subcontext; + patch = & rangeCoder -> symbols [patch -> parent]) + { + ENET_CONTEXT_ENCODE (patch, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0); + * parent = symbol - rangeCoder -> symbols; + parent = & symbol -> parent; + if (count <= 0) + { + patch -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA; + patch -> total += ENET_SUBCONTEXT_ESCAPE_DELTA; + } + patch -> total += ENET_SUBCONTEXT_SYMBOL_DELTA; + if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || patch -> total > ENET_RANGE_CODER_BOTTOM - 0x100) + ENET_CONTEXT_RESCALE (patch, 0); + } + * parent = bottom; + + ENET_RANGE_CODER_OUTPUT (value); + + if (order >= ENET_SUBCONTEXT_ORDER) + predicted = rangeCoder -> symbols [predicted].parent; + else + order ++; + ENET_RANGE_CODER_FREE_SYMBOLS; + } + + return (size_t) (outData - outStart); +} + +/** @defgroup host ENet host functions + @{ +*/ + +/** Sets the packet compressor the host should use to the default range coder. + @param host host to enable the range coder for + @returns 0 on success, < 0 on failure +*/ +int +enet_host_compress_with_range_coder (ENetHost * host) +{ + ENetCompressor compressor; + memset (& compressor, 0, sizeof (compressor)); + compressor.context = enet_range_coder_create(); + if (compressor.context == NULL) + return -1; + compressor.compress = enet_range_coder_compress; + compressor.decompress = enet_range_coder_decompress; + compressor.destroy = enet_range_coder_destroy; + enet_host_compress (host, & compressor); + return 0; +} + +/** @} */ + + diff --git a/enet/docs/install.dox b/enet/docs/install.dox index 2f0ae1b..f5e46fb 100644 --- a/enet/docs/install.dox +++ b/enet/docs/install.dox @@ -7,7 +7,17 @@ SourceDistro. @section Unix Unix-like Operating Systems -[to be completed] +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 @@ -17,15 +27,28 @@ is linked in. @section Windows Microsoft Windows -Using MSVC 6 under Windows simply drag all the ENet source files into -your main project or, better yet, create a new static library project -and make your executable dependent (Project|Dependencies) on ENet. -There is also an enet.dsp provided. +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 to your library list (Project Settings | Link | +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 diff --git a/enet/docs/license.dox b/enet/docs/license.dox index a72c6ea..c0fffb4 100644 --- a/enet/docs/license.dox +++ b/enet/docs/license.dox @@ -1,7 +1,7 @@ /** @page License License -Copyright (c) 2002 Lee Salzman +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 diff --git a/enet/docs/mainpage.dox b/enet/docs/mainpage.dox index 813b657..1ea5b4e 100644 --- a/enet/docs/mainpage.dox +++ b/enet/docs/mainpage.dox @@ -7,10 +7,10 @@ network communication layer on top of UDP (User Datagram Protocol). The primary feature it provides is optional reliable, in-order delivery of packets. -ENet is NOT intended to be a general purpose high level networking -library that handles authentication, lobbying, server discovery, -compression, encryption and other high level, often application level -or dependent tasks. +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 @@ -22,6 +22,8 @@ or dependent tasks. @ref MailingList +@ref IRCChannel + @ref FAQ @ref License @@ -34,7 +36,8 @@ or dependent tasks. 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.0) can be downloaded here. +The most recent stable release (1.3.1) can be downloaded here. +The last release that is protocol compatible with the 1.2 series or earlier (1.2.3) can be downloaded here To access ENet via anonymous CVS, you must use the CVSROOT :pserver:anonymous\@bespin.org:/var/lib/cvs/enet with an empty @@ -59,9 +62,14 @@ sent via email to @ref MailingList. /** @page MailingList ENet Mailing List -The -enet-discuss list is for discussion of ENet, including bug reports -or feature requests. +The enet-discuss 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. + +*/ + diff --git a/enet/docs/tutorial.dox b/enet/docs/tutorial.dox index 7829d6c..dd911d3 100644 --- a/enet/docs/tutorial.dox +++ b/enet/docs/tutorial.dox @@ -17,11 +17,17 @@ @section Initialization Initialization +You should include the file when using ENet. Do not +include 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 + int main (int argc, char ** argv) { @@ -67,6 +73,7 @@ and the resources used by the host will be freed. 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) @@ -94,6 +101,7 @@ may be simultaneously open. 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 */); @@ -315,7 +323,7 @@ ENET_EVENT_TYPE_DISCONNECT will be generated. address.port = 1234; /* Initiate the connection, allocating the two channels 0 and 1. */ - peer = enet_host_connect (client, & address, 2); + peer = enet_host_connect (client, & address, 2, 0); if (peer == NULL) { diff --git a/enet/enet.dsp b/enet/enet.dsp index d5b6df0..dce4537 100644 --- a/enet/enet.dsp +++ b/enet/enet.dsp @@ -42,7 +42,7 @@ RSC=rc.exe # PROP Target_Dir "" MTL=midl.exe # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c -# ADD CPP /nologo /W3 /O2 /I "include/enet" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c +# ADD CPP /nologo /W3 /O2 /I "include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" @@ -62,12 +62,12 @@ LIB32=link.exe -lib # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 -# PROP Output_Dir "\temp\enet\Debug" -# PROP Intermediate_Dir "\temp\enet\Debug" +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" # PROP Target_Dir "" MTL=midl.exe # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c -# ADD CPP /nologo /G6 /MTd /W3 /ZI /Od /I "include/enet" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /c +# ADD CPP /nologo /G6 /MTd /W3 /ZI /Od /I "include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" @@ -101,6 +101,10 @@ SOURCE=.\callbacks.c # End Source File # Begin Source File +SOURCE=.\compress.c +# End Source File +# Begin Source File + SOURCE=.\packet.c # End Source File # Begin Source File diff --git a/enet/enet_dll.cbp b/enet/enet_dll.cbp new file mode 100644 index 0000000..961274c --- /dev/null +++ b/enet/enet_dll.cbp @@ -0,0 +1,86 @@ + + + + + + diff --git a/enet/host.c b/enet/host.c index e5db56e..8bb2433 100644 --- a/enet/host.c +++ b/enet/host.c @@ -4,6 +4,7 @@ */ #define ENET_BUILDING_LIB 1 #include +#include #include "enet/enet.h" /** @defgroup host ENet host functions @@ -14,6 +15,7 @@ @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. @@ -25,45 +27,89 @@ at any given time. */ ENetHost * -enet_host_create (const ENetAddress * address, size_t peerCount, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) +enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth) { - ENetHost * host = (ENetHost *) enet_malloc (sizeof (ENetHost)); + ENetHost * host; ENetPeer * currentPeer; + 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)); - host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM, address); - if (host -> socket == ENET_SOCKET_NULL) + host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM); + if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0)) { + if (host -> socket != ENET_SOCKET_NULL) + enet_socket_destroy (host -> socket); + enet_free (host -> peers); enet_free (host); return NULL; } + enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE); + enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE); + if (address != NULL) host -> address = * address; + if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) + channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; + else + if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) + channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; + + host -> randomSeed = (enet_uint32) 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 -> lastServicedPeer = host -> peers; 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); @@ -71,10 +117,11 @@ enet_host_create (const ENetAddress * address, size_t peerCount, enet_uint32 inc 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; } @@ -95,6 +142,9 @@ enet_host_destroy (ENetHost * host) 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); } @@ -103,12 +153,13 @@ enet_host_destroy (ENetHost * 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_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount, enet_uint32 data) { ENetPeer * currentPeer; ENetChannel * channel; @@ -131,11 +182,13 @@ enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelC if (currentPeer >= & host -> peers [host -> peerCount]) return NULL; - currentPeer -> state = ENET_PEER_STATE_CONNECTING; - currentPeer -> address = * address; currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); + if (currentPeer -> channels == NULL) + return NULL; currentPeer -> channelCount = channelCount; - currentPeer -> challenge = (enet_uint32) enet_rand (); + currentPeer -> state = ENET_PEER_STATE_CONNECTING; + currentPeer -> address = * address; + currentPeer -> connectID = ++ host -> randomSeed; if (host -> outgoingBandwidth == 0) currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; @@ -157,18 +210,20 @@ enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelC channel -> outgoingReliableSequenceNumber = 0; channel -> outgoingUnreliableSequenceNumber = 0; channel -> incomingReliableSequenceNumber = 0; - channel -> incomingUnreliableSequenceNumber = 0; enet_list_clear (& channel -> incomingReliableCommands); enet_list_clear (& channel -> incomingUnreliableCommands); + + channel -> usedReliableWindows = 0; + memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); } - command.header.command = ENET_PROTOCOL_COMMAND_CONNECT; + command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; command.header.channelID = 0xFF; - command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE; - command.header.commandLength = sizeof (ENetProtocolConnect); command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID); - command.connect.mtu = ENET_HOST_TO_NET_16 (currentPeer -> mtu); + 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); @@ -176,7 +231,9 @@ enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelC 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; @@ -206,6 +263,39 @@ enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet) 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 @@ -243,7 +333,7 @@ enet_host_bandwidth_throttle (ENetHost * host) peer < & host -> peers [host -> peerCount]; ++ peer) { - if (peer -> state != ENET_PEER_STATE_CONNECTED) + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) continue; ++ peersTotal; @@ -276,7 +366,7 @@ enet_host_bandwidth_throttle (ENetHost * host) { enet_uint32 peerBandwidth; - if (peer -> state != ENET_PEER_STATE_CONNECTED || + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || peer -> incomingBandwidth == 0 || peer -> outgoingBandwidthThrottleEpoch == timeCurrent) continue; @@ -309,7 +399,7 @@ enet_host_bandwidth_throttle (ENetHost * host) peer < & host -> peers [host -> peerCount]; ++ peer) { - if (peer -> state != ENET_PEER_STATE_CONNECTED || + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || peer -> outgoingBandwidthThrottleEpoch == timeCurrent) continue; @@ -339,12 +429,12 @@ enet_host_bandwidth_throttle (ENetHost * host) peer < & host -> peers [host -> peerCount]; ++ peer) { - if (peer -> state != ENET_PEER_STATE_CONNECTED || + if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) || peer -> incomingBandwidthThrottleEpoch == timeCurrent) continue; if (peer -> outgoingBandwidth > 0 && - bandwidthLimit > peer -> outgoingBandwidth) + peer -> outgoingBandwidth >= bandwidthLimit) continue; peer -> incomingBandwidthThrottleEpoch = timeCurrent; @@ -359,13 +449,11 @@ enet_host_bandwidth_throttle (ENetHost * host) peer < & host -> peers [host -> peerCount]; ++ peer) { - if (peer -> state != ENET_PEER_STATE_CONNECTED) + if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) continue; - command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT; + command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; command.header.channelID = 0xFF; - command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE; - command.header.commandLength = sizeof (ENetProtocolBandwidthLimit); command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth); if (peer -> incomingBandwidthThrottleEpoch == timeCurrent) diff --git a/enet/include/enet/callbacks.h b/enet/include/enet/callbacks.h index be29ae0..340a4a9 100644 --- a/enet/include/enet/callbacks.h +++ b/enet/include/enet/callbacks.h @@ -7,11 +7,11 @@ #include -typedef struct +typedef struct _ENetCallbacks { void * (ENET_CALLBACK * malloc) (size_t size); void (ENET_CALLBACK * free) (void * memory); - int (ENET_CALLBACK * rand) (void); + void (ENET_CALLBACK * no_memory) (void); } ENetCallbacks; /** @defgroup callbacks ENet internal callbacks @@ -20,7 +20,6 @@ typedef struct */ extern void * enet_malloc (size_t); extern void enet_free (void *); -extern int enet_rand (void); /** @} */ diff --git a/enet/include/enet/enet.h b/enet/include/enet/enet.h index 9b32635..b572590 100644 --- a/enet/include/enet/enet.h +++ b/enet/include/enet/enet.h @@ -23,28 +23,42 @@ extern "C" #include "enet/list.h" #include "enet/callbacks.h" -typedef enum -{ - ENET_VERSION = 1 -} ENetVersion; +#define ENET_VERSION_MAJOR 1 +#define ENET_VERSION_MINOR 3 +#define ENET_VERSION_PATCH 1 +#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 +typedef enum _ENetSocketType { ENET_SOCKET_TYPE_STREAM = 1, ENET_SOCKET_TYPE_DATAGRAM = 2 } ENetSocketType; -typedef enum +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; + enum { ENET_HOST_ANY = 0, /**< specifies the default server host */ - ENET_HOST_BROADCAST = 0xFFFFFFFF /**< specifies a subnet-wide broadcast */ + ENET_HOST_BROADCAST = 0xFFFFFFFF, /**< specifies a subnet-wide broadcast */ + + ENET_PORT_ANY = 0 /**< specifies that a port should be automatically chosen */ }; /** @@ -72,7 +86,7 @@ typedef struct _ENetAddress @sa ENetPacket */ -typedef enum +typedef enum _ENetPacketFlag { /** packet must be received by the target peer and resend attempts should be * made until the packet is delivered */ @@ -80,9 +94,14 @@ typedef enum /** packet will not be sequenced with other packets * not supported for reliable packets */ - ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1) + 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. * @@ -94,15 +113,21 @@ typedef enum * * 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 */ + 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 @@ -115,13 +140,14 @@ typedef struct _ENetAcknowledgement typedef struct _ENetOutgoingCommand { ENetListNode outgoingCommandList; - enet_uint32 reliableSequenceNumber; - enet_uint32 unreliableSequenceNumber; + 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; @@ -129,8 +155,8 @@ typedef struct _ENetOutgoingCommand typedef struct _ENetIncomingCommand { ENetListNode incomingCommandList; - enet_uint32 reliableSequenceNumber; - enet_uint32 unreliableSequenceNumber; + enet_uint16 reliableSequenceNumber; + enet_uint16 unreliableSequenceNumber; ENetProtocol command; enet_uint32 fragmentCount; enet_uint32 fragmentsRemaining; @@ -138,16 +164,18 @@ typedef struct _ENetIncomingCommand ENetPacket * packet; } ENetIncomingCommand; -typedef enum +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_CONNECTED = 4, - ENET_PEER_STATE_DISCONNECTING = 5, - ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT = 6, - ENET_PEER_STATE_ZOMBIE = 7 + 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 @@ -157,6 +185,7 @@ typedef enum 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, @@ -174,15 +203,21 @@ enum ENET_PEER_TIMEOUT_MINIMUM = 5000, ENET_PEER_TIMEOUT_MAXIMUM = 30000, ENET_PEER_PING_INTERVAL = 500, - ENET_PEER_UNSEQUENCED_WINDOW_SIZE = 4 * 32 + 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_uint32 outgoingReliableSequenceNumber; - enet_uint32 outgoingUnreliableSequenceNumber; - enet_uint32 incomingReliableSequenceNumber; - enet_uint32 incomingUnreliableSequenceNumber; + enet_uint16 outgoingReliableSequenceNumber; + enet_uint16 outgoingUnreliableSequenceNumber; + enet_uint16 usedReliableWindows; + enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS]; + enet_uint16 incomingReliableSequenceNumber; ENetList incomingReliableCommands; ENetList incomingUnreliableCommands; } ENetChannel; @@ -194,10 +229,13 @@ typedef struct _ENetChannel */ typedef struct _ENetPeer { + ENetListNode dispatchList; struct _ENetHost * host; enet_uint16 outgoingPeerID; enet_uint16 incomingPeerID; - enet_uint32 challenge; + 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; @@ -231,24 +269,43 @@ typedef struct _ENetPeer 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_uint16 mtu; + enet_uint32 mtu; enet_uint32 windowSize; enet_uint32 reliableDataInTransit; - enet_uint32 outgoingReliableSequenceNumber; + enet_uint16 outgoingReliableSequenceNumber; ENetList acknowledgements; ENetList sentReliableCommands; ENetList sentUnreliableCommands; ENetList outgoingReliableCommands; ENetList outgoingUnreliableCommands; - enet_uint32 incomingUnsequencedGroup; - enet_uint32 outgoingUnsequencedGroup; + ENetList dispatchedCommands; + int needsDispatch; + enet_uint16 incomingUnsequencedGroup; + enet_uint16 outgoingUnsequencedGroup; enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32]; - enet_uint32 disconnectData; + 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. + * No fields should be modified unless otherwise stated. @sa enet_host_create() @sa enet_host_destroy() @@ -256,35 +313,50 @@ typedef struct _ENetPeer @sa enet_host_service() @sa enet_host_flush() @sa enet_host_broadcast() + @sa enet_host_compress() + @sa enet_host_compress_with_range_coder() + @sa enet_host_channel_limit() @sa enet_host_bandwidth_limit() @sa enet_host_bandwidth_throttle() */ typedef struct _ENetHost { - ENetSocket socket; - ENetAddress address; /**< Internet address of the host */ - enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ - enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ - enet_uint32 bandwidthThrottleEpoch; - enet_uint32 mtu; - int recalculateBandwidthLimits; - ENetPeer * peers; /**< array of peers allocated for this host */ - size_t peerCount; /**< number of peers allocated for this host */ - ENetPeer * lastServicedPeer; - size_t packetSize; - ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; - size_t commandCount; - ENetBuffer buffers [ENET_BUFFER_MAXIMUM]; - size_t bufferCount; - ENetAddress receivedAddress; - enet_uint8 receivedData [ENET_PROTOCOL_MAXIMUM_MTU]; - size_t receivedDataLength; + ENetSocket socket; + ENetAddress address; /**< Internet address of the host */ + enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */ + enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */ + enet_uint32 bandwidthThrottleEpoch; + enet_uint32 mtu; + enet_uint32 randomSeed; + int recalculateBandwidthLimits; + ENetPeer * peers; /**< array of peers allocated for this host */ + size_t peerCount; /**< number of peers allocated for this host */ + size_t channelLimit; /**< maximum number of channels allowed for connected peers */ + enet_uint32 serviceTime; + ENetList dispatchQueue; + int continueSending; + size_t packetSize; + enet_uint16 headerFlags; + ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS]; + size_t commandCount; + ENetBuffer buffers [ENET_BUFFER_MAXIMUM]; + size_t bufferCount; + ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */ + ENetCompressor compressor; + enet_uint8 packetData [2][ENET_PROTOCOL_MAXIMUM_MTU]; + ENetAddress receivedAddress; + enet_uint8 * receivedData; + size_t receivedDataLength; + enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */ + enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */ } ENetHost; /** * An ENet event type, as specified in @ref ENetEvent. */ -typedef enum +typedef enum _ENetEventType { /** no event occurred within the specified time limit */ ENET_EVENT_TYPE_NONE = 0, @@ -337,6 +409,13 @@ typedef struct _ENetEvent */ 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); /** @@ -361,15 +440,18 @@ ENET_API void enet_time_set (enet_uint32); /** @defgroup socket ENet socket functions @{ - @ingroup private */ -extern ENetSocket enet_socket_create (ENetSocketType, const ENetAddress *); -extern ENetSocket enet_socket_accept (ENetSocket, ENetAddress *); -extern int enet_socket_connect (ENetSocket, const ENetAddress *); -extern int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); -extern int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t); -extern int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); -extern void enet_socket_destroy (ENetSocket); +ENET_API ENetSocket enet_socket_create (ENetSocketType); +ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_listen (ENetSocket, int); +ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *); +ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *); +ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t); +ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t); +ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32); +ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int); +ENET_API void enet_socket_destroy (ENetSocket); +ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32); /** @} */ @@ -384,9 +466,19 @@ extern void enet_socket_destroy (ENetSocket); @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 ); +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 reserve lookup of the host field in the address parameter. +/** 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. @@ -394,35 +486,51 @@ ENET_API int enet_address_set_host (ENetAddress *address, const char *hostName ) @retval 0 on success @retval < 0 on failure */ -ENET_API int enet_address_get_host (const ENetAddress *address, char *hostName, size_t nameLength ); +ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength); /** @} */ -ENET_API ENetPacket * enet_packet_create (const void *dataContents, size_t dataLength, enet_uint32 flags); -ENET_API void enet_packet_destroy (ENetPacket *packet ); -ENET_API int enet_packet_resize (ENetPacket *packet, size_t dataLength ); - -ENET_API ENetHost * enet_host_create (const ENetAddress *address, size_t peerCount, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth ); -ENET_API void enet_host_destroy (ENetHost *host ); -ENET_API ENetPeer * enet_host_connect (ENetHost *host, const ENetAddress *address, size_t channelCount ); +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); +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_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 } diff --git a/enet/include/enet/list.h b/enet/include/enet/list.h index 99bc4ae..d7b2600 100644 --- a/enet/include/enet/list.h +++ b/enet/include/enet/list.h @@ -24,6 +24,7 @@ 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 *); diff --git a/enet/include/enet/protocol.h b/enet/include/enet/protocol.h index 6d4dae9..19f7e45 100644 --- a/enet/include/enet/protocol.h +++ b/enet/include/enet/protocol.h @@ -15,10 +15,11 @@ enum 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_CHANNEL_COUNT = 255, + ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF }; -typedef enum +typedef enum _ENetProtocolCommand { ENET_PROTOCOL_COMMAND_NONE = 0, ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, @@ -29,48 +30,63 @@ typedef enum ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, - ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 9, - ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 10, - ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 11 + 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 +typedef enum _ENetProtocolFlag { - ENET_PROTOCOL_FLAG_ACKNOWLEDGE = (1 << 0), - ENET_PROTOCOL_FLAG_UNSEQUENCED = (1 << 1) + 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; -typedef struct +#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_uint8 flags; - enet_uint8 commandCount; - enet_uint32 sentTime; - enet_uint32 challenge; -} ENetProtocolHeader; + enet_uint16 sentTime; +} ENET_PACKED ENetProtocolHeader; -typedef struct +typedef struct _ENetProtocolCommandHeader { enet_uint8 command; enet_uint8 channelID; - enet_uint8 flags; - enet_uint8 reserved; - enet_uint32 commandLength; - enet_uint32 reliableSequenceNumber; -} ENetProtocolCommandHeader; + enet_uint16 reliableSequenceNumber; +} ENET_PACKED ENetProtocolCommandHeader; -typedef struct +typedef struct _ENetProtocolAcknowledge { ENetProtocolCommandHeader header; - enet_uint32 receivedReliableSequenceNumber; - enet_uint32 receivedSentTime; -} ENetProtocolAcknowledge; + enet_uint16 receivedReliableSequenceNumber; + enet_uint16 receivedSentTime; +} ENET_PACKED ENetProtocolAcknowledge; -typedef struct +typedef struct _ENetProtocolConnect { ENetProtocolCommandHeader header; enet_uint16 outgoingPeerID; - enet_uint16 mtu; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; enet_uint32 windowSize; enet_uint32 channelCount; enet_uint32 incomingBandwidth; @@ -78,13 +94,17 @@ typedef struct enet_uint32 packetThrottleInterval; enet_uint32 packetThrottleAcceleration; enet_uint32 packetThrottleDeceleration; -} ENetProtocolConnect; + enet_uint32 connectID; + enet_uint32 data; +} ENET_PACKED ENetProtocolConnect; -typedef struct +typedef struct _ENetProtocolVerifyConnect { ENetProtocolCommandHeader header; enet_uint16 outgoingPeerID; - enet_uint16 mtu; + enet_uint8 incomingSessionID; + enet_uint8 outgoingSessionID; + enet_uint32 mtu; enet_uint32 windowSize; enet_uint32 channelCount; enet_uint32 incomingBandwidth; @@ -92,62 +112,67 @@ typedef struct enet_uint32 packetThrottleInterval; enet_uint32 packetThrottleAcceleration; enet_uint32 packetThrottleDeceleration; -} ENetProtocolVerifyConnect; + enet_uint32 connectID; +} ENET_PACKED ENetProtocolVerifyConnect; -typedef struct +typedef struct _ENetProtocolBandwidthLimit { ENetProtocolCommandHeader header; enet_uint32 incomingBandwidth; enet_uint32 outgoingBandwidth; -} ENetProtocolBandwidthLimit; +} ENET_PACKED ENetProtocolBandwidthLimit; -typedef struct +typedef struct _ENetProtocolThrottleConfigure { ENetProtocolCommandHeader header; enet_uint32 packetThrottleInterval; enet_uint32 packetThrottleAcceleration; enet_uint32 packetThrottleDeceleration; -} ENetProtocolThrottleConfigure; +} ENET_PACKED ENetProtocolThrottleConfigure; -typedef struct +typedef struct _ENetProtocolDisconnect { ENetProtocolCommandHeader header; enet_uint32 data; -} ENetProtocolDisconnect; +} ENET_PACKED ENetProtocolDisconnect; -typedef struct +typedef struct _ENetProtocolPing { ENetProtocolCommandHeader header; -} ENetProtocolPing; +} ENET_PACKED ENetProtocolPing; -typedef struct +typedef struct _ENetProtocolSendReliable { ENetProtocolCommandHeader header; -} ENetProtocolSendReliable; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendReliable; -typedef struct +typedef struct _ENetProtocolSendUnreliable { ENetProtocolCommandHeader header; - enet_uint32 unreliableSequenceNumber; -} ENetProtocolSendUnreliable; + enet_uint16 unreliableSequenceNumber; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnreliable; -typedef struct +typedef struct _ENetProtocolSendUnsequenced { ENetProtocolCommandHeader header; - enet_uint32 unsequencedGroup; -} ENetProtocolSendUnsequenced; + enet_uint16 unsequencedGroup; + enet_uint16 dataLength; +} ENET_PACKED ENetProtocolSendUnsequenced; -typedef struct +typedef struct _ENetProtocolSendFragment { ENetProtocolCommandHeader header; - enet_uint32 startSequenceNumber; + enet_uint16 startSequenceNumber; + enet_uint16 dataLength; enet_uint32 fragmentCount; enet_uint32 fragmentNumber; enet_uint32 totalLength; enet_uint32 fragmentOffset; -} ENetProtocolSendFragment; +} ENET_PACKED ENetProtocolSendFragment; -typedef union +typedef union _ENetProtocol { ENetProtocolCommandHeader header; ENetProtocolAcknowledge acknowledge; @@ -161,7 +186,11 @@ typedef union ENetProtocolSendFragment sendFragment; ENetProtocolBandwidthLimit bandwidthLimit; ENetProtocolThrottleConfigure throttleConfigure; -} ENetProtocol; +} ENET_PACKED ENetProtocol; + +#ifdef _MSC_VER_ +#pragma pack(pop) +#endif #endif /* __ENET_PROTOCOL_H__ */ diff --git a/enet/include/enet/unix.h b/enet/include/enet/unix.h index b20fecd..087015e 100644 --- a/enet/include/enet/unix.h +++ b/enet/include/enet/unix.h @@ -6,8 +6,10 @@ #define __ENET_UNIX_H__ #include +#include #include #include +#include typedef int ENetSocket; @@ -32,5 +34,12 @@ typedef struct #define ENET_API extern +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLEAR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + #endif /* __ENET_UNIX_H__ */ diff --git a/enet/include/enet/win32.h b/enet/include/enet/win32.h index 310ecd5..0e1cf0c 100644 --- a/enet/include/enet/win32.h +++ b/enet/include/enet/win32.h @@ -46,6 +46,13 @@ typedef struct #define ENET_API extern #endif /* ENET_DLL */ +typedef fd_set ENetSocketSet; + +#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset)) +#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset)) +#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLEAR (socket, & (sockset)) +#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset)) + #endif /* __ENET_WIN32_H__ */ diff --git a/enet/list.c b/enet/list.c index 1a4aa3a..1c1a8df 100644 --- a/enet/list.c +++ b/enet/list.c @@ -3,7 +3,7 @@ @brief ENet linked list functions */ #define ENET_BUILDING_LIB 1 -#include "enet/list.h" +#include "enet/enet.h" /** @defgroup list ENet linked list utility functions @@ -40,6 +40,24 @@ enet_list_remove (ENetListIterator position) 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) { diff --git a/enet/packet.c b/enet/packet.c index 5226550..2fc9a10 100644 --- a/enet/packet.c +++ b/enet/packet.c @@ -20,15 +20,28 @@ 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; - packet -> data = (enet_uint8 *) enet_malloc (dataLength); + 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); + if (data != NULL) + memcpy (packet -> data, data, dataLength); + } packet -> referenceCount = 0; packet -> flags = flags; packet -> dataLength = dataLength; + packet -> freeCallback = NULL; return packet; } @@ -39,7 +52,10 @@ enet_packet_create (const void * data, size_t dataLength, enet_uint32 flags) void enet_packet_destroy (ENetPacket * packet) { - enet_free (packet -> data); + if (packet -> freeCallback != NULL) + (* packet -> freeCallback) (packet); + if (! (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE)) + enet_free (packet -> data); enet_free (packet); } @@ -54,7 +70,7 @@ enet_packet_resize (ENetPacket * packet, size_t dataLength) { enet_uint8 * newData; - if (dataLength <= packet -> dataLength) + if (dataLength <= packet -> dataLength || (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE)) { packet -> dataLength = dataLength; @@ -62,6 +78,9 @@ enet_packet_resize (ENetPacket * packet, size_t dataLength) } newData = (enet_uint8 *) enet_malloc (dataLength); + if (newData == NULL) + return -1; + memcpy (newData, packet -> data, packet -> dataLength); enet_free (packet -> data); @@ -71,4 +90,68 @@ enet_packet_resize (ENetPacket * packet, size_t 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); +} + /** @} */ diff --git a/enet/peer.c b/enet/peer.c index 754239f..e1c117f 100644 --- a/enet/peer.c +++ b/enet/peer.c @@ -48,10 +48,8 @@ enet_peer_throttle_configure (ENetPeer * peer, enet_uint32 interval, enet_uint32 peer -> packetThrottleAcceleration = acceleration; peer -> packetThrottleDeceleration = deceleration; - command.header.command = ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE; + command.header.command = ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; command.header.channelID = 0xFF; - command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE; - command.header.commandLength = sizeof (ENetProtocolThrottleConfigure); command.throttleConfigure.packetThrottleInterval = ENET_HOST_TO_NET_32 (interval); command.throttleConfigure.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (acceleration); @@ -110,15 +108,19 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet) return -1; fragmentLength = peer -> mtu - sizeof (ENetProtocolHeader) - sizeof (ENetProtocolSendFragment); + if (peer -> host -> checksum != NULL) + fragmentLength -= sizeof(enet_uint32); 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), - startSequenceNumber = ENET_HOST_TO_NET_32 (channel -> outgoingReliableSequenceNumber + 1), fragmentNumber, fragmentOffset; + ENetList fragments; + ENetOutgoingCommand * fragment; - packet -> flags = ENET_PACKET_FLAG_RELIABLE; + enet_list_clear (& fragments); for (fragmentNumber = 0, fragmentOffset = 0; @@ -126,20 +128,44 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet) ++ fragmentNumber, fragmentOffset += fragmentLength) { - command.header.command = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT; - command.header.channelID = channelID; - command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE; - command.header.commandLength = sizeof (ENetProtocolSendFragment); - command.sendFragment.startSequenceNumber = startSequenceNumber; - command.sendFragment.fragmentCount = fragmentCount; - command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32 (fragmentNumber); - command.sendFragment.totalLength = ENET_HOST_TO_NET_32 (packet -> dataLength); - command.sendFragment.fragmentOffset = ENET_NET_TO_HOST_32 (fragmentOffset); - if (packet -> dataLength - fragmentOffset < fragmentLength) fragmentLength = packet -> dataLength - fragmentOffset; - enet_peer_queue_outgoing_command (peer, & command, packet, fragmentOffset, fragmentLength); + 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; @@ -149,99 +175,53 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet) if (packet -> flags & ENET_PACKET_FLAG_RELIABLE) { - command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE; - command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE; - command.header.commandLength = sizeof (ENetProtocolSendReliable); + 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; - command.header.flags = ENET_PROTOCOL_FLAG_UNSEQUENCED; - command.header.commandLength = sizeof (ENetProtocolSendUnsequenced); - command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_32 (peer -> outgoingUnsequencedGroup + 1); + 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.header.flags = 0; - command.header.commandLength = sizeof (ENetProtocolSendUnreliable); - command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_32 (channel -> outgoingUnreliableSequenceNumber + 1); + command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1); + command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength); } - enet_peer_queue_outgoing_command (peer, & command, packet, 0, 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 channel on which to receive + @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) +enet_peer_receive (ENetPeer * peer, enet_uint8 * channelID) { - ENetChannel * channel = & peer -> channels [channelID]; - ENetIncomingCommand * incomingCommand = NULL; + ENetIncomingCommand * incomingCommand; ENetPacket * packet; - - if (enet_list_empty (& channel -> incomingUnreliableCommands) == 0) - { - incomingCommand = (ENetIncomingCommand *) enet_list_front (& channel -> incomingUnreliableCommands); - - if (incomingCommand -> unreliableSequenceNumber > 0) - { - if (incomingCommand -> reliableSequenceNumber > channel -> incomingReliableSequenceNumber) - incomingCommand = NULL; - else - channel -> incomingUnreliableSequenceNumber = incomingCommand -> unreliableSequenceNumber; - } - } - - if (incomingCommand == NULL && - enet_list_empty (& channel -> incomingReliableCommands) == 0) - { - do - { - incomingCommand = (ENetIncomingCommand *) enet_list_front (& channel -> incomingReliableCommands); - - if (incomingCommand -> fragmentsRemaining > 0 || - incomingCommand -> reliableSequenceNumber > channel -> incomingReliableSequenceNumber + 1) - return NULL; - - if (incomingCommand -> reliableSequenceNumber <= channel -> incomingReliableSequenceNumber) - { - -- incomingCommand -> packet -> referenceCount; - - if (incomingCommand -> packet -> referenceCount == 0) - enet_packet_destroy (incomingCommand -> packet); - - if (incomingCommand -> fragments != NULL) - enet_free (incomingCommand -> fragments); - - enet_list_remove (& incomingCommand -> incomingCommandList); - - enet_free (incomingCommand); - - incomingCommand = NULL; - } - } while (incomingCommand == NULL && - enet_list_empty (& channel -> incomingReliableCommands) == 0); - - if (incomingCommand == NULL) - return NULL; - - channel -> incomingReliableSequenceNumber = incomingCommand -> reliableSequenceNumber; - - if (incomingCommand -> fragmentCount > 0) - channel -> incomingReliableSequenceNumber += incomingCommand -> fragmentCount - 1; - } - - if (incomingCommand == NULL) + + if (enet_list_empty (& peer -> dispatchedCommands)) return NULL; - enet_list_remove (& incomingCommand -> incomingCommandList); + incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (& peer -> dispatchedCommands)); + + if (channelID != NULL) + * channelID = incomingCommand -> command.header.channelID; packet = incomingCommand -> packet; @@ -260,7 +240,7 @@ enet_peer_reset_outgoing_commands (ENetList * queue) { ENetOutgoingCommand * outgoingCommand; - while (enet_list_empty (queue) == 0) + while (! enet_list_empty (queue)) { outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (queue)); @@ -281,7 +261,7 @@ enet_peer_reset_incoming_commands (ENetList * queue) { ENetIncomingCommand * incomingCommand; - while (enet_list_empty (queue) == 0) + while (! enet_list_empty (queue)) { incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (queue)); @@ -305,13 +285,21 @@ enet_peer_reset_queues (ENetPeer * peer) { ENetChannel * channel; - while (enet_list_empty (& peer -> acknowledgements) == 0) + 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) { @@ -338,11 +326,8 @@ enet_peer_reset_queues (ENetPeer * peer) void enet_peer_reset (ENetPeer * peer) { - peer -> outgoingPeerID = 0xFFFF; - peer -> challenge = 0; - - peer -> address.host = ENET_HOST_ANY; - peer -> address.port = 0; + peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID; + peer -> connectID = 0; peer -> state = ENET_PEER_STATE_DISCONNECTED; @@ -380,7 +365,7 @@ enet_peer_reset (ENetPeer * peer) peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; peer -> incomingUnsequencedGroup = 0; peer -> outgoingUnsequencedGroup = 0; - peer -> disconnectData = 0; + peer -> eventData = 0; memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow)); @@ -402,10 +387,8 @@ enet_peer_ping (ENetPeer * peer) if (peer -> state != ENET_PEER_STATE_CONNECTED) return; - command.header.command = ENET_PROTOCOL_COMMAND_PING; + command.header.command = ENET_PROTOCOL_COMMAND_PING | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; command.header.channelID = 0xFF; - command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE; - command.header.commandLength = sizeof (ENetProtocolPing); enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); } @@ -430,11 +413,9 @@ enet_peer_disconnect_now (ENetPeer * peer, enet_uint32 data) { enet_peer_reset_queues (peer); - command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT; + command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED; command.header.channelID = 0xFF; - command.header.flags = ENET_PROTOCOL_FLAG_UNSEQUENCED; - command.header.commandLength = sizeof (ENetProtocolDisconnect); - command.disconnect.data = data; + command.disconnect.data = ENET_HOST_TO_NET_32 (data); enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0); @@ -457,6 +438,7 @@ enet_peer_disconnect (ENetPeer * peer, enet_uint32 data) 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; @@ -464,16 +446,16 @@ enet_peer_disconnect (ENetPeer * peer, enet_uint32 data) command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT; command.header.channelID = 0xFF; - command.header.flags = ENET_PROTOCOL_FLAG_UNSEQUENCED; - command.header.commandLength = sizeof (ENetProtocolDisconnect); - command.disconnect.data = data; + command.disconnect.data = ENET_HOST_TO_NET_32 (data); - if (peer -> state == ENET_PEER_STATE_CONNECTED) - command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE; + 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) + if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) peer -> state = ENET_PEER_STATE_DISCONNECTING; else { @@ -482,14 +464,50 @@ enet_peer_disconnect (ENetPeer * peer, enet_uint32 data) } } +/** 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_uint32 sentTime) +enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command, enet_uint16 sentTime) { ENetAcknowledgement * acknowledgement; - peer -> outgoingDataTotal += sizeof (ENetProtocolAcknowledge); + 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; @@ -499,17 +517,14 @@ enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command, return acknowledgement; } -ENetOutgoingCommand * -enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, enet_uint32 offset, enet_uint16 length) +void +enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoingCommand) { - ENetChannel * channel = & peer -> channels [command -> header.channelID]; - ENetOutgoingCommand * outgoingCommand; - - peer -> outgoingDataTotal += command -> header.commandLength + length; + ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID]; - outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand)); + peer -> outgoingDataTotal += enet_protocol_command_size (outgoingCommand -> command.header.command) + outgoingCommand -> fragmentLength; - if (command -> header.channelID == 0xFF) + if (outgoingCommand -> command.header.channelID == 0xFF) { ++ peer -> outgoingReliableSequenceNumber; @@ -517,15 +532,16 @@ enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, outgoingCommand -> unreliableSequenceNumber = 0; } else - if (command -> header.flags & ENET_PROTOCOL_FLAG_ACKNOWLEDGE) + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) { ++ channel -> outgoingReliableSequenceNumber; - + channel -> outgoingUnreliableSequenceNumber = 0; + outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber; outgoingCommand -> unreliableSequenceNumber = 0; } else - if (command -> header.flags & ENET_PROTOCOL_FLAG_UNSEQUENCED) + if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED) { ++ peer -> outgoingUnsequencedGroup; @@ -540,47 +556,154 @@ enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, 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; - outgoingCommand -> command = * command; - outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_32 (outgoingCommand -> reliableSequenceNumber); - if (packet != NULL) ++ packet -> referenceCount; - if (command -> header.flags & ENET_PROTOCOL_FLAG_ACKNOWLEDGE) - enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand); - else - enet_list_insert (enet_list_end (& peer -> outgoingUnreliableCommands), outgoingCommand); + 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; + enet_uint32 unreliableSequenceNumber = 0, reliableSequenceNumber; + enet_uint16 reliableWindow, currentWindow; ENetIncomingCommand * incomingCommand; ENetListIterator currentCommand; - switch (command -> header.command) + 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 (incomingCommand -> reliableSequenceNumber <= command -> header.reliableSequenceNumber) + if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) { - if (incomingCommand -> reliableSequenceNumber < command -> header.reliableSequenceNumber) + if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber) + continue; + } + else + if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber) + break; + + if (incomingCommand -> reliableSequenceNumber <= reliableSequenceNumber) + { + if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber) break; goto freePacket; @@ -589,13 +712,7 @@ enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, break; case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: - unreliableSequenceNumber = ENET_NET_TO_HOST_32 (command -> sendUnreliable.unreliableSequenceNumber); - - if (command -> header.reliableSequenceNumber < channel -> incomingReliableSequenceNumber) - goto freePacket; - - if (unreliableSequenceNumber <= channel -> incomingUnreliableSequenceNumber) - goto freePacket; + 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); @@ -603,6 +720,24 @@ enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, { 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) @@ -622,9 +757,11 @@ enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, } incomingCommand = (ENetIncomingCommand *) enet_malloc (sizeof (ENetIncomingCommand)); + if (incomingCommand == NULL) + goto notifyError; incomingCommand -> reliableSequenceNumber = command -> header.reliableSequenceNumber; - incomingCommand -> unreliableSequenceNumber = unreliableSequenceNumber; + incomingCommand -> unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF; incomingCommand -> command = * command; incomingCommand -> fragmentCount = fragmentCount; incomingCommand -> fragmentsRemaining = fragmentCount; @@ -634,6 +771,12 @@ enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, 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)); } @@ -642,14 +785,32 @@ enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, 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 (packet != NULL) - { - if (packet -> referenceCount == 0) - enet_packet_destroy (packet); - } + if (fragmentCount > 0) + goto notifyError; + + if (packet != NULL && packet -> referenceCount == 0) + enet_packet_destroy (packet); + + return & dummyCommand; + +notifyError: + if (packet != NULL && packet -> referenceCount == 0) + enet_packet_destroy (packet); return NULL; } diff --git a/enet/protocol.c b/enet/protocol.c index 75cdd64..2237ba8 100644 --- a/enet/protocol.c +++ b/enet/protocol.c @@ -9,28 +9,46 @@ #include "enet/time.h" #include "enet/enet.h" -static enet_uint32 timeCurrent; +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), +}; + +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) { - ENetPeer * currentPeer = host -> lastServicedPeer; - ENetChannel * channel; - - do + while (! enet_list_empty (& host -> dispatchQueue)) { - ++ currentPeer; - - if (currentPeer >= & host -> peers [host -> peerCount]) - currentPeer = host -> peers; + ENetPeer * peer = (ENetPeer *) enet_list_remove (enet_list_begin (& host -> dispatchQueue)); - switch (currentPeer -> state) + peer -> needsDispatch = 0; + + switch (peer -> state) { case ENET_PEER_STATE_CONNECTION_PENDING: - currentPeer -> state = ENET_PEER_STATE_CONNECTED; + case ENET_PEER_STATE_CONNECTION_SUCCEEDED: + peer -> state = ENET_PEER_STATE_CONNECTED; event -> type = ENET_EVENT_TYPE_CONNECT; - event -> peer = currentPeer; + event -> peer = peer; + event -> data = peer -> eventData; return 1; @@ -38,72 +56,78 @@ enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event) host -> recalculateBandwidthLimits = 1; event -> type = ENET_EVENT_TYPE_DISCONNECT; - event -> peer = currentPeer; - event -> data = currentPeer -> disconnectData; - - enet_peer_reset (currentPeer); + event -> peer = peer; + event -> data = peer -> eventData; - host -> lastServicedPeer = currentPeer; + enet_peer_reset (peer); return 1; - } - - if (currentPeer -> state != ENET_PEER_STATE_CONNECTED) - continue; - for (channel = currentPeer -> channels; - channel < & currentPeer -> channels [currentPeer -> channelCount]; - ++ channel) - { - if (enet_list_empty (& channel -> incomingReliableCommands) && - enet_list_empty (& channel -> incomingUnreliableCommands)) + case ENET_PEER_STATE_CONNECTED: + if (enet_list_empty (& peer -> dispatchedCommands)) continue; - event -> packet = enet_peer_receive (currentPeer, channel - currentPeer -> channels); + event -> packet = enet_peer_receive (peer, & event -> channelID); if (event -> packet == NULL) continue; event -> type = ENET_EVENT_TYPE_RECEIVE; - event -> peer = currentPeer; - event -> channelID = (enet_uint8) (channel - currentPeer -> channels); + event -> peer = peer; - host -> lastServicedPeer = currentPeer; + if (! enet_list_empty (& peer -> dispatchedCommands)) + { + peer -> needsDispatch = 1; + + enet_list_insert (enet_list_end (& host -> dispatchQueue), & peer -> dispatchList); + } return 1; } - } while (currentPeer != host -> lastServicedPeer); + } 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_CONNECTION_PENDING; - else + if (event != NULL) { - peer -> state = ENET_PEER_STATE_CONNECTED; + peer -> state = ENET_PEER_STATE_CONNECTED; - event -> type = ENET_EVENT_TYPE_CONNECT; - event -> peer = peer; + 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; + host -> recalculateBandwidthLimits = 1; - if (peer -> state < ENET_PEER_STATE_CONNECTED) + if (peer -> state != ENET_PEER_STATE_CONNECTING && peer -> state < ENET_PEER_STATE_CONNECTION_SUCCEEDED) enet_peer_reset (peer); else - if (event == NULL) - peer -> state = ENET_PEER_STATE_ZOMBIE; - else + if (event != NULL) { event -> type = ENET_EVENT_TYPE_DISCONNECT; event -> peer = peer; @@ -111,6 +135,12 @@ enet_protocol_notify_disconnect (ENetHost * host, ENetPeer * peer, ENetEvent * e enet_peer_reset (peer); } + else + { + peer -> eventData = 0; + + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); + } } static void @@ -118,7 +148,7 @@ enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer) { ENetOutgoingCommand * outgoingCommand; - while (enet_list_empty (& peer -> sentUnreliableCommands) == 0) + while (! enet_list_empty (& peer -> sentUnreliableCommands)) { outgoingCommand = (ENetOutgoingCommand *) enet_list_front (& peer -> sentUnreliableCommands); @@ -137,11 +167,12 @@ enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer) } static ENetProtocolCommand -enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint32 reliableSequenceNumber, enet_uint8 channelID) +enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID) { ENetOutgoingCommand * outgoingCommand; ENetListIterator currentCommand; ENetProtocolCommand commandNumber; + int wasSent = 1; for (currentCommand = enet_list_begin (& peer -> sentReliableCommands); currentCommand != enet_list_end (& peer -> sentReliableCommands); @@ -155,15 +186,46 @@ enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint32 reliabl } if (currentCommand == enet_list_end (& peer -> sentReliableCommands)) - return ENET_PROTOCOL_COMMAND_NONE; + { + 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; + } - commandNumber = outgoingCommand -> command.header.command; + if (currentCommand == enet_list_end (& peer -> outgoingReliableCommands)) + return ENET_PROTOCOL_COMMAND_NONE; + + wasSent = 0; + } + + 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; + if (wasSent) + peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength; -- outgoingCommand -> packet -> referenceCount; @@ -184,18 +246,15 @@ enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint32 reliabl } static ENetPeer * -enet_protocol_handle_connect (ENetHost * host, const ENetProtocolHeader * header, const ENetProtocol * command) +enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENetProtocol * command) { - enet_uint16 mtu; - enet_uint32 windowSize; + enet_uint8 incomingSessionID, outgoingSessionID; + enet_uint32 mtu, windowSize; ENetChannel * channel; size_t channelCount; ENetPeer * currentPeer; ENetProtocol verifyCommand; - if (command -> header.commandLength < sizeof (ENetProtocolConnect)) - return NULL; - channelCount = ENET_NET_TO_HOST_32 (command -> connect.channelCount); if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || @@ -209,7 +268,7 @@ enet_protocol_handle_connect (ENetHost * host, const ENetProtocolHeader * header if (currentPeer -> state != ENET_PEER_STATE_DISCONNECTED && currentPeer -> address.host == host -> receivedAddress.host && currentPeer -> address.port == host -> receivedAddress.port && - currentPeer -> challenge == header -> challenge) + currentPeer -> connectID == command -> connect.connectID) return NULL; } @@ -224,8 +283,14 @@ enet_protocol_handle_connect (ENetHost * host, const ENetProtocolHeader * header 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 -> challenge = header -> challenge; + 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); @@ -233,8 +298,19 @@ enet_protocol_handle_connect (ENetHost * host, const ENetProtocolHeader * header 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 -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); - currentPeer -> channelCount = channelCount; + 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]; @@ -243,13 +319,15 @@ enet_protocol_handle_connect (ENetHost * host, const ENetProtocolHeader * header channel -> outgoingReliableSequenceNumber = 0; channel -> outgoingUnreliableSequenceNumber = 0; channel -> incomingReliableSequenceNumber = 0; - channel -> incomingUnreliableSequenceNumber = 0; enet_list_clear (& channel -> incomingReliableCommands); enet_list_clear (& channel -> incomingUnreliableCommands); + + channel -> usedReliableWindows = 0; + memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); } - mtu = ENET_NET_TO_HOST_16 (command -> connect.mtu); + mtu = ENET_NET_TO_HOST_32 (command -> connect.mtu); if (mtu < ENET_PROTOCOL_MINIMUM_MTU) mtu = ENET_PROTOCOL_MINIMUM_MTU; @@ -262,6 +340,12 @@ enet_protocol_handle_connect (ENetHost * host, const ENetProtocolHeader * header 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) * @@ -288,11 +372,11 @@ enet_protocol_handle_connect (ENetHost * host, const ENetProtocolHeader * header if (windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; - verifyCommand.header.command = ENET_PROTOCOL_COMMAND_VERIFY_CONNECT; + verifyCommand.header.command = ENET_PROTOCOL_COMMAND_VERIFY_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE; verifyCommand.header.channelID = 0xFF; - verifyCommand.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE; - verifyCommand.header.commandLength = sizeof (ENetProtocolVerifyConnect); 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); @@ -301,83 +385,114 @@ enet_protocol_handle_connect (ENetHost * host, const ENetProtocolHeader * header 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 void -enet_protocol_handle_send_reliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +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.commandLength <= sizeof (ENetProtocolSendReliable) || - command -> header.channelID >= peer -> channelCount || - peer -> state != ENET_PEER_STATE_CONNECTED) - return; + 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), - command -> header.commandLength - sizeof (ENetProtocolSendReliable), + dataLength, ENET_PACKET_FLAG_RELIABLE); + if (packet == NULL || + enet_peer_queue_incoming_command (peer, command, packet, 0) == NULL) + return -1; - enet_peer_queue_incoming_command (peer, command, packet, 0); + return 0; } -static void -enet_protocol_handle_send_unsequenced (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +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.commandLength <= sizeof (ENetProtocolSendUnsequenced) || - command -> header.channelID >= peer -> channelCount || - peer -> state != ENET_PEER_STATE_CONNECTED) - return; + if (command -> header.channelID >= peer -> channelCount || + (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)) + return -1; - unsequencedGroup = ENET_NET_TO_HOST_32 (command -> sendUnsequenced.unsequencedGroup); + 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 + 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 (unsequencedGroup < peer -> incomingUnsequencedGroup || - peer -> unsequencedWindow [index / 32] & (1 << (index % 32))) - return; + if (peer -> unsequencedWindow [index / 32] & (1 << (index % 32))) + return 0; - peer -> unsequencedWindow [index / 32] |= 1 << (index % 32); - - packet = enet_packet_create ((const enet_uint8 *) command + sizeof (ENetProtocolSendUnsequenced), - command -> header.commandLength - sizeof (ENetProtocolSendUnsequenced), + dataLength, ENET_PACKET_FLAG_UNSEQUENCED); - - enet_peer_queue_incoming_command (peer, command, packet, 0); + 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 void -enet_protocol_handle_send_unreliable (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +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; - if (command -> header.commandLength <= sizeof (ENetProtocolSendUnreliable) || - command -> header.channelID >= peer -> channelCount || - peer -> state != ENET_PEER_STATE_CONNECTED) - return; + 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), - command -> header.commandLength - sizeof (ENetProtocolSendUnreliable), + dataLength, 0); + if (packet == NULL || + enet_peer_queue_incoming_command (peer, command, packet, 0) == NULL) + return -1; - enet_peer_queue_incoming_command (peer, command, packet, 0); + return 0; } -static void -enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) +static int +enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData) { enet_uint32 fragmentNumber, fragmentCount, @@ -386,62 +501,89 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet startSequenceNumber, totalLength; ENetChannel * channel; + enet_uint16 startWindow, currentWindow; ENetListIterator currentCommand; - ENetIncomingCommand * startCommand; + 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 (command -> header.commandLength <= sizeof (ENetProtocolSendFragment) || - command -> header.channelID >= peer -> channelCount || - peer -> state != ENET_PEER_STATE_CONNECTED) - return; + if (startSequenceNumber < channel -> incomingReliableSequenceNumber) + startWindow += ENET_PEER_RELIABLE_WINDOWS; + + if (startWindow < currentWindow || startWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1) + return 0; - startSequenceNumber = ENET_NET_TO_HOST_32 (command -> sendFragment.startSequenceNumber); 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); - fragmentLength = command -> header.commandLength - sizeof (ENetProtocolSendFragment); if (fragmentOffset >= totalLength || fragmentOffset + fragmentLength > totalLength || fragmentNumber >= fragmentCount) - return; + return -1; - channel = & peer -> channels [command -> header.channelID]; - - if (startSequenceNumber <= channel -> incomingReliableSequenceNumber) - return; - for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands)); currentCommand != enet_list_end (& channel -> incomingReliableCommands); currentCommand = enet_list_previous (currentCommand)) { - startCommand = (ENetIncomingCommand *) currentCommand; + ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand; - if (startCommand -> command.header.command == ENET_PROTOCOL_COMMAND_SEND_FRAGMENT && - startCommand -> command.sendFragment.startSequenceNumber == startSequenceNumber) + 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 (currentCommand == enet_list_end (& channel -> incomingReliableCommands)) + 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, - enet_packet_create (NULL, totalLength, ENET_PACKET_FLAG_RELIABLE), - fragmentCount); + startCommand = enet_peer_queue_incoming_command (peer, & hostCommand, packet, fragmentCount); + if (startCommand == NULL) + return -1; } - else - if (totalLength != startCommand -> packet -> dataLength || - fragmentCount != startCommand -> fragmentCount) - return; if ((startCommand -> fragments [fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0) { @@ -455,27 +597,27 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet 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 void +static int enet_protocol_handle_ping (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) { - if (command -> header.commandLength < sizeof (ENetProtocolPing)) - return; + return 0; } -static void +static int enet_protocol_handle_bandwidth_limit (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) { - if (command -> header.commandLength < sizeof (ENetProtocolBandwidthLimit)) - return; - 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) + if (peer -> incomingBandwidth == 0 && host -> outgoingBandwidth == 0) peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; else peer -> windowSize = (ENET_MIN (peer -> incomingBandwidth, host -> outgoingBandwidth) / @@ -486,40 +628,47 @@ enet_protocol_handle_bandwidth_limit (ENetHost * host, ENetPeer * peer, const EN else if (peer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; + + return 0; } -static void +static int enet_protocol_handle_throttle_configure (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) { - if (command -> header.commandLength < sizeof (ENetProtocolThrottleConfigure)) - return; - 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 void +static int enet_protocol_handle_disconnect (ENetHost * host, ENetPeer * peer, const ENetProtocol * command) { - if (command -> header.commandLength < sizeof (ENetProtocolDisconnect)) - return; + 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_CONNECTED) + 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.flags & ENET_PROTOCOL_FLAG_ACKNOWLEDGE) + if (command -> header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT; else - peer -> state = ENET_PEER_STATE_ZOMBIE; + enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE); - peer -> disconnectData = command -> disconnect.data; + if (peer -> state != ENET_PEER_STATE_DISCONNECTED) + peer -> eventData = ENET_NET_TO_HOST_32 (command -> disconnect.data); + + return 0; } static int @@ -530,18 +679,18 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * receivedReliableSequenceNumber; ENetProtocolCommand commandNumber; - if (command -> header.commandLength < sizeof (ENetProtocolAcknowledge)) - return 0; - - receivedSentTime = ENET_NET_TO_HOST_32 (command -> acknowledge.receivedSentTime); + 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 (timeCurrent, receivedSentTime)) + if (ENET_TIME_LESS (host -> serviceTime, receivedSentTime)) return 0; - peer -> lastReceiveTime = timeCurrent; + peer -> lastReceiveTime = host -> serviceTime; peer -> earliestTimeout = 0; - roundTripTime = ENET_TIME_DIFFERENCE (timeCurrent, receivedSentTime); + roundTripTime = ENET_TIME_DIFFERENCE (host -> serviceTime, receivedSentTime); enet_peer_throttle (peer, roundTripTime); @@ -565,16 +714,16 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * peer -> highestRoundTripTimeVariance = peer -> roundTripTimeVariance; if (peer -> packetThrottleEpoch == 0 || - ENET_TIME_DIFFERENCE(timeCurrent, peer -> packetThrottleEpoch) >= peer -> packetThrottleInterval) + 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 = timeCurrent; + peer -> packetThrottleEpoch = host -> serviceTime; } - receivedReliableSequenceNumber = ENET_NET_TO_HOST_32 (command -> acknowledge.receivedReliableSequenceNumber); + receivedReliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedReliableSequenceNumber); commandNumber = enet_protocol_remove_sent_reliable_command (peer, receivedReliableSequenceNumber, command -> header.channelID); @@ -582,48 +731,63 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * { case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT: if (commandNumber != ENET_PROTOCOL_COMMAND_VERIFY_CONNECT) - return 0; + return -1; enet_protocol_notify_connect (host, peer, event); - - return 1; + break; case ENET_PEER_STATE_DISCONNECTING: if (commandNumber != ENET_PROTOCOL_COMMAND_DISCONNECT) - return 0; + return -1; enet_protocol_notify_disconnect (host, peer, event); - - return 1; + 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 void +static int enet_protocol_handle_verify_connect (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command) { - enet_uint16 mtu; - enet_uint32 windowSize; + enet_uint32 mtu, windowSize; + size_t channelCount; + + if (peer -> state != ENET_PEER_STATE_CONNECTING) + return 0; - if (event == NULL || - command -> header.commandLength < sizeof (ENetProtocolVerifyConnect) || - peer -> state != ENET_PEER_STATE_CONNECTING) - return; + channelCount = ENET_NET_TO_HOST_32 (command -> verifyConnect.channelCount); - if (ENET_NET_TO_HOST_32 (command -> verifyConnect.channelCount) != peer -> 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) + ENET_NET_TO_HOST_32 (command -> verifyConnect.packetThrottleDeceleration) != peer -> packetThrottleDeceleration || + command -> verifyConnect.connectID != peer -> connectID) { - peer -> state = ENET_PEER_STATE_ZOMBIE; + peer -> eventData = 0; - return; + 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_16 (command -> verifyConnect.mtu); + mtu = ENET_NET_TO_HOST_32 (command -> verifyConnect.mtu); if (mtu < ENET_PROTOCOL_MINIMUM_MTU) mtu = ENET_PROTOCOL_MINIMUM_MTU; @@ -649,6 +813,7 @@ enet_protocol_handle_verify_connect (ENetHost * host, ENetEvent * event, ENetPee peer -> outgoingBandwidth = ENET_NET_TO_HOST_32 (command -> verifyConnect.outgoingBandwidth); enet_protocol_notify_connect (host, peer, event); + return 0; } static int @@ -658,147 +823,201 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event) ENetProtocol * command; ENetPeer * peer; enet_uint8 * currentData; - size_t commandCount; + size_t headerSize; + enet_uint16 peerID, flags; + enet_uint8 sessionID; - if (host -> receivedDataLength < sizeof (ENetProtocolHeader)) + if (host -> receivedDataLength < (size_t) & ((ENetProtocolHeader *) 0) -> sentTime) return 0; header = (ENetProtocolHeader *) host -> receivedData; - header -> peerID = ENET_NET_TO_HOST_16 (header -> peerID); - header -> sentTime = ENET_NET_TO_HOST_32 (header -> sentTime); + 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 (header -> peerID == 0xFFFF) + if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID) peer = NULL; else - if (header -> peerID >= host -> peerCount) + if (peerID >= host -> peerCount) return 0; else { - peer = & host -> peers [header -> peerID]; + peer = & host -> peers [peerID]; if (peer -> state == ENET_PEER_STATE_DISCONNECTED || - peer -> state == ENET_PEER_STATE_ZOMBIE || + peer -> state == ENET_PEER_STATE_ZOMBIE || (host -> receivedAddress.host != peer -> address.host && peer -> address.host != ENET_HOST_BROADCAST) || - header -> challenge != peer -> challenge) + (peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID && + sessionID != peer -> incomingSessionID)) return 0; - else - { - peer -> address.host = host -> receivedAddress.host; - peer -> address.port = host -> receivedAddress.port; - } + } + + 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 (peer != NULL) - peer -> incomingDataTotal += host -> receivedDataLength; + 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; - commandCount = header -> commandCount; - currentData = host -> receivedData + sizeof (ENetProtocolHeader); + buffer.data = host -> receivedData; + buffer.dataLength = host -> receivedDataLength; + + if (host -> checksum (& buffer, 1) != desiredChecksum) + return 0; + } + + if (peer != NULL) + { + peer -> address.host = host -> receivedAddress.host; + peer -> address.port = host -> receivedAddress.port; + peer -> incomingDataTotal += host -> receivedDataLength; + } + + currentData = host -> receivedData + headerSize; - while (commandCount > 0 && - currentData < & host -> receivedData [host -> receivedDataLength]) + while (currentData < & host -> receivedData [host -> receivedDataLength]) { + enet_uint8 commandNumber; + size_t commandSize; + command = (ENetProtocol *) currentData; if (currentData + sizeof (ENetProtocolCommandHeader) > & host -> receivedData [host -> receivedDataLength]) break; - command -> header.commandLength = ENET_NET_TO_HOST_32 (command -> header.commandLength); - - if (command -> header.commandLength <= 0 || - command -> header.commandLength > & host -> receivedData [host -> receivedDataLength] - currentData) + 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; - -- commandCount; - currentData += command -> header.commandLength; + currentData += commandSize; - if (peer == NULL && command -> header.command != ENET_PROTOCOL_COMMAND_CONNECT) + if (peer == NULL && commandNumber != ENET_PROTOCOL_COMMAND_CONNECT) break; - command -> header.reliableSequenceNumber = ENET_NET_TO_HOST_32 (command -> header.reliableSequenceNumber); + command -> header.reliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> header.reliableSequenceNumber); - switch (command -> header.command) + switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK) { case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE: - enet_protocol_handle_acknowledge (host, event, peer, command); - + 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: - enet_protocol_handle_verify_connect (host, event, peer, command); - + if (enet_protocol_handle_verify_connect (host, event, peer, command)) + goto commandError; break; case ENET_PROTOCOL_COMMAND_DISCONNECT: - enet_protocol_handle_disconnect (host, peer, command); - + if (enet_protocol_handle_disconnect (host, peer, command)) + goto commandError; break; case ENET_PROTOCOL_COMMAND_PING: - enet_protocol_handle_ping (host, peer, command); - + if (enet_protocol_handle_ping (host, peer, command)) + goto commandError; break; case ENET_PROTOCOL_COMMAND_SEND_RELIABLE: - enet_protocol_handle_send_reliable (host, peer, command); - + if (enet_protocol_handle_send_reliable (host, peer, command, & currentData)) + goto commandError; break; case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE: - enet_protocol_handle_send_unreliable (host, peer, command); - + if (enet_protocol_handle_send_unreliable (host, peer, command, & currentData)) + goto commandError; break; case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED: - enet_protocol_handle_send_unsequenced (host, peer, command); - + if (enet_protocol_handle_send_unsequenced (host, peer, command, & currentData)) + goto commandError; break; case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT: - enet_protocol_handle_send_fragment (host, peer, command); - + if (enet_protocol_handle_send_fragment (host, peer, command, & currentData)) + goto commandError; break; case ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT: - enet_protocol_handle_bandwidth_limit (host, peer, command); - + if (enet_protocol_handle_bandwidth_limit (host, peer, command)) + goto commandError; break; case ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE: - enet_protocol_handle_throttle_configure (host, peer, command); - + if (enet_protocol_handle_throttle_configure (host, peer, command)) + goto commandError; break; default: - break; + goto commandError; } if (peer != NULL && - (command -> header.flags & ENET_PROTOCOL_FLAG_ACKNOWLEDGE) != 0) + (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_DISCONNECT) - break; + 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, header -> sentTime); - + enet_peer_queue_acknowledgement (peer, command, sentTime); break; } } } +commandError: if (event != NULL && event -> type != ENET_EVENT_TYPE_NONE) return 1; @@ -813,8 +1032,8 @@ enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event) int receivedLength; ENetBuffer buffer; - buffer.data = host -> receivedData; - buffer.dataLength = sizeof (host -> receivedData); + buffer.data = host -> packetData [0]; + buffer.dataLength = sizeof (host -> packetData [0]); receivedLength = enet_socket_receive (host -> socket, & host -> receivedAddress, @@ -827,8 +1046,12 @@ enet_protocol_receive_incoming_commands (ENetHost * host, ENetEvent * event) if (receivedLength == 0) return 0; + host -> receivedData = host -> packetData [0]; host -> receivedDataLength = receivedLength; - + + host -> totalReceivedData += receivedLength; + host -> totalReceivedPackets ++; + switch (enet_protocol_handle_incoming_commands (host, event)) { case 1: @@ -860,7 +1083,11 @@ enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer) if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || buffer >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || peer -> mtu - host -> packetSize < sizeof (ENetProtocolAcknowledge)) - break; + { + host -> continueSending = 1; + + break; + } acknowledgement = (ENetAcknowledgement *) currentAcknowledgement; @@ -873,13 +1100,11 @@ enet_protocol_send_acknowledgements (ENetHost * host, ENetPeer * peer) command -> header.command = ENET_PROTOCOL_COMMAND_ACKNOWLEDGE; command -> header.channelID = acknowledgement -> command.header.channelID; - command -> header.flags = 0; - command -> header.commandLength = ENET_HOST_TO_NET_32 (sizeof (ENetProtocolAcknowledge)); - command -> acknowledge.receivedReliableSequenceNumber = ENET_HOST_TO_NET_32 (acknowledgement -> command.header.reliableSequenceNumber); - command -> acknowledge.receivedSentTime = ENET_HOST_TO_NET_32 (acknowledgement -> sentTime); + 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_DISCONNECT) - peer -> state = ENET_PEER_STATE_ZOMBIE; + 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); @@ -904,15 +1129,21 @@ enet_protocol_send_unreliable_outgoing_commands (ENetHost * host, ENetPeer * pee 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 < outgoingCommand -> command.header.commandLength || + peer -> mtu - host -> packetSize < commandSize || (outgoingCommand -> packet != NULL && - peer -> mtu - host -> packetSize < outgoingCommand -> command.header.commandLength + - outgoingCommand -> packet -> dataLength)) - break; + peer -> mtu - host -> packetSize < commandSize + outgoingCommand -> packet -> dataLength)) + { + host -> continueSending = 1; + + break; + } currentCommand = enet_list_next (currentCommand); @@ -936,7 +1167,7 @@ enet_protocol_send_unreliable_outgoing_commands (ENetHost * host, ENetPeer * pee } buffer -> data = command; - buffer -> dataLength = outgoingCommand -> command.header.commandLength; + buffer -> dataLength = commandSize; host -> packetSize += buffer -> dataLength; @@ -951,8 +1182,6 @@ enet_protocol_send_unreliable_outgoing_commands (ENetHost * host, ENetPeer * pee buffer -> data = outgoingCommand -> packet -> data; buffer -> dataLength = outgoingCommand -> packet -> dataLength; - command -> header.commandLength += buffer -> dataLength; - host -> packetSize += buffer -> dataLength; enet_list_insert (enet_list_end (& peer -> sentUnreliableCommands), outgoingCommand); @@ -960,23 +1189,28 @@ enet_protocol_send_unreliable_outgoing_commands (ENetHost * host, ENetPeer * pee else enet_free (outgoingCommand); - command -> header.commandLength = ENET_HOST_TO_NET_32 (command -> header.commandLength); - ++ 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; + ENetListIterator currentCommand, insertPosition; currentCommand = enet_list_begin (& peer -> sentReliableCommands); + insertPosition = enet_list_begin (& peer -> outgoingReliableCommands); while (currentCommand != enet_list_end (& peer -> sentReliableCommands)) { @@ -984,17 +1218,17 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even currentCommand = enet_list_next (currentCommand); - if (ENET_TIME_DIFFERENCE (timeCurrent, outgoingCommand -> sentTime) < outgoingCommand -> roundTripTimeout) + 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_LESS (outgoingCommand -> sentTime, peer -> earliestTimeout)) + peer -> earliestTimeout = outgoingCommand -> sentTime; if (peer -> earliestTimeout != 0 && - (ENET_TIME_DIFFERENCE(timeCurrent, peer -> earliestTimeout) >= ENET_PEER_TIMEOUT_MAXIMUM || + (ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= ENET_PEER_TIMEOUT_MAXIMUM || (outgoingCommand -> roundTripTimeout >= outgoingCommand -> roundTripTimeoutLimit && - ENET_TIME_DIFFERENCE(timeCurrent, peer -> earliestTimeout) >= ENET_PEER_TIMEOUT_MINIMUM))) + ENET_TIME_DIFFERENCE (host -> serviceTime, peer -> earliestTimeout) >= ENET_PEER_TIMEOUT_MINIMUM))) { enet_protocol_notify_disconnect (host, peer, event); @@ -1008,11 +1242,10 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even outgoingCommand -> roundTripTimeout *= 2; - enet_list_insert (enet_list_begin (& peer -> outgoingReliableCommands), - enet_list_remove (& outgoingCommand -> outgoingCommandList)); + enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList)); if (currentCommand == enet_list_begin (& peer -> sentReliableCommands) && - enet_list_empty (& peer -> sentReliableCommands) == 0) + ! enet_list_empty (& peer -> sentReliableCommands)) { outgoingCommand = (ENetOutgoingCommand *) currentCommand; @@ -1023,13 +1256,17 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even return 0; } -static void +static int enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) { ENetProtocol * command = & host -> commands [host -> commandCount]; ENetBuffer * buffer = & host -> buffers [host -> bufferCount]; ENetOutgoingCommand * outgoingCommand; ENetListIterator currentCommand; + ENetChannel *channel; + enet_uint16 reliableWindow; + size_t commandSize; + int windowExceeded = 0, windowWrap = 0, canPing = 1; currentCommand = enet_list_begin (& peer -> outgoingReliableCommands); @@ -1037,22 +1274,66 @@ enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) { outgoingCommand = (ENetOutgoingCommand *) currentCommand; + channel = outgoingCommand -> command.header.channelID < peer -> channelCount ? & peer -> channels [outgoingCommand -> command.header.channelID] : NULL; + reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE; + if (channel != NULL) + { + if (! windowWrap && + outgoingCommand -> sendAttempts < 1 && + ! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) && + (channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE || + channel -> usedReliableWindows & ((((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) << reliableWindow) | + (((1 << ENET_PEER_FREE_RELIABLE_WINDOWS) - 1) >> (ENET_PEER_RELIABLE_WINDOW_SIZE - reliableWindow))))) + windowWrap = 1; + if (windowWrap) + { + currentCommand = enet_list_next (currentCommand); + + continue; + } + } + + if (outgoingCommand -> packet != NULL) + { + if (! windowExceeded) + { + enet_uint32 windowSize = (peer -> packetThrottle * peer -> windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE; + + if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > ENET_MAX (windowSize, peer -> mtu)) + windowExceeded = 1; + } + if (windowExceeded) + { + currentCommand = enet_list_next (currentCommand); + + continue; + } + } + + canPing = 0; + + commandSize = commandSizes [outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK]; if (command >= & host -> commands [sizeof (host -> commands) / sizeof (ENetProtocol)] || buffer + 1 >= & host -> buffers [sizeof (host -> buffers) / sizeof (ENetBuffer)] || - peer -> mtu - host -> packetSize < outgoingCommand -> command.header.commandLength) - break; + peer -> mtu - host -> packetSize < commandSize || + (outgoingCommand -> packet != NULL && + (enet_uint16) (peer -> mtu - host -> packetSize) < (enet_uint16) (commandSize + outgoingCommand -> fragmentLength))) + { + host -> continueSending = 1; + + break; + } currentCommand = enet_list_next (currentCommand); - if (outgoingCommand -> packet != NULL) + if (channel != NULL && outgoingCommand -> sendAttempts < 1) { - if ((enet_uint16) (peer -> mtu - host -> packetSize) < - (enet_uint16) (outgoingCommand -> command.header.commandLength + - outgoingCommand -> fragmentLength) || - peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > peer -> windowSize) - break; + channel -> usedReliableWindows |= 1 << reliableWindow; + ++ channel -> reliableWindows [reliableWindow]; } - + + ++ outgoingCommand -> sendAttempts; + if (outgoingCommand -> roundTripTimeout == 0) { outgoingCommand -> roundTripTimeout = peer -> roundTripTime + 4 * peer -> roundTripTimeVariance; @@ -1060,17 +1341,18 @@ enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) } if (enet_list_empty (& peer -> sentReliableCommands)) - peer -> nextTimeout = timeCurrent + outgoingCommand -> roundTripTimeout; + peer -> nextTimeout = host -> serviceTime + outgoingCommand -> roundTripTimeout; enet_list_insert (enet_list_end (& peer -> sentReliableCommands), enet_list_remove (& outgoingCommand -> outgoingCommandList)); - outgoingCommand -> sentTime = timeCurrent; + outgoingCommand -> sentTime = host -> serviceTime; buffer -> data = command; - buffer -> dataLength = outgoingCommand -> command.header.commandLength; + buffer -> dataLength = commandSize; host -> packetSize += buffer -> dataLength; + host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME; * command = outgoingCommand -> command; @@ -1081,15 +1363,11 @@ enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) buffer -> data = outgoingCommand -> packet -> data + outgoingCommand -> fragmentOffset; buffer -> dataLength = outgoingCommand -> fragmentLength; - command -> header.commandLength += outgoingCommand -> fragmentLength; - host -> packetSize += outgoingCommand -> fragmentLength; peer -> reliableDataInTransit += outgoingCommand -> fragmentLength; } - command -> header.commandLength = ENET_HOST_TO_NET_32 (command -> header.commandLength); - ++ peer -> packetsSent; ++ command; @@ -1098,19 +1376,24 @@ enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer) host -> commandCount = command - host -> commands; host -> bufferCount = buffer - host -> buffers; + + return canPing; } static int enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int checkForTimeouts) { - size_t packetsSent = 1; - ENetProtocolHeader header; + enet_uint8 headerData [sizeof (ENetProtocolHeader) + sizeof (enet_uint32)]; + ENetProtocolHeader * header = (ENetProtocolHeader *) headerData; ENetPeer * currentPeer; int sentLength; - - while (packetsSent > 0) - for (currentPeer = host -> peers, - packetsSent = 0; + size_t shouldCompress = 0; + + host -> continueSending = 1; + + while (host -> continueSending) + for (host -> continueSending = 0, + currentPeer = host -> peers; currentPeer < & host -> peers [host -> peerCount]; ++ currentPeer) { @@ -1118,43 +1401,40 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch 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) == 0) + if (! enet_list_empty (& currentPeer -> acknowledgements)) enet_protocol_send_acknowledgements (host, currentPeer); - - if (host -> commandCount < sizeof (host -> commands) / sizeof (ENetProtocol)) - { - if (checkForTimeouts != 0 && - enet_list_empty (& currentPeer -> sentReliableCommands) == 0 && - ENET_TIME_GREATER_EQUAL (timeCurrent, currentPeer -> nextTimeout) && - enet_protocol_check_timeouts (host, currentPeer, event) == 1) - return 1; - } - if (enet_list_empty (& currentPeer -> outgoingReliableCommands) == 0) - enet_protocol_send_reliable_outgoing_commands (host, currentPeer); - else - if (enet_list_empty (& currentPeer -> sentReliableCommands) && - ENET_TIME_DIFFERENCE (timeCurrent, currentPeer -> lastReceiveTime) >= ENET_PEER_PING_INTERVAL && + + 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)) && + 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 (host -> commandCount < sizeof (host -> commands) / sizeof (ENetProtocol) && - enet_list_empty (& currentPeer -> outgoingUnreliableCommands) == 0) + 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 = timeCurrent; + currentPeer -> packetLossEpoch = host -> serviceTime; else - if (ENET_TIME_DIFFERENCE (timeCurrent, currentPeer -> packetLossEpoch) >= ENET_PEER_PACKET_LOSS_INTERVAL && + 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; @@ -1165,7 +1445,7 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch #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, enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands)); + "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; @@ -1181,23 +1461,64 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch currentPeer -> packetLossVariance += (currentPeer -> packetLoss - packetLoss) / 4; } - currentPeer -> packetLossEpoch = timeCurrent; + currentPeer -> packetLossEpoch = host -> serviceTime; currentPeer -> packetsSent = 0; currentPeer -> packetsLost = 0; } - header.peerID = ENET_HOST_TO_NET_16 (currentPeer -> outgoingPeerID); - header.flags = 0; - header.commandCount = host -> commandCount; - header.sentTime = ENET_HOST_TO_NET_32 (timeCurrent); - header.challenge = currentPeer -> challenge; + 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 -> data = & header; - host -> buffers -> dataLength = sizeof (ENetProtocolHeader); + host -> buffers -> dataLength = sizeof (ENetProtocolHeader); + } + else + host -> buffers -> dataLength = (size_t) & ((ENetProtocolHeader *) 0) -> sentTime; - currentPeer -> lastSendTime = timeCurrent; + 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 + } + } - ++ packetsSent; + if (currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID) + host -> headerFlags |= currentPeer -> outgoingSessionID << ENET_PROTOCOL_HEADER_SESSION_SHIFT; + header -> peerID = ENET_HOST_TO_NET_16 (currentPeer -> outgoingPeerID | host -> headerFlags); + if (host -> checksum != NULL) + { + enet_uint32 * checksum = (enet_uint32 *) & headerData [host -> buffers -> dataLength]; + * checksum = currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer -> connectID : 0; + host -> buffers -> dataLength += sizeof (enet_uint32); + * checksum = host -> checksum (host -> buffers, host -> bufferCount); + } + + if (shouldCompress > 0) + { + host -> buffers [1].data = host -> packetData [1]; + host -> buffers [1].dataLength = shouldCompress; + host -> bufferCount = 2; + } + + currentPeer -> lastSendTime = host -> serviceTime; sentLength = enet_socket_send (host -> socket, & currentPeer -> address, host -> buffers, host -> bufferCount); @@ -1205,6 +1526,9 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch if (sentLength < 0) return -1; + + host -> totalSentData += sentLength; + host -> totalSentPackets ++; } return 0; @@ -1219,11 +1543,32 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch void enet_host_flush (ENetHost * host) { - timeCurrent = enet_time_get (); + 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. @@ -1263,13 +1608,13 @@ enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout) } } - timeCurrent = enet_time_get (); + host -> serviceTime = enet_time_get (); - timeout += timeCurrent; + timeout += host -> serviceTime; do { - if (ENET_TIME_DIFFERENCE (timeCurrent, host -> bandwidthThrottleEpoch) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) + 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)) @@ -1331,17 +1676,17 @@ enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout) } } - timeCurrent = enet_time_get (); + host -> serviceTime = enet_time_get (); - if (ENET_TIME_GREATER_EQUAL (timeCurrent, timeout)) + if (ENET_TIME_GREATER_EQUAL (host -> serviceTime, timeout)) return 0; waitCondition = ENET_SOCKET_WAIT_RECEIVE; - if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, timeCurrent)) != 0) + if (enet_socket_wait (host -> socket, & waitCondition, ENET_TIME_DIFFERENCE (timeout, host -> serviceTime)) != 0) return -1; - timeCurrent = enet_time_get (); + host -> serviceTime = enet_time_get (); } while (waitCondition == ENET_SOCKET_WAIT_RECEIVE); return 0; diff --git a/enet/tutorial.txt b/enet/tutorial.txt deleted file mode 100644 index f187e2d..0000000 --- a/enet/tutorial.txt +++ /dev/null @@ -1,325 +0,0 @@ -* Using ENet - - 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. - -i.e. - -int -main (int argc, char ** argv) -{ - if (enet_initialize () != 0) - { - fprintf (stderror, "An error occurred while initializing ENet.\n"); - return EXIT_FAILURE; - } - atexit (enet_deinitialize); - ... - ... - ... -} - -* 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. - -i.e. - - 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 */, - 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); - -* 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. - -i.e. - - ENetHost * client; - - clienet = enet_host_create (NULL /* create a client host */, - 1 /* only allow 1 outgoing connection */, - 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); - -* 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. - -i.e. - - 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; - } - } - ... - ... - ... - -* 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. - -i.e. - - /* 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 3. - * One could also broadcast the packet by - * enet_host_broadcast (host, 3, packet); - */ - enet_peer_send (peer, 3, packet); - ... - ... - ... - /* One could just use enet_host_service() instead. */ - enet_host_flush (host); - -* 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. - -i.e. - ENetEvent event; - - enet_peer_disconnect (& client -> peers [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 (& client -> peers [0]); - ... - ... - ... - -* Connecting to an ENet host - - A connection to a foregin 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. - -i.e. - 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); - - 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."); - } - ... - ... - ... - diff --git a/enet/unix.c b/enet/unix.c index 1e47624..db1b617 100644 --- a/enet/unix.c +++ b/enet/unix.c @@ -84,7 +84,7 @@ enet_address_set_host (ENetAddress * address, const char * name) char buffer [2048]; int errnum; -#ifdef linux +#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); @@ -110,6 +110,21 @@ enet_address_set_host (ENetAddress * address, const char * name) return 0; } +int +enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) +{ +#ifdef HAS_INET_NTOP + if (inet_ntop (AF_INET, & address -> host, name, nameLength) == NULL) +#else + char * addr = inet_ntoa (* (struct in_addr *) & address -> host); + if (addr != NULL) + strncpy (name, addr, nameLength); + else +#endif + return -1; + return 0; +} + int enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) { @@ -122,7 +137,7 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng in.s_addr = address -> host; -#ifdef linux +#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); @@ -134,71 +149,84 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng #endif if (hostEntry == NULL) - { -#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; - } + return enet_address_get_host_ip (address, name, nameLength); strncpy (name, hostEntry -> h_name, nameLength); return 0; } -ENetSocket -enet_socket_create (ENetSocketType type, const ENetAddress * address) +int +enet_socket_bind (ENetSocket socket, const ENetAddress * address) { - ENetSocket newSocket = socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); - int receiveBufferSize = ENET_HOST_RECEIVE_BUFFER_SIZE, - allowBroadcasting = 1; -#ifndef HAS_FCNTL - int nonBlocking = 1; -#endif struct sockaddr_in sin; - if (newSocket == ENET_SOCKET_NULL) - return ENET_SOCKET_NULL; + memset (& sin, 0, sizeof (struct sockaddr_in)); + + sin.sin_family = AF_INET; - if (type == ENET_SOCKET_TYPE_DATAGRAM) + if (address != NULL) + { + sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); + sin.sin_addr.s_addr = address -> host; + } + else { + sin.sin_port = 0; + sin.sin_addr.s_addr = INADDR_ANY; + } + + return bind (socket, + (struct sockaddr *) & sin, + sizeof (struct sockaddr_in)); +} + +int +enet_socket_listen (ENetSocket socket, int backlog) +{ + return listen (socket, backlog < 0 ? SOMAXCONN : backlog); +} + +ENetSocket +enet_socket_create (ENetSocketType type) +{ + return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); +} + +int +enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) +{ + int result = -1; + switch (option) + { + case ENET_SOCKOPT_NONBLOCK: #ifdef HAS_FCNTL - fcntl (newSocket, F_SETFL, O_NONBLOCK | fcntl (newSocket, F_GETFL)); + result = fcntl (socket, F_SETFL, O_NONBLOCK | fcntl (socket, F_GETFL)); #else - ioctl (newSocket, FIONBIO, & nonBlocking); + result = ioctl (socket, FIONBIO, & value); #endif + break; - setsockopt (newSocket, SOL_SOCKET, SO_RCVBUF, (char *) & receiveBufferSize, sizeof (int)); - setsockopt (newSocket, SOL_SOCKET, SO_BROADCAST, (char *) & allowBroadcasting, sizeof (int)); - } - - if (address == NULL) - return newSocket; + case ENET_SOCKOPT_BROADCAST: + result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int)); + break; - memset (& sin, 0, sizeof (struct sockaddr_in)); + case ENET_SOCKOPT_REUSEADDR: + result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int)); + break; - sin.sin_family = AF_INET; - sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); - sin.sin_addr.s_addr = address -> host; + case ENET_SOCKOPT_RCVBUF: + result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int)); + break; - if (bind (newSocket, - (struct sockaddr *) & sin, - sizeof (struct sockaddr_in)) == -1 || - (type == ENET_SOCKET_TYPE_STREAM && - listen (newSocket, SOMAXCONN) == -1)) - { - close (newSocket); + case ENET_SOCKOPT_SNDBUF: + result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int)); + break; - return ENET_SOCKET_NULL; + default: + break; } - - return newSocket; + return result == -1 ? -1 : 0; } int @@ -258,6 +286,8 @@ enet_socket_send (ENetSocket socket, 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; @@ -327,6 +357,17 @@ enet_socket_receive (ENetSocket socket, return recvLength; } +int +enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout) +{ + struct timeval timeVal; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal); +} + int enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) { diff --git a/enet/win32.c b/enet/win32.c index 2300071..e1fae23 100644 --- a/enet/win32.c +++ b/enet/win32.c @@ -73,6 +73,16 @@ enet_address_set_host (ENetAddress * address, const char * name) return 0; } +int +enet_address_get_host_ip (const ENetAddress * address, char * name, size_t nameLength) +{ + char * addr = inet_ntoa (* (struct in_addr *) & address -> host); + if (addr == NULL) + return -1; + strncpy (name, addr, nameLength); + return 0; +} + int enet_address_get_host (const ENetAddress * address, char * name, size_t nameLength) { @@ -83,43 +93,22 @@ enet_address_get_host (const ENetAddress * address, char * name, size_t nameLeng hostEntry = gethostbyaddr ((char *) & in, sizeof (struct in_addr), AF_INET); if (hostEntry == NULL) - { - char * addr = inet_ntoa (* (struct in_addr *) & address -> host); - if (addr == NULL) - return -1; - strncpy (name, addr, nameLength); - return 0; - } + return enet_address_get_host_ip (address, name, nameLength); strncpy (name, hostEntry -> h_name, nameLength); return 0; } -ENetSocket -enet_socket_create (ENetSocketType type, const ENetAddress * address) +int +enet_socket_bind (ENetSocket socket, const ENetAddress * address) { - ENetSocket newSocket = socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); - u_long nonBlocking = 1; - int receiveBufferSize = ENET_HOST_RECEIVE_BUFFER_SIZE, - allowBroadcasting = 1; struct sockaddr_in sin; - if (newSocket == ENET_SOCKET_NULL) - return ENET_SOCKET_NULL; - - if (type == ENET_SOCKET_TYPE_DATAGRAM) - { - ioctlsocket (newSocket, FIONBIO, & nonBlocking); - - setsockopt (newSocket, SOL_SOCKET, SO_RCVBUF, (char *) & receiveBufferSize, sizeof (int)); - setsockopt (newSocket, SOL_SOCKET, SO_BROADCAST, (char *) & allowBroadcasting, sizeof (int)); - } - memset (& sin, 0, sizeof (struct sockaddr_in)); sin.sin_family = AF_INET; - + if (address != NULL) { sin.sin_port = ENET_HOST_TO_NET_16 (address -> port); @@ -131,19 +120,56 @@ enet_socket_create (ENetSocketType type, const ENetAddress * address) sin.sin_addr.s_addr = INADDR_ANY; } - if (bind (newSocket, - (struct sockaddr *) & sin, - sizeof (struct sockaddr_in)) == SOCKET_ERROR || - (type == ENET_SOCKET_TYPE_STREAM && - address != NULL && - listen (newSocket, SOMAXCONN) == SOCKET_ERROR)) - { - closesocket (newSocket); + return bind (socket, + (struct sockaddr *) & sin, + sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0; +} - return ENET_SOCKET_NULL; - } +int +enet_socket_listen (ENetSocket socket, int backlog) +{ + return listen (socket, backlog < 0 ? SOMAXCONN : backlog) == SOCKET_ERROR ? -1 : 0; +} - return newSocket; +ENetSocket +enet_socket_create (ENetSocketType type) +{ + return socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0); +} + +int +enet_socket_set_option (ENetSocket socket, ENetSocketOption option, int value) +{ + int result = SOCKET_ERROR; + switch (option) + { + case ENET_SOCKOPT_NONBLOCK: + { + u_long nonBlocking = (u_long) value; + result = ioctlsocket (socket, FIONBIO, & nonBlocking); + break; + } + + case ENET_SOCKOPT_BROADCAST: + result = setsockopt (socket, SOL_SOCKET, SO_BROADCAST, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_REUSEADDR: + result = setsockopt (socket, SOL_SOCKET, SO_REUSEADDR, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_RCVBUF: + result = setsockopt (socket, SOL_SOCKET, SO_RCVBUF, (char *) & value, sizeof (int)); + break; + + case ENET_SOCKOPT_SNDBUF: + result = setsockopt (socket, SOL_SOCKET, SO_SNDBUF, (char *) & value, sizeof (int)); + break; + + default: + break; + } + return result == SOCKET_ERROR ? -1 : 0; } int @@ -157,7 +183,7 @@ enet_socket_connect (ENetSocket socket, const ENetAddress * address) 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, sizeof (struct sockaddr_in)) == SOCKET_ERROR ? -1 : 0; } ENetSocket @@ -200,6 +226,8 @@ enet_socket_send (ENetSocket socket, 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; @@ -267,6 +295,17 @@ enet_socket_receive (ENetSocket socket, return (int) recvLength; } +int +enet_socketset_select (ENetSocket maxSocket, ENetSocketSet * readSet, ENetSocketSet * writeSet, enet_uint32 timeout) +{ + struct timeval timeVal; + + timeVal.tv_sec = timeout / 1000; + timeVal.tv_usec = (timeout % 1000) * 1000; + + return select (maxSocket + 1, readSet, writeSet, NULL, & timeVal); +} + int enet_socket_wait (ENetSocket socket, enet_uint32 * condition, enet_uint32 timeout) { diff --git a/src/Communicator.cxx b/src/Communicator.cxx index c96cbb5..a3ddd99 100644 --- a/src/Communicator.cxx +++ b/src/Communicator.cxx @@ -148,7 +148,7 @@ void Communicator::initialize ( int mode, int port, char host_name[256], case CM_SERVER: { address.host = ENET_HOST_ANY; - host = enet_host_create(&address, 1, 0, 0); + host = enet_host_create(&address, 1, NUM_CHANNELS, 0, 0); if (NULL == host) { cerr << "An error occured while trying to create the server" << endl; exit(1); @@ -208,7 +208,7 @@ void Communicator::initialize ( int mode, int port, char host_name[256], } case CM_CLIENT: { - host = enet_host_create(NULL, 1, 57600 / 8, 14400 / 8); + host = enet_host_create(NULL, 1, NUM_CHANNELS, 57600 / 8, 14400 / 8); if(NULL == host) { cerr << "Could not create ENet host." << endl; exit(1); @@ -224,7 +224,7 @@ void Communicator::initialize ( int mode, int port, char host_name[256], } - peer = enet_host_connect(host, &address, NUM_CHANNELS); + peer = enet_host_connect(host, &address, NUM_CHANNELS, 0); if(NULL == peer) { cerr << "No available peers for initiating an ENet connection." << endl; exit(1); diff --git a/src/OBJModel.cxx b/src/OBJModel.cxx index 5a44419..ac79b1c 100644 --- a/src/OBJModel.cxx +++ b/src/OBJModel.cxx @@ -23,6 +23,7 @@ #include "TextureLoader.h" #include +#include #include #include diff --git a/src/OBJModel.h b/src/OBJModel.h index 0ee58e2..ecaa6a9 100644 --- a/src/OBJModel.h +++ b/src/OBJModel.h @@ -32,7 +32,7 @@ class OBJModel { public: - OBJModel() { }; + OBJModel() { } OBJModel(const std::string& filename); virtual ~OBJModel(); diff --git a/src/TextureLoader.cxx b/src/TextureLoader.cxx index a62f773..0160a5e 100644 --- a/src/TextureLoader.cxx +++ b/src/TextureLoader.cxx @@ -99,7 +99,7 @@ GLubyte *TextureLoader::loadImage ( const std::string &file_name, int _height, if (!img) { SDL_RWops *img_file_rwops = SDL_RWFromFile(file_name.data(), "r"); - img = IMG_LoadTyped_RW(img_file_rwops, 1, "TGA"); + img = IMG_LoadTyped_RW(img_file_rwops, 1, const_cast("TGA")); if (!img) { cerr << "Error opening texture file '" << file_name << "'. " << IMG_GetError() << endl; diff --git a/src/obj_block.cxx b/src/obj_block.cxx index eec5e71..840dfaa 100644 --- a/src/obj_block.cxx +++ b/src/obj_block.cxx @@ -30,6 +30,7 @@ #include "glext.h" +#include #include #include "Game.h" @@ -56,11 +57,12 @@ void Displayer::generateBlockDisplayList ( ) block_model = new OBJModel(GC_MODEL_DIRECTORY("crackattackcubehires.obj")); block_model_tex = new OBJModel(GC_MODEL_DIRECTORY("crackattackcubehires_tex.obj")); } else { + std::string base = GC_MODEL_DIRECTORY("crack_attack_bf_"); const size_t n = 256; - char model_name[n]; - snprintf(model_name, n, "crack_attack_bf_%03d.obj", i); - block_model = new OBJModel(GC_MODEL_DIRECTORY(model_name)); - block_model_tex = new OBJModel(GC_MODEL_DIRECTORY(model_name)); + char model_number[n]; + snprintf(model_number, n, "%03d.obj", i); + block_model = new OBJModel(base + model_number); + block_model_tex = new OBJModel(base + model_number); } } block_list[i] = glGenLists(1);