home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2007 September / maximum-cd-2007-09.iso / Assets / data / AssaultCube_v0.93.exe / source / enet / host.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-11-06  |  13.9 KB  |  392 lines

  1. /** 
  2.  @file host.c
  3.  @brief ENet host management functions
  4. */
  5. #define ENET_BUILDING_LIB 1
  6. #include <string.h>
  7. #include "enet/enet.h"
  8.  
  9. /** @defgroup host ENet host functions
  10.     @{
  11. */
  12.  
  13. /** Creates a host for communicating to peers.  
  14.  
  15.     @param address   the address at which other peers may connect to this host.  If NULL, then no peers may connect to the host.
  16.     @param peerCount the maximum number of peers that should be allocated for the host.
  17.     @param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
  18.     @param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
  19.  
  20.     @returns the host on success and NULL on failure
  21.  
  22.     @remarks ENet will strategically drop packets on specific sides of a connection between hosts
  23.     to ensure the host's bandwidth is not overwhelmed.  The bandwidth parameters also determine
  24.     the window size of a connection which limits the amount of reliable packets that may be in transit
  25.     at any given time.
  26. */
  27. ENetHost *
  28. enet_host_create (const ENetAddress * address, size_t peerCount, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
  29. {
  30.     ENetHost * host = (ENetHost *) enet_malloc (sizeof (ENetHost));
  31.     ENetPeer * currentPeer;
  32.  
  33.     if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID)
  34.       return NULL;
  35.  
  36.     host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer));
  37.     memset (host -> peers, 0, peerCount * sizeof (ENetPeer));
  38.  
  39.     host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM, address);
  40.     if (host -> socket == ENET_SOCKET_NULL)
  41.     {
  42.        enet_free (host -> peers);
  43.        enet_free (host);
  44.  
  45.        return NULL;
  46.     }
  47.  
  48.     if (address != NULL)
  49.       host -> address = * address;
  50.  
  51.     host -> incomingBandwidth = incomingBandwidth;
  52.     host -> outgoingBandwidth = outgoingBandwidth;
  53.     host -> bandwidthThrottleEpoch = 0;
  54.     host -> recalculateBandwidthLimits = 0;
  55.     host -> mtu = ENET_HOST_DEFAULT_MTU;
  56.     host -> peerCount = peerCount;
  57.     host -> lastServicedPeer = host -> peers;
  58.     host -> commandCount = 0;
  59.     host -> bufferCount = 0;
  60.     host -> receivedAddress.host = ENET_HOST_ANY;
  61.     host -> receivedAddress.port = 0;
  62.     host -> receivedDataLength = 0;
  63.      
  64.     for (currentPeer = host -> peers;
  65.          currentPeer < & host -> peers [host -> peerCount];
  66.          ++ currentPeer)
  67.     {
  68.        currentPeer -> host = host;
  69.        currentPeer -> incomingPeerID = currentPeer - host -> peers;
  70.        currentPeer -> data = NULL;
  71.  
  72.        enet_list_clear (& currentPeer -> acknowledgements);
  73.        enet_list_clear (& currentPeer -> sentReliableCommands);
  74.        enet_list_clear (& currentPeer -> sentUnreliableCommands);
  75.        enet_list_clear (& currentPeer -> outgoingReliableCommands);
  76.        enet_list_clear (& currentPeer -> outgoingUnreliableCommands);
  77.  
  78.        enet_peer_reset (currentPeer);
  79.     }
  80.  
  81.     return host;
  82. }
  83.  
  84. /** Destroys the host and all resources associated with it.
  85.     @param host pointer to the host to destroy
  86. */
  87. void
  88. enet_host_destroy (ENetHost * host)
  89. {
  90.     ENetPeer * currentPeer;
  91.  
  92.     enet_socket_destroy (host -> socket);
  93.  
  94.     for (currentPeer = host -> peers;
  95.          currentPeer < & host -> peers [host -> peerCount];
  96.          ++ currentPeer)
  97.     {
  98.        enet_peer_reset (currentPeer);
  99.     }
  100.  
  101.     enet_free (host -> peers);
  102.     enet_free (host);
  103. }
  104.  
  105. /** Initiates a connection to a foreign host.
  106.     @param host host seeking the connection
  107.     @param address destination for the connection
  108.     @param channelCount number of channels to allocate
  109.     @returns a peer representing the foreign host on success, NULL on failure
  110.     @remarks The peer returned will have not completed the connection until enet_host_service()
  111.     notifies of an ENET_EVENT_TYPE_CONNECT event for the peer.
  112. */
  113. ENetPeer *
  114. enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount)
  115. {
  116.     ENetPeer * currentPeer;
  117.     ENetChannel * channel;
  118.     ENetProtocol command;
  119.  
  120.     if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
  121.       channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
  122.     else
  123.     if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
  124.       channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
  125.  
  126.     for (currentPeer = host -> peers;
  127.          currentPeer < & host -> peers [host -> peerCount];
  128.          ++ currentPeer)
  129.     {
  130.        if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED)
  131.          break;
  132.     }
  133.  
  134.     if (currentPeer >= & host -> peers [host -> peerCount])
  135.       return NULL;
  136.  
  137.     currentPeer -> state = ENET_PEER_STATE_CONNECTING;
  138.     currentPeer -> address = * address;
  139.     currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel));
  140.     currentPeer -> channelCount = channelCount;
  141.     currentPeer -> sessionID = (enet_uint32) enet_rand ();
  142.  
  143.     if (host -> outgoingBandwidth == 0)
  144.       currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
  145.     else
  146.       currentPeer -> windowSize = (host -> outgoingBandwidth /
  147.                                     ENET_PEER_WINDOW_SIZE_SCALE) * 
  148.                                       ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
  149.  
  150.     if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE)
  151.       currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
  152.     else
  153.     if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE)
  154.       currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
  155.          
  156.     for (channel = currentPeer -> channels;
  157.          channel < & currentPeer -> channels [channelCount];
  158.          ++ channel)
  159.     {
  160.         channel -> outgoingReliableSequenceNumber = 0;
  161.         channel -> outgoingUnreliableSequenceNumber = 0;
  162.         channel -> incomingReliableSequenceNumber = 0;
  163.         channel -> incomingUnreliableSequenceNumber = 0;
  164.  
  165.         enet_list_clear (& channel -> incomingReliableCommands);
  166.         enet_list_clear (& channel -> incomingUnreliableCommands);
  167.     }
  168.         
  169.     command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
  170.     command.header.channelID = 0xFF;
  171.     command.connect.outgoingPeerID = ENET_HOST_TO_NET_16 (currentPeer -> incomingPeerID);
  172.     command.connect.mtu = ENET_HOST_TO_NET_16 (currentPeer -> mtu);
  173.     command.connect.windowSize = ENET_HOST_TO_NET_32 (currentPeer -> windowSize);
  174.     command.connect.channelCount = ENET_HOST_TO_NET_32 (channelCount);
  175.     command.connect.incomingBandwidth = ENET_HOST_TO_NET_32 (host -> incomingBandwidth);
  176.     command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
  177.     command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleInterval);
  178.     command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleAcceleration);
  179.     command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (currentPeer -> packetThrottleDeceleration);
  180.     command.connect.sessionID = currentPeer -> sessionID;
  181.     
  182.     enet_peer_queue_outgoing_command (currentPeer, & command, NULL, 0, 0);
  183.  
  184.     return currentPeer;
  185. }
  186.  
  187. /** Queues a packet to be sent to all peers associated with the host.
  188.     @param host host on which to broadcast the packet
  189.     @param channelID channel on which to broadcast
  190.     @param packet packet to broadcast
  191. */
  192. void
  193. enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet)
  194. {
  195.     ENetPeer * currentPeer;
  196.  
  197.     for (currentPeer = host -> peers;
  198.          currentPeer < & host -> peers [host -> peerCount];
  199.          ++ currentPeer)
  200.     {
  201.        if (currentPeer -> state != ENET_PEER_STATE_CONNECTED)
  202.          continue;
  203.  
  204.        enet_peer_send (currentPeer, channelID, packet);
  205.     }
  206.  
  207.     if (packet -> referenceCount == 0)
  208.       enet_packet_destroy (packet);
  209. }
  210.  
  211. /** Adjusts the bandwidth limits of a host.
  212.     @param host host to adjust
  213.     @param incomingBandwidth new incoming bandwidth
  214.     @param outgoingBandwidth new outgoing bandwidth
  215.     @remarks the incoming and outgoing bandwidth parameters are identical in function to those
  216.     specified in enet_host_create().
  217. */
  218. void
  219. enet_host_bandwidth_limit (ENetHost * host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
  220. {
  221.     host -> incomingBandwidth = incomingBandwidth;
  222.     host -> outgoingBandwidth = outgoingBandwidth;
  223.     host -> recalculateBandwidthLimits = 1;
  224. }
  225.  
  226. void
  227. enet_host_bandwidth_throttle (ENetHost * host)
  228. {
  229.     enet_uint32 timeCurrent = enet_time_get (),
  230.            elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch,
  231.            peersTotal = 0,
  232.            dataTotal = 0,
  233.            peersRemaining,
  234.            bandwidth,
  235.            throttle = 0,
  236.            bandwidthLimit = 0;
  237.     int needsAdjustment;
  238.     ENetPeer * peer;
  239.     ENetProtocol command;
  240.  
  241.     if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL)
  242.       return;
  243.  
  244.     for (peer = host -> peers;
  245.          peer < & host -> peers [host -> peerCount];
  246.          ++ peer)
  247.     {
  248.         if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
  249.           continue;
  250.  
  251.         ++ peersTotal;
  252.         dataTotal += peer -> outgoingDataTotal;
  253.     }
  254.  
  255.     if (peersTotal == 0)
  256.       return;
  257.  
  258.     peersRemaining = peersTotal;
  259.     needsAdjustment = 1;
  260.  
  261.     if (host -> outgoingBandwidth == 0)
  262.       bandwidth = ~0;
  263.     else
  264.       bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000;
  265.  
  266.     while (peersRemaining > 0 && needsAdjustment != 0)
  267.     {
  268.         needsAdjustment = 0;
  269.         
  270.         if (dataTotal < bandwidth)
  271.           throttle = ENET_PEER_PACKET_THROTTLE_SCALE;
  272.         else
  273.           throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal;
  274.  
  275.         for (peer = host -> peers;
  276.              peer < & host -> peers [host -> peerCount];
  277.              ++ peer)
  278.         {
  279.             enet_uint32 peerBandwidth;
  280.             
  281.             if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
  282.                 peer -> incomingBandwidth == 0 ||
  283.                 peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
  284.               continue;
  285.  
  286.             peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000;
  287.             if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth)
  288.               continue;
  289.  
  290.             peer -> packetThrottleLimit = (peerBandwidth * 
  291.                                             ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal;
  292.             
  293.             if (peer -> packetThrottleLimit == 0)
  294.               peer -> packetThrottleLimit = 1;
  295.             
  296.             if (peer -> packetThrottle > peer -> packetThrottleLimit)
  297.               peer -> packetThrottle = peer -> packetThrottleLimit;
  298.  
  299.             peer -> outgoingBandwidthThrottleEpoch = timeCurrent;
  300.  
  301.             
  302.             needsAdjustment = 1;
  303.             -- peersRemaining;
  304.             bandwidth -= peerBandwidth;
  305.             dataTotal -= peerBandwidth;
  306.         }
  307.     }
  308.  
  309.     if (peersRemaining > 0)
  310.     for (peer = host -> peers;
  311.          peer < & host -> peers [host -> peerCount];
  312.          ++ peer)
  313.     {
  314.         if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
  315.             peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
  316.           continue;
  317.  
  318.         peer -> packetThrottleLimit = throttle;
  319.  
  320.         if (peer -> packetThrottle > peer -> packetThrottleLimit)
  321.           peer -> packetThrottle = peer -> packetThrottleLimit;
  322.     }
  323.     
  324.     if (host -> recalculateBandwidthLimits)
  325.     {
  326.        host -> recalculateBandwidthLimits = 0;
  327.  
  328.        peersRemaining = peersTotal;
  329.        bandwidth = host -> incomingBandwidth;
  330.        needsAdjustment = 1;
  331.  
  332.        if (bandwidth == 0)
  333.          bandwidthLimit = 0;
  334.        else
  335.        while (peersRemaining > 0 && needsAdjustment != 0)
  336.        {
  337.            needsAdjustment = 0;
  338.            bandwidthLimit = bandwidth / peersRemaining;
  339.  
  340.            for (peer = host -> peers;
  341.                 peer < & host -> peers [host -> peerCount];
  342.                 ++ peer)
  343.            {
  344.                if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
  345.                    peer -> incomingBandwidthThrottleEpoch == timeCurrent)
  346.                  continue;
  347.  
  348.                if (peer -> outgoingBandwidth > 0 &&
  349.                    peer -> outgoingBandwidth >= bandwidthLimit)
  350.                  continue;
  351.  
  352.                peer -> incomingBandwidthThrottleEpoch = timeCurrent;
  353.  
  354.                needsAdjustment = 1;
  355.                -- peersRemaining;
  356.                bandwidth -= peer -> outgoingBandwidth;
  357.            }
  358.        }
  359.  
  360.        for (peer = host -> peers;
  361.             peer < & host -> peers [host -> peerCount];
  362.             ++ peer)
  363.        {
  364.            if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
  365.              continue;
  366.  
  367.            command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
  368.            command.header.channelID = 0xFF;
  369.            command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
  370.  
  371.            if (peer -> incomingBandwidthThrottleEpoch == timeCurrent)
  372.              command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth);
  373.            else
  374.              command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit);
  375.  
  376.            enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
  377.        } 
  378.     }
  379.  
  380.     host -> bandwidthThrottleEpoch = timeCurrent;
  381.  
  382.     for (peer = host -> peers;
  383.          peer < & host -> peers [host -> peerCount];
  384.          ++ peer)
  385.     {
  386.         peer -> incomingDataTotal = 0;
  387.         peer -> outgoingDataTotal = 0;
  388.     }
  389. }
  390.     
  391. /** @} */
  392.