Kaynağa Gözat

1.3.0 import

eihrul 15 yıl önce
ebeveyn
işleme
572636062e
14 değiştirilmiş dosya ile 301 ekleme ve 132 silme
  1. 17 0
      ChangeLog
  2. 1 1
      Makefile.am
  3. 6 15
      callbacks.c
  4. 1 1
      configure.ac
  5. 6 5
      docs/mainpage.dox
  6. 3 1
      docs/tutorial.dox
  7. 4 0
      enet.dsp
  8. 3 0
      enet_dll.cbp
  9. 65 24
      host.c
  10. 0 2
      include/enet/callbacks.h
  11. 39 12
      include/enet/enet.h
  12. 16 7
      include/enet/protocol.h
  13. 3 3
      peer.c
  14. 137 61
      protocol.c

+ 17 - 0
ChangeLog

@@ -1,3 +1,20 @@
+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

+ 1 - 1
Makefile.am

@@ -14,7 +14,7 @@ enetinclude_HEADERS = \
 	include/enet/win32.h
 
 lib_LTLIBRARIES = libenet.la
-libenet_la_SOURCES = host.c list.c callbacks.c packet.c peer.c protocol.c unix.c win32.c
+libenet_la_SOURCES = callbacks.c compress.c host.c list.c packet.c peer.c protocol.c unix.c win32.c
 # see info '(libtool) Updating version info' before making a release
 libenet_la_LDFLAGS = $(AM_LDFLAGS) -version-info 0:0:0
 INCLUDES = -Iinclude

+ 6 - 15
callbacks.c

@@ -5,11 +5,14 @@
 #define ENET_BUILDING_LIB 1
 #include "enet/enet.h"
 
-static ENetCallbacks callbacks = { malloc, free, rand, abort };
+static ENetCallbacks callbacks = { malloc, free, abort };
 
 int
 enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits)
 {
+   if (version < ENET_VERSION_CREATE (1, 3, 0))
+     return -1;
+
    if (inits -> malloc != NULL || inits -> free != NULL)
    {
       if (inits -> malloc == NULL || inits -> free == NULL)
@@ -19,14 +22,8 @@ enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits
       callbacks.free = inits -> free;
    }
       
-   if (inits -> rand != NULL)
-     callbacks.rand = inits -> rand;
-
-   if (version >= ENET_VERSION_CREATE (1, 2, 2))
-   {
-      if (inits -> no_memory != NULL)
-        callbacks.no_memory = inits -> no_memory;
-   }
+   if (inits -> no_memory != NULL)
+     callbacks.no_memory = inits -> no_memory;
 
    return enet_initialize ();
 }
@@ -48,9 +45,3 @@ enet_free (void * memory)
    callbacks.free (memory);
 }
 
-int
-enet_rand (void)
-{
-   return callbacks.rand ();
-}
-

+ 1 - 1
configure.ac

@@ -1,4 +1,4 @@
-AC_INIT([libenet], [1.2.2])
+AC_INIT([libenet], [1.3.0])
 AC_CONFIG_SRCDIR([include/enet/enet.h])
 AM_INIT_AUTOMAKE([foreign])
 

+ 6 - 5
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
 
@@ -36,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.2.2) can be downloaded <a href="http://enet.bespin.org/download/enet-1.2.2.tar.gz">here</a>.
+The most recent stable release (1.3.0) can be downloaded <a href="http://enet.bespin.org/download/enet-1.3.0.tar.gz">here</a>. 
+The last release that is protocol compatible with the 1.2 series or earlier (1.2.2) can be downloaded <a href="http://enet.bespin.org/download/enet-1.3.0.tar.gz">here</a> 
 
 To access ENet via anonymous CVS, you must use the CVSROOT
 :pserver:anonymous\@bespin.org:/var/lib/cvs/enet with an empty

+ 3 - 1
docs/tutorial.dox

@@ -73,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)
@@ -100,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 */);
 
@@ -321,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)
     {

+ 4 - 0
enet.dsp

@@ -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

+ 3 - 0
enet_dll.cbp

@@ -44,6 +44,9 @@
 		<Unit filename="callbacks.c">
 			<Option compilerVar="CC" />
 		</Unit>
+		<Unit filename="compress.c">
+			<Option compilerVar="CC" />
+		</Unit>
 		<Unit filename="host.c">
 			<Option compilerVar="CC" />
 		</Unit>

+ 65 - 24
host.c

@@ -4,6 +4,7 @@
 */
 #define ENET_BUILDING_LIB 1
 #include <string.h>
+#include <time.h>
 #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,7 +27,7 @@
     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;
     ENetPeer * currentPeer;
@@ -66,7 +68,15 @@ enet_host_create (const ENetAddress * address, size_t peerCount, enet_uint32 inc
     if (address != NULL)
       host -> address = * address;
 
-    host -> channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
+    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;
@@ -78,6 +88,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, enet_uint32 inc
     host -> checksum = NULL;
     host -> receivedAddress.host = ENET_HOST_ANY;
     host -> receivedAddress.port = 0;
+    host -> receivedData = NULL;
     host -> receivedDataLength = 0;
      
     host -> totalSentData = 0;
@@ -85,6 +96,11 @@ enet_host_create (const ENetAddress * address, size_t peerCount, enet_uint32 inc
     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;
@@ -93,6 +109,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, enet_uint32 inc
     {
        currentPeer -> host = host;
        currentPeer -> incomingPeerID = currentPeer - host -> peers;
+       currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF;
        currentPeer -> data = NULL;
 
        enet_list_clear (& currentPeer -> acknowledgements);
@@ -104,7 +121,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, enet_uint32 inc
 
        enet_peer_reset (currentPeer);
     }
- 
+
     return host;
 }
 
@@ -125,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);
 }
@@ -133,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;
@@ -167,7 +188,7 @@ enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelC
     currentPeer -> channelCount = channelCount;
     currentPeer -> state = ENET_PEER_STATE_CONNECTING;
     currentPeer -> address = * address;
-    currentPeer -> sessionID = (enet_uint32) enet_rand ();
+    currentPeer -> connectID = ++ host -> randomSeed;
 
     if (host -> outgoingBandwidth == 0)
       currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
@@ -200,7 +221,9 @@ enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelC
     command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
     command.header.channelID = 0xFF;
     command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID);
-    command.connect.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);
@@ -208,29 +231,14 @@ 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.sessionID = currentPeer -> sessionID;
-    
+    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;
 }
 
-/** 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;
-}
- 
 /** Queues a packet to be sent to all peers associated with the host.
     @param host host on which to broadcast the packet
     @param channelID channel on which to broadcast
@@ -255,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

+ 0 - 2
include/enet/callbacks.h

@@ -11,7 +11,6 @@ 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;
 
@@ -21,7 +20,6 @@ typedef struct _ENetCallbacks
 */
 extern void * enet_malloc (size_t);
 extern void   enet_free (void *);
-extern int    enet_rand (void);
 
 /** @} */
 

+ 39 - 12
include/enet/enet.h

@@ -24,8 +24,8 @@ extern "C"
 #include "enet/callbacks.h"
 
 #define ENET_VERSION_MAJOR 1
-#define ENET_VERSION_MINOR 2
-#define ENET_VERSION_PATCH 2
+#define ENET_VERSION_MINOR 3
+#define ENET_VERSION_PATCH 0
 #define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch))
 #define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH)
 
@@ -233,7 +233,9 @@ typedef struct _ENetPeer
    struct _ENetHost * host;
    enet_uint16   outgoingPeerID;
    enet_uint16   incomingPeerID;
-   enet_uint32   sessionID;
+   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;
@@ -267,7 +269,7 @@ 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_uint16   outgoingReliableSequenceNumber;
@@ -281,15 +283,29 @@ typedef struct _ENetPeer
    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()
@@ -297,7 +313,8 @@ typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * b
     @sa enet_host_service()
     @sa enet_host_flush()
     @sa enet_host_broadcast()
-    @sa enet_host_checksum()
+    @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()
@@ -310,6 +327,7 @@ typedef struct _ENetHost
    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 */
@@ -323,9 +341,11 @@ typedef struct _ENetHost
    size_t               commandCount;
    ENetBuffer           buffers [ENET_BUFFER_MAXIMUM];
    size_t               bufferCount;
-   ENetChecksumCallback checksum;
+   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 [ENET_PROTOCOL_MAXIMUM_MTU];
+   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 */
@@ -475,13 +495,15 @@ 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, enet_uint32, enet_uint32);
+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_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 *);
@@ -503,6 +525,11 @@ extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const
 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

+ 16 - 7
include/enet/protocol.h

@@ -16,7 +16,7 @@ enum
    ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE     = 32768,
    ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT   = 1,
    ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT   = 255,
-   ENET_PROTOCOL_MAXIMUM_PEER_ID         = 0x7FFF
+   ENET_PROTOCOL_MAXIMUM_PEER_ID         = 0xFFF
 };
 
 typedef enum _ENetProtocolCommand
@@ -43,8 +43,12 @@ typedef enum _ENetProtocolFlag
    ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7),
    ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6),
 
-   ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15),
-   ENET_PROTOCOL_HEADER_FLAG_MASK      = 0x8000
+   ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14),
+   ENET_PROTOCOL_HEADER_FLAG_SENT_TIME  = (1 << 15),
+   ENET_PROTOCOL_HEADER_FLAG_MASK       = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME,
+
+   ENET_PROTOCOL_HEADER_SESSION_MASK    = (3 << 12),
+   ENET_PROTOCOL_HEADER_SESSION_SHIFT   = 12
 } ENetProtocolFlag;
 
 #ifdef _MSC_VER_
@@ -58,7 +62,6 @@ typedef enum _ENetProtocolFlag
 
 typedef struct _ENetProtocolHeader
 {
-   enet_uint32 checksum;
    enet_uint16 peerID;
    enet_uint16 sentTime;
 } ENET_PACKED ENetProtocolHeader;
@@ -81,7 +84,9 @@ 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;
@@ -89,14 +94,17 @@ typedef struct _ENetProtocolConnect
    enet_uint32 packetThrottleInterval;
    enet_uint32 packetThrottleAcceleration;
    enet_uint32 packetThrottleDeceleration;
-   enet_uint32 sessionID;
+   enet_uint32 connectID;
+   enet_uint32 data;
 } ENET_PACKED ENetProtocolConnect;
 
 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;
@@ -104,6 +112,7 @@ typedef struct _ENetProtocolVerifyConnect
    enet_uint32 packetThrottleInterval;
    enet_uint32 packetThrottleAcceleration;
    enet_uint32 packetThrottleDeceleration;
+   enet_uint32 connectID;
 } ENET_PACKED ENetProtocolVerifyConnect;
 
 typedef struct _ENetProtocolBandwidthLimit

+ 3 - 3
peer.c

@@ -325,7 +325,7 @@ void
 enet_peer_reset (ENetPeer * peer)
 {
     peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID;
-    peer -> sessionID = 0;
+    peer -> connectID = 0;
 
     peer -> state = ENET_PEER_STATE_DISCONNECTED;
 
@@ -363,7 +363,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));
     
@@ -477,7 +477,7 @@ enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data)
            enet_list_empty (& peer -> sentReliableCommands)))
     {
         peer -> state = ENET_PEER_STATE_DISCONNECT_LATER;
-        peer -> disconnectData = data;
+        peer -> eventData = data;
     }
     else
       enet_peer_disconnect (peer, data);

+ 137 - 61
protocol.c

@@ -48,6 +48,7 @@ enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event)
 
            event -> type = ENET_EVENT_TYPE_CONNECT;
            event -> peer = peer;
+           event -> data = peer -> eventData;
 
            return 1;
            
@@ -56,7 +57,7 @@ enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event)
 
            event -> type = ENET_EVENT_TYPE_DISCONNECT;
            event -> peer = peer;
-           event -> data = peer -> disconnectData;
+           event -> data = peer -> eventData;
 
            enet_peer_reset (peer);
 
@@ -111,6 +112,7 @@ enet_protocol_notify_connect (ENetHost * host, ENetPeer * peer, ENetEvent * even
 
         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);
@@ -134,7 +136,11 @@ 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
@@ -238,31 +244,13 @@ enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliabl
 static ENetPeer *
 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 (host -> checksum != NULL)
-    {
-        enet_uint32 checksum = header -> checksum;
-        ENetBuffer buffer;
-
-        command -> header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (command -> header.reliableSequenceNumber);
-
-        header -> checksum = command -> connect.sessionID;
-
-        buffer.data = host -> receivedData;
-        buffer.dataLength = host -> receivedDataLength;
-
-        if (host -> checksum (& buffer, 1) != checksum)
-          return NULL;
-
-        command -> header.reliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> header.reliableSequenceNumber);
-    }
- 
     channelCount = ENET_NET_TO_HOST_32 (command -> connect.channelCount);
 
     if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT ||
@@ -276,7 +264,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
         if (currentPeer -> state != ENET_PEER_STATE_DISCONNECTED &&
             currentPeer -> address.host == host -> receivedAddress.host &&
             currentPeer -> address.port == host -> receivedAddress.port &&
-            currentPeer -> sessionID == command -> connect.sessionID)
+            currentPeer -> connectID == command -> connect.connectID)
           return NULL;
     }
 
@@ -298,7 +286,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
       return NULL;
     currentPeer -> channelCount = channelCount;
     currentPeer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT;
-    currentPeer -> sessionID = command -> connect.sessionID;
+    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);
@@ -306,6 +294,19 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
     currentPeer -> packetThrottleInterval = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleInterval);
     currentPeer -> packetThrottleAcceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleAcceleration);
     currentPeer -> packetThrottleDeceleration = ENET_NET_TO_HOST_32 (command -> connect.packetThrottleDeceleration);
+    currentPeer -> eventData = ENET_NET_TO_HOST_32 (command -> connect.data);
+
+    incomingSessionID = command -> connect.incomingSessionID == 0xFF ? currentPeer -> outgoingSessionID : command -> connect.incomingSessionID;
+    incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT);
+    if (incomingSessionID == currentPeer -> outgoingSessionID)
+      incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT);
+    currentPeer -> outgoingSessionID = incomingSessionID;
+
+    outgoingSessionID = command -> connect.outgoingSessionID == 0xFF ? currentPeer -> incomingSessionID : command -> connect.outgoingSessionID;
+    outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT);
+    if (outgoingSessionID == currentPeer -> incomingSessionID)
+      outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT);
+    currentPeer -> incomingSessionID = outgoingSessionID;
 
     for (channel = currentPeer -> channels;
          channel < & currentPeer -> channels [channelCount];
@@ -322,7 +323,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
         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;
@@ -370,6 +371,8 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
     verifyCommand.header.command = ENET_PROTOCOL_COMMAND_VERIFY_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
     verifyCommand.header.channelID = 0xFF;
     verifyCommand.verifyConnect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID);
+    verifyCommand.verifyConnect.incomingSessionID = incomingSessionID;
+    verifyCommand.verifyConnect.outgoingSessionID = outgoingSessionID;
     verifyCommand.verifyConnect.mtu = ENET_HOST_TO_NET_16 (currentPeer -> mtu);
     verifyCommand.verifyConnect.windowSize = ENET_HOST_TO_NET_32 (windowSize);
     verifyCommand.verifyConnect.channelCount = ENET_HOST_TO_NET_32 (channelCount);
@@ -378,6 +381,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
     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);
 
@@ -657,7 +661,9 @@ enet_protocol_handle_disconnect (ENetHost * host, ENetPeer * peer, const ENetPro
     else
       enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE);
 
-    peer -> disconnectData = ENET_NET_TO_HOST_32 (command -> disconnect.data);
+    if (peer -> state != ENET_PEER_STATE_DISCONNECTED)
+      peer -> eventData = ENET_NET_TO_HOST_32 (command -> disconnect.data);
+
     return 0;
 }
 
@@ -737,7 +743,7 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer *
        if (enet_list_empty (& peer -> outgoingReliableCommands) &&
            enet_list_empty (& peer -> outgoingUnreliableCommands) &&   
            enet_list_empty (& peer -> sentReliableCommands))
-         enet_peer_disconnect (peer, peer -> disconnectData);
+         enet_peer_disconnect (peer, peer -> eventData);
        break;
     }
    
@@ -747,8 +753,7 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer *
 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)
@@ -759,8 +764,11 @@ enet_protocol_handle_verify_connect (ENetHost * host, ENetEvent * event, ENetPee
     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 -> eventData = 0;
+
         enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE);
 
         return -1;
@@ -772,8 +780,10 @@ enet_protocol_handle_verify_connect (ENetHost * host, ENetEvent * event, ENetPee
       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;
@@ -811,15 +821,21 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
     enet_uint8 * currentData;
     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;
 
     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;
+    peerID &= ~ (ENET_PROTOCOL_HEADER_FLAG_MASK | ENET_PROTOCOL_HEADER_SESSION_MASK);
+
+    headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof (ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *) 0) -> sentTime);
+    if (host -> checksum != NULL)
+      headerSize += sizeof (enet_uint32);
 
     if (peerID == ENET_PROTOCOL_MAXIMUM_PEER_ID)
       peer = NULL;
@@ -831,34 +847,55 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
        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))
+             peer -> address.host != ENET_HOST_BROADCAST) ||
+           (peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID &&
+            sessionID != peer -> incomingSessionID))
          return 0;
+    }
+ 
+    if (flags & ENET_PROTOCOL_HEADER_FLAG_COMPRESSED)
+    {
+        size_t originalSize;
+        if (host -> compressor.context == NULL || host -> compressor.decompress == NULL)
+          return 0;
+
+        originalSize = host -> compressor.decompress (host -> compressor.context,
+                                    host -> receivedData + headerSize, 
+                                    host -> receivedDataLength - headerSize, 
+                                    host -> packetData [1] + headerSize, 
+                                    sizeof (host -> packetData [1]) - headerSize);
+        if (originalSize <= 0 || originalSize > sizeof (host -> packetData [1]) - headerSize)
+          return 0;
+
+        memcpy (host -> packetData [1], header, headerSize);
+        host -> receivedData = host -> packetData [1];
+        host -> receivedDataLength = headerSize + originalSize;
+    }
 
-       if (host -> checksum != NULL)
-       {
-           enet_uint32 checksum = header -> checksum;
-           ENetBuffer buffer;
-
-           header -> checksum = peer -> sessionID;
+    if (host -> checksum != NULL)
+    {
+        enet_uint32 * checksum = (enet_uint32 *) & host -> receivedData [headerSize - sizeof (enet_uint32)],
+                    desiredChecksum = * checksum;
+        ENetBuffer buffer;
 
-           buffer.data = host -> receivedData;
-           buffer.dataLength = host -> receivedDataLength;
+        * checksum = peer != NULL ? peer -> connectID : 0;
 
-           if (host -> checksum (& buffer, 1) != checksum)
-             return 0;
-       }
-       else
-       if (header -> checksum != peer -> sessionID)
-         return 0;
+        buffer.data = host -> receivedData;
+        buffer.dataLength = host -> receivedDataLength;
 
+        if (host -> checksum (& buffer, 1) != desiredChecksum)
+          return 0;
+    }
+       
+    if (peer != NULL)
+    {
        peer -> address.host = host -> receivedAddress.host;
        peer -> address.port = host -> receivedAddress.port;
        peer -> incomingDataTotal += host -> receivedDataLength;
     }
     
-    headerSize = (flags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? sizeof (ENetProtocolHeader) : (size_t) & ((ENetProtocolHeader *) 0) -> sentTime);
     currentData = host -> receivedData + headerSize;
   
     while (currentData < & host -> receivedData [host -> receivedDataLength])
@@ -991,8 +1028,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,
@@ -1005,6 +1042,7 @@ 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;
@@ -1158,7 +1196,7 @@ enet_protocol_send_unreliable_outgoing_commands (ENetHost * host, ENetPeer * pee
         enet_list_empty (& peer -> outgoingReliableCommands) &&
         enet_list_empty (& peer -> outgoingUnreliableCommands) && 
         enet_list_empty (& peer -> sentReliableCommands))
-      enet_peer_disconnect (peer, peer -> disconnectData);
+      enet_peer_disconnect (peer, peer -> eventData);
 }
 
 static int
@@ -1321,10 +1359,12 @@ enet_protocol_send_reliable_outgoing_commands (ENetHost * host, ENetPeer * peer)
 static int
 enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int checkForTimeouts)
 {
-    ENetProtocolHeader header;
+    enet_uint8 headerData [sizeof (ENetProtocolHeader) + sizeof (enet_uint32)];
+    ENetProtocolHeader * header = (ENetProtocolHeader *) headerData;
     ENetPeer * currentPeer;
     int sentLength;
-    
+    size_t shouldCompress = 0;
+ 
     host -> continueSending = 1;
 
     while (host -> continueSending)
@@ -1403,21 +1443,57 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
            currentPeer -> packetsLost = 0;
         }
 
-        header.checksum = currentPeer -> sessionID;
-        header.peerID = ENET_HOST_TO_NET_16 (currentPeer -> outgoingPeerID | host -> headerFlags);
-        
-        host -> buffers -> data = & header;
+        host -> buffers -> data = headerData;
         if (host -> headerFlags & ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)
         {
-            header.sentTime = ENET_HOST_TO_NET_16 (host -> serviceTime & 0xFFFF);
+            header -> sentTime = ENET_HOST_TO_NET_16 (host -> serviceTime & 0xFFFF);
 
             host -> buffers -> dataLength = sizeof (ENetProtocolHeader);
         }
         else
           host -> buffers -> dataLength = (size_t) & ((ENetProtocolHeader *) 0) -> sentTime;
- 
+
+        shouldCompress = 0;
+        if (host -> compressor.context != NULL && host -> compressor.compress != NULL)
+        {
+            size_t originalSize = host -> packetSize - sizeof(ENetProtocolHeader),
+                   compressedSize = host -> compressor.compress (host -> compressor.context,
+                                        & host -> buffers [1], host -> bufferCount - 1,
+                                        originalSize,
+                                        host -> packetData [1],
+                                        originalSize);
+            if (compressedSize > 0 && compressedSize < originalSize)
+            {
+                host -> headerFlags |= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED;
+                shouldCompress = compressedSize;
+#ifdef ENET_DEBUG_COMPRESS
+#ifdef WIN32
+           printf (
+#else
+           fprintf (stderr,
+#endif
+                    "peer %u: compressed %u -> %u (%u%%)\n", currentPeer -> incomingPeerID, originalSize, compressedSize, (compressedSize * 100) / originalSize);
+#endif
+            }
+        }
+
+        if (currentPeer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID)
+          host -> headerFlags |= currentPeer -> outgoingSessionID << ENET_PROTOCOL_HEADER_SESSION_SHIFT;
+        header -> peerID = ENET_HOST_TO_NET_16 (currentPeer -> outgoingPeerID | host -> headerFlags);
         if (host -> checksum != NULL)
-          header.checksum = host -> checksum (host -> buffers, host -> bufferCount);
+        {
+            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;