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 |
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 |
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 | |
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 | */ |
106 | int |
107 | enet_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 | */ |
229 | ENetPacket * |
230 | enet_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 | |
257 | static void |
258 | enet_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 | |
278 | static void |
279 | enet_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 | |
309 | static void |
310 | enet_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 | |
315 | void |
316 | enet_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 | |
352 | void |
353 | enet_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 | |
364 | void |
365 | enet_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 | */ |
381 | void |
382 | enet_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 | */ |
445 | void |
446 | enet_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 | */ |
468 | void |
469 | enet_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 | |
491 | void |
492 | enet_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 | */ |
506 | void |
507 | enet_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 | */ |
537 | void |
538 | enet_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 | |
574 | int |
575 | enet_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 | */ |
591 | void |
592 | enet_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 | |
604 | ENetAcknowledgement * |
605 | enet_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 | |
636 | void |
637 | enet_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 | |
705 | ENetOutgoingCommand * |
706 | enet_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 | |
724 | void |
725 | enet_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 | |
807 | void |
808 | enet_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 | |
846 | ENetIncomingCommand * |
847 | enet_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 | |
1011 | discardCommand: |
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 | |
1020 | notifyError: |
1021 | if (packet != NULL && packet -> referenceCount == 0) |
1022 | enet_packet_destroy (packet); |
1023 | |
1024 | return NULL; |
1025 | } |
1026 | |
1027 | /** @} */ |
1028 | |