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*/
42void
43enet_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
61int
62enet_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*/
99int
100enet_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*/
221ENetPacket *
222enet_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
249static void
250enet_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
270static void
271enet_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
298static void
299enet_peer_reset_incoming_commands (ENetList * queue)
300{
301 enet_peer_remove_incoming_commands(queue, enet_list_begin (queue), enet_list_end (queue));
302}
303
304void
305enet_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
342void
343enet_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
354void
355enet_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*/
371void
372enet_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*/
434void
435enet_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*/
457void
458enet_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
480void
481enet_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*/
495void
496enet_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*/
526void
527enet_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*/
569void
570enet_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
584ENetAcknowledgement *
585enet_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
616void
617enet_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
682ENetOutgoingCommand *
683enet_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
701void
702enet_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
784void
785enet_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
823ENetIncomingCommand *
824enet_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
988discardCommand:
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
997notifyError:
998 if (packet != NULL && packet -> referenceCount == 0)
999 enet_packet_destroy (packet);
1000
1001 return NULL;
1002}
1003
1004/** @} */
1005