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