| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 | 
							- /** 
 
-  @file host.c
 
-  @brief ENet host management functions
 
- */
 
- #define ENET_BUILDING_LIB 1
 
- #include <string.h>
 
- #include <time.h>
 
- #include "enet/enet.h"
 
- /** @defgroup host ENet host functions
 
-     @{
 
- */
 
- /** Creates a host for communicating to peers.  
 
-     @param address   the address at which other peers may connect to this host.  If NULL, then no peers may connect to the host.
 
-     @param peerCount the maximum number of peers that should be allocated for the host.
 
-     @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
 
-     @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
 
-     @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
 
-     @returns the host on success and NULL on failure
 
-     @remarks ENet will strategically drop packets on specific sides of a connection between hosts
 
-     to ensure the host's bandwidth is not overwhelmed.  The bandwidth parameters also determine
 
-     the window size of a connection which limits the amount of reliable packets that may be in transit
 
-     at any given time.
 
- */
 
- ENetHost *
 
- enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
 
- {
 
-     ENetHost * host;
 
-     ENetPeer * currentPeer;
 
-     if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID)
 
-       return NULL;
 
-     host = (ENetHost *) enet_malloc (sizeof (ENetHost));
 
-     if (host == NULL)
 
-       return NULL;
 
-     memset (host, 0, sizeof (ENetHost));
 
-     host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer));
 
-     if (host -> peers == NULL)
 
-     {
 
-        enet_free (host);
 
-        return NULL;
 
-     }
 
-     memset (host -> peers, 0, peerCount * sizeof (ENetPeer));
 
-     host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM);
 
-     if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0))
 
-     {
 
-        if (host -> socket != ENET_SOCKET_NULL)
 
-          enet_socket_destroy (host -> socket);
 
-        enet_free (host -> peers);
 
-        enet_free (host);
 
-        return NULL;
 
-     }
 
-     enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1);
 
-     enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1);
 
-     enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE);
 
-     enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE);
 
-     if (address != NULL)
 
-       host -> address = * address;
 
-     if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
 
-       channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
 
-     else
 
-     if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
 
-       channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
 
-     host -> randomSeed = (enet_uint32) time(NULL) + (enet_uint32) (size_t) host;
 
-     host -> randomSeed = (host -> randomSeed << 16) | (host -> randomSeed >> 16);
 
-     host -> channelLimit = channelLimit;
 
-     host -> incomingBandwidth = incomingBandwidth;
 
-     host -> outgoingBandwidth = outgoingBandwidth;
 
-     host -> bandwidthThrottleEpoch = 0;
 
-     host -> recalculateBandwidthLimits = 0;
 
-     host -> mtu = ENET_HOST_DEFAULT_MTU;
 
-     host -> peerCount = peerCount;
 
-     host -> commandCount = 0;
 
-     host -> bufferCount = 0;
 
-     host -> checksum = NULL;
 
-     host -> receivedAddress.host = ENET_HOST_ANY;
 
-     host -> receivedAddress.port = 0;
 
-     host -> receivedData = NULL;
 
-     host -> receivedDataLength = 0;
 
-      
 
-     host -> totalSentData = 0;
 
-     host -> totalSentPackets = 0;
 
-     host -> totalReceivedData = 0;
 
-     host -> totalReceivedPackets = 0;
 
-     host -> compressor.context = NULL;
 
-     host -> compressor.compress = NULL;
 
-     host -> compressor.decompress = NULL;
 
-     host -> compressor.destroy = NULL;
 
-     enet_list_clear (& host -> dispatchQueue);
 
-     for (currentPeer = host -> peers;
 
-          currentPeer < & host -> peers [host -> peerCount];
 
-          ++ currentPeer)
 
-     {
 
-        currentPeer -> host = host;
 
-        currentPeer -> incomingPeerID = currentPeer - host -> peers;
 
-        currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF;
 
-        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 -> dispatchedCommands);
 
-        enet_peer_reset (currentPeer);
 
-     }
 
-     return host;
 
- }
 
- /** Destroys the host and all resources associated with it.
 
-     @param host pointer to the host to destroy
 
- */
 
- void
 
- enet_host_destroy (ENetHost * host)
 
- {
 
-     ENetPeer * currentPeer;
 
-     enet_socket_destroy (host -> socket);
 
-     for (currentPeer = host -> peers;
 
-          currentPeer < & host -> peers [host -> peerCount];
 
-          ++ currentPeer)
 
-     {
 
-        enet_peer_reset (currentPeer);
 
-     }
 
-     if (host -> compressor.context != NULL && host -> compressor.destroy)
 
-       (* host -> compressor.destroy) (host -> compressor.context);
 
-     enet_free (host -> peers);
 
-     enet_free (host);
 
- }
 
- /** Initiates a connection to a foreign host.
 
-     @param host host seeking the connection
 
-     @param address destination for the connection
 
-     @param channelCount number of channels to allocate
 
-     @param data user data supplied to the receiving host 
 
-     @returns a peer representing the foreign host on success, NULL on failure
 
-     @remarks The peer returned will have not completed the connection until enet_host_service()
 
-     notifies of an ENET_EVENT_TYPE_CONNECT event for the peer.
 
- */
 
- ENetPeer *
 
- enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount, enet_uint32 data)
 
- {
 
-     ENetPeer * currentPeer;
 
-     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)
 
-     {
 
-        if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED)
 
-          break;
 
-     }
 
-     if (currentPeer >= & host -> peers [host -> peerCount])
 
-       return NULL;
 
-     currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel));
 
-     if (currentPeer -> channels == NULL)
 
-       return NULL;
 
-     currentPeer -> channelCount = channelCount;
 
-     currentPeer -> state = ENET_PEER_STATE_CONNECTING;
 
-     currentPeer -> address = * address;
 
-     currentPeer -> connectID = ++ host -> randomSeed;
 
-     if (host -> outgoingBandwidth == 0)
 
-       currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
 
-     else
 
-       currentPeer -> windowSize = (host -> outgoingBandwidth /
 
-                                     ENET_PEER_WINDOW_SIZE_SCALE) * 
 
-                                       ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
 
-     if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE)
 
-       currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
 
-     else
 
-     if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE)
 
-       currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
 
-          
 
-     for (channel = currentPeer -> channels;
 
-          channel < & currentPeer -> channels [channelCount];
 
-          ++ channel)
 
-     {
 
-         channel -> outgoingReliableSequenceNumber = 0;
 
-         channel -> outgoingUnreliableSequenceNumber = 0;
 
-         channel -> incomingReliableSequenceNumber = 0;
 
-         channel -> incomingUnreliableSequenceNumber = 0;
 
-         enet_list_clear (& channel -> incomingReliableCommands);
 
-         enet_list_clear (& channel -> incomingUnreliableCommands);
 
-         channel -> usedReliableWindows = 0;
 
-         memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows));
 
-     }
 
-         
 
-     command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
 
-     command.header.channelID = 0xFF;
 
-     command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID);
 
-     command.connect.incomingSessionID = currentPeer -> incomingSessionID;
 
-     command.connect.outgoingSessionID = currentPeer -> outgoingSessionID;
 
-     command.connect.mtu = ENET_HOST_TO_NET_32 (currentPeer -> mtu);
 
-     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);
 
-     command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval);
 
-     command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration);
 
-     command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration);
 
-     command.connect.connectID = currentPeer -> connectID;
 
-     command.connect.data = ENET_HOST_TO_NET_32 (data);
 
-  
 
-     enet_peer_queue_outgoing_command (currentPeer, & command, NULL, 0, 0);
 
-     return currentPeer;
 
- }
 
- /** Queues a packet to be sent to all peers associated with the host.
 
-     @param host host on which to broadcast the packet
 
-     @param channelID channel on which to broadcast
 
-     @param packet packet to broadcast
 
- */
 
- void
 
- enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet)
 
- {
 
-     ENetPeer * currentPeer;
 
-     for (currentPeer = host -> peers;
 
-          currentPeer < & host -> peers [host -> peerCount];
 
-          ++ currentPeer)
 
-     {
 
-        if (currentPeer -> state != ENET_PEER_STATE_CONNECTED)
 
-          continue;
 
-        enet_peer_send (currentPeer, channelID, packet);
 
-     }
 
-     if (packet -> referenceCount == 0)
 
-       enet_packet_destroy (packet);
 
- }
 
- /** Sets the packet compressor the host should use to compress and decompress packets.
 
-     @param host host to enable or disable compression for
 
-     @param compressor callbacks for for the packet compressor; if NULL, then compression is disabled
 
- */
 
- void
 
- enet_host_compress (ENetHost * host, const ENetCompressor * compressor)
 
- {
 
-     if (host -> compressor.context != NULL && host -> compressor.destroy)
 
-       (* host -> compressor.destroy) (host -> compressor.context);
 
-     if (compressor)
 
-       host -> compressor = * compressor;
 
-     else
 
-       host -> compressor.context = NULL;
 
- }
 
- /** Limits the maximum allowed channels of future incoming connections.
 
-     @param host host to limit
 
-     @param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
 
- */
 
- void
 
- enet_host_channel_limit (ENetHost * host, size_t channelLimit)
 
- {
 
-     if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
 
-       channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
 
-     else
 
-     if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
 
-       channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
 
-     host -> channelLimit = channelLimit;
 
- }
 
- /** Adjusts the bandwidth limits of a host.
 
-     @param host host to adjust
 
-     @param incomingBandwidth new incoming bandwidth
 
-     @param outgoingBandwidth new outgoing bandwidth
 
-     @remarks the incoming and outgoing bandwidth parameters are identical in function to those
 
-     specified in enet_host_create().
 
- */
 
- void
 
- enet_host_bandwidth_limit (ENetHost * host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
 
- {
 
-     host -> incomingBandwidth = incomingBandwidth;
 
-     host -> outgoingBandwidth = outgoingBandwidth;
 
-     host -> recalculateBandwidthLimits = 1;
 
- }
 
- void
 
- enet_host_bandwidth_throttle (ENetHost * host)
 
- {
 
-     enet_uint32 timeCurrent = enet_time_get (),
 
-            elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch,
 
-            peersTotal = 0,
 
-            dataTotal = 0,
 
-            peersRemaining,
 
-            bandwidth,
 
-            throttle = 0,
 
-            bandwidthLimit = 0;
 
-     int needsAdjustment;
 
-     ENetPeer * peer;
 
-     ENetProtocol command;
 
-     if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL)
 
-       return;
 
-     for (peer = host -> peers;
 
-          peer < & host -> peers [host -> peerCount];
 
-          ++ peer)
 
-     {
 
-         if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
 
-           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)
 
-         {
 
-             enet_uint32 peerBandwidth;
 
-             
 
-             if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
 
-                 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;
 
-             
 
-             if (peer -> packetThrottle > peer -> packetThrottleLimit)
 
-               peer -> packetThrottle = peer -> packetThrottleLimit;
 
-             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 -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
 
-             peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
 
-           continue;
 
-         peer -> packetThrottleLimit = throttle;
 
-         if (peer -> packetThrottle > peer -> packetThrottleLimit)
 
-           peer -> packetThrottle = peer -> packetThrottleLimit;
 
-     }
 
-     
 
-     if (host -> recalculateBandwidthLimits)
 
-     {
 
-        host -> recalculateBandwidthLimits = 0;
 
-        peersRemaining = peersTotal;
 
-        bandwidth = host -> incomingBandwidth;
 
-        needsAdjustment = 1;
 
-        if (bandwidth == 0)
 
-          bandwidthLimit = 0;
 
-        else
 
-        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 -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
 
-                    peer -> incomingBandwidthThrottleEpoch == timeCurrent)
 
-                  continue;
 
-                if (peer -> outgoingBandwidth > 0 &&
 
-                    peer -> outgoingBandwidth >= bandwidthLimit)
 
-                  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 && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
 
-              continue;
 
-            command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
 
-            command.header.channelID = 0xFF;
 
-            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;
 
-     }
 
- }
 
-     
 
- /** @} */
 
 
  |