aboutsummaryrefslogtreecommitdiffhomepage
path: root/protocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'protocol.c')
-rw-r--r--protocol.c133
1 files changed, 133 insertions, 0 deletions
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);
@@ -606,6 +608,132 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet
}
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)
{
return 0;
@@ -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;
}