diff --git a/enet/host.c b/enet/host.c index 8ff072cf..a398af99 100644 --- a/enet/host.c +++ b/enet/host.c @@ -158,6 +158,8 @@ enet_host_destroy (ENetHost * host) if (host -> compressor.context != NULL && host -> compressor.destroy) (* host -> compressor.destroy) (host -> compressor.context); + enet_free (host -> connectsData); + enet_free (host -> idlePeersList); enet_free (host -> peers); enet_free (host); } @@ -489,5 +491,51 @@ enet_host_bandwidth_throttle (ENetHost * host) } } } - + +int +enet_host_connect_cookies(ENetHost * host, const ENetRandom * randomFunction, enet_uint32 connectingPeerTimeout) +{ + size_t iPeer; + if (host -> randomFunction.context && host -> randomFunction.destroy) + host -> randomFunction.destroy (host -> randomFunction.context); + memset (& host -> randomFunction, 0, sizeof (ENetRandom)); + host -> connectingPeerTimeout = 0; + enet_free (host -> idlePeersList); + host -> idlePeersList = NULL; + host -> idlePeers = 0; + enet_free (host -> connectsData); + host -> connectsData = NULL; + host -> connectsInWindow = 0; + host -> connectsDataIndex = 0; + host -> connectsDataIndexTimestamp = 0; + host -> connectsWindow = 0; + for (iPeer = 0; iPeer < host -> peerCount; ++ iPeer) + { + enet_free (host -> peers [iPeer].connectingPeers); + host -> peers [iPeer].connectingPeers = NULL; + } + + if (! randomFunction) + return 0; + host -> randomFunction = * randomFunction; + host -> connectingPeerTimeout = connectingPeerTimeout ? ((connectingPeerTimeout - 1) / ENET_HOST_CONNECTS_TIME_DELTA + 1) * ENET_HOST_CONNECTS_TIME_DELTA : ENET_HOST_DEFAULT_CONNECTING_PEER_TIMEOUT; + host -> idlePeersList = enet_malloc (sizeof (enet_uint16) * host -> peerCount); + host -> connectsData = enet_malloc (sizeof (enet_uint32) * (host -> connectingPeerTimeout / ENET_HOST_CONNECTS_TIME_DELTA + 1)); + if (! host -> idlePeersList || ! host -> connectsData) + { + host -> connectingPeerTimeout = 0; + memset (& host -> randomFunction, 0, sizeof (ENetRandom)); + enet_free (host -> idlePeersList); + host -> idlePeersList = NULL; + enet_free (host -> connectsData); + host -> connectsData = NULL; + return -1; + } + for (iPeer = 0; iPeer < host -> peerCount; ++ iPeer) + if (host -> peers [iPeer].state == ENET_PEER_STATE_DISCONNECTED) + host -> idlePeersList [host -> idlePeers ++] = host -> peers [iPeer].incomingPeerID; + memset (host -> connectsData, 0, sizeof (enet_uint32) * (host -> connectingPeerTimeout / ENET_HOST_CONNECTS_TIME_DELTA + 1)); + return 0; +} + /** @} */ diff --git a/enet/include/enet/enet.h b/enet/include/enet/enet.h index f3ed811d..ee67ea7c 100644 --- a/enet/include/enet/enet.h +++ b/enet/include/enet/enet.h @@ -212,6 +212,9 @@ enum ENET_HOST_DEFAULT_MTU = 1400, ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE = 32 * 1024 * 1024, ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA = 32 * 1024 * 1024, + ENET_HOST_DEFAULT_CONNECTING_PEER_TIMEOUT = 2000, + ENET_HOST_CONNECTS_TIME_DELTA = 100, + ENET_HOST_CONNECTS_CLEANUP_SIZE = 1024 * 1024, ENET_PEER_DEFAULT_ROUND_TRIP_TIME = 500, ENET_PEER_DEFAULT_PACKET_THROTTLE = 32, @@ -232,7 +235,8 @@ enum ENET_PEER_FREE_UNSEQUENCED_WINDOWS = 32, ENET_PEER_RELIABLE_WINDOWS = 16, ENET_PEER_RELIABLE_WINDOW_SIZE = 0x1000, - ENET_PEER_FREE_RELIABLE_WINDOWS = 8 + ENET_PEER_FREE_RELIABLE_WINDOWS = 8, + ENET_PEER_MINIMUM_TIME_SENT_MASK = 3 }; typedef struct _ENetChannel @@ -247,6 +251,26 @@ typedef struct _ENetChannel ENetList incomingUnreliableCommands; } ENetChannel; +typedef struct _ENetConnectingPeer +{ + ENetAddress address; + ENetAddress localAddress; + enet_uint32 realTimeSent; + enet_uint32 connectID; + enet_uint32 incomingBandwidth; + enet_uint32 outgoingBandwidth; + enet_uint32 packetThrottleAcceleration; + enet_uint32 packetThrottleDeceleration; + enet_uint32 packetThrottleInterval; + enet_uint32 eventData; + enet_uint32 mtu; + enet_uint16 windowSize; + enet_uint16 randomTimeSent; + enet_uint16 outgoingPeerID; + enet_uint8 channelCount; + enet_uint8 outgoingSessionID; +} ENetConnectingPeer; + /** * An ENet peer which data packets may be sent or received from. * @@ -256,6 +280,8 @@ typedef struct _ENetPeer { ENetListNode dispatchList; struct _ENetHost * host; + ENetConnectingPeer (* connectingPeers) [ENET_PROTOCOL_TOTAL_SESSIONS]; + enet_uint32 connectingPeersTimeMask; enet_uint16 outgoingPeerID; enet_uint16 incomingPeerID; enet_uint32 connectID; @@ -337,6 +363,13 @@ typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * b /** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */ typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, struct _ENetEvent * event); +typedef struct _ENetRandom +{ + void * context; + enet_uint32 (ENET_CALLBACK * generate) (void * context); + void (ENET_CALLBACK * destroy) (void * context); +} ENetRandom; + /** An ENet host for communicating with peers. * * No fields should be modified unless otherwise stated. @@ -365,6 +398,15 @@ typedef struct _ENetHost int recalculateBandwidthLimits; ENetPeer * peers; /**< array of peers allocated for this host */ size_t peerCount; /**< number of peers allocated for this host */ + enet_uint32 connectingPeerTimeout; + enet_uint32 connectsWindow; + enet_uint32 * connectsData; + size_t connectsDataIndex; + enet_uint32 connectsDataIndexTimestamp; + enet_uint32 connectsInWindow; + enet_uint16 * idlePeersList; + size_t idlePeers; + ENetRandom randomFunction; size_t channelLimit; /**< maximum number of channels allowed for connected peers */ enet_uint32 serviceTime; ENetList dispatchQueue; @@ -558,6 +600,7 @@ ENET_API void enet_host_compress (ENetHost *, const ENetCompressor *); ENET_API int enet_host_compress_with_range_coder (ENetHost * host); ENET_API void enet_host_channel_limit (ENetHost *, size_t); ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32); +ENET_API int enet_host_connect_cookies(ENetHost *, const ENetRandom *, enet_uint32); extern void enet_host_bandwidth_throttle (ENetHost *); extern enet_uint32 enet_host_random_seed (void); diff --git a/enet/include/enet/protocol.h b/enet/include/enet/protocol.h index f8c73d8a..1c52daa6 100644 --- a/enet/include/enet/protocol.h +++ b/enet/include/enet/protocol.h @@ -50,7 +50,8 @@ typedef enum _ENetProtocolFlag ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), - ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 + ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12, + ENET_PROTOCOL_TOTAL_SESSIONS = (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT) + 1 } ENetProtocolFlag; #ifdef _MSC_VER diff --git a/enet/peer.c b/enet/peer.c index 24a70849..57de8324 100644 --- a/enet/peer.c +++ b/enet/peer.c @@ -371,6 +371,22 @@ enet_peer_on_disconnect (ENetPeer * peer) void enet_peer_reset (ENetPeer * peer) { + if (peer -> host -> connectingPeerTimeout) + { + size_t i; + ENetHost * host = peer -> host; + if (peer -> connectingPeers) + { + enet_free(peer -> connectingPeers); + peer -> connectingPeers = NULL; + peer -> host -> connectsWindow -= ENET_PROTOCOL_TOTAL_SESSIONS * (peer -> connectingPeersTimeMask + 1); + } + for (i = 0; i < host -> idlePeers; ++ i) + if (host -> idlePeersList [i] == peer -> incomingPeerID) + break; + if (i == host -> idlePeers) + host -> idlePeersList [host -> idlePeers ++] = peer -> incomingPeerID; + } enet_peer_on_disconnect (peer); peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID; diff --git a/enet/protocol.c b/enet/protocol.c index 0f913fdc..40143485 100644 --- a/enet/protocol.c +++ b/enet/protocol.c @@ -274,12 +274,17 @@ enet_protocol_remove_sent_reliable_command (ENetPeer * peer, enet_uint16 reliabl static ENetPeer * enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENetProtocol * command, ENetAddress * localAddress) { - enet_uint8 incomingSessionID, outgoingSessionID; + enet_uint8 incomingSessionID, outgoingSessionID = 0; enet_uint32 mtu, windowSize; ENetChannel * channel; size_t channelCount, duplicatePeers = 0; - ENetPeer * currentPeer, * peer = NULL; + ENetPeer * currentPeer, * peer = NULL, * realPeer = NULL, dummyPeer; ENetProtocol verifyCommand; + enet_uint16 randomTimeSent = 0; + ENetConnectingPeer * cookie = NULL; + ENetProtocolHeader responseHeader; + enet_uint32 checksum; + ENetBuffer buffers[3]; channelCount = ENET_NET_TO_HOST_32 (command -> connect.channelCount); @@ -287,25 +292,68 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) return NULL; - for (currentPeer = host -> peers; - currentPeer < & host -> peers [host -> peerCount]; - ++ currentPeer) + if (! host -> connectingPeerTimeout) { - if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) + for (currentPeer = host -> peers; + currentPeer < & host -> peers [host -> peerCount]; + ++ currentPeer) { - if (peer == NULL) - peer = currentPeer; + if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED) + { + if (peer == NULL) + peer = currentPeer; + } + else + if (currentPeer -> state != ENET_PEER_STATE_CONNECTING && + currentPeer -> address.host == host -> receivedAddress.host) + { + if (currentPeer -> address.port == host -> receivedAddress.port && + currentPeer -> connectID == command -> connect.connectID) + return NULL; + + ++ duplicatePeers; + } } - else - if (currentPeer -> state != ENET_PEER_STATE_CONNECTING && - currentPeer -> address.host == host -> receivedAddress.host) + } + else + { + if (! host -> idlePeers) return NULL; + enet_uint32 random = host -> randomFunction.generate (host -> randomFunction.context), randomTry = random; + retry: + outgoingSessionID = randomTry % ENET_PROTOCOL_TOTAL_SESSIONS; + randomTry /= ENET_PROTOCOL_TOTAL_SESSIONS; + randomTimeSent = randomTry; + randomTry >>= 16; + realPeer = & host -> peers [host -> idlePeersList [randomTry % host -> idlePeers]]; + if (realPeer -> connectingPeers) + { + cookie = & realPeer -> connectingPeers [randomTimeSent & realPeer -> connectingPeersTimeMask] [outgoingSessionID]; + if (cookie -> address.host) { - if (currentPeer -> address.port == host -> receivedAddress.port && - currentPeer -> connectID == command -> connect.connectID) + if (host -> serviceTime - cookie -> realTimeSent > host -> connectingPeerTimeout) + cookie -> address.host = 0; + else + { + if ((host -> connectsInWindow * 100) / host -> connectsWindow < 80) + { + randomTry = ++ random; + goto retry; + } + if (realPeer -> connectingPeersTimeMask == (enet_uint16)-1) return NULL; - - ++ duplicatePeers; + else + { + enet_uint16 extraBit; + extraBit = realPeer -> connectingPeersTimeMask + 1; + randomTimeSent = (randomTimeSent & ~extraBit) | (~(cookie -> randomTimeSent) & extraBit); + cookie = NULL; + } + } } + } + peer = & dummyPeer; + peer -> outgoingSessionID = realPeer -> outgoingSessionID; + peer -> incomingPeerID = realPeer -> incomingPeerID; } if (peer == NULL || duplicatePeers >= host -> duplicatePeers) @@ -313,9 +361,12 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet if (channelCount > host -> channelLimit) channelCount = host -> channelLimit; - peer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); - if (peer -> channels == NULL) - return NULL; + if (! host -> connectingPeerTimeout) + { + peer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel)); + if (peer -> channels == NULL) + return NULL; + } peer -> channelCount = channelCount; peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT; peer -> connectID = command -> connect.connectID; @@ -335,16 +386,21 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet incomingSessionID = (incomingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); peer -> outgoingSessionID = incomingSessionID; - outgoingSessionID = command -> connect.outgoingSessionID == 0xFF ? peer -> incomingSessionID : command -> connect.outgoingSessionID; - outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); - if (outgoingSessionID == peer -> incomingSessionID) + if (! host -> connectingPeerTimeout) + { + outgoingSessionID = command -> connect.outgoingSessionID == 0xFF ? peer -> incomingSessionID : command -> connect.outgoingSessionID; outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + if (outgoingSessionID == peer -> incomingSessionID) + outgoingSessionID = (outgoingSessionID + 1) & (ENET_PROTOCOL_HEADER_SESSION_MASK >> ENET_PROTOCOL_HEADER_SESSION_SHIFT); + } peer -> incomingSessionID = outgoingSessionID; - for (channel = peer -> channels; - channel < & peer -> channels [channelCount]; - ++ channel) + if (! host -> connectingPeerTimeout) { + for (channel = peer -> channels; + channel < & peer -> channels [channelCount]; + ++ channel) + { channel -> outgoingReliableSequenceNumber = 0; channel -> outgoingUnreliableSequenceNumber = 0; channel -> incomingReliableSequenceNumber = 0; @@ -355,6 +411,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet channel -> usedReliableWindows = 0; memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); + } } mtu = ENET_NET_TO_HOST_32 (command -> connect.mtu); @@ -417,9 +474,90 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet verifyCommand.verifyConnect.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (peer -> packetThrottleDeceleration); verifyCommand.verifyConnect.connectID = peer -> connectID; - enet_peer_queue_outgoing_command (peer, & verifyCommand, NULL, 0, 0); + if (! host -> connectingPeerTimeout) + { + enet_peer_queue_outgoing_command (peer, & verifyCommand, NULL, 0, 0); + + return peer; + } + + responseHeader.peerID = ENET_HOST_TO_NET_16(peer -> outgoingPeerID | (peer -> outgoingSessionID << ENET_PROTOCOL_HEADER_SESSION_SHIFT) | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME); + responseHeader.sentTime = randomTimeSent; + verifyCommand.verifyConnect.header.reliableSequenceNumber = ENET_HOST_TO_NET_16(1); + buffers[0].data = & responseHeader; + buffers[0].dataLength = sizeof (responseHeader); + if (host -> checksum != NULL) + { + buffers[1].data = & checksum; + buffers[1].dataLength = sizeof (enet_uint32); + buffers[2].data = & verifyCommand; + buffers[2].dataLength = commandSizes [ENET_PROTOCOL_COMMAND_VERIFY_CONNECT]; + checksum = peer -> connectID; + checksum = host -> checksum (buffers, 3); + } + else + { + buffers[1].data = & verifyCommand; + buffers[1].dataLength = commandSizes [ENET_PROTOCOL_COMMAND_VERIFY_CONNECT]; + } + if (enet_socket_send_local (host -> socket, & peer -> address, buffers, 2 + (host -> checksum != NULL), localAddress) < 0) + return NULL; + + host -> totalSentData += sizeof (responseHeader) + sizeof (enet_uint32) * (host -> checksum != NULL) + commandSizes [ENET_PROTOCOL_COMMAND_VERIFY_CONNECT]; + ++ host -> totalSentPackets; + if (! cookie) + { + if (! realPeer -> connectingPeers) + { + realPeer -> connectingPeers = enet_malloc (sizeof (ENetConnectingPeer) * ENET_PROTOCOL_TOTAL_SESSIONS * (ENET_PEER_MINIMUM_TIME_SENT_MASK + 1)); + memset (realPeer -> connectingPeers, 0, sizeof (ENetConnectingPeer) * ENET_PROTOCOL_TOTAL_SESSIONS * (ENET_PEER_MINIMUM_TIME_SENT_MASK + 1)); + if (! realPeer -> connectingPeers) + return NULL; + realPeer -> connectingPeersTimeMask = ENET_PEER_MINIMUM_TIME_SENT_MASK; + host -> connectsWindow += ENET_PROTOCOL_TOTAL_SESSIONS * (ENET_PEER_MINIMUM_TIME_SENT_MASK + 1); + } + else + { + size_t iCookie, iSession, oldLength = realPeer -> connectingPeersTimeMask + 1; + ENetConnectingPeer (* newConnectingPeers) [ENET_PROTOCOL_TOTAL_SESSIONS] = enet_malloc (sizeof (ENetConnectingPeer) * ENET_PROTOCOL_TOTAL_SESSIONS * (oldLength * 2)); + if (! newConnectingPeers) + return NULL; + memset (newConnectingPeers, 0, sizeof (ENetConnectingPeer) * ENET_PROTOCOL_TOTAL_SESSIONS * (oldLength * 2)); + realPeer -> connectingPeersTimeMask |= oldLength; + for (iCookie = 0; iCookie < oldLength; ++ iCookie) + for (iSession = 0; iSession < ENET_PROTOCOL_TOTAL_SESSIONS; ++ iSession) + { + ENetConnectingPeer * oldCookie = & realPeer -> connectingPeers [iCookie] [iSession]; + if (oldCookie -> address.host) + newConnectingPeers [oldCookie -> randomTimeSent & realPeer -> connectingPeersTimeMask] [iSession] = * oldCookie; + } + enet_free (realPeer -> connectingPeers); + realPeer -> connectingPeers = newConnectingPeers; + host -> connectsWindow += ENET_PROTOCOL_TOTAL_SESSIONS * oldLength; + } + cookie = & realPeer -> connectingPeers [randomTimeSent & realPeer -> connectingPeersTimeMask] [outgoingSessionID]; + } + + cookie -> address = peer -> address; + cookie -> localAddress.host = peer -> localAddress.host; + cookie -> randomTimeSent = randomTimeSent; + cookie -> realTimeSent = host -> serviceTime; + cookie -> channelCount = peer -> channelCount; + cookie -> connectID = peer -> connectID; + cookie -> outgoingPeerID = peer -> outgoingPeerID; + cookie -> incomingBandwidth = peer -> incomingBandwidth; + cookie -> outgoingBandwidth = peer -> outgoingBandwidth; + cookie -> packetThrottleInterval = peer -> packetThrottleInterval; + cookie -> packetThrottleAcceleration = peer -> packetThrottleAcceleration; + cookie -> packetThrottleDeceleration = peer -> packetThrottleDeceleration; + cookie -> eventData = peer -> eventData; + cookie -> outgoingSessionID = peer -> outgoingSessionID; + cookie -> mtu = peer -> mtu; + cookie -> windowSize = peer -> windowSize - 1; + ++ host -> connectsInWindow; + ++ host -> connectsData [host -> connectsDataIndex]; + return NULL; - return peer; } static int @@ -821,23 +959,105 @@ enet_protocol_handle_disconnect (ENetHost * host, ENetPeer * peer, const ENetPro } static int -enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command) +enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * peer, const ENetProtocol * command, enet_uint8 sessionID, const ENetAddress * localAddress) { enet_uint32 roundTripTime, receivedSentTime, receivedReliableSequenceNumber; ENetProtocolCommand commandNumber; + int cookieRestored = 0; - if (peer -> state == ENET_PEER_STATE_DISCONNECTED || peer -> state == ENET_PEER_STATE_ZOMBIE) + if (peer -> state == ENET_PEER_STATE_ZOMBIE) return 0; - receivedSentTime = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedSentTime); - receivedSentTime |= host -> serviceTime & 0xFFFF0000; - if ((receivedSentTime & 0x8000) > (host -> serviceTime & 0x8000)) - receivedSentTime -= 0x10000; + if (peer -> state == ENET_PEER_STATE_DISCONNECTED) + { + ENetConnectingPeer * cookie; + size_t iPeer, duplicatePeers = 0; + ENetChannel * channel; + if (! host -> connectingPeerTimeout || + ! peer -> connectingPeers || + command -> header.channelID != 0xFF || + command -> header.reliableSequenceNumber != 1 || + command -> acknowledge.receivedReliableSequenceNumber != ENET_HOST_TO_NET_16(1)) + return -1; + receivedSentTime = command -> acknowledge.receivedSentTime; + cookie = & peer -> connectingPeers [receivedSentTime & peer -> connectingPeersTimeMask] [sessionID]; + if (cookie -> randomTimeSent != receivedSentTime || + cookie -> address.host != host -> receivedAddress.host || + cookie -> address.port != host -> receivedAddress.port || + cookie -> localAddress.host != localAddress -> host) + return -1; + cookie -> address.host = 0; + if (host -> serviceTime - cookie -> realTimeSent > host -> connectingPeerTimeout) + return -1; + for (iPeer = 0; iPeer < host -> peerCount && duplicatePeers < host -> duplicatePeers; ++ iPeer) + if (host -> peers [iPeer].address.host == host -> receivedAddress.host) + ++ duplicatePeers; + if (duplicatePeers > host -> duplicatePeers) + return -1; + peer -> channels = (ENetChannel *) enet_malloc (cookie -> channelCount * sizeof (ENetChannel)); + if (peer -> channels == NULL) + return -1; + for (iPeer = 0; iPeer < host -> idlePeers; ++ iPeer) + if (host -> idlePeersList [iPeer] == peer -> incomingPeerID) + { + host -> idlePeersList [iPeer] = host -> idlePeersList [-- host -> idlePeers]; + break; + } + for (channel = peer -> channels; + channel < & peer -> channels [cookie -> channelCount]; + ++ channel) + { + channel -> outgoingReliableSequenceNumber = 0; + channel -> outgoingUnreliableSequenceNumber = 0; + channel -> incomingReliableSequenceNumber = 0; + channel -> incomingUnreliableSequenceNumber = 0; - if (ENET_TIME_LESS (host -> serviceTime, receivedSentTime)) - return 0; + enet_list_clear (& channel -> incomingReliableCommands); + enet_list_clear (& channel -> incomingUnreliableCommands); + + channel -> usedReliableWindows = 0; + memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows)); + } + peer -> state = ENET_PEER_STATE_ACKNOWLEDGING_CONNECT; + peer -> address = host -> receivedAddress; + peer -> localAddress.host = cookie -> localAddress.host; + peer -> incomingSessionID = sessionID; + peer -> channelCount = cookie -> channelCount; + peer -> connectID = cookie -> connectID; + peer -> outgoingPeerID = cookie -> outgoingPeerID; + peer -> incomingBandwidth = cookie -> incomingBandwidth; + peer -> outgoingBandwidth = cookie -> outgoingBandwidth; + peer -> packetThrottleInterval = cookie -> packetThrottleInterval; + peer -> packetThrottleAcceleration = cookie -> packetThrottleAcceleration; + peer -> packetThrottleDeceleration = cookie -> packetThrottleDeceleration; + peer -> eventData = cookie -> eventData; + peer -> outgoingSessionID = cookie -> outgoingSessionID; + peer -> mtu = cookie -> mtu; + peer -> windowSize = cookie -> windowSize + 1; + peer -> outgoingReliableSequenceNumber = 1; + peer -> packetsSent = 1; + peer -> outgoingDataTotal = sizeof (ENetProtocolHeader) + sizeof (enet_uint32) * (host -> checksum != 0) + sizeof (ENetProtocolConnect); + peer -> incomingDataTotal = host -> receivedDataLength; + peer -> lastSendTime = cookie -> realTimeSent; + receivedSentTime = cookie -> realTimeSent; + cookieRestored = 1; + commandNumber = ENET_PROTOCOL_COMMAND_VERIFY_CONNECT; + enet_free (peer -> connectingPeers); + peer -> connectingPeers = NULL; + host -> connectsWindow -= ENET_PROTOCOL_TOTAL_SESSIONS * (peer -> connectingPeersTimeMask + 1); + } + else + { + receivedSentTime = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedSentTime); + receivedSentTime |= host -> serviceTime & 0xFFFF0000; + if ((receivedSentTime & 0x8000) > (host -> serviceTime & 0x8000)) + receivedSentTime -= 0x10000; + + if (ENET_TIME_LESS (host -> serviceTime, receivedSentTime)) + return 0; + } peer -> lastReceiveTime = host -> serviceTime; peer -> earliestTimeout = 0; @@ -875,9 +1095,12 @@ enet_protocol_handle_acknowledge (ENetHost * host, ENetEvent * event, ENetPeer * peer -> packetThrottleEpoch = host -> serviceTime; } - receivedReliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedReliableSequenceNumber); + if (!cookieRestored) + { + receivedReliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> acknowledge.receivedReliableSequenceNumber); - commandNumber = enet_protocol_remove_sent_reliable_command (peer, receivedReliableSequenceNumber, command -> header.channelID); + commandNumber = enet_protocol_remove_sent_reliable_command (peer, receivedReliableSequenceNumber, command -> header.channelID); + } switch (peer -> state) { @@ -1005,8 +1228,12 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event, ENet { peer = & host -> peers [peerID]; - if (peer -> state == ENET_PEER_STATE_DISCONNECTED || - peer -> state == ENET_PEER_STATE_ZOMBIE || + if (peer -> state == ENET_PEER_STATE_DISCONNECTED) + { + if (! host -> connectingPeerTimeout || !peer -> connectingPeers) + return 0; + } + else if (peer -> state == ENET_PEER_STATE_ZOMBIE || ((host -> receivedAddress.host != peer -> address.host || host -> receivedAddress.port != peer -> address.port) && peer -> address.host != ENET_HOST_BROADCAST) || @@ -1036,7 +1263,7 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event, ENet host -> receivedDataLength = headerSize + originalSize; } - if (host -> checksum != NULL) + if (host -> checksum != NULL && !(host -> connectingPeerTimeout && peer -> state == ENET_PEER_STATE_DISCONNECTED)) { enet_uint32 * checksum = (enet_uint32 *) & host -> receivedData [headerSize - sizeof (enet_uint32)], desiredChecksum = * checksum; @@ -1051,7 +1278,7 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event, ENet return 0; } - if (peer != NULL) + if (peer != NULL && peer -> state != ENET_PEER_STATE_DISCONNECTED) { peer -> address.host = host -> receivedAddress.host; peer -> address.port = host -> receivedAddress.port; @@ -1088,17 +1315,15 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event, ENet switch (commandNumber) { case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE: - if (enet_protocol_handle_acknowledge (host, event, peer, command)) + if (enet_protocol_handle_acknowledge (host, event, peer, command, sessionID, localAddress)) goto commandError; break; case ENET_PROTOCOL_COMMAND_CONNECT: if (peer != NULL) goto commandError; - peer = enet_protocol_handle_connect (host, header, command, localAddress); - if (peer == NULL) - goto commandError; - break; + enet_protocol_handle_connect (host, header, command, localAddress); + return 0; case ENET_PROTOCOL_COMMAND_VERIFY_CONNECT: if (enet_protocol_handle_verify_connect (host, event, peer, command)) @@ -1814,6 +2039,30 @@ enet_host_service (ENetHost * host, ENetEvent * event, enet_uint32 timeout) } host -> serviceTime = enet_time_get (); + if (host -> connectingPeerTimeout) + { + while (host -> serviceTime - host -> connectsDataIndexTimestamp > ENET_HOST_CONNECTS_TIME_DELTA) + { + host -> connectsDataIndex = (host -> connectsDataIndex + 1) % (host -> connectingPeerTimeout / ENET_HOST_CONNECTS_TIME_DELTA + 1); + host -> connectsInWindow -= host -> connectsData [host -> connectsDataIndex]; + host -> connectsData [host -> connectsDataIndex] = 0; + host -> connectsDataIndexTimestamp += ENET_HOST_CONNECTS_TIME_DELTA; + } + if (! host -> connectsInWindow && host -> connectsWindow * sizeof (ENetConnectingPeer) > ENET_HOST_CONNECTS_CLEANUP_SIZE) + { + size_t iPeer; + for (iPeer = 0; iPeer < host -> idlePeers; ++ iPeer) + { + ENetPeer * peer = & host -> peers [host -> idlePeersList [iPeer]]; + if (peer -> connectingPeers) + { + enet_free (peer -> connectingPeers); + peer -> connectingPeers = NULL; + } + } + host -> connectsWindow = 0; + } + } timeout += host -> serviceTime;