[enet-cvs] CVS: enet host.c,1.2,1.3 peer.c,1.2,1.3 protocol.c,1.2,1.3 unix.c,1.1,1.2 win32.c,1.2,1.3

ENet CVS enet-discuss@lists.puremagic.com
Fri, 7 Jun 2002 20:29:14 -0600


Update of /home/enet/cvsroot/enet
In directory sferik:/tmp/cvs-serv1105

Modified Files:
	host.c peer.c protocol.c unix.c win32.c 
Log Message:
Added channels, revised throttle, fixed bugs, etc. etc.



Index: host.c
===================================================================
RCS file: /home/enet/cvsroot/enet/host.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- host.c	2002/02/10 22:24:41	1.2
+++ host.c	2002/06/08 02:29:12	1.3
@@ -2,14 +2,14 @@
 #include <enet/enet.h>
 
 ENetHost *
-enet_host_create (const ENetAddress * address, size_t peerCount)
+enet_host_create (const ENetAddress * address, size_t peerCount, uint32 incomingBandwidth, uint32 outgoingBandwidth)
 {
     ENetHost * host = (ENetHost *) enet_malloc (sizeof (ENetHost));
     ENetPeer * currentPeer;
 
     host -> peers = (ENetPeer *) enet_calloc (peerCount, sizeof (ENetPeer));
 
-    host -> socket = enet_socket_create (address);
+    host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM, address);
     if (host -> socket == ENET_SOCKET_NULL)
     {
        enet_free (host -> peers);
@@ -21,6 +21,10 @@
     if (address != NULL)
       host -> address = * address;
 
+    host -> incomingBandwidth = incomingBandwidth;
+    host -> outgoingBandwidth = outgoingBandwidth;
+    host -> bandwidthThrottleEpoch = 0;
+    host -> recalculateBandwidthLimits = 0;
     host -> peerCount = peerCount;
     host -> lastServicedPeer = host -> peers;
     host -> commandCount = 0;
@@ -33,14 +37,15 @@
          currentPeer < & host -> peers [host -> peerCount];
          ++ currentPeer)
     {
+       currentPeer -> host = host;
        currentPeer -> incomingPeerID = currentPeer - host -> peers;
        currentPeer -> data = NULL;
 
+       enet_list_clear (& currentPeer -> acknowledgements);
        enet_list_clear (& currentPeer -> sentReliableCommands);
+       enet_list_clear (& currentPeer -> sentUnreliableCommands);
        enet_list_clear (& currentPeer -> outgoingReliableCommands);
        enet_list_clear (& currentPeer -> outgoingUnreliableCommands);
-       enet_list_clear (& currentPeer -> incomingReliableCommands);
-       enet_list_clear (& currentPeer -> incomingUnreliableCommands);
 
        enet_peer_reset (currentPeer);
     }
@@ -67,11 +72,18 @@
 }
 
 ENetPeer *
-enet_host_connect (ENetHost * host, const ENetAddress * address)
+enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount)
 {
     ENetPeer * currentPeer;
-    ENetOutgoingCommand * outgoingCommand;
+    ENetChannel * channel;
+    ENetProtocol command;
 
+    if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
+      channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
+    else
+    if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
+      channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
+
     for (currentPeer = host -> peers;
          currentPeer < & host -> peers [host -> peerCount];
          ++ currentPeer)
@@ -84,35 +96,41 @@
       return NULL;
 
     currentPeer -> state = ENET_PEER_STATE_CONNECTING;
-    currentPeer -> challenge = (uint32) rand ();
     currentPeer -> address = * address;
-
-    outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand));
+    currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel));
+    currentPeer -> channelCount = channelCount;
 
-    currentPeer -> outgoingReliableSequenceNumber = 1;
+    for (channel = currentPeer -> channels;
+         channel < & currentPeer -> channels [channelCount];
+         ++ channel)
+    {
+        channel -> outgoingReliableSequenceNumber = 0;
+        channel -> outgoingUnreliableSequenceNumber = 0;
+        channel -> incomingReliableSequenceNumber = 0;
+        channel -> incomingUnreliableSequenceNumber = 0;
 
-    outgoingCommand -> reliableSequenceNumber = 1;
-    outgoingCommand -> unreliableSequenceNumber = 0;
-    outgoingCommand -> sentTime = 0;
-    outgoingCommand -> roundTripTimeout = 0;
-    outgoingCommand -> roundTripTimeoutLimit = 0;
-    outgoingCommand -> packet = NULL;
-
-    outgoingCommand -> command.header.command = ENET_PROTOCOL_COMMAND_CONNECT;
-    outgoingCommand -> command.header.flags = 0;
-    outgoingCommand -> command.header.commandLength = sizeof (ENetProtocolConnect);
-    outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_32 (1);
-    outgoingCommand -> command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID);
-    outgoingCommand -> command.connect.packetSize = ENET_HOST_TO_NET_16 (currentPeer -> packetSize);
-    outgoingCommand -> command.connect.windowSize = ENET_HOST_TO_NET_32 (currentPeer -> windowSize);
+        enet_list_clear (& channel -> incomingReliableCommands);
+        enet_list_clear (& channel -> incomingUnreliableCommands);
+    }
+        
+    command.header.command = ENET_PROTOCOL_COMMAND_CONNECT;
+    command.header.channelID = 0xFF;
+    command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE;
+    command.header.commandLength = sizeof (ENetProtocolConnect);
+    command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID);
+    command.connect.packetSize = ENET_HOST_TO_NET_16 (currentPeer -> packetSize);
+    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);
+    command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
 
-    enet_list_insert (enet_list_end (& currentPeer -> outgoingReliableCommands), outgoingCommand);
+    enet_peer_queue_outgoing_command (currentPeer, & command, NULL, 0, 0);
 
     return currentPeer;
 }
 
 void
-enet_host_broadcast (ENetHost * host, ENetPacket * packet)
+enet_host_broadcast (ENetHost * host, uint8 channelID, ENetPacket * packet)
 {
     ENetPeer * currentPeer;
 
@@ -123,10 +141,176 @@
        if (currentPeer -> state != ENET_PEER_STATE_CONNECTED)
          continue;
 
-       enet_peer_send (currentPeer, packet);
+       enet_peer_send (currentPeer, channelID, packet);
     }
 
     if (packet -> referenceCount == 0)
       enet_packet_destroy (packet);
 }
 
+void
+enet_host_bandwidth_limit (ENetHost * host, uint32 incomingBandwidth, uint32 outgoingBandwidth)
+{
+    host -> incomingBandwidth = incomingBandwidth;
+    host -> outgoingBandwidth = outgoingBandwidth;
+    host -> recalculateBandwidthLimits = 1;
+}
+
+void
+enet_host_bandwidth_throttle (ENetHost * host)
+{
+    uint32 timeCurrent = enet_time_get (),
+           elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch,
+           peersTotal = 0,
+           dataTotal = 0,
+           peersRemaining,
+           bandwidth,
+           throttle,
+           bandwidthLimit;
+    int needsAdjustment;
+    ENetPeer * peer;
+    ENetProtocol command;
+
+    if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_EPOCH)
+      return;
+
+    for (peer = host -> peers;
+         peer < & host -> peers [host -> peerCount];
+         ++ peer)
+    {
+        if (peer -> state != ENET_PEER_STATE_CONNECTED)
+          continue;
+
+        ++ peersTotal;
+        dataTotal += peer -> outgoingDataTotal;
+    }
+
+    if (peersTotal == 0)
+      return;
+
+    peersRemaining = peersTotal;
+    needsAdjustment = 1;
+
+    if (host -> outgoingBandwidth == 0)
+      bandwidth = ~0;
+    else
+      bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000;
+
+    while (peersRemaining > 0 && needsAdjustment != 0)
+    {
+        needsAdjustment = 0;
+        
+        if (dataTotal < bandwidth)
+          throttle = ENET_PEER_PACKET_THROTTLE_SCALE;
+        else
+          throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal;
+
+        for (peer = host -> peers;
+             peer < & host -> peers [host -> peerCount];
+             ++ peer)
+        {
+            uint32 peerBandwidth;
+            
+            if (peer -> state != ENET_PEER_STATE_CONNECTED ||
+                peer -> incomingBandwidth == 0 ||
+                peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
+              continue;
+
+            peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000;
+            if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth)
+              continue;
+
+            peer -> packetThrottleLimit = (peerBandwidth * 
+                                            ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal;
+            
+            if (peer -> packetThrottleLimit == 0)
+              peer -> packetThrottleLimit = 1;
+            
+            peer -> outgoingBandwidthThrottleEpoch = timeCurrent;
+
+            
+            needsAdjustment = 1;
+            -- peersRemaining;
+            bandwidth -= peerBandwidth;
+            dataTotal -= peerBandwidth;
+        }
+    }
+
+    if (peersRemaining > 0)
+    for (peer = host -> peers;
+         peer < & host -> peers [host -> peerCount];
+         ++ peer)
+    {
+        if (peer -> state != ENET_PEER_STATE_CONNECTED ||
+            peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
+          continue;
+
+        peer -> packetThrottleLimit = throttle;
+    }
+    
+    if (host -> incomingBandwidth > 0 &&
+        host -> recalculateBandwidthLimits)
+    {
+       host -> recalculateBandwidthLimits = 0;
+
+       peersRemaining = peersTotal;
+       bandwidth = host -> incomingBandwidth;
+       needsAdjustment = 1;
+
+       while (peersRemaining > 0 && needsAdjustment != 0)
+       {
+           needsAdjustment = 0;
+           bandwidthLimit = bandwidth / peersRemaining;
+
+           for (peer = host -> peers;
+                peer < & host -> peers [host -> peerCount];
+                ++ peer)
+           {
+               if (peer -> state != ENET_PEER_STATE_CONNECTED ||
+                   peer -> incomingBandwidthThrottleEpoch == timeCurrent)
+                 continue;
+
+               if (bandwidthLimit <= peer -> outgoingBandwidth)
+                 continue;
+
+               peer -> incomingBandwidthThrottleEpoch = timeCurrent;
+ 
+               needsAdjustment = 1;
+               -- peersRemaining;
+               bandwidth -= peer -> outgoingBandwidth;
+           }
+       }
+
+       for (peer = host -> peers;
+            peer < & host -> peers [host -> peerCount];
+            ++ peer)
+       {
+           if (peer -> state != ENET_PEER_STATE_CONNECTED)
+             continue;
+
+           command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT;
+           command.header.channelID = 0xFF;
+           command.header.flags = 0;
+           command.header.commandLength = sizeof (ENetProtocolBandwidthLimit);
+           command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
+
+           if (peer -> incomingBandwidthThrottleEpoch == timeCurrent)
+             command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth);
+           else
+             command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit);
+
+           enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
+       } 
+    }
+
+    host -> bandwidthThrottleEpoch = timeCurrent;
+
+    for (peer = host -> peers;
+         peer < & host -> peers [host -> peerCount];
+         ++ peer)
+    {
+        peer -> incomingDataTotal = 0;
+        peer -> outgoingDataTotal = 0;
+    }
+}
+    

Index: peer.c
===================================================================
RCS file: /home/enet/cvsroot/enet/peer.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- peer.c	2002/02/10 22:24:41	1.2
+++ peer.c	2002/06/08 02:29:12	1.3
@@ -2,9 +2,37 @@
 #include <enet/enet.h>
 
 int
-enet_peer_send (ENetPeer * peer, ENetPacket * packet)
+enet_peer_throttle (ENetPeer * peer, uint32 statistic, uint32 mean, uint32 variance)
 {
-   ENetOutgoingCommand * outgoingCommand;
+    if (mean > variance &&
+        statistic < mean - variance)
+    {
+        peer -> packetThrottle += ENET_PEER_PACKET_THROTTLE_ACCELERATION;
+
+        if (peer -> packetThrottle > peer -> packetThrottleLimit)
+          peer -> packetThrottle = peer -> packetThrottleLimit;
+        
+        return 1;
+    }
+    else
+    if (statistic > mean + variance)
+    {
+        if (peer -> packetThrottle > ENET_PEER_PACKET_THROTTLE_DECELERATION)
+          peer -> packetThrottle -= ENET_PEER_PACKET_THROTTLE_DECELERATION;
+        else
+          peer -> packetThrottle = 0;
+
+        return -1;
+    }    
+
+    return 0;
+}
+
+int
+enet_peer_send (ENetPeer * peer, uint8 channelID, ENetPacket * packet)
+{
+   ENetChannel * channel = & peer -> channels [channelID];
+   ENetProtocol command;
    size_t fragmentLength;
 
    if (peer -> state != ENET_PEER_STATE_CONNECTED)
@@ -15,136 +43,95 @@
    if (packet -> dataLength > fragmentLength)
    {
       uint32 fragmentCount = ENET_HOST_TO_NET_32 ((packet -> dataLength + fragmentLength - 1) / fragmentLength),
-             startSequenceNumber = ENET_HOST_TO_NET_32 (peer -> outgoingReliableSequenceNumber + 1),
-             fragmentNumber = 0,
-             fragmentOffset = 0;
+             startSequenceNumber = ENET_HOST_TO_NET_32 (channel -> outgoingReliableSequenceNumber + 1),
+             fragmentNumber,
+             fragmentOffset;
 
       packet -> flags |= ENET_PACKET_FLAG_RELIABLE;
 
-      do
+      for (fragmentNumber = 0,
+             fragmentOffset = 0;
+           fragmentOffset < packet -> dataLength;
+           ++ fragmentNumber,
+             fragmentOffset += fragmentLength)
       {
-         outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand));
-
-         ++ peer -> outgoingReliableSequenceNumber;
-
-         outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber;
-         outgoingCommand -> unreliableSequenceNumber = 0;
-         outgoingCommand -> sentTime = 0;
-         outgoingCommand -> roundTripTimeout = 0;
-         outgoingCommand -> roundTripTimeoutLimit = 0;
-         outgoingCommand -> fragmentOffset = fragmentOffset;
-         
-         if (packet -> dataLength - fragmentOffset >= fragmentLength)
-           outgoingCommand -> fragmentLength = fragmentLength;
-         else
-           outgoingCommand -> fragmentLength = packet -> dataLength - fragmentOffset;
-
-         outgoingCommand -> command.header.command = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT;
-         outgoingCommand -> command.header.flags = 0;
-         outgoingCommand -> command.header.commandLength = sizeof (ENetProtocolSendFragment);
-         outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_32 (peer -> outgoingReliableSequenceNumber);
-         outgoingCommand -> command.sendFragment.startSequenceNumber = startSequenceNumber;
-         outgoingCommand -> command.sendFragment.fragmentCount = fragmentCount;
-         outgoingCommand -> command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32 (fragmentNumber);
-         outgoingCommand -> command.sendFragment.totalLength = ENET_HOST_TO_NET_32 (packet -> dataLength);
-         outgoingCommand -> command.sendFragment.fragmentOffset = ENET_HOST_TO_NET_32 (fragmentOffset);
-         
-         ++ packet -> referenceCount;
+         command.header.command = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT;
+         command.header.channelID = channelID;
+         command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE;
+         command.header.commandLength = sizeof (ENetProtocolSendFragment);
+         command.sendFragment.startSequenceNumber = startSequenceNumber;
+         command.sendFragment.fragmentCount = fragmentCount;
+         command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32 (fragmentNumber);
+         command.sendFragment.totalLength = ENET_HOST_TO_NET_32 (packet -> dataLength);
+         command.sendFragment.fragmentOffset = ENET_NET_TO_HOST_32 (fragmentOffset);
 
-         outgoingCommand -> packet = packet;
+         if (packet -> dataLength - fragmentOffset < fragmentLength)
+           fragmentLength = packet -> dataLength - fragmentOffset;
 
-         ++ fragmentNumber;
-         fragmentOffset += outgoingCommand -> fragmentLength;
+         enet_peer_queue_outgoing_command (peer, & command, packet, fragmentOffset, fragmentLength);
+      }
 
-         enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand);
-      } while (fragmentOffset < packet -> dataLength);
-
       return 0;
    }
-
-   outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand));
 
-   ++ packet -> referenceCount;
+   command.header.channelID = channelID;
 
    if (packet -> flags & ENET_PACKET_FLAG_RELIABLE)
    {
-      ++ peer -> outgoingReliableSequenceNumber;
-
-      outgoingCommand -> unreliableSequenceNumber = 0;
-      
-      outgoingCommand -> command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE;
-      outgoingCommand -> command.header.commandLength = sizeof (ENetProtocolSendReliable);
-
-      enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand);
+      command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE;
+      command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE;
+      command.header.commandLength = sizeof (ENetProtocolSendReliable);
    }
    else
    {
-      ++ peer -> outgoingUnreliableSequenceNumber;
-
-      outgoingCommand -> unreliableSequenceNumber = peer -> outgoingUnreliableSequenceNumber;
-
-      outgoingCommand -> command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE;
-      outgoingCommand -> command.header.commandLength = sizeof (ENetProtocolSendUnreliable);
-      outgoingCommand -> command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_32 (peer -> outgoingUnreliableSequenceNumber);
-
-      enet_list_insert (enet_list_end (& peer -> outgoingUnreliableCommands), outgoingCommand);
+      command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE;
+      command.header.flags = 0;
+      command.header.commandLength = sizeof (ENetProtocolSendUnreliable);
+      command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_32 (channel -> outgoingUnreliableSequenceNumber + 1);
    }
-
-   outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber;
-   outgoingCommand -> sentTime = 0;
-   outgoingCommand -> roundTripTimeout = 0;
-   outgoingCommand -> roundTripTimeoutLimit = 0;
-   outgoingCommand -> fragmentOffset = 0;
-   outgoingCommand -> fragmentLength = packet -> dataLength;
-   outgoingCommand -> packet = packet;
 
-   outgoingCommand -> command.header.flags = 0;
-   outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_32 (peer -> outgoingReliableSequenceNumber);
+   enet_peer_queue_outgoing_command (peer, & command, packet, 0, packet -> dataLength);
 
    return 0;
 }
 
 ENetPacket *
-enet_peer_receive (ENetPeer * peer)
+enet_peer_receive (ENetPeer * peer, uint8 channelID)
 {
+   ENetChannel * channel = & peer -> channels [channelID];
    ENetIncomingCommand * incomingCommand = NULL;
    ENetPacket * packet;
 
-   if (enet_list_empty (& peer -> incomingUnreliableCommands) == 0)
+   if (enet_list_empty (& channel -> incomingUnreliableCommands) == 0)
    {
-      incomingCommand = (ENetIncomingCommand *) enet_list_front (& peer -> incomingUnreliableCommands);
+      incomingCommand = (ENetIncomingCommand *) enet_list_front (& channel -> incomingUnreliableCommands);
 
-      if (incomingCommand -> reliableSequenceNumber > peer -> incomingReliableSequenceNumber)
+      if (incomingCommand -> reliableSequenceNumber > channel -> incomingReliableSequenceNumber)
         incomingCommand = NULL;
       else
-        peer -> incomingUnreliableSequenceNumber = incomingCommand -> unreliableSequenceNumber;
+        channel -> incomingUnreliableSequenceNumber = incomingCommand -> unreliableSequenceNumber;
    }
 
    if (incomingCommand == NULL &&
-       enet_list_empty (& peer -> incomingReliableCommands) == 0)
+       enet_list_empty (& channel -> incomingReliableCommands) == 0)
    {
       do
       {
-        incomingCommand = (ENetIncomingCommand *) enet_list_front (& peer -> incomingReliableCommands);
+        incomingCommand = (ENetIncomingCommand *) enet_list_front (& channel -> incomingReliableCommands);
 
-        if (incomingCommand -> acknowledged == 0 ||
-            incomingCommand -> fragmentsRemaining > 0 ||
-            incomingCommand -> reliableSequenceNumber > peer -> incomingReliableSequenceNumber + 1)
+        if (incomingCommand -> fragmentsRemaining > 0 ||
+            incomingCommand -> reliableSequenceNumber > channel -> incomingReliableSequenceNumber + 1)
           return NULL;
 
-        if (incomingCommand -> packet == NULL ||
-            incomingCommand -> reliableSequenceNumber <= peer -> incomingReliableSequenceNumber)
+        if (incomingCommand -> reliableSequenceNumber <= channel -> incomingReliableSequenceNumber)
         {
-           if (incomingCommand -> reliableSequenceNumber == peer -> incomingReliableSequenceNumber + 1)
-             peer -> incomingReliableSequenceNumber = incomingCommand -> reliableSequenceNumber;
+           -- incomingCommand -> packet -> referenceCount;
+
+           if (incomingCommand -> packet -> referenceCount == 0)
+             enet_packet_destroy (incomingCommand -> packet);
 
-           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_list_remove (& incomingCommand -> incomingCommandList);
 
@@ -153,12 +140,15 @@
            incomingCommand = NULL;
         }
       } while (incomingCommand == NULL &&
-               enet_list_empty (& peer -> incomingReliableCommands) == 0);
+               enet_list_empty (& channel -> incomingReliableCommands) == 0);
 
       if (incomingCommand == NULL)
         return NULL;
 
-      peer -> incomingReliableSequenceNumber = incomingCommand -> reliableSequenceNumber;
+      channel -> incomingReliableSequenceNumber = incomingCommand -> reliableSequenceNumber;
+
+      if (incomingCommand -> fragmentCount > 0)
+        channel -> incomingReliableSequenceNumber += incomingCommand -> fragmentCount - 1;
    }
 
    if (incomingCommand == NULL)
@@ -178,13 +168,54 @@
    return packet;
 }
 
+static void
+enet_peer_reset_outgoing_commands (ENetList * queue)
+{
+    ENetOutgoingCommand * outgoingCommand;
+
+    while (enet_list_empty (queue) == 0)
+    {
+       outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (queue));
+
+       if (outgoingCommand -> packet != NULL)
+       {
+          -- outgoingCommand -> packet -> referenceCount;
+
+          if (outgoingCommand -> packet -> referenceCount == 0)
+            enet_packet_destroy (outgoingCommand -> packet);
+       }
+
+       enet_free (outgoingCommand);
+    }
+}
+
+static void
+enet_peer_reset_incoming_commands (ENetList * queue)
+{
+    ENetIncomingCommand * incomingCommand;
+
+    while (enet_list_empty (queue) == 0)
+    {
+       incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (queue));
+
+       if (incomingCommand -> packet != NULL)
+       {
+          -- incomingCommand -> packet -> referenceCount;
+
+          if (incomingCommand -> packet -> referenceCount == 0)
+            enet_packet_destroy (incomingCommand -> packet);
+       }
+
+       enet_free (incomingCommand);
+    }
+}
+
 void
 enet_peer_reset (ENetPeer * peer)
 {
-    ENetIncomingCommand * incomingCommand;
-    ENetOutgoingCommand * outgoingCommand;
+    ENetChannel * channel;
 
-    peer -> outgoingPeerID = ~0;
+    peer -> outgoingPeerID = 0xFFFF;
     peer -> challenge = 0;
 
     peer -> address.host = ENET_HOST_ANY;
@@ -192,6 +223,12 @@
 
     peer -> state = ENET_PEER_STATE_DISCONNECTED;
 
+    peer -> incomingBandwidth = 0;
+    peer -> outgoingBandwidth = 0;
+    peer -> incomingBandwidthThrottleEpoch = 0;
+    peer -> outgoingBandwidthThrottleEpoch = 0;
+    peer -> incomingDataTotal = 0;
+    peer -> outgoingDataTotal = 0;
     peer -> lastSendTime = 0;
     peer -> lastReceiveTime = 0;
     peer -> nextTimeout = 0;
@@ -201,150 +238,240 @@
     peer -> packetLoss = 0;
     peer -> packetLossVariance = 0;
     peer -> packetThrottle = ENET_PEER_DEFAULT_PACKET_THROTTLE;
+    peer -> packetThrottleLimit = ENET_PEER_PACKET_THROTTLE_SCALE;
+    peer -> packetThrottleCounter = 0;
+    peer -> packetThrottleEpoch = 0;
+    peer -> bestRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
     peer -> roundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
     peer -> roundTripTimeVariance = 0;
     peer -> packetSize = ENET_PROTOCOL_MINIMUM_PACKET_SIZE;
-    peer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
     peer -> reliableDataInTransit = 0;
-    peer -> sentUnreliableSequenceNumber = 0;
     peer -> outgoingReliableSequenceNumber = 0;
-    peer -> outgoingUnreliableSequenceNumber = 0;
-    peer -> incomingReliableSequenceNumber = 0;
-    peer -> incomingUnreliableSequenceNumber = 0;
 
-    while (enet_list_empty (& peer -> sentReliableCommands) == 0)
-    {
-       outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& peer -> sentReliableCommands));
+    peer -> windowSize = (peer -> host -> outgoingBandwidth / 
+                           ENET_PEER_WINDOW_SIZE_SCALE) * ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
 
-       if (outgoingCommand -> packet != NULL)
-       {
-          -- outgoingCommand -> packet -> referenceCount;
+    if (peer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE)
+      peer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
+    else
+    if (peer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE)
+      peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
+    
+    while (enet_list_empty (& peer -> acknowledgements) == 0)
+      enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements)));
+
+    enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands);
+    enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands);
+    enet_peer_reset_outgoing_commands (& peer -> outgoingReliableCommands);
+    enet_peer_reset_outgoing_commands (& peer -> outgoingUnreliableCommands);
 
-          if (outgoingCommand -> packet -> referenceCount == 0)
-            enet_packet_destroy (outgoingCommand -> packet);
-       }
+    if (peer -> channels != NULL && peer -> channelCount > 0)
+    {
+        for (channel = peer -> channels;
+             channel < & peer -> channels [peer -> channelCount];
+             ++ channel)
+        {
+            channel -> outgoingReliableSequenceNumber = 0;
+            channel -> outgoingUnreliableSequenceNumber = 0;
+            channel -> incomingReliableSequenceNumber = 0;
+            channel -> incomingUnreliableSequenceNumber = 0;
+             
+            enet_peer_reset_incoming_commands (& channel -> incomingReliableCommands);
+            enet_peer_reset_incoming_commands (& channel -> incomingUnreliableCommands);
+        }
 
-       enet_free (outgoingCommand);
+        enet_free (peer -> channels);
     }
 
-    while (enet_list_empty (& peer -> outgoingReliableCommands) == 0)
-    {
-       outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& peer -> outgoingReliableCommands));
+    peer -> channels = NULL;
+    peer -> channelCount = 0;
+}
 
-       if (outgoingCommand -> packet != NULL)
-       {
-          -- outgoingCommand -> packet -> referenceCount;
+void
+enet_peer_ping (ENetPeer * peer)
+{
+    ENetProtocol command;
 
-          if (outgoingCommand -> packet -> referenceCount == 0)
-            enet_packet_destroy (outgoingCommand -> packet);
-       }
-       
-       enet_free (outgoingCommand);
-    }
+    if (peer -> state != ENET_PEER_STATE_CONNECTED)
+      return;
 
-    while (enet_list_empty (& peer -> outgoingUnreliableCommands) == 0)
-    {
-       outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& peer -> outgoingUnreliableCommands));
+    command.header.command = ENET_PROTOCOL_COMMAND_PING;
+    command.header.channelID = 0xFF;
+    command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE;
+    command.header.commandLength = sizeof (ENetProtocolPing);
+   
+    enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
+}
 
-       if (outgoingCommand -> packet != NULL)
-       {
-          -- outgoingCommand -> packet -> referenceCount;
+void
+enet_peer_disconnect (ENetPeer * peer)
+{
+    ENetProtocol command;
 
-          if (outgoingCommand -> packet -> referenceCount == 0)
-            enet_packet_destroy (outgoingCommand -> packet);
-       }
+    if (peer -> state == ENET_PEER_STATE_DISCONNECTING ||
+        peer -> state == ENET_PEER_STATE_DISCONNECTED)
+      return;
 
-       enet_free (outgoingCommand);
-    }
+    peer -> state = ENET_PEER_STATE_DISCONNECTING;
 
-    while (enet_list_empty (& peer -> incomingReliableCommands) == 0)
-    {
-       incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (& peer -> incomingReliableCommands));
+    command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT;
+    command.header.channelID = 0xFF;
+    command.header.flags = ENET_PROTOCOL_FLAG_ACKNOWLEDGE;
+    command.header.commandLength = sizeof (ENetProtocolDisconnect);
 
-       if (incomingCommand -> packet != NULL)
-       {
-          -- incomingCommand -> packet -> referenceCount;
-          
-          if (incomingCommand -> packet -> referenceCount == 0)
-            enet_packet_destroy (incomingCommand -> packet);
-       }
-       
-       enet_free (incomingCommand);
-    } 
+    enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
+}
 
-    while (enet_list_empty (& peer -> incomingUnreliableCommands) == 0)
-    {
-       incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (& peer -> incomingUnreliableCommands));
+ENetAcknowledgement *
+enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command, uint32 sentTime)
+{
+    ENetAcknowledgement * acknowledgement;
 
-       if (incomingCommand -> packet != NULL)
-       {
-          -- incomingCommand -> packet -> referenceCount;
+    peer -> outgoingDataTotal += sizeof (ENetProtocolAcknowledge);
 
-          if (incomingCommand -> packet -> referenceCount == 0)
-            enet_packet_destroy (incomingCommand -> packet);
-       }
+    acknowledgement = (ENetAcknowledgement *) enet_malloc (sizeof (ENetAcknowledgement));
 
-       enet_free (incomingCommand);
-    }
+    acknowledgement -> sentTime = sentTime;
+    acknowledgement -> command = * command;
+    
+    enet_list_insert (enet_list_end (& peer -> acknowledgements), acknowledgement);
+    
+    return acknowledgement;
 }
 
-void
-enet_peer_ping (ENetPeer * peer)
+ENetOutgoingCommand *
+enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, uint32 offset, uint16 length)
 {
+    ENetChannel * channel = & peer -> channels [command -> header.channelID];
     ENetOutgoingCommand * outgoingCommand;
 
+    peer -> outgoingDataTotal += command -> header.commandLength + length;
+
     outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand));
 
-    ++ peer -> outgoingReliableSequenceNumber;
+    if (command -> header.channelID == 0xFF)
+    {
+       ++ peer -> outgoingReliableSequenceNumber;
 
-    outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber;
-    outgoingCommand -> unreliableSequenceNumber = 0;
+       outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber;
+       outgoingCommand -> unreliableSequenceNumber = 0;
+    }
+    else
+    if (command -> header.flags & ENET_PROTOCOL_FLAG_ACKNOWLEDGE)
+    {
+       ++ channel -> outgoingReliableSequenceNumber;
+       
+       outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
+       outgoingCommand -> unreliableSequenceNumber = 0;
+    }
+    else
+    {
+       ++ channel -> outgoingUnreliableSequenceNumber;
+        
+       outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
+       outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber;
+    }
+   
     outgoingCommand -> sentTime = 0;
     outgoingCommand -> roundTripTimeout = 0;
     outgoingCommand -> roundTripTimeoutLimit = 0;
-    outgoingCommand -> fragmentOffset = 0;
-    outgoingCommand -> fragmentLength = 0;
-    outgoingCommand -> packet = NULL;
-
-    outgoingCommand -> command.header.command = ENET_PROTOCOL_COMMAND_PING;
-    outgoingCommand -> command.header.flags = 0;
-    outgoingCommand -> command.header.commandLength = sizeof (ENetProtocolPing);
-    outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_32 (peer -> outgoingReliableSequenceNumber);
+    outgoingCommand -> fragmentOffset = offset;
+    outgoingCommand -> fragmentLength = length;
+    outgoingCommand -> packet = packet;
+    outgoingCommand -> command = * command;
+    outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_32 (outgoingCommand -> reliableSequenceNumber);
+
+    if (packet != NULL)
+      ++ packet -> referenceCount;
 
-    enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand);
+    if (command -> header.flags & ENET_PROTOCOL_FLAG_ACKNOWLEDGE)
+      enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand);
+    else
+      enet_list_insert (enet_list_end (& peer -> outgoingUnreliableCommands), outgoingCommand);
+
+    return outgoingCommand;
 }
 
-void
-enet_peer_disconnect (ENetPeer * peer)
+ENetIncomingCommand *
+enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, uint32 fragmentCount)
 {
-    ENetOutgoingCommand * outgoingCommand;
+    ENetChannel * channel = & peer -> channels [command -> header.channelID];
+    uint32 unreliableSequenceNumber = 0;
+    ENetIncomingCommand * incomingCommand;
+    ENetListIterator currentCommand;
 
-    if (peer -> state == ENET_PEER_STATE_DISCONNECTING ||
-        peer -> state == ENET_PEER_STATE_DISCONNECTED)
-      return;
+    if (command -> header.command == ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE)
+      unreliableSequenceNumber = ENET_NET_TO_HOST_32 (command -> sendUnreliable.unreliableSequenceNumber);
 
-    peer -> state = ENET_PEER_STATE_DISCONNECTING;
+    if (unreliableSequenceNumber == 0)
+    {
+       for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands));
+            currentCommand != enet_list_end (& channel -> incomingReliableCommands);
+            currentCommand = enet_list_previous (currentCommand))
+       {
+          incomingCommand = (ENetIncomingCommand *) currentCommand;
 
-    outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand));
+          if (incomingCommand -> reliableSequenceNumber <= command -> header.reliableSequenceNumber)
+          {
+             if (incomingCommand -> reliableSequenceNumber < command -> header.reliableSequenceNumber)
+               break;
 
-    ++ peer -> outgoingReliableSequenceNumber;
+             goto freePacket;
+          }
+       }
+    }
+    else
+    {
+       if (command -> header.reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
+         goto freePacket;
 
-    outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber;
-    outgoingCommand -> unreliableSequenceNumber = 0;
-    outgoingCommand -> sentTime = 0;
-    outgoingCommand -> roundTripTimeout = 0;
-    outgoingCommand -> roundTripTimeoutLimit = 0;
-    outgoingCommand -> fragmentOffset = 0;
-    outgoingCommand -> fragmentLength = 0;
-    outgoingCommand -> packet = NULL;
-
-    outgoingCommand -> command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT;
-    outgoingCommand -> command.header.flags = 0;
-    outgoingCommand -> command.header.commandLength = sizeof (ENetProtocolDisconnect);
-    outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_32 (peer -> outgoingReliableSequenceNumber);
+       if (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 -> unreliableSequenceNumber <= unreliableSequenceNumber)
+          {
+             if (incomingCommand -> unreliableSequenceNumber < unreliableSequenceNumber)
+               break;
 
-    enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand);
+             goto freePacket;
+          }
+       }
+    }
+        
+    incomingCommand = (ENetIncomingCommand *) enet_malloc (sizeof (ENetIncomingCommand));
+
+    incomingCommand -> reliableSequenceNumber = command -> header.reliableSequenceNumber;
+    incomingCommand -> unreliableSequenceNumber = unreliableSequenceNumber;
+    incomingCommand -> command = * command;
+    incomingCommand -> fragmentCount = fragmentCount;
+    incomingCommand -> fragmentsRemaining = fragmentCount;
+    incomingCommand -> packet = packet;
+
+    if (fragmentCount > 0)
+      incomingCommand -> fragments = (uint32 *) enet_calloc ((fragmentCount + 31) / 32, sizeof (uint32));
+    else
+      incomingCommand -> fragments = NULL;
+
+    if (packet != NULL)
+      ++ packet -> referenceCount;
+
+    enet_list_insert (enet_list_next (currentCommand), incomingCommand);
+
+    return incomingCommand;
+
+freePacket:
+    if (packet != NULL)
+    {
+       if (packet -> referenceCount == 0)
+         enet_packet_destroy (packet);
+    }
+
+    return NULL;
 }
- 
 
-   

Index: protocol.c
===================================================================
RCS file: /home/enet/cvsroot/enet/protocol.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- protocol.c	2002/02/10 22:24:41	1.2
+++ protocol.c	2002/06/08 02:29:12	1.3
@@ -8,6 +8,7 @@
 enet_protocol_dispatch_incoming_commands (ENetHost * host, ENetEvent * event)
 {
     ENetPeer * currentPeer = host -> lastServicedPeer;
+    ENetChannel * channel;
 
     do
     {
@@ -19,119 +20,55 @@
        if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED)
          continue;
 
[...1036 lines suppressed...]
           return -1;
@@ -1136,6 +983,8 @@
 void
 enet_host_flush (ENetHost * host)
 {
+    timeCurrent = enet_time_get ();
+
     enet_protocol_send_outgoing_commands (host, NULL, 0);
 }
 
@@ -1168,6 +1017,9 @@
 
     do
     {
+       if (timeCurrent - host -> bandwidthThrottleEpoch >= ENET_HOST_BANDWIDTH_THROTTLE_EPOCH)
+         enet_host_bandwidth_throttle (host);
+
        switch (enet_protocol_receive_incoming_commands (host, event))
        {
        case 1:

Index: unix.c
===================================================================
RCS file: /home/enet/cvsroot/enet/unix.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- unix.c	2002/02/10 21:27:03	1.1
+++ unix.c	2002/06/08 02:29:12	1.2
@@ -28,8 +28,6 @@
 int
 enet_initialize (void)
 {
-    srand (time (NULL));
-    
     return 0;
 }
 
@@ -91,9 +89,9 @@
 }
 
 ENetSocket
-enet_socket_create (const ENetAddress * address)
+enet_socket_create (ENetSocketType type, const ENetAddress * address)
 {
-    ENetSocket newSocket = socket (PF_INET, SOCK_DGRAM, 0);
+    ENetSocket newSocket = socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
     int nonBlocking = 1,
         receiveBufferSize = ENET_HOST_RECEIVE_BUFFER_SIZE;
     struct sockaddr_in sin;
@@ -101,14 +99,17 @@
     if (newSocket == ENET_SOCKET_NULL)
       return ENET_SOCKET_NULL;
 
+    if (type == ENET_SOCKET_TYPE_DATAGRAM)
+    {
 #ifdef HAS_FCNTL
-    fcntl (newSocket, F_SETFL, O_NONBLOCK | fcntl (newSocket, F_GETFL));
+        fcntl (newSocket, F_SETFL, O_NONBLOCK | fcntl (newSocket, F_GETFL));
 #else
-    ioctl (newSocket, FIONBIO, & nonBlocking);
+        ioctl (newSocket, FIONBIO, & nonBlocking);
 #endif
-
-    setsockopt (newSocket, SOL_SOCKET, SO_RCVBUF, (char *) & receiveBufferSize, sizeof (int));
 
+        setsockopt (newSocket, SOL_SOCKET, SO_RCVBUF, (char *) & receiveBufferSize, sizeof (int));
+    }
+    
     if (address == NULL)
       return newSocket;
 
@@ -118,7 +119,9 @@
     sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
     sin.sin_addr.s_addr = address -> host;
 
-    if (bind (newSocket, 
+    if ((type == ENET_SOCKET_TYPE_STREAM &&
+          listen (newSocket, SOMAXCONN) == -1) ||
+        bind (newSocket, 
               (struct sockaddr *) & sin,
               sizeof (struct sockaddr_in)) == -1)
     {
@@ -130,6 +133,43 @@
     return newSocket;
 }
 
+int
+enet_socket_connect (ENetSocket socket, const ENetAddress * address)
+{
+    struct sockaddr_in sin;
+
+    memset (& sin, 0, sizeof (struct sockaddr_in));
+
+    sin.sin_family = AF_INET;
+    sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+    sin.sin_addr.s_addr = address -> host;
+
+    return connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
+}
+
+ENetSocket
+enet_socket_accept (ENetSocket socket, ENetAddress * address)
+{
+    int result;
+    struct sockaddr_in sin;
+    socklen_t sinLength = sizeof (struct sockaddr_in);
+
+    result = accept (socket, 
+                     address != NULL ? (struct sockaddr *) & sin : NULL, 
+                     address != NULL ? & sinLength : NULL);
+    
+    if (result == -1)
+      return ENET_SOCKET_NULL;
+
+    if (address != NULL)
+    {
+        address -> host = (uint32) sin.sin_addr.s_addr;
+        address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+    }
+
+    return result;
+} 
+    
 void
 enet_socket_destroy (ENetSocket socket)
 {
@@ -146,14 +186,18 @@
     struct sockaddr_in sin;
     int sentLength;
 
-    sin.sin_family = AF_INET;
-    sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
-    sin.sin_addr.s_addr = address -> host;
-
     memset (& msgHdr, 0, sizeof (struct msghdr));
+
+    if (address != NULL)
+    {
+        sin.sin_family = AF_INET;
+        sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+        sin.sin_addr.s_addr = address -> host;
+
+        msgHdr.msg_name = & sin;
+        msgHdr.msg_namelen = sizeof (struct sockaddr_in);
+    }
 
-    msgHdr.msg_name = & sin;
-    msgHdr.msg_namelen = sizeof (struct sockaddr_in);
     msgHdr.msg_iov = (struct iovec *) buffers;
     msgHdr.msg_iovlen = bufferCount;
 
@@ -182,8 +226,12 @@
 
     memset (& msgHdr, 0, sizeof (struct msghdr));
 
-    msgHdr.msg_name = & sin;
-    msgHdr.msg_namelen = sizeof (struct sockaddr_in);
+    if (address != NULL)
+    {
+        msgHdr.msg_name = & sin;
+        msgHdr.msg_namelen = sizeof (struct sockaddr_in);
+    }
+
     msgHdr.msg_iov = (struct iovec *) buffers;
     msgHdr.msg_iovlen = bufferCount;
 
@@ -202,8 +250,11 @@
       return -1;
 #endif
 
-    address -> host = (uint32) sin.sin_addr.s_addr;
-    address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+    if (address != NULL)
+    {
+        address -> host = (uint32) sin.sin_addr.s_addr;
+        address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+    }
 
     return recvLength;
 }

Index: win32.c
===================================================================
RCS file: /home/enet/cvsroot/enet/win32.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- win32.c	2002/02/10 22:24:41	1.2
+++ win32.c	2002/06/08 02:29:12	1.3
@@ -22,8 +22,6 @@
        return -1;
     }
 
-    srand (time (NULL));
-
     return 0;
 }
 
@@ -78,9 +76,9 @@
 }
 
 ENetSocket
-enet_socket_create (const ENetAddress * address)
+enet_socket_create (ENetSocketType type, const ENetAddress * address)
 {
-    ENetSocket newSocket = socket (PF_INET, SOCK_DGRAM, 0);
+    ENetSocket newSocket = socket (PF_INET, type == ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM : SOCK_STREAM, 0);
     int nonBlocking = 1,
         receiveBufferSize = ENET_HOST_RECEIVE_BUFFER_SIZE;
     struct sockaddr_in sin;
@@ -88,9 +86,12 @@
     if (newSocket == ENET_SOCKET_NULL)
       return ENET_SOCKET_NULL;
 
-    ioctlsocket (newSocket, FIONBIO, & nonBlocking);
+    if (type == ENET_SOCKET_TYPE_DATAGRAM)
+    {
+        ioctlsocket (newSocket, FIONBIO, & nonBlocking);
 
-    setsockopt (newSocket, SOL_SOCKET, SO_RCVBUF, (char *) & receiveBufferSize, sizeof (int));
+        setsockopt (newSocket, SOL_SOCKET, SO_RCVBUF, (char *) & receiveBufferSize, sizeof (int));
+    }
 
     memset (& sin, 0, sizeof (struct sockaddr_in));
 
@@ -107,7 +108,9 @@
        sin.sin_addr.s_addr = INADDR_ANY;
     }
 
-    if (bind (newSocket, 
+    if ((type == ENET_SOCKET_TYPE_STREAM &&
+          listen (newSocket, SOMAXCONN) == SOCKET_ERROR) ||
+        bind (newSocket,    
               (struct sockaddr *) & sin,
               sizeof (struct sockaddr_in)) == SOCKET_ERROR)
     {
@@ -119,6 +122,43 @@
     return newSocket;
 }
 
+int
+enet_socket_connect (ENetSocket socket, const ENetAddress * address)
+{
+    struct sockaddr_in sin;
+
+    memset (& sin, 0, sizeof (struct sockaddr_in));
+
+    sin.sin_family = AF_INET;
+    sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+    sin.sin_addr.s_addr = address -> host;
+
+    return connect (socket, (struct sockaddr *) & sin, sizeof (struct sockaddr_in));
+}
+
+ENetSocket
+enet_socket_accept (ENetSocket socket, ENetAddress * address)
+{
+    int result;
+    struct sockaddr_in sin;
+    int sinLength = sizeof (struct sockaddr_in);
+
+    result = accept (socket, 
+                     address != NULL ? (struct sockaddr *) & sin : NULL, 
+                     address != NULL ? & sinLength : NULL);
+
+    if (result == -1)
+      return ENET_SOCKET_NULL;
+
+    if (address != NULL)
+    {
+        address -> host = (uint32) sin.sin_addr.s_addr;
+        address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+    }
+
+    return result;
+}
+
 void
 enet_socket_destroy (ENetSocket socket)
 {
@@ -134,17 +174,20 @@
     struct sockaddr_in sin;
     DWORD sentLength;
 
-    sin.sin_family = AF_INET;
-    sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
-    sin.sin_addr.s_addr = address -> host;
+    if (address != NULL)
+    {
+        sin.sin_family = AF_INET;
+        sin.sin_port = ENET_HOST_TO_NET_16 (address -> port);
+        sin.sin_addr.s_addr = address -> host;
+    }
 
     if (WSASendTo (socket, 
                    (LPWSABUF) buffers,
                    (DWORD) bufferCount,
                    & sentLength,
                    0,
-                   (struct sockaddr *) & sin,
-                   sizeof (struct sockaddr_in),
+                   address != NULL ? (struct sockaddr *) & sin : 0,
+                   address != NULL ? sizeof (struct sockaddr_in) : 0,
                    NULL,
                    NULL) == SOCKET_ERROR)
     {
@@ -173,13 +216,17 @@
                      (DWORD) bufferCount,
                      & recvLength,
                      & flags,
-                     (struct sockaddr *) & sin,
-                     & sinLength,
+                     address != NULL ? (struct sockaddr *) & sin : NULL,
+                     address != NULL ? & sinLength : NULL,
                      NULL,
                      NULL) == SOCKET_ERROR)
     {
-       if (WSAGetLastError () == WSAEWOULDBLOCK)
-         return 0;
+       switch (WSAGetLastError ())
+       {
+       case WSAEWOULDBLOCK:
+       case WSAECONNRESET:
+          return 0;
+       }
 
        return -1;
     }
@@ -187,8 +234,11 @@
     if (flags & MSG_PARTIAL)
       return -1;
 
-    address -> host = (uint32) sin.sin_addr.s_addr;
-    address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+    if (address != NULL)
+    {
+        address -> host = (uint32) sin.sin_addr.s_addr;
+        address -> port = ENET_NET_TO_HOST_16 (sin.sin_port);
+    }
 
     return (int) recvLength;
 }