1 /**
2  @file  peer.c
3  @brief ENet peer management functions
4 */
5 #include <string.h>
6 #define ENET_BUILDING_LIB 1
7 #include "enet/enet.h"
8 
9 /** @defgroup peer ENet peer functions
10     @{
11 */
12 
13 /** Configures throttle parameter for a peer.
14 
15     Unreliable packets are dropped by ENet in response to the varying conditions
16     of the Internet connection to the peer.  The throttle represents a probability
17     that an unreliable packet should not be dropped and thus sent by ENet to the peer.
18     The lowest mean round trip time from the sending of a reliable packet to the
19     receipt of its acknowledgement is measured over an amount of time specified by
20     the interval parameter in milliseconds.  If a measured round trip time happens to
21     be significantly less than the mean round trip time measured over the interval,
22     then the throttle probability is increased to allow more traffic by an amount
23     specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE
24     constant.  If a measured round trip time happens to be significantly greater than
25     the mean round trip time measured over the interval, then the throttle probability
26     is decreased to limit traffic by an amount specified in the deceleration parameter, which
27     is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant.  When the throttle has
28     a value of ENET_PEER_PACKET_THROTTLE_SCALE, no unreliable packets are dropped by
29     ENet, and so 100% of all unreliable packets will be sent.  When the throttle has a
30     value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable
31     packets will be sent.  Intermediate values for the throttle represent intermediate
32     probabilities between 0% and 100% of unreliable packets being sent.  The bandwidth
33     limits of the local and foreign hosts are taken into account to determine a
34     sensible limit for the throttle probability above which it should not raise even in
35     the best of conditions.
36 
37     @param peer peer to configure
38     @param interval interval, in milliseconds, over which to measure lowest mean RTT; the default value is ENET_PEER_PACKET_THROTTLE_INTERVAL.
39     @param acceleration rate at which to increase the throttle probability as mean RTT declines
40     @param deceleration rate at which to decrease the throttle probability as mean RTT increases
41 */
42 void
enet_peer_throttle_configure(ENetPeer * peer,enet_uint32 interval,enet_uint32 acceleration,enet_uint32 deceleration)43 enet_peer_throttle_configure (ENetPeer * peer, enet_uint32 interval, enet_uint32 acceleration, enet_uint32 deceleration)
44 {
45     ENetProtocol command;
46 
47     peer -> packetThrottleInterval = interval;
48     peer -> packetThrottleAcceleration = acceleration;
49     peer -> packetThrottleDeceleration = deceleration;
50 
51     command.header.command = ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
52     command.header.channelID = 0xFF;
53 
54     command.throttleConfigure.packetThrottleInterval = ENET_HOST_TO_NET_32 (interval);
55     command.throttleConfigure.packetThrottleAcceleration = ENET_HOST_TO_NET_32 (acceleration);
56     command.throttleConfigure.packetThrottleDeceleration = ENET_HOST_TO_NET_32 (deceleration);
57 
58     enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
59 }
60 
61 int
enet_peer_throttle(ENetPeer * peer,enet_uint32 rtt)62 enet_peer_throttle (ENetPeer * peer, enet_uint32 rtt)
63 {
64     if (peer -> lastRoundTripTime <= peer -> lastRoundTripTimeVariance)
65     {
66         peer -> packetThrottle = peer -> packetThrottleLimit;
67     }
68     else
69     if (rtt < peer -> lastRoundTripTime)
70     {
71         peer -> packetThrottle += peer -> packetThrottleAcceleration;
72 
73         if (peer -> packetThrottle > peer -> packetThrottleLimit)
74           peer -> packetThrottle = peer -> packetThrottleLimit;
75 
76         return 1;
77     }
78     else
79     if (rtt > peer -> lastRoundTripTime + 2 * peer -> lastRoundTripTimeVariance)
80     {
81         if (peer -> packetThrottle > peer -> packetThrottleDeceleration)
82           peer -> packetThrottle -= peer -> packetThrottleDeceleration;
83         else
84           peer -> packetThrottle = 0;
85 
86         return -1;
87     }
88 
89     return 0;
90 }
91 
92 /** Queues a packet to be sent.
93     @param peer destination for the packet
94     @param channelID channel on which to send
95     @param packet packet to send
96     @retval 0 on success
97     @retval < 0 on failure
98 */
99 int
enet_peer_send(ENetPeer * peer,enet_uint8 channelID,ENetPacket * packet)100 enet_peer_send (ENetPeer * peer, enet_uint8 channelID, ENetPacket * packet)
101 {
102    ENetChannel * channel = & peer -> channels [channelID];
103    ENetProtocol command;
104    size_t fragmentLength;
105 
106    if (peer -> state != ENET_PEER_STATE_CONNECTED ||
107        channelID >= peer -> channelCount ||
108        packet -> dataLength > peer -> host -> maximumPacketSize)
109      return -1;
110 
111    fragmentLength = peer -> mtu - sizeof (ENetProtocolHeader) - sizeof (ENetProtocolSendFragment);
112    if (peer -> host -> checksum != NULL)
113      fragmentLength -= sizeof(enet_uint32);
114 
115    if (packet -> dataLength > fragmentLength)
116    {
117       enet_uint32 fragmentCount = (packet -> dataLength + fragmentLength - 1) / fragmentLength,
118              fragmentNumber,
119              fragmentOffset;
120       enet_uint8 commandNumber;
121       enet_uint16 startSequenceNumber;
122       ENetList fragments;
123       ENetOutgoingCommand * fragment;
124 
125       if (fragmentCount > ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT)
126         return -1;
127 
128       if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT)) == ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT &&
129           channel -> outgoingUnreliableSequenceNumber < 0xFFFF)
130       {
131          commandNumber = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT;
132          startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingUnreliableSequenceNumber + 1);
133       }
134       else
135       {
136          commandNumber = ENET_PROTOCOL_COMMAND_SEND_FRAGMENT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
137          startSequenceNumber = ENET_HOST_TO_NET_16 (channel -> outgoingReliableSequenceNumber + 1);
138       }
139 
140       enet_list_clear (& fragments);
141 
142       for (fragmentNumber = 0,
143              fragmentOffset = 0;
144            fragmentOffset < packet -> dataLength;
145            ++ fragmentNumber,
146              fragmentOffset += fragmentLength)
147       {
148          if (packet -> dataLength - fragmentOffset < fragmentLength)
149            fragmentLength = packet -> dataLength - fragmentOffset;
150 
151          fragment = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand));
152          if (fragment == NULL)
153          {
154             while (! enet_list_empty (& fragments))
155             {
156                fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments));
157 
158                enet_free (fragment);
159             }
160 
161             return -1;
162          }
163 
164          fragment -> fragmentOffset = fragmentOffset;
165          fragment -> fragmentLength = fragmentLength;
166          fragment -> packet = packet;
167          fragment -> command.header.command = commandNumber;
168          fragment -> command.header.channelID = channelID;
169          fragment -> command.sendFragment.startSequenceNumber = startSequenceNumber;
170          fragment -> command.sendFragment.dataLength = ENET_HOST_TO_NET_16 (fragmentLength);
171          fragment -> command.sendFragment.fragmentCount = ENET_HOST_TO_NET_32 (fragmentCount);
172          fragment -> command.sendFragment.fragmentNumber = ENET_HOST_TO_NET_32 (fragmentNumber);
173          fragment -> command.sendFragment.totalLength = ENET_HOST_TO_NET_32 (packet -> dataLength);
174          fragment -> command.sendFragment.fragmentOffset = ENET_NET_TO_HOST_32 (fragmentOffset);
175 
176          enet_list_insert (enet_list_end (& fragments), fragment);
177       }
178 
179       packet -> referenceCount += fragmentNumber;
180 
181       while (! enet_list_empty (& fragments))
182       {
183          fragment = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (& fragments));
184 
185          enet_peer_setup_outgoing_command (peer, fragment);
186       }
187 
188       return 0;
189    }
190 
191    command.header.channelID = channelID;
192 
193    if ((packet -> flags & (ENET_PACKET_FLAG_RELIABLE | ENET_PACKET_FLAG_UNSEQUENCED)) == ENET_PACKET_FLAG_UNSEQUENCED)
194    {
195       command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED;
196       command.sendUnsequenced.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
197    }
198    else
199    if (packet -> flags & ENET_PACKET_FLAG_RELIABLE || channel -> outgoingUnreliableSequenceNumber >= 0xFFFF)
200    {
201       command.header.command = ENET_PROTOCOL_COMMAND_SEND_RELIABLE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
202       command.sendReliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
203    }
204    else
205    {
206       command.header.command = ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE;
207       command.sendUnreliable.dataLength = ENET_HOST_TO_NET_16 (packet -> dataLength);
208    }
209 
210    if (enet_peer_queue_outgoing_command (peer, & command, packet, 0, packet -> dataLength) == NULL)
211      return -1;
212 
213    return 0;
214 }
215 
216 /** Attempts to dequeue any incoming queued packet.
217     @param peer peer to dequeue packets from
218     @param channelID holds the channel ID of the channel the packet was received on success
219     @returns a pointer to the packet, or NULL if there are no available incoming queued packets
220 */
221 ENetPacket *
enet_peer_receive(ENetPeer * peer,enet_uint8 * channelID)222 enet_peer_receive (ENetPeer * peer, enet_uint8 * channelID)
223 {
224    ENetIncomingCommand * incomingCommand;
225    ENetPacket * packet;
226 
227    if (enet_list_empty (& peer -> dispatchedCommands))
228      return NULL;
229 
230    incomingCommand = (ENetIncomingCommand *) enet_list_remove (enet_list_begin (& peer -> dispatchedCommands));
231 
232    if (channelID != NULL)
233      * channelID = incomingCommand -> command.header.channelID;
234 
235    packet = incomingCommand -> packet;
236 
237    -- packet -> referenceCount;
238 
239    if (incomingCommand -> fragments != NULL)
240      enet_free (incomingCommand -> fragments);
241 
242    enet_free (incomingCommand);
243 
244    peer -> totalWaitingData -= packet -> dataLength;
245 
246    return packet;
247 }
248 
249 static void
enet_peer_reset_outgoing_commands(ENetList * queue)250 enet_peer_reset_outgoing_commands (ENetList * queue)
251 {
252     ENetOutgoingCommand * outgoingCommand;
253 
254     while (! enet_list_empty (queue))
255     {
256        outgoingCommand = (ENetOutgoingCommand *) enet_list_remove (enet_list_begin (queue));
257 
258        if (outgoingCommand -> packet != NULL)
259        {
260           -- outgoingCommand -> packet -> referenceCount;
261 
262           if (outgoingCommand -> packet -> referenceCount == 0)
263             enet_packet_destroy (outgoingCommand -> packet);
264        }
265 
266        enet_free (outgoingCommand);
267     }
268 }
269 
270 static void
enet_peer_remove_incoming_commands(ENetList * queue,ENetListIterator startCommand,ENetListIterator endCommand)271 enet_peer_remove_incoming_commands (ENetList * queue, ENetListIterator startCommand, ENetListIterator endCommand)
272 {
273     ENetListIterator currentCommand;
274 
275     for (currentCommand = startCommand; currentCommand != endCommand; )
276     {
277        ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand;
278 
279        currentCommand = enet_list_next (currentCommand);
280 
281        enet_list_remove (& incomingCommand -> incomingCommandList);
282 
283        if (incomingCommand -> packet != NULL)
284        {
285           -- incomingCommand -> packet -> referenceCount;
286 
287           if (incomingCommand -> packet -> referenceCount == 0)
288             enet_packet_destroy (incomingCommand -> packet);
289        }
290 
291        if (incomingCommand -> fragments != NULL)
292          enet_free (incomingCommand -> fragments);
293 
294        enet_free (incomingCommand);
295     }
296 }
297 
298 static void
enet_peer_reset_incoming_commands(ENetList * queue)299 enet_peer_reset_incoming_commands (ENetList * queue)
300 {
301     enet_peer_remove_incoming_commands(queue, enet_list_begin (queue), enet_list_end (queue));
302 }
303 
304 void
enet_peer_reset_queues(ENetPeer * peer)305 enet_peer_reset_queues (ENetPeer * peer)
306 {
307     ENetChannel * channel;
308 
309     if (peer -> needsDispatch)
310     {
311        enet_list_remove (& peer -> dispatchList);
312 
313        peer -> needsDispatch = 0;
314     }
315 
316     while (! enet_list_empty (& peer -> acknowledgements))
317       enet_free (enet_list_remove (enet_list_begin (& peer -> acknowledgements)));
318 
319     enet_peer_reset_outgoing_commands (& peer -> sentReliableCommands);
320     enet_peer_reset_outgoing_commands (& peer -> sentUnreliableCommands);
321     enet_peer_reset_outgoing_commands (& peer -> outgoingReliableCommands);
322     enet_peer_reset_outgoing_commands (& peer -> outgoingUnreliableCommands);
323     enet_peer_reset_incoming_commands (& peer -> dispatchedCommands);
324 
325     if (peer -> channels != NULL && peer -> channelCount > 0)
326     {
327         for (channel = peer -> channels;
328              channel < & peer -> channels [peer -> channelCount];
329              ++ channel)
330         {
331             enet_peer_reset_incoming_commands (& channel -> incomingReliableCommands);
332             enet_peer_reset_incoming_commands (& channel -> incomingUnreliableCommands);
333         }
334 
335         enet_free (peer -> channels);
336     }
337 
338     peer -> channels = NULL;
339     peer -> channelCount = 0;
340 }
341 
342 void
enet_peer_on_connect(ENetPeer * peer)343 enet_peer_on_connect (ENetPeer * peer)
344 {
345     if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
346     {
347         if (peer -> incomingBandwidth != 0)
348           ++ peer -> host -> bandwidthLimitedPeers;
349 
350         ++ peer -> host -> connectedPeers;
351     }
352 }
353 
354 void
enet_peer_on_disconnect(ENetPeer * peer)355 enet_peer_on_disconnect (ENetPeer * peer)
356 {
357     if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER)
358     {
359         if (peer -> incomingBandwidth != 0)
360           -- peer -> host -> bandwidthLimitedPeers;
361 
362         -- peer -> host -> connectedPeers;
363     }
364 }
365 
366 /** Forcefully disconnects a peer.
367     @param peer peer to forcefully disconnect
368     @remarks The foreign host represented by the peer is not notified of the disconnection and will timeout
369     on its connection to the local host.
370 */
371 void
enet_peer_reset(ENetPeer * peer)372 enet_peer_reset (ENetPeer * peer)
373 {
374     enet_peer_on_disconnect (peer);
375 
376     peer -> outgoingPeerID = ENET_PROTOCOL_MAXIMUM_PEER_ID;
377     peer -> connectID = 0;
378 
379     peer -> state = ENET_PEER_STATE_DISCONNECTED;
380 
381     peer -> incomingBandwidth = 0;
382     peer -> outgoingBandwidth = 0;
383     peer -> incomingBandwidthThrottleEpoch = 0;
384     peer -> outgoingBandwidthThrottleEpoch = 0;
385     peer -> incomingDataTotal = 0;
386     peer -> outgoingDataTotal = 0;
387     peer -> lastSendTime = 0;
388     peer -> lastReceiveTime = 0;
389     peer -> nextTimeout = 0;
390     peer -> earliestTimeout = 0;
391     peer -> packetLossEpoch = 0;
392     peer -> packetsSent = 0;
393     peer -> packetsLost = 0;
394     peer -> packetLoss = 0;
395     peer -> packetLossVariance = 0;
396     peer -> packetThrottle = ENET_PEER_DEFAULT_PACKET_THROTTLE;
397     peer -> packetThrottleLimit = ENET_PEER_PACKET_THROTTLE_SCALE;
398     peer -> packetThrottleCounter = 0;
399     peer -> packetThrottleEpoch = 0;
400     peer -> packetThrottleAcceleration = ENET_PEER_PACKET_THROTTLE_ACCELERATION;
401     peer -> packetThrottleDeceleration = ENET_PEER_PACKET_THROTTLE_DECELERATION;
402     peer -> packetThrottleInterval = ENET_PEER_PACKET_THROTTLE_INTERVAL;
403     peer -> pingInterval = ENET_PEER_PING_INTERVAL;
404     peer -> timeoutLimit = ENET_PEER_TIMEOUT_LIMIT;
405     peer -> timeoutMinimum = ENET_PEER_TIMEOUT_MINIMUM;
406     peer -> timeoutMaximum = ENET_PEER_TIMEOUT_MAXIMUM;
407     peer -> lastRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
408     peer -> lowestRoundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
409     peer -> lastRoundTripTimeVariance = 0;
410     peer -> highestRoundTripTimeVariance = 0;
411     peer -> roundTripTime = ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
412     peer -> roundTripTimeVariance = 0;
413     peer -> mtu = peer -> host -> mtu;
414     peer -> reliableDataInTransit = 0;
415     peer -> outgoingReliableSequenceNumber = 0;
416     peer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
417     peer -> incomingUnsequencedGroup = 0;
418     peer -> outgoingUnsequencedGroup = 0;
419     peer -> eventData = 0;
420     peer -> totalWaitingData = 0;
421 
422     memset (peer -> unsequencedWindow, 0, sizeof (peer -> unsequencedWindow));
423 
424     enet_peer_reset_queues (peer);
425 }
426 
427 /** Sends a ping request to a peer.
428     @param peer destination for the ping request
429     @remarks ping requests factor into the mean round trip time as designated by the
430     roundTripTime field in the ENetPeer structure.  ENet automatically pings all connected
431     peers at regular intervals, however, this function may be called to ensure more
432     frequent ping requests.
433 */
434 void
enet_peer_ping(ENetPeer * peer)435 enet_peer_ping (ENetPeer * peer)
436 {
437     ENetProtocol command;
438 
439     if (peer -> state != ENET_PEER_STATE_CONNECTED)
440       return;
441 
442     command.header.command = ENET_PROTOCOL_COMMAND_PING | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
443     command.header.channelID = 0xFF;
444 
445     enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
446 }
447 
448 /** Sets the interval at which pings will be sent to a peer.
449 
450     Pings are used both to monitor the liveness of the connection and also to dynamically
451     adjust the throttle during periods of low traffic so that the throttle has reasonable
452     responsiveness during traffic spikes.
453 
454     @param peer the peer to adjust
455     @param pingInterval the interval at which to send pings; defaults to ENET_PEER_PING_INTERVAL if 0
456 */
457 void
enet_peer_ping_interval(ENetPeer * peer,enet_uint32 pingInterval)458 enet_peer_ping_interval (ENetPeer * peer, enet_uint32 pingInterval)
459 {
460     peer -> pingInterval = pingInterval ? pingInterval : ENET_PEER_PING_INTERVAL;
461 }
462 
463 /** Sets the timeout parameters for a peer.
464 
465     The timeout parameter control how and when a peer will timeout from a failure to acknowledge
466     reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable
467     packet is not acknowledge within some multiple of the average RTT plus a variance tolerance,
468     the timeout will be doubled until it reaches a set limit. If the timeout is thus at this
469     limit and reliable packets have been sent but not acknowledged within a certain minimum time
470     period, the peer will be disconnected. Alternatively, if reliable packets have been sent
471     but not acknowledged for a certain maximum time period, the peer will be disconnected regardless
472     of the current timeout limit value.
473 
474     @param peer the peer to adjust
475     @param timeoutLimit the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0
476     @param timeoutMinimum the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0
477     @param timeoutMaximum the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0
478 */
479 
480 void
enet_peer_timeout(ENetPeer * peer,enet_uint32 timeoutLimit,enet_uint32 timeoutMinimum,enet_uint32 timeoutMaximum)481 enet_peer_timeout (ENetPeer * peer, enet_uint32 timeoutLimit, enet_uint32 timeoutMinimum, enet_uint32 timeoutMaximum)
482 {
483     peer -> timeoutLimit = timeoutLimit ? timeoutLimit : ENET_PEER_TIMEOUT_LIMIT;
484     peer -> timeoutMinimum = timeoutMinimum ? timeoutMinimum : ENET_PEER_TIMEOUT_MINIMUM;
485     peer -> timeoutMaximum = timeoutMaximum ? timeoutMaximum : ENET_PEER_TIMEOUT_MAXIMUM;
486 }
487 
488 /** Force an immediate disconnection from a peer.
489     @param peer peer to disconnect
490     @param data data describing the disconnection
491     @remarks No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not
492     guaranteed to receive the disconnect notification, and is reset immediately upon
493     return from this function.
494 */
495 void
enet_peer_disconnect_now(ENetPeer * peer,enet_uint32 data)496 enet_peer_disconnect_now (ENetPeer * peer, enet_uint32 data)
497 {
498     ENetProtocol command;
499 
500     if (peer -> state == ENET_PEER_STATE_DISCONNECTED)
501       return;
502 
503     if (peer -> state != ENET_PEER_STATE_ZOMBIE &&
504         peer -> state != ENET_PEER_STATE_DISCONNECTING)
505     {
506         enet_peer_reset_queues (peer);
507 
508         command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED;
509         command.header.channelID = 0xFF;
510         command.disconnect.data = ENET_HOST_TO_NET_32 (data);
511 
512         enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
513 
514         enet_host_flush (peer -> host);
515     }
516 
517     enet_peer_reset (peer);
518 }
519 
520 /** Request a disconnection from a peer.
521     @param peer peer to request a disconnection
522     @param data data describing the disconnection
523     @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service()
524     once the disconnection is complete.
525 */
526 void
enet_peer_disconnect(ENetPeer * peer,enet_uint32 data)527 enet_peer_disconnect (ENetPeer * peer, enet_uint32 data)
528 {
529     ENetProtocol command;
530 
531     if (peer -> state == ENET_PEER_STATE_DISCONNECTING ||
532         peer -> state == ENET_PEER_STATE_DISCONNECTED ||
533         peer -> state == ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT ||
534         peer -> state == ENET_PEER_STATE_ZOMBIE)
535       return;
536 
537     enet_peer_reset_queues (peer);
538 
539     command.header.command = ENET_PROTOCOL_COMMAND_DISCONNECT;
540     command.header.channelID = 0xFF;
541     command.disconnect.data = ENET_HOST_TO_NET_32 (data);
542 
543     if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER)
544       command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
545     else
546       command.header.command |= ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED;
547 
548     enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
549 
550     if (peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER)
551     {
552         enet_peer_on_disconnect (peer);
553 
554         peer -> state = ENET_PEER_STATE_DISCONNECTING;
555     }
556     else
557     {
558         enet_host_flush (peer -> host);
559         enet_peer_reset (peer);
560     }
561 }
562 
563 /** Request a disconnection from a peer, but only after all queued outgoing packets are sent.
564     @param peer peer to request a disconnection
565     @param data data describing the disconnection
566     @remarks An ENET_EVENT_DISCONNECT event will be generated by enet_host_service()
567     once the disconnection is complete.
568 */
569 void
enet_peer_disconnect_later(ENetPeer * peer,enet_uint32 data)570 enet_peer_disconnect_later (ENetPeer * peer, enet_uint32 data)
571 {
572     if ((peer -> state == ENET_PEER_STATE_CONNECTED || peer -> state == ENET_PEER_STATE_DISCONNECT_LATER) &&
573         ! (enet_list_empty (& peer -> outgoingReliableCommands) &&
574            enet_list_empty (& peer -> outgoingUnreliableCommands) &&
575            enet_list_empty (& peer -> sentReliableCommands)))
576     {
577         peer -> state = ENET_PEER_STATE_DISCONNECT_LATER;
578         peer -> eventData = data;
579     }
580     else
581       enet_peer_disconnect (peer, data);
582 }
583 
584 ENetAcknowledgement *
enet_peer_queue_acknowledgement(ENetPeer * peer,const ENetProtocol * command,enet_uint16 sentTime)585 enet_peer_queue_acknowledgement (ENetPeer * peer, const ENetProtocol * command, enet_uint16 sentTime)
586 {
587     ENetAcknowledgement * acknowledgement;
588 
589     if (command -> header.channelID < peer -> channelCount)
590     {
591         ENetChannel * channel = & peer -> channels [command -> header.channelID];
592         enet_uint16 reliableWindow = command -> header.reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE,
593                     currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
594 
595         if (command -> header.reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
596            reliableWindow += ENET_PEER_RELIABLE_WINDOWS;
597 
598         if (reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1 && reliableWindow <= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS)
599           return NULL;
600     }
601 
602     acknowledgement = (ENetAcknowledgement *) enet_malloc (sizeof (ENetAcknowledgement));
603     if (acknowledgement == NULL)
604       return NULL;
605 
606     peer -> outgoingDataTotal += sizeof (ENetProtocolAcknowledge);
607 
608     acknowledgement -> sentTime = sentTime;
609     acknowledgement -> command = * command;
610 
611     enet_list_insert (enet_list_end (& peer -> acknowledgements), acknowledgement);
612 
613     return acknowledgement;
614 }
615 
616 void
enet_peer_setup_outgoing_command(ENetPeer * peer,ENetOutgoingCommand * outgoingCommand)617 enet_peer_setup_outgoing_command (ENetPeer * peer, ENetOutgoingCommand * outgoingCommand)
618 {
619     ENetChannel * channel = & peer -> channels [outgoingCommand -> command.header.channelID];
620 
621     peer -> outgoingDataTotal += enet_protocol_command_size (outgoingCommand -> command.header.command) + outgoingCommand -> fragmentLength;
622 
623     if (outgoingCommand -> command.header.channelID == 0xFF)
624     {
625        ++ peer -> outgoingReliableSequenceNumber;
626 
627        outgoingCommand -> reliableSequenceNumber = peer -> outgoingReliableSequenceNumber;
628        outgoingCommand -> unreliableSequenceNumber = 0;
629     }
630     else
631     if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
632     {
633        ++ channel -> outgoingReliableSequenceNumber;
634        channel -> outgoingUnreliableSequenceNumber = 0;
635 
636        outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
637        outgoingCommand -> unreliableSequenceNumber = 0;
638     }
639     else
640     if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED)
641     {
642        ++ peer -> outgoingUnsequencedGroup;
643 
644        outgoingCommand -> reliableSequenceNumber = 0;
645        outgoingCommand -> unreliableSequenceNumber = 0;
646     }
647     else
648     {
649        if (outgoingCommand -> fragmentOffset == 0)
650          ++ channel -> outgoingUnreliableSequenceNumber;
651 
652        outgoingCommand -> reliableSequenceNumber = channel -> outgoingReliableSequenceNumber;
653        outgoingCommand -> unreliableSequenceNumber = channel -> outgoingUnreliableSequenceNumber;
654     }
655 
656     outgoingCommand -> sendAttempts = 0;
657     outgoingCommand -> sentTime = 0;
658     outgoingCommand -> roundTripTimeout = 0;
659     outgoingCommand -> roundTripTimeoutLimit = 0;
660     outgoingCommand -> command.header.reliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> reliableSequenceNumber);
661 
662     switch (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK)
663     {
664     case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:
665         outgoingCommand -> command.sendUnreliable.unreliableSequenceNumber = ENET_HOST_TO_NET_16 (outgoingCommand -> unreliableSequenceNumber);
666         break;
667 
668     case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
669         outgoingCommand -> command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16 (peer -> outgoingUnsequencedGroup);
670         break;
671 
672     default:
673         break;
674     }
675 
676     if (outgoingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)
677       enet_list_insert (enet_list_end (& peer -> outgoingReliableCommands), outgoingCommand);
678     else
679       enet_list_insert (enet_list_end (& peer -> outgoingUnreliableCommands), outgoingCommand);
680 }
681 
682 ENetOutgoingCommand *
enet_peer_queue_outgoing_command(ENetPeer * peer,const ENetProtocol * command,ENetPacket * packet,enet_uint32 offset,enet_uint16 length)683 enet_peer_queue_outgoing_command (ENetPeer * peer, const ENetProtocol * command, ENetPacket * packet, enet_uint32 offset, enet_uint16 length)
684 {
685     ENetOutgoingCommand * outgoingCommand = (ENetOutgoingCommand *) enet_malloc (sizeof (ENetOutgoingCommand));
686     if (outgoingCommand == NULL)
687       return NULL;
688 
689     outgoingCommand -> command = * command;
690     outgoingCommand -> fragmentOffset = offset;
691     outgoingCommand -> fragmentLength = length;
692     outgoingCommand -> packet = packet;
693     if (packet != NULL)
694       ++ packet -> referenceCount;
695 
696     enet_peer_setup_outgoing_command (peer, outgoingCommand);
697 
698     return outgoingCommand;
699 }
700 
701 void
enet_peer_dispatch_incoming_unreliable_commands(ENetPeer * peer,ENetChannel * channel)702 enet_peer_dispatch_incoming_unreliable_commands (ENetPeer * peer, ENetChannel * channel)
703 {
704     ENetListIterator droppedCommand, startCommand, currentCommand;
705 
706     for (droppedCommand = startCommand = currentCommand = enet_list_begin (& channel -> incomingUnreliableCommands);
707          currentCommand != enet_list_end (& channel -> incomingUnreliableCommands);
708          currentCommand = enet_list_next (currentCommand))
709     {
710        ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand;
711 
712        if ((incomingCommand -> command.header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED)
713          continue;
714 
715        if (incomingCommand -> reliableSequenceNumber == channel -> incomingReliableSequenceNumber)
716        {
717           if (incomingCommand -> fragmentsRemaining <= 0)
718           {
719              channel -> incomingUnreliableSequenceNumber = incomingCommand -> unreliableSequenceNumber;
720              continue;
721           }
722 
723           if (startCommand != currentCommand)
724           {
725              enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand));
726 
727              if (! peer -> needsDispatch)
728              {
729                 enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
730 
731                 peer -> needsDispatch = 1;
732              }
733 
734              droppedCommand = currentCommand;
735           }
736           else
737           if (droppedCommand != currentCommand)
738             droppedCommand = enet_list_previous (currentCommand);
739        }
740        else
741        {
742           enet_uint16 reliableWindow = incomingCommand -> reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE,
743                       currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
744           if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
745             reliableWindow += ENET_PEER_RELIABLE_WINDOWS;
746           if (reliableWindow >= currentWindow && reliableWindow < currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1)
747             break;
748 
749           droppedCommand = enet_list_next (currentCommand);
750 
751           if (startCommand != currentCommand)
752           {
753              enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand));
754 
755              if (! peer -> needsDispatch)
756              {
757                 enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
758 
759                 peer -> needsDispatch = 1;
760              }
761           }
762        }
763 
764        startCommand = enet_list_next (currentCommand);
765     }
766 
767     if (startCommand != currentCommand)
768     {
769        enet_list_move (enet_list_end (& peer -> dispatchedCommands), startCommand, enet_list_previous (currentCommand));
770 
771        if (! peer -> needsDispatch)
772        {
773            enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
774 
775            peer -> needsDispatch = 1;
776        }
777 
778        droppedCommand = currentCommand;
779     }
780 
781     enet_peer_remove_incoming_commands (& channel -> incomingUnreliableCommands, enet_list_begin (& channel -> incomingUnreliableCommands), droppedCommand);
782 }
783 
784 void
enet_peer_dispatch_incoming_reliable_commands(ENetPeer * peer,ENetChannel * channel)785 enet_peer_dispatch_incoming_reliable_commands (ENetPeer * peer, ENetChannel * channel)
786 {
787     ENetListIterator currentCommand;
788 
789     for (currentCommand = enet_list_begin (& channel -> incomingReliableCommands);
790          currentCommand != enet_list_end (& channel -> incomingReliableCommands);
791          currentCommand = enet_list_next (currentCommand))
792     {
793        ENetIncomingCommand * incomingCommand = (ENetIncomingCommand *) currentCommand;
794 
795        if (incomingCommand -> fragmentsRemaining > 0 ||
796            incomingCommand -> reliableSequenceNumber != (enet_uint16) (channel -> incomingReliableSequenceNumber + 1))
797          break;
798 
799        channel -> incomingReliableSequenceNumber = incomingCommand -> reliableSequenceNumber;
800 
801        if (incomingCommand -> fragmentCount > 0)
802          channel -> incomingReliableSequenceNumber += incomingCommand -> fragmentCount - 1;
803     }
804 
805     if (currentCommand == enet_list_begin (& channel -> incomingReliableCommands))
806       return;
807 
808     channel -> incomingUnreliableSequenceNumber = 0;
809 
810     enet_list_move (enet_list_end (& peer -> dispatchedCommands), enet_list_begin (& channel -> incomingReliableCommands), enet_list_previous (currentCommand));
811 
812     if (! peer -> needsDispatch)
813     {
814        enet_list_insert (enet_list_end (& peer -> host -> dispatchQueue), & peer -> dispatchList);
815 
816        peer -> needsDispatch = 1;
817     }
818 
819     if (! enet_list_empty (& channel -> incomingUnreliableCommands))
820        enet_peer_dispatch_incoming_unreliable_commands (peer, channel);
821 }
822 
823 ENetIncomingCommand *
enet_peer_queue_incoming_command(ENetPeer * peer,const ENetProtocol * command,const void * data,size_t dataLength,enet_uint32 flags,enet_uint32 fragmentCount)824 enet_peer_queue_incoming_command (ENetPeer * peer, const ENetProtocol * command, const void * data, size_t dataLength, enet_uint32 flags, enet_uint32 fragmentCount)
825 {
826     static ENetIncomingCommand dummyCommand;
827 
828     ENetChannel * channel = & peer -> channels [command -> header.channelID];
829     enet_uint32 unreliableSequenceNumber = 0, reliableSequenceNumber = 0;
830     enet_uint16 reliableWindow, currentWindow;
831     ENetIncomingCommand * incomingCommand;
832     ENetListIterator currentCommand;
833     ENetPacket * packet = NULL;
834 
835     if (peer -> state == ENET_PEER_STATE_DISCONNECT_LATER)
836       goto discardCommand;
837 
838     if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) != ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED)
839     {
840         reliableSequenceNumber = command -> header.reliableSequenceNumber;
841         reliableWindow = reliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
842         currentWindow = channel -> incomingReliableSequenceNumber / ENET_PEER_RELIABLE_WINDOW_SIZE;
843 
844         if (reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
845            reliableWindow += ENET_PEER_RELIABLE_WINDOWS;
846 
847         if (reliableWindow < currentWindow || reliableWindow >= currentWindow + ENET_PEER_FREE_RELIABLE_WINDOWS - 1)
848           goto discardCommand;
849     }
850 
851     switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK)
852     {
853     case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT:
854     case ENET_PROTOCOL_COMMAND_SEND_RELIABLE:
855        if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber)
856          goto discardCommand;
857 
858        for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingReliableCommands));
859             currentCommand != enet_list_end (& channel -> incomingReliableCommands);
860             currentCommand = enet_list_previous (currentCommand))
861        {
862           incomingCommand = (ENetIncomingCommand *) currentCommand;
863 
864           if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
865           {
866              if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
867                continue;
868           }
869           else
870           if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
871             break;
872 
873           if (incomingCommand -> reliableSequenceNumber <= reliableSequenceNumber)
874           {
875              if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber)
876                break;
877 
878              goto discardCommand;
879           }
880        }
881        break;
882 
883     case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:
884     case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT:
885        unreliableSequenceNumber = ENET_NET_TO_HOST_16 (command -> sendUnreliable.unreliableSequenceNumber);
886 
887        if (reliableSequenceNumber == channel -> incomingReliableSequenceNumber &&
888            unreliableSequenceNumber <= channel -> incomingUnreliableSequenceNumber)
889          goto discardCommand;
890 
891        for (currentCommand = enet_list_previous (enet_list_end (& channel -> incomingUnreliableCommands));
892             currentCommand != enet_list_end (& channel -> incomingUnreliableCommands);
893             currentCommand = enet_list_previous (currentCommand))
894        {
895           incomingCommand = (ENetIncomingCommand *) currentCommand;
896 
897           if ((command -> header.command & ENET_PROTOCOL_COMMAND_MASK) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED)
898             continue;
899 
900           if (reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
901           {
902              if (incomingCommand -> reliableSequenceNumber < channel -> incomingReliableSequenceNumber)
903                continue;
904           }
905           else
906           if (incomingCommand -> reliableSequenceNumber >= channel -> incomingReliableSequenceNumber)
907             break;
908 
909           if (incomingCommand -> reliableSequenceNumber < reliableSequenceNumber)
910             break;
911 
912           if (incomingCommand -> reliableSequenceNumber > reliableSequenceNumber)
913             continue;
914 
915           if (incomingCommand -> unreliableSequenceNumber <= unreliableSequenceNumber)
916           {
917              if (incomingCommand -> unreliableSequenceNumber < unreliableSequenceNumber)
918                break;
919 
920              goto discardCommand;
921           }
922        }
923        break;
924 
925     case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
926        currentCommand = enet_list_end (& channel -> incomingUnreliableCommands);
927        break;
928 
929     default:
930        goto discardCommand;
931     }
932 
933     if (peer -> totalWaitingData >= peer -> host -> maximumWaitingData)
934       goto notifyError;
935 
936     packet = enet_packet_create (data, dataLength, flags);
937     if (packet == NULL)
938       goto notifyError;
939 
940     incomingCommand = (ENetIncomingCommand *) enet_malloc (sizeof (ENetIncomingCommand));
941     if (incomingCommand == NULL)
942       goto notifyError;
943 
944     incomingCommand -> reliableSequenceNumber = command -> header.reliableSequenceNumber;
945     incomingCommand -> unreliableSequenceNumber = unreliableSequenceNumber & 0xFFFF;
946     incomingCommand -> command = * command;
947     incomingCommand -> fragmentCount = fragmentCount;
948     incomingCommand -> fragmentsRemaining = fragmentCount;
949     incomingCommand -> packet = packet;
950     incomingCommand -> fragments = NULL;
951 
952     if (fragmentCount > 0)
953     {
954        if (fragmentCount <= ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT)
955          incomingCommand -> fragments = (enet_uint32 *) enet_malloc ((fragmentCount + 31) / 32 * sizeof (enet_uint32));
956        if (incomingCommand -> fragments == NULL)
957        {
958           enet_free (incomingCommand);
959 
960           goto notifyError;
961        }
962        memset (incomingCommand -> fragments, 0, (fragmentCount + 31) / 32 * sizeof (enet_uint32));
963     }
964 
965     if (packet != NULL)
966     {
967        ++ packet -> referenceCount;
968 
969        peer -> totalWaitingData += packet -> dataLength;
970     }
971 
972     enet_list_insert (enet_list_next (currentCommand), incomingCommand);
973 
974     switch (command -> header.command & ENET_PROTOCOL_COMMAND_MASK)
975     {
976     case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT:
977     case ENET_PROTOCOL_COMMAND_SEND_RELIABLE:
978        enet_peer_dispatch_incoming_reliable_commands (peer, channel);
979        break;
980 
981     default:
982        enet_peer_dispatch_incoming_unreliable_commands (peer, channel);
983        break;
984     }
985 
986     return incomingCommand;
987 
988 discardCommand:
989     if (fragmentCount > 0)
990       goto notifyError;
991 
992     if (packet != NULL && packet -> referenceCount == 0)
993       enet_packet_destroy (packet);
994 
995     return & dummyCommand;
996 
997 notifyError:
998     if (packet != NULL && packet -> referenceCount == 0)
999       enet_packet_destroy (packet);
1000 
1001     return NULL;
1002 }
1003 
1004 /** @} */
1005