Browse Source

support for ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT
1.3.2 release prep

eihrul 14 years ago
parent
commit
f38c177db0
9 changed files with 256 additions and 32 deletions
  1. 16 0
      ChangeLog
  2. 1 1
      Makefile.am
  3. 1 1
      configure.ac
  4. 2 2
      docs/mainpage.dox
  5. 1 0
      host.c
  6. 6 2
      include/enet/enet.h
  7. 2 1
      include/enet/protocol.h
  8. 94 25
      peer.c
  9. 133 0
      protocol.c

+ 16 - 0
ChangeLog

@@ -1,3 +1,10 @@
+ENet 1.3.2 (May 31, 2011):
+
+* added support for unreliable packet fragmenting via the packet flag
+ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT
+* fixed regression in unreliable packet queuing
+* added check against received port to limit some forms of IP-spoofing
+
 ENet 1.3.1 (February 10, 2011):
 ENet 1.3.1 (February 10, 2011):
 
 
 * fixed bug in tracking of reliable data in transit
 * fixed bug in tracking of reliable data in transit
@@ -21,6 +28,15 @@ 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
 earlier. The enet_host_connect and enet_host_create API functions require
 supplying additional parameters.
 supplying additional parameters.
 
 
+ENet 1.2.4 (May 31, 2011):
+
+* fixed regression in unreliable packet queuing
+* added check against received port to limit some forms of IP-spoofing
+
+ENet 1.2.3 (February 10, 2011):
+
+* fixed bug in tracking reliable data in transit
+
 ENet 1.2.2 (June 5, 2010):
 ENet 1.2.2 (June 5, 2010):
 
 
 * checksum functionality is now enabled by setting a checksum callback
 * checksum functionality is now enabled by setting a checksum callback

+ 1 - 1
Makefile.am

@@ -16,7 +16,7 @@ enetinclude_HEADERS = \
 lib_LTLIBRARIES = libenet.la
 lib_LTLIBRARIES = libenet.la
 libenet_la_SOURCES = callbacks.c compress.c host.c list.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
 # see info '(libtool) Updating version info' before making a release
-libenet_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:1:0
+libenet_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:2:0
 INCLUDES = -Iinclude
 INCLUDES = -Iinclude
 
 
 ACLOCAL_AMFLAGS = -Im4
 ACLOCAL_AMFLAGS = -Im4

+ 1 - 1
configure.ac

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

+ 2 - 2
docs/mainpage.dox

@@ -36,8 +36,8 @@ portable, and easily embeddable.
 You can retrieve the source to ENet by downloading it in either .tar.gz form
 You can retrieve the source to ENet by downloading it in either .tar.gz form
 or accessing the cvs distribution directly.
 or accessing the cvs distribution directly.
 
 
-The most recent stable release (1.3.1) can be downloaded <a href="http://enet.bespin.org/download/enet-1.3.1.tar.gz">here</a>. 
-The last release that is protocol compatible with the 1.2 series or earlier (1.2.3) can be downloaded <a href="http://enet.bespin.org/download/enet-1.2.3.tar.gz">here</a> 
+The most recent stable release (1.3.2) can be downloaded <a href="http://enet.bespin.org/download/enet-1.3.2.tar.gz">here</a>. 
+The last release that is protocol compatible with the 1.2 series or earlier (1.2.4) can be downloaded <a href="http://enet.bespin.org/download/enet-1.2.4.tar.gz">here</a> 
 
 
 To access ENet via anonymous CVS, you must use the CVSROOT
 To access ENet via anonymous CVS, you must use the CVSROOT
 :pserver:anonymous\@bespin.org:/var/lib/cvs/enet with an empty
 :pserver:anonymous\@bespin.org:/var/lib/cvs/enet with an empty

+ 1 - 0
host.c

@@ -210,6 +210,7 @@ enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelC
         channel -> outgoingReliableSequenceNumber = 0;
         channel -> outgoingReliableSequenceNumber = 0;
         channel -> outgoingUnreliableSequenceNumber = 0;
         channel -> outgoingUnreliableSequenceNumber = 0;
         channel -> incomingReliableSequenceNumber = 0;
         channel -> incomingReliableSequenceNumber = 0;
+        channel -> incomingUnreliableSequenceNumber = 0;
 
 
         enet_list_clear (& channel -> incomingReliableCommands);
         enet_list_clear (& channel -> incomingReliableCommands);
         enet_list_clear (& channel -> incomingUnreliableCommands);
         enet_list_clear (& channel -> incomingUnreliableCommands);

+ 6 - 2
include/enet/enet.h

@@ -25,7 +25,7 @@ extern "C"
 
 
 #define ENET_VERSION_MAJOR 1
 #define ENET_VERSION_MAJOR 1
 #define ENET_VERSION_MINOR 3
 #define ENET_VERSION_MINOR 3
-#define ENET_VERSION_PATCH 1
+#define ENET_VERSION_PATCH 2
 #define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch))
 #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)
 #define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH)
 
 
@@ -96,7 +96,10 @@ typedef enum _ENetPacketFlag
      */
      */
    ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1),
    ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1),
    /** packet will not allocate data, and user must supply it instead */
    /** packet will not allocate data, and user must supply it instead */
-   ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2)
+   ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2),
+   /** packet will be fragmented using unreliable (instead of reliable) sends
+     * if it exceeds the MTU */
+   ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3)
 } ENetPacketFlag;
 } ENetPacketFlag;
 
 
 struct _ENetPacket;
 struct _ENetPacket;
@@ -218,6 +221,7 @@ typedef struct _ENetChannel
    enet_uint16  usedReliableWindows;
    enet_uint16  usedReliableWindows;
    enet_uint16  reliableWindows [ENET_PEER_RELIABLE_WINDOWS];
    enet_uint16  reliableWindows [ENET_PEER_RELIABLE_WINDOWS];
    enet_uint16  incomingReliableSequenceNumber;
    enet_uint16  incomingReliableSequenceNumber;
+   enet_uint16  incomingUnreliableSequenceNumber;
    ENetList     incomingReliableCommands;
    ENetList     incomingReliableCommands;
    ENetList     incomingUnreliableCommands;
    ENetList     incomingUnreliableCommands;
 } ENetChannel;
 } ENetChannel;

+ 2 - 1
include/enet/protocol.h

@@ -33,7 +33,8 @@ typedef enum _ENetProtocolCommand
    ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED   = 9,
    ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED   = 9,
    ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT    = 10,
    ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT    = 10,
    ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11,
    ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11,
-   ENET_PROTOCOL_COMMAND_COUNT              = 12,
+   ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12,
+   ENET_PROTOCOL_COMMAND_COUNT              = 13,
 
 
    ENET_PROTOCOL_COMMAND_MASK               = 0x0F
    ENET_PROTOCOL_COMMAND_MASK               = 0x0F
 } ENetProtocolCommand;
 } ENetProtocolCommand;

+ 94 - 25
peer.c

@@ -113,13 +113,26 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet)
 
 
    if (packet -> dataLength > fragmentLength)
    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),
       enet_uint32 fragmentCount = ENET_HOST_TO_NET_32 ((packet -> dataLength + fragmentLength - 1) / fragmentLength),
              fragmentNumber,
              fragmentNumber,
              fragmentOffset;
              fragmentOffset;
+      enet_uint8 commandNumber;
+      enet_uint16 startSequenceNumber; 
       ENetList fragments;
       ENetList fragments;
       ENetOutgoingCommand * fragment;
       ENetOutgoingCommand * fragment;
 
 
+      if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT)) == ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT &&
+          channel -> outgoingUnreliableSequenceNumber < 0xFFFF)
+      {
+         commandNumber = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT;
+         startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1);
+      }
+      else
+      {
+         commandNumber = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+         startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingReliableSequenceNumber + 1);
+      }
+        
       enet_list_clear (& fragments);
       enet_list_clear (& fragments);
 
 
       for (fragmentNumber = 0,
       for (fragmentNumber = 0,
@@ -147,7 +160,7 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet)
          fragment -> fragmentOffset = fragmentOffset;
          fragment -> fragmentOffset = fragmentOffset;
          fragment -> fragmentLength = fragmentLength;
          fragment -> fragmentLength = fragmentLength;
          fragment -> packet = packet;
          fragment -> packet = packet;
-         fragment -> command.header.command = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
+         fragment -> command.header.command = commandNumber;
          fragment -> command.header.channelID = channelID;
          fragment -> command.header.channelID = channelID;
          fragment -> command.sendFragment.startSequenceNumber = startSequenceNumber;
          fragment -> command.sendFragment.startSequenceNumber = startSequenceNumber;
          fragment -> command.sendFragment.dataLength = ENET_HOST_TO_NET_16 (fragmentLength);
          fragment -> command.sendFragment.dataLength = ENET_HOST_TO_NET_16 (fragmentLength);
@@ -173,20 +186,13 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet)
 
 
    command.header.channelID = channelID;
    command.header.channelID = channelID;
 
 
-   if (packet -> flags & ENET_PACKET_FLAG_RELIABLE)
-   {
-      command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
-      command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
-   }
-   else
-   if (packet -> flags & ENET_PACKET_FLAG_UNSEQUENCED)
+   if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNSEQUENCED)) == ENET_PACKET_FLAG_UNSEQUENCED)
    {
    {
       command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED;
       command.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);
       command.sendUnsequenced.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
    }
    }
    else 
    else 
-   if (channel -> outgoingUnreliableSequenceNumber >= 0xFFFF)
+   if (packet -> flags & ENET_PACKET_FLAG_RELIABLE || channel -> outgoingUnreliableSequenceNumber >= 0xFFFF)
    {
    {
       command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
       command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
       command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
       command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
@@ -194,7 +200,6 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet)
    else
    else
    {
    {
       command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE;
       command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE;
-      command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1);
       command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
       command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
    }
    }
 
 
@@ -550,7 +555,8 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin
     }
     }
     else
     else
     {
     {
-       ++ channel -> outgoingUnreliableSequenceNumber;
+       if (outgoingCommand -> fragmentOffset == 0)
+         ++ channel -> outgoingUnreliableSequenceNumber;
         
         
        outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
        outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
        outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber;
        outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber;
@@ -562,6 +568,20 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin
     outgoingCommand -> roundTripTimeoutLimit = 0;
     outgoingCommand -> roundTripTimeoutLimit = 0;
     outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber);
     outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber);
 
 
+    switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK)
+    {
+    case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:
+        outgoingCommand -> command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> unreliableSequenceNumber);
+        break;
+
+    case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
+        outgoingCommand -> command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup);
+        break;
+
+    default:
+        break;
+    }
+
     if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
     if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
       enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand);
       enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand);
     else
     else
@@ -590,29 +610,71 @@ enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command,
 void
 void
 enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * channel)
 enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * channel)
 {
 {
-    ENetListIterator currentCommand;
+    ENetListIterator startCommand, currentCommand;
 
 
-    for (currentCommand = enet_list_begin (& channel -> incomingUnreliableCommands);
+    for (startCommand = currentCommand = enet_list_begin (& channel -> incomingUnreliableCommands);
          currentCommand != enet_list_end (& channel -> incomingUnreliableCommands);
          currentCommand != enet_list_end (& channel -> incomingUnreliableCommands);
          currentCommand = enet_list_next (currentCommand))
          currentCommand = enet_list_next (currentCommand))
     {
     {
        ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand;
        ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand;
 
 
-       if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE &&
-           incomingCommand -> reliableSequenceNumber != channel -> incomingReliableSequenceNumber)
+       if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED)
+         continue;
+       else
+       if (incomingCommand -> reliableSequenceNumber != channel -> incomingReliableSequenceNumber)
          break;
          break;
+       else
+       if (incomingCommand -> fragmentsRemaining <= 0)
+         channel -> incomingUnreliableSequenceNumber = incomingCommand -> unreliableSequenceNumber;
+       else
+       {
+            if (startCommand != currentCommand)
+            {
+                enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand));
+
+                if (! peer -> needsDispatch)
+                {
+                    enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
+
+                    peer -> needsDispatch = 1;
+                }
+
+            }
+            
+            startCommand = enet_list_next (currentCommand);
+       }
     }
     }
 
 
-    if (currentCommand == enet_list_begin (& channel -> incomingUnreliableCommands))
-      return;
+    if (startCommand != currentCommand)
+    {
+        enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand));
 
 
-    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);
 
 
-    if (! peer -> needsDispatch)
+            peer -> needsDispatch = 1;
+        }
+    }
+
+    while (currentCommand != enet_list_begin (& channel -> incomingUnreliableCommands))
     {
     {
-       enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
+       ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) enet_list_previous (currentCommand);
 
 
-       peer -> needsDispatch = 1;
+       enet_list_remove (& incomingCommand -> incomingCommandList);
+
+       if (incomingCommand -> packet != NULL)
+       {
+          -- incomingCommand -> packet -> referenceCount;
+
+          if (incomingCommand -> packet -> referenceCount == 0)
+            enet_packet_destroy (incomingCommand -> packet);
+       }
+
+       if (incomingCommand -> fragments != NULL)
+         enet_free (incomingCommand -> fragments);
+
+       enet_free (incomingCommand);
     }
     }
 }
 }
 
 
@@ -640,6 +702,8 @@ enet_peer_dispatch_incoming_reliable_commands (ENetPeer * peer, ENetChannel * ch
     if (currentCommand == enet_list_begin (& channel -> incomingReliableCommands))
     if (currentCommand == enet_list_begin (& channel -> incomingReliableCommands))
       return;
       return;
 
 
+    channel -> incomingUnreliableSequenceNumber = 0;
+
     enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingReliableCommands), enet_list_previous (currentCommand));
     enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingReliableCommands), enet_list_previous (currentCommand));
 
 
     if (! peer -> needsDispatch)
     if (! peer -> needsDispatch)
@@ -684,7 +748,7 @@ enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command,
     case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT:
     case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT:
     case ENET_PROTOCOL_COMMAND_SEND_RELIABLE:
     case ENET_PROTOCOL_COMMAND_SEND_RELIABLE:
        if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber)
        if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber)
-           goto freePacket;
+         goto freePacket;
        
        
        for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands));
        for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands));
             currentCommand != enet_list_end (& channel -> incomingReliableCommands);
             currentCommand != enet_list_end (& channel -> incomingReliableCommands);
@@ -712,15 +776,20 @@ enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command,
        break;
        break;
 
 
     case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:
     case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:
+    case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT:
        unreliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendUnreliable.unreliableSequenceNumber);
        unreliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendUnreliable.unreliableSequenceNumber);
 
 
+       if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber && 
+           unreliableSequenceNumber <= channel -> incomingUnreliableSequenceNumber)
+         goto freePacket;
+
        for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands));
        for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands));
             currentCommand != enet_list_end (& channel -> incomingUnreliableCommands);
             currentCommand != enet_list_end (& channel -> incomingUnreliableCommands);
             currentCommand = enet_list_previous (currentCommand))
             currentCommand = enet_list_previous (currentCommand))
        {
        {
           incomingCommand = (ENetIncomingCommand *) currentCommand;
           incomingCommand = (ENetIncomingCommand *) currentCommand;
 
 
-          if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE)
+          if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED)
             continue;
             continue;
 
 
           if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
           if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)

+ 133 - 0
protocol.c

@@ -23,6 +23,7 @@ static size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] =
     sizeof (ENetProtocolSendUnsequenced),
     sizeof (ENetProtocolSendUnsequenced),
     sizeof (ENetProtocolBandwidthLimit),
     sizeof (ENetProtocolBandwidthLimit),
     sizeof (ENetProtocolThrottleConfigure),
     sizeof (ENetProtocolThrottleConfigure),
+    sizeof (ENetProtocolSendFragment)
 };
 };
 
 
 size_t
 size_t
@@ -319,6 +320,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
         channel -> outgoingReliableSequenceNumber = 0;
         channel -> outgoingReliableSequenceNumber = 0;
         channel -> outgoingUnreliableSequenceNumber = 0;
         channel -> outgoingUnreliableSequenceNumber = 0;
         channel -> incomingReliableSequenceNumber = 0;
         channel -> incomingReliableSequenceNumber = 0;
+        channel -> incomingUnreliableSequenceNumber = 0;
 
 
         enet_list_clear (& channel -> incomingReliableCommands);
         enet_list_clear (& channel -> incomingReliableCommands);
         enet_list_clear (& channel -> incomingUnreliableCommands);
         enet_list_clear (& channel -> incomingUnreliableCommands);
@@ -605,6 +607,132 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet
     return 0;
     return 0;
 }
 }
 
 
+static int
+enet_protocol_handle_send_unreliable_fragment (ENetHost * host, ENetPeer * peer, const ENetProtocol * command, enet_uint8 ** currentData)
+{
+    enet_uint32 fragmentNumber,
+           fragmentCount,
+           fragmentOffset,
+           fragmentLength,
+           reliableSequenceNumber,
+           startSequenceNumber,
+           totalLength;
+    enet_uint16 reliableWindow, currentWindow;
+    ENetChannel * channel;
+    ENetListIterator currentCommand;
+    ENetIncomingCommand * startCommand = NULL;
+
+    if (command -> header.channelID >= peer -> channelCount ||
+        (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER))
+      return -1;
+
+    fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength);
+    * currentData += fragmentLength;
+    if (* currentData > & host -> receivedData [host -> receivedDataLength])
+      return -1;
+
+    channel = & peer -> channels [command -> header.channelID];
+    reliableSequenceNumber = command -> header.reliableSequenceNumber;
+    startSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendFragment.startSequenceNumber);
+
+    reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+    currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
+
+    if (reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
+      reliableWindow += ENET_PEER_RELIABLE_WINDOWS;
+
+    if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1)
+      return 0;
+
+    if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber &&
+        startSequenceNumber <= channel -> incomingUnreliableSequenceNumber)
+      return 0;
+
+    fragmentNumber = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentNumber);
+    fragmentCount = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentCount);
+    fragmentOffset = ENET_NET_TO_HOST_32 (command -> sendFragment.fragmentOffset);
+    totalLength = ENET_NET_TO_HOST_32 (command -> sendFragment.totalLength);
+
+    if (fragmentOffset >= totalLength ||
+        fragmentOffset + fragmentLength > totalLength ||
+        fragmentNumber >= fragmentCount)
+      return -1;
+
+    for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands));
+         currentCommand != enet_list_end (& channel -> incomingUnreliableCommands);
+         currentCommand = enet_list_previous (currentCommand))
+    {
+       ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand;
+
+       if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
+       {
+          if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
+            continue;
+       }
+       else
+       if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
+         break;
+
+       if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber)
+         break;
+
+       if (incomingCommand -> reliableSequenceNumber > reliableSequenceNumber)
+         continue;
+
+       if (incomingCommand -> unreliableSequenceNumber <= startSequenceNumber)
+       {
+          if (incomingCommand -> unreliableSequenceNumber < startSequenceNumber)
+            break;
+
+          if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT ||
+              totalLength != incomingCommand -> packet -> dataLength ||
+              fragmentCount != incomingCommand -> fragmentCount)
+            return -1;
+
+          startCommand = incomingCommand;
+          break;
+       }
+    }
+
+    if (startCommand == NULL)
+    {
+       ENetProtocol hostCommand = * command;
+       ENetPacket * packet = enet_packet_create (NULL, totalLength, ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT);
+       if (packet == NULL)
+         return -1;
+
+       hostCommand.sendFragment.startSequenceNumber = startSequenceNumber;
+       hostCommand.sendFragment.dataLength = fragmentLength;
+       hostCommand.sendFragment.fragmentNumber = fragmentNumber;
+       hostCommand.sendFragment.fragmentCount = fragmentCount;
+       hostCommand.sendFragment.fragmentOffset = fragmentOffset;
+       hostCommand.sendFragment.totalLength = totalLength;
+
+       startCommand = enet_peer_queue_incoming_command (peer, & hostCommand, packet, fragmentCount);
+       if (startCommand == NULL)
+         return -1;
+    }
+
+    if ((startCommand -> fragments [fragmentNumber / 32] & (1 << (fragmentNumber % 32))) == 0)
+    {
+       -- startCommand -> fragmentsRemaining;
+
+       startCommand -> fragments [fragmentNumber / 32] |= (1 << (fragmentNumber % 32));
+
+       if (fragmentOffset + fragmentLength > startCommand -> packet -> dataLength)
+         fragmentLength = startCommand -> packet -> dataLength - fragmentOffset;
+
+       memcpy (startCommand -> packet -> data + fragmentOffset,
+               (enet_uint8 *) command + sizeof (ENetProtocolSendFragment),
+               fragmentLength);
+
+        if (startCommand -> fragmentsRemaining <= 0)
+          enet_peer_dispatch_incoming_unreliable_commands (peer, channel);
+    }
+
+    return 0;
+}
+
 static int
 static int
 enet_protocol_handle_ping (ENetHost * host, ENetPeer * peer, const ENetProtocol * command)
 enet_protocol_handle_ping (ENetHost * host, ENetPeer * peer, const ENetProtocol * command)
 {
 {
@@ -986,6 +1114,11 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
             goto commandError;
             goto commandError;
           break;
           break;
 
 
+       case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT:
+          if (enet_protocol_handle_send_unreliable_fragment (host, peer, command, & currentData))
+            goto commandError;
+          break;
+
        default:
        default:
           goto commandError;
           goto commandError;
        }
        }