Browse Source

maintain a separate queue for outgoing send reliable packets

Lee Salzman 2 years ago
parent
commit
d7e5470cf7
4 changed files with 110 additions and 60 deletions
  1. 2 0
      host.c
  2. 4 0
      include/enet/enet.h
  3. 20 4
      peer.c
  4. 84 56
      protocol.c

+ 2 - 0
host.c

@@ -96,6 +96,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
     host -> totalSentPackets = 0;
     host -> totalSentPackets = 0;
     host -> totalReceivedData = 0;
     host -> totalReceivedData = 0;
     host -> totalReceivedPackets = 0;
     host -> totalReceivedPackets = 0;
+    host -> totalQueued = 0;
 
 
     host -> connectedPeers = 0;
     host -> connectedPeers = 0;
     host -> bandwidthLimitedPeers = 0;
     host -> bandwidthLimitedPeers = 0;
@@ -125,6 +126,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
        enet_list_clear (& currentPeer -> sentReliableCommands);
        enet_list_clear (& currentPeer -> sentReliableCommands);
        enet_list_clear (& currentPeer -> sentUnreliableCommands);
        enet_list_clear (& currentPeer -> sentUnreliableCommands);
        enet_list_clear (& currentPeer -> outgoingCommands);
        enet_list_clear (& currentPeer -> outgoingCommands);
+       enet_list_clear (& currentPeer -> outgoingSendReliableCommands);
        enet_list_clear (& currentPeer -> dispatchedCommands);
        enet_list_clear (& currentPeer -> dispatchedCommands);
 
 
        enet_peer_reset (currentPeer);
        enet_peer_reset (currentPeer);

+ 4 - 0
include/enet/enet.h

@@ -174,6 +174,7 @@ typedef struct _ENetOutgoingCommand
    enet_uint32  fragmentOffset;
    enet_uint32  fragmentOffset;
    enet_uint16  fragmentLength;
    enet_uint16  fragmentLength;
    enet_uint16  sendAttempts;
    enet_uint16  sendAttempts;
+   enet_uint32  queueTime;
    ENetProtocol command;
    ENetProtocol command;
    ENetPacket * packet;
    ENetPacket * packet;
 } ENetOutgoingCommand;
 } ENetOutgoingCommand;
@@ -315,6 +316,7 @@ typedef struct _ENetPeer
    ENetList      sentReliableCommands;
    ENetList      sentReliableCommands;
    ENetList      sentUnreliableCommands;
    ENetList      sentUnreliableCommands;
    ENetList      outgoingCommands;
    ENetList      outgoingCommands;
+   ENetList      outgoingSendReliableCommands;
    ENetList      dispatchedCommands;
    ENetList      dispatchedCommands;
    enet_uint16   flags;
    enet_uint16   flags;
    enet_uint16   reserved;
    enet_uint16   reserved;
@@ -399,6 +401,7 @@ typedef struct _ENetHost
    size_t               duplicatePeers;              /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */
    size_t               duplicatePeers;              /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */
    size_t               maximumPacketSize;           /**< the maximum allowable packet size that may be sent or received on a peer */
    size_t               maximumPacketSize;           /**< the maximum allowable packet size that may be sent or received on a peer */
    size_t               maximumWaitingData;          /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */
    size_t               maximumWaitingData;          /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */
+   enet_uint32          totalQueued;
 } ENetHost;
 } ENetHost;
 
 
 /**
 /**
@@ -590,6 +593,7 @@ ENET_API void                enet_peer_disconnect_later (ENetPeer *, enet_uint32
 ENET_API void                enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32);
 ENET_API void                enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32);
 extern int                   enet_peer_throttle (ENetPeer *, enet_uint32);
 extern int                   enet_peer_throttle (ENetPeer *, enet_uint32);
 extern void                  enet_peer_reset_queues (ENetPeer *);
 extern void                  enet_peer_reset_queues (ENetPeer *);
+extern int                   enet_peer_has_outgoing_commands (ENetPeer *);
 extern void                  enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *);
 extern void                  enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *);
 extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16);
 extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16);
 extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32);
 extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32);

+ 20 - 4
peer.c

@@ -330,6 +330,7 @@ enet_peer_reset_queues (ENetPeer * peer)
     enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands);
     enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands);
     enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands);
     enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands);
     enet_peer_reset_outgoing_commands (& peer -> outgoingCommands);
     enet_peer_reset_outgoing_commands (& peer -> outgoingCommands);
+    enet_peer_reset_outgoing_commands (& peer -> outgoingSendReliableCommands);
     enet_peer_reset_incoming_commands (& peer -> dispatchedCommands);
     enet_peer_reset_incoming_commands (& peer -> dispatchedCommands);
 
 
     if (peer -> channels != NULL && peer -> channelCount > 0)
     if (peer -> channels != NULL && peer -> channelCount > 0)
@@ -571,6 +572,17 @@ enet_peer_disconnect (ENetPeer * peer, enet_uint32 data)
     }
     }
 }
 }
 
 
+int
+enet_peer_has_outgoing_commands (ENetPeer * peer)
+{
+  if (enet_list_empty (& peer -> outgoingCommands) &&
+      enet_list_empty (& peer -> outgoingSendReliableCommands) &&
+      enet_list_empty (& peer -> sentReliableCommands))
+    return 0;
+
+  return 1;
+}
+
 /** Request a disconnection from a peer, but only after all queued outgoing packets are sent.
 /** Request a disconnection from a peer, but only after all queued outgoing packets are sent.
     @param peer peer to request a disconnection
     @param peer peer to request a disconnection
     @param data data describing the disconnection
     @param data data describing the disconnection
@@ -581,8 +593,7 @@ void
 enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data)
 enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data)
 {   
 {   
     if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) && 
     if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) && 
-        ! (enet_list_empty (& peer -> outgoingCommands) &&
-           enet_list_empty (& peer -> sentReliableCommands)))
+        enet_peer_has_outgoing_commands (peer))
     {
     {
         peer -> state = ENET_PEER_STATE_DISCONNECT_LATER;
         peer -> state = ENET_PEER_STATE_DISCONNECT_LATER;
         peer -> eventData = data;
         peer -> eventData = data;
@@ -670,6 +681,7 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin
     outgoingCommand -> roundTripTimeout = 0;
     outgoingCommand -> roundTripTimeout = 0;
     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);
+    outgoingCommand -> queueTime = ++ peer -> host -> totalQueued;
 
 
     switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK)
     switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK)
     {
     {
@@ -680,12 +692,16 @@ enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoin
     case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
     case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
         outgoingCommand -> command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup);
         outgoingCommand -> command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup);
         break;
         break;
-    
+
     default:
     default:
         break;
         break;
     }
     }
 
 
-    enet_list_insert (enet_list_end (& peer -> outgoingCommands), outgoingCommand);
+    if ((outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) != 0 &&
+        outgoingCommand -> packet != NULL)
+      enet_list_insert (enet_list_end (& peer -> outgoingSendReliableCommands), outgoingCommand);
+    else
+      enet_list_insert (enet_list_end (& peer -> outgoingCommands), outgoingCommand);
 }
 }
 
 
 ENetOutgoingCommand *
 ENetOutgoingCommand *

+ 84 - 56
protocol.c

@@ -188,11 +188,35 @@ enet_protocol_remove_sent_unreliable_commands (ENetPeer * peer)
     } while (! enet_list_empty (& peer -> sentUnreliableCommands));
     } while (! enet_list_empty (& peer -> sentUnreliableCommands));
 
 
     if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER &&
     if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER &&
-        enet_list_empty (& peer -> outgoingCommands) &&
-        enet_list_empty (& peer -> sentReliableCommands))
+        ! enet_peer_has_outgoing_commands (peer))
       enet_peer_disconnect (peer, peer -> eventData);
       enet_peer_disconnect (peer, peer -> eventData);
 }
 }
 
 
+static ENetOutgoingCommand *
+enet_protocol_find_sent_reliable_command (ENetList * list, enet_uint16 reliableSequenceNumber, enet_uint8 channelID)
+{
+    ENetListIterator currentCommand;
+
+    for (currentCommand = enet_list_begin (list);
+         currentCommand != enet_list_end (list);
+         currentCommand = enet_list_next (currentCommand))
+    {
+       ENetOutgoingCommand * outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+
+       if (! (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE))
+         continue;
+
+       if (outgoingCommand -> sendAttempts < 1)
+         break;
+
+       if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber &&
+           outgoingCommand -> command.header.channelID == channelID)
+         return outgoingCommand;
+    }
+
+    return NULL;
+}
+
 static ENetProtocolCommand
 static ENetProtocolCommand
 enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID)
 enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliableSequenceNumber, enet_uint8 channelID)
 {
 {
@@ -214,24 +238,9 @@ enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliabl
 
 
     if (currentCommand == enet_list_end (& peer -> sentReliableCommands))
     if (currentCommand == enet_list_end (& peer -> sentReliableCommands))
     {
     {
-       for (currentCommand = enet_list_begin (& peer -> outgoingCommands);
-            currentCommand != enet_list_end (& peer -> outgoingCommands);
-            currentCommand = enet_list_next (currentCommand))
-       {
-          outgoingCommand = (ENetOutgoingCommand *) currentCommand;
-
-          if (! (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE))
-            continue;
-
-          if (outgoingCommand -> sendAttempts < 1) return ENET_PROTOCOL_COMMAND_NONE;
-
-          if (outgoingCommand -> reliableSequenceNumber == reliableSequenceNumber &&
-              outgoingCommand -> command.header.channelID == channelID)
-            break;
-       }
-
-       if (currentCommand == enet_list_end (& peer -> outgoingCommands))
-         return ENET_PROTOCOL_COMMAND_NONE;
+       outgoingCommand = enet_protocol_find_sent_reliable_command (& peer -> outgoingCommands, reliableSequenceNumber, channelID);
+       if (outgoingCommand == NULL)
+         outgoingCommand = enet_protocol_find_sent_reliable_command (& peer -> outgoingSendReliableCommands, reliableSequenceNumber, channelID);
 
 
        wasSent = 0;
        wasSent = 0;
     }
     }
@@ -542,7 +551,8 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet
 
 
     fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength);
     fragmentLength = ENET_NET_TO_HOST_16 (command -> sendFragment.dataLength);
     * currentData += fragmentLength;
     * currentData += fragmentLength;
-    if (fragmentLength > host -> maximumPacketSize ||
+    if (fragmentLength <= 0 ||
+        fragmentLength > host -> maximumPacketSize ||
         * currentData < host -> receivedData ||
         * currentData < host -> receivedData ||
         * currentData > & host -> receivedData [host -> receivedDataLength])
         * currentData > & host -> receivedData [host -> receivedDataLength])
       return -1;
       return -1;
@@ -566,6 +576,7 @@ enet_protocol_handle_send_fragment (ENetHost * host, ENetPeer * peer, const ENet
     if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT ||
     if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT ||
         fragmentNumber >= fragmentCount ||
         fragmentNumber >= fragmentCount ||
         totalLength > host -> maximumPacketSize ||
         totalLength > host -> maximumPacketSize ||
+        totalLength < fragmentCount ||
         fragmentOffset >= totalLength ||
         fragmentOffset >= totalLength ||
         fragmentLength > totalLength - fragmentOffset)
         fragmentLength > totalLength - fragmentOffset)
       return -1;
       return -1;
@@ -921,8 +932,7 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer *
        break;
        break;
 
 
     case ENET_PEER_STATE_DISCONNECT_LATER:
     case ENET_PEER_STATE_DISCONNECT_LATER:
-       if (enet_list_empty (& peer -> outgoingCommands) &&
-           enet_list_empty (& peer -> sentReliableCommands))
+       if (! enet_peer_has_outgoing_commands (peer))
          enet_peer_disconnect (peer, peer -> eventData);
          enet_peer_disconnect (peer, peer -> eventData);
        break;
        break;
 
 
@@ -1334,10 +1344,11 @@ static int
 enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * event)
 enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * event)
 {
 {
     ENetOutgoingCommand * outgoingCommand;
     ENetOutgoingCommand * outgoingCommand;
-    ENetListIterator currentCommand, insertPosition;
+    ENetListIterator currentCommand, insertPosition, insertSendReliablePosition;
 
 
     currentCommand = enet_list_begin (& peer -> sentReliableCommands);
     currentCommand = enet_list_begin (& peer -> sentReliableCommands);
     insertPosition = enet_list_begin (& peer -> outgoingCommands);
     insertPosition = enet_list_begin (& peer -> outgoingCommands);
+    insertSendReliablePosition = enet_list_begin (& peer -> outgoingSendReliableCommands);
 
 
     while (currentCommand != enet_list_end (& peer -> sentReliableCommands))
     while (currentCommand != enet_list_end (& peer -> sentReliableCommands))
     {
     {
@@ -1362,14 +1373,18 @@ enet_protocol_check_timeouts (ENetHost * host, ENetPeer * peer, ENetEvent * even
           return 1;
           return 1;
        }
        }
 
 
-       if (outgoingCommand -> packet != NULL)
-         peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength;
-          
        ++ peer -> packetsLost;
        ++ peer -> packetsLost;
 
 
        outgoingCommand -> roundTripTimeout *= 2;
        outgoingCommand -> roundTripTimeout *= 2;
 
 
-       enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList));
+       if (outgoingCommand -> packet != NULL)
+       {
+         peer -> reliableDataInTransit -= outgoingCommand -> fragmentLength;
+
+         enet_list_insert (insertSendReliablePosition, enet_list_remove (& outgoingCommand -> outgoingCommandList));
+       }
+       else
+         enet_list_insert (insertPosition, enet_list_remove (& outgoingCommand -> outgoingCommandList));
 
 
        if (currentCommand == enet_list_begin (& peer -> sentReliableCommands) &&
        if (currentCommand == enet_list_begin (& peer -> sentReliableCommands) &&
            ! enet_list_empty (& peer -> sentReliableCommands))
            ! enet_list_empty (& peer -> sentReliableCommands))
@@ -1389,17 +1404,36 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
     ENetProtocol * command = & host -> commands [host -> commandCount];
     ENetProtocol * command = & host -> commands [host -> commandCount];
     ENetBuffer * buffer = & host -> buffers [host -> bufferCount];
     ENetBuffer * buffer = & host -> buffers [host -> bufferCount];
     ENetOutgoingCommand * outgoingCommand;
     ENetOutgoingCommand * outgoingCommand;
-    ENetListIterator currentCommand;
+    ENetListIterator currentCommand, currentSendReliableCommand;
     ENetChannel *channel = NULL;
     ENetChannel *channel = NULL;
     enet_uint16 reliableWindow = 0;
     enet_uint16 reliableWindow = 0;
     size_t commandSize;
     size_t commandSize;
-    int windowExceeded = 0, windowWrap = 0, canPing = 1;
+    int windowWrap = 0, canPing = 1;
 
 
     currentCommand = enet_list_begin (& peer -> outgoingCommands);
     currentCommand = enet_list_begin (& peer -> outgoingCommands);
-    
-    while (currentCommand != enet_list_end (& peer -> outgoingCommands))
+    currentSendReliableCommand = enet_list_begin (& peer -> outgoingSendReliableCommands);
+
+    for (;;)
     {
     {
-       outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+       if (currentCommand != enet_list_end (& peer -> outgoingCommands))
+       {
+          outgoingCommand = (ENetOutgoingCommand *) currentCommand;
+
+          if (currentSendReliableCommand != enet_list_end (& peer -> outgoingSendReliableCommands) &&
+              ENET_TIME_LESS (((ENetOutgoingCommand *) currentSendReliableCommand) -> queueTime, outgoingCommand -> queueTime))
+            goto useSendReliableCommand;
+
+          currentCommand = enet_list_next (currentCommand);
+       }
+       else
+       if (currentSendReliableCommand != enet_list_end (& peer -> outgoingSendReliableCommands))
+       {
+       useSendReliableCommand:
+          outgoingCommand = (ENetOutgoingCommand *) currentSendReliableCommand;
+          currentSendReliableCommand = enet_list_next (currentSendReliableCommand);
+       }
+       else
+         break;
 
 
        if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
        if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
        {
        {
@@ -1407,33 +1441,29 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
           reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
           reliableWindow = outgoingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
           if (channel != NULL)
           if (channel != NULL)
           {
           {
-             if (! windowWrap &&      
-                  outgoingCommand -> sendAttempts < 1 && 
+             if (windowWrap)
+               continue;
+             else
+             if (outgoingCommand -> sendAttempts < 1 &&
                   ! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) &&
                   ! (outgoingCommand -> reliableSequenceNumber % ENET_PEER_RELIABLE_WINDOW_SIZE) &&
                   (channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE ||
                   (channel -> reliableWindows [(reliableWindow + ENET_PEER_RELIABLE_WINDOWS - 1) % ENET_PEER_RELIABLE_WINDOWS] >= ENET_PEER_RELIABLE_WINDOW_SIZE ||
                     channel -> usedReliableWindows & ((((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) << reliableWindow) |
                     channel -> usedReliableWindows & ((((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) << reliableWindow) |
                       (((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) >> (ENET_PEER_RELIABLE_WINDOWS - reliableWindow)))))
                       (((1 << (ENET_PEER_FREE_RELIABLE_WINDOWS + 2)) - 1) >> (ENET_PEER_RELIABLE_WINDOWS - reliableWindow)))))
-                windowWrap = 1;
-             if (windowWrap)
              {
              {
-                currentCommand = enet_list_next (currentCommand);
- 
+                windowWrap = 1;
+                currentSendReliableCommand = enet_list_end (& peer -> outgoingSendReliableCommands);
+
                 continue;
                 continue;
              }
              }
           }
           }
- 
+
           if (outgoingCommand -> packet != NULL)
           if (outgoingCommand -> packet != NULL)
           {
           {
-             if (! windowExceeded)
-             {
-                enet_uint32 windowSize = (peer -> packetThrottle * peer -> windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE;
-             
-                if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > ENET_MAX (windowSize, peer -> mtu))
-                  windowExceeded = 1;
-             }
-             if (windowExceeded)
+             enet_uint32 windowSize = (peer -> packetThrottle * peer -> windowSize) / ENET_PEER_PACKET_THROTTLE_SCALE;
+
+             if (peer -> reliableDataInTransit + outgoingCommand -> fragmentLength > ENET_MAX (windowSize, peer -> mtu))
              {
              {
-                currentCommand = enet_list_next (currentCommand);
+                currentSendReliableCommand = enet_list_end (& peer -> outgoingSendReliableCommands);
 
 
                 continue;
                 continue;
              }
              }
@@ -1454,8 +1484,6 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
           break;
           break;
        }
        }
 
 
-       currentCommand = enet_list_next (currentCommand);
-
        if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
        if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
        {
        {
           if (channel != NULL && outgoingCommand -> sendAttempts < 1)
           if (channel != NULL && outgoingCommand -> sendAttempts < 1)
@@ -1556,8 +1584,7 @@ enet_protocol_check_outgoing_commands (ENetHost * host, ENetPeer * peer)
     host -> bufferCount = buffer - host -> buffers;
     host -> bufferCount = buffer - host -> buffers;
 
 
     if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER &&
     if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER &&
-        enet_list_empty (& peer -> outgoingCommands) &&
-        enet_list_empty (& peer -> sentReliableCommands) &&
+        ! enet_peer_has_outgoing_commands (peer) &&
         enet_list_empty (& peer -> sentUnreliableCommands))
         enet_list_empty (& peer -> sentUnreliableCommands))
       enet_peer_disconnect (peer, peer -> eventData);
       enet_peer_disconnect (peer, peer -> eventData);
 
 
@@ -1604,8 +1631,9 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
               continue;
               continue;
         }
         }
 
 
-        if ((enet_list_empty (& currentPeer -> outgoingCommands) ||
-              enet_protocol_check_outgoing_commands (host, currentPeer)) &&
+        if (((enet_list_empty (& currentPeer -> outgoingCommands) &&
+              enet_list_empty (& currentPeer -> outgoingSendReliableCommands)) ||
+             enet_protocol_check_outgoing_commands (host, currentPeer)) &&
             enet_list_empty (& currentPeer -> sentReliableCommands) &&
             enet_list_empty (& currentPeer -> sentReliableCommands) &&
             ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= currentPeer -> pingInterval &&
             ENET_TIME_DIFFERENCE (host -> serviceTime, currentPeer -> lastReceiveTime) >= currentPeer -> pingInterval &&
             currentPeer -> mtu - host -> packetSize >= sizeof (ENetProtocolPing))
             currentPeer -> mtu - host -> packetSize >= sizeof (ENetProtocolPing))
@@ -1626,7 +1654,7 @@ enet_protocol_send_outgoing_commands (ENetHost * host, ENetEvent * event, int ch
            enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> packetsSent;
            enet_uint32 packetLoss = currentPeer -> packetsLost * ENET_PEER_PACKET_LOSS_SCALE / currentPeer -> packetsSent;
 
 
 #ifdef ENET_DEBUG
 #ifdef ENET_DEBUG
-           printf ("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0);
+           printf ("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u outgoing, %u/%u incoming\n", currentPeer -> incomingPeerID, currentPeer -> packetLoss / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> packetLossVariance / (float) ENET_PEER_PACKET_LOSS_SCALE, currentPeer -> roundTripTime, currentPeer -> roundTripTimeVariance, currentPeer -> packetThrottle / (float) ENET_PEER_PACKET_THROTTLE_SCALE, enet_list_size (& currentPeer -> outgoingCommands) + enet_list_size (& currentPeer -> outgoingSendReliableCommands), currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingReliableCommands) : 0, currentPeer -> channels != NULL ? enet_list_size (& currentPeer -> channels -> incomingUnreliableCommands) : 0);
 #endif
 #endif
 
 
            currentPeer -> packetLossVariance = (currentPeer -> packetLossVariance * 3 + ENET_DIFFERENCE (packetLoss, currentPeer -> packetLoss)) / 4;
            currentPeer -> packetLossVariance = (currentPeer -> packetLossVariance * 3 + ENET_DIFFERENCE (packetLoss, currentPeer -> packetLoss)) / 4;