diff --git a/ChangeLog b/ChangeLog
index b1fc200..47c38ad 100644
--- a/ChangeLog
+++ b/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):
* 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
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):
* checksum functionality is now enabled by setting a checksum callback
diff --git a/Makefile.am b/Makefile.am
index 4f39688..da792bc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -16,7 +16,7 @@ enetinclude_HEADERS = \
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
# 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
ACLOCAL_AMFLAGS = -Im4
diff --git a/configure.ac b/configure.ac
index 468a4b4..dc6da4f 100644
--- a/configure.ac
+++ b/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])
AM_INIT_AUTOMAKE([foreign])
diff --git a/docs/mainpage.dox b/docs/mainpage.dox
index 1ea5b4e..3b6234a 100755
--- a/docs/mainpage.dox
+++ b/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
or accessing the cvs distribution directly.
-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
+The most recent stable release (1.3.2) can be downloaded here.
+The last release that is protocol compatible with the 1.2 series or earlier (1.2.4) 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
diff --git a/host.c b/host.c
index 8bb2433..c44f2ed 100644
--- a/host.c
+++ b/host.c
@@ -210,6 +210,7 @@ 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);
diff --git a/include/enet/enet.h b/include/enet/enet.h
index b572590..02dc2c0 100644
--- a/include/enet/enet.h
+++ b/include/enet/enet.h
@@ -25,7 +25,7 @@ extern "C"
#define ENET_VERSION_MAJOR 1
#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 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),
/** 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;
struct _ENetPacket;
@@ -218,6 +221,7 @@ typedef struct _ENetChannel
enet_uint16 usedReliableWindows;
enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS];
enet_uint16 incomingReliableSequenceNumber;
+ enet_uint16 incomingUnreliableSequenceNumber;
ENetList incomingReliableCommands;
ENetList incomingUnreliableCommands;
} ENetChannel;
diff --git a/include/enet/protocol.h b/include/enet/protocol.h
index 19f7e45..faef917 100644
--- a/include/enet/protocol.h
+++ b/include/enet/protocol.h
@@ -33,7 +33,8 @@ typedef enum _ENetProtocolCommand
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_SEND_UNRELIABLE_FRAGMENT = 12,
+ ENET_PROTOCOL_COMMAND_COUNT = 13,
ENET_PROTOCOL_COMMAND_MASK = 0x0F
} ENetProtocolCommand;
diff --git a/peer.c b/peer.c
index e1c117f..5047a47 100644
--- a/peer.c
+++ b/peer.c
@@ -113,13 +113,26 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet)
if (packet -> dataLength > fragmentLength)
{
- enet_uint16 startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingReliableSequenceNumber + 1);
enet_uint32 fragmentCount = ENET_HOST_TO_NET_32 ((packet -> dataLength + fragmentLength - 1) / fragmentLength),
fragmentNumber,
fragmentOffset;
+ enet_uint8 commandNumber;
+ enet_uint16 startSequenceNumber;
ENetList fragments;
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);
for (fragmentNumber = 0,
@@ -147,7 +160,7 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet)
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.command = commandNumber;
fragment -> command.header.channelID = channelID;
fragment -> command.sendFragment.startSequenceNumber = startSequenceNumber;
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;
- 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.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)
+ if (packet -> flags & ENET_PACKET_FLAG_RELIABLE || channel -> outgoingUnreliableSequenceNumber >= 0xFFFF)
{
command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
@@ -194,7 +200,6 @@ enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet)
else
{
command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE;
- command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1);
command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
}
@@ -550,7 +555,8 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin
}
else
{
- ++ channel -> outgoingUnreliableSequenceNumber;
+ if (outgoingCommand -> fragmentOffset == 0)
+ ++ channel -> outgoingUnreliableSequenceNumber;
outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber;
@@ -562,6 +568,20 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin
outgoingCommand -> roundTripTimeoutLimit = 0;
outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber);
+ switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK)
+ {
+ case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:
+ outgoingCommand -> command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> unreliableSequenceNumber);
+ break;
+
+ case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
+ outgoingCommand -> command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup);
+ break;
+
+ default:
+ break;
+ }
+
if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand);
else
@@ -590,29 +610,71 @@ enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command,
void
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_next (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;
+ 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;
-
- enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingUnreliableCommands), enet_list_previous (currentCommand));
-
- if (! peer -> needsDispatch)
+ if (startCommand != currentCommand)
{
- enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
+ enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand));
- peer -> needsDispatch = 1;
+ if (! peer -> needsDispatch)
+ {
+ enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
+
+ peer -> needsDispatch = 1;
+ }
+ }
+
+ while (currentCommand != enet_list_begin (& channel -> incomingUnreliableCommands))
+ {
+ ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) enet_list_previous (currentCommand);
+
+ enet_list_remove (& incomingCommand -> incomingCommandList);
+
+ if (incomingCommand -> packet != NULL)
+ {
+ -- incomingCommand -> packet -> referenceCount;
+
+ if (incomingCommand -> packet -> referenceCount == 0)
+ enet_packet_destroy (incomingCommand -> packet);
+ }
+
+ if (incomingCommand -> fragments != NULL)
+ enet_free (incomingCommand -> fragments);
+
+ enet_free (incomingCommand);
}
}
@@ -640,6 +702,8 @@ enet_peer_dispatch_incoming_reliable_commands (ENetPeer * peer, ENetChannel * ch
if (currentCommand == enet_list_begin (& channel -> incomingReliableCommands))
return;
+ channel -> incomingUnreliableSequenceNumber = 0;
+
enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingReliableCommands), enet_list_previous (currentCommand));
if (! peer -> needsDispatch)
@@ -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_RELIABLE:
if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber)
- goto freePacket;
+ goto freePacket;
for (currentCommand = enet_list_previous (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;
case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:
+ case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT:
unreliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendUnreliable.unreliableSequenceNumber);
+ if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber &&
+ unreliableSequenceNumber <= channel -> incomingUnreliableSequenceNumber)
+ goto freePacket;
+
for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands));
currentCommand != enet_list_end (& channel -> incomingUnreliableCommands);
currentCommand = enet_list_previous (currentCommand))
{
incomingCommand = (ENetIncomingCommand *) currentCommand;
- if ((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;
if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
diff --git a/protocol.c b/protocol.c
index 9791839..f48d271 100644
--- a/protocol.c
+++ b/protocol.c
@@ -23,6 +23,7 @@ static size_t commandSizes [ENET_PROTOCOL_COMMAND_COUNT] =
sizeof (ENetProtocolSendUnsequenced),
sizeof (ENetProtocolBandwidthLimit),
sizeof (ENetProtocolThrottleConfigure),
+ sizeof (ENetProtocolSendFragment)
};
size_t
@@ -319,6 +320,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
channel -> outgoingReliableSequenceNumber = 0;
channel -> outgoingUnreliableSequenceNumber = 0;
channel -> incomingReliableSequenceNumber = 0;
+ channel -> incomingUnreliableSequenceNumber = 0;
enet_list_clear (& channel -> incomingReliableCommands);
enet_list_clear (& channel -> incomingUnreliableCommands);
@@ -605,6 +607,132 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet
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
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;
break;
+ case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT:
+ if (enet_protocol_handle_send_unreliable_fragment (host, peer, command, & currentData))
+ goto commandError;
+ break;
+
default:
goto commandError;
}