2 * Copyright (c) 2002-2015 Lee Salzman
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to permit
9 * persons to whom the Software is furnished to do so, subject to the
10 * following conditions:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
24 * D translation by Ketmar // Invisible Vector
25 * This port is licenced under the following GNU GPL.
26 * Keep using wrappers, you suckers. Or go GPL.
28 * This program is free software: you can redistribute it and/or modify
29 * it under the terms of the GNU General Public License as published by
30 * the Free Software Foundation, version 3 of the License ONLY.
32 * This program is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
37 * You should have received a copy of the GNU General Public License
38 * along with this program. If not, see <http://www.gnu.org/licenses/>.
40 module iv
.enet
/*is aliced*/;
46 ushort ENET_HOST_TO_NET_16 (ushort x
) @safe pure @nogc nothrow {
51 uint ENET_HOST_TO_NET_32 (uint x
) @safe pure @nogc nothrow {
55 } else version(LittleEndian
) {
56 ushort ENET_HOST_TO_NET_16 (ushort x
) @safe pure @nogc nothrow {
58 return ((x
&255)<<8)|
(x
>>8);
61 uint ENET_HOST_TO_NET_32 (uint x
) @safe pure @nogc nothrow {
63 import core
.bitop
: bswap;
67 static assert(false, "Compiling on another planet!");
71 alias ENET_NET_TO_HOST_16
= ENET_HOST_TO_NET_16
;
72 alias ENET_NET_TO_HOST_32
= ENET_HOST_TO_NET_32
;
76 import core
.sys
.windows
.mmsystem
;
77 import core
.sys
.windows
.winsock2
;
79 alias ENetSocket
= int;
80 enum ENET_SOCKET_NULL
= -1;
82 alias ENetSocketSet
= core
.sys
.windows
.winsock2
.fd_set
;
96 alias ENetSocket = SOCKET;
98 enum ENET_SOCKET_NULL = ~0;
100 align(1) struct ENetBuffer {
108 enum FD_SETSIZE = 64;
111 uint fd_count; // how many are SET?
112 SOCKET[FD_SETSIZE] fd_array; // an array of SOCKETs
115 alias fd_set ENetSocketSet;
117 void ENET_SOCKETSET_EMPTY() (ref ENetSocketSet sockset) {
118 sockset.fd_count = 0;
121 void ENET_SOCKETSET_ADD() (ref ENetSocketSet sockset, ENetSocket socket) {
122 foreach (immutable i; 0..sockset.fd_count) if (sockset.fd_array[i] == socket) return;
123 if (sockset.fd_count < FD_SETSIZE) {
124 sockset.fd_array[i] = socket;
129 bool ENET_SOCKETSET_CHECK() (ref ENetSocketSet sockset, ENetSocket socket) {
130 foreach (immutable i; 0..sockset.fd_count) if (sockset.fd_array[i] == socket) return true;
134 void ENET_SOCKETSET_REMOVE() (ref ENetSocketSet sockset, ENetSocket socket) {
135 foreach (usize i; 0..sockset.fd_count) {
136 if (sockset.fd_array[i] == socket) {
137 while (i < sockset.fd_count-1) {
138 sockset.fd_array[i] = sockset.fd_array[i+1];
148 static import core
.sys
.posix
.sys
.select
; // fd_set
150 alias ENetSocket
= int;
151 enum ENET_SOCKET_NULL
= -1;
153 alias ENetSocketSet
= core
.sys
.posix
.sys
.select
.fd_set
;
155 align(1) struct ENetBuffer
{
164 alias enet_uint8
= ubyte;
165 alias enet_uint16
= ushort;
166 alias enet_uint32
= uint;
171 ENET_PROTOCOL_MINIMUM_MTU
= 576,
172 ENET_PROTOCOL_MAXIMUM_MTU
= 4096,
173 ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS
= 32,
174 ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
= 4096,
176 // Warning when using this constant, it depends on the linked library version:
177 // - enet <= 1.3.9 defines ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE as 32768
178 // - enet >= 1.3.9 defines ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE as 65536
179 ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
= 65536,
181 ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
= 1,
182 ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
= 255,
183 ENET_PROTOCOL_MAXIMUM_PEER_ID
= 0xFFF,
184 ENET_PROTOCOL_MAXIMUM_PACKET_SIZE
= 1024*1024*1024,
185 ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT
= 1024*1024,
188 alias ENetProtocolCommand
= int;
189 enum : ENetProtocolCommand
{
190 ENET_PROTOCOL_COMMAND_NONE
= 0,
191 ENET_PROTOCOL_COMMAND_ACKNOWLEDGE
= 1,
192 ENET_PROTOCOL_COMMAND_CONNECT
= 2,
193 ENET_PROTOCOL_COMMAND_VERIFY_CONNECT
= 3,
194 ENET_PROTOCOL_COMMAND_DISCONNECT
= 4,
195 ENET_PROTOCOL_COMMAND_PING
= 5,
196 ENET_PROTOCOL_COMMAND_SEND_RELIABLE
= 6,
197 ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE
= 7,
198 ENET_PROTOCOL_COMMAND_SEND_FRAGMENT
= 8,
199 ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
= 9,
200 ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT
= 10,
201 ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE
= 11,
202 ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT
= 12,
203 ENET_PROTOCOL_COMMAND_COUNT
= 13,
205 ENET_PROTOCOL_COMMAND_MASK
= 0x0F,
208 alias ENetProtocolFlag
= int;
209 enum : ENetProtocolFlag
{
210 ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
= (1 << 7),
211 ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED
= (1 << 6),
213 ENET_PROTOCOL_HEADER_FLAG_COMPRESSED
= (1 << 14),
214 ENET_PROTOCOL_HEADER_FLAG_SENT_TIME
= (1 << 15),
215 ENET_PROTOCOL_HEADER_FLAG_MASK
= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED|ENET_PROTOCOL_HEADER_FLAG_SENT_TIME
,
217 ENET_PROTOCOL_HEADER_SESSION_MASK
= (3 << 12),
218 ENET_PROTOCOL_HEADER_SESSION_SHIFT
= 12,
221 align(1) struct ENetProtocolHeader
{
224 enet_uint16 sentTime
;
227 align(1) struct ENetProtocolCommandHeader
{
230 enet_uint8 channelID
;
231 enet_uint16 reliableSequenceNumber
;
234 align(1) struct ENetProtocolAcknowledge
{
236 ENetProtocolCommandHeader header
;
237 enet_uint16 receivedReliableSequenceNumber
;
238 enet_uint16 receivedSentTime
;
241 align(1) struct ENetProtocolConnect
{
243 ENetProtocolCommandHeader header
;
244 enet_uint16 outgoingPeerID
;
245 enet_uint8 incomingSessionID
;
246 enet_uint8 outgoingSessionID
;
248 enet_uint32 windowSize
;
249 enet_uint32 channelCount
;
250 enet_uint32 incomingBandwidth
;
251 enet_uint32 outgoingBandwidth
;
252 enet_uint32 packetThrottleInterval
;
253 enet_uint32 packetThrottleAcceleration
;
254 enet_uint32 packetThrottleDeceleration
;
255 enet_uint32 connectID
;
259 align(1) struct ENetProtocolVerifyConnect
{
261 ENetProtocolCommandHeader header
;
262 enet_uint16 outgoingPeerID
;
263 enet_uint8 incomingSessionID
;
264 enet_uint8 outgoingSessionID
;
266 enet_uint32 windowSize
;
267 enet_uint32 channelCount
;
268 enet_uint32 incomingBandwidth
;
269 enet_uint32 outgoingBandwidth
;
270 enet_uint32 packetThrottleInterval
;
271 enet_uint32 packetThrottleAcceleration
;
272 enet_uint32 packetThrottleDeceleration
;
273 enet_uint32 connectID
;
276 align(1) struct ENetProtocolBandwidthLimit
{
278 ENetProtocolCommandHeader header
;
279 enet_uint32 incomingBandwidth
;
280 enet_uint32 outgoingBandwidth
;
283 align(1) struct ENetProtocolThrottleConfigure
{
285 ENetProtocolCommandHeader header
;
286 enet_uint32 packetThrottleInterval
;
287 enet_uint32 packetThrottleAcceleration
;
288 enet_uint32 packetThrottleDeceleration
;
291 align(1) struct ENetProtocolDisconnect
{
293 ENetProtocolCommandHeader header
;
297 align(1) struct ENetProtocolPing
{
299 ENetProtocolCommandHeader header
;
302 align(1) struct ENetProtocolSendReliable
{
304 ENetProtocolCommandHeader header
;
305 enet_uint16 dataLength
;
308 align(1) struct ENetProtocolSendUnreliable
{
310 ENetProtocolCommandHeader header
;
311 enet_uint16 unreliableSequenceNumber
;
312 enet_uint16 dataLength
;
315 align(1) struct ENetProtocolSendUnsequenced
{
317 ENetProtocolCommandHeader header
;
318 enet_uint16 unsequencedGroup
;
319 enet_uint16 dataLength
;
322 align(1) struct ENetProtocolSendFragment
{
324 ENetProtocolCommandHeader header
;
325 enet_uint16 startSequenceNumber
;
326 enet_uint16 dataLength
;
327 enet_uint32 fragmentCount
;
328 enet_uint32 fragmentNumber
;
329 enet_uint32 totalLength
;
330 enet_uint32 fragmentOffset
;
333 align(1) union ENetProtocol
{
335 ENetProtocolCommandHeader header
;
336 ENetProtocolAcknowledge acknowledge
;
337 ENetProtocolConnect connect
;
338 ENetProtocolVerifyConnect verifyConnect
;
339 ENetProtocolDisconnect disconnect
;
340 ENetProtocolPing ping
;
341 ENetProtocolSendReliable sendReliable
;
342 ENetProtocolSendUnreliable sendUnreliable
;
343 ENetProtocolSendUnsequenced sendUnsequenced
;
344 ENetProtocolSendFragment sendFragment
;
345 ENetProtocolBandwidthLimit bandwidthLimit
;
346 ENetProtocolThrottleConfigure throttleConfigure
;
351 struct ENetListNode
{
353 ENetListNode
* previous
;
357 ENetListNode sentinel
;
362 struct ENetCallbacks
{
364 void* function (usize size
) malloc
;
365 void function (void* memory
) free
;
366 void function () no_memory
;
369 //extern(C) void* enet_malloc (usize) nothrow @trusted;
370 //extern(C) void enet_free (void*) nothrow @trusted;
375 ENET_VERSION_MAJOR
= 1,
376 ENET_VERSION_MINOR
= 3,
377 ENET_VERSION_PATCH
= 13,
380 int ENET_VERSION_CREATE() (int major
, int minor
, int patch
) pure nothrow @safe @nogc {
381 pragma(inline
, true);
382 return (major
<< 16) |
(minor
<< 8) | patch
;
385 int ENET_VERSION_GET_MAJOR() (int version_
) pure nothrow @safe @nogc {
386 pragma(inline
, true);
387 return (version_
>> 16) & 0xFF;
390 int ENET_VERSION_GET_MINOR() (int version_
) pure nothrow @safe @nogc {
391 pragma(inline
, true);
392 return (version_
>> 8) & 0xFF;
395 int ENET_VERSION_GET_PATCH() (int version_
) pure nothrow @safe @nogc {
396 pragma(inline
, true);
397 return version_
& 0xFF;
400 enum ENET_VERSION
= ENET_VERSION_CREATE(ENET_VERSION_MAJOR
, ENET_VERSION_MINOR
, ENET_VERSION_PATCH
);
402 alias ENetVersion
= enet_uint32
;
404 alias ENetSocketType
= int;
405 enum : ENetSocketType
{
406 ENET_SOCKET_TYPE_STREAM
= 1,
407 ENET_SOCKET_TYPE_DATAGRAM
= 2,
410 alias ENetSocketWait
= int;
411 enum : ENetSocketWait
{
412 ENET_SOCKET_WAIT_NONE
= 0,
413 ENET_SOCKET_WAIT_SEND
= (1<<0),
414 ENET_SOCKET_WAIT_RECEIVE
= (1<<1),
415 ENET_SOCKET_WAIT_INTERRUPT
= (1<<2),
418 alias ENetSocketOption
= int;
419 enum : ENetSocketOption
{
420 ENET_SOCKOPT_NONBLOCK
= 1,
421 ENET_SOCKOPT_BROADCAST
= 2,
422 ENET_SOCKOPT_RCVBUF
= 3,
423 ENET_SOCKOPT_SNDBUF
= 4,
424 ENET_SOCKOPT_REUSEADDR
= 5,
425 ENET_SOCKOPT_RCVTIMEO
= 6,
426 ENET_SOCKOPT_SNDTIMEO
= 7,
427 ENET_SOCKOPT_ERROR
= 8,
428 ENET_SOCKOPT_NODELAY
= 9,
431 alias ENetSocketShutdown
= int;
432 enum : ENetSocketShutdown
{
433 ENET_SOCKET_SHUTDOWN_READ
= 0,
434 ENET_SOCKET_SHUTDOWN_WRITE
= 1,
435 ENET_SOCKET_SHUTDOWN_READ_WRITE
= 2,
440 ENET_HOST_BROADCAST
= 0xFFFFFFFFU
,
446 * Portable internet address structure.
448 * The host must be specified in network byte-order, and the port must be in host
449 * byte-order. The constant ENET_HOST_ANY may be used to specify the default
450 * server host. The constant ENET_HOST_BROADCAST may be used to specify the
451 * broadcast address (255.255.255.255). This makes sense for enet_host_connect,
452 * but not for enet_host_create. Once a server responds to a broadcast, the
453 * address is updated from ENET_HOST_BROADCAST to the server's actual IP address.
461 * Packet flag bit constants.
463 * The host must be specified in network byte-order, and the port must be in
464 * host byte-order. The constant ENET_HOST_ANY may be used to specify the
465 * default server host.
467 alias ENetPacketFlag
= int;
468 enum : ENetPacketFlag
{
469 /** packet must be received by the target peer and resend attempts should be
470 * made until the packet is delivered */
471 ENET_PACKET_FLAG_RELIABLE
= (1 << 0),
472 /** packet will not be sequenced with other packets
473 * not supported for reliable packets
475 ENET_PACKET_FLAG_UNSEQUENCED
= (1 << 1),
476 /** packet will not allocate data, and user must supply it instead */
477 ENET_PACKET_FLAG_NO_ALLOCATE
= (1 << 2),
478 /** packet will be fragmented using unreliable (instead of reliable) sends
479 * if it exceeds the MTU */
480 ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT
= (1 << 3),
482 /** whether the packet has been sent from all queues it has been entered into */
483 ENET_PACKET_FLAG_SENT
= (1<<8),
486 alias extern(C
) nothrow void function (ENetPacket
*) ENetPacketFreeCallback
;
489 * ENet packet structure.
491 * An ENet data packet that may be sent to or received from a peer. The shown
492 * fields should only be read and never modified. The data field contains the
493 * allocated data for the packet. The dataLength fields specifies the length
494 * of the allocated data. The flags field is either 0 (specifying no flags),
495 * or a bitwise-or of any combination of the following flags:
497 * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer
498 * and resend attempts should be made until the packet is delivered
500 * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets
501 * (not supported for reliable packets)
503 * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead
505 * ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable
506 * (instead of reliable) sends if it exceeds the MTU
508 * ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into
511 usize referenceCount
; /** internal use only */
512 enet_uint32 flags
; /** bitwise-or of ENetPacketFlag constants */
513 enet_uint8
* data
; /** allocated data for packet */
514 usize dataLength
; /** length of data */
515 ENetPacketFreeCallback freeCallback
; /** function to be called when the packet is no longer in use */
516 void* userData
; /** application private data, may be freely modified */
519 struct ENetAcknowledgement
{
520 ENetListNode acknowledgementList
;
521 enet_uint32 sentTime
;
522 ENetProtocol command
;
525 struct ENetOutgoingCommand
{
526 ENetListNode outgoingCommandList
;
527 enet_uint16 reliableSequenceNumber
;
528 enet_uint16 unreliableSequenceNumber
;
529 enet_uint32 sentTime
;
530 enet_uint32 roundTripTimeout
;
531 enet_uint32 roundTripTimeoutLimit
;
532 enet_uint32 fragmentOffset
;
533 enet_uint16 fragmentLength
;
534 enet_uint16 sendAttempts
;
535 ENetProtocol command
;
539 struct ENetIncomingCommand
{
540 ENetListNode incomingCommandList
;
541 enet_uint16 reliableSequenceNumber
;
542 enet_uint16 unreliableSequenceNumber
;
543 ENetProtocol command
;
544 enet_uint32 fragmentCount
;
545 enet_uint32 fragmentsRemaining
;
546 enet_uint32
* fragments
;
550 alias ENetPeerState
= int;
551 enum : ENetPeerState
{
552 ENET_PEER_STATE_DISCONNECTED
= 0,
553 ENET_PEER_STATE_CONNECTING
= 1,
554 ENET_PEER_STATE_ACKNOWLEDGING_CONNECT
= 2,
555 ENET_PEER_STATE_CONNECTION_PENDING
= 3,
556 ENET_PEER_STATE_CONNECTION_SUCCEEDED
= 4,
557 ENET_PEER_STATE_CONNECTED
= 5,
558 ENET_PEER_STATE_DISCONNECT_LATER
= 6,
559 ENET_PEER_STATE_DISCONNECTING
= 7,
560 ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT
= 8,
561 ENET_PEER_STATE_ZOMBIE
= 9,
564 enum ENET_BUFFER_MAXIMUM
= 1+2*ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS
;
567 ENET_HOST_RECEIVE_BUFFER_SIZE
= 256*1024,
568 ENET_HOST_SEND_BUFFER_SIZE
= 256*1024,
569 ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL
= 1000,
570 ENET_HOST_DEFAULT_MTU
= 1400,
571 ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE
= 32*1024*1024,
572 ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA
= 32*1024*1024,
574 ENET_PEER_DEFAULT_ROUND_TRIP_TIME
= 500,
575 ENET_PEER_DEFAULT_PACKET_THROTTLE
= 32,
576 ENET_PEER_PACKET_THROTTLE_SCALE
= 32,
577 ENET_PEER_PACKET_THROTTLE_COUNTER
= 7,
578 ENET_PEER_PACKET_THROTTLE_ACCELERATION
= 2,
579 ENET_PEER_PACKET_THROTTLE_DECELERATION
= 2,
580 ENET_PEER_PACKET_THROTTLE_INTERVAL
= 5000,
581 ENET_PEER_PACKET_LOSS_SCALE
= (1 << 16),
582 ENET_PEER_PACKET_LOSS_INTERVAL
= 10000,
583 ENET_PEER_WINDOW_SIZE_SCALE
= 64 * 1024,
584 ENET_PEER_TIMEOUT_LIMIT
= 32,
585 ENET_PEER_TIMEOUT_MINIMUM
= 5000,
586 ENET_PEER_TIMEOUT_MAXIMUM
= 30000,
587 ENET_PEER_PING_INTERVAL
= 500,
588 ENET_PEER_UNSEQUENCED_WINDOWS
= 64,
589 ENET_PEER_UNSEQUENCED_WINDOW_SIZE
= 1024,
590 ENET_PEER_FREE_UNSEQUENCED_WINDOWS
= 32,
591 ENET_PEER_RELIABLE_WINDOWS
= 16,
592 ENET_PEER_RELIABLE_WINDOW_SIZE
= 0x1000,
593 ENET_PEER_FREE_RELIABLE_WINDOWS
= 8,
597 enet_uint16 outgoingReliableSequenceNumber
;
598 enet_uint16 outgoingUnreliableSequenceNumber
;
599 enet_uint16 usedReliableWindows
;
600 enet_uint16
[ENET_PEER_RELIABLE_WINDOWS
] reliableWindows
;
601 enet_uint16 incomingReliableSequenceNumber
;
602 enet_uint16 incomingUnreliableSequenceNumber
;
603 ENetList incomingReliableCommands
;
604 ENetList incomingUnreliableCommands
;
608 * An ENet peer which data packets may be sent or received from.
610 * No fields should be modified unless otherwise specified.
613 ENetListNode dispatchList
;
615 enet_uint16 outgoingPeerID
;
616 enet_uint16 incomingPeerID
;
617 enet_uint32 connectID
;
618 enet_uint8 outgoingSessionID
;
619 enet_uint8 incomingSessionID
;
620 ENetAddress address
; /** Internet address of the peer */
621 void* data
; /** Application private data, may be freely modified */
623 ENetChannel
* channels
;
624 usize channelCount
; /** Number of channels allocated for communication with peer */
625 enet_uint32 incomingBandwidth
; /** Downstream bandwidth of the client in bytes/second */
626 enet_uint32 outgoingBandwidth
; /** Upstream bandwidth of the client in bytes/second */
627 enet_uint32 incomingBandwidthThrottleEpoch
;
628 enet_uint32 outgoingBandwidthThrottleEpoch
;
629 enet_uint32 incomingDataTotal
;
630 enet_uint32 outgoingDataTotal
;
631 enet_uint32 lastSendTime
;
632 enet_uint32 lastReceiveTime
;
633 enet_uint32 nextTimeout
;
634 enet_uint32 earliestTimeout
;
635 enet_uint32 packetLossEpoch
;
636 enet_uint32 packetsSent
;
637 enet_uint32 packetsLost
;
638 enet_uint32 packetLoss
; /** mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */
639 enet_uint32 packetLossVariance
;
640 enet_uint32 packetThrottle
;
641 enet_uint32 packetThrottleLimit
;
642 enet_uint32 packetThrottleCounter
;
643 enet_uint32 packetThrottleEpoch
;
644 enet_uint32 packetThrottleAcceleration
;
645 enet_uint32 packetThrottleDeceleration
;
646 enet_uint32 packetThrottleInterval
;
647 enet_uint32 pingInterval
;
648 enet_uint32 timeoutLimit
;
649 enet_uint32 timeoutMinimum
;
650 enet_uint32 timeoutMaximum
;
651 enet_uint32 lastRoundTripTime
;
652 enet_uint32 lowestRoundTripTime
;
653 enet_uint32 lastRoundTripTimeVariance
;
654 enet_uint32 highestRoundTripTimeVariance
;
655 enet_uint32 roundTripTime
; /** mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */
656 enet_uint32 roundTripTimeVariance
;
658 enet_uint32 windowSize
;
659 enet_uint32 reliableDataInTransit
;
660 enet_uint16 outgoingReliableSequenceNumber
;
661 ENetList acknowledgements
;
662 ENetList sentReliableCommands
;
663 ENetList sentUnreliableCommands
;
664 ENetList outgoingReliableCommands
;
665 ENetList outgoingUnreliableCommands
;
666 ENetList dispatchedCommands
;
668 enet_uint16 incomingUnsequencedGroup
;
669 enet_uint16 outgoingUnsequencedGroup
;
670 enet_uint32
[ENET_PEER_UNSEQUENCED_WINDOW_SIZE
/32] unsequencedWindow
;
671 enet_uint32 eventData
;
672 usize totalWaitingData
;
675 /** An ENet packet compressor for compressing UDP packets before socket sends or receives.
677 struct ENetCompressor
{
678 /** Context data for the compressor. Must be non-null. */
680 extern(C
) nothrow @trusted:
681 /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */
682 usize
function (void* context
, const(ENetBuffer
)* inBuffers
, usize inBufferCount
, usize inLimit
, enet_uint8
* outData
, usize outLimit
) @nogc compress
;
683 /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */
684 usize
function (void* context
, const(enet_uint8
)* inData
, usize inLimit
, enet_uint8
* outData
, usize outLimit
) @nogc decompress
;
685 /** Destroys the context when compression is disabled or the host is destroyed. May be null. */
686 void function (void* context
) destroy
;
689 /** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */
690 extern(C
) nothrow @trusted @nogc {
691 alias ENetChecksumCallback
= enet_uint32
function (const(ENetBuffer
)* buffers
, usize bufferCount
);
693 /** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */
694 alias ENetInterceptCallback
= int function (ENetHost
* host
, ENetEvent
* event
);
697 /** An ENet host for communicating with peers.
699 * No fields should be modified unless otherwise stated.
701 @sa enet_host_create()
702 @sa enet_host_destroy()
703 @sa enet_host_connect()
704 @sa enet_host_service()
705 @sa enet_host_flush()
706 @sa enet_host_broadcast()
707 @sa enet_host_compress()
708 @sa enet_host_compress_with_range_coder()
709 @sa enet_host_channel_limit()
710 @sa enet_host_bandwidth_limit()
711 @sa enet_host_bandwidth_throttle()
715 ENetAddress address
; /** Internet address of the host */
716 enet_uint32 incomingBandwidth
; /** downstream bandwidth of the host */
717 enet_uint32 outgoingBandwidth
; /** upstream bandwidth of the host */
718 enet_uint32 bandwidthThrottleEpoch
;
720 enet_uint32 randomSeed
;
721 int recalculateBandwidthLimits
;
722 ENetPeer
* peers
; /** array of peers allocated for this host */
723 usize peerCount
; /** number of peers allocated for this host */
724 usize channelLimit
; /** maximum number of channels allowed for connected peers */
725 enet_uint32 serviceTime
;
726 ENetList dispatchQueue
;
729 enet_uint16 headerFlags
;
730 ENetProtocol
[ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS
] commands
;
732 ENetBuffer
[ENET_BUFFER_MAXIMUM
] buffers
;
734 ENetChecksumCallback checksum
; /** callback the user can set to enable packet checksums for this host */
735 ENetCompressor compressor
;
736 enet_uint8
[ENET_PROTOCOL_MAXIMUM_MTU
][2] packetData
;
737 ENetAddress receivedAddress
;
738 enet_uint8
* receivedData
;
739 usize receivedDataLength
;
740 enet_uint32 totalSentData
; /** total data sent, user should reset to 0 as needed to prevent overflow */
741 enet_uint32 totalSentPackets
; /** total UDP packets sent, user should reset to 0 as needed to prevent overflow */
742 enet_uint32 totalReceivedData
; /** total data received, user should reset to 0 as needed to prevent overflow */
743 enet_uint32 totalReceivedPackets
; /** total UDP packets received, user should reset to 0 as needed to prevent overflow */
744 ENetInterceptCallback intercept
; /** callback the user can set to intercept received raw UDP packets */
745 usize connectedPeers
;
746 usize bandwidthLimitedPeers
;
747 usize duplicatePeers
; /** optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */
748 usize maximumPacketSize
; /** the maximum allowable packet size that may be sent or received on a peer */
749 usize maximumWaitingData
; /** the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */
753 * An ENet event type, as specified in @ref ENetEvent.
755 alias ENetEventType
= int;
756 enum : ENetEventType
{
757 /** no event occurred within the specified time limit */
758 ENET_EVENT_TYPE_NONE
= 0,
760 /** a connection request initiated by enet_host_connect has completed.
761 * The peer field contains the peer which successfully connected.
763 ENET_EVENT_TYPE_CONNECT
= 1,
765 /** a peer has disconnected. This event is generated on a successful
766 * completion of a disconnect initiated by enet_pper_disconnect, if
767 * a peer has timed out, or if a connection request intialized by
768 * enet_host_connect has timed out. The peer field contains the peer
769 * which disconnected. The data field contains user supplied data
770 * describing the disconnection, or 0, if none is available.
772 ENET_EVENT_TYPE_DISCONNECT
= 2,
774 /** a packet has been received from a peer. The peer field specifies the
775 * peer which sent the packet. The channelID field specifies the channel
776 * number upon which the packet was received. The packet field contains
777 * the packet that was received; this packet must be destroyed with
778 * enet_packet_destroy after use.
780 ENET_EVENT_TYPE_RECEIVE
= 3,
784 * An ENet event as returned by enet_host_service().
787 ENetEventType type
; /** type of the event */
788 ENetPeer
* peer
; /** peer that generated a connect, disconnect or receive event */
789 enet_uint8 channelID
; /** channel on the peer that generated the event, if appropriate */
790 enet_uint32 data
; /** data associated with the event, if appropriate */
791 ENetPacket
* packet
; /** packet associated with the event, if appropriate */
795 private __gshared enet_uint32 timeBase
= 0;
797 version(Windows
) nothrow @nogc {
798 //static assert(0, "windoze socket module is not here");
799 pragma(lib
, "ws2_32");
800 pragma(lib
, "winmm");
801 import core
.sys
.windows
.mmsystem
;
802 import core
.sys
.windows
.winsock2
;
803 import core
.sys
.windows
.windef
: DWORD
, LPDWORD
;
805 private __gshared
bool shitdozeinited
= false;
807 shared static this () {
809 if (WSAStartup(0x0101, &wsaData
)) return;
810 if ((wsaData
.wVersion
&0xffff) != 0x0101) {
815 shitdozeinited
= true;
818 shared static ~this () {
819 if (shitdozeinited
) {
822 shitdozeinited
= false;
826 int enet_initialize () {
827 return (shitdozeinited ?
0 : -1);
830 void enet_deinitialize () {
833 enet_uint32
enet_host_random_seed () {
834 return cast(enet_uint32
)timeGetTime();
837 enet_uint32
enet_time_get () {
838 return cast(enet_uint32
)timeGetTime()-timeBase
;
841 void enet_time_set (enet_uint32 newTimeBase
) {
842 timeBase
= cast(enet_uint32
)timeGetTime()-newTimeBase
;
845 int enet_address_set_host_ip (ENetAddress
* address
, const(char)[] name
) {
847 enet_uint8
[4] vals
= 0;
848 foreach (immutable i
, ref ubyte v
; vals
[]) {
850 while (name
.length
) {
851 char ch
= name
.ptr
[0];
853 if (ch
< '0' || ch
> '9') return -1;
855 if (val
> 255) return -1;
859 if (name
.ptr
[0] != '.') return -1;
864 import core
.stdc
.string
: memcpy
;
865 memcpy(&address
.host
, vals
.ptr
, enet_uint32
.sizeof
);
869 int enet_address_set_host (ENetAddress
* address
, const(char)[] namestr
) {
870 import std
.internal
.cstring
: tempCString
;
871 auto name
= namestr
.tempCString
;
872 hostent
* hostEntry
= gethostbyname(name
);
873 if (hostEntry
is null || hostEntry
.h_addrtype
!= AF_INET
) return enet_address_set_host_ip(address
, namestr
);
874 address
.host
= *cast(const(enet_uint32
)*)hostEntry
.h_addr_list
[0];
878 int enet_address_get_host_ip (const ENetAddress
* address
, char* name
, usize nameLength
) {
879 import core
.stdc
.string
: memcpy
, strlen
;
880 char* addr
= inet_ntoa(*cast(const(in_addr
)*)&address
.host
);
881 if (addr
is null) return -1;
882 usize addrLen
= strlen(addr
);
883 if (addrLen
>= nameLength
) return -1;
884 memcpy(name
, addr
, addrLen
+1);
888 int enet_address_get_host (const ENetAddress
* address
, char* name
, usize nameLength
) {
892 in_
.s_addr
= address
.host
;
894 hostEntry
= gethostbyaddr(cast(char*)&in_
, in_addr
.sizeof
, AF_INET
);
895 if (hostEntry
is null) {
896 return enet_address_get_host_ip(address
, name
, nameLength
);
898 import core
.stdc
.string
: memcpy
, strlen
;
899 usize hostLen
= strlen(hostEntry
.h_name
);
900 if (hostLen
>= nameLength
) return -1;
901 memcpy(name
, hostEntry
.h_name
, hostLen
+1);
907 int enet_socket_bind (ENetSocket socket
, const ENetAddress
* address
) {
908 import core
.stdc
.string
: memset
;
911 memset(&sin
, 0, sockaddr_in
.sizeof
);
912 sin
.sin_family
= AF_INET
;
913 if (address
!is null) {
914 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
915 sin
.sin_addr
.s_addr
= address
.host
;
918 sin
.sin_addr
.s_addr
= INADDR_ANY
;
921 return (bind(socket
, cast(sockaddr
*)&sin
, sockaddr_in
.sizeof
) == SOCKET_ERROR ?
-1 : 0);
924 int enet_socket_get_address (ENetSocket socket
, ENetAddress
* address
) {
926 socklen_t sinLength
= cast(socklen_t
)sockaddr_in
.sizeof
;
928 if (getsockname(socket
, cast(sockaddr
*)&sin
, &sinLength
) == -1) return -1;
930 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
931 address
.port
= ENET_NET_TO_HOST_16(sin
.sin_port
);
936 int enet_socket_listen (ENetSocket socket
, int backlog
) {
937 return (listen(socket
, (backlog
< 0 ?
/*SOMAXCONN*/127 : backlog
)) == SOCKET_ERROR ?
-1 : 0);
940 ENetSocket
enet_socket_create (ENetSocketType type
) {
941 return socket(PF_INET
, (type
== ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM
: SOCK_STREAM
), 0);
944 int enet_socket_set_option (ENetSocket socket
, ENetSocketOption option
, int value
) {
945 int result
= SOCKET_ERROR
;
947 case ENET_SOCKOPT_NONBLOCK
:
948 uint nonBlocking
= cast(uint)value
;
949 result
= ioctlsocket(socket
, FIONBIO
, &nonBlocking
);
951 case ENET_SOCKOPT_BROADCAST
:
952 result
= setsockopt(socket
, SOL_SOCKET
, SO_BROADCAST
, cast(void*)&value
, int.sizeof
);
954 case ENET_SOCKOPT_REUSEADDR
:
955 result
= setsockopt(socket
, SOL_SOCKET
, SO_REUSEADDR
, cast(void*)&value
, int.sizeof
);
957 case ENET_SOCKOPT_RCVBUF
:
958 result
= setsockopt(socket
, SOL_SOCKET
, SO_RCVBUF
, cast(void*)&value
, int.sizeof
);
960 case ENET_SOCKOPT_SNDBUF
:
961 result
= setsockopt(socket
, SOL_SOCKET
, SO_SNDBUF
, cast(void*)&value
, int.sizeof
);
963 case ENET_SOCKOPT_RCVTIMEO
:
964 result
= setsockopt(socket
, SOL_SOCKET
, SO_RCVTIMEO
, cast(void*)&value
, int.sizeof
);
966 case ENET_SOCKOPT_SNDTIMEO
:
967 result
= setsockopt(socket
, SOL_SOCKET
, SO_SNDTIMEO
, cast(void*)&value
, int.sizeof
);
969 case ENET_SOCKOPT_NODELAY
:
970 result
= setsockopt(socket
, IPPROTO_TCP
, TCP_NODELAY
, cast(void*)&value
, int.sizeof
);
975 return (result
== SOCKET_ERROR ?
-1 : 0);
978 int enet_socket_get_option (ENetSocket socket
, ENetSocketOption option
, int* value
) {
979 int result
= SOCKET_ERROR
, len
;
981 case ENET_SOCKOPT_ERROR
:
983 result
= getsockopt(socket
, SOL_SOCKET
, SO_ERROR
, cast(void*)value
, &len
);
988 return (result
== SOCKET_ERROR ?
-1 : 0);
991 int enet_socket_connect (ENetSocket socket
, const ENetAddress
* address
) {
992 import core
.stdc
.string
: memset
;
996 memset(&sin
, 0, sockaddr_in
.sizeof
);
998 sin
.sin_family
= AF_INET
;
999 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1000 sin
.sin_addr
.s_addr
= address
.host
;
1002 result
= connect(socket
, cast(sockaddr
*)&sin
, sockaddr_in
.sizeof
);
1003 if (result
== SOCKET_ERROR
&& WSAGetLastError() != WSAEWOULDBLOCK
) return -1;
1008 ENetSocket
enet_socket_accept (ENetSocket socket
, ENetAddress
* address
) {
1011 socklen_t sinLength
= cast(socklen_t
)sockaddr_in
.sizeof
;
1013 result
= accept(socket
, (address
!is null ?
cast(sockaddr
*)&sin
: null), (address
!is null ?
&sinLength
: null));
1015 if (result
== INVALID_SOCKET
) return ENET_SOCKET_NULL
;
1017 if (address
!is null) {
1018 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
1019 address
.port
= ENET_NET_TO_HOST_16 (sin
.sin_port
);
1025 int enet_socket_shutdown (ENetSocket socket
, ENetSocketShutdown how
) {
1026 return (shutdown(socket
, cast(int)how
) == SOCKET_ERROR ?
-1 : 0);
1029 void enet_socket_destroy (ENetSocket socket
) {
1030 if (socket
!= INVALID_SOCKET
) closesocket(socket
);
1033 private extern(Windows
) nothrow @nogc int WSASendTo (
1035 const ENetBuffer
* lpBuffers
,
1036 DWORD dwBufferCount
,
1037 LPDWORD lpNumberOfBytesSent
,
1039 const sockaddr
* lpTo
,
1041 /*LPWSAOVERLAPPED*/void* lpOverlapped
=null,
1042 /*LPWSAOVERLAPPED_COMPLETION_ROUTINE*/void* lpCompletionRoutine
=null
1045 private extern(Windows
) nothrow @nogc int WSARecvFrom (
1047 ENetBuffer
* lpBuffers
,
1048 DWORD dwBufferCount
,
1049 LPDWORD lpNumberOfBytesRecvd
,
1052 /*LPINT*/int* lpFromlen
,
1053 /*LPWSAOVERLAPPED*/void* lpOverlapped
=null,
1054 /*LPWSAOVERLAPPED_COMPLETION_ROUTINE*/void* lpCompletionRoutine
=null
1058 int enet_socket_send (ENetSocket socket
, const ENetAddress
* address
, const ENetBuffer
* buffers
, usize bufferCount
) {
1059 import core
.stdc
.string
: memset
;
1063 if (address
!is null) {
1064 memset(&sin
, 0, sockaddr_in
.sizeof
);
1065 sin
.sin_family
= AF_INET
;
1066 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1067 sin
.sin_addr
.s_addr
= address
.host
;
1070 if (WSASendTo(socket
, /*cast(LPWSABUF)*/buffers
, cast(DWORD
)bufferCount
, &sentLength
, 0, (address
!is null ?
cast(sockaddr
*)&sin
: null), (address
!is null ? sockaddr_in
.sizeof
: 0), null, null) == SOCKET_ERROR
) {
1071 if (WSAGetLastError() == WSAEWOULDBLOCK
) return 0;
1075 return cast(int)sentLength
;
1078 int enet_socket_receive (ENetSocket socket
, ENetAddress
* address
, ENetBuffer
* buffers
, usize bufferCount
) {
1079 enum MSG_PARTIAL
= 0x8000;
1080 socklen_t sinLength
= cast(socklen_t
)sockaddr_in
.sizeof
;
1081 DWORD flags
= 0, recvLength
;
1084 if (WSARecvFrom(socket
, /*cast(LPWSABUF)*/buffers
, cast(DWORD
)bufferCount
, &recvLength
, &flags
, (address
!is null ?
cast(sockaddr
*)&sin
: null), (address
!is null ?
&sinLength
: null), null, null) == SOCKET_ERROR
) {
1085 switch (WSAGetLastError()) {
1086 case WSAEWOULDBLOCK
:
1094 if (flags
&MSG_PARTIAL
) return -1;
1096 if (address
!is null) {
1097 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
1098 address
.port
= ENET_NET_TO_HOST_16(sin
.sin_port
);
1101 return cast(int)recvLength
;
1104 int enet_socketset_select (ENetSocket maxSocket
, ENetSocketSet
* readSet
, ENetSocketSet
* writeSet
, enet_uint32 timeout
) {
1106 timeVal
.tv_sec
= timeout
/1000;
1107 timeVal
.tv_usec
= (timeout
%1000)*1000;
1108 return select(maxSocket
+1, readSet
, writeSet
, null, &timeVal
);
1111 int enet_socket_wait (ENetSocket socket
, enet_uint32
* condition
, enet_uint32 timeout
) {
1112 fd_set readSet
, writeSet
;
1116 timeVal
.tv_sec
= timeout
/ 1000;
1117 timeVal
.tv_usec
= (timeout
% 1000) * 1000;
1122 if ((*condition
)&ENET_SOCKET_WAIT_SEND
) FD_SET(socket
, &writeSet
);
1123 if ((*condition
)&ENET_SOCKET_WAIT_RECEIVE
) FD_SET(socket
, &readSet
);
1125 selectCount
= select(socket
+1, &readSet
, &writeSet
, null, &timeVal
);
1126 if (selectCount
< 0) return -1;
1128 *condition
= ENET_SOCKET_WAIT_NONE
;
1130 if (selectCount
== 0) return 0;
1132 if (FD_ISSET(socket
, &writeSet
)) *condition |
= ENET_SOCKET_WAIT_SEND
;
1133 if (FD_ISSET(socket
, &readSet
)) *condition |
= ENET_SOCKET_WAIT_RECEIVE
;
1137 } else extern(C
) nothrow @nogc {
1139 static import core
.sys
.posix
.sys
.select
; // FD_XXX
1141 auto ENET_SOCKETSET_EMPTY (ref ENetSocketSet sockset
) {
1142 pragma(inline
, true);
1143 core
.sys
.posix
.sys
.select
.FD_ZERO(&sockset
);
1146 auto ENET_SOCKETSET_ADD (ref ENetSocketSet sockset
, ENetSocket socket
) {
1147 pragma(inline
, true);
1148 core
.sys
.posix
.sys
.select
.FD_SET(socket
, &sockset
);
1151 auto ENET_SOCKETSET_REMOVE (ref ENetSocketSet sockset
, ENetSocket socket
) {
1152 pragma(inline
, true);
1153 core
.sys
.posix
.sys
.select
.FD_CLR(socket
, &sockset
);
1156 auto ENET_SOCKETSET_CHECK (ref ENetSocketSet sockset
, ENetSocket socket
) {
1157 pragma(inline
, true);
1158 return !!core
.sys
.posix
.sys
.select
.FD_ISSET(socket
, &sockset
);
1162 int enet_initialize () {
1167 void enet_deinitialize () {
1171 enet_uint32
enet_host_random_seed () {
1172 import core
.stdc
.time
: time
;
1173 return cast(enet_uint32
)time(null);
1177 enet_uint32
enet_time_get () {
1178 import core
.sys
.posix
.sys
.time
: gettimeofday
, timeval
;
1179 timeval timeVal
= void;
1180 gettimeofday(&timeVal
, null);
1181 return cast(uint)(timeVal
.tv_sec
*1000+timeVal
.tv_usec
/1000-timeBase
);
1185 void enet_time_set (enet_uint32 newTimeBase
) {
1186 import core
.sys
.posix
.sys
.time
: gettimeofday
, timeval
;
1187 timeval timeVal
= void;
1188 gettimeofday(&timeVal
, null);
1189 timeBase
= cast(uint)(timeVal
.tv_sec
*1000+timeVal
.tv_usec
/1000-newTimeBase
);
1193 int enet_address_set_host (ENetAddress
* address
, const(char)[] namestr
) {
1194 import core
.stdc
.string
: memset
;
1195 import core
.sys
.posix
.arpa
.inet
: inet_pton
;
1196 import core
.sys
.posix
.netdb
: addrinfo
, getaddrinfo
, freeaddrinfo
;
1197 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1198 import core
.sys
.posix
.sys
.socket
: AF_INET
;
1199 import std
.internal
.cstring
: tempCString
;
1201 addrinfo hints
= void;
1202 addrinfo
* resultList
= null, result
= null;
1204 memset(&hints
, 0, hints
.sizeof
);
1205 hints
.ai_family
= AF_INET
;
1207 auto name
= namestr
.tempCString
;
1209 if (getaddrinfo(name
, null, null, &resultList
) != 0) return -1;
1211 for (result
= resultList
; result
!is null; result
= result
.ai_next
) {
1212 if (result
.ai_family
== AF_INET
&& result
.ai_addr
!is null && result
.ai_addrlen
>= sockaddr_in
.sizeof
) {
1213 sockaddr_in
* sin
= cast(sockaddr_in
*)result
.ai_addr
;
1214 address
.host
= sin
.sin_addr
.s_addr
;
1215 freeaddrinfo(resultList
);
1220 if (resultList
!is null) freeaddrinfo(resultList
);
1222 if (!inet_pton(AF_INET
, name
, &address
.host
)) return -1;
1228 int enet_address_get_host_ip (const ENetAddress
* address
, char* name
, usize nameLength
) {
1229 import core
.sys
.posix
.arpa
.inet
: inet_ntop
;
1230 import core
.sys
.posix
.sys
.socket
: AF_INET
;
1232 if (inet_ntop(AF_INET
, &address
.host
, name
, cast(uint)nameLength
) is null) return -1; // crude x86_64 fix
1237 int enet_address_get_host (const ENetAddress
* address
, char* name
, usize nameLength
) {
1238 import core
.stdc
.string
: memchr
, memset
;
1239 import core
.sys
.posix
.netdb
: EAI_NONAME
, NI_NAMEREQD
, getnameinfo
;
1240 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1241 import core
.sys
.posix
.sys
.socket
: AF_INET
;
1242 import core
.sys
.posix
.sys
.socket
: sockaddr
;
1245 sockaddr_in sin
= void;
1246 memset(&sin
, 0, sockaddr_in
.sizeof
);
1247 sin
.sin_family
= AF_INET
;
1248 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1249 sin
.sin_addr
.s_addr
= address
.host
;
1250 err
= getnameinfo(cast(sockaddr
*)&sin
, sin
.sizeof
, name
, cast(uint)nameLength
, null, 0, NI_NAMEREQD
); // crude x86_64 fix
1252 if (name
!is null && nameLength
> 0 && !memchr(name
, 0, nameLength
)) return -1;
1255 if (err
!= EAI_NONAME
) return 0;
1256 return enet_address_get_host_ip(address
, name
, nameLength
);
1260 int enet_socket_bind (ENetSocket socket
, const ENetAddress
* address
) {
1261 import core
.stdc
.string
: memset
;
1262 import core
.sys
.posix
.netinet
.in_
: INADDR_ANY
, sockaddr_in
;
1263 import core
.sys
.posix
.sys
.socket
: AF_INET
, bind
, sockaddr
;
1265 sockaddr_in sin
= void;
1266 memset(&sin
, 0, sockaddr_in
.sizeof
);
1267 sin
.sin_family
= AF_INET
;
1268 if (address
!is null) {
1269 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1270 sin
.sin_addr
.s_addr
= address
.host
;
1273 sin
.sin_addr
.s_addr
= INADDR_ANY
;
1275 return bind(socket
, cast(sockaddr
*)&sin
, sockaddr_in
.sizeof
);
1279 int enet_socket_get_address (ENetSocket socket
, ENetAddress
* address
) {
1280 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1281 import core
.sys
.posix
.sys
.socket
: getsockname
, sockaddr
, socklen_t
;
1283 sockaddr_in sin
= void;
1284 socklen_t sinLength
= sockaddr_in
.sizeof
;
1285 if (getsockname(socket
, cast(sockaddr
*)&sin
, &sinLength
) == -1) return -1;
1286 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
1287 address
.port
= ENET_NET_TO_HOST_16(sin
.sin_port
);
1292 int enet_socket_listen (ENetSocket socket
, int backlog
) {
1293 import core
.sys
.posix
.sys
.socket
: SOMAXCONN
, listen
;
1294 return listen(socket
, (backlog
< 0 ? SOMAXCONN
: backlog
));
1298 ENetSocket
enet_socket_create (ENetSocketType type
) {
1299 import core
.sys
.posix
.sys
.socket
: AF_INET
, SOCK_DGRAM
, SOCK_STREAM
, socket
;
1300 return socket(AF_INET
, (type
== ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM
: SOCK_STREAM
), 0);
1304 int enet_socket_set_option (ENetSocket socket
, ENetSocketOption option
, int value
) {
1305 import core
.sys
.posix
.fcntl
: F_GETFL
, F_SETFL
, O_NONBLOCK
, fcntl
;
1306 import core
.sys
.posix
.netinet
.in_
: IPPROTO_TCP
;
1307 import core
.sys
.posix
.netinet
.tcp
: TCP_NODELAY
;
1308 import core
.sys
.posix
.sys
.socket
: SOL_SOCKET
, SO_BROADCAST
, SO_REUSEADDR
, SO_RCVBUF
, SO_SNDBUF
,
1309 SO_RCVTIMEO
, SO_SNDTIMEO
, setsockopt
;
1310 import core
.sys
.posix
.sys
.time
: timeval
;
1312 timeval timeVal
= void;
1315 case ENET_SOCKOPT_NONBLOCK
:
1316 result
= fcntl(socket
, F_SETFL
, (value ? O_NONBLOCK
: 0)|
(fcntl(socket
, F_GETFL
)&~O_NONBLOCK
));
1318 case ENET_SOCKOPT_BROADCAST
:
1319 result
= setsockopt(socket
, SOL_SOCKET
, SO_BROADCAST
, cast(void*)&value
, int.sizeof
);
1321 case ENET_SOCKOPT_REUSEADDR
:
1322 result
= setsockopt(socket
, SOL_SOCKET
, SO_REUSEADDR
, cast(void*)&value
, int.sizeof
);
1324 case ENET_SOCKOPT_RCVBUF
:
1325 result
= setsockopt(socket
, SOL_SOCKET
, SO_RCVBUF
, cast(void*)&value
, int.sizeof
);
1327 case ENET_SOCKOPT_SNDBUF
:
1328 result
= setsockopt(socket
, SOL_SOCKET
, SO_SNDBUF
, cast(void*)&value
, int.sizeof
);
1330 case ENET_SOCKOPT_RCVTIMEO
:
1331 timeVal
.tv_sec
= value
/1000;
1332 timeVal
.tv_usec
= (value
%1000)*1000;
1333 result
= setsockopt(socket
, SOL_SOCKET
, SO_RCVTIMEO
, cast(void*)&timeVal
, timeval
.sizeof
);
1335 case ENET_SOCKOPT_SNDTIMEO
:
1336 timeVal
.tv_sec
= value
/1000;
1337 timeVal
.tv_usec
= (value
%1000)*1000;
1338 result
= setsockopt(socket
, SOL_SOCKET
, SO_SNDTIMEO
, cast(void*)&timeVal
, timeval
.sizeof
);
1340 case ENET_SOCKOPT_NODELAY
:
1341 result
= setsockopt(socket
, IPPROTO_TCP
, TCP_NODELAY
, cast(void*)&value
, int.sizeof
);
1346 return (result
== -1 ?
-1 : 0);
1350 int enet_socket_get_option (ENetSocket socket
, ENetSocketOption option
, int* value
) {
1351 import core
.sys
.posix
.sys
.socket
: SO_ERROR
, SOL_SOCKET
, getsockopt
, socklen_t
;
1355 case ENET_SOCKOPT_ERROR
:
1357 result
= getsockopt(socket
, SOL_SOCKET
, SO_ERROR
, value
, &len
);
1362 return (result
== -1 ?
-1 : 0);
1366 int enet_socket_connect (ENetSocket socket
, const ENetAddress
* address
) {
1367 import core
.stdc
.string
: memset
;
1368 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1369 import core
.sys
.posix
.sys
.socket
: AF_INET
, connect
, sockaddr
;
1372 sockaddr_in sin
= void;
1373 memset(&sin
, 0, sockaddr_in
.sizeof
);
1375 sin
.sin_family
= AF_INET
;
1376 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1377 sin
.sin_addr
.s_addr
= address
.host
;
1379 result
= connect(socket
, cast(sockaddr
*)&sin
, sockaddr_in
.sizeof
);
1381 import core
.stdc
.errno
: errno
, EINPROGRESS
;
1382 if (errno
== EINPROGRESS
) return 0;
1389 ENetSocket
enet_socket_accept (ENetSocket socket
, ENetAddress
* address
) {
1390 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1391 import core
.sys
.posix
.sys
.socket
: AF_INET
, accept
, sockaddr
, socklen_t
;
1394 sockaddr_in sin
= void;
1395 socklen_t sinLength
= sockaddr_in
.sizeof
;
1397 result
= accept(socket
, (address
!is null ?
cast(sockaddr
*)&sin
: null), (address
!is null ?
&sinLength
: null));
1398 if (result
== -1) return ENET_SOCKET_NULL
;
1400 if (address
!is null) {
1401 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
1402 address
.port
= ENET_NET_TO_HOST_16(sin
.sin_port
);
1409 int enet_socket_shutdown (ENetSocket socket
, ENetSocketShutdown how
) {
1410 import core
.sys
.posix
.sys
.socket
: shutdown
;
1411 return shutdown(socket
, cast(int)how
);
1415 void enet_socket_destroy (ENetSocket socket
) {
1416 import core
.sys
.posix
.unistd
: close
;
1417 if (socket
>= 0) close(socket
);
1421 int enet_socket_send (ENetSocket socket
, const ENetAddress
* address
, const(ENetBuffer
)* buffers
, usize bufferCount
) {
1422 import core
.stdc
.string
: memset
;
1423 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1424 import core
.sys
.posix
.sys
.socket
: AF_INET
, MSG_NOSIGNAL
, msghdr
, sendmsg
;
1425 import core
.sys
.posix
.sys
.uio
: iovec
;
1427 msghdr msgHdr
= void;
1428 sockaddr_in sin
= void;
1431 memset(& msgHdr
, 0, msghdr
.sizeof
);
1432 if (address
!is null) {
1433 memset(&sin
, 0, sockaddr_in
.sizeof
);
1435 sin
.sin_family
= AF_INET
;
1436 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1437 sin
.sin_addr
.s_addr
= address
.host
;
1439 msgHdr
.msg_name
= &sin
;
1440 msgHdr
.msg_namelen
= sockaddr_in
.sizeof
;
1443 msgHdr
.msg_iov
= cast(iovec
*)buffers
;
1444 msgHdr
.msg_iovlen
= bufferCount
;
1446 sentLength
= cast(uint)sendmsg(socket
, &msgHdr
, MSG_NOSIGNAL
); // crude x86_64 fix
1448 if (sentLength
== -1) {
1449 import core
.stdc
.errno
: errno
, EWOULDBLOCK
;
1450 if (errno
== EWOULDBLOCK
) return 0;
1458 int enet_socket_receive (ENetSocket socket
, ENetAddress
* address
, ENetBuffer
* buffers
, usize bufferCount
) {
1459 import core
.stdc
.string
: memset
;
1460 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1461 import core
.sys
.posix
.sys
.socket
: MSG_NOSIGNAL
, MSG_TRUNC
, msghdr
, recvmsg
;
1462 import core
.sys
.posix
.sys
.uio
: iovec
;
1464 msghdr msgHdr
= void;
1468 memset(&msgHdr
, 0, msghdr
.sizeof
);
1470 if (address
!is null) {
1471 msgHdr
.msg_name
= &sin
;
1472 msgHdr
.msg_namelen
= sockaddr_in
.sizeof
;
1475 msgHdr
.msg_iov
= cast(iovec
*)buffers
;
1476 msgHdr
.msg_iovlen
= bufferCount
;
1478 recvLength
= cast(uint)recvmsg(socket
, &msgHdr
, MSG_NOSIGNAL
); // crude x86_64 fix
1480 if (recvLength
== -1) {
1481 import core
.stdc
.errno
: errno
, EWOULDBLOCK
;
1482 if (errno
== EWOULDBLOCK
) return 0;
1486 if (msgHdr
.msg_flags
&MSG_TRUNC
) return -1;
1488 if (address
!is null) {
1489 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
1490 address
.port
= ENET_NET_TO_HOST_16(sin
.sin_port
);
1497 int enet_socketset_select (ENetSocket maxSocket
, ENetSocketSet
* readSet
, ENetSocketSet
* writeSet
, enet_uint32 timeout
) {
1498 import core
.sys
.posix
.sys
.time
: timeval
;
1499 import core
.sys
.posix
.sys
.select
: select
;
1501 timeval timeVal
= void;
1502 timeVal
.tv_sec
= timeout
/1000;
1503 timeVal
.tv_usec
= (timeout
%1000)*1000;
1504 return select(maxSocket
+1, readSet
, writeSet
, null, &timeVal
);
1508 int enet_socket_wait (ENetSocket socket
, enet_uint32
* condition
, enet_uint32 timeout
) {
1509 import core
.sys
.posix
.poll
: POLLIN
, POLLOUT
, poll
, pollfd
;
1511 pollfd pollSocket
= void;
1514 pollSocket
.fd
= socket
;
1515 pollSocket
.events
= 0;
1517 if ((*condition
)&ENET_SOCKET_WAIT_SEND
) pollSocket
.events |
= POLLOUT
;
1518 if ((*condition
)&ENET_SOCKET_WAIT_RECEIVE
) pollSocket
.events |
= POLLIN
;
1520 pollCount
= poll(&pollSocket
, 1, timeout
);
1522 if (pollCount
< 0) {
1523 import core
.stdc
.errno
: errno
, EINTR
;
1524 if (errno
== EINTR
&& (*condition
)&ENET_SOCKET_WAIT_INTERRUPT
) {
1525 *condition
= ENET_SOCKET_WAIT_INTERRUPT
;
1531 *condition
= ENET_SOCKET_WAIT_NONE
;
1533 if (pollCount
== 0) return 0;
1535 if (pollSocket
.revents
&POLLOUT
) *condition |
= ENET_SOCKET_WAIT_SEND
;
1536 if (pollSocket
.revents
&POLLIN
) *condition |
= ENET_SOCKET_WAIT_RECEIVE
;
1545 private __gshared ENetCallbacks callbacks
;
1548 shared static this () @nogc {
1549 static import core
.stdc
.stdlib
;
1550 callbacks
.malloc
= &core
.stdc
.stdlib
.malloc
;
1551 callbacks
.free
= &core
.stdc
.stdlib
.free
;
1552 callbacks
.no_memory
= &core
.stdc
.stdlib
.abort
; //FIXME
1556 int enet_initialize_with_callbacks (ENetVersion version_
, const ENetCallbacks
* inits
) nothrow @nogc {
1557 if (version_
< ENET_VERSION_CREATE(1, 3, 0)) return -1;
1558 if (inits
.malloc
!is null || inits
.free
!is null) {
1559 if (inits
.malloc
is null || inits
.free
is null) return -1;
1560 callbacks
.malloc
= inits
.malloc
;
1561 callbacks
.free
= inits
.free
;
1563 if (inits
.no_memory
!is null) callbacks
.no_memory
= inits
.no_memory
;
1564 return enet_initialize();
1568 ENetVersion
enet_linked_version () nothrow @nogc {
1569 return ENET_VERSION
;
1573 void* enet_malloc (usize size
) nothrow {
1574 void* memory
= callbacks
.malloc(size
);
1575 if (memory
is null) callbacks
.no_memory();
1580 void enet_free (void* memory
) nothrow {
1581 callbacks
.free(memory
);
1587 extern(C
) @nogc nothrow {
1588 alias ENetListIterator
= ENetListNode
*;
1592 ENetListIterator
enet_list_begin (ENetList
* list
) {
1593 pragma(inline
, true);
1594 return list
.sentinel
.next
;
1597 ENetListIterator
enet_list_end (ENetList
* list
) {
1598 pragma(inline
, true);
1599 return &list
.sentinel
;
1602 bool enet_list_empty (ENetList
* list
) {
1603 pragma(inline
, true);
1604 return enet_list_begin(list
) == enet_list_end(list
);
1607 ENetListIterator
enet_list_next (ENetListIterator iterator
) {
1608 pragma(inline
, true);
1609 return iterator
.next
;
1612 ENetListIterator
enet_list_previous (ENetListIterator iterator
) {
1613 pragma(inline
, true);
1614 return iterator
.previous
;
1617 void* enet_list_front (ENetList
* list
) {
1618 pragma(inline
, true);
1619 return cast(void*)(list
.sentinel
.next
);
1622 void* enet_list_back (ENetList
* list
) {
1623 pragma(inline
, true);
1624 return cast(void*)(list
.sentinel
.previous
);
1629 @defgroup list ENet linked list utility functions
1633 void enet_list_clear (ENetList
* list
) {
1634 list
.sentinel
.next
= &list
.sentinel
;
1635 list
.sentinel
.previous
= &list
.sentinel
;
1638 ENetListIterator
enet_list_insert (ENetListIterator position
, void* data
) {
1639 ENetListIterator result
= cast(ENetListIterator
)data
;
1641 result
.previous
= position
.previous
;
1642 result
.next
= position
;
1644 result
.previous
.next
= result
;
1645 position
.previous
= result
;
1650 void* enet_list_remove (ENetListIterator position
) {
1651 position
.previous
.next
= position
.next
;
1652 position
.next
.previous
= position
.previous
;
1656 ENetListIterator
enet_list_move (ENetListIterator position
, void * dataFirst
, void * dataLast
) {
1657 ENetListIterator first
= cast(ENetListIterator
)dataFirst
;
1658 ENetListIterator last
= cast(ENetListIterator
)dataLast
;
1660 first
.previous
.next
= last
.next
;
1661 last
.next
.previous
= first
.previous
;
1663 first
.previous
= position
.previous
;
1664 last
.next
= position
;
1666 first
.previous
.next
= first
;
1667 position
.previous
= last
;
1672 usize
enet_list_size (ENetList
* list
) {
1674 ENetListIterator position
;
1675 for (position
= enet_list_begin(list
); position
!= enet_list_end(list
); position
= enet_list_next(position
)) ++size
;
1683 /** Creates a packet that may be sent to a peer.
1686 * data = initial contents of the packet's data; the packet's data will remain uninitialized if data is null
1687 * dataLength = size of the data allocated for this packet
1688 * flags = flags for this packet as described for the ENetPacket structure
1691 * the packet on success, null on failure
1693 ENetPacket
* enet_packet_create (const(void)* data
, usize dataLength
, enet_uint32 flags
) {
1694 ENetPacket
* packet
= cast(ENetPacket
*)enet_malloc(ENetPacket
.sizeof
);
1695 if (packet
is null) return null;
1697 if (flags
&ENET_PACKET_FLAG_NO_ALLOCATE
) {
1698 packet
.data
= cast(enet_uint8
*)data
;
1699 } else if (dataLength
<= 0) {
1702 packet
.data
= cast(enet_uint8
*)enet_malloc(dataLength
);
1703 if (packet
.data
is null) {
1707 if (data
!is null) {
1708 import core
.stdc
.string
: memcpy
;
1709 memcpy(packet
.data
, data
, dataLength
);
1714 packet
.referenceCount
= 0;
1715 packet
.flags
= flags
;
1716 packet
.dataLength
= dataLength
;
1717 packet
.freeCallback
= null;
1718 packet
.userData
= null;
1724 /** Destroys the packet and deallocates its data.
1727 * packet = packet to be destroyed
1729 void enet_packet_destroy (ENetPacket
* packet
) {
1730 if (packet
is null) return;
1731 if (packet
.freeCallback
!is null) (*packet
.freeCallback
)(packet
);
1732 if (!(packet
.flags
&ENET_PACKET_FLAG_NO_ALLOCATE
) && packet
.data
!is null) enet_free(packet
.data
);
1737 /** Attempts to resize the data in the packet to length specified in the dataLength parameter.
1740 * packet = packet to resize
1741 * dataLength = new size for the packet data
1744 * 0 on success, < 0 on failure
1746 int enet_packet_resize (ENetPacket
* packet
, usize dataLength
) {
1747 import core
.stdc
.string
: memcpy
;
1749 enet_uint8
* newData
;
1751 if (dataLength
<= packet
.dataLength ||
(packet
.flags
&ENET_PACKET_FLAG_NO_ALLOCATE
)) {
1752 packet
.dataLength
= dataLength
;
1756 newData
= cast(enet_uint8
*) enet_malloc(dataLength
);
1757 if (newData
is null) return -1;
1759 memcpy(newData
, packet
.data
, packet
.dataLength
);
1760 enet_free(packet
.data
);
1762 packet
.data
= newData
;
1763 packet
.dataLength
= dataLength
;
1769 private immutable enet_uint32
[256] crcTable
= (() {
1770 enet_uint32
reflect_crc (int val
, int bits
) {
1771 int result
= 0, bit
;
1772 for (bit
= 0; bit
< bits
; ++bit
) {
1773 if (val
&1) result |
= 1<<(bits
-1-bit
);
1779 enet_uint32
[256] crcTable
;
1780 for (int bt = 0; bt < 256; ++bt) {
1781 enet_uint32 crc
= reflect_crc(bt, 8)<<24;
1782 for (int offset
= 0; offset
< 8; ++offset
) {
1783 if (crc
&0x80000000u
) crc
= (crc
<<1)^
0x04c11db7u
; else crc
<<= 1;
1785 crcTable
[bt] = reflect_crc (crc
, 32);
1791 enet_uint32
enet_crc32 (const(ENetBuffer
)* buffers
, usize bufferCount
) pure @nogc {
1792 enet_uint32 crc
= 0xFFFFFFFF;
1793 while (bufferCount
-- > 0) {
1794 auto data
= cast(const(enet_uint8
)*)buffers
.data
;
1795 auto dataEnd
= data
+buffers
.dataLength
;
1796 while (data
< dataEnd
) crc
= (crc
>>8)^crcTable
[(crc
&0xFF)^
*data
++];
1799 return ENET_HOST_TO_NET_32(~crc
);
1806 /** Configures throttle parameter for a peer.
1808 * Unreliable packets are dropped by ENet in response to the varying conditions
1809 * of the Internet connection to the peer. The throttle represents a probability
1810 * that an unreliable packet should not be dropped and thus sent by ENet to the peer.
1811 * The lowest mean round trip time from the sending of a reliable packet to the
1812 * receipt of its acknowledgement is measured over an amount of time specified by
1813 * the interval parameter in milliseconds. If a measured round trip time happens to
1814 * be significantly less than the mean round trip time measured over the interval,
1815 * then the throttle probability is increased to allow more traffic by an amount
1816 * specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE
1817 * constant. If a measured round trip time happens to be significantly greater than
1818 * the mean round trip time measured over the interval, then the throttle probability
1819 * is decreased to limit traffic by an amount specified in the deceleration parameter, which
1820 * is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant. When the throttle has
1821 * a value of ENET_PEER_PACKET_THROTTLE_SCALE, no unreliable packets are dropped by
1822 * ENet, and so 100% of all unreliable packets will be sent. When the throttle has a
1823 * value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable
1824 * packets will be sent. Intermediate values for the throttle represent intermediate
1825 * probabilities between 0% and 100% of unreliable packets being sent. The bandwidth
1826 * limits of the local and foreign hosts are taken into account to determine a
1827 * sensible limit for the throttle probability above which it should not raise even in
1828 * the best of conditions.
1831 * peer = peer to configure
1832 * interval = interval, in milliseconds, over which to measure lowest mean RTT; the default value is ENET_PEER_PACKET_THROTTLE_INTERVAL.
1833 * acceleration = rate at which to increase the throttle probability as mean RTT declines
1834 * deceleration = rate at which to decrease the throttle probability as mean RTT increases
1836 void enet_peer_throttle_configure (ENetPeer
* peer
, enet_uint32 interval
, enet_uint32 acceleration
, enet_uint32 deceleration
) {
1837 ENetProtocol command
;
1839 peer
.packetThrottleInterval
= interval
;
1840 peer
.packetThrottleAcceleration
= acceleration
;
1841 peer
.packetThrottleDeceleration
= deceleration
;
1843 command
.header
.command
= ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
1844 command
.header
.channelID
= 0xFF;
1846 command
.throttleConfigure
.packetThrottleInterval
= ENET_HOST_TO_NET_32 (interval
);
1847 command
.throttleConfigure
.packetThrottleAcceleration
= ENET_HOST_TO_NET_32 (acceleration
);
1848 command
.throttleConfigure
.packetThrottleDeceleration
= ENET_HOST_TO_NET_32 (deceleration
);
1850 enet_peer_queue_outgoing_command(peer
, &command
, null, 0, 0);
1854 int enet_peer_throttle (ENetPeer
* peer
, enet_uint32 rtt
) @nogc {
1855 if (peer
.lastRoundTripTime
<= peer
.lastRoundTripTimeVariance
) {
1856 peer
.packetThrottle
= peer
.packetThrottleLimit
;
1857 } else if (rtt
< peer
.lastRoundTripTime
) {
1858 peer
.packetThrottle
+= peer
.packetThrottleAcceleration
;
1859 if (peer
.packetThrottle
> peer
.packetThrottleLimit
) peer
.packetThrottle
= peer
.packetThrottleLimit
;
1861 } else if (rtt
> peer
.lastRoundTripTime
+2*peer
.lastRoundTripTimeVariance
) {
1862 if (peer
.packetThrottle
> peer
.packetThrottleDeceleration
) {
1863 peer
.packetThrottle
-= peer
.packetThrottleDeceleration
;
1865 peer
.packetThrottle
= 0;
1873 /** Queues a packet to be sent.
1876 * peer = destination for the packet
1877 * channelID = channel on which to send
1878 * packet = packet to send
1881 * 0 on success, < 0 on failure
1883 int enet_peer_send (ENetPeer
* peer
, enet_uint8 channelID
, ENetPacket
* packet
) {
1884 ENetChannel
* channel
= &peer
.channels
[channelID
];
1885 ENetProtocol command
;
1886 usize fragmentLength
;
1888 if (peer
.state
!= ENET_PEER_STATE_CONNECTED || channelID
>= peer
.channelCount || packet
.dataLength
> peer
.host
.maximumPacketSize
) return -1;
1890 fragmentLength
= peer
.mtu
-ENetProtocolHeader
.sizeof
-ENetProtocolSendFragment
.sizeof
;
1891 if (peer
.host
.checksum
!is null) fragmentLength
-= enet_uint32
.sizeof
;
1893 if (packet
.dataLength
> fragmentLength
) {
1894 enet_uint32 fragmentCount
= cast(uint)((packet
.dataLength
+fragmentLength
-1)/fragmentLength
);
1895 enet_uint32 fragmentNumber
, fragmentOffset
;
1896 enet_uint8 commandNumber
;
1897 enet_uint16 startSequenceNumber
;
1899 ENetOutgoingCommand
* fragment
;
1901 if (fragmentCount
> ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT
) return -1;
1903 if ((packet
.flags
&(ENET_PACKET_FLAG_RELIABLE|ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT
)) == ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT
&& channel
.outgoingUnreliableSequenceNumber
< 0xFFFF) {
1904 commandNumber
= ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT
;
1905 startSequenceNumber
= ENET_HOST_TO_NET_16(cast(ushort)(channel
.outgoingUnreliableSequenceNumber
+1));
1907 commandNumber
= ENET_PROTOCOL_COMMAND_SEND_FRAGMENT|ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
1908 startSequenceNumber
= ENET_HOST_TO_NET_16(cast(ushort)(channel
.outgoingReliableSequenceNumber
+1));
1911 enet_list_clear(&fragments
);
1913 for (fragmentNumber
= 0, fragmentOffset
= 0; fragmentOffset
< packet
.dataLength
; ++fragmentNumber
, fragmentOffset
+= fragmentLength
) {
1914 if (packet
.dataLength
-fragmentOffset
< fragmentLength
) fragmentLength
= packet
.dataLength
-fragmentOffset
;
1916 fragment
= cast(ENetOutgoingCommand
*)enet_malloc(ENetOutgoingCommand
.sizeof
);
1917 if (fragment
is null) {
1918 while (!enet_list_empty(&fragments
)) {
1919 fragment
= cast(ENetOutgoingCommand
*)enet_list_remove(enet_list_begin(&fragments
));
1920 enet_free(fragment
);
1925 fragment
.fragmentOffset
= fragmentOffset
;
1926 fragment
.fragmentLength
= cast(ushort)fragmentLength
;
1927 fragment
.packet
= packet
;
1928 fragment
.command
.header
.command
= commandNumber
;
1929 fragment
.command
.header
.channelID
= channelID
;
1930 fragment
.command
.sendFragment
.startSequenceNumber
= startSequenceNumber
;
1931 fragment
.command
.sendFragment
.dataLength
= ENET_HOST_TO_NET_16(cast(ushort)fragmentLength
);
1932 fragment
.command
.sendFragment
.fragmentCount
= ENET_HOST_TO_NET_32(fragmentCount
);
1933 fragment
.command
.sendFragment
.fragmentNumber
= ENET_HOST_TO_NET_32(fragmentNumber
);
1934 fragment
.command
.sendFragment
.totalLength
= ENET_HOST_TO_NET_32(cast(uint)packet
.dataLength
);
1935 fragment
.command
.sendFragment
.fragmentOffset
= ENET_NET_TO_HOST_32(fragmentOffset
);
1937 enet_list_insert(enet_list_end(&fragments
), fragment
);
1940 packet
.referenceCount
+= fragmentNumber
;
1942 while (!enet_list_empty(&fragments
)) {
1943 fragment
= cast(ENetOutgoingCommand
*)enet_list_remove(enet_list_begin(&fragments
));
1944 enet_peer_setup_outgoing_command(peer
, fragment
);
1950 command
.header
.channelID
= channelID
;
1952 if ((packet
.flags
&(ENET_PACKET_FLAG_RELIABLE|ENET_PACKET_FLAG_UNSEQUENCED
)) == ENET_PACKET_FLAG_UNSEQUENCED
) {
1953 command
.header
.command
= ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED|ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED
;
1954 command
.sendUnsequenced
.dataLength
= ENET_HOST_TO_NET_16(cast(ushort)packet
.dataLength
);
1955 } else if (packet
.flags
&ENET_PACKET_FLAG_RELIABLE || channel
.outgoingUnreliableSequenceNumber
>= 0xFFFF) {
1956 command
.header
.command
= ENET_PROTOCOL_COMMAND_SEND_RELIABLE|ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
1957 command
.sendReliable
.dataLength
= ENET_HOST_TO_NET_16(cast(ushort)packet
.dataLength
);
1959 command
.header
.command
= ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE
;
1960 command
.sendUnreliable
.dataLength
= ENET_HOST_TO_NET_16(cast(ushort)packet
.dataLength
);
1963 if (enet_peer_queue_outgoing_command(peer
, &command
, packet
, 0, cast(ushort)packet
.dataLength
) is null) return -1;
1969 /** Attempts to dequeue any incoming queued packet.
1972 * peer = peer to dequeue packets from
1973 * channelID = holds the channel ID of the channel the packet was received on success
1976 * returns a pointer to the packet, or null if there are no available incoming queued packets
1978 ENetPacket
* enet_peer_receive (ENetPeer
* peer
, enet_uint8
* channelID
) {
1979 ENetIncomingCommand
* incomingCommand
;
1982 if (enet_list_empty(&peer
.dispatchedCommands
)) return null;
1983 incomingCommand
= cast(ENetIncomingCommand
*)enet_list_remove(enet_list_begin(&peer
.dispatchedCommands
));
1984 if (channelID
!is null) *channelID
= incomingCommand
.command
.header
.channelID
;
1985 packet
= incomingCommand
.packet
;
1986 --packet
.referenceCount
;
1987 if (incomingCommand
.fragments
!is null) enet_free(incomingCommand
.fragments
);
1988 enet_free(incomingCommand
);
1989 peer
.totalWaitingData
-= packet
.dataLength
;
1995 private void enet_peer_reset_outgoing_commands (ENetList
* queue
) {
1996 ENetOutgoingCommand
* outgoingCommand
;
1997 while (!enet_list_empty(queue
)) {
1998 outgoingCommand
= cast(ENetOutgoingCommand
*)enet_list_remove(enet_list_begin(queue
));
1999 if (outgoingCommand
.packet
!is null) {
2000 --outgoingCommand
.packet
.referenceCount
;
2001 if (outgoingCommand
.packet
.referenceCount
== 0) enet_packet_destroy(outgoingCommand
.packet
);
2003 enet_free(outgoingCommand
);
2008 private void enet_peer_remove_incoming_commands (ENetList
* queue
, ENetListIterator startCommand
, ENetListIterator endCommand
) {
2009 ENetListIterator currentCommand
;
2010 for (currentCommand
= startCommand
; currentCommand
!= endCommand
; ) {
2011 ENetIncomingCommand
* incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
2012 currentCommand
= enet_list_next(currentCommand
);
2013 enet_list_remove(&incomingCommand
.incomingCommandList
);
2014 if (incomingCommand
.packet
!is null) {
2015 --incomingCommand
.packet
.referenceCount
;
2016 if (incomingCommand
.packet
.referenceCount
== 0) enet_packet_destroy(incomingCommand
.packet
);
2018 if (incomingCommand
.fragments
!is null) enet_free(incomingCommand
.fragments
);
2019 enet_free(incomingCommand
);
2024 private void enet_peer_reset_incoming_commands (ENetList
* queue
) {
2025 enet_peer_remove_incoming_commands(queue
, enet_list_begin(queue
), enet_list_end(queue
));
2029 void enet_peer_reset_queues (ENetPeer
* peer
) {
2030 ENetChannel
* channel
;
2032 if (peer
.needsDispatch
) {
2033 enet_list_remove(&peer
.dispatchList
);
2034 peer
.needsDispatch
= false;
2037 while (!enet_list_empty(&peer
.acknowledgements
)) enet_free(enet_list_remove(enet_list_begin(&peer
.acknowledgements
)));
2039 enet_peer_reset_outgoing_commands(&peer
.sentReliableCommands
);
2040 enet_peer_reset_outgoing_commands(&peer
.sentUnreliableCommands
);
2041 enet_peer_reset_outgoing_commands(&peer
.outgoingReliableCommands
);
2042 enet_peer_reset_outgoing_commands(&peer
.outgoingUnreliableCommands
);
2043 enet_peer_reset_incoming_commands(&peer
.dispatchedCommands
);
2045 if (peer
.channels
!is null && peer
.channelCount
> 0) {
2046 for (channel
= peer
.channels
; channel
< &peer
.channels
[peer
.channelCount
]; ++channel
) {
2047 enet_peer_reset_incoming_commands(&channel
.incomingReliableCommands
);
2048 enet_peer_reset_incoming_commands(&channel
.incomingUnreliableCommands
);
2050 enet_free(peer
.channels
);
2053 peer
.channels
= null;
2054 peer
.channelCount
= 0;
2058 void enet_peer_on_connect (ENetPeer
* peer
) @nogc {
2059 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) {
2060 if (peer
.incomingBandwidth
!= 0) ++peer
.host
.bandwidthLimitedPeers
;
2061 ++peer
.host
.connectedPeers
;
2066 void enet_peer_on_disconnect (ENetPeer
* peer
) @nogc {
2067 if (peer
.state
== ENET_PEER_STATE_CONNECTED || peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
) {
2068 if (peer
.incomingBandwidth
!= 0) --peer
.host
.bandwidthLimitedPeers
;
2069 --peer
.host
.connectedPeers
;
2074 /** Forcefully disconnects a peer.
2077 * peer = peer to forcefully disconnect
2080 * The foreign host represented by the peer is not notified of the disconnection and will timeout
2081 * on its connection to the local host.
2083 void enet_peer_reset (ENetPeer
* peer
) {
2084 import core
.stdc
.string
: memset
;
2086 enet_peer_on_disconnect(peer
);
2088 peer
.outgoingPeerID
= ENET_PROTOCOL_MAXIMUM_PEER_ID
;
2091 peer
.state
= ENET_PEER_STATE_DISCONNECTED
;
2093 peer
.incomingBandwidth
= 0;
2094 peer
.outgoingBandwidth
= 0;
2095 peer
.incomingBandwidthThrottleEpoch
= 0;
2096 peer
.outgoingBandwidthThrottleEpoch
= 0;
2097 peer
.incomingDataTotal
= 0;
2098 peer
.outgoingDataTotal
= 0;
2099 peer
.lastSendTime
= 0;
2100 peer
.lastReceiveTime
= 0;
2101 peer
.nextTimeout
= 0;
2102 peer
.earliestTimeout
= 0;
2103 peer
.packetLossEpoch
= 0;
2104 peer
.packetsSent
= 0;
2105 peer
.packetsLost
= 0;
2106 peer
.packetLoss
= 0;
2107 peer
.packetLossVariance
= 0;
2108 peer
.packetThrottle
= ENET_PEER_DEFAULT_PACKET_THROTTLE
;
2109 peer
.packetThrottleLimit
= ENET_PEER_PACKET_THROTTLE_SCALE
;
2110 peer
.packetThrottleCounter
= 0;
2111 peer
.packetThrottleEpoch
= 0;
2112 peer
.packetThrottleAcceleration
= ENET_PEER_PACKET_THROTTLE_ACCELERATION
;
2113 peer
.packetThrottleDeceleration
= ENET_PEER_PACKET_THROTTLE_DECELERATION
;
2114 peer
.packetThrottleInterval
= ENET_PEER_PACKET_THROTTLE_INTERVAL
;
2115 peer
.pingInterval
= ENET_PEER_PING_INTERVAL
;
2116 peer
.timeoutLimit
= ENET_PEER_TIMEOUT_LIMIT
;
2117 peer
.timeoutMinimum
= ENET_PEER_TIMEOUT_MINIMUM
;
2118 peer
.timeoutMaximum
= ENET_PEER_TIMEOUT_MAXIMUM
;
2119 peer
.lastRoundTripTime
= ENET_PEER_DEFAULT_ROUND_TRIP_TIME
;
2120 peer
.lowestRoundTripTime
= ENET_PEER_DEFAULT_ROUND_TRIP_TIME
;
2121 peer
.lastRoundTripTimeVariance
= 0;
2122 peer
.highestRoundTripTimeVariance
= 0;
2123 peer
.roundTripTime
= ENET_PEER_DEFAULT_ROUND_TRIP_TIME
;
2124 peer
.roundTripTimeVariance
= 0;
2125 peer
.mtu
= peer
.host
.mtu
;
2126 peer
.reliableDataInTransit
= 0;
2127 peer
.outgoingReliableSequenceNumber
= 0;
2128 peer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
2129 peer
.incomingUnsequencedGroup
= 0;
2130 peer
.outgoingUnsequencedGroup
= 0;
2132 peer
.totalWaitingData
= 0;
2134 memset(peer
.unsequencedWindow
.ptr
, 0, peer
.unsequencedWindow
.sizeof
);
2136 enet_peer_reset_queues(peer
);
2140 /** Sends a ping request to a peer.
2143 * peer = destination for the ping request
2146 * ping requests factor into the mean round trip time as designated by the
2147 * roundTripTime field in the ENetPeer structure. ENet automatically pings all connected
2148 * peers at regular intervals, however, this function may be called to ensure more
2149 * frequent ping requests.
2151 void enet_peer_ping (ENetPeer
* peer
) {
2152 ENetProtocol command
;
2154 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
) return;
2156 command
.header
.command
= ENET_PROTOCOL_COMMAND_PING|ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
2157 command
.header
.channelID
= 0xFF;
2159 enet_peer_queue_outgoing_command(peer
, &command
, null, 0, 0);
2163 /** Sets the interval at which pings will be sent to a peer.
2165 * Pings are used both to monitor the liveness of the connection and also to dynamically
2166 * adjust the throttle during periods of low traffic so that the throttle has reasonable
2167 * responsiveness during traffic spikes.
2170 * peer = the peer to adjust
2171 * pingInterval = the interval at which to send pings; defaults to ENET_PEER_PING_INTERVAL if 0
2173 void enet_peer_ping_interval (ENetPeer
* peer
, enet_uint32 pingInterval
) @nogc {
2174 peer
.pingInterval
= (pingInterval ? pingInterval
: ENET_PEER_PING_INTERVAL
);
2178 /** Sets the timeout parameters for a peer.
2180 * The timeout parameter control how and when a peer will timeout from a failure to acknowledge
2181 * reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable
2182 * packet is not acknowledge within some multiple of the average RTT plus a variance tolerance,
2183 * the timeout will be doubled until it reaches a set limit. If the timeout is thus at this
2184 * limit and reliable packets have been sent but not acknowledged within a certain minimum time
2185 * period, the peer will be disconnected. Alternatively, if reliable packets have been sent
2186 * but not acknowledged for a certain maximum time period, the peer will be disconnected regardless
2187 * of the current timeout limit value.
2190 * peer = the peer to adjust
2191 * timeoutLimit = the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0
2192 * timeoutMinimum = the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0
2193 * timeoutMaximum = the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0
2195 void enet_peer_timeout (ENetPeer
* peer
, enet_uint32 timeoutLimit
, enet_uint32 timeoutMinimum
, enet_uint32 timeoutMaximum
) @nogc {
2196 peer
.timeoutLimit
= (timeoutLimit ? timeoutLimit
: ENET_PEER_TIMEOUT_LIMIT
);
2197 peer
.timeoutMinimum
= (timeoutMinimum ? timeoutMinimum
: ENET_PEER_TIMEOUT_MINIMUM
);
2198 peer
.timeoutMaximum
= (timeoutMaximum ? timeoutMaximum
: ENET_PEER_TIMEOUT_MAXIMUM
);
2202 /** Force an immediate disconnection from a peer.
2205 * peer = peer to disconnect
2206 * data = data describing the disconnection
2209 * No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not
2210 * guaranteed to receive the disconnect notification, and is reset immediately upon
2211 * return from this function.
2213 void enet_peer_disconnect_now (ENetPeer
* peer
, enet_uint32 data
) {
2214 ENetProtocol command
;
2216 if (peer
.state
== ENET_PEER_STATE_DISCONNECTED
) return;
2218 if (peer
.state
!= ENET_PEER_STATE_ZOMBIE
&& peer
.state
!= ENET_PEER_STATE_DISCONNECTING
) {
2219 enet_peer_reset_queues(peer
);
2221 command
.header
.command
= ENET_PROTOCOL_COMMAND_DISCONNECT|ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED
;
2222 command
.header
.channelID
= 0xFF;
2223 command
.disconnect
.data
= ENET_HOST_TO_NET_32(data
);
2225 enet_peer_queue_outgoing_command(peer
, &command
, null, 0, 0);
2227 enet_host_flush(peer
.host
);
2230 enet_peer_reset(peer
);
2234 /** Request a disconnection from a peer.
2237 * peer = peer to request a disconnection
2238 * data = data describing the disconnection
2241 * An ENET_EVENT_DISCONNECT event will be generated by enet_host_service()
2242 * once the disconnection is complete.
2244 void enet_peer_disconnect (ENetPeer
* peer
, enet_uint32 data
) {
2245 ENetProtocol command
;
2247 if (peer
.state
== ENET_PEER_STATE_DISCONNECTING ||
2248 peer
.state
== ENET_PEER_STATE_DISCONNECTED ||
2249 peer
.state
== ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT ||
2250 peer
.state
== ENET_PEER_STATE_ZOMBIE
)
2253 enet_peer_reset_queues(peer
);
2255 command
.header
.command
= ENET_PROTOCOL_COMMAND_DISCONNECT
;
2256 command
.header
.channelID
= 0xFF;
2257 command
.disconnect
.data
= ENET_HOST_TO_NET_32(data
);
2259 if (peer
.state
== ENET_PEER_STATE_CONNECTED || peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
) {
2260 command
.header
.command |
= ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
2262 command
.header
.command |
= ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED
;
2265 enet_peer_queue_outgoing_command(peer
, &command
, null, 0, 0);
2267 if (peer
.state
== ENET_PEER_STATE_CONNECTED || peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
) {
2268 enet_peer_on_disconnect(peer
);
2269 peer
.state
= ENET_PEER_STATE_DISCONNECTING
;
2271 enet_host_flush(peer
.host
);
2272 enet_peer_reset(peer
);
2277 /** Request a disconnection from a peer, but only after all queued outgoing packets are sent.
2280 * peer = peer to request a disconnection
2281 * data = data describing the disconnection
2284 * An ENET_EVENT_DISCONNECT event will be generated by enet_host_service()
2285 * once the disconnection is complete.
2287 void enet_peer_disconnect_later (ENetPeer
* peer
, enet_uint32 data
) {
2288 if ((peer
.state
== ENET_PEER_STATE_CONNECTED || peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
) &&
2289 !(enet_list_empty (& peer
.outgoingReliableCommands
) &&
2290 enet_list_empty (& peer
.outgoingUnreliableCommands
) &&
2291 enet_list_empty (& peer
.sentReliableCommands
)))
2293 peer
.state
= ENET_PEER_STATE_DISCONNECT_LATER
;
2294 peer
.eventData
= data
;
2296 enet_peer_disconnect(peer
, data
);
2301 ENetAcknowledgement
* enet_peer_queue_acknowledgement (ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint16 sentTime
) {
2302 ENetAcknowledgement
* acknowledgement
;
2304 if (command
.header
.channelID
< peer
.channelCount
) {
2305 ENetChannel
* channel
= &peer
.channels
[command
.header
.channelID
];
2306 enet_uint16 reliableWindow
= command
.header
.reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
2307 enet_uint16 currentWindow
= channel
.incomingReliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
2309 if (command
.header
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) reliableWindow
+= ENET_PEER_RELIABLE_WINDOWS
;
2310 if (reliableWindow
>= currentWindow
+ ENET_PEER_FREE_RELIABLE_WINDOWS
-1 && reliableWindow
<= currentWindow
+ENET_PEER_FREE_RELIABLE_WINDOWS
) return null;
2313 acknowledgement
= cast(ENetAcknowledgement
*)enet_malloc(ENetAcknowledgement
.sizeof
);
2314 if (acknowledgement
is null) return null;
2316 peer
.outgoingDataTotal
+= ENetProtocolAcknowledge
.sizeof
;
2318 acknowledgement
.sentTime
= sentTime
;
2319 acknowledgement
.command
= * command
;
2321 enet_list_insert(enet_list_end(&peer
.acknowledgements
), acknowledgement
);
2323 return acknowledgement
;
2327 void enet_peer_setup_outgoing_command (ENetPeer
* peer
, ENetOutgoingCommand
* outgoingCommand
) @nogc {
2328 ENetChannel
* channel
= &peer
.channels
[outgoingCommand
.command
.header
.channelID
];
2330 peer
.outgoingDataTotal
+= enet_protocol_command_size(outgoingCommand
.command
.header
.command
)+outgoingCommand
.fragmentLength
;
2332 if (outgoingCommand
.command
.header
.channelID
== 0xFF) {
2333 ++peer
.outgoingReliableSequenceNumber
;
2334 outgoingCommand
.reliableSequenceNumber
= peer
.outgoingReliableSequenceNumber
;
2335 outgoingCommand
.unreliableSequenceNumber
= 0;
2336 } else if (outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
) {
2337 ++channel
.outgoingReliableSequenceNumber
;
2338 channel
.outgoingUnreliableSequenceNumber
= 0;
2340 outgoingCommand
.reliableSequenceNumber
= channel
.outgoingReliableSequenceNumber
;
2341 outgoingCommand
.unreliableSequenceNumber
= 0;
2342 } else if (outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED
) {
2343 ++peer
.outgoingUnsequencedGroup
;
2344 outgoingCommand
.reliableSequenceNumber
= 0;
2345 outgoingCommand
.unreliableSequenceNumber
= 0;
2347 if (outgoingCommand
.fragmentOffset
== 0) ++channel
.outgoingUnreliableSequenceNumber
;
2348 outgoingCommand
.reliableSequenceNumber
= channel
.outgoingReliableSequenceNumber
;
2349 outgoingCommand
.unreliableSequenceNumber
= channel
.outgoingUnreliableSequenceNumber
;
2352 outgoingCommand
.sendAttempts
= 0;
2353 outgoingCommand
.sentTime
= 0;
2354 outgoingCommand
.roundTripTimeout
= 0;
2355 outgoingCommand
.roundTripTimeoutLimit
= 0;
2356 outgoingCommand
.command
.header
.reliableSequenceNumber
= ENET_HOST_TO_NET_16(outgoingCommand
.reliableSequenceNumber
);
2358 switch (outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) {
2359 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE
:
2360 outgoingCommand
.command
.sendUnreliable
.unreliableSequenceNumber
= ENET_HOST_TO_NET_16(outgoingCommand
.unreliableSequenceNumber
);
2362 case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
:
2363 outgoingCommand
.command
.sendUnsequenced
.unsequencedGroup
= ENET_HOST_TO_NET_16(peer
.outgoingUnsequencedGroup
);
2369 if (outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
) {
2370 enet_list_insert(enet_list_end(&peer
.outgoingReliableCommands
), outgoingCommand
);
2372 enet_list_insert(enet_list_end(&peer
.outgoingUnreliableCommands
), outgoingCommand
);
2377 ENetOutgoingCommand
* enet_peer_queue_outgoing_command (ENetPeer
* peer
, const ENetProtocol
* command
, ENetPacket
* packet
, enet_uint32 offset
, enet_uint16 length
) {
2378 ENetOutgoingCommand
* outgoingCommand
= cast(ENetOutgoingCommand
*)enet_malloc(ENetOutgoingCommand
.sizeof
);
2379 if (outgoingCommand
is null) return null;
2381 outgoingCommand
.command
= * command
;
2382 outgoingCommand
.fragmentOffset
= offset
;
2383 outgoingCommand
.fragmentLength
= length
;
2384 outgoingCommand
.packet
= packet
;
2385 if (packet
!is null) ++packet
.referenceCount
;
2387 enet_peer_setup_outgoing_command (peer
, outgoingCommand
);
2389 return outgoingCommand
;
2393 void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer
* peer
, ENetChannel
* channel
) {
2394 ENetListIterator droppedCommand
, startCommand
, currentCommand
;
2396 for (droppedCommand
= startCommand
= currentCommand
= enet_list_begin(& channel
.incomingUnreliableCommands
);
2397 currentCommand
!= enet_list_end(& channel
.incomingUnreliableCommands
);
2398 currentCommand
= enet_list_next(currentCommand
))
2400 ENetIncomingCommand
* incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
2401 if ((incomingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
) continue;
2403 if (incomingCommand
.reliableSequenceNumber
== channel
.incomingReliableSequenceNumber
) {
2404 if (incomingCommand
.fragmentsRemaining
<= 0) {
2405 channel
.incomingUnreliableSequenceNumber
= incomingCommand
.unreliableSequenceNumber
;
2408 if (startCommand
!= currentCommand
) {
2409 enet_list_move(enet_list_end(&peer
.dispatchedCommands
), startCommand
, enet_list_previous(currentCommand
));
2410 if (!peer
.needsDispatch
) {
2411 enet_list_insert(enet_list_end(&peer
.host
.dispatchQueue
), &peer
.dispatchList
);
2412 peer
.needsDispatch
= true;
2414 droppedCommand
= currentCommand
;
2415 } else if (droppedCommand
!= currentCommand
) {
2416 droppedCommand
= enet_list_previous (currentCommand
);
2419 enet_uint16 reliableWindow
= incomingCommand
.reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
2420 enet_uint16 currentWindow
= channel
.incomingReliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
2421 if (incomingCommand
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) reliableWindow
+= ENET_PEER_RELIABLE_WINDOWS
;
2422 if (reliableWindow
>= currentWindow
&& reliableWindow
< currentWindow
+ENET_PEER_FREE_RELIABLE_WINDOWS
-1) break;
2424 droppedCommand
= enet_list_next(currentCommand
);
2426 if (startCommand
!= currentCommand
) {
2427 enet_list_move(enet_list_end(&peer
.dispatchedCommands
), startCommand
, enet_list_previous(currentCommand
));
2428 if (!peer
.needsDispatch
) {
2429 enet_list_insert (enet_list_end(&peer
.host
.dispatchQueue
), &peer
.dispatchList
);
2430 peer
.needsDispatch
= true;
2435 startCommand
= enet_list_next(currentCommand
);
2438 if (startCommand
!= currentCommand
) {
2439 enet_list_move(enet_list_end(&peer
.dispatchedCommands
), startCommand
, enet_list_previous(currentCommand
));
2440 if (!peer
.needsDispatch
) {
2441 enet_list_insert(enet_list_end(&peer
.host
.dispatchQueue
), &peer
.dispatchList
);
2442 peer
.needsDispatch
= true;
2444 droppedCommand
= currentCommand
;
2447 enet_peer_remove_incoming_commands(&channel
.incomingUnreliableCommands
, enet_list_begin(&channel
.incomingUnreliableCommands
), droppedCommand
);
2451 void enet_peer_dispatch_incoming_reliable_commands (ENetPeer
* peer
, ENetChannel
* channel
) {
2452 ENetListIterator currentCommand
;
2454 for (currentCommand
= enet_list_begin(&channel
.incomingReliableCommands
);
2455 currentCommand
!= enet_list_end(&channel
.incomingReliableCommands
);
2456 currentCommand
= enet_list_next(currentCommand
))
2458 ENetIncomingCommand
* incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
2459 if (incomingCommand
.fragmentsRemaining
> 0 || incomingCommand
.reliableSequenceNumber
!= cast(enet_uint16
)(channel
.incomingReliableSequenceNumber
+1)) break;
2460 channel
.incomingReliableSequenceNumber
= incomingCommand
.reliableSequenceNumber
;
2461 if (incomingCommand
.fragmentCount
> 0) channel
.incomingReliableSequenceNumber
+= incomingCommand
.fragmentCount
-1;
2464 if (currentCommand
== enet_list_begin(&channel
.incomingReliableCommands
)) return;
2466 channel
.incomingUnreliableSequenceNumber
= 0;
2468 enet_list_move(enet_list_end(&peer
.dispatchedCommands
), enet_list_begin(&channel
.incomingReliableCommands
), enet_list_previous(currentCommand
));
2470 if (!peer
.needsDispatch
) {
2471 enet_list_insert(enet_list_end(&peer
.host
.dispatchQueue
), &peer
.dispatchList
);
2472 peer
.needsDispatch
= true;
2475 if (!enet_list_empty(&channel
.incomingUnreliableCommands
)) enet_peer_dispatch_incoming_unreliable_commands(peer
, channel
);
2479 ENetIncomingCommand
* enet_peer_queue_incoming_command (ENetPeer
* peer
, const ENetProtocol
* command
, const(void)* data
, usize dataLength
, enet_uint32 flags
, enet_uint32 fragmentCount
) {
2480 static ENetIncomingCommand dummyCommand
;
2482 ENetChannel
* channel
= &peer
.channels
[command
.header
.channelID
];
2483 enet_uint32 unreliableSequenceNumber
= 0, reliableSequenceNumber
= 0;
2484 enet_uint16 reliableWindow
, currentWindow
;
2485 ENetIncomingCommand
* incomingCommand
;
2486 ENetListIterator currentCommand
;
2487 ENetPacket
* packet
= null;
2489 if (peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
) goto discardCommand
;
2491 if ((command
.header
.command
& ENET_PROTOCOL_COMMAND_MASK
) != ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
) {
2492 reliableSequenceNumber
= command
.header
.reliableSequenceNumber
;
2493 reliableWindow
= cast(ushort)(reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
);
2494 currentWindow
= channel
.incomingReliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
2496 if (reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) reliableWindow
+= ENET_PEER_RELIABLE_WINDOWS
;
2498 if (reliableWindow
< currentWindow || reliableWindow
>= currentWindow
+ENET_PEER_FREE_RELIABLE_WINDOWS
-1) goto discardCommand
;
2501 switch (command
.header
.command
& ENET_PROTOCOL_COMMAND_MASK
) {
2502 case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT
:
2503 case ENET_PROTOCOL_COMMAND_SEND_RELIABLE
:
2504 if (reliableSequenceNumber
== channel
.incomingReliableSequenceNumber
) goto discardCommand
;
2505 for (currentCommand
= enet_list_previous(enet_list_end(&channel
.incomingReliableCommands
));
2506 currentCommand
!= enet_list_end(&channel
.incomingReliableCommands
);
2507 currentCommand
= enet_list_previous(currentCommand
))
2509 incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
2510 if (reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) {
2511 if (incomingCommand
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) continue;
2512 } else if (incomingCommand
.reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) break;
2513 if (incomingCommand
.reliableSequenceNumber
<= reliableSequenceNumber
) {
2514 if (incomingCommand
.reliableSequenceNumber
< reliableSequenceNumber
) break;
2515 goto discardCommand
;
2519 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE
:
2520 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT
:
2521 unreliableSequenceNumber
= ENET_NET_TO_HOST_16(command
.sendUnreliable
.unreliableSequenceNumber
);
2522 if (reliableSequenceNumber
== channel
.incomingReliableSequenceNumber
&& unreliableSequenceNumber
<= channel
.incomingUnreliableSequenceNumber
) goto discardCommand
;
2523 for (currentCommand
= enet_list_previous (enet_list_end (& channel
.incomingUnreliableCommands
));
2524 currentCommand
!= enet_list_end (& channel
.incomingUnreliableCommands
);
2525 currentCommand
= enet_list_previous (currentCommand
))
2527 incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
2528 if ((command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
) continue;
2529 if (reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) {
2530 if (incomingCommand
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) continue;
2531 } else if (incomingCommand
.reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) break;
2532 if (incomingCommand
.reliableSequenceNumber
< reliableSequenceNumber
) break;
2533 if (incomingCommand
.reliableSequenceNumber
> reliableSequenceNumber
) continue;
2534 if (incomingCommand
.unreliableSequenceNumber
<= unreliableSequenceNumber
) {
2535 if (incomingCommand
.unreliableSequenceNumber
< unreliableSequenceNumber
) break;
2536 goto discardCommand
;
2540 case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
:
2541 currentCommand
= enet_list_end(&channel
.incomingUnreliableCommands
);
2544 goto discardCommand
;
2547 if (peer
.totalWaitingData
>= peer
.host
.maximumWaitingData
) goto notifyError
;
2549 packet
= enet_packet_create(data
, dataLength
, flags
);
2550 if (packet
is null) goto notifyError
;
2552 incomingCommand
= cast(ENetIncomingCommand
*)enet_malloc(ENetIncomingCommand
.sizeof
);
2553 if (incomingCommand
is null) goto notifyError
;
2555 incomingCommand
.reliableSequenceNumber
= command
.header
.reliableSequenceNumber
;
2556 incomingCommand
.unreliableSequenceNumber
= unreliableSequenceNumber
&0xFFFF;
2557 incomingCommand
.command
= *command
;
2558 incomingCommand
.fragmentCount
= fragmentCount
;
2559 incomingCommand
.fragmentsRemaining
= fragmentCount
;
2560 incomingCommand
.packet
= packet
;
2561 incomingCommand
.fragments
= null;
2563 if (fragmentCount
> 0) {
2564 if (fragmentCount
<= ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT
) {
2565 incomingCommand
.fragments
= cast(enet_uint32
*)enet_malloc((fragmentCount
+31)/32*enet_uint32
.sizeof
);
2567 if (incomingCommand
.fragments
is null) {
2568 enet_free(incomingCommand
);
2571 import core
.stdc
.string
: memset
;
2572 memset(incomingCommand
.fragments
, 0, (fragmentCount
+31)/32*enet_uint32
.sizeof
);
2575 if (packet
!is null) {
2576 ++packet
.referenceCount
;
2577 peer
.totalWaitingData
+= packet
.dataLength
;
2580 enet_list_insert(enet_list_next(currentCommand
), incomingCommand
);
2582 switch (command
.header
.command
& ENET_PROTOCOL_COMMAND_MASK
) {
2583 case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT
:
2584 case ENET_PROTOCOL_COMMAND_SEND_RELIABLE
:
2585 enet_peer_dispatch_incoming_reliable_commands (peer
, channel
);
2588 enet_peer_dispatch_incoming_unreliable_commands (peer
, channel
);
2592 return incomingCommand
;
2595 if (fragmentCount
> 0) goto notifyError
;
2596 if (packet
!is null && packet
.referenceCount
== 0) enet_packet_destroy(packet
);
2597 return &dummyCommand
;
2600 if (packet
!is null && packet
.referenceCount
== 0) enet_packet_destroy(packet
);
2608 /** Creates a host for communicating to peers.
2611 * address = the address at which other peers may connect to this host. If null, then no peers may connect to the host.
2612 * peerCount = the maximum number of peers that should be allocated for the host.
2613 * channelLimit = the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
2614 * incomingBandwidth = downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
2615 * outgoingBandwidth = upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
2618 * the host on success and null on failure
2621 * ENet will strategically drop packets on specific sides of a connection between hosts
2622 * to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine
2623 * the window size of a connection which limits the amount of reliable packets that may be in transit
2624 * at any given time.
2626 ENetHost
* enet_host_create (const ENetAddress
* address
, usize peerCount
, usize channelLimit
, enet_uint32 incomingBandwidth
=0, enet_uint32 outgoingBandwidth
=0) {
2627 import core
.stdc
.string
: memset
;
2630 ENetPeer
* currentPeer
;
2632 if (peerCount
> ENET_PROTOCOL_MAXIMUM_PEER_ID
) return null;
2634 host
= cast(ENetHost
*)enet_malloc(ENetHost
.sizeof
);
2635 if (host
is null) return null;
2636 memset(host
, 0, ENetHost
.sizeof
);
2638 host
.peers
= cast(ENetPeer
*)enet_malloc(peerCount
*ENetPeer
.sizeof
);
2639 if (host
.peers
is null) {
2643 memset(host
.peers
, 0, peerCount
*ENetPeer
.sizeof
);
2645 host
.socket
= enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM
);
2646 if (host
.socket
== ENET_SOCKET_NULL ||
(address
!is null && enet_socket_bind(host
.socket
, address
) < 0)) {
2647 if (host
.socket
!= ENET_SOCKET_NULL
) enet_socket_destroy(host
.socket
);
2648 enet_free(host
.peers
);
2653 enet_socket_set_option(host
.socket
, ENET_SOCKOPT_NONBLOCK
, 1);
2654 enet_socket_set_option(host
.socket
, ENET_SOCKOPT_BROADCAST
, 1);
2655 enet_socket_set_option(host
.socket
, ENET_SOCKOPT_RCVBUF
, ENET_HOST_RECEIVE_BUFFER_SIZE
);
2656 enet_socket_set_option(host
.socket
, ENET_SOCKOPT_SNDBUF
, ENET_HOST_SEND_BUFFER_SIZE
);
2658 if (address
!is null && enet_socket_get_address(host
.socket
, &host
.address
) < 0) host
.address
= *address
;
2660 if (!channelLimit || channelLimit
> ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
) channelLimit
= ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
;
2661 else if (channelLimit
< ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
) channelLimit
= ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
;
2663 host
.randomSeed
= cast(enet_uint32
)cast(usize
)host
;
2664 host
.randomSeed
+= enet_host_random_seed();
2665 host
.randomSeed
= (host
.randomSeed
<<16)|
(host
.randomSeed
>>16);
2666 host
.channelLimit
= channelLimit
;
2667 host
.incomingBandwidth
= incomingBandwidth
;
2668 host
.outgoingBandwidth
= outgoingBandwidth
;
2669 host
.bandwidthThrottleEpoch
= 0;
2670 host
.recalculateBandwidthLimits
= 0;
2671 host
.mtu
= ENET_HOST_DEFAULT_MTU
;
2672 host
.peerCount
= peerCount
;
2673 host
.commandCount
= 0;
2674 host
.bufferCount
= 0;
2675 host
.checksum
= null;
2676 host
.receivedAddress
.host
= ENET_HOST_ANY
;
2677 host
.receivedAddress
.port
= 0;
2678 host
.receivedData
= null;
2679 host
.receivedDataLength
= 0;
2681 host
.totalSentData
= 0;
2682 host
.totalSentPackets
= 0;
2683 host
.totalReceivedData
= 0;
2684 host
.totalReceivedPackets
= 0;
2686 host
.connectedPeers
= 0;
2687 host
.bandwidthLimitedPeers
= 0;
2688 host
.duplicatePeers
= ENET_PROTOCOL_MAXIMUM_PEER_ID
;
2689 host
.maximumPacketSize
= ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE
;
2690 host
.maximumWaitingData
= ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA
;
2692 host
.compressor
.context
= null;
2693 host
.compressor
.compress
= null;
2694 host
.compressor
.decompress
= null;
2695 host
.compressor
.destroy
= null;
2697 host
.intercept
= null;
2699 enet_list_clear(&host
.dispatchQueue
);
2701 for (currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
2702 currentPeer
.host
= host
;
2703 currentPeer
.incomingPeerID
= cast(ushort)(currentPeer
-host
.peers
);
2704 currentPeer
.outgoingSessionID
= currentPeer
.incomingSessionID
= 0xFF;
2705 currentPeer
.data
= null;
2707 enet_list_clear(¤tPeer
.acknowledgements
);
2708 enet_list_clear(¤tPeer
.sentReliableCommands
);
2709 enet_list_clear(¤tPeer
.sentUnreliableCommands
);
2710 enet_list_clear(¤tPeer
.outgoingReliableCommands
);
2711 enet_list_clear(¤tPeer
.outgoingUnreliableCommands
);
2712 enet_list_clear(¤tPeer
.dispatchedCommands
);
2714 enet_peer_reset(currentPeer
);
2721 /** Destroys the host and all resources associated with it.
2724 * host = pointer to the host to destroy
2726 void enet_host_destroy (ENetHost
* host
) {
2727 ENetPeer
* currentPeer
;
2729 if (host
is null) return;
2731 enet_socket_destroy(host
.socket
);
2733 for (currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
2734 enet_peer_reset(currentPeer
);
2737 if (host
.compressor
.context
!is null && host
.compressor
.destroy
) (*host
.compressor
.destroy
)(host
.compressor
.context
);
2739 enet_free(host
.peers
);
2744 /** Initiates a connection to a foreign host.
2747 * host = host seeking the connection
2748 * address = destination for the connection
2749 * channelCount = number of channels to allocate
2750 * data = user data supplied to the receiving host
2753 * a peer representing the foreign host on success, null on failure
2756 * The peer returned will have not completed the connection until enet_host_service()
2757 * notifies of an ENET_EVENT_TYPE_CONNECT event for the peer.
2759 ENetPeer
* enet_host_connect (ENetHost
* host
, const ENetAddress
* address
, usize channelCount
, enet_uint32 data
) {
2760 ENetPeer
* currentPeer
;
2761 ENetChannel
* channel
;
2762 ENetProtocol command
;
2764 if (channelCount
< ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
) channelCount
= ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
;
2765 else if (channelCount
> ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
) channelCount
= ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
;
2767 for (currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
2768 if (currentPeer
.state
== ENET_PEER_STATE_DISCONNECTED
) break;
2771 if (currentPeer
>= &host
.peers
[host
.peerCount
]) return null;
2773 currentPeer
.channels
= cast(ENetChannel
*)enet_malloc(channelCount
*ENetChannel
.sizeof
);
2774 if (currentPeer
.channels
is null) return null;
2775 currentPeer
.channelCount
= channelCount
;
2776 currentPeer
.state
= ENET_PEER_STATE_CONNECTING
;
2777 currentPeer
.address
= *address
;
2778 currentPeer
.connectID
= ++host
.randomSeed
;
2780 if (host
.outgoingBandwidth
== 0) {
2781 currentPeer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
2783 currentPeer
.windowSize
= (host
.outgoingBandwidth
/ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
2786 if (currentPeer
.windowSize
< ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
) currentPeer
.windowSize
= ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
2787 else if (currentPeer
.windowSize
> ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
) currentPeer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
2789 for (channel
= currentPeer
.channels
; channel
< ¤tPeer
.channels
[channelCount
]; ++channel
) {
2790 import core
.stdc
.string
: memset
;
2792 channel
.outgoingReliableSequenceNumber
= 0;
2793 channel
.outgoingUnreliableSequenceNumber
= 0;
2794 channel
.incomingReliableSequenceNumber
= 0;
2795 channel
.incomingUnreliableSequenceNumber
= 0;
2797 enet_list_clear(&channel
.incomingReliableCommands
);
2798 enet_list_clear(&channel
.incomingUnreliableCommands
);
2800 channel
.usedReliableWindows
= 0;
2801 memset(channel
.reliableWindows
.ptr
, 0, channel
.reliableWindows
.sizeof
);
2804 command
.header
.command
= ENET_PROTOCOL_COMMAND_CONNECT|ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
2805 command
.header
.channelID
= 0xFF;
2806 command
.connect
.outgoingPeerID
= ENET_HOST_TO_NET_16(currentPeer
.incomingPeerID
);
2807 command
.connect
.incomingSessionID
= currentPeer
.incomingSessionID
;
2808 command
.connect
.outgoingSessionID
= currentPeer
.outgoingSessionID
;
2809 command
.connect
.mtu
= ENET_HOST_TO_NET_32(currentPeer
.mtu
);
2810 command
.connect
.windowSize
= ENET_HOST_TO_NET_32(currentPeer
.windowSize
);
2811 command
.connect
.channelCount
= ENET_HOST_TO_NET_32(cast(uint)channelCount
);
2812 command
.connect
.incomingBandwidth
= ENET_HOST_TO_NET_32(host
.incomingBandwidth
);
2813 command
.connect
.outgoingBandwidth
= ENET_HOST_TO_NET_32(host
.outgoingBandwidth
);
2814 command
.connect
.packetThrottleInterval
= ENET_HOST_TO_NET_32(currentPeer
.packetThrottleInterval
);
2815 command
.connect
.packetThrottleAcceleration
= ENET_HOST_TO_NET_32(currentPeer
.packetThrottleAcceleration
);
2816 command
.connect
.packetThrottleDeceleration
= ENET_HOST_TO_NET_32(currentPeer
.packetThrottleDeceleration
);
2817 command
.connect
.connectID
= currentPeer
.connectID
;
2818 command
.connect
.data
= ENET_HOST_TO_NET_32(data
);
2820 enet_peer_queue_outgoing_command(currentPeer
, &command
, null, 0, 0);
2826 /** Queues a packet to be sent to all peers associated with the host.
2829 * host = host on which to broadcast the packet
2830 * channelID = channel on which to broadcast
2831 * packet = packet to broadcast
2833 void enet_host_broadcast (ENetHost
* host
, enet_uint8 channelID
, ENetPacket
* packet
) {
2834 ENetPeer
* currentPeer
;
2836 for (currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
2837 if (currentPeer
.state
!= ENET_PEER_STATE_CONNECTED
) continue;
2838 enet_peer_send(currentPeer
, channelID
, packet
);
2841 if (packet
.referenceCount
== 0) enet_packet_destroy(packet
);
2845 /** Sets the packet compressor the host should use to compress and decompress packets.
2848 * host = host to enable or disable compression for
2849 * compressor = callbacks for for the packet compressor; if null, then compression is disabled
2851 void enet_host_compress (ENetHost
* host
, /*const*/ ENetCompressor
* compressor
) {
2852 if (host
.compressor
.context
!is null && host
.compressor
.destroy
) (*host
.compressor
.destroy
)(host
.compressor
.context
);
2853 if (compressor
) host
.compressor
= *compressor
; else host
.compressor
.context
= null;
2857 /** Limits the maximum allowed channels of future incoming connections.
2860 * host = host to limit
2861 * channelLimit = the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
2863 void enet_host_channel_limit (ENetHost
* host
, usize channelLimit
) @nogc {
2864 if (!channelLimit || channelLimit
> ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
) channelLimit
= ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
;
2865 else if (channelLimit
< ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
) channelLimit
= ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
;
2866 host
.channelLimit
= channelLimit
;
2870 /** Adjusts the bandwidth limits of a host.
2873 * host = host to adjust
2874 * incomingBandwidth = new incoming bandwidth
2875 * outgoingBandwidth = new outgoing bandwidth
2878 * the incoming and outgoing bandwidth parameters are identical in function to those
2879 * specified in enet_host_create().
2881 void enet_host_bandwidth_limit (ENetHost
* host
, enet_uint32 incomingBandwidth
, enet_uint32 outgoingBandwidth
) @nogc {
2882 host
.incomingBandwidth
= incomingBandwidth
;
2883 host
.outgoingBandwidth
= outgoingBandwidth
;
2884 host
.recalculateBandwidthLimits
= 1;
2888 void enet_host_bandwidth_throttle (ENetHost
* host
) {
2889 enet_uint32 timeCurrent
= enet_time_get();
2890 enet_uint32 elapsedTime
= timeCurrent
-host
.bandwidthThrottleEpoch
;
2891 enet_uint32 peersRemaining
= cast(enet_uint32
)host
.connectedPeers
;
2892 enet_uint32 dataTotal
= ~0;
2893 enet_uint32 bandwidth
= ~0;
2894 enet_uint32 throttle
= 0;
2895 enet_uint32 bandwidthLimit
= 0;
2896 int needsAdjustment
= (host
.bandwidthLimitedPeers
> 0 ?
1 : 0);
2898 ENetProtocol command
;
2900 if (elapsedTime
< ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL
) return;
2902 host
.bandwidthThrottleEpoch
= timeCurrent
;
2904 if (peersRemaining
== 0) return;
2906 if (host
.outgoingBandwidth
!= 0) {
2908 bandwidth
= (host
.outgoingBandwidth
*elapsedTime
)/1000;
2910 for (peer
= host
.peers
; peer
< &host
.peers
[host
.peerCount
]; ++peer
) {
2911 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) continue;
2912 dataTotal
+= peer
.outgoingDataTotal
;
2916 while (peersRemaining
> 0 && needsAdjustment
!= 0) {
2917 needsAdjustment
= 0;
2919 throttle
= (dataTotal
<= bandwidth ? ENET_PEER_PACKET_THROTTLE_SCALE
: (bandwidth
*ENET_PEER_PACKET_THROTTLE_SCALE
)/dataTotal
);
2921 for (peer
= host
.peers
; peer
< &host
.peers
[host
.peerCount
]; ++peer
) {
2922 enet_uint32 peerBandwidth
;
2924 if ((peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) ||
2925 peer
.incomingBandwidth
== 0 ||
2926 peer
.outgoingBandwidthThrottleEpoch
== timeCurrent
)
2929 peerBandwidth
= (peer
.incomingBandwidth
*elapsedTime
)/1000;
2930 if ((throttle
*peer
.outgoingDataTotal
)/ENET_PEER_PACKET_THROTTLE_SCALE
<= peerBandwidth
) continue;
2932 peer
.packetThrottleLimit
= (peerBandwidth
*ENET_PEER_PACKET_THROTTLE_SCALE
)/peer
.outgoingDataTotal
;
2934 if (peer
.packetThrottleLimit
== 0) peer
.packetThrottleLimit
= 1;
2936 if (peer
.packetThrottle
> peer
.packetThrottleLimit
) peer
.packetThrottle
= peer
.packetThrottleLimit
;
2938 peer
.outgoingBandwidthThrottleEpoch
= timeCurrent
;
2940 peer
.incomingDataTotal
= 0;
2941 peer
.outgoingDataTotal
= 0;
2943 needsAdjustment
= 1;
2945 bandwidth
-= peerBandwidth
;
2946 dataTotal
-= peerBandwidth
;
2950 if (peersRemaining
> 0) {
2951 throttle
= (dataTotal
<= bandwidth ? ENET_PEER_PACKET_THROTTLE_SCALE
: (bandwidth
*ENET_PEER_PACKET_THROTTLE_SCALE
)/dataTotal
);
2953 for (peer
= host
.peers
; peer
< &host
.peers
[host
.peerCount
]; ++peer
) {
2954 if ((peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) ||
2955 peer
.outgoingBandwidthThrottleEpoch
== timeCurrent
)
2958 peer
.packetThrottleLimit
= throttle
;
2960 if (peer
.packetThrottle
> peer
.packetThrottleLimit
) peer
.packetThrottle
= peer
.packetThrottleLimit
;
2962 peer
.incomingDataTotal
= 0;
2963 peer
.outgoingDataTotal
= 0;
2967 if (host
.recalculateBandwidthLimits
) {
2968 host
.recalculateBandwidthLimits
= 0;
2970 peersRemaining
= cast(enet_uint32
)host
.connectedPeers
;
2971 bandwidth
= host
.incomingBandwidth
;
2972 needsAdjustment
= 1;
2974 if (bandwidth
== 0) {
2977 while (peersRemaining
> 0 && needsAdjustment
!= 0) {
2978 needsAdjustment
= 0;
2979 bandwidthLimit
= bandwidth
/peersRemaining
;
2981 for (peer
= host
.peers
; peer
< &host
.peers
[host
.peerCount
]; ++peer
) {
2982 if ((peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) ||
2983 peer
.incomingBandwidthThrottleEpoch
== timeCurrent
)
2986 if (peer
.outgoingBandwidth
> 0 && peer
.outgoingBandwidth
>= bandwidthLimit
) continue;
2988 peer
.incomingBandwidthThrottleEpoch
= timeCurrent
;
2990 needsAdjustment
= 1;
2992 bandwidth
-= peer
.outgoingBandwidth
;
2997 for (peer
= host
.peers
; peer
< &host
.peers
[host
.peerCount
]; ++peer
) {
2998 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)
3001 command
.header
.command
= ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
3002 command
.header
.channelID
= 0xFF;
3003 command
.bandwidthLimit
.outgoingBandwidth
= ENET_HOST_TO_NET_32 (host
.outgoingBandwidth
);
3005 if (peer
.incomingBandwidthThrottleEpoch
== timeCurrent
) {
3006 command
.bandwidthLimit
.incomingBandwidth
= ENET_HOST_TO_NET_32(peer
.outgoingBandwidth
);
3008 command
.bandwidthLimit
.incomingBandwidth
= ENET_HOST_TO_NET_32(bandwidthLimit
);
3011 enet_peer_queue_outgoing_command(peer
, &command
, null, 0, 0);
3020 // `auto` to trigger attribute inference
3021 private auto ENET_MIN(T
) (T a
, T b
) { pragma(inline
, true); return (a
< b ? a
: b
); }
3022 private auto ENET_MAX(T
) (T a
, T b
) { pragma(inline
, true); return (a
> b ? a
: b
); }
3025 enum ENET_TIME_OVERFLOW
= 86400000;
3027 // `auto` to trigger attribute inference
3028 auto ENET_TIME_LESS(T
) (T a
, T b
) { pragma(inline
, true); return (a
-b
>= ENET_TIME_OVERFLOW
); }
3029 auto ENET_TIME_GREATER(T
) (T a
, T b
) { pragma(inline
, true); return (b
-a
>= ENET_TIME_OVERFLOW
); }
3030 auto ENET_TIME_LESS_EQUAL(T
) (T a
, T b
) { pragma(inline
, true); return !ENET_TIME_GREATER(a
, b
); }
3031 auto ENET_TIME_GREATER_EQUAL(T
) (T a
, T b
) { pragma(inline
, true); return !ENET_TIME_LESS(a
, b
); }
3033 auto ENET_TIME_DIFFERENCE(T
) (T a
, T b
) { pragma(inline
, true); return (a
-b
>= ENET_TIME_OVERFLOW ? b
-a
: a
-b
); }
3036 private immutable usize
[ENET_PROTOCOL_COMMAND_COUNT
] commandSizes
= [
3038 ENetProtocolAcknowledge
.sizeof
,
3039 ENetProtocolConnect
.sizeof
,
3040 ENetProtocolVerifyConnect
.sizeof
,
3041 ENetProtocolDisconnect
.sizeof
,
3042 ENetProtocolPing
.sizeof
,
3043 ENetProtocolSendReliable
.sizeof
,
3044 ENetProtocolSendUnreliable
.sizeof
,
3045 ENetProtocolSendFragment
.sizeof
,
3046 ENetProtocolSendUnsequenced
.sizeof
,
3047 ENetProtocolBandwidthLimit
.sizeof
,
3048 ENetProtocolThrottleConfigure
.sizeof
,
3049 ENetProtocolSendFragment
.sizeof
,
3053 usize
enet_protocol_command_size (enet_uint8 commandNumber
) @nogc {
3054 return commandSizes
[commandNumber
&ENET_PROTOCOL_COMMAND_MASK
];
3058 private void enet_protocol_change_state (ENetHost
* host
, ENetPeer
* peer
, ENetPeerState state
) {
3059 if (state
== ENET_PEER_STATE_CONNECTED || state
== ENET_PEER_STATE_DISCONNECT_LATER
) {
3060 enet_peer_on_connect(peer
);
3062 enet_peer_on_disconnect(peer
);
3068 private void enet_protocol_dispatch_state (ENetHost
* host
, ENetPeer
* peer
, ENetPeerState state
) {
3069 enet_protocol_change_state(host
, peer
, state
);
3070 if (!peer
.needsDispatch
) {
3071 enet_list_insert(enet_list_end(&host
.dispatchQueue
), &peer
.dispatchList
);
3072 peer
.needsDispatch
= true;
3077 private int enet_protocol_dispatch_incoming_commands (ENetHost
* host
, ENetEvent
* event
) {
3078 while (!enet_list_empty(&host
.dispatchQueue
)) {
3079 ENetPeer
* peer
= cast(ENetPeer
*)enet_list_remove(enet_list_begin(&host
.dispatchQueue
));
3080 peer
.needsDispatch
= false;
3081 switch (peer
.state
) {
3082 case ENET_PEER_STATE_CONNECTION_PENDING
:
3083 case ENET_PEER_STATE_CONNECTION_SUCCEEDED
:
3084 enet_protocol_change_state(host
, peer
, ENET_PEER_STATE_CONNECTED
);
3085 event
.type
= ENET_EVENT_TYPE_CONNECT
;
3087 event
.data
= peer
.eventData
;
3089 case ENET_PEER_STATE_ZOMBIE
:
3090 host
.recalculateBandwidthLimits
= 1;
3091 event
.type
= ENET_EVENT_TYPE_DISCONNECT
;
3093 event
.data
= peer
.eventData
;
3094 enet_peer_reset(peer
);
3096 case ENET_PEER_STATE_CONNECTED
:
3097 if (enet_list_empty(&peer
.dispatchedCommands
)) continue;
3098 event
.packet
= enet_peer_receive(peer
, &event
.channelID
);
3099 if (event
.packet
is null) continue;
3100 event
.type
= ENET_EVENT_TYPE_RECEIVE
;
3102 if (!enet_list_empty(&peer
.dispatchedCommands
)) {
3103 peer
.needsDispatch
= true;
3104 enet_list_insert(enet_list_end(&host
.dispatchQueue
), &peer
.dispatchList
);
3115 private void enet_protocol_notify_connect (ENetHost
* host
, ENetPeer
* peer
, ENetEvent
* event
) {
3116 host
.recalculateBandwidthLimits
= 1;
3117 if (event
!is null) {
3118 enet_protocol_change_state(host
, peer
, ENET_PEER_STATE_CONNECTED
);
3119 event
.type
= ENET_EVENT_TYPE_CONNECT
;
3121 event
.data
= peer
.eventData
;
3123 enet_protocol_dispatch_state(host
, peer
, (peer
.state
== ENET_PEER_STATE_CONNECTING ? ENET_PEER_STATE_CONNECTION_SUCCEEDED
: ENET_PEER_STATE_CONNECTION_PENDING
));
3128 private void enet_protocol_notify_disconnect (ENetHost
* host
, ENetPeer
* peer
, ENetEvent
* event
) {
3129 if (peer
.state
>= ENET_PEER_STATE_CONNECTION_PENDING
) host
.recalculateBandwidthLimits
= 1;
3130 if (peer
.state
!= ENET_PEER_STATE_CONNECTING
&& peer
.state
< ENET_PEER_STATE_CONNECTION_SUCCEEDED
) {
3131 enet_peer_reset(peer
);
3132 } else if (event
!is null) {
3133 event
.type
= ENET_EVENT_TYPE_DISCONNECT
;
3136 enet_peer_reset(peer
);
3139 enet_protocol_dispatch_state(host
, peer
, ENET_PEER_STATE_ZOMBIE
);
3144 private void enet_protocol_remove_sent_unreliable_commands (ENetPeer
* peer
) {
3145 ENetOutgoingCommand
*outgoingCommand
;
3146 if (enet_list_empty(&peer
.sentUnreliableCommands
)) return;
3148 outgoingCommand
= cast(ENetOutgoingCommand
*)enet_list_front(&peer
.sentUnreliableCommands
);
3149 enet_list_remove(&outgoingCommand
.outgoingCommandList
);
3150 if (outgoingCommand
.packet
!is null) {
3151 --outgoingCommand
.packet
.referenceCount
;
3152 if (outgoingCommand
.packet
.referenceCount
== 0) {
3153 outgoingCommand
.packet
.flags |
= ENET_PACKET_FLAG_SENT
;
3154 enet_packet_destroy (outgoingCommand
.packet
);
3157 enet_free(outgoingCommand
);
3158 } while (!enet_list_empty(&peer
.sentUnreliableCommands
));
3159 if (peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
&&
3160 enet_list_empty(&peer
.outgoingReliableCommands
) &&
3161 enet_list_empty(&peer
.outgoingUnreliableCommands
) &&
3162 enet_list_empty(&peer
.sentReliableCommands
))
3164 enet_peer_disconnect(peer
, peer
.eventData
);
3169 private ENetProtocolCommand
enet_protocol_remove_sent_reliable_command (ENetPeer
* peer
, enet_uint16 reliableSequenceNumber
, enet_uint8 channelID
) {
3170 ENetOutgoingCommand
*outgoingCommand
= null;
3171 ENetListIterator currentCommand
;
3172 ENetProtocolCommand commandNumber
;
3175 for (currentCommand
= enet_list_begin(&peer
.sentReliableCommands
);
3176 currentCommand
!= enet_list_end(&peer
.sentReliableCommands
);
3177 currentCommand
= enet_list_next(currentCommand
))
3179 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
3180 if (outgoingCommand
.reliableSequenceNumber
== reliableSequenceNumber
&& outgoingCommand
.command
.header
.channelID
== channelID
) break;
3183 if (currentCommand
== enet_list_end(&peer
.sentReliableCommands
)) {
3184 for (currentCommand
= enet_list_begin(&peer
.outgoingReliableCommands
);
3185 currentCommand
!= enet_list_end(&peer
.outgoingReliableCommands
);
3186 currentCommand
= enet_list_next(currentCommand
))
3188 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
3189 if (outgoingCommand
.sendAttempts
< 1) return ENET_PROTOCOL_COMMAND_NONE
;
3190 if (outgoingCommand
.reliableSequenceNumber
== reliableSequenceNumber
&& outgoingCommand
.command
.header
.channelID
== channelID
) break;
3192 if (currentCommand
== enet_list_end(&peer
.outgoingReliableCommands
)) return ENET_PROTOCOL_COMMAND_NONE
;
3196 if (outgoingCommand
is null) return ENET_PROTOCOL_COMMAND_NONE
;
3198 if (channelID
< peer
.channelCount
) {
3199 ENetChannel
* channel
= &peer
.channels
[channelID
];
3200 enet_uint16 reliableWindow
= reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
3201 if (channel
.reliableWindows
[reliableWindow
] > 0) {
3202 --channel
.reliableWindows
[reliableWindow
];
3203 if (!channel
.reliableWindows
[reliableWindow
]) channel
.usedReliableWindows
&= ~(1<<reliableWindow
);
3207 commandNumber
= cast(ENetProtocolCommand
)(outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
);
3209 enet_list_remove(&outgoingCommand
.outgoingCommandList
);
3211 if (outgoingCommand
.packet
!is null) {
3212 if (wasSent
) peer
.reliableDataInTransit
-= outgoingCommand
.fragmentLength
;
3213 --outgoingCommand
.packet
.referenceCount
;
3214 if (outgoingCommand
.packet
.referenceCount
== 0) {
3215 outgoingCommand
.packet
.flags |
= ENET_PACKET_FLAG_SENT
;
3216 enet_packet_destroy (outgoingCommand
.packet
);
3220 enet_free(outgoingCommand
);
3222 if (enet_list_empty(&peer
.sentReliableCommands
)) return commandNumber
;
3224 outgoingCommand
= cast(ENetOutgoingCommand
*)enet_list_front(&peer
.sentReliableCommands
);
3226 peer
.nextTimeout
= outgoingCommand
.sentTime
+outgoingCommand
.roundTripTimeout
;
3228 return commandNumber
;
3232 private ENetPeer
* enet_protocol_handle_connect (ENetHost
* host
, ENetProtocolHeader
* header
, ENetProtocol
* command
) {
3233 enet_uint8 incomingSessionID
, outgoingSessionID
;
3234 enet_uint32 mtu
, windowSize
;
3235 ENetChannel
* channel
;
3236 usize channelCount
, duplicatePeers
= 0;
3237 ENetPeer
* currentPeer
, peer
= null;
3238 ENetProtocol verifyCommand
;
3240 channelCount
= ENET_NET_TO_HOST_32(command
.connect
.channelCount
);
3242 if (channelCount
< ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount
> ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
) return null;
3244 for (currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
3245 if (currentPeer
.state
== ENET_PEER_STATE_DISCONNECTED
) {
3246 if (peer
is null) peer
= currentPeer
;
3247 } else if (currentPeer
.state
!= ENET_PEER_STATE_CONNECTING
&& currentPeer
.address
.host
== host
.receivedAddress
.host
) {
3248 if (currentPeer
.address
.port
== host
.receivedAddress
.port
&& currentPeer
.connectID
== command
.connect
.connectID
) return null;
3253 if (peer
is null || duplicatePeers
>= host
.duplicatePeers
) return null;
3255 if (channelCount
> host
.channelLimit
) channelCount
= host
.channelLimit
;
3256 peer
.channels
= cast(ENetChannel
*)enet_malloc(channelCount
*ENetChannel
.sizeof
);
3257 if (peer
.channels
is null) return null;
3259 peer
.channelCount
= channelCount
;
3260 peer
.state
= ENET_PEER_STATE_ACKNOWLEDGING_CONNECT
;
3261 peer
.connectID
= command
.connect
.connectID
;
3262 peer
.address
= host
.receivedAddress
;
3263 peer
.outgoingPeerID
= ENET_NET_TO_HOST_16(command
.connect
.outgoingPeerID
);
3264 peer
.incomingBandwidth
= ENET_NET_TO_HOST_32(command
.connect
.incomingBandwidth
);
3265 peer
.outgoingBandwidth
= ENET_NET_TO_HOST_32(command
.connect
.outgoingBandwidth
);
3266 peer
.packetThrottleInterval
= ENET_NET_TO_HOST_32(command
.connect
.packetThrottleInterval
);
3267 peer
.packetThrottleAcceleration
= ENET_NET_TO_HOST_32(command
.connect
.packetThrottleAcceleration
);
3268 peer
.packetThrottleDeceleration
= ENET_NET_TO_HOST_32(command
.connect
.packetThrottleDeceleration
);
3269 peer
.eventData
= ENET_NET_TO_HOST_32(command
.connect
.data
);
3271 incomingSessionID
= (command
.connect
.incomingSessionID
== 0xFF ? peer
.outgoingSessionID
: command
.connect
.incomingSessionID
);
3272 incomingSessionID
= (incomingSessionID
+1)&(ENET_PROTOCOL_HEADER_SESSION_MASK
>>ENET_PROTOCOL_HEADER_SESSION_SHIFT
);
3273 if (incomingSessionID
== peer
.outgoingSessionID
) incomingSessionID
= (incomingSessionID
+1)&(ENET_PROTOCOL_HEADER_SESSION_MASK
>>ENET_PROTOCOL_HEADER_SESSION_SHIFT
);
3274 peer
.outgoingSessionID
= incomingSessionID
;
3276 outgoingSessionID
= (command
.connect
.outgoingSessionID
== 0xFF ? peer
.incomingSessionID
: command
.connect
.outgoingSessionID
);
3277 outgoingSessionID
= (outgoingSessionID
+1)&(ENET_PROTOCOL_HEADER_SESSION_MASK
>>ENET_PROTOCOL_HEADER_SESSION_SHIFT
);
3278 if (outgoingSessionID
== peer
.incomingSessionID
) outgoingSessionID
= (outgoingSessionID
+1)&(ENET_PROTOCOL_HEADER_SESSION_MASK
>>ENET_PROTOCOL_HEADER_SESSION_SHIFT
);
3279 peer
.incomingSessionID
= outgoingSessionID
;
3281 for (channel
= peer
.channels
; channel
< &peer
.channels
[channelCount
]; ++channel
) {
3282 channel
.outgoingReliableSequenceNumber
= 0;
3283 channel
.outgoingUnreliableSequenceNumber
= 0;
3284 channel
.incomingReliableSequenceNumber
= 0;
3285 channel
.incomingUnreliableSequenceNumber
= 0;
3287 enet_list_clear(&channel
.incomingReliableCommands
);
3288 enet_list_clear(&channel
.incomingUnreliableCommands
);
3290 channel
.usedReliableWindows
= 0;
3292 import core
.stdc
.string
: memset
;
3293 memset(channel
.reliableWindows
.ptr
, 0, channel
.reliableWindows
.sizeof
);
3296 mtu
= ENET_NET_TO_HOST_32(command
.connect
.mtu
);
3298 if (mtu
< ENET_PROTOCOL_MINIMUM_MTU
) mtu
= ENET_PROTOCOL_MINIMUM_MTU
;
3299 else if (mtu
> ENET_PROTOCOL_MAXIMUM_MTU
) mtu
= ENET_PROTOCOL_MAXIMUM_MTU
;
3303 if (host
.outgoingBandwidth
== 0 && peer
.incomingBandwidth
== 0) {
3304 peer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3305 } else if (host
.outgoingBandwidth
== 0 || peer
.incomingBandwidth
== 0) {
3306 peer
.windowSize
= (ENET_MAX(host
.outgoingBandwidth
, peer
.incomingBandwidth
)/ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3308 peer
.windowSize
= (ENET_MIN(host
.outgoingBandwidth
, peer
.incomingBandwidth
)/ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3310 if (peer
.windowSize
< ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
) peer
.windowSize
= ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3311 else if (peer
.windowSize
> ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
) peer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3313 if (host
.incomingBandwidth
== 0) windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3314 else windowSize
= (host
.incomingBandwidth
/ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3316 if (windowSize
> ENET_NET_TO_HOST_32(command
.connect
.windowSize
)) windowSize
= ENET_NET_TO_HOST_32(command
.connect
.windowSize
);
3318 if (windowSize
< ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
) windowSize
= ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3319 else if (windowSize
> ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
) windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3321 verifyCommand
.header
.command
= ENET_PROTOCOL_COMMAND_VERIFY_CONNECT|ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
3322 verifyCommand
.header
.channelID
= 0xFF;
3323 verifyCommand
.verifyConnect
.outgoingPeerID
= ENET_HOST_TO_NET_16 (peer
.incomingPeerID
);
3324 verifyCommand
.verifyConnect
.incomingSessionID
= incomingSessionID
;
3325 verifyCommand
.verifyConnect
.outgoingSessionID
= outgoingSessionID
;
3326 verifyCommand
.verifyConnect
.mtu
= ENET_HOST_TO_NET_32(peer
.mtu
);
3327 verifyCommand
.verifyConnect
.windowSize
= ENET_HOST_TO_NET_32(windowSize
);
3328 verifyCommand
.verifyConnect
.channelCount
= ENET_HOST_TO_NET_32(cast(uint)channelCount
);
3329 verifyCommand
.verifyConnect
.incomingBandwidth
= ENET_HOST_TO_NET_32(host
.incomingBandwidth
);
3330 verifyCommand
.verifyConnect
.outgoingBandwidth
= ENET_HOST_TO_NET_32(host
.outgoingBandwidth
);
3331 verifyCommand
.verifyConnect
.packetThrottleInterval
= ENET_HOST_TO_NET_32(peer
.packetThrottleInterval
);
3332 verifyCommand
.verifyConnect
.packetThrottleAcceleration
= ENET_HOST_TO_NET_32(peer
.packetThrottleAcceleration
);
3333 verifyCommand
.verifyConnect
.packetThrottleDeceleration
= ENET_HOST_TO_NET_32(peer
.packetThrottleDeceleration
);
3334 verifyCommand
.verifyConnect
.connectID
= peer
.connectID
;
3336 enet_peer_queue_outgoing_command(peer
, &verifyCommand
, null, 0, 0);
3342 private int enet_protocol_handle_send_reliable (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint8
** currentData
) {
3344 if (command
.header
.channelID
>= peer
.channelCount ||
(peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)) return -1;
3345 dataLength
= ENET_NET_TO_HOST_16(command
.sendReliable
.dataLength
);
3346 *currentData
+= dataLength
;
3347 if (dataLength
> host
.maximumPacketSize ||
*currentData
< host
.receivedData ||
*currentData
> &host
.receivedData
[host
.receivedDataLength
]) return -1;
3348 if (enet_peer_queue_incoming_command(peer
, command
, cast(const(enet_uint8
)*)command
+ENetProtocolSendReliable
.sizeof
, dataLength
, ENET_PACKET_FLAG_RELIABLE
, 0) is null) return -1;
3353 private int enet_protocol_handle_send_unsequenced (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint8
** currentData
) {
3354 enet_uint32 unsequencedGroup
, index
;
3357 if (command
.header
.channelID
>= peer
.channelCount ||
(peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)) return -1;
3359 dataLength
= ENET_NET_TO_HOST_16(command
.sendUnsequenced
.dataLength
);
3360 *currentData
+= dataLength
;
3361 if (dataLength
> host
.maximumPacketSize ||
*currentData
< host
.receivedData ||
*currentData
> &host
.receivedData
[host
.receivedDataLength
]) return -1;
3363 unsequencedGroup
= ENET_NET_TO_HOST_16 (command
.sendUnsequenced
.unsequencedGroup
);
3364 index
= unsequencedGroup
%ENET_PEER_UNSEQUENCED_WINDOW_SIZE
;
3366 if (unsequencedGroup
< peer
.incomingUnsequencedGroup
) unsequencedGroup
+= 0x10000;
3368 if (unsequencedGroup
>= cast(enet_uint32
)peer
.incomingUnsequencedGroup
+ENET_PEER_FREE_UNSEQUENCED_WINDOWS
*ENET_PEER_UNSEQUENCED_WINDOW_SIZE
) return 0;
3370 unsequencedGroup
&= 0xFFFF;
3372 if (unsequencedGroup
-index
!= peer
.incomingUnsequencedGroup
) {
3373 import core
.stdc
.string
: memset
;
3374 peer
.incomingUnsequencedGroup
= cast(ushort)(unsequencedGroup
-index
);
3375 memset(peer
.unsequencedWindow
.ptr
, 0, peer
.unsequencedWindow
.sizeof
);
3376 } else if (peer
.unsequencedWindow
.ptr
[index
/32]&(1<<(index
%32))) {
3380 if (enet_peer_queue_incoming_command(peer
, command
, cast(const(enet_uint8
)*)command
+ENetProtocolSendUnsequenced
.sizeof
, dataLength
, ENET_PACKET_FLAG_UNSEQUENCED
, 0) is null) return -1;
3382 peer
.unsequencedWindow
.ptr
[index
/32] |
= 1<<(index
%32);
3388 private int enet_protocol_handle_send_unreliable (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint8
** currentData
) {
3391 if (command
.header
.channelID
>= peer
.channelCount ||
(peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)) return -1;
3393 dataLength
= ENET_NET_TO_HOST_16(command
.sendUnreliable
.dataLength
);
3394 *currentData
+= dataLength
;
3395 if (dataLength
> host
.maximumPacketSize ||
*currentData
< host
.receivedData ||
*currentData
> &host
.receivedData
[host
.receivedDataLength
]) return -1;
3397 if (enet_peer_queue_incoming_command(peer
, command
, cast(const(enet_uint8
)*)command
+ENetProtocolSendUnreliable
.sizeof
, dataLength
, 0, 0) is null) return -1;
3403 private int enet_protocol_handle_send_fragment (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint8
** currentData
) {
3404 enet_uint32 fragmentNumber
, fragmentCount
, fragmentOffset
, fragmentLength
, startSequenceNumber
, totalLength
;
3405 ENetChannel
* channel
;
3406 enet_uint16 startWindow
, currentWindow
;
3407 ENetListIterator currentCommand
;
3408 ENetIncomingCommand
* startCommand
= null;
3410 if (command
.header
.channelID
>= peer
.channelCount ||
(peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)) return -1;
3412 fragmentLength
= ENET_NET_TO_HOST_16 (command
.sendFragment
.dataLength
);
3413 *currentData
+= fragmentLength
;
3414 if (fragmentLength
> host
.maximumPacketSize ||
*currentData
< host
.receivedData ||
*currentData
> &host
.receivedData
[host
.receivedDataLength
]) return -1;
3416 channel
= &peer
.channels
[command
.header
.channelID
];
3417 startSequenceNumber
= ENET_NET_TO_HOST_16(command
.sendFragment
.startSequenceNumber
);
3418 startWindow
= cast(ushort)(startSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
);
3419 currentWindow
= channel
.incomingReliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
3421 if (startSequenceNumber
< channel
.incomingReliableSequenceNumber
) startWindow
+= ENET_PEER_RELIABLE_WINDOWS
;
3423 if (startWindow
< currentWindow || startWindow
>= currentWindow
+ENET_PEER_FREE_RELIABLE_WINDOWS
-1) return 0;
3425 fragmentNumber
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentNumber
);
3426 fragmentCount
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentCount
);
3427 fragmentOffset
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentOffset
);
3428 totalLength
= ENET_NET_TO_HOST_32(command
.sendFragment
.totalLength
);
3430 if (fragmentCount
> ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT ||
3431 fragmentNumber
>= fragmentCount ||
3432 totalLength
> host
.maximumPacketSize ||
3433 fragmentOffset
>= totalLength ||
3434 fragmentLength
> totalLength
-fragmentOffset
)
3437 for (currentCommand
= enet_list_previous(enet_list_end(&channel
.incomingReliableCommands
));
3438 currentCommand
!= enet_list_end(&channel
.incomingReliableCommands
);
3439 currentCommand
= enet_list_previous(currentCommand
))
3441 ENetIncomingCommand
* incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
3442 if (startSequenceNumber
>= channel
.incomingReliableSequenceNumber
) {
3443 if (incomingCommand
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) continue;
3444 } else if (incomingCommand
.reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) break;
3445 if (incomingCommand
.reliableSequenceNumber
<= startSequenceNumber
) {
3446 if (incomingCommand
.reliableSequenceNumber
< startSequenceNumber
) break;
3447 if ((incomingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) != ENET_PROTOCOL_COMMAND_SEND_FRAGMENT ||
3448 totalLength
!= incomingCommand
.packet
.dataLength ||
3449 fragmentCount
!= incomingCommand
.fragmentCount
)
3451 startCommand
= incomingCommand
;
3456 if (startCommand
is null) {
3457 ENetProtocol hostCommand
= *command
;
3458 hostCommand
.header
.reliableSequenceNumber
= cast(ushort)startSequenceNumber
;
3459 startCommand
= enet_peer_queue_incoming_command(peer
, &hostCommand
, null, totalLength
, ENET_PACKET_FLAG_RELIABLE
, fragmentCount
);
3460 if (startCommand
is null) return -1;
3463 if ((startCommand
.fragments
[fragmentNumber
/32]&(1<<(fragmentNumber
%32))) == 0) {
3464 import core
.stdc
.string
: memcpy
;
3465 --startCommand
.fragmentsRemaining
;
3466 startCommand
.fragments
[fragmentNumber
/32] |
= (1<<(fragmentNumber
%32));
3467 if (fragmentOffset
+fragmentLength
> startCommand
.packet
.dataLength
) fragmentLength
= cast(uint)(startCommand
.packet
.dataLength
-fragmentOffset
);
3468 memcpy(startCommand
.packet
.data
+fragmentOffset
, cast(enet_uint8
*)command
+ENetProtocolSendFragment
.sizeof
, fragmentLength
);
3469 if (startCommand
.fragmentsRemaining
<= 0) enet_peer_dispatch_incoming_reliable_commands(peer
, channel
);
3476 private int enet_protocol_handle_send_unreliable_fragment (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint8
** currentData
) {
3477 enet_uint32 fragmentNumber
, fragmentCount
, fragmentOffset
, fragmentLength
, reliableSequenceNumber
, startSequenceNumber
, totalLength
;
3478 enet_uint16 reliableWindow
, currentWindow
;
3479 ENetChannel
* channel
;
3480 ENetListIterator currentCommand
;
3481 ENetIncomingCommand
* startCommand
= null;
3483 if (command
.header
.channelID
>= peer
.channelCount ||
(peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)) return -1;
3485 fragmentLength
= ENET_NET_TO_HOST_16(command
.sendFragment
.dataLength
);
3486 *currentData
+= fragmentLength
;
3487 if (fragmentLength
> host
.maximumPacketSize ||
*currentData
< host
.receivedData ||
*currentData
> &host
.receivedData
[host
.receivedDataLength
]) return -1;
3489 channel
= &peer
.channels
[command
.header
.channelID
];
3490 reliableSequenceNumber
= command
.header
.reliableSequenceNumber
;
3491 startSequenceNumber
= ENET_NET_TO_HOST_16(command
.sendFragment
.startSequenceNumber
);
3493 reliableWindow
= cast(ushort)(reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
);
3494 currentWindow
= channel
.incomingReliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
3496 if (reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) reliableWindow
+= ENET_PEER_RELIABLE_WINDOWS
;
3498 if (reliableWindow
< currentWindow || reliableWindow
>= currentWindow
+ENET_PEER_FREE_RELIABLE_WINDOWS
-1) return 0;
3500 if (reliableSequenceNumber
== channel
.incomingReliableSequenceNumber
&& startSequenceNumber
<= channel
.incomingUnreliableSequenceNumber
) return 0;
3502 fragmentNumber
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentNumber
);
3503 fragmentCount
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentCount
);
3504 fragmentOffset
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentOffset
);
3505 totalLength
= ENET_NET_TO_HOST_32(command
.sendFragment
.totalLength
);
3507 if (fragmentCount
> ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT ||
3508 fragmentNumber
>= fragmentCount ||
3509 totalLength
> host
.maximumPacketSize ||
3510 fragmentOffset
>= totalLength ||
3511 fragmentLength
> totalLength
- fragmentOffset
)
3514 for (currentCommand
= enet_list_previous(enet_list_end (&channel
.incomingUnreliableCommands
));
3515 currentCommand
!= enet_list_end(&channel
.incomingUnreliableCommands
);
3516 currentCommand
= enet_list_previous(currentCommand
))
3518 ENetIncomingCommand
* incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
3519 if (reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) {
3520 if (incomingCommand
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) continue;
3521 } else if (incomingCommand
.reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) break;
3522 if (incomingCommand
.reliableSequenceNumber
< reliableSequenceNumber
) break;
3523 if (incomingCommand
.reliableSequenceNumber
> reliableSequenceNumber
) continue;
3524 if (incomingCommand
.unreliableSequenceNumber
<= startSequenceNumber
) {
3525 if (incomingCommand
.unreliableSequenceNumber
< startSequenceNumber
) break;
3526 if ((incomingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) != ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT ||
3527 totalLength
!= incomingCommand
.packet
.dataLength ||
3528 fragmentCount
!= incomingCommand
.fragmentCount
)
3530 startCommand
= incomingCommand
;
3535 if (startCommand
is null) {
3536 startCommand
= enet_peer_queue_incoming_command(peer
, command
, null, totalLength
, ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT
, fragmentCount
);
3537 if (startCommand
is null) return -1;
3540 if ((startCommand
.fragments
[fragmentNumber
/32]&(1<<(fragmentNumber
%32))) == 0) {
3541 import core
.stdc
.string
: memcpy
;
3542 --startCommand
.fragmentsRemaining
;
3543 startCommand
.fragments
[fragmentNumber
/32] |
= (1<<(fragmentNumber
%32));
3544 if (fragmentOffset
+fragmentLength
> startCommand
.packet
.dataLength
) fragmentLength
= cast(uint)(startCommand
.packet
.dataLength
-fragmentOffset
);
3545 memcpy(startCommand
.packet
.data
+fragmentOffset
, cast(enet_uint8
*)command
+ENetProtocolSendFragment
.sizeof
, fragmentLength
);
3546 if (startCommand
.fragmentsRemaining
<= 0) enet_peer_dispatch_incoming_unreliable_commands(peer
, channel
);
3553 private int enet_protocol_handle_ping (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
) @nogc {
3554 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) return -1;
3559 private int enet_protocol_handle_bandwidth_limit (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
) @nogc {
3560 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) return -1;
3562 if (peer
.incomingBandwidth
!= 0) --host
.bandwidthLimitedPeers
;
3564 peer
.incomingBandwidth
= ENET_NET_TO_HOST_32(command
.bandwidthLimit
.incomingBandwidth
);
3565 peer
.outgoingBandwidth
= ENET_NET_TO_HOST_32(command
.bandwidthLimit
.outgoingBandwidth
);
3567 if (peer
.incomingBandwidth
!= 0) ++host
.bandwidthLimitedPeers
;
3569 if (peer
.incomingBandwidth
== 0 && host
.outgoingBandwidth
== 0) {
3570 peer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3571 } else if (peer
.incomingBandwidth
== 0 || host
.outgoingBandwidth
== 0) {
3572 peer
.windowSize
= (ENET_MAX(peer
.incomingBandwidth
, host
.outgoingBandwidth
)/ ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3574 peer
.windowSize
= (ENET_MIN(peer
.incomingBandwidth
, host
.outgoingBandwidth
)/ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3577 if (peer
.windowSize
< ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
) peer
.windowSize
= ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3578 else if (peer
.windowSize
> ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
) peer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3584 private int enet_protocol_handle_throttle_configure (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
) @nogc {
3585 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) return -1;
3587 peer
.packetThrottleInterval
= ENET_NET_TO_HOST_32(command
.throttleConfigure
.packetThrottleInterval
);
3588 peer
.packetThrottleAcceleration
= ENET_NET_TO_HOST_32(command
.throttleConfigure
.packetThrottleAcceleration
);
3589 peer
.packetThrottleDeceleration
= ENET_NET_TO_HOST_32(command
.throttleConfigure
.packetThrottleDeceleration
);
3595 private int enet_protocol_handle_disconnect (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
) {
3596 if (peer
.state
== ENET_PEER_STATE_DISCONNECTED || peer
.state
== ENET_PEER_STATE_ZOMBIE || peer
.state
== ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT
) return 0;
3598 enet_peer_reset_queues(peer
);
3600 if (peer
.state
== ENET_PEER_STATE_CONNECTION_SUCCEEDED || peer
.state
== ENET_PEER_STATE_DISCONNECTING || peer
.state
== ENET_PEER_STATE_CONNECTING
) {
3601 enet_protocol_dispatch_state(host
, peer
, ENET_PEER_STATE_ZOMBIE
);
3602 } else if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) {
3603 if (peer
.state
== ENET_PEER_STATE_CONNECTION_PENDING
) host
.recalculateBandwidthLimits
= 1;
3604 enet_peer_reset(peer
);
3605 } else if (command
.header
.command
&ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
) {
3606 enet_protocol_change_state(host
, peer
, ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT
);
3608 enet_protocol_dispatch_state(host
, peer
, ENET_PEER_STATE_ZOMBIE
);
3611 if (peer
.state
!= ENET_PEER_STATE_DISCONNECTED
) peer
.eventData
= ENET_NET_TO_HOST_32(command
.disconnect
.data
);
3617 private int enet_protocol_handle_acknowledge (ENetHost
* host
, ENetEvent
* event
, ENetPeer
* peer
, const ENetProtocol
* command
) {
3618 enet_uint32 roundTripTime
, receivedSentTime
, receivedReliableSequenceNumber
;
3619 ENetProtocolCommand commandNumber
;
3621 if (peer
.state
== ENET_PEER_STATE_DISCONNECTED || peer
.state
== ENET_PEER_STATE_ZOMBIE
) return 0;
3623 receivedSentTime
= ENET_NET_TO_HOST_16(command
.acknowledge
.receivedSentTime
);
3624 receivedSentTime |
= host
.serviceTime
&0xFFFF0000;
3625 if ((receivedSentTime
&0x8000) > (host
.serviceTime
&0x8000)) receivedSentTime
-= 0x10000;
3627 if (ENET_TIME_LESS(host
.serviceTime
, receivedSentTime
)) return 0;
3629 peer
.lastReceiveTime
= host
.serviceTime
;
3630 peer
.earliestTimeout
= 0;
3632 roundTripTime
= ENET_TIME_DIFFERENCE(host
.serviceTime
, receivedSentTime
);
3634 enet_peer_throttle(peer
, roundTripTime
);
3636 peer
.roundTripTimeVariance
-= peer
.roundTripTimeVariance
/4;
3638 if (roundTripTime
>= peer
.roundTripTime
) {
3639 peer
.roundTripTime
+= (roundTripTime
-peer
.roundTripTime
)/8;
3640 peer
.roundTripTimeVariance
+= (roundTripTime
-peer
.roundTripTime
)/4;
3642 peer
.roundTripTime
-= (peer
.roundTripTime
-roundTripTime
)/8;
3643 peer
.roundTripTimeVariance
+= (peer
.roundTripTime
-roundTripTime
)/4;
3646 if (peer
.roundTripTime
< peer
.lowestRoundTripTime
) peer
.lowestRoundTripTime
= peer
.roundTripTime
;
3648 if (peer
.roundTripTimeVariance
> peer
.highestRoundTripTimeVariance
) peer
.highestRoundTripTimeVariance
= peer
.roundTripTimeVariance
;
3650 if (peer
.packetThrottleEpoch
== 0 ||
ENET_TIME_DIFFERENCE(host
.serviceTime
, peer
.packetThrottleEpoch
) >= peer
.packetThrottleInterval
) {
3651 peer
.lastRoundTripTime
= peer
.lowestRoundTripTime
;
3652 peer
.lastRoundTripTimeVariance
= peer
.highestRoundTripTimeVariance
;
3653 peer
.lowestRoundTripTime
= peer
.roundTripTime
;
3654 peer
.highestRoundTripTimeVariance
= peer
.roundTripTimeVariance
;
3655 peer
.packetThrottleEpoch
= host
.serviceTime
;
3658 receivedReliableSequenceNumber
= ENET_NET_TO_HOST_16(command
.acknowledge
.receivedReliableSequenceNumber
);
3660 commandNumber
= enet_protocol_remove_sent_reliable_command(peer
, cast(ushort)receivedReliableSequenceNumber
, command
.header
.channelID
);
3662 switch (peer
.state
) {
3663 case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT
:
3664 if (commandNumber
!= ENET_PROTOCOL_COMMAND_VERIFY_CONNECT
) return -1;
3665 enet_protocol_notify_connect (host
, peer
, event
);
3667 case ENET_PEER_STATE_DISCONNECTING
:
3668 if (commandNumber
!= ENET_PROTOCOL_COMMAND_DISCONNECT
) return -1;
3669 enet_protocol_notify_disconnect (host
, peer
, event
);
3671 case ENET_PEER_STATE_DISCONNECT_LATER
:
3672 if (enet_list_empty (&peer
.outgoingReliableCommands
) && enet_list_empty(&peer
.outgoingUnreliableCommands
) && enet_list_empty(&peer
.sentReliableCommands
)) {
3673 enet_peer_disconnect(peer
, peer
.eventData
);
3684 private int enet_protocol_handle_verify_connect (ENetHost
* host
, ENetEvent
* event
, ENetPeer
* peer
, const ENetProtocol
* command
) {
3685 enet_uint32 mtu
, windowSize
;
3688 if (peer
.state
!= ENET_PEER_STATE_CONNECTING
) return 0;
3690 channelCount
= ENET_NET_TO_HOST_32(command
.verifyConnect
.channelCount
);
3692 if (channelCount
< ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount
> ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT ||
3693 ENET_NET_TO_HOST_32 (command
.verifyConnect
.packetThrottleInterval
) != peer
.packetThrottleInterval ||
3694 ENET_NET_TO_HOST_32 (command
.verifyConnect
.packetThrottleAcceleration
) != peer
.packetThrottleAcceleration ||
3695 ENET_NET_TO_HOST_32 (command
.verifyConnect
.packetThrottleDeceleration
) != peer
.packetThrottleDeceleration ||
3696 command
.verifyConnect
.connectID
!= peer
.connectID
)
3699 enet_protocol_dispatch_state(host
, peer
, ENET_PEER_STATE_ZOMBIE
);
3703 enet_protocol_remove_sent_reliable_command(peer
, 1, 0xFF);
3705 if (channelCount
< peer
.channelCount
) peer
.channelCount
= channelCount
;
3707 peer
.outgoingPeerID
= ENET_NET_TO_HOST_16(command
.verifyConnect
.outgoingPeerID
);
3708 peer
.incomingSessionID
= command
.verifyConnect
.incomingSessionID
;
3709 peer
.outgoingSessionID
= command
.verifyConnect
.outgoingSessionID
;
3711 mtu
= ENET_NET_TO_HOST_32(command
.verifyConnect
.mtu
);
3713 if (mtu
< ENET_PROTOCOL_MINIMUM_MTU
) mtu
= ENET_PROTOCOL_MINIMUM_MTU
;
3714 else if (mtu
> ENET_PROTOCOL_MAXIMUM_MTU
) mtu
= ENET_PROTOCOL_MAXIMUM_MTU
;
3716 if (mtu
< peer
.mtu
) peer
.mtu
= mtu
;
3718 windowSize
= ENET_NET_TO_HOST_32(command
.verifyConnect
.windowSize
);
3720 if (windowSize
< ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
) windowSize
= ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3721 if (windowSize
> ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
) windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3722 if (windowSize
< peer
.windowSize
) peer
.windowSize
= windowSize
;
3724 peer
.incomingBandwidth
= ENET_NET_TO_HOST_32(command
.verifyConnect
.incomingBandwidth
);
3725 peer
.outgoingBandwidth
= ENET_NET_TO_HOST_32(command
.verifyConnect
.outgoingBandwidth
);
3727 enet_protocol_notify_connect(host
, peer
, event
);
3733 private int enet_protocol_handle_incoming_commands (ENetHost
* host
, ENetEvent
* event
) {
3734 ENetProtocolHeader
* header
;
3735 ENetProtocol
* command
;
3737 enet_uint8
* currentData
;
3739 enet_uint16 peerID
, flags
;
3740 enet_uint8 sessionID
;
3742 if (host
.receivedDataLength
< cast(usize
)&(cast(ENetProtocolHeader
*)0).sentTime
) return 0; //k8:???
3744 header
= cast(ENetProtocolHeader
*)host
.receivedData
;
3746 peerID
= ENET_NET_TO_HOST_16(header
.peerID
);
3747 sessionID
= (peerID
&ENET_PROTOCOL_HEADER_SESSION_MASK
)>>ENET_PROTOCOL_HEADER_SESSION_SHIFT
;
3748 flags
= peerID
&ENET_PROTOCOL_HEADER_FLAG_MASK
;
3749 peerID
&= ~(ENET_PROTOCOL_HEADER_FLAG_MASK|ENET_PROTOCOL_HEADER_SESSION_MASK
);
3751 headerSize
= (flags
&ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? ENetProtocolHeader
.sizeof
: cast(usize
)&(cast(ENetProtocolHeader
*)0).sentTime
);
3752 if (host
.checksum
!is null) headerSize
+= enet_uint32
.sizeof
;
3754 if (peerID
== ENET_PROTOCOL_MAXIMUM_PEER_ID
) {
3756 } else if (peerID
>= host
.peerCount
) {
3759 peer
= &host
.peers
[peerID
];
3760 if (peer
.state
== ENET_PEER_STATE_DISCONNECTED ||
3761 peer
.state
== ENET_PEER_STATE_ZOMBIE ||
3762 ((host
.receivedAddress
.host
!= peer
.address
.host ||
3763 host
.receivedAddress
.port
!= peer
.address
.port
) && peer
.address
.host
!= ENET_HOST_BROADCAST
) ||
3764 (peer
.outgoingPeerID
< ENET_PROTOCOL_MAXIMUM_PEER_ID
&& sessionID
!= peer
.incomingSessionID
))
3768 if (flags
&ENET_PROTOCOL_HEADER_FLAG_COMPRESSED
) {
3770 if (host
.compressor
.context
is null || host
.compressor
.decompress
is null) return 0;
3772 originalSize
= host
.compressor
.decompress(host
.compressor
.context
,
3773 host
.receivedData
+headerSize
,
3774 host
.receivedDataLength
-headerSize
,
3775 host
.packetData
.ptr
[1].ptr
+headerSize
,
3776 host
.packetData
.ptr
[1].sizeof
-headerSize
);
3777 if (originalSize
<= 0 || originalSize
> host
.packetData
.ptr
[1].sizeof
-headerSize
) return 0;
3779 import core
.stdc
.string
: memcpy
;
3780 memcpy(host
.packetData
.ptr
[1].ptr
, header
, headerSize
);
3781 host
.receivedData
= host
.packetData
.ptr
[1].ptr
;
3782 host
.receivedDataLength
= headerSize
+originalSize
;
3785 if (host
.checksum
!is null) {
3786 enet_uint32
* checksum
= cast(enet_uint32
*)&host
.receivedData
[headerSize
-enet_uint32
.sizeof
];
3787 enet_uint32 desiredChecksum
= *checksum
;
3790 *checksum
= (peer
!is null ? peer
.connectID
: 0);
3792 buffer
.data
= host
.receivedData
;
3793 buffer
.dataLength
= host
.receivedDataLength
;
3795 if (host
.checksum(&buffer
, 1) != desiredChecksum
) return 0;
3798 if (peer
!is null) {
3799 peer
.address
.host
= host
.receivedAddress
.host
;
3800 peer
.address
.port
= host
.receivedAddress
.port
;
3801 peer
.incomingDataTotal
+= host
.receivedDataLength
;
3804 currentData
= host
.receivedData
+headerSize
;
3806 while (currentData
< &host
.receivedData
[host
.receivedDataLength
]) {
3807 enet_uint8 commandNumber
;
3810 command
= cast(ENetProtocol
*)currentData
;
3812 if (currentData
+ENetProtocolCommandHeader
.sizeof
> &host
.receivedData
[host
.receivedDataLength
]) break;
3814 commandNumber
= command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
;
3815 if (commandNumber
>= ENET_PROTOCOL_COMMAND_COUNT
) break;
3817 commandSize
= commandSizes
[commandNumber
];
3818 if (commandSize
== 0 || currentData
+commandSize
> &host
.receivedData
[host
.receivedDataLength
]) break;
3820 currentData
+= commandSize
;
3822 if (peer
is null && commandNumber
!= ENET_PROTOCOL_COMMAND_CONNECT
) break;
3824 command
.header
.reliableSequenceNumber
= ENET_NET_TO_HOST_16(command
.header
.reliableSequenceNumber
);
3826 switch (commandNumber
) {
3827 case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE
:
3828 if (enet_protocol_handle_acknowledge(host
, event
, peer
, command
)) goto commandError
;
3830 case ENET_PROTOCOL_COMMAND_CONNECT
:
3831 if (peer
!is null) goto commandError
;
3832 peer
= enet_protocol_handle_connect(host
, header
, command
);
3833 if (peer
is null) goto commandError
;
3835 case ENET_PROTOCOL_COMMAND_VERIFY_CONNECT
:
3836 if (enet_protocol_handle_verify_connect(host
, event
, peer
, command
)) goto commandError
;
3838 case ENET_PROTOCOL_COMMAND_DISCONNECT
:
3839 if (enet_protocol_handle_disconnect(host
, peer
, command
)) goto commandError
;
3841 case ENET_PROTOCOL_COMMAND_PING
:
3842 if (enet_protocol_handle_ping(host
, peer
, command
)) goto commandError
;
3844 case ENET_PROTOCOL_COMMAND_SEND_RELIABLE
:
3845 if (enet_protocol_handle_send_reliable(host
, peer
, command
, ¤tData
)) goto commandError
;
3847 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE
:
3848 if (enet_protocol_handle_send_unreliable(host
, peer
, command
, ¤tData
)) goto commandError
;
3850 case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
:
3851 if (enet_protocol_handle_send_unsequenced(host
, peer
, command
, ¤tData
)) goto commandError
;
3853 case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT
:
3854 if (enet_protocol_handle_send_fragment(host
, peer
, command
, ¤tData
)) goto commandError
;
3856 case ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT
:
3857 if (enet_protocol_handle_bandwidth_limit(host
, peer
, command
)) goto commandError
;
3859 case ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE
:
3860 if (enet_protocol_handle_throttle_configure(host
, peer
, command
)) goto commandError
;
3862 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT
:
3863 if (enet_protocol_handle_send_unreliable_fragment(host
, peer
, command
, ¤tData
)) goto commandError
;
3869 if (peer
!is null && (command
.header
.command
&ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
) != 0) {
3870 enet_uint16 sentTime
;
3872 if (!(flags
&ENET_PROTOCOL_HEADER_FLAG_SENT_TIME
)) break;
3873 sentTime
= ENET_NET_TO_HOST_16 (header
.sentTime
);
3874 switch (peer
.state
) {
3875 case ENET_PEER_STATE_DISCONNECTING
:
3876 case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT
:
3877 case ENET_PEER_STATE_DISCONNECTED
:
3878 case ENET_PEER_STATE_ZOMBIE
:
3880 case ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT
:
3881 if ((command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) == ENET_PROTOCOL_COMMAND_DISCONNECT
) {
3882 enet_peer_queue_acknowledgement(peer
, command
, sentTime
);
3886 enet_peer_queue_acknowledgement(peer
, command
, sentTime
);
3893 if (event
!is null && event
.type
!= ENET_EVENT_TYPE_NONE
) return 1;
3898 private int enet_protocol_receive_incoming_commands (ENetHost
* host
, ENetEvent
* event
) {
3899 for (int packets
= 0; packets
< 256; ++packets
) {
3902 buffer
.data
= host
.packetData
.ptr
[0].ptr
;
3903 buffer
.dataLength
= host
.packetData
.ptr
[0].sizeof
;
3904 receivedLength
= enet_socket_receive(host
.socket
, &host
.receivedAddress
, &buffer
, 1);
3905 if (receivedLength
< 0) return -1;
3906 if (receivedLength
== 0) return 0;
3907 host
.receivedData
= host
.packetData
.ptr
[0].ptr
;
3908 host
.receivedDataLength
= receivedLength
;
3909 host
.totalReceivedData
+= receivedLength
;
3910 ++host
.totalReceivedPackets
;
3911 if (host
.intercept
!is null) {
3912 switch (host
.intercept(host
, event
)) {
3914 if (event
!is null && event
.type
!= ENET_EVENT_TYPE_NONE
) return 1;
3922 switch (enet_protocol_handle_incoming_commands(host
, event
)) {
3932 private void enet_protocol_send_acknowledgements (ENetHost
* host
, ENetPeer
* peer
) {
3933 ENetProtocol
* command
= &host
.commands
.ptr
[host
.commandCount
];
3934 ENetBuffer
* buffer
= &host
.buffers
.ptr
[host
.bufferCount
];
3935 ENetAcknowledgement
* acknowledgement
;
3936 ENetListIterator currentAcknowledgement
;
3937 enet_uint16 reliableSequenceNumber
;
3939 currentAcknowledgement
= enet_list_begin(&peer
.acknowledgements
);
3941 while (currentAcknowledgement
!= enet_list_end(&peer
.acknowledgements
)) {
3942 if (command
>= &host
.commands
.ptr
[host
.commands
.sizeof
/ENetProtocol
.sizeof
] ||
3943 buffer
>= &host
.buffers
.ptr
[host
.buffers
.sizeof
/ENetBuffer
.sizeof
] ||
3944 peer
.mtu
-host
.packetSize
< ENetProtocolAcknowledge
.sizeof
)
3946 host
.continueSending
= 1;
3950 acknowledgement
= cast(ENetAcknowledgement
*)currentAcknowledgement
;
3952 currentAcknowledgement
= enet_list_next(currentAcknowledgement
);
3954 buffer
.data
= command
;
3955 buffer
.dataLength
= ENetProtocolAcknowledge
.sizeof
;
3957 host
.packetSize
+= buffer
.dataLength
;
3959 reliableSequenceNumber
= ENET_HOST_TO_NET_16(acknowledgement
.command
.header
.reliableSequenceNumber
);
3961 command
.header
.command
= ENET_PROTOCOL_COMMAND_ACKNOWLEDGE
;
3962 command
.header
.channelID
= acknowledgement
.command
.header
.channelID
;
3963 command
.header
.reliableSequenceNumber
= reliableSequenceNumber
;
3964 command
.acknowledge
.receivedReliableSequenceNumber
= reliableSequenceNumber
;
3965 command
.acknowledge
.receivedSentTime
= ENET_HOST_TO_NET_16(cast(ushort)acknowledgement
.sentTime
);
3967 if ((acknowledgement
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) == ENET_PROTOCOL_COMMAND_DISCONNECT
) {
3968 enet_protocol_dispatch_state(host
, peer
, ENET_PEER_STATE_ZOMBIE
);
3971 enet_list_remove(&acknowledgement
.acknowledgementList
);
3972 enet_free(acknowledgement
);
3978 host
.commandCount
= command
-host
.commands
.ptr
;
3979 host
.bufferCount
= buffer
-host
.buffers
.ptr
;
3983 private void enet_protocol_send_unreliable_outgoing_commands (ENetHost
* host
, ENetPeer
* peer
) {
3984 ENetProtocol
* command
= &host
.commands
.ptr
[host
.commandCount
];
3985 ENetBuffer
* buffer
= &host
.buffers
.ptr
[host
.bufferCount
];
3986 ENetOutgoingCommand
* outgoingCommand
;
3987 ENetListIterator currentCommand
;
3989 currentCommand
= enet_list_begin(&peer
.outgoingUnreliableCommands
);
3991 while (currentCommand
!= enet_list_end(&peer
.outgoingUnreliableCommands
)) {
3994 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
3995 commandSize
= commandSizes
[outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
];
3997 if (command
>= &host
.commands
.ptr
[host
.commands
.sizeof
/ENetProtocol
.sizeof
] ||
3998 buffer
+1 >= &host
.buffers
.ptr
[host
.buffers
.sizeof
/ENetBuffer
.sizeof
] ||
3999 peer
.mtu
-host
.packetSize
< commandSize ||
4000 (outgoingCommand
.packet
!is null && peer
.mtu
-host
.packetSize
< commandSize
+outgoingCommand
.fragmentLength
))
4002 host
.continueSending
= 1;
4006 currentCommand
= enet_list_next(currentCommand
);
4008 if (outgoingCommand
.packet
!is null && outgoingCommand
.fragmentOffset
== 0) {
4009 peer
.packetThrottleCounter
+= ENET_PEER_PACKET_THROTTLE_COUNTER
;
4010 peer
.packetThrottleCounter
%= ENET_PEER_PACKET_THROTTLE_SCALE
;
4011 if (peer
.packetThrottleCounter
> peer
.packetThrottle
) {
4012 enet_uint16 reliableSequenceNumber
= outgoingCommand
.reliableSequenceNumber
;
4013 enet_uint16 unreliableSequenceNumber
= outgoingCommand
.unreliableSequenceNumber
;
4015 --outgoingCommand
.packet
.referenceCount
;
4017 if (outgoingCommand
.packet
.referenceCount
== 0) enet_packet_destroy(outgoingCommand
.packet
);
4019 enet_list_remove(&outgoingCommand
.outgoingCommandList
);
4020 enet_free(outgoingCommand
);
4022 if (currentCommand
== enet_list_end(&peer
.outgoingUnreliableCommands
)) break;
4024 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
4025 if (outgoingCommand
.reliableSequenceNumber
!= reliableSequenceNumber ||
4026 outgoingCommand
.unreliableSequenceNumber
!= unreliableSequenceNumber
)
4029 currentCommand
= enet_list_next(currentCommand
);
4035 buffer
.data
= command
;
4036 buffer
.dataLength
= commandSize
;
4038 host
.packetSize
+= buffer
.dataLength
;
4040 *command
= outgoingCommand
.command
;
4042 enet_list_remove(&outgoingCommand
.outgoingCommandList
);
4044 if (outgoingCommand
.packet
!is null) {
4047 buffer
.data
= outgoingCommand
.packet
.data
+outgoingCommand
.fragmentOffset
;
4048 buffer
.dataLength
= outgoingCommand
.fragmentLength
;
4050 host
.packetSize
+= buffer
.dataLength
;
4052 enet_list_insert(enet_list_end(&peer
.sentUnreliableCommands
), outgoingCommand
);
4054 enet_free(outgoingCommand
);
4061 host
.commandCount
= command
-host
.commands
.ptr
;
4062 host
.bufferCount
= buffer
-host
.buffers
.ptr
;
4064 if (peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
&&
4065 enet_list_empty(&peer
.outgoingReliableCommands
) &&
4066 enet_list_empty(&peer
.outgoingUnreliableCommands
) &&
4067 enet_list_empty(&peer
.sentReliableCommands
) &&
4068 enet_list_empty(&peer
.sentUnreliableCommands
))
4070 enet_peer_disconnect(peer
, peer
.eventData
);
4075 private int enet_protocol_check_timeouts (ENetHost
* host
, ENetPeer
* peer
, ENetEvent
* event
) {
4076 ENetOutgoingCommand
* outgoingCommand
;
4077 ENetListIterator currentCommand
, insertPosition
;
4079 currentCommand
= enet_list_begin(&peer
.sentReliableCommands
);
4080 insertPosition
= enet_list_begin(&peer
.outgoingReliableCommands
);
4082 while (currentCommand
!= enet_list_end(&peer
.sentReliableCommands
)) {
4083 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
4085 currentCommand
= enet_list_next(currentCommand
);
4087 if (ENET_TIME_DIFFERENCE(host
.serviceTime
, outgoingCommand
.sentTime
) < outgoingCommand
.roundTripTimeout
) continue;
4089 if (peer
.earliestTimeout
== 0 ||
ENET_TIME_LESS(outgoingCommand
.sentTime
, peer
.earliestTimeout
)) {
4090 peer
.earliestTimeout
= outgoingCommand
.sentTime
;
4093 if (peer
.earliestTimeout
!= 0 && (ENET_TIME_DIFFERENCE(host
.serviceTime
, peer
.earliestTimeout
) >= peer
.timeoutMaximum ||
4094 (outgoingCommand
.roundTripTimeout
>= outgoingCommand
.roundTripTimeoutLimit
&& ENET_TIME_DIFFERENCE(host
.serviceTime
, peer
.earliestTimeout
) >= peer
.timeoutMinimum
)))
4096 enet_protocol_notify_disconnect(host
, peer
, event
);
4100 if (outgoingCommand
.packet
!is null) peer
.reliableDataInTransit
-= outgoingCommand
.fragmentLength
;
4104 outgoingCommand
.roundTripTimeout
*= 2;
4106 enet_list_insert(insertPosition
, enet_list_remove(&outgoingCommand
.outgoingCommandList
));
4108 if (currentCommand
== enet_list_begin(&peer
.sentReliableCommands
) && !enet_list_empty(&peer
.sentReliableCommands
)) {
4109 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
4110 peer
.nextTimeout
= outgoingCommand
.sentTime
+outgoingCommand
.roundTripTimeout
;
4118 private int enet_protocol_send_reliable_outgoing_commands (ENetHost
* host
, ENetPeer
* peer
) @nogc {
4119 ENetProtocol
* command
= &host
.commands
.ptr
[host
.commandCount
];
4120 ENetBuffer
* buffer
= &host
.buffers
.ptr
[host
.bufferCount
];
4121 ENetOutgoingCommand
* outgoingCommand
;
4122 ENetListIterator currentCommand
;
4123 ENetChannel
* channel
;
4124 enet_uint16 reliableWindow
;
4126 int windowExceeded
= 0, windowWrap
= 0, canPing
= 1;
4128 currentCommand
= enet_list_begin(&peer
.outgoingReliableCommands
);
4129 while (currentCommand
!= enet_list_end(&peer
.outgoingReliableCommands
)) {
4130 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
4131 channel
= (outgoingCommand
.command
.header
.channelID
< peer
.channelCount ?
&peer
.channels
[outgoingCommand
.command
.header
.channelID
] : null);
4132 reliableWindow
= outgoingCommand
.reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
4134 if (channel
!is null) {
4135 if (!windowWrap
&& outgoingCommand
.sendAttempts
< 1 && !(outgoingCommand
.reliableSequenceNumber
%ENET_PEER_RELIABLE_WINDOW_SIZE
) &&
4136 (channel
.reliableWindows
[(reliableWindow
+ENET_PEER_RELIABLE_WINDOWS
-1)%ENET_PEER_RELIABLE_WINDOWS
] >= ENET_PEER_RELIABLE_WINDOW_SIZE ||
4137 channel
.usedReliableWindows
&(
4138 (((1<<ENET_PEER_FREE_RELIABLE_WINDOWS
)-1)<<reliableWindow
)|
4139 (((1<<ENET_PEER_FREE_RELIABLE_WINDOWS
)-1)>>(ENET_PEER_RELIABLE_WINDOWS
-reliableWindow
)))))
4144 currentCommand
= enet_list_next(currentCommand
);
4149 if (outgoingCommand
.packet
!is null) {
4150 if (!windowExceeded
) {
4151 enet_uint32 windowSize
= (peer
.packetThrottle
*peer
.windowSize
)/ENET_PEER_PACKET_THROTTLE_SCALE
;
4152 if (peer
.reliableDataInTransit
+outgoingCommand
.fragmentLength
> ENET_MAX(windowSize
, peer
.mtu
)) windowExceeded
= 1;
4154 if (windowExceeded
) {
4155 currentCommand
= enet_list_next(currentCommand
);
4162 commandSize
= commandSizes
[outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
];
4164 if (command
>= &host
.commands
.ptr
[host
.commands
.sizeof
/ENetProtocol
.sizeof
] ||
4165 buffer
+1 >= &host
.buffers
.ptr
[host
.buffers
.sizeof
/ENetBuffer
.sizeof
] ||
4166 peer
.mtu
-host
.packetSize
< commandSize ||
4167 (outgoingCommand
.packet
!is null && cast(enet_uint16
)(peer
.mtu
-host
.packetSize
) < cast(enet_uint16
)(commandSize
+outgoingCommand
.fragmentLength
)))
4169 host
.continueSending
= 1;
4173 currentCommand
= enet_list_next(currentCommand
);
4175 if (channel
!is null && outgoingCommand
.sendAttempts
< 1) {
4176 channel
.usedReliableWindows |
= 1<<reliableWindow
;
4177 ++channel
.reliableWindows
[reliableWindow
];
4180 ++outgoingCommand
.sendAttempts
;
4182 if (outgoingCommand
.roundTripTimeout
== 0) {
4183 outgoingCommand
.roundTripTimeout
= peer
.roundTripTime
+4*peer
.roundTripTimeVariance
;
4184 outgoingCommand
.roundTripTimeoutLimit
= peer
.timeoutLimit
*outgoingCommand
.roundTripTimeout
;
4187 if (enet_list_empty(&peer
.sentReliableCommands
)) peer
.nextTimeout
= host
.serviceTime
+outgoingCommand
.roundTripTimeout
;
4189 enet_list_insert(enet_list_end(&peer
.sentReliableCommands
), enet_list_remove(&outgoingCommand
.outgoingCommandList
));
4191 outgoingCommand
.sentTime
= host
.serviceTime
;
4193 buffer
.data
= command
;
4194 buffer
.dataLength
= commandSize
;
4196 host
.packetSize
+= buffer
.dataLength
;
4197 host
.headerFlags |
= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME
;
4199 *command
= outgoingCommand
.command
;
4201 if (outgoingCommand
.packet
!is null) {
4204 buffer
.data
= outgoingCommand
.packet
.data
+outgoingCommand
.fragmentOffset
;
4205 buffer
.dataLength
= outgoingCommand
.fragmentLength
;
4207 host
.packetSize
+= outgoingCommand
.fragmentLength
;
4209 peer
.reliableDataInTransit
+= outgoingCommand
.fragmentLength
;
4218 host
.commandCount
= command
-host
.commands
.ptr
;
4219 host
.bufferCount
= buffer
-host
.buffers
.ptr
;
4225 private int enet_protocol_send_outgoing_commands (ENetHost
* host
, ENetEvent
* event
, int checkForTimeouts
) {
4226 enet_uint8
[ENetProtocolHeader
.sizeof
+enet_uint32
.sizeof
] headerData
;
4227 ENetProtocolHeader
* header
= cast(ENetProtocolHeader
*)headerData
;
4228 ENetPeer
* currentPeer
;
4230 usize shouldCompress
= 0;
4232 host
.continueSending
= 1;
4234 while (host
.continueSending
) {
4235 for (host
.continueSending
= 0, currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
4236 if (currentPeer
.state
== ENET_PEER_STATE_DISCONNECTED || currentPeer
.state
== ENET_PEER_STATE_ZOMBIE
) continue;
4238 host
.headerFlags
= 0;
4239 host
.commandCount
= 0;
4240 host
.bufferCount
= 1;
4241 host
.packetSize
= ENetProtocolHeader
.sizeof
;
4243 if (!enet_list_empty(¤tPeer
.acknowledgements
)) enet_protocol_send_acknowledgements(host
, currentPeer
);
4245 if (checkForTimeouts
!= 0 && !enet_list_empty(¤tPeer
.sentReliableCommands
) && ENET_TIME_GREATER_EQUAL(host
.serviceTime
, currentPeer
.nextTimeout
) &&
4246 enet_protocol_check_timeouts(host
, currentPeer
, event
) == 1)
4248 if (event
!is null && event
.type
!= ENET_EVENT_TYPE_NONE
) return 1;
4252 if ((enet_list_empty(¤tPeer
.outgoingReliableCommands
) ||
enet_protocol_send_reliable_outgoing_commands(host
, currentPeer
)) &&
4253 enet_list_empty(¤tPeer
.sentReliableCommands
) && ENET_TIME_DIFFERENCE(host
.serviceTime
, currentPeer
.lastReceiveTime
) >= currentPeer
.pingInterval
&&
4254 currentPeer
.mtu
-host
.packetSize
>= ENetProtocolPing
.sizeof
)
4256 enet_peer_ping(currentPeer
);
4257 enet_protocol_send_reliable_outgoing_commands(host
, currentPeer
);
4260 if (!enet_list_empty(¤tPeer
.outgoingUnreliableCommands
)) enet_protocol_send_unreliable_outgoing_commands (host
, currentPeer
);
4262 if (host
.commandCount
== 0) continue;
4264 if (currentPeer
.packetLossEpoch
== 0) {
4265 currentPeer
.packetLossEpoch
= host
.serviceTime
;
4266 } else if (ENET_TIME_DIFFERENCE(host
.serviceTime
, currentPeer
.packetLossEpoch
) >= ENET_PEER_PACKET_LOSS_INTERVAL
&& currentPeer
.packetsSent
> 0) {
4267 enet_uint32 packetLoss
= currentPeer
.packetsLost
* ENET_PEER_PACKET_LOSS_SCALE
/ currentPeer
.packetsSent
;
4269 version(enet_debug
) {
4270 import core
.stdc
.stdio
: printf
;
4271 printf("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n",
4272 currentPeer
.incomingPeerID
, currentPeer
.packetLoss
/cast(float)ENET_PEER_PACKET_LOSS_SCALE
, currentPeer
.packetLossVariance
/cast(float)ENET_PEER_PACKET_LOSS_SCALE
,
4273 currentPeer
.roundTripTime
, currentPeer
.roundTripTimeVariance
, currentPeer
.packetThrottle
/cast(float)ENET_PEER_PACKET_THROTTLE_SCALE
,
4274 enet_list_size(¤tPeer
.outgoingReliableCommands
), enet_list_size(¤tPeer
.outgoingUnreliableCommands
),
4275 (currentPeer
.channels
!is null ?
enet_list_size(¤tPeer
.channels
.incomingReliableCommands
) : 0),
4276 (currentPeer
.channels
!is null ?
enet_list_size(¤tPeer
.channels
.incomingUnreliableCommands
) : 0));
4279 currentPeer
.packetLossVariance
-= currentPeer
.packetLossVariance
/4;
4281 if (packetLoss
>= currentPeer
.packetLoss
) {
4282 currentPeer
.packetLoss
+= (packetLoss
- currentPeer
.packetLoss
)/8;
4283 currentPeer
.packetLossVariance
+= (packetLoss
-currentPeer
.packetLoss
)/4;
4285 currentPeer
.packetLoss
-= (currentPeer
.packetLoss
-packetLoss
)/8;
4286 currentPeer
.packetLossVariance
+= (currentPeer
.packetLoss
-packetLoss
)/4;
4289 currentPeer
.packetLossEpoch
= host
.serviceTime
;
4290 currentPeer
.packetsSent
= 0;
4291 currentPeer
.packetsLost
= 0;
4294 host
.buffers
.ptr
[0].data
= headerData
.ptr
;
4295 if (host
.headerFlags
&ENET_PROTOCOL_HEADER_FLAG_SENT_TIME
) {
4296 header
.sentTime
= ENET_HOST_TO_NET_16(host
.serviceTime
&0xFFFF);
4297 host
.buffers
.ptr
[0].dataLength
= ENetProtocolHeader
.sizeof
;
4299 host
.buffers
.ptr
[0].dataLength
= cast(usize
)&(cast(ENetProtocolHeader
*)0).sentTime
;
4303 if (host
.compressor
.context
!is null && host
.compressor
.compress
!is null) {
4304 usize originalSize
= host
.packetSize
-ENetProtocolHeader
.sizeof
;
4305 usize compressedSize
= host
.compressor
.compress(host
.compressor
.context
, &host
.buffers
.ptr
[1], host
.bufferCount
-1, originalSize
, host
.packetData
.ptr
[1].ptr
, originalSize
);
4306 if (compressedSize
> 0 && compressedSize
< originalSize
) {
4307 host
.headerFlags |
= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED
;
4308 shouldCompress
= compressedSize
;
4309 version(enet_debug_compress
) {
4310 import core
.stdc
.stdio
: printf
;
4311 printf("peer %u: compressed %u.%u (%u%%)\n", currentPeer
.incomingPeerID
, originalSize
, compressedSize
, (compressedSize
*100)/originalSize
);
4316 if (currentPeer
.outgoingPeerID
< ENET_PROTOCOL_MAXIMUM_PEER_ID
) host
.headerFlags |
= currentPeer
.outgoingSessionID
<<ENET_PROTOCOL_HEADER_SESSION_SHIFT
;
4317 header
.peerID
= ENET_HOST_TO_NET_16(currentPeer
.outgoingPeerID|host
.headerFlags
);
4318 if (host
.checksum
!is null) {
4319 enet_uint32
* checksum
= cast(enet_uint32
*)&headerData
[host
.buffers
.ptr
[0].dataLength
];
4320 *checksum
= (currentPeer
.outgoingPeerID
< ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer
.connectID
: 0);
4321 host
.buffers
.ptr
[0].dataLength
+= enet_uint32
.sizeof
;
4322 *checksum
= host
.checksum(host
.buffers
.ptr
, host
.bufferCount
);
4325 if (shouldCompress
> 0) {
4326 host
.buffers
.ptr
[1].data
= host
.packetData
.ptr
[1].ptr
;
4327 host
.buffers
.ptr
[1].dataLength
= shouldCompress
;
4328 host
.bufferCount
= 2;
4331 currentPeer
.lastSendTime
= host
.serviceTime
;
4333 sentLength
= enet_socket_send(host
.socket
, ¤tPeer
.address
, host
.buffers
.ptr
, host
.bufferCount
);
4335 enet_protocol_remove_sent_unreliable_commands(currentPeer
);
4337 if (sentLength
< 0) return -1;
4339 host
.totalSentData
+= sentLength
;
4340 ++host
.totalSentPackets
;
4348 /** Sends any queued packets on the host specified to its designated peers.
4351 * host = host to flush
4354 * this function need only be used in circumstances where one wishes to send queued packets earlier than in a call to enet_host_service().
4356 void enet_host_flush (ENetHost
* host
) {
4357 host
.serviceTime
= enet_time_get();
4358 enet_protocol_send_outgoing_commands(host
, null, 0);
4362 /** Checks for any queued events on the host and dispatches one if available.
4365 * host = host to check for events
4366 * event = an event structure where event details will be placed if available
4369 * > 0 if an event was dispatched, 0 if no events are available, < 0 on failure
4371 int enet_host_check_events (ENetHost
* host
, ENetEvent
* event
) {
4372 if (event
is null) return -1;
4373 event
.type
= ENET_EVENT_TYPE_NONE
;
4375 event
.packet
= null;
4376 return enet_protocol_dispatch_incoming_commands(host
, event
);
4380 /** Waits for events on the host specified and shuttles packets between
4381 * the host and its peers.
4384 * host = host to service
4385 * event = an event structure where event details will be placed if one occurs
4386 * if event is null then no events will be delivered
4387 * timeout = number of milliseconds that ENet should wait for events
4390 * > 0 if an event occurred within the specified time limit, 0 if no event occurred, < 0 on failure
4393 * enet_host_service should be called fairly regularly for adequate performance
4395 int enet_host_service (ENetHost
* host
, ENetEvent
* event
, enet_uint32 timeout
) {
4396 enet_uint32 waitCondition
;
4398 if (event
!is null) {
4399 event
.type
= ENET_EVENT_TYPE_NONE
;
4401 event
.packet
= null;
4402 switch (enet_protocol_dispatch_incoming_commands(host
, event
)) {
4404 case -1: version(enet_debug
) { import core
.stdc
.stdio
: perror
; perror("Error dispatching incoming packets"); } return -1;
4409 host
.serviceTime
= enet_time_get();
4410 timeout
+= host
.serviceTime
;
4412 if (ENET_TIME_DIFFERENCE(host
.serviceTime
, host
.bandwidthThrottleEpoch
) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL
) enet_host_bandwidth_throttle(host
);
4413 switch (enet_protocol_send_outgoing_commands(host
, event
, 1)) {
4415 case -1:version(enet_debug
) { import core
.stdc
.stdio
: perror
; perror("Error sending outgoing packets"); } return -1;
4419 switch (enet_protocol_receive_incoming_commands(host
, event
)) {
4421 case -1: version(enet_debug
) { import core
.stdc
.stdio
: perror
; perror("Error receiving incoming packets"); } return -1;
4425 switch (enet_protocol_send_outgoing_commands(host
, event
, 1)) {
4427 case -1: version(enet_debug
) { import core
.stdc
.stdio
: perror
; perror("Error sending outgoing packets"); } return -1;
4431 if (event
!is null) {
4432 switch (enet_protocol_dispatch_incoming_commands (host
, event
)) {
4434 case -1: version(enet_debug
) { import core
.stdc
.stdio
: perror
; perror("Error dispatching incoming packets"); } return -1;
4439 if (ENET_TIME_GREATER_EQUAL(host
.serviceTime
, timeout
)) return 0;
4442 host
.serviceTime
= enet_time_get();
4443 if (ENET_TIME_GREATER_EQUAL(host
.serviceTime
, timeout
)) return 0;
4444 waitCondition
= ENET_SOCKET_WAIT_RECEIVE|ENET_SOCKET_WAIT_INTERRUPT
;
4445 if (enet_socket_wait(host
.socket
, &waitCondition
, ENET_TIME_DIFFERENCE (timeout
, host
.serviceTime
)) != 0) return -1;
4446 } while (waitCondition
&ENET_SOCKET_WAIT_INTERRUPT
);
4448 host
.serviceTime
= enet_time_get ();
4449 } while (waitCondition
&ENET_SOCKET_WAIT_RECEIVE
);
4458 * An adaptive order-2 PPM range coder
4461 // cool helper to translate C defines
4462 template cmacroFixVars(T
...) {
4463 string
cmacroFixVars (string s
, string
[] names
...) {
4464 assert(T
.length
== names
.length
, "cmacroFixVars: names and arguments count mismatch");
4467 // skip empty lines (for pretty printing)
4468 // trim trailing spaces
4469 while (s
.length
> 0 && s
[$-1] <= ' ') s
= s
[0..$-1];
4470 uint linestpos
= 0; // start of the current line
4471 while (pos
< s
.length
) {
4472 if (s
[pos
] > ' ') break;
4473 if (s
[pos
] == '\n') linestpos
= pos
+1;
4477 while (pos
+2 < s
.length
) {
4479 while (epos
+2 < s
.length
&& (s
[epos
] != '$' || s
[epos
+1] != '{')) ++epos
;
4481 if (s
.length
-epos
< 3) break;
4482 res
~= s
[pos
..epos
];
4485 assert(s
[pos
] == '$' && s
[pos
+1] == '{');
4486 bool ascode
= (pos
> 0 && s
[pos
-1] == '$');
4489 if (ascode
) res
= res
[0..$-1]; // remove dollar
4490 foreach (immutable nidx
, string oname
; T
) {
4491 static assert(oname
.length
> 0);
4492 if (s
.length
-pos
>= oname
.length
+1 && s
[pos
+oname
.length
] == '}' && s
[pos
..pos
+oname
.length
] == oname
) {
4494 pos
+= oname
.length
+1;
4496 bool hasbang
= false;
4497 foreach (immutable char ch
; names
[nidx
]) {
4498 if (ch
== '{') break;
4499 if (ch
== '!') { hasbang
= true; break; }
4501 if (hasbang
) res
~= "mixin("~names
[nidx
]~")"; else res
~= names
[nidx
];
4502 if (names
[nidx
][$-1] != '}') res
~= ";";
4509 assert(found
, "unknown variable in macro");
4511 if (pos
< s
.length
) res
~= s
[pos
..$];
4518 /* binary indexed tree of symbols */
4522 enet_uint16 left
, right
;
4524 /* context defined by this symbol */
4525 enet_uint16 symbols
;
4526 enet_uint16 escapes
;
4531 /* adaptation constants tuned aggressively for small packet sizes rather than large file compression */
4533 ENET_RANGE_CODER_TOP
= 1<<24,
4534 ENET_RANGE_CODER_BOTTOM
= 1<<16,
4536 ENET_CONTEXT_SYMBOL_DELTA
= 3,
4537 ENET_CONTEXT_SYMBOL_MINIMUM
= 1,
4538 ENET_CONTEXT_ESCAPE_MINIMUM
= 1,
4540 ENET_SUBCONTEXT_ORDER
= 2,
4541 ENET_SUBCONTEXT_SYMBOL_DELTA
= 2,
4542 ENET_SUBCONTEXT_ESCAPE_DELTA
= 5
4545 /* context exclusion roughly halves compression speed, so disable for now (k8: and i removed it's code) */
4547 struct ENetRangeCoder
{
4548 /* only allocate enough symbols for reasonable MTUs, would need to be larger for large file compression */
4549 ENetSymbol
[4096] symbols
;
4553 public extern(C
) void *enet_range_coder_create () nothrow @trusted {
4554 return enet_malloc(ENetRangeCoder
.sizeof
);
4558 public extern(C
) void enet_range_coder_destroy (void* context
) nothrow @trusted {
4559 if (context
!is null) enet_free(context
);
4562 enum ENET_SYMBOL_CREATE(string symbol
, string value_
, string count_
) = q
{{
4563 ${symbol
} = &rangeCoder
.symbols
.ptr
[nextSymbol
++];
4564 ${symbol
}.value
= ${value_
};
4565 ${symbol
}.count
= ${count_
};
4566 ${symbol
}.under
= ${count_
};
4568 ${symbol
}.right
= 0;
4569 ${symbol
}.symbols
= 0;
4570 ${symbol
}.escapes
= 0;
4571 ${symbol
}.total
= 0;
4572 ${symbol
}.parent
= 0;
4573 }}.cmacroFixVars
!("symbol", "value_", "count_")(symbol
, value_
, count_
);
4575 enum ENET_CONTEXT_CREATE(string context
, string escapes_
, string minimum
) = q
{{
4576 mixin(ENET_SYMBOL_CREATE
!("${context}", "0", "0"));
4577 (${context
}).escapes
= ${escapes_
};
4578 (${context
}).total
= ${escapes_
}+256*${minimum
};
4579 (${context
}).symbols
= 0;
4580 }}.cmacroFixVars
!("context", "escapes_", "minimum")(context
, escapes_
, minimum
);
4583 enet_uint16
enet_symbol_rescale (ENetSymbol
* symbol
) nothrow @trusted @nogc {
4584 enet_uint16 total
= 0;
4586 symbol
.count
-= symbol
.count
>>1;
4587 symbol
.under
= symbol
.count
;
4588 if (symbol
.left
) symbol
.under
+= enet_symbol_rescale(symbol
+symbol
.left
);
4589 total
+= symbol
.under
;
4590 if (!symbol
.right
) break;
4591 symbol
+= symbol
.right
;
4596 enum ENET_CONTEXT_RESCALE(string context
, string minimum
) = q
{{
4597 (${context
}).total
= (${context
}).symbols ?
enet_symbol_rescale((${context
})+(${context
}).symbols
) : 0;
4598 (${context
}).escapes
-= (${context
}).escapes
>>1;
4599 (${context
}).total
+= (${context
}).escapes
+256*${minimum
};
4600 }}.cmacroFixVars
!("context", "minimum")(context
, minimum
);
4602 enum ENET_RANGE_CODER_OUTPUT(string value
) = q
{{
4603 if (outData
>= outEnd
) return 0;
4604 *outData
++ = ${value
};
4605 }}.cmacroFixVars
!("value")(value
);
4607 enum ENET_RANGE_CODER_ENCODE(string under
, string count
, string total
) = q
{{
4608 encodeRange
/= (${total
});
4609 encodeLow
+= (${under
})*encodeRange
;
4610 encodeRange
*= (${count
});
4612 if ((encodeLow^
(encodeLow
+encodeRange
)) >= ENET_RANGE_CODER_TOP
) {
4613 if (encodeRange
>= ENET_RANGE_CODER_BOTTOM
) break;
4614 encodeRange
= -encodeLow
&(ENET_RANGE_CODER_BOTTOM
-1);
4616 mixin(ENET_RANGE_CODER_OUTPUT
!"encodeLow>>24");
4620 }}.cmacroFixVars
!("under", "count", "total")(under
, count
, total
);
4622 enum ENET_RANGE_CODER_FLUSH
= q
{{
4624 mixin(ENET_RANGE_CODER_OUTPUT
!"encodeLow>>24");
4629 enum ENET_RANGE_CODER_FREE_SYMBOLS
= q
{{
4630 if (nextSymbol
>= rangeCoder
.symbols
.sizeof
/ENetSymbol
.sizeof
-ENET_SUBCONTEXT_ORDER
) {
4632 mixin(ENET_CONTEXT_CREATE
!("root", "ENET_CONTEXT_ESCAPE_MINIMUM", "ENET_CONTEXT_SYMBOL_MINIMUM"));
4638 enum ENET_CONTEXT_ENCODE(string context
, string symbol_
, string value_
, string under_
, string count_
, string update
, string minimum
) = q
{{
4639 ${under_
} = value
*${minimum
};
4640 ${count_
} = ${minimum
};
4641 if (!(${context
}).symbols
) {
4642 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4643 (${context
}).symbols
= cast(typeof((${context
}).symbols
))(${symbol_
}-(${context
}));
4645 ENetSymbol
* node
= (${context
})+(${context
}).symbols
;
4647 if (${value_
} < node
.value
) {
4648 node
.under
+= ${update
};
4649 if (node
.left
) { node
+= node
.left
; continue; }
4650 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4651 node
.left
= cast(typeof(node
.left
))(${symbol_
}-node
);
4652 } else if (${value_
} > node
.value
) {
4653 ${under_
} += node
.under
;
4654 if (node
.right
) { node
+= node
.right
; continue; }
4655 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4656 node
.right
= cast(typeof(node
.right
))(${symbol_
}-node
);
4658 ${count_
} += node
.count
;
4659 ${under_
} += node
.under
-node
.count
;
4660 node
.under
+= ${update
};
4661 node
.count
+= ${update
};
4667 }}.cmacroFixVars
!("context","symbol_","value_","under_","count_","update","minimum")(context
,symbol_
,value_
,under_
,count_
,update
,minimum
);
4670 public extern(C
) usize
enet_range_coder_compress (void* context
, const(ENetBuffer
)* inBuffers
, usize inBufferCount
, usize inLimit
, ubyte* outData
, usize outLimit
) nothrow @trusted @nogc {
4671 ENetRangeCoder
* rangeCoder
= cast(ENetRangeCoder
*)context
;
4672 ubyte* outStart
= outData
, outEnd
= &outData
[outLimit
];
4673 const(ubyte)* inData
, inEnd
;
4674 enet_uint32 encodeLow
= 0, encodeRange
= ~0;
4676 ushort predicted
= 0;
4677 usize order
= 0, nextSymbol
= 0;
4679 if (rangeCoder
is null || inBufferCount
<= 0 || inLimit
<= 0) return 0;
4681 inData
= cast(const(ubyte)*)inBuffers
.data
;
4682 inEnd
= &inData
[inBuffers
.dataLength
];
4686 mixin(ENET_CONTEXT_CREATE
!("root", "ENET_CONTEXT_ESCAPE_MINIMUM", "ENET_CONTEXT_SYMBOL_MINIMUM"));
4689 ENetSymbol
* subcontext
, symbol
;
4691 ushort count
, under
, total
;
4692 ushort *parent
= &predicted
;
4693 if (inData
>= inEnd
) {
4694 if (inBufferCount
<= 0) break;
4695 inData
= cast(const(ubyte)*)inBuffers
.data
;
4696 inEnd
= &inData
[inBuffers
.dataLength
];
4702 for (subcontext
= &rangeCoder
.symbols
.ptr
[predicted
]; subcontext
!= root
; subcontext
= &rangeCoder
.symbols
.ptr
[subcontext
.parent
]) {
4703 mixin(ENET_CONTEXT_ENCODE
!("subcontext", "symbol", "value", "under", "count", "ENET_SUBCONTEXT_SYMBOL_DELTA", "0"));
4704 *parent
= cast(ushort)(symbol
-rangeCoder
.symbols
.ptr
);
4705 parent
= &symbol
.parent
;
4706 total
= subcontext
.total
;
4708 mixin(ENET_RANGE_CODER_ENCODE
!("subcontext.escapes+under", "count", "total"));
4710 if (subcontext
.escapes
> 0 && subcontext
.escapes
< total
) { mixin(ENET_RANGE_CODER_ENCODE
!("0", "subcontext.escapes", "total")); }
4711 subcontext
.escapes
+= ENET_SUBCONTEXT_ESCAPE_DELTA
;
4712 subcontext
.total
+= ENET_SUBCONTEXT_ESCAPE_DELTA
;
4714 subcontext
.total
+= ENET_SUBCONTEXT_SYMBOL_DELTA
;
4715 if (count
> 0xFF-2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext
.total
> ENET_RANGE_CODER_BOTTOM
-0x100) { mixin(ENET_CONTEXT_RESCALE
!("subcontext", "0")); }
4716 if (count
> 0) goto nextInput
;
4719 mixin(ENET_CONTEXT_ENCODE
!("root", "symbol", "value", "under", "count", "ENET_CONTEXT_SYMBOL_DELTA", "ENET_CONTEXT_SYMBOL_MINIMUM"));
4720 *parent
= cast(ushort)(symbol
-rangeCoder
.symbols
.ptr
);
4721 parent
= &symbol
.parent
;
4723 mixin(ENET_RANGE_CODER_ENCODE
!("root.escapes+under", "count", "total"));
4724 root
.total
+= ENET_CONTEXT_SYMBOL_DELTA
;
4725 if (count
> 0xFF-2*ENET_CONTEXT_SYMBOL_DELTA
+ENET_CONTEXT_SYMBOL_MINIMUM || root
.total
> ENET_RANGE_CODER_BOTTOM
-0x100) { mixin(ENET_CONTEXT_RESCALE
!("root", "ENET_CONTEXT_SYMBOL_MINIMUM")); }
4728 if (order
>= ENET_SUBCONTEXT_ORDER
) {
4729 predicted
= rangeCoder
.symbols
.ptr
[predicted
].parent
;
4733 mixin(ENET_RANGE_CODER_FREE_SYMBOLS
);
4736 mixin(ENET_RANGE_CODER_FLUSH
);
4738 return cast(usize
)(outData
-outStart
);
4741 enum ENET_RANGE_CODER_SEED
= q
{{
4742 if (inData
< inEnd
) decodeCode |
= *inData
++<<24;
4743 if (inData
< inEnd
) decodeCode |
= *inData
++<<16;
4744 if (inData
< inEnd
) decodeCode |
= *inData
++<<8;
4745 if (inData
< inEnd
) decodeCode |
= *inData
++;
4748 enum ENET_RANGE_CODER_READ(string total
) = q
{((decodeCode
-decodeLow
)/(decodeRange
/= (${total
})))}.cmacroFixVars
!"total"(total
);
4750 enum ENET_RANGE_CODER_DECODE(string under
, string count
, string total
) = q
{{
4751 decodeLow
+= (${under
})*decodeRange
;
4752 decodeRange
*= (${count
});
4754 if ((decodeLow^
(decodeLow
+decodeRange
)) >= ENET_RANGE_CODER_TOP
) {
4755 if (decodeRange
>= ENET_RANGE_CODER_BOTTOM
) break;
4756 decodeRange
= -decodeLow
&(ENET_RANGE_CODER_BOTTOM
-1);
4759 if (inData
< inEnd
) decodeCode |
= *inData
++;
4763 }}.cmacroFixVars
!("under", "count", "total")(under
, count
, total
);
4765 enum ENET_CONTEXT_DECODE(string context
, string symbol_
, string code
, string value_
, string under_
, string count_
, string update
, string minimum
, string createRoot
,
4766 string visitNode
, string createRight
, string createLeft
) =
4769 ${count_
} = ${minimum
};
4770 if (!(${context
}).symbols
) {
4773 ENetSymbol
* node
= (${context
})+(${context
}).symbols
;
4775 ushort after
= cast(ushort)(${under_
}+node
.under
+(node
.value
+1)*${minimum
}), before
= cast(ushort)(node
.count
+${minimum
});
4777 if (${code
} >= after
) {
4778 ${under_
} += node
.under
;
4779 if (node
.right
) { node
+= node
.right
; continue; }
4781 } else if (${code
} < after
-before
) {
4782 node
.under
+= ${update
};
4783 if (node
.left
) { node
+= node
.left
; continue; }
4786 ${value_
} = node
.value
;
4787 ${count_
} += node
.count
;
4788 ${under_
} = cast(typeof(${under_
}))(after
-before
);
4789 node
.under
+= ${update
};
4790 node
.count
+= ${update
};
4796 }}.cmacroFixVars
!("context","symbol_","code","value_","under_","count_","update","minimum","createRoot","visitNode","createRight","createLeft")
4797 (context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
, createRoot
, visitNode
, createRight
, createLeft
);
4799 enum ENET_CONTEXT_TRY_DECODE(string context
, string symbol_
, string code
, string value_
, string under_
, string count_
, string update
, string minimum
, string exclude
) =
4800 ENET_CONTEXT_DECODE
!(context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
, "return 0", exclude
~"(`node.value`, `after`, `before`)", "return 0", "return 0");
4802 enum ENET_CONTEXT_ROOT_DECODE(string context
, string symbol_
, string code
, string value_
, string under_
, string count_
, string update
, string minimum
, string exclude
) =
4803 ENET_CONTEXT_DECODE
!(context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
,
4805 ${value_
} = cast(typeof(${value_
}))(${code
}/${minimum
});
4806 ${under_
} = cast(typeof(${under_
}))(${code
}-${code
}%${minimum
});
4807 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4808 (${context
}).symbols
= cast(typeof((${context
}).symbols
))(${symbol_
}-(${context
}));
4809 }}.cmacroFixVars
!("context","symbol_","code","value_","under_","count_","update","minimum","exclude")(context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
, exclude
),
4810 exclude
~"(`node.value`, `after`, `before`)",
4812 ${value_
} = cast(typeof(${value_
}))(node
.value
+1+(${code
}-after
)/${minimum
});
4813 ${under_
} = cast(typeof(${under_
}))(${code
}-(${code
}-after
)%${minimum
});
4814 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4815 node
.right
= cast(typeof(node
.right
))(${symbol_
}-node
);
4816 }}.cmacroFixVars
!("context","symbol_","code","value_","under_","count_","update","minimum","exclude")(context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
, exclude
),
4818 ${value_
} = cast(typeof(${value_
}))(node
.value
-1-(after
-before
-${code
}-1)/${minimum
});
4819 ${under_
} = cast(typeof(${under_
}))(${code
}-(after
-before
-${code
}-1)%${minimum
});
4820 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4821 node
.left
= cast(typeof(node
.left
))(${symbol_
}-node
);
4822 }}.cmacroFixVars
!("context","symbol_","code","value_","under_","count_","update","minimum","exclude")(context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
, exclude
));
4825 enum ENET_CONTEXT_NOT_EXCLUDED(string value_
, string after
, string before
) = "{}";
4828 public extern(C
) usize
enet_range_coder_decompress (void* context
, const(ubyte)* inData
, usize inLimit
, ubyte* outData
, usize outLimit
) nothrow @trusted @nogc {
4829 ENetRangeCoder
* rangeCoder
= cast(ENetRangeCoder
*)context
;
4830 ubyte* outStart
= outData
, outEnd
= &outData
[outLimit
];
4831 const(ubyte)* inEnd
= &inData
[inLimit
];
4832 enet_uint32 decodeLow
= 0, decodeCode
= 0, decodeRange
= ~0;
4834 ushort predicted
= 0;
4835 usize order
= 0, nextSymbol
= 0;
4837 if (rangeCoder
is null || inLimit
<= 0) return 0;
4839 mixin(ENET_CONTEXT_CREATE
!("root", "ENET_CONTEXT_ESCAPE_MINIMUM", "ENET_CONTEXT_SYMBOL_MINIMUM"));
4841 mixin(ENET_RANGE_CODER_SEED
);
4844 ENetSymbol
* subcontext
, symbol
, patch
;
4846 ushort code
, under
, count
, bottom
, total
;
4847 ushort* parent
= &predicted
;
4849 for (subcontext
= &rangeCoder
.symbols
.ptr
[predicted
]; subcontext
!= root
; subcontext
= &rangeCoder
.symbols
.ptr
[subcontext
.parent
]) {
4850 if (subcontext
.escapes
<= 0) continue;
4851 total
= subcontext
.total
;
4852 if (subcontext
.escapes
>= total
) continue;
4853 code
= cast(ushort)(mixin(ENET_RANGE_CODER_READ
!"total"));
4854 if (code
< subcontext
.escapes
) {
4855 mixin(ENET_RANGE_CODER_DECODE
!("0", "subcontext.escapes", "total"));
4858 code
-= subcontext
.escapes
;
4860 mixin(ENET_CONTEXT_TRY_DECODE
!("subcontext", "symbol", "code", "value", "under", "count", "ENET_SUBCONTEXT_SYMBOL_DELTA", "0", "ENET_CONTEXT_NOT_EXCLUDED!"));
4862 bottom
= cast(ushort)(symbol
-rangeCoder
.symbols
.ptr
);
4863 mixin(ENET_RANGE_CODER_DECODE
!("subcontext.escapes+under", "count", "total"));
4864 subcontext
.total
+= ENET_SUBCONTEXT_SYMBOL_DELTA
;
4865 if (count
> 0xFF-2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext
.total
> ENET_RANGE_CODER_BOTTOM
-0x100) { mixin(ENET_CONTEXT_RESCALE
!("subcontext", "0")); }
4870 code
= cast(ushort)(mixin(ENET_RANGE_CODER_READ
!"total"));
4871 if (code
< root
.escapes
) {
4872 mixin(ENET_RANGE_CODER_DECODE
!("0", "root.escapes", "total"));
4875 code
-= root
.escapes
;
4877 mixin(ENET_CONTEXT_ROOT_DECODE
!("root", "symbol", "code", "value", "under", "count", "ENET_CONTEXT_SYMBOL_DELTA", "ENET_CONTEXT_SYMBOL_MINIMUM", "ENET_CONTEXT_NOT_EXCLUDED!"));
4879 bottom
= cast(ushort)(symbol
-rangeCoder
.symbols
.ptr
);
4880 mixin(ENET_RANGE_CODER_DECODE
!("root.escapes+under", "count", "total"));
4881 root
.total
+= ENET_CONTEXT_SYMBOL_DELTA
;
4882 if (count
> 0xFF-2*ENET_CONTEXT_SYMBOL_DELTA
+ENET_CONTEXT_SYMBOL_MINIMUM || root
.total
> ENET_RANGE_CODER_BOTTOM
-0x100) { mixin(ENET_CONTEXT_RESCALE
!("root", "ENET_CONTEXT_SYMBOL_MINIMUM")); }
4885 for (patch
= &rangeCoder
.symbols
.ptr
[predicted
]; patch
!= subcontext
; patch
= &rangeCoder
.symbols
.ptr
[patch
.parent
]) {
4886 mixin(ENET_CONTEXT_ENCODE
!("patch", "symbol", "value", "under", "count", "ENET_SUBCONTEXT_SYMBOL_DELTA", "0"));
4887 *parent
= cast(ushort)(symbol
-rangeCoder
.symbols
.ptr
);
4888 parent
= &symbol
.parent
;
4890 patch
.escapes
+= ENET_SUBCONTEXT_ESCAPE_DELTA
;
4891 patch
.total
+= ENET_SUBCONTEXT_ESCAPE_DELTA
;
4893 patch
.total
+= ENET_SUBCONTEXT_SYMBOL_DELTA
;
4894 if (count
> 0xFF-2*ENET_SUBCONTEXT_SYMBOL_DELTA || patch
.total
> ENET_RANGE_CODER_BOTTOM
-0x100) { mixin(ENET_CONTEXT_RESCALE
!("patch", "0")); }
4898 mixin(ENET_RANGE_CODER_OUTPUT
!"value");
4900 if (order
>= ENET_SUBCONTEXT_ORDER
) {
4901 predicted
= rangeCoder
.symbols
.ptr
[predicted
].parent
;
4905 mixin(ENET_RANGE_CODER_FREE_SYMBOLS
);
4908 return cast(usize
)(outData
-outStart
);
4911 /** @defgroup host ENet host functions
4915 /** Sets the packet compressor the host should use to the default range coder.
4916 @param host host to enable the range coder for
4917 @returns 0 on success, < 0 on failure
4919 public int enet_host_compress_with_range_coder (ENetHost
* host
) nothrow {
4920 import core
.stdc
.string
: memset
;
4922 ENetCompressor compressor
= void;
4923 memset(&compressor
, 0, compressor
.sizeof
);
4924 compressor
.context
= enet_range_coder_create();
4925 if (compressor
.context
is null) return -1;
4926 compressor
.compress
= &enet_range_coder_compress
;
4927 compressor
.decompress
= &enet_range_coder_decompress
;
4928 compressor
.destroy
= &enet_range_coder_destroy
;
4929 enet_host_compress(host
, &compressor
);