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, either version 3 of the License, or
31 * (at your option) any later version.
33 * This program is distributed in the hope that it will be useful,
34 * but WITHOUT ANY WARRANTY; without even the implied warranty of
35 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
36 * GNU General Public License for more details.
38 * You should have received a copy of the GNU General Public License
39 * along with this program. If not, see <http://www.gnu.org/licenses/>.
41 module iv
.enet
/*is aliced*/;
47 ushort ENET_HOST_TO_NET_16 (ushort x
) @safe pure @nogc nothrow {
52 uint ENET_HOST_TO_NET_32 (uint x
) @safe pure @nogc nothrow {
56 } else version(LittleEndian
) {
57 ushort ENET_HOST_TO_NET_16 (ushort x
) @safe pure @nogc nothrow {
59 return ((x
&255)<<8)|
(x
>>8);
62 uint ENET_HOST_TO_NET_32 (uint x
) @safe pure @nogc nothrow {
64 import core
.bitop
: bswap;
68 static assert(false, "Compiling on another planet!");
72 alias ENET_NET_TO_HOST_16
= ENET_HOST_TO_NET_16
;
73 alias ENET_NET_TO_HOST_32
= ENET_HOST_TO_NET_32
;
77 import core
.sys
.windows
.mmsystem
;
78 import core
.sys
.windows
.winsock2
;
80 alias ENetSocket
= int;
81 enum ENET_SOCKET_NULL
= -1;
83 alias ENetSocketSet
= core
.sys
.windows
.winsock2
.fd_set
;
97 alias ENetSocket = SOCKET;
99 enum ENET_SOCKET_NULL = ~0;
101 align(1) struct ENetBuffer {
109 enum FD_SETSIZE = 64;
112 uint fd_count; // how many are SET?
113 SOCKET[FD_SETSIZE] fd_array; // an array of SOCKETs
116 alias fd_set ENetSocketSet;
118 void ENET_SOCKETSET_EMPTY() (ref ENetSocketSet sockset) {
119 sockset.fd_count = 0;
122 void ENET_SOCKETSET_ADD() (ref ENetSocketSet sockset, ENetSocket socket) {
123 foreach (immutable i; 0..sockset.fd_count) if (sockset.fd_array[i] == socket) return;
124 if (sockset.fd_count < FD_SETSIZE) {
125 sockset.fd_array[i] = socket;
130 bool ENET_SOCKETSET_CHECK() (ref ENetSocketSet sockset, ENetSocket socket) {
131 foreach (immutable i; 0..sockset.fd_count) if (sockset.fd_array[i] == socket) return true;
135 void ENET_SOCKETSET_REMOVE() (ref ENetSocketSet sockset, ENetSocket socket) {
136 foreach (usize i; 0..sockset.fd_count) {
137 if (sockset.fd_array[i] == socket) {
138 while (i < sockset.fd_count-1) {
139 sockset.fd_array[i] = sockset.fd_array[i+1];
149 static import core
.sys
.posix
.sys
.select
; // fd_set
151 alias ENetSocket
= int;
152 enum ENET_SOCKET_NULL
= -1;
154 alias ENetSocketSet
= core
.sys
.posix
.sys
.select
.fd_set
;
156 align(1) struct ENetBuffer
{
165 alias enet_uint8
= ubyte;
166 alias enet_uint16
= ushort;
167 alias enet_uint32
= uint;
172 ENET_PROTOCOL_MINIMUM_MTU
= 576,
173 ENET_PROTOCOL_MAXIMUM_MTU
= 4096,
174 ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS
= 32,
175 ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
= 4096,
177 // Warning when using this constant, it depends on the linked library version:
178 // - enet <= 1.3.9 defines ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE as 32768
179 // - enet >= 1.3.9 defines ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE as 65536
180 ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
= 65536,
182 ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
= 1,
183 ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
= 255,
184 ENET_PROTOCOL_MAXIMUM_PEER_ID
= 0xFFF,
185 ENET_PROTOCOL_MAXIMUM_PACKET_SIZE
= 1024*1024*1024,
186 ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT
= 1024*1024,
189 alias ENetProtocolCommand
= int;
190 enum : ENetProtocolCommand
{
191 ENET_PROTOCOL_COMMAND_NONE
= 0,
192 ENET_PROTOCOL_COMMAND_ACKNOWLEDGE
= 1,
193 ENET_PROTOCOL_COMMAND_CONNECT
= 2,
194 ENET_PROTOCOL_COMMAND_VERIFY_CONNECT
= 3,
195 ENET_PROTOCOL_COMMAND_DISCONNECT
= 4,
196 ENET_PROTOCOL_COMMAND_PING
= 5,
197 ENET_PROTOCOL_COMMAND_SEND_RELIABLE
= 6,
198 ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE
= 7,
199 ENET_PROTOCOL_COMMAND_SEND_FRAGMENT
= 8,
200 ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
= 9,
201 ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT
= 10,
202 ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE
= 11,
203 ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT
= 12,
204 ENET_PROTOCOL_COMMAND_COUNT
= 13,
206 ENET_PROTOCOL_COMMAND_MASK
= 0x0F,
209 alias ENetProtocolFlag
= int;
210 enum : ENetProtocolFlag
{
211 ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
= (1 << 7),
212 ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED
= (1 << 6),
214 ENET_PROTOCOL_HEADER_FLAG_COMPRESSED
= (1 << 14),
215 ENET_PROTOCOL_HEADER_FLAG_SENT_TIME
= (1 << 15),
216 ENET_PROTOCOL_HEADER_FLAG_MASK
= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED|ENET_PROTOCOL_HEADER_FLAG_SENT_TIME
,
218 ENET_PROTOCOL_HEADER_SESSION_MASK
= (3 << 12),
219 ENET_PROTOCOL_HEADER_SESSION_SHIFT
= 12,
222 align(1) struct ENetProtocolHeader
{
225 enet_uint16 sentTime
;
228 align(1) struct ENetProtocolCommandHeader
{
231 enet_uint8 channelID
;
232 enet_uint16 reliableSequenceNumber
;
235 align(1) struct ENetProtocolAcknowledge
{
237 ENetProtocolCommandHeader header
;
238 enet_uint16 receivedReliableSequenceNumber
;
239 enet_uint16 receivedSentTime
;
242 align(1) struct ENetProtocolConnect
{
244 ENetProtocolCommandHeader header
;
245 enet_uint16 outgoingPeerID
;
246 enet_uint8 incomingSessionID
;
247 enet_uint8 outgoingSessionID
;
249 enet_uint32 windowSize
;
250 enet_uint32 channelCount
;
251 enet_uint32 incomingBandwidth
;
252 enet_uint32 outgoingBandwidth
;
253 enet_uint32 packetThrottleInterval
;
254 enet_uint32 packetThrottleAcceleration
;
255 enet_uint32 packetThrottleDeceleration
;
256 enet_uint32 connectID
;
260 align(1) struct ENetProtocolVerifyConnect
{
262 ENetProtocolCommandHeader header
;
263 enet_uint16 outgoingPeerID
;
264 enet_uint8 incomingSessionID
;
265 enet_uint8 outgoingSessionID
;
267 enet_uint32 windowSize
;
268 enet_uint32 channelCount
;
269 enet_uint32 incomingBandwidth
;
270 enet_uint32 outgoingBandwidth
;
271 enet_uint32 packetThrottleInterval
;
272 enet_uint32 packetThrottleAcceleration
;
273 enet_uint32 packetThrottleDeceleration
;
274 enet_uint32 connectID
;
277 align(1) struct ENetProtocolBandwidthLimit
{
279 ENetProtocolCommandHeader header
;
280 enet_uint32 incomingBandwidth
;
281 enet_uint32 outgoingBandwidth
;
284 align(1) struct ENetProtocolThrottleConfigure
{
286 ENetProtocolCommandHeader header
;
287 enet_uint32 packetThrottleInterval
;
288 enet_uint32 packetThrottleAcceleration
;
289 enet_uint32 packetThrottleDeceleration
;
292 align(1) struct ENetProtocolDisconnect
{
294 ENetProtocolCommandHeader header
;
298 align(1) struct ENetProtocolPing
{
300 ENetProtocolCommandHeader header
;
303 align(1) struct ENetProtocolSendReliable
{
305 ENetProtocolCommandHeader header
;
306 enet_uint16 dataLength
;
309 align(1) struct ENetProtocolSendUnreliable
{
311 ENetProtocolCommandHeader header
;
312 enet_uint16 unreliableSequenceNumber
;
313 enet_uint16 dataLength
;
316 align(1) struct ENetProtocolSendUnsequenced
{
318 ENetProtocolCommandHeader header
;
319 enet_uint16 unsequencedGroup
;
320 enet_uint16 dataLength
;
323 align(1) struct ENetProtocolSendFragment
{
325 ENetProtocolCommandHeader header
;
326 enet_uint16 startSequenceNumber
;
327 enet_uint16 dataLength
;
328 enet_uint32 fragmentCount
;
329 enet_uint32 fragmentNumber
;
330 enet_uint32 totalLength
;
331 enet_uint32 fragmentOffset
;
334 align(1) union ENetProtocol
{
336 ENetProtocolCommandHeader header
;
337 ENetProtocolAcknowledge acknowledge
;
338 ENetProtocolConnect connect
;
339 ENetProtocolVerifyConnect verifyConnect
;
340 ENetProtocolDisconnect disconnect
;
341 ENetProtocolPing ping
;
342 ENetProtocolSendReliable sendReliable
;
343 ENetProtocolSendUnreliable sendUnreliable
;
344 ENetProtocolSendUnsequenced sendUnsequenced
;
345 ENetProtocolSendFragment sendFragment
;
346 ENetProtocolBandwidthLimit bandwidthLimit
;
347 ENetProtocolThrottleConfigure throttleConfigure
;
352 struct ENetListNode
{
354 ENetListNode
* previous
;
358 ENetListNode sentinel
;
363 struct ENetCallbacks
{
365 void* function (usize size
) malloc
;
366 void function (void* memory
) free
;
367 void function () no_memory
;
370 //extern(C) void* enet_malloc (usize) nothrow @trusted;
371 //extern(C) void enet_free (void*) nothrow @trusted;
376 ENET_VERSION_MAJOR
= 1,
377 ENET_VERSION_MINOR
= 3,
378 ENET_VERSION_PATCH
= 13,
381 int ENET_VERSION_CREATE() (int major
, int minor
, int patch
) pure nothrow @safe @nogc {
382 pragma(inline
, true);
383 return (major
<< 16) |
(minor
<< 8) | patch
;
386 int ENET_VERSION_GET_MAJOR() (int version_
) pure nothrow @safe @nogc {
387 pragma(inline
, true);
388 return (version_
>> 16) & 0xFF;
391 int ENET_VERSION_GET_MINOR() (int version_
) pure nothrow @safe @nogc {
392 pragma(inline
, true);
393 return (version_
>> 8) & 0xFF;
396 int ENET_VERSION_GET_PATCH() (int version_
) pure nothrow @safe @nogc {
397 pragma(inline
, true);
398 return version_
& 0xFF;
401 enum ENET_VERSION
= ENET_VERSION_CREATE(ENET_VERSION_MAJOR
, ENET_VERSION_MINOR
, ENET_VERSION_PATCH
);
403 alias ENetVersion
= enet_uint32
;
405 alias ENetSocketType
= int;
406 enum : ENetSocketType
{
407 ENET_SOCKET_TYPE_STREAM
= 1,
408 ENET_SOCKET_TYPE_DATAGRAM
= 2,
411 alias ENetSocketWait
= int;
412 enum : ENetSocketWait
{
413 ENET_SOCKET_WAIT_NONE
= 0,
414 ENET_SOCKET_WAIT_SEND
= (1<<0),
415 ENET_SOCKET_WAIT_RECEIVE
= (1<<1),
416 ENET_SOCKET_WAIT_INTERRUPT
= (1<<2),
419 alias ENetSocketOption
= int;
420 enum : ENetSocketOption
{
421 ENET_SOCKOPT_NONBLOCK
= 1,
422 ENET_SOCKOPT_BROADCAST
= 2,
423 ENET_SOCKOPT_RCVBUF
= 3,
424 ENET_SOCKOPT_SNDBUF
= 4,
425 ENET_SOCKOPT_REUSEADDR
= 5,
426 ENET_SOCKOPT_RCVTIMEO
= 6,
427 ENET_SOCKOPT_SNDTIMEO
= 7,
428 ENET_SOCKOPT_ERROR
= 8,
429 ENET_SOCKOPT_NODELAY
= 9,
432 alias ENetSocketShutdown
= int;
433 enum : ENetSocketShutdown
{
434 ENET_SOCKET_SHUTDOWN_READ
= 0,
435 ENET_SOCKET_SHUTDOWN_WRITE
= 1,
436 ENET_SOCKET_SHUTDOWN_READ_WRITE
= 2,
441 ENET_HOST_BROADCAST
= 0xFFFFFFFFU
,
447 * Portable internet address structure.
449 * The host must be specified in network byte-order, and the port must be in host
450 * byte-order. The constant ENET_HOST_ANY may be used to specify the default
451 * server host. The constant ENET_HOST_BROADCAST may be used to specify the
452 * broadcast address (255.255.255.255). This makes sense for enet_host_connect,
453 * but not for enet_host_create. Once a server responds to a broadcast, the
454 * address is updated from ENET_HOST_BROADCAST to the server's actual IP address.
462 * Packet flag bit constants.
464 * The host must be specified in network byte-order, and the port must be in
465 * host byte-order. The constant ENET_HOST_ANY may be used to specify the
466 * default server host.
468 alias ENetPacketFlag
= int;
469 enum : ENetPacketFlag
{
470 /** packet must be received by the target peer and resend attempts should be
471 * made until the packet is delivered */
472 ENET_PACKET_FLAG_RELIABLE
= (1 << 0),
473 /** packet will not be sequenced with other packets
474 * not supported for reliable packets
476 ENET_PACKET_FLAG_UNSEQUENCED
= (1 << 1),
477 /** packet will not allocate data, and user must supply it instead */
478 ENET_PACKET_FLAG_NO_ALLOCATE
= (1 << 2),
479 /** packet will be fragmented using unreliable (instead of reliable) sends
480 * if it exceeds the MTU */
481 ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT
= (1 << 3),
483 /** whether the packet has been sent from all queues it has been entered into */
484 ENET_PACKET_FLAG_SENT
= (1<<8),
487 alias extern(C
) nothrow void function (ENetPacket
*) ENetPacketFreeCallback
;
490 * ENet packet structure.
492 * An ENet data packet that may be sent to or received from a peer. The shown
493 * fields should only be read and never modified. The data field contains the
494 * allocated data for the packet. The dataLength fields specifies the length
495 * of the allocated data. The flags field is either 0 (specifying no flags),
496 * or a bitwise-or of any combination of the following flags:
498 * ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer
499 * and resend attempts should be made until the packet is delivered
501 * ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets
502 * (not supported for reliable packets)
504 * ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead
506 * ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable
507 * (instead of reliable) sends if it exceeds the MTU
509 * ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into
512 usize referenceCount
; /** internal use only */
513 enet_uint32 flags
; /** bitwise-or of ENetPacketFlag constants */
514 enet_uint8
* data
; /** allocated data for packet */
515 usize dataLength
; /** length of data */
516 ENetPacketFreeCallback freeCallback
; /** function to be called when the packet is no longer in use */
517 void* userData
; /** application private data, may be freely modified */
520 struct ENetAcknowledgement
{
521 ENetListNode acknowledgementList
;
522 enet_uint32 sentTime
;
523 ENetProtocol command
;
526 struct ENetOutgoingCommand
{
527 ENetListNode outgoingCommandList
;
528 enet_uint16 reliableSequenceNumber
;
529 enet_uint16 unreliableSequenceNumber
;
530 enet_uint32 sentTime
;
531 enet_uint32 roundTripTimeout
;
532 enet_uint32 roundTripTimeoutLimit
;
533 enet_uint32 fragmentOffset
;
534 enet_uint16 fragmentLength
;
535 enet_uint16 sendAttempts
;
536 ENetProtocol command
;
540 struct ENetIncomingCommand
{
541 ENetListNode incomingCommandList
;
542 enet_uint16 reliableSequenceNumber
;
543 enet_uint16 unreliableSequenceNumber
;
544 ENetProtocol command
;
545 enet_uint32 fragmentCount
;
546 enet_uint32 fragmentsRemaining
;
547 enet_uint32
* fragments
;
551 alias ENetPeerState
= int;
552 enum : ENetPeerState
{
553 ENET_PEER_STATE_DISCONNECTED
= 0,
554 ENET_PEER_STATE_CONNECTING
= 1,
555 ENET_PEER_STATE_ACKNOWLEDGING_CONNECT
= 2,
556 ENET_PEER_STATE_CONNECTION_PENDING
= 3,
557 ENET_PEER_STATE_CONNECTION_SUCCEEDED
= 4,
558 ENET_PEER_STATE_CONNECTED
= 5,
559 ENET_PEER_STATE_DISCONNECT_LATER
= 6,
560 ENET_PEER_STATE_DISCONNECTING
= 7,
561 ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT
= 8,
562 ENET_PEER_STATE_ZOMBIE
= 9,
565 enum ENET_BUFFER_MAXIMUM
= 1+2*ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS
;
568 ENET_HOST_RECEIVE_BUFFER_SIZE
= 256*1024,
569 ENET_HOST_SEND_BUFFER_SIZE
= 256*1024,
570 ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL
= 1000,
571 ENET_HOST_DEFAULT_MTU
= 1400,
572 ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE
= 32*1024*1024,
573 ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA
= 32*1024*1024,
575 ENET_PEER_DEFAULT_ROUND_TRIP_TIME
= 500,
576 ENET_PEER_DEFAULT_PACKET_THROTTLE
= 32,
577 ENET_PEER_PACKET_THROTTLE_SCALE
= 32,
578 ENET_PEER_PACKET_THROTTLE_COUNTER
= 7,
579 ENET_PEER_PACKET_THROTTLE_ACCELERATION
= 2,
580 ENET_PEER_PACKET_THROTTLE_DECELERATION
= 2,
581 ENET_PEER_PACKET_THROTTLE_INTERVAL
= 5000,
582 ENET_PEER_PACKET_LOSS_SCALE
= (1 << 16),
583 ENET_PEER_PACKET_LOSS_INTERVAL
= 10000,
584 ENET_PEER_WINDOW_SIZE_SCALE
= 64 * 1024,
585 ENET_PEER_TIMEOUT_LIMIT
= 32,
586 ENET_PEER_TIMEOUT_MINIMUM
= 5000,
587 ENET_PEER_TIMEOUT_MAXIMUM
= 30000,
588 ENET_PEER_PING_INTERVAL
= 500,
589 ENET_PEER_UNSEQUENCED_WINDOWS
= 64,
590 ENET_PEER_UNSEQUENCED_WINDOW_SIZE
= 1024,
591 ENET_PEER_FREE_UNSEQUENCED_WINDOWS
= 32,
592 ENET_PEER_RELIABLE_WINDOWS
= 16,
593 ENET_PEER_RELIABLE_WINDOW_SIZE
= 0x1000,
594 ENET_PEER_FREE_RELIABLE_WINDOWS
= 8,
598 enet_uint16 outgoingReliableSequenceNumber
;
599 enet_uint16 outgoingUnreliableSequenceNumber
;
600 enet_uint16 usedReliableWindows
;
601 enet_uint16
[ENET_PEER_RELIABLE_WINDOWS
] reliableWindows
;
602 enet_uint16 incomingReliableSequenceNumber
;
603 enet_uint16 incomingUnreliableSequenceNumber
;
604 ENetList incomingReliableCommands
;
605 ENetList incomingUnreliableCommands
;
609 * An ENet peer which data packets may be sent or received from.
611 * No fields should be modified unless otherwise specified.
614 ENetListNode dispatchList
;
616 enet_uint16 outgoingPeerID
;
617 enet_uint16 incomingPeerID
;
618 enet_uint32 connectID
;
619 enet_uint8 outgoingSessionID
;
620 enet_uint8 incomingSessionID
;
621 ENetAddress address
; /** Internet address of the peer */
622 void* data
; /** Application private data, may be freely modified */
624 ENetChannel
* channels
;
625 usize channelCount
; /** Number of channels allocated for communication with peer */
626 enet_uint32 incomingBandwidth
; /** Downstream bandwidth of the client in bytes/second */
627 enet_uint32 outgoingBandwidth
; /** Upstream bandwidth of the client in bytes/second */
628 enet_uint32 incomingBandwidthThrottleEpoch
;
629 enet_uint32 outgoingBandwidthThrottleEpoch
;
630 enet_uint32 incomingDataTotal
;
631 enet_uint32 outgoingDataTotal
;
632 enet_uint32 lastSendTime
;
633 enet_uint32 lastReceiveTime
;
634 enet_uint32 nextTimeout
;
635 enet_uint32 earliestTimeout
;
636 enet_uint32 packetLossEpoch
;
637 enet_uint32 packetsSent
;
638 enet_uint32 packetsLost
;
639 enet_uint32 packetLoss
; /** mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */
640 enet_uint32 packetLossVariance
;
641 enet_uint32 packetThrottle
;
642 enet_uint32 packetThrottleLimit
;
643 enet_uint32 packetThrottleCounter
;
644 enet_uint32 packetThrottleEpoch
;
645 enet_uint32 packetThrottleAcceleration
;
646 enet_uint32 packetThrottleDeceleration
;
647 enet_uint32 packetThrottleInterval
;
648 enet_uint32 pingInterval
;
649 enet_uint32 timeoutLimit
;
650 enet_uint32 timeoutMinimum
;
651 enet_uint32 timeoutMaximum
;
652 enet_uint32 lastRoundTripTime
;
653 enet_uint32 lowestRoundTripTime
;
654 enet_uint32 lastRoundTripTimeVariance
;
655 enet_uint32 highestRoundTripTimeVariance
;
656 enet_uint32 roundTripTime
; /** mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */
657 enet_uint32 roundTripTimeVariance
;
659 enet_uint32 windowSize
;
660 enet_uint32 reliableDataInTransit
;
661 enet_uint16 outgoingReliableSequenceNumber
;
662 ENetList acknowledgements
;
663 ENetList sentReliableCommands
;
664 ENetList sentUnreliableCommands
;
665 ENetList outgoingReliableCommands
;
666 ENetList outgoingUnreliableCommands
;
667 ENetList dispatchedCommands
;
669 enet_uint16 incomingUnsequencedGroup
;
670 enet_uint16 outgoingUnsequencedGroup
;
671 enet_uint32
[ENET_PEER_UNSEQUENCED_WINDOW_SIZE
/32] unsequencedWindow
;
672 enet_uint32 eventData
;
673 usize totalWaitingData
;
676 /** An ENet packet compressor for compressing UDP packets before socket sends or receives.
678 struct ENetCompressor
{
679 /** Context data for the compressor. Must be non-null. */
681 extern(C
) nothrow @trusted:
682 /** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */
683 usize
function (void* context
, const(ENetBuffer
)* inBuffers
, usize inBufferCount
, usize inLimit
, enet_uint8
* outData
, usize outLimit
) @nogc compress
;
684 /** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */
685 usize
function (void* context
, const(enet_uint8
)* inData
, usize inLimit
, enet_uint8
* outData
, usize outLimit
) @nogc decompress
;
686 /** Destroys the context when compression is disabled or the host is destroyed. May be null. */
687 void function (void* context
) destroy
;
690 /** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */
691 extern(C
) nothrow @trusted @nogc {
692 alias ENetChecksumCallback
= enet_uint32
function (const(ENetBuffer
)* buffers
, usize bufferCount
);
694 /** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */
695 alias ENetInterceptCallback
= int function (ENetHost
* host
, ENetEvent
* event
);
698 /** An ENet host for communicating with peers.
700 * No fields should be modified unless otherwise stated.
702 @sa enet_host_create()
703 @sa enet_host_destroy()
704 @sa enet_host_connect()
705 @sa enet_host_service()
706 @sa enet_host_flush()
707 @sa enet_host_broadcast()
708 @sa enet_host_compress()
709 @sa enet_host_compress_with_range_coder()
710 @sa enet_host_channel_limit()
711 @sa enet_host_bandwidth_limit()
712 @sa enet_host_bandwidth_throttle()
716 ENetAddress address
; /** Internet address of the host */
717 enet_uint32 incomingBandwidth
; /** downstream bandwidth of the host */
718 enet_uint32 outgoingBandwidth
; /** upstream bandwidth of the host */
719 enet_uint32 bandwidthThrottleEpoch
;
721 enet_uint32 randomSeed
;
722 int recalculateBandwidthLimits
;
723 ENetPeer
* peers
; /** array of peers allocated for this host */
724 usize peerCount
; /** number of peers allocated for this host */
725 usize channelLimit
; /** maximum number of channels allowed for connected peers */
726 enet_uint32 serviceTime
;
727 ENetList dispatchQueue
;
730 enet_uint16 headerFlags
;
731 ENetProtocol
[ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS
] commands
;
733 ENetBuffer
[ENET_BUFFER_MAXIMUM
] buffers
;
735 ENetChecksumCallback checksum
; /** callback the user can set to enable packet checksums for this host */
736 ENetCompressor compressor
;
737 enet_uint8
[ENET_PROTOCOL_MAXIMUM_MTU
][2] packetData
;
738 ENetAddress receivedAddress
;
739 enet_uint8
* receivedData
;
740 usize receivedDataLength
;
741 enet_uint32 totalSentData
; /** total data sent, user should reset to 0 as needed to prevent overflow */
742 enet_uint32 totalSentPackets
; /** total UDP packets sent, user should reset to 0 as needed to prevent overflow */
743 enet_uint32 totalReceivedData
; /** total data received, user should reset to 0 as needed to prevent overflow */
744 enet_uint32 totalReceivedPackets
; /** total UDP packets received, user should reset to 0 as needed to prevent overflow */
745 ENetInterceptCallback intercept
; /** callback the user can set to intercept received raw UDP packets */
746 usize connectedPeers
;
747 usize bandwidthLimitedPeers
;
748 usize duplicatePeers
; /** optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */
749 usize maximumPacketSize
; /** the maximum allowable packet size that may be sent or received on a peer */
750 usize maximumWaitingData
; /** the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */
754 * An ENet event type, as specified in @ref ENetEvent.
756 alias ENetEventType
= int;
757 enum : ENetEventType
{
758 /** no event occurred within the specified time limit */
759 ENET_EVENT_TYPE_NONE
= 0,
761 /** a connection request initiated by enet_host_connect has completed.
762 * The peer field contains the peer which successfully connected.
764 ENET_EVENT_TYPE_CONNECT
= 1,
766 /** a peer has disconnected. This event is generated on a successful
767 * completion of a disconnect initiated by enet_pper_disconnect, if
768 * a peer has timed out, or if a connection request intialized by
769 * enet_host_connect has timed out. The peer field contains the peer
770 * which disconnected. The data field contains user supplied data
771 * describing the disconnection, or 0, if none is available.
773 ENET_EVENT_TYPE_DISCONNECT
= 2,
775 /** a packet has been received from a peer. The peer field specifies the
776 * peer which sent the packet. The channelID field specifies the channel
777 * number upon which the packet was received. The packet field contains
778 * the packet that was received; this packet must be destroyed with
779 * enet_packet_destroy after use.
781 ENET_EVENT_TYPE_RECEIVE
= 3,
785 * An ENet event as returned by enet_host_service().
788 ENetEventType type
; /** type of the event */
789 ENetPeer
* peer
; /** peer that generated a connect, disconnect or receive event */
790 enet_uint8 channelID
; /** channel on the peer that generated the event, if appropriate */
791 enet_uint32 data
; /** data associated with the event, if appropriate */
792 ENetPacket
* packet
; /** packet associated with the event, if appropriate */
796 private __gshared enet_uint32 timeBase
= 0;
798 version(Windows
) nothrow @nogc {
799 //static assert(0, "windoze socket module is not here");
800 pragma(lib
, "ws2_32");
801 pragma(lib
, "winmm");
802 import core
.sys
.windows
.mmsystem
;
803 import core
.sys
.windows
.winsock2
;
804 import core
.sys
.windows
.windef
: DWORD
, LPDWORD
;
806 private __gshared
bool shitdozeinited
= false;
808 shared static this () {
810 if (WSAStartup(0x0101, &wsaData
)) return;
811 if ((wsaData
.wVersion
&0xffff) != 0x0101) {
816 shitdozeinited
= true;
819 shared static ~this () {
820 if (shitdozeinited
) {
823 shitdozeinited
= false;
827 int enet_initialize () {
828 return (shitdozeinited ?
0 : -1);
831 void enet_deinitialize () {
834 enet_uint32
enet_host_random_seed () {
835 return cast(enet_uint32
)timeGetTime();
838 enet_uint32
enet_time_get () {
839 return cast(enet_uint32
)timeGetTime()-timeBase
;
842 void enet_time_set (enet_uint32 newTimeBase
) {
843 timeBase
= cast(enet_uint32
)timeGetTime()-newTimeBase
;
846 int enet_address_set_host_ip (ENetAddress
* address
, const(char)[] name
) {
848 enet_uint8
[4] vals
= 0;
849 foreach (immutable i
, ref ubyte v
; vals
[]) {
851 while (name
.length
) {
852 char ch
= name
.ptr
[0];
854 if (ch
< '0' || ch
> '9') return -1;
856 if (val
> 255) return -1;
860 if (name
.ptr
[0] != '.') return -1;
865 import core
.stdc
.string
: memcpy
;
866 memcpy(&address
.host
, vals
.ptr
, enet_uint32
.sizeof
);
870 int enet_address_set_host (ENetAddress
* address
, const(char)[] namestr
) {
871 import std
.internal
.cstring
: tempCString
;
872 auto name
= namestr
.tempCString
;
873 hostent
* hostEntry
= gethostbyname(name
);
874 if (hostEntry
is null || hostEntry
.h_addrtype
!= AF_INET
) return enet_address_set_host_ip(address
, namestr
);
875 address
.host
= *cast(const(enet_uint32
)*)hostEntry
.h_addr_list
[0];
879 int enet_address_get_host_ip (const ENetAddress
* address
, char* name
, usize nameLength
) {
880 import core
.stdc
.string
: memcpy
, strlen
;
881 char* addr
= inet_ntoa(*cast(const(in_addr
)*)&address
.host
);
882 if (addr
is null) return -1;
883 usize addrLen
= strlen(addr
);
884 if (addrLen
>= nameLength
) return -1;
885 memcpy(name
, addr
, addrLen
+1);
889 int enet_address_get_host (const ENetAddress
* address
, char* name
, usize nameLength
) {
893 in_
.s_addr
= address
.host
;
895 hostEntry
= gethostbyaddr(cast(char*)&in_
, in_addr
.sizeof
, AF_INET
);
896 if (hostEntry
is null) {
897 return enet_address_get_host_ip(address
, name
, nameLength
);
899 import core
.stdc
.string
: memcpy
, strlen
;
900 usize hostLen
= strlen(hostEntry
.h_name
);
901 if (hostLen
>= nameLength
) return -1;
902 memcpy(name
, hostEntry
.h_name
, hostLen
+1);
908 int enet_socket_bind (ENetSocket socket
, const ENetAddress
* address
) {
909 import core
.stdc
.string
: memset
;
912 memset(&sin
, 0, sockaddr_in
.sizeof
);
913 sin
.sin_family
= AF_INET
;
914 if (address
!is null) {
915 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
916 sin
.sin_addr
.s_addr
= address
.host
;
919 sin
.sin_addr
.s_addr
= INADDR_ANY
;
922 return (bind(socket
, cast(sockaddr
*)&sin
, sockaddr_in
.sizeof
) == SOCKET_ERROR ?
-1 : 0);
925 int enet_socket_get_address (ENetSocket socket
, ENetAddress
* address
) {
927 socklen_t sinLength
= cast(socklen_t
)sockaddr_in
.sizeof
;
929 if (getsockname(socket
, cast(sockaddr
*)&sin
, &sinLength
) == -1) return -1;
931 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
932 address
.port
= ENET_NET_TO_HOST_16(sin
.sin_port
);
937 int enet_socket_listen (ENetSocket socket
, int backlog
) {
938 return (listen(socket
, (backlog
< 0 ?
/*SOMAXCONN*/127 : backlog
)) == SOCKET_ERROR ?
-1 : 0);
941 ENetSocket
enet_socket_create (ENetSocketType type
) {
942 return socket(PF_INET
, (type
== ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM
: SOCK_STREAM
), 0);
945 int enet_socket_set_option (ENetSocket socket
, ENetSocketOption option
, int value
) {
946 int result
= SOCKET_ERROR
;
948 case ENET_SOCKOPT_NONBLOCK
:
949 uint nonBlocking
= cast(uint)value
;
950 result
= ioctlsocket(socket
, FIONBIO
, &nonBlocking
);
952 case ENET_SOCKOPT_BROADCAST
:
953 result
= setsockopt(socket
, SOL_SOCKET
, SO_BROADCAST
, cast(void*)&value
, int.sizeof
);
955 case ENET_SOCKOPT_REUSEADDR
:
956 result
= setsockopt(socket
, SOL_SOCKET
, SO_REUSEADDR
, cast(void*)&value
, int.sizeof
);
958 case ENET_SOCKOPT_RCVBUF
:
959 result
= setsockopt(socket
, SOL_SOCKET
, SO_RCVBUF
, cast(void*)&value
, int.sizeof
);
961 case ENET_SOCKOPT_SNDBUF
:
962 result
= setsockopt(socket
, SOL_SOCKET
, SO_SNDBUF
, cast(void*)&value
, int.sizeof
);
964 case ENET_SOCKOPT_RCVTIMEO
:
965 result
= setsockopt(socket
, SOL_SOCKET
, SO_RCVTIMEO
, cast(void*)&value
, int.sizeof
);
967 case ENET_SOCKOPT_SNDTIMEO
:
968 result
= setsockopt(socket
, SOL_SOCKET
, SO_SNDTIMEO
, cast(void*)&value
, int.sizeof
);
970 case ENET_SOCKOPT_NODELAY
:
971 result
= setsockopt(socket
, IPPROTO_TCP
, TCP_NODELAY
, cast(void*)&value
, int.sizeof
);
976 return (result
== SOCKET_ERROR ?
-1 : 0);
979 int enet_socket_get_option (ENetSocket socket
, ENetSocketOption option
, int* value
) {
980 int result
= SOCKET_ERROR
, len
;
982 case ENET_SOCKOPT_ERROR
:
984 result
= getsockopt(socket
, SOL_SOCKET
, SO_ERROR
, cast(void*)value
, &len
);
989 return (result
== SOCKET_ERROR ?
-1 : 0);
992 int enet_socket_connect (ENetSocket socket
, const ENetAddress
* address
) {
993 import core
.stdc
.string
: memset
;
997 memset(&sin
, 0, sockaddr_in
.sizeof
);
999 sin
.sin_family
= AF_INET
;
1000 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1001 sin
.sin_addr
.s_addr
= address
.host
;
1003 result
= connect(socket
, cast(sockaddr
*)&sin
, sockaddr_in
.sizeof
);
1004 if (result
== SOCKET_ERROR
&& WSAGetLastError() != WSAEWOULDBLOCK
) return -1;
1009 ENetSocket
enet_socket_accept (ENetSocket socket
, ENetAddress
* address
) {
1012 socklen_t sinLength
= cast(socklen_t
)sockaddr_in
.sizeof
;
1014 result
= accept(socket
, (address
!is null ?
cast(sockaddr
*)&sin
: null), (address
!is null ?
&sinLength
: null));
1016 if (result
== INVALID_SOCKET
) return ENET_SOCKET_NULL
;
1018 if (address
!is null) {
1019 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
1020 address
.port
= ENET_NET_TO_HOST_16 (sin
.sin_port
);
1026 int enet_socket_shutdown (ENetSocket socket
, ENetSocketShutdown how
) {
1027 return (shutdown(socket
, cast(int)how
) == SOCKET_ERROR ?
-1 : 0);
1030 void enet_socket_destroy (ENetSocket socket
) {
1031 if (socket
!= INVALID_SOCKET
) closesocket(socket
);
1034 private extern(Windows
) nothrow @nogc int WSASendTo (
1036 const ENetBuffer
* lpBuffers
,
1037 DWORD dwBufferCount
,
1038 LPDWORD lpNumberOfBytesSent
,
1040 const sockaddr
* lpTo
,
1042 /*LPWSAOVERLAPPED*/void* lpOverlapped
=null,
1043 /*LPWSAOVERLAPPED_COMPLETION_ROUTINE*/void* lpCompletionRoutine
=null
1046 private extern(Windows
) nothrow @nogc int WSARecvFrom (
1048 ENetBuffer
* lpBuffers
,
1049 DWORD dwBufferCount
,
1050 LPDWORD lpNumberOfBytesRecvd
,
1053 /*LPINT*/int* lpFromlen
,
1054 /*LPWSAOVERLAPPED*/void* lpOverlapped
=null,
1055 /*LPWSAOVERLAPPED_COMPLETION_ROUTINE*/void* lpCompletionRoutine
=null
1059 int enet_socket_send (ENetSocket socket
, const ENetAddress
* address
, const ENetBuffer
* buffers
, usize bufferCount
) {
1060 import core
.stdc
.string
: memset
;
1064 if (address
!is null) {
1065 memset(&sin
, 0, sockaddr_in
.sizeof
);
1066 sin
.sin_family
= AF_INET
;
1067 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1068 sin
.sin_addr
.s_addr
= address
.host
;
1071 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
) {
1072 if (WSAGetLastError() == WSAEWOULDBLOCK
) return 0;
1076 return cast(int)sentLength
;
1079 int enet_socket_receive (ENetSocket socket
, ENetAddress
* address
, ENetBuffer
* buffers
, usize bufferCount
) {
1080 enum MSG_PARTIAL
= 0x8000;
1081 socklen_t sinLength
= cast(socklen_t
)sockaddr_in
.sizeof
;
1082 DWORD flags
= 0, recvLength
;
1085 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
) {
1086 switch (WSAGetLastError()) {
1087 case WSAEWOULDBLOCK
:
1095 if (flags
&MSG_PARTIAL
) return -1;
1097 if (address
!is null) {
1098 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
1099 address
.port
= ENET_NET_TO_HOST_16(sin
.sin_port
);
1102 return cast(int)recvLength
;
1105 int enet_socketset_select (ENetSocket maxSocket
, ENetSocketSet
* readSet
, ENetSocketSet
* writeSet
, enet_uint32 timeout
) {
1107 timeVal
.tv_sec
= timeout
/1000;
1108 timeVal
.tv_usec
= (timeout
%1000)*1000;
1109 return select(maxSocket
+1, readSet
, writeSet
, null, &timeVal
);
1112 int enet_socket_wait (ENetSocket socket
, enet_uint32
* condition
, enet_uint32 timeout
) {
1113 fd_set readSet
, writeSet
;
1117 timeVal
.tv_sec
= timeout
/ 1000;
1118 timeVal
.tv_usec
= (timeout
% 1000) * 1000;
1123 if ((*condition
)&ENET_SOCKET_WAIT_SEND
) FD_SET(socket
, &writeSet
);
1124 if ((*condition
)&ENET_SOCKET_WAIT_RECEIVE
) FD_SET(socket
, &readSet
);
1126 selectCount
= select(socket
+1, &readSet
, &writeSet
, null, &timeVal
);
1127 if (selectCount
< 0) return -1;
1129 *condition
= ENET_SOCKET_WAIT_NONE
;
1131 if (selectCount
== 0) return 0;
1133 if (FD_ISSET(socket
, &writeSet
)) *condition |
= ENET_SOCKET_WAIT_SEND
;
1134 if (FD_ISSET(socket
, &readSet
)) *condition |
= ENET_SOCKET_WAIT_RECEIVE
;
1138 } else extern(C
) nothrow @nogc {
1140 static import core
.sys
.posix
.sys
.select
; // FD_XXX
1142 auto ENET_SOCKETSET_EMPTY (ref ENetSocketSet sockset
) {
1143 pragma(inline
, true);
1144 core
.sys
.posix
.sys
.select
.FD_ZERO(&sockset
);
1147 auto ENET_SOCKETSET_ADD (ref ENetSocketSet sockset
, ENetSocket socket
) {
1148 pragma(inline
, true);
1149 core
.sys
.posix
.sys
.select
.FD_SET(socket
, &sockset
);
1152 auto ENET_SOCKETSET_REMOVE (ref ENetSocketSet sockset
, ENetSocket socket
) {
1153 pragma(inline
, true);
1154 core
.sys
.posix
.sys
.select
.FD_CLR(socket
, &sockset
);
1157 auto ENET_SOCKETSET_CHECK (ref ENetSocketSet sockset
, ENetSocket socket
) {
1158 pragma(inline
, true);
1159 return !!core
.sys
.posix
.sys
.select
.FD_ISSET(socket
, &sockset
);
1163 int enet_initialize () {
1168 void enet_deinitialize () {
1172 enet_uint32
enet_host_random_seed () {
1173 import core
.stdc
.time
: time
;
1174 return cast(enet_uint32
)time(null);
1178 enet_uint32
enet_time_get () {
1179 import core
.sys
.posix
.sys
.time
: gettimeofday
, timeval
;
1180 timeval timeVal
= void;
1181 gettimeofday(&timeVal
, null);
1182 return cast(uint)(timeVal
.tv_sec
*1000+timeVal
.tv_usec
/1000-timeBase
);
1186 void enet_time_set (enet_uint32 newTimeBase
) {
1187 import core
.sys
.posix
.sys
.time
: gettimeofday
, timeval
;
1188 timeval timeVal
= void;
1189 gettimeofday(&timeVal
, null);
1190 timeBase
= cast(uint)(timeVal
.tv_sec
*1000+timeVal
.tv_usec
/1000-newTimeBase
);
1194 int enet_address_set_host (ENetAddress
* address
, const(char)[] namestr
) {
1195 import core
.stdc
.string
: memset
;
1196 import core
.sys
.posix
.arpa
.inet
: inet_pton
;
1197 import core
.sys
.posix
.netdb
: addrinfo
, getaddrinfo
, freeaddrinfo
;
1198 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1199 import core
.sys
.posix
.sys
.socket
: AF_INET
;
1200 import std
.internal
.cstring
: tempCString
;
1202 addrinfo hints
= void;
1203 addrinfo
* resultList
= null, result
= null;
1205 memset(&hints
, 0, hints
.sizeof
);
1206 hints
.ai_family
= AF_INET
;
1208 auto name
= namestr
.tempCString
;
1210 if (getaddrinfo(name
, null, null, &resultList
) != 0) return -1;
1212 for (result
= resultList
; result
!is null; result
= result
.ai_next
) {
1213 if (result
.ai_family
== AF_INET
&& result
.ai_addr
!is null && result
.ai_addrlen
>= sockaddr_in
.sizeof
) {
1214 sockaddr_in
* sin
= cast(sockaddr_in
*)result
.ai_addr
;
1215 address
.host
= sin
.sin_addr
.s_addr
;
1216 freeaddrinfo(resultList
);
1221 if (resultList
!is null) freeaddrinfo(resultList
);
1223 if (!inet_pton(AF_INET
, name
, &address
.host
)) return -1;
1229 int enet_address_get_host_ip (const ENetAddress
* address
, char* name
, usize nameLength
) {
1230 import core
.sys
.posix
.arpa
.inet
: inet_ntop
;
1231 import core
.sys
.posix
.sys
.socket
: AF_INET
;
1233 if (inet_ntop(AF_INET
, &address
.host
, name
, cast(uint)nameLength
) is null) return -1; // crude x86_64 fix
1238 int enet_address_get_host (const ENetAddress
* address
, char* name
, usize nameLength
) {
1239 import core
.stdc
.string
: memchr
, memset
;
1240 import core
.sys
.posix
.netdb
: EAI_NONAME
, NI_NAMEREQD
, getnameinfo
;
1241 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1242 import core
.sys
.posix
.sys
.socket
: AF_INET
;
1243 import core
.sys
.posix
.sys
.socket
: sockaddr
;
1246 sockaddr_in sin
= void;
1247 memset(&sin
, 0, sockaddr_in
.sizeof
);
1248 sin
.sin_family
= AF_INET
;
1249 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1250 sin
.sin_addr
.s_addr
= address
.host
;
1251 err
= getnameinfo(cast(sockaddr
*)&sin
, sin
.sizeof
, name
, cast(uint)nameLength
, null, 0, NI_NAMEREQD
); // crude x86_64 fix
1253 if (name
!is null && nameLength
> 0 && !memchr(name
, 0, nameLength
)) return -1;
1256 if (err
!= EAI_NONAME
) return 0;
1257 return enet_address_get_host_ip(address
, name
, nameLength
);
1261 int enet_socket_bind (ENetSocket socket
, const ENetAddress
* address
) {
1262 import core
.stdc
.string
: memset
;
1263 import core
.sys
.posix
.netinet
.in_
: INADDR_ANY
, sockaddr_in
;
1264 import core
.sys
.posix
.sys
.socket
: AF_INET
, bind
, sockaddr
;
1266 sockaddr_in sin
= void;
1267 memset(&sin
, 0, sockaddr_in
.sizeof
);
1268 sin
.sin_family
= AF_INET
;
1269 if (address
!is null) {
1270 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1271 sin
.sin_addr
.s_addr
= address
.host
;
1274 sin
.sin_addr
.s_addr
= INADDR_ANY
;
1276 return bind(socket
, cast(sockaddr
*)&sin
, sockaddr_in
.sizeof
);
1280 int enet_socket_get_address (ENetSocket socket
, ENetAddress
* address
) {
1281 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1282 import core
.sys
.posix
.sys
.socket
: getsockname
, sockaddr
, socklen_t
;
1284 sockaddr_in sin
= void;
1285 socklen_t sinLength
= sockaddr_in
.sizeof
;
1286 if (getsockname(socket
, cast(sockaddr
*)&sin
, &sinLength
) == -1) return -1;
1287 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
1288 address
.port
= ENET_NET_TO_HOST_16(sin
.sin_port
);
1293 int enet_socket_listen (ENetSocket socket
, int backlog
) {
1294 import core
.sys
.posix
.sys
.socket
: SOMAXCONN
, listen
;
1295 return listen(socket
, (backlog
< 0 ? SOMAXCONN
: backlog
));
1299 ENetSocket
enet_socket_create (ENetSocketType type
) {
1300 import core
.sys
.posix
.sys
.socket
: AF_INET
, SOCK_DGRAM
, SOCK_STREAM
, socket
;
1301 return socket(AF_INET
, (type
== ENET_SOCKET_TYPE_DATAGRAM ? SOCK_DGRAM
: SOCK_STREAM
), 0);
1305 int enet_socket_set_option (ENetSocket socket
, ENetSocketOption option
, int value
) {
1306 import core
.sys
.posix
.fcntl
: F_GETFL
, F_SETFL
, O_NONBLOCK
, fcntl
;
1307 import core
.sys
.posix
.netinet
.in_
: IPPROTO_TCP
;
1308 import core
.sys
.posix
.netinet
.tcp
: TCP_NODELAY
;
1309 import core
.sys
.posix
.sys
.socket
: SOL_SOCKET
, SO_BROADCAST
, SO_REUSEADDR
, SO_RCVBUF
, SO_SNDBUF
,
1310 SO_RCVTIMEO
, SO_SNDTIMEO
, setsockopt
;
1311 import core
.sys
.posix
.sys
.time
: timeval
;
1313 timeval timeVal
= void;
1316 case ENET_SOCKOPT_NONBLOCK
:
1317 result
= fcntl(socket
, F_SETFL
, (value ? O_NONBLOCK
: 0)|
(fcntl(socket
, F_GETFL
)&~O_NONBLOCK
));
1319 case ENET_SOCKOPT_BROADCAST
:
1320 result
= setsockopt(socket
, SOL_SOCKET
, SO_BROADCAST
, cast(void*)&value
, int.sizeof
);
1322 case ENET_SOCKOPT_REUSEADDR
:
1323 result
= setsockopt(socket
, SOL_SOCKET
, SO_REUSEADDR
, cast(void*)&value
, int.sizeof
);
1325 case ENET_SOCKOPT_RCVBUF
:
1326 result
= setsockopt(socket
, SOL_SOCKET
, SO_RCVBUF
, cast(void*)&value
, int.sizeof
);
1328 case ENET_SOCKOPT_SNDBUF
:
1329 result
= setsockopt(socket
, SOL_SOCKET
, SO_SNDBUF
, cast(void*)&value
, int.sizeof
);
1331 case ENET_SOCKOPT_RCVTIMEO
:
1332 timeVal
.tv_sec
= value
/1000;
1333 timeVal
.tv_usec
= (value
%1000)*1000;
1334 result
= setsockopt(socket
, SOL_SOCKET
, SO_RCVTIMEO
, cast(void*)&timeVal
, timeval
.sizeof
);
1336 case ENET_SOCKOPT_SNDTIMEO
:
1337 timeVal
.tv_sec
= value
/1000;
1338 timeVal
.tv_usec
= (value
%1000)*1000;
1339 result
= setsockopt(socket
, SOL_SOCKET
, SO_SNDTIMEO
, cast(void*)&timeVal
, timeval
.sizeof
);
1341 case ENET_SOCKOPT_NODELAY
:
1342 result
= setsockopt(socket
, IPPROTO_TCP
, TCP_NODELAY
, cast(void*)&value
, int.sizeof
);
1347 return (result
== -1 ?
-1 : 0);
1351 int enet_socket_get_option (ENetSocket socket
, ENetSocketOption option
, int* value
) {
1352 import core
.sys
.posix
.sys
.socket
: SO_ERROR
, SOL_SOCKET
, getsockopt
, socklen_t
;
1356 case ENET_SOCKOPT_ERROR
:
1358 result
= getsockopt(socket
, SOL_SOCKET
, SO_ERROR
, value
, &len
);
1363 return (result
== -1 ?
-1 : 0);
1367 int enet_socket_connect (ENetSocket socket
, const ENetAddress
* address
) {
1368 import core
.stdc
.string
: memset
;
1369 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1370 import core
.sys
.posix
.sys
.socket
: AF_INET
, connect
, sockaddr
;
1373 sockaddr_in sin
= void;
1374 memset(&sin
, 0, sockaddr_in
.sizeof
);
1376 sin
.sin_family
= AF_INET
;
1377 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1378 sin
.sin_addr
.s_addr
= address
.host
;
1380 result
= connect(socket
, cast(sockaddr
*)&sin
, sockaddr_in
.sizeof
);
1382 import core
.stdc
.errno
: errno
, EINPROGRESS
;
1383 if (errno
== EINPROGRESS
) return 0;
1390 ENetSocket
enet_socket_accept (ENetSocket socket
, ENetAddress
* address
) {
1391 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1392 import core
.sys
.posix
.sys
.socket
: AF_INET
, accept
, sockaddr
, socklen_t
;
1395 sockaddr_in sin
= void;
1396 socklen_t sinLength
= sockaddr_in
.sizeof
;
1398 result
= accept(socket
, (address
!is null ?
cast(sockaddr
*)&sin
: null), (address
!is null ?
&sinLength
: null));
1399 if (result
== -1) return ENET_SOCKET_NULL
;
1401 if (address
!is null) {
1402 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
1403 address
.port
= ENET_NET_TO_HOST_16(sin
.sin_port
);
1410 int enet_socket_shutdown (ENetSocket socket
, ENetSocketShutdown how
) {
1411 import core
.sys
.posix
.sys
.socket
: shutdown
;
1412 return shutdown(socket
, cast(int)how
);
1416 void enet_socket_destroy (ENetSocket socket
) {
1417 import core
.sys
.posix
.unistd
: close
;
1418 if (socket
>= 0) close(socket
);
1422 int enet_socket_send (ENetSocket socket
, const ENetAddress
* address
, const(ENetBuffer
)* buffers
, usize bufferCount
) {
1423 import core
.stdc
.string
: memset
;
1424 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1425 import core
.sys
.posix
.sys
.socket
: AF_INET
, MSG_NOSIGNAL
, msghdr
, sendmsg
;
1426 import core
.sys
.posix
.sys
.uio
: iovec
;
1428 msghdr msgHdr
= void;
1429 sockaddr_in sin
= void;
1432 memset(& msgHdr
, 0, msghdr
.sizeof
);
1433 if (address
!is null) {
1434 memset(&sin
, 0, sockaddr_in
.sizeof
);
1436 sin
.sin_family
= AF_INET
;
1437 sin
.sin_port
= ENET_HOST_TO_NET_16(address
.port
);
1438 sin
.sin_addr
.s_addr
= address
.host
;
1440 msgHdr
.msg_name
= &sin
;
1441 msgHdr
.msg_namelen
= sockaddr_in
.sizeof
;
1444 msgHdr
.msg_iov
= cast(iovec
*)buffers
;
1445 msgHdr
.msg_iovlen
= bufferCount
;
1447 sentLength
= cast(uint)sendmsg(socket
, &msgHdr
, MSG_NOSIGNAL
); // crude x86_64 fix
1449 if (sentLength
== -1) {
1450 import core
.stdc
.errno
: errno
, EWOULDBLOCK
;
1451 if (errno
== EWOULDBLOCK
) return 0;
1459 int enet_socket_receive (ENetSocket socket
, ENetAddress
* address
, ENetBuffer
* buffers
, usize bufferCount
) {
1460 import core
.stdc
.string
: memset
;
1461 import core
.sys
.posix
.netinet
.in_
: sockaddr_in
;
1462 import core
.sys
.posix
.sys
.socket
: MSG_NOSIGNAL
, MSG_TRUNC
, msghdr
, recvmsg
;
1463 import core
.sys
.posix
.sys
.uio
: iovec
;
1465 msghdr msgHdr
= void;
1469 memset(&msgHdr
, 0, msghdr
.sizeof
);
1471 if (address
!is null) {
1472 msgHdr
.msg_name
= &sin
;
1473 msgHdr
.msg_namelen
= sockaddr_in
.sizeof
;
1476 msgHdr
.msg_iov
= cast(iovec
*)buffers
;
1477 msgHdr
.msg_iovlen
= bufferCount
;
1479 recvLength
= cast(uint)recvmsg(socket
, &msgHdr
, MSG_NOSIGNAL
); // crude x86_64 fix
1481 if (recvLength
== -1) {
1482 import core
.stdc
.errno
: errno
, EWOULDBLOCK
;
1483 if (errno
== EWOULDBLOCK
) return 0;
1487 if (msgHdr
.msg_flags
&MSG_TRUNC
) return -1;
1489 if (address
!is null) {
1490 address
.host
= cast(enet_uint32
)sin
.sin_addr
.s_addr
;
1491 address
.port
= ENET_NET_TO_HOST_16(sin
.sin_port
);
1498 int enet_socketset_select (ENetSocket maxSocket
, ENetSocketSet
* readSet
, ENetSocketSet
* writeSet
, enet_uint32 timeout
) {
1499 import core
.sys
.posix
.sys
.time
: timeval
;
1500 import core
.sys
.posix
.sys
.select
: select
;
1502 timeval timeVal
= void;
1503 timeVal
.tv_sec
= timeout
/1000;
1504 timeVal
.tv_usec
= (timeout
%1000)*1000;
1505 return select(maxSocket
+1, readSet
, writeSet
, null, &timeVal
);
1509 int enet_socket_wait (ENetSocket socket
, enet_uint32
* condition
, enet_uint32 timeout
) {
1510 import core
.sys
.posix
.poll
: POLLIN
, POLLOUT
, poll
, pollfd
;
1512 pollfd pollSocket
= void;
1515 pollSocket
.fd
= socket
;
1516 pollSocket
.events
= 0;
1518 if ((*condition
)&ENET_SOCKET_WAIT_SEND
) pollSocket
.events |
= POLLOUT
;
1519 if ((*condition
)&ENET_SOCKET_WAIT_RECEIVE
) pollSocket
.events |
= POLLIN
;
1521 pollCount
= poll(&pollSocket
, 1, timeout
);
1523 if (pollCount
< 0) {
1524 import core
.stdc
.errno
: errno
, EINTR
;
1525 if (errno
== EINTR
&& (*condition
)&ENET_SOCKET_WAIT_INTERRUPT
) {
1526 *condition
= ENET_SOCKET_WAIT_INTERRUPT
;
1532 *condition
= ENET_SOCKET_WAIT_NONE
;
1534 if (pollCount
== 0) return 0;
1536 if (pollSocket
.revents
&POLLOUT
) *condition |
= ENET_SOCKET_WAIT_SEND
;
1537 if (pollSocket
.revents
&POLLIN
) *condition |
= ENET_SOCKET_WAIT_RECEIVE
;
1546 private __gshared ENetCallbacks callbacks
;
1549 shared static this () @nogc {
1550 static import core
.stdc
.stdlib
;
1551 callbacks
.malloc
= &core
.stdc
.stdlib
.malloc
;
1552 callbacks
.free
= &core
.stdc
.stdlib
.free
;
1553 callbacks
.no_memory
= &core
.stdc
.stdlib
.abort
; //FIXME
1557 int enet_initialize_with_callbacks (ENetVersion version_
, const ENetCallbacks
* inits
) nothrow @nogc {
1558 if (version_
< ENET_VERSION_CREATE(1, 3, 0)) return -1;
1559 if (inits
.malloc
!is null || inits
.free
!is null) {
1560 if (inits
.malloc
is null || inits
.free
is null) return -1;
1561 callbacks
.malloc
= inits
.malloc
;
1562 callbacks
.free
= inits
.free
;
1564 if (inits
.no_memory
!is null) callbacks
.no_memory
= inits
.no_memory
;
1565 return enet_initialize();
1569 ENetVersion
enet_linked_version () nothrow @nogc {
1570 return ENET_VERSION
;
1574 void* enet_malloc (usize size
) nothrow {
1575 void* memory
= callbacks
.malloc(size
);
1576 if (memory
is null) callbacks
.no_memory();
1581 void enet_free (void* memory
) nothrow {
1582 callbacks
.free(memory
);
1588 extern(C
) @nogc nothrow {
1589 alias ENetListIterator
= ENetListNode
*;
1593 ENetListIterator
enet_list_begin (ENetList
* list
) {
1594 pragma(inline
, true);
1595 return list
.sentinel
.next
;
1598 ENetListIterator
enet_list_end (ENetList
* list
) {
1599 pragma(inline
, true);
1600 return &list
.sentinel
;
1603 bool enet_list_empty (ENetList
* list
) {
1604 pragma(inline
, true);
1605 return enet_list_begin(list
) == enet_list_end(list
);
1608 ENetListIterator
enet_list_next (ENetListIterator iterator
) {
1609 pragma(inline
, true);
1610 return iterator
.next
;
1613 ENetListIterator
enet_list_previous (ENetListIterator iterator
) {
1614 pragma(inline
, true);
1615 return iterator
.previous
;
1618 void* enet_list_front (ENetList
* list
) {
1619 pragma(inline
, true);
1620 return cast(void*)(list
.sentinel
.next
);
1623 void* enet_list_back (ENetList
* list
) {
1624 pragma(inline
, true);
1625 return cast(void*)(list
.sentinel
.previous
);
1630 @defgroup list ENet linked list utility functions
1634 void enet_list_clear (ENetList
* list
) {
1635 list
.sentinel
.next
= &list
.sentinel
;
1636 list
.sentinel
.previous
= &list
.sentinel
;
1639 ENetListIterator
enet_list_insert (ENetListIterator position
, void* data
) {
1640 ENetListIterator result
= cast(ENetListIterator
)data
;
1642 result
.previous
= position
.previous
;
1643 result
.next
= position
;
1645 result
.previous
.next
= result
;
1646 position
.previous
= result
;
1651 void* enet_list_remove (ENetListIterator position
) {
1652 position
.previous
.next
= position
.next
;
1653 position
.next
.previous
= position
.previous
;
1657 ENetListIterator
enet_list_move (ENetListIterator position
, void * dataFirst
, void * dataLast
) {
1658 ENetListIterator first
= cast(ENetListIterator
)dataFirst
;
1659 ENetListIterator last
= cast(ENetListIterator
)dataLast
;
1661 first
.previous
.next
= last
.next
;
1662 last
.next
.previous
= first
.previous
;
1664 first
.previous
= position
.previous
;
1665 last
.next
= position
;
1667 first
.previous
.next
= first
;
1668 position
.previous
= last
;
1673 usize
enet_list_size (ENetList
* list
) {
1675 ENetListIterator position
;
1676 for (position
= enet_list_begin(list
); position
!= enet_list_end(list
); position
= enet_list_next(position
)) ++size
;
1684 /** Creates a packet that may be sent to a peer.
1687 * data = initial contents of the packet's data; the packet's data will remain uninitialized if data is null
1688 * dataLength = size of the data allocated for this packet
1689 * flags = flags for this packet as described for the ENetPacket structure
1692 * the packet on success, null on failure
1694 ENetPacket
* enet_packet_create (const(void)* data
, usize dataLength
, enet_uint32 flags
) {
1695 ENetPacket
* packet
= cast(ENetPacket
*)enet_malloc(ENetPacket
.sizeof
);
1696 if (packet
is null) return null;
1698 if (flags
&ENET_PACKET_FLAG_NO_ALLOCATE
) {
1699 packet
.data
= cast(enet_uint8
*)data
;
1700 } else if (dataLength
<= 0) {
1703 packet
.data
= cast(enet_uint8
*)enet_malloc(dataLength
);
1704 if (packet
.data
is null) {
1708 if (data
!is null) {
1709 import core
.stdc
.string
: memcpy
;
1710 memcpy(packet
.data
, data
, dataLength
);
1715 packet
.referenceCount
= 0;
1716 packet
.flags
= flags
;
1717 packet
.dataLength
= dataLength
;
1718 packet
.freeCallback
= null;
1719 packet
.userData
= null;
1725 /** Destroys the packet and deallocates its data.
1728 * packet = packet to be destroyed
1730 void enet_packet_destroy (ENetPacket
* packet
) {
1731 if (packet
is null) return;
1732 if (packet
.freeCallback
!is null) (*packet
.freeCallback
)(packet
);
1733 if (!(packet
.flags
&ENET_PACKET_FLAG_NO_ALLOCATE
) && packet
.data
!is null) enet_free(packet
.data
);
1738 /** Attempts to resize the data in the packet to length specified in the dataLength parameter.
1741 * packet = packet to resize
1742 * dataLength = new size for the packet data
1745 * 0 on success, < 0 on failure
1747 int enet_packet_resize (ENetPacket
* packet
, usize dataLength
) {
1748 import core
.stdc
.string
: memcpy
;
1750 enet_uint8
* newData
;
1752 if (dataLength
<= packet
.dataLength ||
(packet
.flags
&ENET_PACKET_FLAG_NO_ALLOCATE
)) {
1753 packet
.dataLength
= dataLength
;
1757 newData
= cast(enet_uint8
*) enet_malloc(dataLength
);
1758 if (newData
is null) return -1;
1760 memcpy(newData
, packet
.data
, packet
.dataLength
);
1761 enet_free(packet
.data
);
1763 packet
.data
= newData
;
1764 packet
.dataLength
= dataLength
;
1770 private immutable enet_uint32
[256] crcTable
= (() {
1771 enet_uint32
reflect_crc (int val
, int bits
) {
1772 int result
= 0, bit
;
1773 for (bit
= 0; bit
< bits
; ++bit
) {
1774 if (val
&1) result |
= 1<<(bits
-1-bit
);
1780 enet_uint32
[256] crcTable
;
1781 for (int bt = 0; bt < 256; ++bt) {
1782 enet_uint32 crc
= reflect_crc(bt, 8)<<24;
1783 for (int offset
= 0; offset
< 8; ++offset
) {
1784 if (crc
&0x80000000u
) crc
= (crc
<<1)^
0x04c11db7u
; else crc
<<= 1;
1786 crcTable
[bt] = reflect_crc (crc
, 32);
1792 enet_uint32
enet_crc32 (const(ENetBuffer
)* buffers
, usize bufferCount
) pure @nogc {
1793 enet_uint32 crc
= 0xFFFFFFFF;
1794 while (bufferCount
-- > 0) {
1795 auto data
= cast(const(enet_uint8
)*)buffers
.data
;
1796 auto dataEnd
= data
+buffers
.dataLength
;
1797 while (data
< dataEnd
) crc
= (crc
>>8)^crcTable
[(crc
&0xFF)^
*data
++];
1800 return ENET_HOST_TO_NET_32(~crc
);
1807 /** Configures throttle parameter for a peer.
1809 * Unreliable packets are dropped by ENet in response to the varying conditions
1810 * of the Internet connection to the peer. The throttle represents a probability
1811 * that an unreliable packet should not be dropped and thus sent by ENet to the peer.
1812 * The lowest mean round trip time from the sending of a reliable packet to the
1813 * receipt of its acknowledgement is measured over an amount of time specified by
1814 * the interval parameter in milliseconds. If a measured round trip time happens to
1815 * be significantly less than the mean round trip time measured over the interval,
1816 * then the throttle probability is increased to allow more traffic by an amount
1817 * specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE
1818 * constant. If a measured round trip time happens to be significantly greater than
1819 * the mean round trip time measured over the interval, then the throttle probability
1820 * is decreased to limit traffic by an amount specified in the deceleration parameter, which
1821 * is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant. When the throttle has
1822 * a value of ENET_PEER_PACKET_THROTTLE_SCALE, no unreliable packets are dropped by
1823 * ENet, and so 100% of all unreliable packets will be sent. When the throttle has a
1824 * value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable
1825 * packets will be sent. Intermediate values for the throttle represent intermediate
1826 * probabilities between 0% and 100% of unreliable packets being sent. The bandwidth
1827 * limits of the local and foreign hosts are taken into account to determine a
1828 * sensible limit for the throttle probability above which it should not raise even in
1829 * the best of conditions.
1832 * peer = peer to configure
1833 * interval = interval, in milliseconds, over which to measure lowest mean RTT; the default value is ENET_PEER_PACKET_THROTTLE_INTERVAL.
1834 * acceleration = rate at which to increase the throttle probability as mean RTT declines
1835 * deceleration = rate at which to decrease the throttle probability as mean RTT increases
1837 void enet_peer_throttle_configure (ENetPeer
* peer
, enet_uint32 interval
, enet_uint32 acceleration
, enet_uint32 deceleration
) {
1838 ENetProtocol command
;
1840 peer
.packetThrottleInterval
= interval
;
1841 peer
.packetThrottleAcceleration
= acceleration
;
1842 peer
.packetThrottleDeceleration
= deceleration
;
1844 command
.header
.command
= ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
1845 command
.header
.channelID
= 0xFF;
1847 command
.throttleConfigure
.packetThrottleInterval
= ENET_HOST_TO_NET_32 (interval
);
1848 command
.throttleConfigure
.packetThrottleAcceleration
= ENET_HOST_TO_NET_32 (acceleration
);
1849 command
.throttleConfigure
.packetThrottleDeceleration
= ENET_HOST_TO_NET_32 (deceleration
);
1851 enet_peer_queue_outgoing_command(peer
, &command
, null, 0, 0);
1855 int enet_peer_throttle (ENetPeer
* peer
, enet_uint32 rtt
) @nogc {
1856 if (peer
.lastRoundTripTime
<= peer
.lastRoundTripTimeVariance
) {
1857 peer
.packetThrottle
= peer
.packetThrottleLimit
;
1858 } else if (rtt
< peer
.lastRoundTripTime
) {
1859 peer
.packetThrottle
+= peer
.packetThrottleAcceleration
;
1860 if (peer
.packetThrottle
> peer
.packetThrottleLimit
) peer
.packetThrottle
= peer
.packetThrottleLimit
;
1862 } else if (rtt
> peer
.lastRoundTripTime
+2*peer
.lastRoundTripTimeVariance
) {
1863 if (peer
.packetThrottle
> peer
.packetThrottleDeceleration
) {
1864 peer
.packetThrottle
-= peer
.packetThrottleDeceleration
;
1866 peer
.packetThrottle
= 0;
1874 /** Queues a packet to be sent.
1877 * peer = destination for the packet
1878 * channelID = channel on which to send
1879 * packet = packet to send
1882 * 0 on success, < 0 on failure
1884 int enet_peer_send (ENetPeer
* peer
, enet_uint8 channelID
, ENetPacket
* packet
) {
1885 ENetChannel
* channel
= &peer
.channels
[channelID
];
1886 ENetProtocol command
;
1887 usize fragmentLength
;
1889 if (peer
.state
!= ENET_PEER_STATE_CONNECTED || channelID
>= peer
.channelCount || packet
.dataLength
> peer
.host
.maximumPacketSize
) return -1;
1891 fragmentLength
= peer
.mtu
-ENetProtocolHeader
.sizeof
-ENetProtocolSendFragment
.sizeof
;
1892 if (peer
.host
.checksum
!is null) fragmentLength
-= enet_uint32
.sizeof
;
1894 if (packet
.dataLength
> fragmentLength
) {
1895 enet_uint32 fragmentCount
= cast(uint)((packet
.dataLength
+fragmentLength
-1)/fragmentLength
);
1896 enet_uint32 fragmentNumber
, fragmentOffset
;
1897 enet_uint8 commandNumber
;
1898 enet_uint16 startSequenceNumber
;
1900 ENetOutgoingCommand
* fragment
;
1902 if (fragmentCount
> ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT
) return -1;
1904 if ((packet
.flags
&(ENET_PACKET_FLAG_RELIABLE|ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT
)) == ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT
&& channel
.outgoingUnreliableSequenceNumber
< 0xFFFF) {
1905 commandNumber
= ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT
;
1906 startSequenceNumber
= ENET_HOST_TO_NET_16(cast(ushort)(channel
.outgoingUnreliableSequenceNumber
+1));
1908 commandNumber
= ENET_PROTOCOL_COMMAND_SEND_FRAGMENT|ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
1909 startSequenceNumber
= ENET_HOST_TO_NET_16(cast(ushort)(channel
.outgoingReliableSequenceNumber
+1));
1912 enet_list_clear(&fragments
);
1914 for (fragmentNumber
= 0, fragmentOffset
= 0; fragmentOffset
< packet
.dataLength
; ++fragmentNumber
, fragmentOffset
+= fragmentLength
) {
1915 if (packet
.dataLength
-fragmentOffset
< fragmentLength
) fragmentLength
= packet
.dataLength
-fragmentOffset
;
1917 fragment
= cast(ENetOutgoingCommand
*)enet_malloc(ENetOutgoingCommand
.sizeof
);
1918 if (fragment
is null) {
1919 while (!enet_list_empty(&fragments
)) {
1920 fragment
= cast(ENetOutgoingCommand
*)enet_list_remove(enet_list_begin(&fragments
));
1921 enet_free(fragment
);
1926 fragment
.fragmentOffset
= fragmentOffset
;
1927 fragment
.fragmentLength
= cast(ushort)fragmentLength
;
1928 fragment
.packet
= packet
;
1929 fragment
.command
.header
.command
= commandNumber
;
1930 fragment
.command
.header
.channelID
= channelID
;
1931 fragment
.command
.sendFragment
.startSequenceNumber
= startSequenceNumber
;
1932 fragment
.command
.sendFragment
.dataLength
= ENET_HOST_TO_NET_16(cast(ushort)fragmentLength
);
1933 fragment
.command
.sendFragment
.fragmentCount
= ENET_HOST_TO_NET_32(fragmentCount
);
1934 fragment
.command
.sendFragment
.fragmentNumber
= ENET_HOST_TO_NET_32(fragmentNumber
);
1935 fragment
.command
.sendFragment
.totalLength
= ENET_HOST_TO_NET_32(cast(uint)packet
.dataLength
);
1936 fragment
.command
.sendFragment
.fragmentOffset
= ENET_NET_TO_HOST_32(fragmentOffset
);
1938 enet_list_insert(enet_list_end(&fragments
), fragment
);
1941 packet
.referenceCount
+= fragmentNumber
;
1943 while (!enet_list_empty(&fragments
)) {
1944 fragment
= cast(ENetOutgoingCommand
*)enet_list_remove(enet_list_begin(&fragments
));
1945 enet_peer_setup_outgoing_command(peer
, fragment
);
1951 command
.header
.channelID
= channelID
;
1953 if ((packet
.flags
&(ENET_PACKET_FLAG_RELIABLE|ENET_PACKET_FLAG_UNSEQUENCED
)) == ENET_PACKET_FLAG_UNSEQUENCED
) {
1954 command
.header
.command
= ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED|ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED
;
1955 command
.sendUnsequenced
.dataLength
= ENET_HOST_TO_NET_16(cast(ushort)packet
.dataLength
);
1956 } else if (packet
.flags
&ENET_PACKET_FLAG_RELIABLE || channel
.outgoingUnreliableSequenceNumber
>= 0xFFFF) {
1957 command
.header
.command
= ENET_PROTOCOL_COMMAND_SEND_RELIABLE|ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
1958 command
.sendReliable
.dataLength
= ENET_HOST_TO_NET_16(cast(ushort)packet
.dataLength
);
1960 command
.header
.command
= ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE
;
1961 command
.sendUnreliable
.dataLength
= ENET_HOST_TO_NET_16(cast(ushort)packet
.dataLength
);
1964 if (enet_peer_queue_outgoing_command(peer
, &command
, packet
, 0, cast(ushort)packet
.dataLength
) is null) return -1;
1970 /** Attempts to dequeue any incoming queued packet.
1973 * peer = peer to dequeue packets from
1974 * channelID = holds the channel ID of the channel the packet was received on success
1977 * returns a pointer to the packet, or null if there are no available incoming queued packets
1979 ENetPacket
* enet_peer_receive (ENetPeer
* peer
, enet_uint8
* channelID
) {
1980 ENetIncomingCommand
* incomingCommand
;
1983 if (enet_list_empty(&peer
.dispatchedCommands
)) return null;
1984 incomingCommand
= cast(ENetIncomingCommand
*)enet_list_remove(enet_list_begin(&peer
.dispatchedCommands
));
1985 if (channelID
!is null) *channelID
= incomingCommand
.command
.header
.channelID
;
1986 packet
= incomingCommand
.packet
;
1987 --packet
.referenceCount
;
1988 if (incomingCommand
.fragments
!is null) enet_free(incomingCommand
.fragments
);
1989 enet_free(incomingCommand
);
1990 peer
.totalWaitingData
-= packet
.dataLength
;
1996 private void enet_peer_reset_outgoing_commands (ENetList
* queue
) {
1997 ENetOutgoingCommand
* outgoingCommand
;
1998 while (!enet_list_empty(queue
)) {
1999 outgoingCommand
= cast(ENetOutgoingCommand
*)enet_list_remove(enet_list_begin(queue
));
2000 if (outgoingCommand
.packet
!is null) {
2001 --outgoingCommand
.packet
.referenceCount
;
2002 if (outgoingCommand
.packet
.referenceCount
== 0) enet_packet_destroy(outgoingCommand
.packet
);
2004 enet_free(outgoingCommand
);
2009 private void enet_peer_remove_incoming_commands (ENetList
* queue
, ENetListIterator startCommand
, ENetListIterator endCommand
) {
2010 ENetListIterator currentCommand
;
2011 for (currentCommand
= startCommand
; currentCommand
!= endCommand
; ) {
2012 ENetIncomingCommand
* incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
2013 currentCommand
= enet_list_next(currentCommand
);
2014 enet_list_remove(&incomingCommand
.incomingCommandList
);
2015 if (incomingCommand
.packet
!is null) {
2016 --incomingCommand
.packet
.referenceCount
;
2017 if (incomingCommand
.packet
.referenceCount
== 0) enet_packet_destroy(incomingCommand
.packet
);
2019 if (incomingCommand
.fragments
!is null) enet_free(incomingCommand
.fragments
);
2020 enet_free(incomingCommand
);
2025 private void enet_peer_reset_incoming_commands (ENetList
* queue
) {
2026 enet_peer_remove_incoming_commands(queue
, enet_list_begin(queue
), enet_list_end(queue
));
2030 void enet_peer_reset_queues (ENetPeer
* peer
) {
2031 ENetChannel
* channel
;
2033 if (peer
.needsDispatch
) {
2034 enet_list_remove(&peer
.dispatchList
);
2035 peer
.needsDispatch
= false;
2038 while (!enet_list_empty(&peer
.acknowledgements
)) enet_free(enet_list_remove(enet_list_begin(&peer
.acknowledgements
)));
2040 enet_peer_reset_outgoing_commands(&peer
.sentReliableCommands
);
2041 enet_peer_reset_outgoing_commands(&peer
.sentUnreliableCommands
);
2042 enet_peer_reset_outgoing_commands(&peer
.outgoingReliableCommands
);
2043 enet_peer_reset_outgoing_commands(&peer
.outgoingUnreliableCommands
);
2044 enet_peer_reset_incoming_commands(&peer
.dispatchedCommands
);
2046 if (peer
.channels
!is null && peer
.channelCount
> 0) {
2047 for (channel
= peer
.channels
; channel
< &peer
.channels
[peer
.channelCount
]; ++channel
) {
2048 enet_peer_reset_incoming_commands(&channel
.incomingReliableCommands
);
2049 enet_peer_reset_incoming_commands(&channel
.incomingUnreliableCommands
);
2051 enet_free(peer
.channels
);
2054 peer
.channels
= null;
2055 peer
.channelCount
= 0;
2059 void enet_peer_on_connect (ENetPeer
* peer
) @nogc {
2060 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) {
2061 if (peer
.incomingBandwidth
!= 0) ++peer
.host
.bandwidthLimitedPeers
;
2062 ++peer
.host
.connectedPeers
;
2067 void enet_peer_on_disconnect (ENetPeer
* peer
) @nogc {
2068 if (peer
.state
== ENET_PEER_STATE_CONNECTED || peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
) {
2069 if (peer
.incomingBandwidth
!= 0) --peer
.host
.bandwidthLimitedPeers
;
2070 --peer
.host
.connectedPeers
;
2075 /** Forcefully disconnects a peer.
2078 * peer = peer to forcefully disconnect
2081 * The foreign host represented by the peer is not notified of the disconnection and will timeout
2082 * on its connection to the local host.
2084 void enet_peer_reset (ENetPeer
* peer
) {
2085 import core
.stdc
.string
: memset
;
2087 enet_peer_on_disconnect(peer
);
2089 peer
.outgoingPeerID
= ENET_PROTOCOL_MAXIMUM_PEER_ID
;
2092 peer
.state
= ENET_PEER_STATE_DISCONNECTED
;
2094 peer
.incomingBandwidth
= 0;
2095 peer
.outgoingBandwidth
= 0;
2096 peer
.incomingBandwidthThrottleEpoch
= 0;
2097 peer
.outgoingBandwidthThrottleEpoch
= 0;
2098 peer
.incomingDataTotal
= 0;
2099 peer
.outgoingDataTotal
= 0;
2100 peer
.lastSendTime
= 0;
2101 peer
.lastReceiveTime
= 0;
2102 peer
.nextTimeout
= 0;
2103 peer
.earliestTimeout
= 0;
2104 peer
.packetLossEpoch
= 0;
2105 peer
.packetsSent
= 0;
2106 peer
.packetsLost
= 0;
2107 peer
.packetLoss
= 0;
2108 peer
.packetLossVariance
= 0;
2109 peer
.packetThrottle
= ENET_PEER_DEFAULT_PACKET_THROTTLE
;
2110 peer
.packetThrottleLimit
= ENET_PEER_PACKET_THROTTLE_SCALE
;
2111 peer
.packetThrottleCounter
= 0;
2112 peer
.packetThrottleEpoch
= 0;
2113 peer
.packetThrottleAcceleration
= ENET_PEER_PACKET_THROTTLE_ACCELERATION
;
2114 peer
.packetThrottleDeceleration
= ENET_PEER_PACKET_THROTTLE_DECELERATION
;
2115 peer
.packetThrottleInterval
= ENET_PEER_PACKET_THROTTLE_INTERVAL
;
2116 peer
.pingInterval
= ENET_PEER_PING_INTERVAL
;
2117 peer
.timeoutLimit
= ENET_PEER_TIMEOUT_LIMIT
;
2118 peer
.timeoutMinimum
= ENET_PEER_TIMEOUT_MINIMUM
;
2119 peer
.timeoutMaximum
= ENET_PEER_TIMEOUT_MAXIMUM
;
2120 peer
.lastRoundTripTime
= ENET_PEER_DEFAULT_ROUND_TRIP_TIME
;
2121 peer
.lowestRoundTripTime
= ENET_PEER_DEFAULT_ROUND_TRIP_TIME
;
2122 peer
.lastRoundTripTimeVariance
= 0;
2123 peer
.highestRoundTripTimeVariance
= 0;
2124 peer
.roundTripTime
= ENET_PEER_DEFAULT_ROUND_TRIP_TIME
;
2125 peer
.roundTripTimeVariance
= 0;
2126 peer
.mtu
= peer
.host
.mtu
;
2127 peer
.reliableDataInTransit
= 0;
2128 peer
.outgoingReliableSequenceNumber
= 0;
2129 peer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
2130 peer
.incomingUnsequencedGroup
= 0;
2131 peer
.outgoingUnsequencedGroup
= 0;
2133 peer
.totalWaitingData
= 0;
2135 memset(peer
.unsequencedWindow
.ptr
, 0, peer
.unsequencedWindow
.sizeof
);
2137 enet_peer_reset_queues(peer
);
2141 /** Sends a ping request to a peer.
2144 * peer = destination for the ping request
2147 * ping requests factor into the mean round trip time as designated by the
2148 * roundTripTime field in the ENetPeer structure. ENet automatically pings all connected
2149 * peers at regular intervals, however, this function may be called to ensure more
2150 * frequent ping requests.
2152 void enet_peer_ping (ENetPeer
* peer
) {
2153 ENetProtocol command
;
2155 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
) return;
2157 command
.header
.command
= ENET_PROTOCOL_COMMAND_PING|ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
2158 command
.header
.channelID
= 0xFF;
2160 enet_peer_queue_outgoing_command(peer
, &command
, null, 0, 0);
2164 /** Sets the interval at which pings will be sent to a peer.
2166 * Pings are used both to monitor the liveness of the connection and also to dynamically
2167 * adjust the throttle during periods of low traffic so that the throttle has reasonable
2168 * responsiveness during traffic spikes.
2171 * peer = the peer to adjust
2172 * pingInterval = the interval at which to send pings; defaults to ENET_PEER_PING_INTERVAL if 0
2174 void enet_peer_ping_interval (ENetPeer
* peer
, enet_uint32 pingInterval
) @nogc {
2175 peer
.pingInterval
= (pingInterval ? pingInterval
: ENET_PEER_PING_INTERVAL
);
2179 /** Sets the timeout parameters for a peer.
2181 * The timeout parameter control how and when a peer will timeout from a failure to acknowledge
2182 * reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable
2183 * packet is not acknowledge within some multiple of the average RTT plus a variance tolerance,
2184 * the timeout will be doubled until it reaches a set limit. If the timeout is thus at this
2185 * limit and reliable packets have been sent but not acknowledged within a certain minimum time
2186 * period, the peer will be disconnected. Alternatively, if reliable packets have been sent
2187 * but not acknowledged for a certain maximum time period, the peer will be disconnected regardless
2188 * of the current timeout limit value.
2191 * peer = the peer to adjust
2192 * timeoutLimit = the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0
2193 * timeoutMinimum = the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0
2194 * timeoutMaximum = the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0
2196 void enet_peer_timeout (ENetPeer
* peer
, enet_uint32 timeoutLimit
, enet_uint32 timeoutMinimum
, enet_uint32 timeoutMaximum
) @nogc {
2197 peer
.timeoutLimit
= (timeoutLimit ? timeoutLimit
: ENET_PEER_TIMEOUT_LIMIT
);
2198 peer
.timeoutMinimum
= (timeoutMinimum ? timeoutMinimum
: ENET_PEER_TIMEOUT_MINIMUM
);
2199 peer
.timeoutMaximum
= (timeoutMaximum ? timeoutMaximum
: ENET_PEER_TIMEOUT_MAXIMUM
);
2203 /** Force an immediate disconnection from a peer.
2206 * peer = peer to disconnect
2207 * data = data describing the disconnection
2210 * No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not
2211 * guaranteed to receive the disconnect notification, and is reset immediately upon
2212 * return from this function.
2214 void enet_peer_disconnect_now (ENetPeer
* peer
, enet_uint32 data
) {
2215 ENetProtocol command
;
2217 if (peer
.state
== ENET_PEER_STATE_DISCONNECTED
) return;
2219 if (peer
.state
!= ENET_PEER_STATE_ZOMBIE
&& peer
.state
!= ENET_PEER_STATE_DISCONNECTING
) {
2220 enet_peer_reset_queues(peer
);
2222 command
.header
.command
= ENET_PROTOCOL_COMMAND_DISCONNECT|ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED
;
2223 command
.header
.channelID
= 0xFF;
2224 command
.disconnect
.data
= ENET_HOST_TO_NET_32(data
);
2226 enet_peer_queue_outgoing_command(peer
, &command
, null, 0, 0);
2228 enet_host_flush(peer
.host
);
2231 enet_peer_reset(peer
);
2235 /** Request a disconnection from a peer.
2238 * peer = peer to request a disconnection
2239 * data = data describing the disconnection
2242 * An ENET_EVENT_DISCONNECT event will be generated by enet_host_service()
2243 * once the disconnection is complete.
2245 void enet_peer_disconnect (ENetPeer
* peer
, enet_uint32 data
) {
2246 ENetProtocol command
;
2248 if (peer
.state
== ENET_PEER_STATE_DISCONNECTING ||
2249 peer
.state
== ENET_PEER_STATE_DISCONNECTED ||
2250 peer
.state
== ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT ||
2251 peer
.state
== ENET_PEER_STATE_ZOMBIE
)
2254 enet_peer_reset_queues(peer
);
2256 command
.header
.command
= ENET_PROTOCOL_COMMAND_DISCONNECT
;
2257 command
.header
.channelID
= 0xFF;
2258 command
.disconnect
.data
= ENET_HOST_TO_NET_32(data
);
2260 if (peer
.state
== ENET_PEER_STATE_CONNECTED || peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
) {
2261 command
.header
.command |
= ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
2263 command
.header
.command |
= ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED
;
2266 enet_peer_queue_outgoing_command(peer
, &command
, null, 0, 0);
2268 if (peer
.state
== ENET_PEER_STATE_CONNECTED || peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
) {
2269 enet_peer_on_disconnect(peer
);
2270 peer
.state
= ENET_PEER_STATE_DISCONNECTING
;
2272 enet_host_flush(peer
.host
);
2273 enet_peer_reset(peer
);
2278 /** Request a disconnection from a peer, but only after all queued outgoing packets are sent.
2281 * peer = peer to request a disconnection
2282 * data = data describing the disconnection
2285 * An ENET_EVENT_DISCONNECT event will be generated by enet_host_service()
2286 * once the disconnection is complete.
2288 void enet_peer_disconnect_later (ENetPeer
* peer
, enet_uint32 data
) {
2289 if ((peer
.state
== ENET_PEER_STATE_CONNECTED || peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
) &&
2290 !(enet_list_empty (& peer
.outgoingReliableCommands
) &&
2291 enet_list_empty (& peer
.outgoingUnreliableCommands
) &&
2292 enet_list_empty (& peer
.sentReliableCommands
)))
2294 peer
.state
= ENET_PEER_STATE_DISCONNECT_LATER
;
2295 peer
.eventData
= data
;
2297 enet_peer_disconnect(peer
, data
);
2302 ENetAcknowledgement
* enet_peer_queue_acknowledgement (ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint16 sentTime
) {
2303 ENetAcknowledgement
* acknowledgement
;
2305 if (command
.header
.channelID
< peer
.channelCount
) {
2306 ENetChannel
* channel
= &peer
.channels
[command
.header
.channelID
];
2307 enet_uint16 reliableWindow
= command
.header
.reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
2308 enet_uint16 currentWindow
= channel
.incomingReliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
2310 if (command
.header
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) reliableWindow
+= ENET_PEER_RELIABLE_WINDOWS
;
2311 if (reliableWindow
>= currentWindow
+ ENET_PEER_FREE_RELIABLE_WINDOWS
-1 && reliableWindow
<= currentWindow
+ENET_PEER_FREE_RELIABLE_WINDOWS
) return null;
2314 acknowledgement
= cast(ENetAcknowledgement
*)enet_malloc(ENetAcknowledgement
.sizeof
);
2315 if (acknowledgement
is null) return null;
2317 peer
.outgoingDataTotal
+= ENetProtocolAcknowledge
.sizeof
;
2319 acknowledgement
.sentTime
= sentTime
;
2320 acknowledgement
.command
= * command
;
2322 enet_list_insert(enet_list_end(&peer
.acknowledgements
), acknowledgement
);
2324 return acknowledgement
;
2328 void enet_peer_setup_outgoing_command (ENetPeer
* peer
, ENetOutgoingCommand
* outgoingCommand
) @nogc {
2329 ENetChannel
* channel
= &peer
.channels
[outgoingCommand
.command
.header
.channelID
];
2331 peer
.outgoingDataTotal
+= enet_protocol_command_size(outgoingCommand
.command
.header
.command
)+outgoingCommand
.fragmentLength
;
2333 if (outgoingCommand
.command
.header
.channelID
== 0xFF) {
2334 ++peer
.outgoingReliableSequenceNumber
;
2335 outgoingCommand
.reliableSequenceNumber
= peer
.outgoingReliableSequenceNumber
;
2336 outgoingCommand
.unreliableSequenceNumber
= 0;
2337 } else if (outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
) {
2338 ++channel
.outgoingReliableSequenceNumber
;
2339 channel
.outgoingUnreliableSequenceNumber
= 0;
2341 outgoingCommand
.reliableSequenceNumber
= channel
.outgoingReliableSequenceNumber
;
2342 outgoingCommand
.unreliableSequenceNumber
= 0;
2343 } else if (outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED
) {
2344 ++peer
.outgoingUnsequencedGroup
;
2345 outgoingCommand
.reliableSequenceNumber
= 0;
2346 outgoingCommand
.unreliableSequenceNumber
= 0;
2348 if (outgoingCommand
.fragmentOffset
== 0) ++channel
.outgoingUnreliableSequenceNumber
;
2349 outgoingCommand
.reliableSequenceNumber
= channel
.outgoingReliableSequenceNumber
;
2350 outgoingCommand
.unreliableSequenceNumber
= channel
.outgoingUnreliableSequenceNumber
;
2353 outgoingCommand
.sendAttempts
= 0;
2354 outgoingCommand
.sentTime
= 0;
2355 outgoingCommand
.roundTripTimeout
= 0;
2356 outgoingCommand
.roundTripTimeoutLimit
= 0;
2357 outgoingCommand
.command
.header
.reliableSequenceNumber
= ENET_HOST_TO_NET_16(outgoingCommand
.reliableSequenceNumber
);
2359 switch (outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) {
2360 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE
:
2361 outgoingCommand
.command
.sendUnreliable
.unreliableSequenceNumber
= ENET_HOST_TO_NET_16(outgoingCommand
.unreliableSequenceNumber
);
2363 case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
:
2364 outgoingCommand
.command
.sendUnsequenced
.unsequencedGroup
= ENET_HOST_TO_NET_16(peer
.outgoingUnsequencedGroup
);
2370 if (outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
) {
2371 enet_list_insert(enet_list_end(&peer
.outgoingReliableCommands
), outgoingCommand
);
2373 enet_list_insert(enet_list_end(&peer
.outgoingUnreliableCommands
), outgoingCommand
);
2378 ENetOutgoingCommand
* enet_peer_queue_outgoing_command (ENetPeer
* peer
, const ENetProtocol
* command
, ENetPacket
* packet
, enet_uint32 offset
, enet_uint16 length
) {
2379 ENetOutgoingCommand
* outgoingCommand
= cast(ENetOutgoingCommand
*)enet_malloc(ENetOutgoingCommand
.sizeof
);
2380 if (outgoingCommand
is null) return null;
2382 outgoingCommand
.command
= * command
;
2383 outgoingCommand
.fragmentOffset
= offset
;
2384 outgoingCommand
.fragmentLength
= length
;
2385 outgoingCommand
.packet
= packet
;
2386 if (packet
!is null) ++packet
.referenceCount
;
2388 enet_peer_setup_outgoing_command (peer
, outgoingCommand
);
2390 return outgoingCommand
;
2394 void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer
* peer
, ENetChannel
* channel
) {
2395 ENetListIterator droppedCommand
, startCommand
, currentCommand
;
2397 for (droppedCommand
= startCommand
= currentCommand
= enet_list_begin(& channel
.incomingUnreliableCommands
);
2398 currentCommand
!= enet_list_end(& channel
.incomingUnreliableCommands
);
2399 currentCommand
= enet_list_next(currentCommand
))
2401 ENetIncomingCommand
* incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
2402 if ((incomingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
) continue;
2404 if (incomingCommand
.reliableSequenceNumber
== channel
.incomingReliableSequenceNumber
) {
2405 if (incomingCommand
.fragmentsRemaining
<= 0) {
2406 channel
.incomingUnreliableSequenceNumber
= incomingCommand
.unreliableSequenceNumber
;
2409 if (startCommand
!= currentCommand
) {
2410 enet_list_move(enet_list_end(&peer
.dispatchedCommands
), startCommand
, enet_list_previous(currentCommand
));
2411 if (!peer
.needsDispatch
) {
2412 enet_list_insert(enet_list_end(&peer
.host
.dispatchQueue
), &peer
.dispatchList
);
2413 peer
.needsDispatch
= true;
2415 droppedCommand
= currentCommand
;
2416 } else if (droppedCommand
!= currentCommand
) {
2417 droppedCommand
= enet_list_previous (currentCommand
);
2420 enet_uint16 reliableWindow
= incomingCommand
.reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
2421 enet_uint16 currentWindow
= channel
.incomingReliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
2422 if (incomingCommand
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) reliableWindow
+= ENET_PEER_RELIABLE_WINDOWS
;
2423 if (reliableWindow
>= currentWindow
&& reliableWindow
< currentWindow
+ENET_PEER_FREE_RELIABLE_WINDOWS
-1) break;
2425 droppedCommand
= enet_list_next(currentCommand
);
2427 if (startCommand
!= currentCommand
) {
2428 enet_list_move(enet_list_end(&peer
.dispatchedCommands
), startCommand
, enet_list_previous(currentCommand
));
2429 if (!peer
.needsDispatch
) {
2430 enet_list_insert (enet_list_end(&peer
.host
.dispatchQueue
), &peer
.dispatchList
);
2431 peer
.needsDispatch
= true;
2436 startCommand
= enet_list_next(currentCommand
);
2439 if (startCommand
!= currentCommand
) {
2440 enet_list_move(enet_list_end(&peer
.dispatchedCommands
), startCommand
, enet_list_previous(currentCommand
));
2441 if (!peer
.needsDispatch
) {
2442 enet_list_insert(enet_list_end(&peer
.host
.dispatchQueue
), &peer
.dispatchList
);
2443 peer
.needsDispatch
= true;
2445 droppedCommand
= currentCommand
;
2448 enet_peer_remove_incoming_commands(&channel
.incomingUnreliableCommands
, enet_list_begin(&channel
.incomingUnreliableCommands
), droppedCommand
);
2452 void enet_peer_dispatch_incoming_reliable_commands (ENetPeer
* peer
, ENetChannel
* channel
) {
2453 ENetListIterator currentCommand
;
2455 for (currentCommand
= enet_list_begin(&channel
.incomingReliableCommands
);
2456 currentCommand
!= enet_list_end(&channel
.incomingReliableCommands
);
2457 currentCommand
= enet_list_next(currentCommand
))
2459 ENetIncomingCommand
* incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
2460 if (incomingCommand
.fragmentsRemaining
> 0 || incomingCommand
.reliableSequenceNumber
!= cast(enet_uint16
)(channel
.incomingReliableSequenceNumber
+1)) break;
2461 channel
.incomingReliableSequenceNumber
= incomingCommand
.reliableSequenceNumber
;
2462 if (incomingCommand
.fragmentCount
> 0) channel
.incomingReliableSequenceNumber
+= incomingCommand
.fragmentCount
-1;
2465 if (currentCommand
== enet_list_begin(&channel
.incomingReliableCommands
)) return;
2467 channel
.incomingUnreliableSequenceNumber
= 0;
2469 enet_list_move(enet_list_end(&peer
.dispatchedCommands
), enet_list_begin(&channel
.incomingReliableCommands
), enet_list_previous(currentCommand
));
2471 if (!peer
.needsDispatch
) {
2472 enet_list_insert(enet_list_end(&peer
.host
.dispatchQueue
), &peer
.dispatchList
);
2473 peer
.needsDispatch
= true;
2476 if (!enet_list_empty(&channel
.incomingUnreliableCommands
)) enet_peer_dispatch_incoming_unreliable_commands(peer
, channel
);
2480 ENetIncomingCommand
* enet_peer_queue_incoming_command (ENetPeer
* peer
, const ENetProtocol
* command
, const(void)* data
, usize dataLength
, enet_uint32 flags
, enet_uint32 fragmentCount
) {
2481 static ENetIncomingCommand dummyCommand
;
2483 ENetChannel
* channel
= &peer
.channels
[command
.header
.channelID
];
2484 enet_uint32 unreliableSequenceNumber
= 0, reliableSequenceNumber
= 0;
2485 enet_uint16 reliableWindow
, currentWindow
;
2486 ENetIncomingCommand
* incomingCommand
;
2487 ENetListIterator currentCommand
;
2488 ENetPacket
* packet
= null;
2490 if (peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
) goto discardCommand
;
2492 if ((command
.header
.command
& ENET_PROTOCOL_COMMAND_MASK
) != ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
) {
2493 reliableSequenceNumber
= command
.header
.reliableSequenceNumber
;
2494 reliableWindow
= cast(ushort)(reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
);
2495 currentWindow
= channel
.incomingReliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
2497 if (reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) reliableWindow
+= ENET_PEER_RELIABLE_WINDOWS
;
2499 if (reliableWindow
< currentWindow || reliableWindow
>= currentWindow
+ENET_PEER_FREE_RELIABLE_WINDOWS
-1) goto discardCommand
;
2502 switch (command
.header
.command
& ENET_PROTOCOL_COMMAND_MASK
) {
2503 case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT
:
2504 case ENET_PROTOCOL_COMMAND_SEND_RELIABLE
:
2505 if (reliableSequenceNumber
== channel
.incomingReliableSequenceNumber
) goto discardCommand
;
2506 for (currentCommand
= enet_list_previous(enet_list_end(&channel
.incomingReliableCommands
));
2507 currentCommand
!= enet_list_end(&channel
.incomingReliableCommands
);
2508 currentCommand
= enet_list_previous(currentCommand
))
2510 incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
2511 if (reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) {
2512 if (incomingCommand
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) continue;
2513 } else if (incomingCommand
.reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) break;
2514 if (incomingCommand
.reliableSequenceNumber
<= reliableSequenceNumber
) {
2515 if (incomingCommand
.reliableSequenceNumber
< reliableSequenceNumber
) break;
2516 goto discardCommand
;
2520 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE
:
2521 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT
:
2522 unreliableSequenceNumber
= ENET_NET_TO_HOST_16(command
.sendUnreliable
.unreliableSequenceNumber
);
2523 if (reliableSequenceNumber
== channel
.incomingReliableSequenceNumber
&& unreliableSequenceNumber
<= channel
.incomingUnreliableSequenceNumber
) goto discardCommand
;
2524 for (currentCommand
= enet_list_previous (enet_list_end (& channel
.incomingUnreliableCommands
));
2525 currentCommand
!= enet_list_end (& channel
.incomingUnreliableCommands
);
2526 currentCommand
= enet_list_previous (currentCommand
))
2528 incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
2529 if ((command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) == ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
) continue;
2530 if (reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) {
2531 if (incomingCommand
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) continue;
2532 } else if (incomingCommand
.reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) break;
2533 if (incomingCommand
.reliableSequenceNumber
< reliableSequenceNumber
) break;
2534 if (incomingCommand
.reliableSequenceNumber
> reliableSequenceNumber
) continue;
2535 if (incomingCommand
.unreliableSequenceNumber
<= unreliableSequenceNumber
) {
2536 if (incomingCommand
.unreliableSequenceNumber
< unreliableSequenceNumber
) break;
2537 goto discardCommand
;
2541 case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
:
2542 currentCommand
= enet_list_end(&channel
.incomingUnreliableCommands
);
2545 goto discardCommand
;
2548 if (peer
.totalWaitingData
>= peer
.host
.maximumWaitingData
) goto notifyError
;
2550 packet
= enet_packet_create(data
, dataLength
, flags
);
2551 if (packet
is null) goto notifyError
;
2553 incomingCommand
= cast(ENetIncomingCommand
*)enet_malloc(ENetIncomingCommand
.sizeof
);
2554 if (incomingCommand
is null) goto notifyError
;
2556 incomingCommand
.reliableSequenceNumber
= command
.header
.reliableSequenceNumber
;
2557 incomingCommand
.unreliableSequenceNumber
= unreliableSequenceNumber
&0xFFFF;
2558 incomingCommand
.command
= *command
;
2559 incomingCommand
.fragmentCount
= fragmentCount
;
2560 incomingCommand
.fragmentsRemaining
= fragmentCount
;
2561 incomingCommand
.packet
= packet
;
2562 incomingCommand
.fragments
= null;
2564 if (fragmentCount
> 0) {
2565 if (fragmentCount
<= ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT
) {
2566 incomingCommand
.fragments
= cast(enet_uint32
*)enet_malloc((fragmentCount
+31)/32*enet_uint32
.sizeof
);
2568 if (incomingCommand
.fragments
is null) {
2569 enet_free(incomingCommand
);
2572 import core
.stdc
.string
: memset
;
2573 memset(incomingCommand
.fragments
, 0, (fragmentCount
+31)/32*enet_uint32
.sizeof
);
2576 if (packet
!is null) {
2577 ++packet
.referenceCount
;
2578 peer
.totalWaitingData
+= packet
.dataLength
;
2581 enet_list_insert(enet_list_next(currentCommand
), incomingCommand
);
2583 switch (command
.header
.command
& ENET_PROTOCOL_COMMAND_MASK
) {
2584 case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT
:
2585 case ENET_PROTOCOL_COMMAND_SEND_RELIABLE
:
2586 enet_peer_dispatch_incoming_reliable_commands (peer
, channel
);
2589 enet_peer_dispatch_incoming_unreliable_commands (peer
, channel
);
2593 return incomingCommand
;
2596 if (fragmentCount
> 0) goto notifyError
;
2597 if (packet
!is null && packet
.referenceCount
== 0) enet_packet_destroy(packet
);
2598 return &dummyCommand
;
2601 if (packet
!is null && packet
.referenceCount
== 0) enet_packet_destroy(packet
);
2609 /** Creates a host for communicating to peers.
2612 * address = the address at which other peers may connect to this host. If null, then no peers may connect to the host.
2613 * peerCount = the maximum number of peers that should be allocated for the host.
2614 * channelLimit = the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
2615 * incomingBandwidth = downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
2616 * outgoingBandwidth = upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
2619 * the host on success and null on failure
2622 * ENet will strategically drop packets on specific sides of a connection between hosts
2623 * to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine
2624 * the window size of a connection which limits the amount of reliable packets that may be in transit
2625 * at any given time.
2627 ENetHost
* enet_host_create (const ENetAddress
* address
, usize peerCount
, usize channelLimit
, enet_uint32 incomingBandwidth
=0, enet_uint32 outgoingBandwidth
=0) {
2628 import core
.stdc
.string
: memset
;
2631 ENetPeer
* currentPeer
;
2633 if (peerCount
> ENET_PROTOCOL_MAXIMUM_PEER_ID
) return null;
2635 host
= cast(ENetHost
*)enet_malloc(ENetHost
.sizeof
);
2636 if (host
is null) return null;
2637 memset(host
, 0, ENetHost
.sizeof
);
2639 host
.peers
= cast(ENetPeer
*)enet_malloc(peerCount
*ENetPeer
.sizeof
);
2640 if (host
.peers
is null) {
2644 memset(host
.peers
, 0, peerCount
*ENetPeer
.sizeof
);
2646 host
.socket
= enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM
);
2647 if (host
.socket
== ENET_SOCKET_NULL ||
(address
!is null && enet_socket_bind(host
.socket
, address
) < 0)) {
2648 if (host
.socket
!= ENET_SOCKET_NULL
) enet_socket_destroy(host
.socket
);
2649 enet_free(host
.peers
);
2654 enet_socket_set_option(host
.socket
, ENET_SOCKOPT_NONBLOCK
, 1);
2655 enet_socket_set_option(host
.socket
, ENET_SOCKOPT_BROADCAST
, 1);
2656 enet_socket_set_option(host
.socket
, ENET_SOCKOPT_RCVBUF
, ENET_HOST_RECEIVE_BUFFER_SIZE
);
2657 enet_socket_set_option(host
.socket
, ENET_SOCKOPT_SNDBUF
, ENET_HOST_SEND_BUFFER_SIZE
);
2659 if (address
!is null && enet_socket_get_address(host
.socket
, &host
.address
) < 0) host
.address
= *address
;
2661 if (!channelLimit || channelLimit
> ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
) channelLimit
= ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
;
2662 else if (channelLimit
< ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
) channelLimit
= ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
;
2664 host
.randomSeed
= cast(enet_uint32
)cast(usize
)host
;
2665 host
.randomSeed
+= enet_host_random_seed();
2666 host
.randomSeed
= (host
.randomSeed
<<16)|
(host
.randomSeed
>>16);
2667 host
.channelLimit
= channelLimit
;
2668 host
.incomingBandwidth
= incomingBandwidth
;
2669 host
.outgoingBandwidth
= outgoingBandwidth
;
2670 host
.bandwidthThrottleEpoch
= 0;
2671 host
.recalculateBandwidthLimits
= 0;
2672 host
.mtu
= ENET_HOST_DEFAULT_MTU
;
2673 host
.peerCount
= peerCount
;
2674 host
.commandCount
= 0;
2675 host
.bufferCount
= 0;
2676 host
.checksum
= null;
2677 host
.receivedAddress
.host
= ENET_HOST_ANY
;
2678 host
.receivedAddress
.port
= 0;
2679 host
.receivedData
= null;
2680 host
.receivedDataLength
= 0;
2682 host
.totalSentData
= 0;
2683 host
.totalSentPackets
= 0;
2684 host
.totalReceivedData
= 0;
2685 host
.totalReceivedPackets
= 0;
2687 host
.connectedPeers
= 0;
2688 host
.bandwidthLimitedPeers
= 0;
2689 host
.duplicatePeers
= ENET_PROTOCOL_MAXIMUM_PEER_ID
;
2690 host
.maximumPacketSize
= ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE
;
2691 host
.maximumWaitingData
= ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA
;
2693 host
.compressor
.context
= null;
2694 host
.compressor
.compress
= null;
2695 host
.compressor
.decompress
= null;
2696 host
.compressor
.destroy
= null;
2698 host
.intercept
= null;
2700 enet_list_clear(&host
.dispatchQueue
);
2702 for (currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
2703 currentPeer
.host
= host
;
2704 currentPeer
.incomingPeerID
= cast(ushort)(currentPeer
-host
.peers
);
2705 currentPeer
.outgoingSessionID
= currentPeer
.incomingSessionID
= 0xFF;
2706 currentPeer
.data
= null;
2708 enet_list_clear(¤tPeer
.acknowledgements
);
2709 enet_list_clear(¤tPeer
.sentReliableCommands
);
2710 enet_list_clear(¤tPeer
.sentUnreliableCommands
);
2711 enet_list_clear(¤tPeer
.outgoingReliableCommands
);
2712 enet_list_clear(¤tPeer
.outgoingUnreliableCommands
);
2713 enet_list_clear(¤tPeer
.dispatchedCommands
);
2715 enet_peer_reset(currentPeer
);
2722 /** Destroys the host and all resources associated with it.
2725 * host = pointer to the host to destroy
2727 void enet_host_destroy (ENetHost
* host
) {
2728 ENetPeer
* currentPeer
;
2730 if (host
is null) return;
2732 enet_socket_destroy(host
.socket
);
2734 for (currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
2735 enet_peer_reset(currentPeer
);
2738 if (host
.compressor
.context
!is null && host
.compressor
.destroy
) (*host
.compressor
.destroy
)(host
.compressor
.context
);
2740 enet_free(host
.peers
);
2745 /** Initiates a connection to a foreign host.
2748 * host = host seeking the connection
2749 * address = destination for the connection
2750 * channelCount = number of channels to allocate
2751 * data = user data supplied to the receiving host
2754 * a peer representing the foreign host on success, null on failure
2757 * The peer returned will have not completed the connection until enet_host_service()
2758 * notifies of an ENET_EVENT_TYPE_CONNECT event for the peer.
2760 ENetPeer
* enet_host_connect (ENetHost
* host
, const ENetAddress
* address
, usize channelCount
, enet_uint32 data
) {
2761 ENetPeer
* currentPeer
;
2762 ENetChannel
* channel
;
2763 ENetProtocol command
;
2765 if (channelCount
< ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
) channelCount
= ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
;
2766 else if (channelCount
> ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
) channelCount
= ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
;
2768 for (currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
2769 if (currentPeer
.state
== ENET_PEER_STATE_DISCONNECTED
) break;
2772 if (currentPeer
>= &host
.peers
[host
.peerCount
]) return null;
2774 currentPeer
.channels
= cast(ENetChannel
*)enet_malloc(channelCount
*ENetChannel
.sizeof
);
2775 if (currentPeer
.channels
is null) return null;
2776 currentPeer
.channelCount
= channelCount
;
2777 currentPeer
.state
= ENET_PEER_STATE_CONNECTING
;
2778 currentPeer
.address
= *address
;
2779 currentPeer
.connectID
= ++host
.randomSeed
;
2781 if (host
.outgoingBandwidth
== 0) {
2782 currentPeer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
2784 currentPeer
.windowSize
= (host
.outgoingBandwidth
/ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
2787 if (currentPeer
.windowSize
< ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
) currentPeer
.windowSize
= ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
2788 else if (currentPeer
.windowSize
> ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
) currentPeer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
2790 for (channel
= currentPeer
.channels
; channel
< ¤tPeer
.channels
[channelCount
]; ++channel
) {
2791 import core
.stdc
.string
: memset
;
2793 channel
.outgoingReliableSequenceNumber
= 0;
2794 channel
.outgoingUnreliableSequenceNumber
= 0;
2795 channel
.incomingReliableSequenceNumber
= 0;
2796 channel
.incomingUnreliableSequenceNumber
= 0;
2798 enet_list_clear(&channel
.incomingReliableCommands
);
2799 enet_list_clear(&channel
.incomingUnreliableCommands
);
2801 channel
.usedReliableWindows
= 0;
2802 memset(channel
.reliableWindows
.ptr
, 0, channel
.reliableWindows
.sizeof
);
2805 command
.header
.command
= ENET_PROTOCOL_COMMAND_CONNECT|ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
2806 command
.header
.channelID
= 0xFF;
2807 command
.connect
.outgoingPeerID
= ENET_HOST_TO_NET_16(currentPeer
.incomingPeerID
);
2808 command
.connect
.incomingSessionID
= currentPeer
.incomingSessionID
;
2809 command
.connect
.outgoingSessionID
= currentPeer
.outgoingSessionID
;
2810 command
.connect
.mtu
= ENET_HOST_TO_NET_32(currentPeer
.mtu
);
2811 command
.connect
.windowSize
= ENET_HOST_TO_NET_32(currentPeer
.windowSize
);
2812 command
.connect
.channelCount
= ENET_HOST_TO_NET_32(cast(uint)channelCount
);
2813 command
.connect
.incomingBandwidth
= ENET_HOST_TO_NET_32(host
.incomingBandwidth
);
2814 command
.connect
.outgoingBandwidth
= ENET_HOST_TO_NET_32(host
.outgoingBandwidth
);
2815 command
.connect
.packetThrottleInterval
= ENET_HOST_TO_NET_32(currentPeer
.packetThrottleInterval
);
2816 command
.connect
.packetThrottleAcceleration
= ENET_HOST_TO_NET_32(currentPeer
.packetThrottleAcceleration
);
2817 command
.connect
.packetThrottleDeceleration
= ENET_HOST_TO_NET_32(currentPeer
.packetThrottleDeceleration
);
2818 command
.connect
.connectID
= currentPeer
.connectID
;
2819 command
.connect
.data
= ENET_HOST_TO_NET_32(data
);
2821 enet_peer_queue_outgoing_command(currentPeer
, &command
, null, 0, 0);
2827 /** Queues a packet to be sent to all peers associated with the host.
2830 * host = host on which to broadcast the packet
2831 * channelID = channel on which to broadcast
2832 * packet = packet to broadcast
2834 void enet_host_broadcast (ENetHost
* host
, enet_uint8 channelID
, ENetPacket
* packet
) {
2835 ENetPeer
* currentPeer
;
2837 for (currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
2838 if (currentPeer
.state
!= ENET_PEER_STATE_CONNECTED
) continue;
2839 enet_peer_send(currentPeer
, channelID
, packet
);
2842 if (packet
.referenceCount
== 0) enet_packet_destroy(packet
);
2846 /** Sets the packet compressor the host should use to compress and decompress packets.
2849 * host = host to enable or disable compression for
2850 * compressor = callbacks for for the packet compressor; if null, then compression is disabled
2852 void enet_host_compress (ENetHost
* host
, /*const*/ ENetCompressor
* compressor
) {
2853 if (host
.compressor
.context
!is null && host
.compressor
.destroy
) (*host
.compressor
.destroy
)(host
.compressor
.context
);
2854 if (compressor
) host
.compressor
= *compressor
; else host
.compressor
.context
= null;
2858 /** Limits the maximum allowed channels of future incoming connections.
2861 * host = host to limit
2862 * channelLimit = the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
2864 void enet_host_channel_limit (ENetHost
* host
, usize channelLimit
) @nogc {
2865 if (!channelLimit || channelLimit
> ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
) channelLimit
= ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
;
2866 else if (channelLimit
< ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
) channelLimit
= ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT
;
2867 host
.channelLimit
= channelLimit
;
2871 /** Adjusts the bandwidth limits of a host.
2874 * host = host to adjust
2875 * incomingBandwidth = new incoming bandwidth
2876 * outgoingBandwidth = new outgoing bandwidth
2879 * the incoming and outgoing bandwidth parameters are identical in function to those
2880 * specified in enet_host_create().
2882 void enet_host_bandwidth_limit (ENetHost
* host
, enet_uint32 incomingBandwidth
, enet_uint32 outgoingBandwidth
) @nogc {
2883 host
.incomingBandwidth
= incomingBandwidth
;
2884 host
.outgoingBandwidth
= outgoingBandwidth
;
2885 host
.recalculateBandwidthLimits
= 1;
2889 void enet_host_bandwidth_throttle (ENetHost
* host
) {
2890 enet_uint32 timeCurrent
= enet_time_get();
2891 enet_uint32 elapsedTime
= timeCurrent
-host
.bandwidthThrottleEpoch
;
2892 enet_uint32 peersRemaining
= cast(enet_uint32
)host
.connectedPeers
;
2893 enet_uint32 dataTotal
= ~0;
2894 enet_uint32 bandwidth
= ~0;
2895 enet_uint32 throttle
= 0;
2896 enet_uint32 bandwidthLimit
= 0;
2897 int needsAdjustment
= (host
.bandwidthLimitedPeers
> 0 ?
1 : 0);
2899 ENetProtocol command
;
2901 if (elapsedTime
< ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL
) return;
2903 host
.bandwidthThrottleEpoch
= timeCurrent
;
2905 if (peersRemaining
== 0) return;
2907 if (host
.outgoingBandwidth
!= 0) {
2909 bandwidth
= (host
.outgoingBandwidth
*elapsedTime
)/1000;
2911 for (peer
= host
.peers
; peer
< &host
.peers
[host
.peerCount
]; ++peer
) {
2912 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) continue;
2913 dataTotal
+= peer
.outgoingDataTotal
;
2917 while (peersRemaining
> 0 && needsAdjustment
!= 0) {
2918 needsAdjustment
= 0;
2920 throttle
= (dataTotal
<= bandwidth ? ENET_PEER_PACKET_THROTTLE_SCALE
: (bandwidth
*ENET_PEER_PACKET_THROTTLE_SCALE
)/dataTotal
);
2922 for (peer
= host
.peers
; peer
< &host
.peers
[host
.peerCount
]; ++peer
) {
2923 enet_uint32 peerBandwidth
;
2925 if ((peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) ||
2926 peer
.incomingBandwidth
== 0 ||
2927 peer
.outgoingBandwidthThrottleEpoch
== timeCurrent
)
2930 peerBandwidth
= (peer
.incomingBandwidth
*elapsedTime
)/1000;
2931 if ((throttle
*peer
.outgoingDataTotal
)/ENET_PEER_PACKET_THROTTLE_SCALE
<= peerBandwidth
) continue;
2933 peer
.packetThrottleLimit
= (peerBandwidth
*ENET_PEER_PACKET_THROTTLE_SCALE
)/peer
.outgoingDataTotal
;
2935 if (peer
.packetThrottleLimit
== 0) peer
.packetThrottleLimit
= 1;
2937 if (peer
.packetThrottle
> peer
.packetThrottleLimit
) peer
.packetThrottle
= peer
.packetThrottleLimit
;
2939 peer
.outgoingBandwidthThrottleEpoch
= timeCurrent
;
2941 peer
.incomingDataTotal
= 0;
2942 peer
.outgoingDataTotal
= 0;
2944 needsAdjustment
= 1;
2946 bandwidth
-= peerBandwidth
;
2947 dataTotal
-= peerBandwidth
;
2951 if (peersRemaining
> 0) {
2952 throttle
= (dataTotal
<= bandwidth ? ENET_PEER_PACKET_THROTTLE_SCALE
: (bandwidth
*ENET_PEER_PACKET_THROTTLE_SCALE
)/dataTotal
);
2954 for (peer
= host
.peers
; peer
< &host
.peers
[host
.peerCount
]; ++peer
) {
2955 if ((peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) ||
2956 peer
.outgoingBandwidthThrottleEpoch
== timeCurrent
)
2959 peer
.packetThrottleLimit
= throttle
;
2961 if (peer
.packetThrottle
> peer
.packetThrottleLimit
) peer
.packetThrottle
= peer
.packetThrottleLimit
;
2963 peer
.incomingDataTotal
= 0;
2964 peer
.outgoingDataTotal
= 0;
2968 if (host
.recalculateBandwidthLimits
) {
2969 host
.recalculateBandwidthLimits
= 0;
2971 peersRemaining
= cast(enet_uint32
)host
.connectedPeers
;
2972 bandwidth
= host
.incomingBandwidth
;
2973 needsAdjustment
= 1;
2975 if (bandwidth
== 0) {
2978 while (peersRemaining
> 0 && needsAdjustment
!= 0) {
2979 needsAdjustment
= 0;
2980 bandwidthLimit
= bandwidth
/peersRemaining
;
2982 for (peer
= host
.peers
; peer
< &host
.peers
[host
.peerCount
]; ++peer
) {
2983 if ((peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) ||
2984 peer
.incomingBandwidthThrottleEpoch
== timeCurrent
)
2987 if (peer
.outgoingBandwidth
> 0 && peer
.outgoingBandwidth
>= bandwidthLimit
) continue;
2989 peer
.incomingBandwidthThrottleEpoch
= timeCurrent
;
2991 needsAdjustment
= 1;
2993 bandwidth
-= peer
.outgoingBandwidth
;
2998 for (peer
= host
.peers
; peer
< &host
.peers
[host
.peerCount
]; ++peer
) {
2999 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)
3002 command
.header
.command
= ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
3003 command
.header
.channelID
= 0xFF;
3004 command
.bandwidthLimit
.outgoingBandwidth
= ENET_HOST_TO_NET_32 (host
.outgoingBandwidth
);
3006 if (peer
.incomingBandwidthThrottleEpoch
== timeCurrent
) {
3007 command
.bandwidthLimit
.incomingBandwidth
= ENET_HOST_TO_NET_32(peer
.outgoingBandwidth
);
3009 command
.bandwidthLimit
.incomingBandwidth
= ENET_HOST_TO_NET_32(bandwidthLimit
);
3012 enet_peer_queue_outgoing_command(peer
, &command
, null, 0, 0);
3021 // `auto` to trigger attribute inference
3022 private auto ENET_MIN(T
) (T a
, T b
) { pragma(inline
, true); return (a
< b ? a
: b
); }
3023 private auto ENET_MAX(T
) (T a
, T b
) { pragma(inline
, true); return (a
> b ? a
: b
); }
3026 enum ENET_TIME_OVERFLOW
= 86400000;
3028 // `auto` to trigger attribute inference
3029 auto ENET_TIME_LESS(T
) (T a
, T b
) { pragma(inline
, true); return (a
-b
>= ENET_TIME_OVERFLOW
); }
3030 auto ENET_TIME_GREATER(T
) (T a
, T b
) { pragma(inline
, true); return (b
-a
>= ENET_TIME_OVERFLOW
); }
3031 auto ENET_TIME_LESS_EQUAL(T
) (T a
, T b
) { pragma(inline
, true); return !ENET_TIME_GREATER(a
, b
); }
3032 auto ENET_TIME_GREATER_EQUAL(T
) (T a
, T b
) { pragma(inline
, true); return !ENET_TIME_LESS(a
, b
); }
3034 auto ENET_TIME_DIFFERENCE(T
) (T a
, T b
) { pragma(inline
, true); return (a
-b
>= ENET_TIME_OVERFLOW ? b
-a
: a
-b
); }
3037 private immutable usize
[ENET_PROTOCOL_COMMAND_COUNT
] commandSizes
= [
3039 ENetProtocolAcknowledge
.sizeof
,
3040 ENetProtocolConnect
.sizeof
,
3041 ENetProtocolVerifyConnect
.sizeof
,
3042 ENetProtocolDisconnect
.sizeof
,
3043 ENetProtocolPing
.sizeof
,
3044 ENetProtocolSendReliable
.sizeof
,
3045 ENetProtocolSendUnreliable
.sizeof
,
3046 ENetProtocolSendFragment
.sizeof
,
3047 ENetProtocolSendUnsequenced
.sizeof
,
3048 ENetProtocolBandwidthLimit
.sizeof
,
3049 ENetProtocolThrottleConfigure
.sizeof
,
3050 ENetProtocolSendFragment
.sizeof
,
3054 usize
enet_protocol_command_size (enet_uint8 commandNumber
) @nogc {
3055 return commandSizes
[commandNumber
&ENET_PROTOCOL_COMMAND_MASK
];
3059 private void enet_protocol_change_state (ENetHost
* host
, ENetPeer
* peer
, ENetPeerState state
) {
3060 if (state
== ENET_PEER_STATE_CONNECTED || state
== ENET_PEER_STATE_DISCONNECT_LATER
) {
3061 enet_peer_on_connect(peer
);
3063 enet_peer_on_disconnect(peer
);
3069 private void enet_protocol_dispatch_state (ENetHost
* host
, ENetPeer
* peer
, ENetPeerState state
) {
3070 enet_protocol_change_state(host
, peer
, state
);
3071 if (!peer
.needsDispatch
) {
3072 enet_list_insert(enet_list_end(&host
.dispatchQueue
), &peer
.dispatchList
);
3073 peer
.needsDispatch
= true;
3078 private int enet_protocol_dispatch_incoming_commands (ENetHost
* host
, ENetEvent
* event
) {
3079 while (!enet_list_empty(&host
.dispatchQueue
)) {
3080 ENetPeer
* peer
= cast(ENetPeer
*)enet_list_remove(enet_list_begin(&host
.dispatchQueue
));
3081 peer
.needsDispatch
= false;
3082 switch (peer
.state
) {
3083 case ENET_PEER_STATE_CONNECTION_PENDING
:
3084 case ENET_PEER_STATE_CONNECTION_SUCCEEDED
:
3085 enet_protocol_change_state(host
, peer
, ENET_PEER_STATE_CONNECTED
);
3086 event
.type
= ENET_EVENT_TYPE_CONNECT
;
3088 event
.data
= peer
.eventData
;
3090 case ENET_PEER_STATE_ZOMBIE
:
3091 host
.recalculateBandwidthLimits
= 1;
3092 event
.type
= ENET_EVENT_TYPE_DISCONNECT
;
3094 event
.data
= peer
.eventData
;
3095 enet_peer_reset(peer
);
3097 case ENET_PEER_STATE_CONNECTED
:
3098 if (enet_list_empty(&peer
.dispatchedCommands
)) continue;
3099 event
.packet
= enet_peer_receive(peer
, &event
.channelID
);
3100 if (event
.packet
is null) continue;
3101 event
.type
= ENET_EVENT_TYPE_RECEIVE
;
3103 if (!enet_list_empty(&peer
.dispatchedCommands
)) {
3104 peer
.needsDispatch
= true;
3105 enet_list_insert(enet_list_end(&host
.dispatchQueue
), &peer
.dispatchList
);
3116 private void enet_protocol_notify_connect (ENetHost
* host
, ENetPeer
* peer
, ENetEvent
* event
) {
3117 host
.recalculateBandwidthLimits
= 1;
3118 if (event
!is null) {
3119 enet_protocol_change_state(host
, peer
, ENET_PEER_STATE_CONNECTED
);
3120 event
.type
= ENET_EVENT_TYPE_CONNECT
;
3122 event
.data
= peer
.eventData
;
3124 enet_protocol_dispatch_state(host
, peer
, (peer
.state
== ENET_PEER_STATE_CONNECTING ? ENET_PEER_STATE_CONNECTION_SUCCEEDED
: ENET_PEER_STATE_CONNECTION_PENDING
));
3129 private void enet_protocol_notify_disconnect (ENetHost
* host
, ENetPeer
* peer
, ENetEvent
* event
) {
3130 if (peer
.state
>= ENET_PEER_STATE_CONNECTION_PENDING
) host
.recalculateBandwidthLimits
= 1;
3131 if (peer
.state
!= ENET_PEER_STATE_CONNECTING
&& peer
.state
< ENET_PEER_STATE_CONNECTION_SUCCEEDED
) {
3132 enet_peer_reset(peer
);
3133 } else if (event
!is null) {
3134 event
.type
= ENET_EVENT_TYPE_DISCONNECT
;
3137 enet_peer_reset(peer
);
3140 enet_protocol_dispatch_state(host
, peer
, ENET_PEER_STATE_ZOMBIE
);
3145 private void enet_protocol_remove_sent_unreliable_commands (ENetPeer
* peer
) {
3146 ENetOutgoingCommand
* outgoingCommand
;
3147 while (!enet_list_empty(&peer
.sentUnreliableCommands
)) {
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
);
3162 private ENetProtocolCommand
enet_protocol_remove_sent_reliable_command (ENetPeer
* peer
, enet_uint16 reliableSequenceNumber
, enet_uint8 channelID
) {
3163 ENetOutgoingCommand
* outgoingCommand
= null;
3164 ENetListIterator currentCommand
;
3165 ENetProtocolCommand commandNumber
;
3168 for (currentCommand
= enet_list_begin(&peer
.sentReliableCommands
);
3169 currentCommand
!= enet_list_end(&peer
.sentReliableCommands
);
3170 currentCommand
= enet_list_next(currentCommand
))
3172 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
3173 if (outgoingCommand
.reliableSequenceNumber
== reliableSequenceNumber
&& outgoingCommand
.command
.header
.channelID
== channelID
) break;
3176 if (currentCommand
== enet_list_end(&peer
.sentReliableCommands
)) {
3177 for (currentCommand
= enet_list_begin(&peer
.outgoingReliableCommands
);
3178 currentCommand
!= enet_list_end(&peer
.outgoingReliableCommands
);
3179 currentCommand
= enet_list_next(currentCommand
))
3181 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
3182 if (outgoingCommand
.sendAttempts
< 1) return ENET_PROTOCOL_COMMAND_NONE
;
3183 if (outgoingCommand
.reliableSequenceNumber
== reliableSequenceNumber
&& outgoingCommand
.command
.header
.channelID
== channelID
) break;
3185 if (currentCommand
== enet_list_end(&peer
.outgoingReliableCommands
)) return ENET_PROTOCOL_COMMAND_NONE
;
3189 if (outgoingCommand
is null) return ENET_PROTOCOL_COMMAND_NONE
;
3191 if (channelID
< peer
.channelCount
) {
3192 ENetChannel
* channel
= &peer
.channels
[channelID
];
3193 enet_uint16 reliableWindow
= reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
3194 if (channel
.reliableWindows
[reliableWindow
] > 0) {
3195 --channel
.reliableWindows
[reliableWindow
];
3196 if (!channel
.reliableWindows
[reliableWindow
]) channel
.usedReliableWindows
&= ~(1<<reliableWindow
);
3200 commandNumber
= cast(ENetProtocolCommand
)(outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
);
3202 enet_list_remove(&outgoingCommand
.outgoingCommandList
);
3204 if (outgoingCommand
.packet
!is null) {
3205 if (wasSent
) peer
.reliableDataInTransit
-= outgoingCommand
.fragmentLength
;
3206 --outgoingCommand
.packet
.referenceCount
;
3207 if (outgoingCommand
.packet
.referenceCount
== 0) {
3208 outgoingCommand
.packet
.flags |
= ENET_PACKET_FLAG_SENT
;
3209 enet_packet_destroy (outgoingCommand
.packet
);
3213 enet_free(outgoingCommand
);
3215 if (enet_list_empty(&peer
.sentReliableCommands
)) return commandNumber
;
3217 outgoingCommand
= cast(ENetOutgoingCommand
*)enet_list_front(&peer
.sentReliableCommands
);
3219 peer
.nextTimeout
= outgoingCommand
.sentTime
+outgoingCommand
.roundTripTimeout
;
3221 return commandNumber
;
3225 private ENetPeer
* enet_protocol_handle_connect (ENetHost
* host
, ENetProtocolHeader
* header
, ENetProtocol
* command
) {
3226 enet_uint8 incomingSessionID
, outgoingSessionID
;
3227 enet_uint32 mtu
, windowSize
;
3228 ENetChannel
* channel
;
3229 usize channelCount
, duplicatePeers
= 0;
3230 ENetPeer
* currentPeer
, peer
= null;
3231 ENetProtocol verifyCommand
;
3233 channelCount
= ENET_NET_TO_HOST_32(command
.connect
.channelCount
);
3235 if (channelCount
< ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount
> ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
) return null;
3237 for (currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
3238 if (currentPeer
.state
== ENET_PEER_STATE_DISCONNECTED
) {
3239 if (peer
is null) peer
= currentPeer
;
3240 } else if (currentPeer
.state
!= ENET_PEER_STATE_CONNECTING
&& currentPeer
.address
.host
== host
.receivedAddress
.host
) {
3241 if (currentPeer
.address
.port
== host
.receivedAddress
.port
&& currentPeer
.connectID
== command
.connect
.connectID
) return null;
3246 if (peer
is null || duplicatePeers
>= host
.duplicatePeers
) return null;
3248 if (channelCount
> host
.channelLimit
) channelCount
= host
.channelLimit
;
3249 peer
.channels
= cast(ENetChannel
*)enet_malloc(channelCount
*ENetChannel
.sizeof
);
3250 if (peer
.channels
is null) return null;
3252 peer
.channelCount
= channelCount
;
3253 peer
.state
= ENET_PEER_STATE_ACKNOWLEDGING_CONNECT
;
3254 peer
.connectID
= command
.connect
.connectID
;
3255 peer
.address
= host
.receivedAddress
;
3256 peer
.outgoingPeerID
= ENET_NET_TO_HOST_16(command
.connect
.outgoingPeerID
);
3257 peer
.incomingBandwidth
= ENET_NET_TO_HOST_32(command
.connect
.incomingBandwidth
);
3258 peer
.outgoingBandwidth
= ENET_NET_TO_HOST_32(command
.connect
.outgoingBandwidth
);
3259 peer
.packetThrottleInterval
= ENET_NET_TO_HOST_32(command
.connect
.packetThrottleInterval
);
3260 peer
.packetThrottleAcceleration
= ENET_NET_TO_HOST_32(command
.connect
.packetThrottleAcceleration
);
3261 peer
.packetThrottleDeceleration
= ENET_NET_TO_HOST_32(command
.connect
.packetThrottleDeceleration
);
3262 peer
.eventData
= ENET_NET_TO_HOST_32(command
.connect
.data
);
3264 incomingSessionID
= (command
.connect
.incomingSessionID
== 0xFF ? peer
.outgoingSessionID
: command
.connect
.incomingSessionID
);
3265 incomingSessionID
= (incomingSessionID
+1)&(ENET_PROTOCOL_HEADER_SESSION_MASK
>>ENET_PROTOCOL_HEADER_SESSION_SHIFT
);
3266 if (incomingSessionID
== peer
.outgoingSessionID
) incomingSessionID
= (incomingSessionID
+1)&(ENET_PROTOCOL_HEADER_SESSION_MASK
>>ENET_PROTOCOL_HEADER_SESSION_SHIFT
);
3267 peer
.outgoingSessionID
= incomingSessionID
;
3269 outgoingSessionID
= (command
.connect
.outgoingSessionID
== 0xFF ? peer
.incomingSessionID
: command
.connect
.outgoingSessionID
);
3270 outgoingSessionID
= (outgoingSessionID
+1)&(ENET_PROTOCOL_HEADER_SESSION_MASK
>>ENET_PROTOCOL_HEADER_SESSION_SHIFT
);
3271 if (outgoingSessionID
== peer
.incomingSessionID
) outgoingSessionID
= (outgoingSessionID
+1)&(ENET_PROTOCOL_HEADER_SESSION_MASK
>>ENET_PROTOCOL_HEADER_SESSION_SHIFT
);
3272 peer
.incomingSessionID
= outgoingSessionID
;
3274 for (channel
= peer
.channels
; channel
< &peer
.channels
[channelCount
]; ++channel
) {
3275 channel
.outgoingReliableSequenceNumber
= 0;
3276 channel
.outgoingUnreliableSequenceNumber
= 0;
3277 channel
.incomingReliableSequenceNumber
= 0;
3278 channel
.incomingUnreliableSequenceNumber
= 0;
3280 enet_list_clear(&channel
.incomingReliableCommands
);
3281 enet_list_clear(&channel
.incomingUnreliableCommands
);
3283 channel
.usedReliableWindows
= 0;
3285 import core
.stdc
.string
: memset
;
3286 memset(channel
.reliableWindows
.ptr
, 0, channel
.reliableWindows
.sizeof
);
3289 mtu
= ENET_NET_TO_HOST_32(command
.connect
.mtu
);
3291 if (mtu
< ENET_PROTOCOL_MINIMUM_MTU
) mtu
= ENET_PROTOCOL_MINIMUM_MTU
;
3292 else if (mtu
> ENET_PROTOCOL_MAXIMUM_MTU
) mtu
= ENET_PROTOCOL_MAXIMUM_MTU
;
3296 if (host
.outgoingBandwidth
== 0 && peer
.incomingBandwidth
== 0) {
3297 peer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3298 } else if (host
.outgoingBandwidth
== 0 || peer
.incomingBandwidth
== 0) {
3299 peer
.windowSize
= (ENET_MAX(host
.outgoingBandwidth
, peer
.incomingBandwidth
)/ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3301 peer
.windowSize
= (ENET_MIN(host
.outgoingBandwidth
, peer
.incomingBandwidth
)/ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3303 if (peer
.windowSize
< ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
) peer
.windowSize
= ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3304 else if (peer
.windowSize
> ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
) peer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3306 if (host
.incomingBandwidth
== 0) windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3307 else windowSize
= (host
.incomingBandwidth
/ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3309 if (windowSize
> ENET_NET_TO_HOST_32(command
.connect
.windowSize
)) windowSize
= ENET_NET_TO_HOST_32(command
.connect
.windowSize
);
3311 if (windowSize
< ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
) windowSize
= ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3312 else if (windowSize
> ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
) windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3314 verifyCommand
.header
.command
= ENET_PROTOCOL_COMMAND_VERIFY_CONNECT|ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
;
3315 verifyCommand
.header
.channelID
= 0xFF;
3316 verifyCommand
.verifyConnect
.outgoingPeerID
= ENET_HOST_TO_NET_16 (peer
.incomingPeerID
);
3317 verifyCommand
.verifyConnect
.incomingSessionID
= incomingSessionID
;
3318 verifyCommand
.verifyConnect
.outgoingSessionID
= outgoingSessionID
;
3319 verifyCommand
.verifyConnect
.mtu
= ENET_HOST_TO_NET_32(peer
.mtu
);
3320 verifyCommand
.verifyConnect
.windowSize
= ENET_HOST_TO_NET_32(windowSize
);
3321 verifyCommand
.verifyConnect
.channelCount
= ENET_HOST_TO_NET_32(cast(uint)channelCount
);
3322 verifyCommand
.verifyConnect
.incomingBandwidth
= ENET_HOST_TO_NET_32(host
.incomingBandwidth
);
3323 verifyCommand
.verifyConnect
.outgoingBandwidth
= ENET_HOST_TO_NET_32(host
.outgoingBandwidth
);
3324 verifyCommand
.verifyConnect
.packetThrottleInterval
= ENET_HOST_TO_NET_32(peer
.packetThrottleInterval
);
3325 verifyCommand
.verifyConnect
.packetThrottleAcceleration
= ENET_HOST_TO_NET_32(peer
.packetThrottleAcceleration
);
3326 verifyCommand
.verifyConnect
.packetThrottleDeceleration
= ENET_HOST_TO_NET_32(peer
.packetThrottleDeceleration
);
3327 verifyCommand
.verifyConnect
.connectID
= peer
.connectID
;
3329 enet_peer_queue_outgoing_command(peer
, &verifyCommand
, null, 0, 0);
3335 private int enet_protocol_handle_send_reliable (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint8
** currentData
) {
3337 if (command
.header
.channelID
>= peer
.channelCount ||
(peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)) return -1;
3338 dataLength
= ENET_NET_TO_HOST_16(command
.sendReliable
.dataLength
);
3339 *currentData
+= dataLength
;
3340 if (dataLength
> host
.maximumPacketSize ||
*currentData
< host
.receivedData ||
*currentData
> &host
.receivedData
[host
.receivedDataLength
]) return -1;
3341 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;
3346 private int enet_protocol_handle_send_unsequenced (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint8
** currentData
) {
3347 enet_uint32 unsequencedGroup
, index
;
3350 if (command
.header
.channelID
>= peer
.channelCount ||
(peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)) return -1;
3352 dataLength
= ENET_NET_TO_HOST_16(command
.sendUnsequenced
.dataLength
);
3353 *currentData
+= dataLength
;
3354 if (dataLength
> host
.maximumPacketSize ||
*currentData
< host
.receivedData ||
*currentData
> &host
.receivedData
[host
.receivedDataLength
]) return -1;
3356 unsequencedGroup
= ENET_NET_TO_HOST_16 (command
.sendUnsequenced
.unsequencedGroup
);
3357 index
= unsequencedGroup
%ENET_PEER_UNSEQUENCED_WINDOW_SIZE
;
3359 if (unsequencedGroup
< peer
.incomingUnsequencedGroup
) unsequencedGroup
+= 0x10000;
3361 if (unsequencedGroup
>= cast(enet_uint32
)peer
.incomingUnsequencedGroup
+ENET_PEER_FREE_UNSEQUENCED_WINDOWS
*ENET_PEER_UNSEQUENCED_WINDOW_SIZE
) return 0;
3363 unsequencedGroup
&= 0xFFFF;
3365 if (unsequencedGroup
-index
!= peer
.incomingUnsequencedGroup
) {
3366 import core
.stdc
.string
: memset
;
3367 peer
.incomingUnsequencedGroup
= cast(ushort)(unsequencedGroup
-index
);
3368 memset(peer
.unsequencedWindow
.ptr
, 0, peer
.unsequencedWindow
.sizeof
);
3369 } else if (peer
.unsequencedWindow
.ptr
[index
/32]&(1<<(index
%32))) {
3373 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;
3375 peer
.unsequencedWindow
.ptr
[index
/32] |
= 1<<(index
%32);
3381 private int enet_protocol_handle_send_unreliable (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint8
** currentData
) {
3384 if (command
.header
.channelID
>= peer
.channelCount ||
(peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)) return -1;
3386 dataLength
= ENET_NET_TO_HOST_16(command
.sendUnreliable
.dataLength
);
3387 *currentData
+= dataLength
;
3388 if (dataLength
> host
.maximumPacketSize ||
*currentData
< host
.receivedData ||
*currentData
> &host
.receivedData
[host
.receivedDataLength
]) return -1;
3390 if (enet_peer_queue_incoming_command(peer
, command
, cast(const(enet_uint8
)*)command
+ENetProtocolSendUnreliable
.sizeof
, dataLength
, 0, 0) is null) return -1;
3396 private int enet_protocol_handle_send_fragment (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint8
** currentData
) {
3397 enet_uint32 fragmentNumber
, fragmentCount
, fragmentOffset
, fragmentLength
, startSequenceNumber
, totalLength
;
3398 ENetChannel
* channel
;
3399 enet_uint16 startWindow
, currentWindow
;
3400 ENetListIterator currentCommand
;
3401 ENetIncomingCommand
* startCommand
= null;
3403 if (command
.header
.channelID
>= peer
.channelCount ||
(peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)) return -1;
3405 fragmentLength
= ENET_NET_TO_HOST_16 (command
.sendFragment
.dataLength
);
3406 *currentData
+= fragmentLength
;
3407 if (fragmentLength
> host
.maximumPacketSize ||
*currentData
< host
.receivedData ||
*currentData
> &host
.receivedData
[host
.receivedDataLength
]) return -1;
3409 channel
= &peer
.channels
[command
.header
.channelID
];
3410 startSequenceNumber
= ENET_NET_TO_HOST_16(command
.sendFragment
.startSequenceNumber
);
3411 startWindow
= cast(ushort)(startSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
);
3412 currentWindow
= channel
.incomingReliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
3414 if (startSequenceNumber
< channel
.incomingReliableSequenceNumber
) startWindow
+= ENET_PEER_RELIABLE_WINDOWS
;
3416 if (startWindow
< currentWindow || startWindow
>= currentWindow
+ENET_PEER_FREE_RELIABLE_WINDOWS
-1) return 0;
3418 fragmentNumber
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentNumber
);
3419 fragmentCount
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentCount
);
3420 fragmentOffset
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentOffset
);
3421 totalLength
= ENET_NET_TO_HOST_32(command
.sendFragment
.totalLength
);
3423 if (fragmentCount
> ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT ||
3424 fragmentNumber
>= fragmentCount ||
3425 totalLength
> host
.maximumPacketSize ||
3426 fragmentOffset
>= totalLength ||
3427 fragmentLength
> totalLength
-fragmentOffset
)
3430 for (currentCommand
= enet_list_previous(enet_list_end(&channel
.incomingReliableCommands
));
3431 currentCommand
!= enet_list_end(&channel
.incomingReliableCommands
);
3432 currentCommand
= enet_list_previous(currentCommand
))
3434 ENetIncomingCommand
* incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
3435 if (startSequenceNumber
>= channel
.incomingReliableSequenceNumber
) {
3436 if (incomingCommand
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) continue;
3437 } else if (incomingCommand
.reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) break;
3438 if (incomingCommand
.reliableSequenceNumber
<= startSequenceNumber
) {
3439 if (incomingCommand
.reliableSequenceNumber
< startSequenceNumber
) break;
3440 if ((incomingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) != ENET_PROTOCOL_COMMAND_SEND_FRAGMENT ||
3441 totalLength
!= incomingCommand
.packet
.dataLength ||
3442 fragmentCount
!= incomingCommand
.fragmentCount
)
3444 startCommand
= incomingCommand
;
3449 if (startCommand
is null) {
3450 ENetProtocol hostCommand
= *command
;
3451 hostCommand
.header
.reliableSequenceNumber
= cast(ushort)startSequenceNumber
;
3452 startCommand
= enet_peer_queue_incoming_command(peer
, &hostCommand
, null, totalLength
, ENET_PACKET_FLAG_RELIABLE
, fragmentCount
);
3453 if (startCommand
is null) return -1;
3456 if ((startCommand
.fragments
[fragmentNumber
/32]&(1<<(fragmentNumber
%32))) == 0) {
3457 import core
.stdc
.string
: memcpy
;
3458 --startCommand
.fragmentsRemaining
;
3459 startCommand
.fragments
[fragmentNumber
/32] |
= (1<<(fragmentNumber
%32));
3460 if (fragmentOffset
+fragmentLength
> startCommand
.packet
.dataLength
) fragmentLength
= cast(uint)(startCommand
.packet
.dataLength
-fragmentOffset
);
3461 memcpy(startCommand
.packet
.data
+fragmentOffset
, cast(enet_uint8
*)command
+ENetProtocolSendFragment
.sizeof
, fragmentLength
);
3462 if (startCommand
.fragmentsRemaining
<= 0) enet_peer_dispatch_incoming_reliable_commands(peer
, channel
);
3469 private int enet_protocol_handle_send_unreliable_fragment (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
, enet_uint8
** currentData
) {
3470 enet_uint32 fragmentNumber
, fragmentCount
, fragmentOffset
, fragmentLength
, reliableSequenceNumber
, startSequenceNumber
, totalLength
;
3471 enet_uint16 reliableWindow
, currentWindow
;
3472 ENetChannel
* channel
;
3473 ENetListIterator currentCommand
;
3474 ENetIncomingCommand
* startCommand
= null;
3476 if (command
.header
.channelID
>= peer
.channelCount ||
(peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
)) return -1;
3478 fragmentLength
= ENET_NET_TO_HOST_16(command
.sendFragment
.dataLength
);
3479 *currentData
+= fragmentLength
;
3480 if (fragmentLength
> host
.maximumPacketSize ||
*currentData
< host
.receivedData ||
*currentData
> &host
.receivedData
[host
.receivedDataLength
]) return -1;
3482 channel
= &peer
.channels
[command
.header
.channelID
];
3483 reliableSequenceNumber
= command
.header
.reliableSequenceNumber
;
3484 startSequenceNumber
= ENET_NET_TO_HOST_16(command
.sendFragment
.startSequenceNumber
);
3486 reliableWindow
= cast(ushort)(reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
);
3487 currentWindow
= channel
.incomingReliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
3489 if (reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) reliableWindow
+= ENET_PEER_RELIABLE_WINDOWS
;
3491 if (reliableWindow
< currentWindow || reliableWindow
>= currentWindow
+ENET_PEER_FREE_RELIABLE_WINDOWS
-1) return 0;
3493 if (reliableSequenceNumber
== channel
.incomingReliableSequenceNumber
&& startSequenceNumber
<= channel
.incomingUnreliableSequenceNumber
) return 0;
3495 fragmentNumber
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentNumber
);
3496 fragmentCount
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentCount
);
3497 fragmentOffset
= ENET_NET_TO_HOST_32(command
.sendFragment
.fragmentOffset
);
3498 totalLength
= ENET_NET_TO_HOST_32(command
.sendFragment
.totalLength
);
3500 if (fragmentCount
> ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT ||
3501 fragmentNumber
>= fragmentCount ||
3502 totalLength
> host
.maximumPacketSize ||
3503 fragmentOffset
>= totalLength ||
3504 fragmentLength
> totalLength
- fragmentOffset
)
3507 for (currentCommand
= enet_list_previous(enet_list_end (&channel
.incomingUnreliableCommands
));
3508 currentCommand
!= enet_list_end(&channel
.incomingUnreliableCommands
);
3509 currentCommand
= enet_list_previous(currentCommand
))
3511 ENetIncomingCommand
* incomingCommand
= cast(ENetIncomingCommand
*)currentCommand
;
3512 if (reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) {
3513 if (incomingCommand
.reliableSequenceNumber
< channel
.incomingReliableSequenceNumber
) continue;
3514 } else if (incomingCommand
.reliableSequenceNumber
>= channel
.incomingReliableSequenceNumber
) break;
3515 if (incomingCommand
.reliableSequenceNumber
< reliableSequenceNumber
) break;
3516 if (incomingCommand
.reliableSequenceNumber
> reliableSequenceNumber
) continue;
3517 if (incomingCommand
.unreliableSequenceNumber
<= startSequenceNumber
) {
3518 if (incomingCommand
.unreliableSequenceNumber
< startSequenceNumber
) break;
3519 if ((incomingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) != ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT ||
3520 totalLength
!= incomingCommand
.packet
.dataLength ||
3521 fragmentCount
!= incomingCommand
.fragmentCount
)
3523 startCommand
= incomingCommand
;
3528 if (startCommand
is null) {
3529 startCommand
= enet_peer_queue_incoming_command(peer
, command
, null, totalLength
, ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT
, fragmentCount
);
3530 if (startCommand
is null) return -1;
3533 if ((startCommand
.fragments
[fragmentNumber
/32]&(1<<(fragmentNumber
%32))) == 0) {
3534 import core
.stdc
.string
: memcpy
;
3535 --startCommand
.fragmentsRemaining
;
3536 startCommand
.fragments
[fragmentNumber
/32] |
= (1<<(fragmentNumber
%32));
3537 if (fragmentOffset
+fragmentLength
> startCommand
.packet
.dataLength
) fragmentLength
= cast(uint)(startCommand
.packet
.dataLength
-fragmentOffset
);
3538 memcpy(startCommand
.packet
.data
+fragmentOffset
, cast(enet_uint8
*)command
+ENetProtocolSendFragment
.sizeof
, fragmentLength
);
3539 if (startCommand
.fragmentsRemaining
<= 0) enet_peer_dispatch_incoming_unreliable_commands(peer
, channel
);
3546 private int enet_protocol_handle_ping (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
) @nogc {
3547 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) return -1;
3552 private int enet_protocol_handle_bandwidth_limit (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
) @nogc {
3553 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) return -1;
3555 if (peer
.incomingBandwidth
!= 0) --host
.bandwidthLimitedPeers
;
3557 peer
.incomingBandwidth
= ENET_NET_TO_HOST_32(command
.bandwidthLimit
.incomingBandwidth
);
3558 peer
.outgoingBandwidth
= ENET_NET_TO_HOST_32(command
.bandwidthLimit
.outgoingBandwidth
);
3560 if (peer
.incomingBandwidth
!= 0) ++host
.bandwidthLimitedPeers
;
3562 if (peer
.incomingBandwidth
== 0 && host
.outgoingBandwidth
== 0) {
3563 peer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3564 } else if (peer
.incomingBandwidth
== 0 || host
.outgoingBandwidth
== 0) {
3565 peer
.windowSize
= (ENET_MAX(peer
.incomingBandwidth
, host
.outgoingBandwidth
)/ ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3567 peer
.windowSize
= (ENET_MIN(peer
.incomingBandwidth
, host
.outgoingBandwidth
)/ENET_PEER_WINDOW_SIZE_SCALE
)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3570 if (peer
.windowSize
< ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
) peer
.windowSize
= ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3571 else if (peer
.windowSize
> ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
) peer
.windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3577 private int enet_protocol_handle_throttle_configure (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
) @nogc {
3578 if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) return -1;
3580 peer
.packetThrottleInterval
= ENET_NET_TO_HOST_32(command
.throttleConfigure
.packetThrottleInterval
);
3581 peer
.packetThrottleAcceleration
= ENET_NET_TO_HOST_32(command
.throttleConfigure
.packetThrottleAcceleration
);
3582 peer
.packetThrottleDeceleration
= ENET_NET_TO_HOST_32(command
.throttleConfigure
.packetThrottleDeceleration
);
3588 private int enet_protocol_handle_disconnect (ENetHost
* host
, ENetPeer
* peer
, const ENetProtocol
* command
) {
3589 if (peer
.state
== ENET_PEER_STATE_DISCONNECTED || peer
.state
== ENET_PEER_STATE_ZOMBIE || peer
.state
== ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT
) return 0;
3591 enet_peer_reset_queues(peer
);
3593 if (peer
.state
== ENET_PEER_STATE_CONNECTION_SUCCEEDED || peer
.state
== ENET_PEER_STATE_DISCONNECTING || peer
.state
== ENET_PEER_STATE_CONNECTING
) {
3594 enet_protocol_dispatch_state(host
, peer
, ENET_PEER_STATE_ZOMBIE
);
3595 } else if (peer
.state
!= ENET_PEER_STATE_CONNECTED
&& peer
.state
!= ENET_PEER_STATE_DISCONNECT_LATER
) {
3596 if (peer
.state
== ENET_PEER_STATE_CONNECTION_PENDING
) host
.recalculateBandwidthLimits
= 1;
3597 enet_peer_reset(peer
);
3598 } else if (command
.header
.command
&ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
) {
3599 enet_protocol_change_state(host
, peer
, ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT
);
3601 enet_protocol_dispatch_state(host
, peer
, ENET_PEER_STATE_ZOMBIE
);
3604 if (peer
.state
!= ENET_PEER_STATE_DISCONNECTED
) peer
.eventData
= ENET_NET_TO_HOST_32(command
.disconnect
.data
);
3610 private int enet_protocol_handle_acknowledge (ENetHost
* host
, ENetEvent
* event
, ENetPeer
* peer
, const ENetProtocol
* command
) {
3611 enet_uint32 roundTripTime
, receivedSentTime
, receivedReliableSequenceNumber
;
3612 ENetProtocolCommand commandNumber
;
3614 if (peer
.state
== ENET_PEER_STATE_DISCONNECTED || peer
.state
== ENET_PEER_STATE_ZOMBIE
) return 0;
3616 receivedSentTime
= ENET_NET_TO_HOST_16(command
.acknowledge
.receivedSentTime
);
3617 receivedSentTime |
= host
.serviceTime
&0xFFFF0000;
3618 if ((receivedSentTime
&0x8000) > (host
.serviceTime
&0x8000)) receivedSentTime
-= 0x10000;
3620 if (ENET_TIME_LESS(host
.serviceTime
, receivedSentTime
)) return 0;
3622 peer
.lastReceiveTime
= host
.serviceTime
;
3623 peer
.earliestTimeout
= 0;
3625 roundTripTime
= ENET_TIME_DIFFERENCE(host
.serviceTime
, receivedSentTime
);
3627 enet_peer_throttle(peer
, roundTripTime
);
3629 peer
.roundTripTimeVariance
-= peer
.roundTripTimeVariance
/4;
3631 if (roundTripTime
>= peer
.roundTripTime
) {
3632 peer
.roundTripTime
+= (roundTripTime
-peer
.roundTripTime
)/8;
3633 peer
.roundTripTimeVariance
+= (roundTripTime
-peer
.roundTripTime
)/4;
3635 peer
.roundTripTime
-= (peer
.roundTripTime
-roundTripTime
)/8;
3636 peer
.roundTripTimeVariance
+= (peer
.roundTripTime
-roundTripTime
)/4;
3639 if (peer
.roundTripTime
< peer
.lowestRoundTripTime
) peer
.lowestRoundTripTime
= peer
.roundTripTime
;
3641 if (peer
.roundTripTimeVariance
> peer
.highestRoundTripTimeVariance
) peer
.highestRoundTripTimeVariance
= peer
.roundTripTimeVariance
;
3643 if (peer
.packetThrottleEpoch
== 0 ||
ENET_TIME_DIFFERENCE(host
.serviceTime
, peer
.packetThrottleEpoch
) >= peer
.packetThrottleInterval
) {
3644 peer
.lastRoundTripTime
= peer
.lowestRoundTripTime
;
3645 peer
.lastRoundTripTimeVariance
= peer
.highestRoundTripTimeVariance
;
3646 peer
.lowestRoundTripTime
= peer
.roundTripTime
;
3647 peer
.highestRoundTripTimeVariance
= peer
.roundTripTimeVariance
;
3648 peer
.packetThrottleEpoch
= host
.serviceTime
;
3651 receivedReliableSequenceNumber
= ENET_NET_TO_HOST_16(command
.acknowledge
.receivedReliableSequenceNumber
);
3653 commandNumber
= enet_protocol_remove_sent_reliable_command(peer
, cast(ushort)receivedReliableSequenceNumber
, command
.header
.channelID
);
3655 switch (peer
.state
) {
3656 case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT
:
3657 if (commandNumber
!= ENET_PROTOCOL_COMMAND_VERIFY_CONNECT
) return -1;
3658 enet_protocol_notify_connect (host
, peer
, event
);
3660 case ENET_PEER_STATE_DISCONNECTING
:
3661 if (commandNumber
!= ENET_PROTOCOL_COMMAND_DISCONNECT
) return -1;
3662 enet_protocol_notify_disconnect (host
, peer
, event
);
3664 case ENET_PEER_STATE_DISCONNECT_LATER
:
3665 if (enet_list_empty (&peer
.outgoingReliableCommands
) && enet_list_empty(&peer
.outgoingUnreliableCommands
) && enet_list_empty(&peer
.sentReliableCommands
)) {
3666 enet_peer_disconnect(peer
, peer
.eventData
);
3677 private int enet_protocol_handle_verify_connect (ENetHost
* host
, ENetEvent
* event
, ENetPeer
* peer
, const ENetProtocol
* command
) {
3678 enet_uint32 mtu
, windowSize
;
3681 if (peer
.state
!= ENET_PEER_STATE_CONNECTING
) return 0;
3683 channelCount
= ENET_NET_TO_HOST_32(command
.verifyConnect
.channelCount
);
3685 if (channelCount
< ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT || channelCount
> ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT ||
3686 ENET_NET_TO_HOST_32 (command
.verifyConnect
.packetThrottleInterval
) != peer
.packetThrottleInterval ||
3687 ENET_NET_TO_HOST_32 (command
.verifyConnect
.packetThrottleAcceleration
) != peer
.packetThrottleAcceleration ||
3688 ENET_NET_TO_HOST_32 (command
.verifyConnect
.packetThrottleDeceleration
) != peer
.packetThrottleDeceleration ||
3689 command
.verifyConnect
.connectID
!= peer
.connectID
)
3692 enet_protocol_dispatch_state(host
, peer
, ENET_PEER_STATE_ZOMBIE
);
3696 enet_protocol_remove_sent_reliable_command(peer
, 1, 0xFF);
3698 if (channelCount
< peer
.channelCount
) peer
.channelCount
= channelCount
;
3700 peer
.outgoingPeerID
= ENET_NET_TO_HOST_16(command
.verifyConnect
.outgoingPeerID
);
3701 peer
.incomingSessionID
= command
.verifyConnect
.incomingSessionID
;
3702 peer
.outgoingSessionID
= command
.verifyConnect
.outgoingSessionID
;
3704 mtu
= ENET_NET_TO_HOST_32(command
.verifyConnect
.mtu
);
3706 if (mtu
< ENET_PROTOCOL_MINIMUM_MTU
) mtu
= ENET_PROTOCOL_MINIMUM_MTU
;
3707 else if (mtu
> ENET_PROTOCOL_MAXIMUM_MTU
) mtu
= ENET_PROTOCOL_MAXIMUM_MTU
;
3709 if (mtu
< peer
.mtu
) peer
.mtu
= mtu
;
3711 windowSize
= ENET_NET_TO_HOST_32(command
.verifyConnect
.windowSize
);
3713 if (windowSize
< ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
) windowSize
= ENET_PROTOCOL_MINIMUM_WINDOW_SIZE
;
3714 if (windowSize
> ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
) windowSize
= ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE
;
3715 if (windowSize
< peer
.windowSize
) peer
.windowSize
= windowSize
;
3717 peer
.incomingBandwidth
= ENET_NET_TO_HOST_32(command
.verifyConnect
.incomingBandwidth
);
3718 peer
.outgoingBandwidth
= ENET_NET_TO_HOST_32(command
.verifyConnect
.outgoingBandwidth
);
3720 enet_protocol_notify_connect(host
, peer
, event
);
3726 private int enet_protocol_handle_incoming_commands (ENetHost
* host
, ENetEvent
* event
) {
3727 ENetProtocolHeader
* header
;
3728 ENetProtocol
* command
;
3730 enet_uint8
* currentData
;
3732 enet_uint16 peerID
, flags
;
3733 enet_uint8 sessionID
;
3735 if (host
.receivedDataLength
< cast(usize
)&(cast(ENetProtocolHeader
*)0).sentTime
) return 0; //k8:???
3737 header
= cast(ENetProtocolHeader
*)host
.receivedData
;
3739 peerID
= ENET_NET_TO_HOST_16(header
.peerID
);
3740 sessionID
= (peerID
&ENET_PROTOCOL_HEADER_SESSION_MASK
)>>ENET_PROTOCOL_HEADER_SESSION_SHIFT
;
3741 flags
= peerID
&ENET_PROTOCOL_HEADER_FLAG_MASK
;
3742 peerID
&= ~(ENET_PROTOCOL_HEADER_FLAG_MASK|ENET_PROTOCOL_HEADER_SESSION_MASK
);
3744 headerSize
= (flags
&ENET_PROTOCOL_HEADER_FLAG_SENT_TIME ? ENetProtocolHeader
.sizeof
: cast(usize
)&(cast(ENetProtocolHeader
*)0).sentTime
);
3745 if (host
.checksum
!is null) headerSize
+= enet_uint32
.sizeof
;
3747 if (peerID
== ENET_PROTOCOL_MAXIMUM_PEER_ID
) {
3749 } else if (peerID
>= host
.peerCount
) {
3752 peer
= &host
.peers
[peerID
];
3753 if (peer
.state
== ENET_PEER_STATE_DISCONNECTED ||
3754 peer
.state
== ENET_PEER_STATE_ZOMBIE ||
3755 ((host
.receivedAddress
.host
!= peer
.address
.host ||
3756 host
.receivedAddress
.port
!= peer
.address
.port
) && peer
.address
.host
!= ENET_HOST_BROADCAST
) ||
3757 (peer
.outgoingPeerID
< ENET_PROTOCOL_MAXIMUM_PEER_ID
&& sessionID
!= peer
.incomingSessionID
))
3761 if (flags
&ENET_PROTOCOL_HEADER_FLAG_COMPRESSED
) {
3763 if (host
.compressor
.context
is null || host
.compressor
.decompress
is null) return 0;
3765 originalSize
= host
.compressor
.decompress(host
.compressor
.context
,
3766 host
.receivedData
+headerSize
,
3767 host
.receivedDataLength
-headerSize
,
3768 host
.packetData
.ptr
[1].ptr
+headerSize
,
3769 host
.packetData
.ptr
[1].sizeof
-headerSize
);
3770 if (originalSize
<= 0 || originalSize
> host
.packetData
.ptr
[1].sizeof
-headerSize
) return 0;
3772 import core
.stdc
.string
: memcpy
;
3773 memcpy(host
.packetData
.ptr
[1].ptr
, header
, headerSize
);
3774 host
.receivedData
= host
.packetData
.ptr
[1].ptr
;
3775 host
.receivedDataLength
= headerSize
+originalSize
;
3778 if (host
.checksum
!is null) {
3779 enet_uint32
* checksum
= cast(enet_uint32
*)&host
.receivedData
[headerSize
-enet_uint32
.sizeof
];
3780 enet_uint32 desiredChecksum
= *checksum
;
3783 *checksum
= (peer
!is null ? peer
.connectID
: 0);
3785 buffer
.data
= host
.receivedData
;
3786 buffer
.dataLength
= host
.receivedDataLength
;
3788 if (host
.checksum(&buffer
, 1) != desiredChecksum
) return 0;
3791 if (peer
!is null) {
3792 peer
.address
.host
= host
.receivedAddress
.host
;
3793 peer
.address
.port
= host
.receivedAddress
.port
;
3794 peer
.incomingDataTotal
+= host
.receivedDataLength
;
3797 currentData
= host
.receivedData
+headerSize
;
3799 while (currentData
< &host
.receivedData
[host
.receivedDataLength
]) {
3800 enet_uint8 commandNumber
;
3803 command
= cast(ENetProtocol
*)currentData
;
3805 if (currentData
+ENetProtocolCommandHeader
.sizeof
> &host
.receivedData
[host
.receivedDataLength
]) break;
3807 commandNumber
= command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
;
3808 if (commandNumber
>= ENET_PROTOCOL_COMMAND_COUNT
) break;
3810 commandSize
= commandSizes
[commandNumber
];
3811 if (commandSize
== 0 || currentData
+commandSize
> &host
.receivedData
[host
.receivedDataLength
]) break;
3813 currentData
+= commandSize
;
3815 if (peer
is null && commandNumber
!= ENET_PROTOCOL_COMMAND_CONNECT
) break;
3817 command
.header
.reliableSequenceNumber
= ENET_NET_TO_HOST_16(command
.header
.reliableSequenceNumber
);
3819 switch (commandNumber
) {
3820 case ENET_PROTOCOL_COMMAND_ACKNOWLEDGE
:
3821 if (enet_protocol_handle_acknowledge(host
, event
, peer
, command
)) goto commandError
;
3823 case ENET_PROTOCOL_COMMAND_CONNECT
:
3824 if (peer
!is null) goto commandError
;
3825 peer
= enet_protocol_handle_connect(host
, header
, command
);
3826 if (peer
is null) goto commandError
;
3828 case ENET_PROTOCOL_COMMAND_VERIFY_CONNECT
:
3829 if (enet_protocol_handle_verify_connect(host
, event
, peer
, command
)) goto commandError
;
3831 case ENET_PROTOCOL_COMMAND_DISCONNECT
:
3832 if (enet_protocol_handle_disconnect(host
, peer
, command
)) goto commandError
;
3834 case ENET_PROTOCOL_COMMAND_PING
:
3835 if (enet_protocol_handle_ping(host
, peer
, command
)) goto commandError
;
3837 case ENET_PROTOCOL_COMMAND_SEND_RELIABLE
:
3838 if (enet_protocol_handle_send_reliable(host
, peer
, command
, ¤tData
)) goto commandError
;
3840 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE
:
3841 if (enet_protocol_handle_send_unreliable(host
, peer
, command
, ¤tData
)) goto commandError
;
3843 case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED
:
3844 if (enet_protocol_handle_send_unsequenced(host
, peer
, command
, ¤tData
)) goto commandError
;
3846 case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT
:
3847 if (enet_protocol_handle_send_fragment(host
, peer
, command
, ¤tData
)) goto commandError
;
3849 case ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT
:
3850 if (enet_protocol_handle_bandwidth_limit(host
, peer
, command
)) goto commandError
;
3852 case ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE
:
3853 if (enet_protocol_handle_throttle_configure(host
, peer
, command
)) goto commandError
;
3855 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT
:
3856 if (enet_protocol_handle_send_unreliable_fragment(host
, peer
, command
, ¤tData
)) goto commandError
;
3862 if (peer
!is null && (command
.header
.command
&ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE
) != 0) {
3863 enet_uint16 sentTime
;
3865 if (!(flags
&ENET_PROTOCOL_HEADER_FLAG_SENT_TIME
)) break;
3866 sentTime
= ENET_NET_TO_HOST_16 (header
.sentTime
);
3867 switch (peer
.state
) {
3868 case ENET_PEER_STATE_DISCONNECTING
:
3869 case ENET_PEER_STATE_ACKNOWLEDGING_CONNECT
:
3870 case ENET_PEER_STATE_DISCONNECTED
:
3871 case ENET_PEER_STATE_ZOMBIE
:
3873 case ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT
:
3874 if ((command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) == ENET_PROTOCOL_COMMAND_DISCONNECT
) {
3875 enet_peer_queue_acknowledgement(peer
, command
, sentTime
);
3879 enet_peer_queue_acknowledgement(peer
, command
, sentTime
);
3886 if (event
!is null && event
.type
!= ENET_EVENT_TYPE_NONE
) return 1;
3891 private int enet_protocol_receive_incoming_commands (ENetHost
* host
, ENetEvent
* event
) {
3892 for (int packets
= 0; packets
< 256; ++packets
) {
3895 buffer
.data
= host
.packetData
.ptr
[0].ptr
;
3896 buffer
.dataLength
= host
.packetData
.ptr
[0].sizeof
;
3897 receivedLength
= enet_socket_receive(host
.socket
, &host
.receivedAddress
, &buffer
, 1);
3898 if (receivedLength
< 0) return -1;
3899 if (receivedLength
== 0) return 0;
3900 host
.receivedData
= host
.packetData
.ptr
[0].ptr
;
3901 host
.receivedDataLength
= receivedLength
;
3902 host
.totalReceivedData
+= receivedLength
;
3903 ++host
.totalReceivedPackets
;
3904 if (host
.intercept
!is null) {
3905 switch (host
.intercept(host
, event
)) {
3907 if (event
!is null && event
.type
!= ENET_EVENT_TYPE_NONE
) return 1;
3915 switch (enet_protocol_handle_incoming_commands(host
, event
)) {
3925 private void enet_protocol_send_acknowledgements (ENetHost
* host
, ENetPeer
* peer
) {
3926 ENetProtocol
* command
= &host
.commands
.ptr
[host
.commandCount
];
3927 ENetBuffer
* buffer
= &host
.buffers
.ptr
[host
.bufferCount
];
3928 ENetAcknowledgement
* acknowledgement
;
3929 ENetListIterator currentAcknowledgement
;
3930 enet_uint16 reliableSequenceNumber
;
3932 currentAcknowledgement
= enet_list_begin(&peer
.acknowledgements
);
3934 while (currentAcknowledgement
!= enet_list_end(&peer
.acknowledgements
)) {
3935 if (command
>= &host
.commands
.ptr
[host
.commands
.sizeof
/ENetProtocol
.sizeof
] ||
3936 buffer
>= &host
.buffers
.ptr
[host
.buffers
.sizeof
/ENetBuffer
.sizeof
] ||
3937 peer
.mtu
-host
.packetSize
< ENetProtocolAcknowledge
.sizeof
)
3939 host
.continueSending
= 1;
3943 acknowledgement
= cast(ENetAcknowledgement
*)currentAcknowledgement
;
3945 currentAcknowledgement
= enet_list_next(currentAcknowledgement
);
3947 buffer
.data
= command
;
3948 buffer
.dataLength
= ENetProtocolAcknowledge
.sizeof
;
3950 host
.packetSize
+= buffer
.dataLength
;
3952 reliableSequenceNumber
= ENET_HOST_TO_NET_16(acknowledgement
.command
.header
.reliableSequenceNumber
);
3954 command
.header
.command
= ENET_PROTOCOL_COMMAND_ACKNOWLEDGE
;
3955 command
.header
.channelID
= acknowledgement
.command
.header
.channelID
;
3956 command
.header
.reliableSequenceNumber
= reliableSequenceNumber
;
3957 command
.acknowledge
.receivedReliableSequenceNumber
= reliableSequenceNumber
;
3958 command
.acknowledge
.receivedSentTime
= ENET_HOST_TO_NET_16(cast(ushort)acknowledgement
.sentTime
);
3960 if ((acknowledgement
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
) == ENET_PROTOCOL_COMMAND_DISCONNECT
) {
3961 enet_protocol_dispatch_state(host
, peer
, ENET_PEER_STATE_ZOMBIE
);
3964 enet_list_remove(&acknowledgement
.acknowledgementList
);
3965 enet_free(acknowledgement
);
3971 host
.commandCount
= command
-host
.commands
.ptr
;
3972 host
.bufferCount
= buffer
-host
.buffers
.ptr
;
3976 private void enet_protocol_send_unreliable_outgoing_commands (ENetHost
* host
, ENetPeer
* peer
) {
3977 ENetProtocol
* command
= &host
.commands
.ptr
[host
.commandCount
];
3978 ENetBuffer
* buffer
= &host
.buffers
.ptr
[host
.bufferCount
];
3979 ENetOutgoingCommand
* outgoingCommand
;
3980 ENetListIterator currentCommand
;
3982 currentCommand
= enet_list_begin(&peer
.outgoingUnreliableCommands
);
3984 while (currentCommand
!= enet_list_end(&peer
.outgoingUnreliableCommands
)) {
3987 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
3988 commandSize
= commandSizes
[outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
];
3990 if (command
>= &host
.commands
.ptr
[host
.commands
.sizeof
/ENetProtocol
.sizeof
] ||
3991 buffer
+1 >= &host
.buffers
.ptr
[host
.buffers
.sizeof
/ENetBuffer
.sizeof
] ||
3992 peer
.mtu
-host
.packetSize
< commandSize ||
3993 (outgoingCommand
.packet
!is null && peer
.mtu
-host
.packetSize
< commandSize
+outgoingCommand
.fragmentLength
))
3995 host
.continueSending
= 1;
3999 currentCommand
= enet_list_next(currentCommand
);
4001 if (outgoingCommand
.packet
!is null && outgoingCommand
.fragmentOffset
== 0) {
4002 peer
.packetThrottleCounter
+= ENET_PEER_PACKET_THROTTLE_COUNTER
;
4003 peer
.packetThrottleCounter
%= ENET_PEER_PACKET_THROTTLE_SCALE
;
4004 if (peer
.packetThrottleCounter
> peer
.packetThrottle
) {
4005 enet_uint16 reliableSequenceNumber
= outgoingCommand
.reliableSequenceNumber
;
4006 enet_uint16 unreliableSequenceNumber
= outgoingCommand
.unreliableSequenceNumber
;
4008 --outgoingCommand
.packet
.referenceCount
;
4010 if (outgoingCommand
.packet
.referenceCount
== 0) enet_packet_destroy(outgoingCommand
.packet
);
4012 enet_list_remove(&outgoingCommand
.outgoingCommandList
);
4013 enet_free(outgoingCommand
);
4015 if (currentCommand
== enet_list_end(&peer
.outgoingUnreliableCommands
)) break;
4017 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
4018 if (outgoingCommand
.reliableSequenceNumber
!= reliableSequenceNumber ||
4019 outgoingCommand
.unreliableSequenceNumber
!= unreliableSequenceNumber
)
4022 currentCommand
= enet_list_next(currentCommand
);
4028 buffer
.data
= command
;
4029 buffer
.dataLength
= commandSize
;
4031 host
.packetSize
+= buffer
.dataLength
;
4033 *command
= outgoingCommand
.command
;
4035 enet_list_remove(&outgoingCommand
.outgoingCommandList
);
4037 if (outgoingCommand
.packet
!is null) {
4040 buffer
.data
= outgoingCommand
.packet
.data
+outgoingCommand
.fragmentOffset
;
4041 buffer
.dataLength
= outgoingCommand
.fragmentLength
;
4043 host
.packetSize
+= buffer
.dataLength
;
4045 enet_list_insert(enet_list_end(&peer
.sentUnreliableCommands
), outgoingCommand
);
4047 enet_free(outgoingCommand
);
4054 host
.commandCount
= command
-host
.commands
.ptr
;
4055 host
.bufferCount
= buffer
-host
.buffers
.ptr
;
4057 if (peer
.state
== ENET_PEER_STATE_DISCONNECT_LATER
&& enet_list_empty(&peer
.outgoingReliableCommands
) &&
4058 enet_list_empty(&peer
.outgoingUnreliableCommands
) && enet_list_empty(&peer
.sentReliableCommands
))
4060 enet_peer_disconnect(peer
, peer
.eventData
);
4065 private int enet_protocol_check_timeouts (ENetHost
* host
, ENetPeer
* peer
, ENetEvent
* event
) {
4066 ENetOutgoingCommand
* outgoingCommand
;
4067 ENetListIterator currentCommand
, insertPosition
;
4069 currentCommand
= enet_list_begin(&peer
.sentReliableCommands
);
4070 insertPosition
= enet_list_begin(&peer
.outgoingReliableCommands
);
4072 while (currentCommand
!= enet_list_end(&peer
.sentReliableCommands
)) {
4073 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
4075 currentCommand
= enet_list_next(currentCommand
);
4077 if (ENET_TIME_DIFFERENCE(host
.serviceTime
, outgoingCommand
.sentTime
) < outgoingCommand
.roundTripTimeout
) continue;
4079 if (peer
.earliestTimeout
== 0 ||
ENET_TIME_LESS(outgoingCommand
.sentTime
, peer
.earliestTimeout
)) {
4080 peer
.earliestTimeout
= outgoingCommand
.sentTime
;
4083 if (peer
.earliestTimeout
!= 0 && (ENET_TIME_DIFFERENCE(host
.serviceTime
, peer
.earliestTimeout
) >= peer
.timeoutMaximum ||
4084 (outgoingCommand
.roundTripTimeout
>= outgoingCommand
.roundTripTimeoutLimit
&& ENET_TIME_DIFFERENCE(host
.serviceTime
, peer
.earliestTimeout
) >= peer
.timeoutMinimum
)))
4086 enet_protocol_notify_disconnect(host
, peer
, event
);
4090 if (outgoingCommand
.packet
!is null) peer
.reliableDataInTransit
-= outgoingCommand
.fragmentLength
;
4094 outgoingCommand
.roundTripTimeout
*= 2;
4096 enet_list_insert(insertPosition
, enet_list_remove(&outgoingCommand
.outgoingCommandList
));
4098 if (currentCommand
== enet_list_begin(&peer
.sentReliableCommands
) && !enet_list_empty(&peer
.sentReliableCommands
)) {
4099 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
4100 peer
.nextTimeout
= outgoingCommand
.sentTime
+outgoingCommand
.roundTripTimeout
;
4108 private int enet_protocol_send_reliable_outgoing_commands (ENetHost
* host
, ENetPeer
* peer
) @nogc {
4109 ENetProtocol
* command
= &host
.commands
.ptr
[host
.commandCount
];
4110 ENetBuffer
* buffer
= &host
.buffers
.ptr
[host
.bufferCount
];
4111 ENetOutgoingCommand
* outgoingCommand
;
4112 ENetListIterator currentCommand
;
4113 ENetChannel
* channel
;
4114 enet_uint16 reliableWindow
;
4116 int windowExceeded
= 0, windowWrap
= 0, canPing
= 1;
4118 currentCommand
= enet_list_begin(&peer
.outgoingReliableCommands
);
4119 while (currentCommand
!= enet_list_end(&peer
.outgoingReliableCommands
)) {
4120 outgoingCommand
= cast(ENetOutgoingCommand
*)currentCommand
;
4121 channel
= (outgoingCommand
.command
.header
.channelID
< peer
.channelCount ?
&peer
.channels
[outgoingCommand
.command
.header
.channelID
] : null);
4122 reliableWindow
= outgoingCommand
.reliableSequenceNumber
/ENET_PEER_RELIABLE_WINDOW_SIZE
;
4124 if (channel
!is null) {
4125 if (!windowWrap
&& outgoingCommand
.sendAttempts
< 1 && !(outgoingCommand
.reliableSequenceNumber
%ENET_PEER_RELIABLE_WINDOW_SIZE
) &&
4126 (channel
.reliableWindows
[(reliableWindow
+ENET_PEER_RELIABLE_WINDOWS
-1)%ENET_PEER_RELIABLE_WINDOWS
] >= ENET_PEER_RELIABLE_WINDOW_SIZE ||
4127 channel
.usedReliableWindows
&(
4128 (((1<<ENET_PEER_FREE_RELIABLE_WINDOWS
)-1)<<reliableWindow
)|
4129 (((1<<ENET_PEER_FREE_RELIABLE_WINDOWS
)-1)>>(ENET_PEER_RELIABLE_WINDOWS
-reliableWindow
)))))
4134 currentCommand
= enet_list_next(currentCommand
);
4139 if (outgoingCommand
.packet
!is null) {
4140 if (!windowExceeded
) {
4141 enet_uint32 windowSize
= (peer
.packetThrottle
*peer
.windowSize
)/ENET_PEER_PACKET_THROTTLE_SCALE
;
4142 if (peer
.reliableDataInTransit
+outgoingCommand
.fragmentLength
> ENET_MAX(windowSize
, peer
.mtu
)) windowExceeded
= 1;
4144 if (windowExceeded
) {
4145 currentCommand
= enet_list_next(currentCommand
);
4152 commandSize
= commandSizes
[outgoingCommand
.command
.header
.command
&ENET_PROTOCOL_COMMAND_MASK
];
4154 if (command
>= &host
.commands
.ptr
[host
.commands
.sizeof
/ENetProtocol
.sizeof
] ||
4155 buffer
+1 >= &host
.buffers
.ptr
[host
.buffers
.sizeof
/ENetBuffer
.sizeof
] ||
4156 peer
.mtu
-host
.packetSize
< commandSize ||
4157 (outgoingCommand
.packet
!is null && cast(enet_uint16
)(peer
.mtu
-host
.packetSize
) < cast(enet_uint16
)(commandSize
+outgoingCommand
.fragmentLength
)))
4159 host
.continueSending
= 1;
4163 currentCommand
= enet_list_next(currentCommand
);
4165 if (channel
!is null && outgoingCommand
.sendAttempts
< 1) {
4166 channel
.usedReliableWindows |
= 1<<reliableWindow
;
4167 ++channel
.reliableWindows
[reliableWindow
];
4170 ++outgoingCommand
.sendAttempts
;
4172 if (outgoingCommand
.roundTripTimeout
== 0) {
4173 outgoingCommand
.roundTripTimeout
= peer
.roundTripTime
+4*peer
.roundTripTimeVariance
;
4174 outgoingCommand
.roundTripTimeoutLimit
= peer
.timeoutLimit
*outgoingCommand
.roundTripTimeout
;
4177 if (enet_list_empty(&peer
.sentReliableCommands
)) peer
.nextTimeout
= host
.serviceTime
+outgoingCommand
.roundTripTimeout
;
4179 enet_list_insert(enet_list_end(&peer
.sentReliableCommands
), enet_list_remove(&outgoingCommand
.outgoingCommandList
));
4181 outgoingCommand
.sentTime
= host
.serviceTime
;
4183 buffer
.data
= command
;
4184 buffer
.dataLength
= commandSize
;
4186 host
.packetSize
+= buffer
.dataLength
;
4187 host
.headerFlags |
= ENET_PROTOCOL_HEADER_FLAG_SENT_TIME
;
4189 *command
= outgoingCommand
.command
;
4191 if (outgoingCommand
.packet
!is null) {
4194 buffer
.data
= outgoingCommand
.packet
.data
+outgoingCommand
.fragmentOffset
;
4195 buffer
.dataLength
= outgoingCommand
.fragmentLength
;
4197 host
.packetSize
+= outgoingCommand
.fragmentLength
;
4199 peer
.reliableDataInTransit
+= outgoingCommand
.fragmentLength
;
4208 host
.commandCount
= command
-host
.commands
.ptr
;
4209 host
.bufferCount
= buffer
-host
.buffers
.ptr
;
4215 private int enet_protocol_send_outgoing_commands (ENetHost
* host
, ENetEvent
* event
, int checkForTimeouts
) {
4216 enet_uint8
[ENetProtocolHeader
.sizeof
+enet_uint32
.sizeof
] headerData
;
4217 ENetProtocolHeader
* header
= cast(ENetProtocolHeader
*)headerData
;
4218 ENetPeer
* currentPeer
;
4220 usize shouldCompress
= 0;
4222 host
.continueSending
= 1;
4224 while (host
.continueSending
) {
4225 for (host
.continueSending
= 0, currentPeer
= host
.peers
; currentPeer
< &host
.peers
[host
.peerCount
]; ++currentPeer
) {
4226 if (currentPeer
.state
== ENET_PEER_STATE_DISCONNECTED || currentPeer
.state
== ENET_PEER_STATE_ZOMBIE
) continue;
4228 host
.headerFlags
= 0;
4229 host
.commandCount
= 0;
4230 host
.bufferCount
= 1;
4231 host
.packetSize
= ENetProtocolHeader
.sizeof
;
4233 if (!enet_list_empty(¤tPeer
.acknowledgements
)) enet_protocol_send_acknowledgements(host
, currentPeer
);
4235 if (checkForTimeouts
!= 0 && !enet_list_empty(¤tPeer
.sentReliableCommands
) && ENET_TIME_GREATER_EQUAL(host
.serviceTime
, currentPeer
.nextTimeout
) &&
4236 enet_protocol_check_timeouts(host
, currentPeer
, event
) == 1)
4238 if (event
!is null && event
.type
!= ENET_EVENT_TYPE_NONE
) return 1;
4242 if ((enet_list_empty(¤tPeer
.outgoingReliableCommands
) ||
enet_protocol_send_reliable_outgoing_commands(host
, currentPeer
)) &&
4243 enet_list_empty(¤tPeer
.sentReliableCommands
) && ENET_TIME_DIFFERENCE(host
.serviceTime
, currentPeer
.lastReceiveTime
) >= currentPeer
.pingInterval
&&
4244 currentPeer
.mtu
-host
.packetSize
>= ENetProtocolPing
.sizeof
)
4246 enet_peer_ping(currentPeer
);
4247 enet_protocol_send_reliable_outgoing_commands(host
, currentPeer
);
4250 if (!enet_list_empty(¤tPeer
.outgoingUnreliableCommands
)) enet_protocol_send_unreliable_outgoing_commands (host
, currentPeer
);
4252 if (host
.commandCount
== 0) continue;
4254 if (currentPeer
.packetLossEpoch
== 0) {
4255 currentPeer
.packetLossEpoch
= host
.serviceTime
;
4256 } else if (ENET_TIME_DIFFERENCE(host
.serviceTime
, currentPeer
.packetLossEpoch
) >= ENET_PEER_PACKET_LOSS_INTERVAL
&& currentPeer
.packetsSent
> 0) {
4257 enet_uint32 packetLoss
= currentPeer
.packetsLost
* ENET_PEER_PACKET_LOSS_SCALE
/ currentPeer
.packetsSent
;
4259 version(enet_debug
) {
4260 import core
.stdc
.stdio
: printf
;
4261 printf("peer %u: %f%%+-%f%% packet loss, %u+-%u ms round trip time, %f%% throttle, %u/%u outgoing, %u/%u incoming\n",
4262 currentPeer
.incomingPeerID
, currentPeer
.packetLoss
/cast(float)ENET_PEER_PACKET_LOSS_SCALE
, currentPeer
.packetLossVariance
/cast(float)ENET_PEER_PACKET_LOSS_SCALE
,
4263 currentPeer
.roundTripTime
, currentPeer
.roundTripTimeVariance
, currentPeer
.packetThrottle
/cast(float)ENET_PEER_PACKET_THROTTLE_SCALE
,
4264 enet_list_size(¤tPeer
.outgoingReliableCommands
), enet_list_size(¤tPeer
.outgoingUnreliableCommands
),
4265 (currentPeer
.channels
!is null ?
enet_list_size(¤tPeer
.channels
.incomingReliableCommands
) : 0),
4266 (currentPeer
.channels
!is null ?
enet_list_size(¤tPeer
.channels
.incomingUnreliableCommands
) : 0));
4269 currentPeer
.packetLossVariance
-= currentPeer
.packetLossVariance
/4;
4271 if (packetLoss
>= currentPeer
.packetLoss
) {
4272 currentPeer
.packetLoss
+= (packetLoss
- currentPeer
.packetLoss
)/8;
4273 currentPeer
.packetLossVariance
+= (packetLoss
-currentPeer
.packetLoss
)/4;
4275 currentPeer
.packetLoss
-= (currentPeer
.packetLoss
-packetLoss
)/8;
4276 currentPeer
.packetLossVariance
+= (currentPeer
.packetLoss
-packetLoss
)/4;
4279 currentPeer
.packetLossEpoch
= host
.serviceTime
;
4280 currentPeer
.packetsSent
= 0;
4281 currentPeer
.packetsLost
= 0;
4284 host
.buffers
.ptr
[0].data
= headerData
.ptr
;
4285 if (host
.headerFlags
&ENET_PROTOCOL_HEADER_FLAG_SENT_TIME
) {
4286 header
.sentTime
= ENET_HOST_TO_NET_16(host
.serviceTime
&0xFFFF);
4287 host
.buffers
.ptr
[0].dataLength
= ENetProtocolHeader
.sizeof
;
4289 host
.buffers
.ptr
[0].dataLength
= cast(usize
)&(cast(ENetProtocolHeader
*)0).sentTime
;
4293 if (host
.compressor
.context
!is null && host
.compressor
.compress
!is null) {
4294 usize originalSize
= host
.packetSize
-ENetProtocolHeader
.sizeof
;
4295 usize compressedSize
= host
.compressor
.compress(host
.compressor
.context
, &host
.buffers
.ptr
[1], host
.bufferCount
-1, originalSize
, host
.packetData
.ptr
[1].ptr
, originalSize
);
4296 if (compressedSize
> 0 && compressedSize
< originalSize
) {
4297 host
.headerFlags |
= ENET_PROTOCOL_HEADER_FLAG_COMPRESSED
;
4298 shouldCompress
= compressedSize
;
4299 version(enet_debug_compress
) {
4300 import core
.stdc
.stdio
: printf
;
4301 printf("peer %u: compressed %u.%u (%u%%)\n", currentPeer
.incomingPeerID
, originalSize
, compressedSize
, (compressedSize
*100)/originalSize
);
4306 if (currentPeer
.outgoingPeerID
< ENET_PROTOCOL_MAXIMUM_PEER_ID
) host
.headerFlags |
= currentPeer
.outgoingSessionID
<<ENET_PROTOCOL_HEADER_SESSION_SHIFT
;
4307 header
.peerID
= ENET_HOST_TO_NET_16(currentPeer
.outgoingPeerID|host
.headerFlags
);
4308 if (host
.checksum
!is null) {
4309 enet_uint32
* checksum
= cast(enet_uint32
*)&headerData
[host
.buffers
.ptr
[0].dataLength
];
4310 *checksum
= (currentPeer
.outgoingPeerID
< ENET_PROTOCOL_MAXIMUM_PEER_ID ? currentPeer
.connectID
: 0);
4311 host
.buffers
.ptr
[0].dataLength
+= enet_uint32
.sizeof
;
4312 *checksum
= host
.checksum(host
.buffers
.ptr
, host
.bufferCount
);
4315 if (shouldCompress
> 0) {
4316 host
.buffers
.ptr
[1].data
= host
.packetData
.ptr
[1].ptr
;
4317 host
.buffers
.ptr
[1].dataLength
= shouldCompress
;
4318 host
.bufferCount
= 2;
4321 currentPeer
.lastSendTime
= host
.serviceTime
;
4323 sentLength
= enet_socket_send(host
.socket
, ¤tPeer
.address
, host
.buffers
.ptr
, host
.bufferCount
);
4325 enet_protocol_remove_sent_unreliable_commands(currentPeer
);
4327 if (sentLength
< 0) return -1;
4329 host
.totalSentData
+= sentLength
;
4330 ++host
.totalSentPackets
;
4338 /** Sends any queued packets on the host specified to its designated peers.
4341 * host = host to flush
4344 * this function need only be used in circumstances where one wishes to send queued packets earlier than in a call to enet_host_service().
4346 void enet_host_flush (ENetHost
* host
) {
4347 host
.serviceTime
= enet_time_get();
4348 enet_protocol_send_outgoing_commands(host
, null, 0);
4352 /** Checks for any queued events on the host and dispatches one if available.
4355 * host = host to check for events
4356 * event = an event structure where event details will be placed if available
4359 * > 0 if an event was dispatched, 0 if no events are available, < 0 on failure
4361 int enet_host_check_events (ENetHost
* host
, ENetEvent
* event
) {
4362 if (event
is null) return -1;
4363 event
.type
= ENET_EVENT_TYPE_NONE
;
4365 event
.packet
= null;
4366 return enet_protocol_dispatch_incoming_commands(host
, event
);
4370 /** Waits for events on the host specified and shuttles packets between
4371 * the host and its peers.
4374 * host = host to service
4375 * event = an event structure where event details will be placed if one occurs
4376 * if event is null then no events will be delivered
4377 * timeout = number of milliseconds that ENet should wait for events
4380 * > 0 if an event occurred within the specified time limit, 0 if no event occurred, < 0 on failure
4383 * enet_host_service should be called fairly regularly for adequate performance
4385 int enet_host_service (ENetHost
* host
, ENetEvent
* event
, enet_uint32 timeout
) {
4386 enet_uint32 waitCondition
;
4388 if (event
!is null) {
4389 event
.type
= ENET_EVENT_TYPE_NONE
;
4391 event
.packet
= null;
4392 switch (enet_protocol_dispatch_incoming_commands(host
, event
)) {
4394 case -1: version(enet_debug
) { import core
.stdc
.stdio
: perror
; perror("Error dispatching incoming packets"); } return -1;
4399 host
.serviceTime
= enet_time_get();
4400 timeout
+= host
.serviceTime
;
4402 if (ENET_TIME_DIFFERENCE(host
.serviceTime
, host
.bandwidthThrottleEpoch
) >= ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL
) enet_host_bandwidth_throttle(host
);
4403 switch (enet_protocol_send_outgoing_commands(host
, event
, 1)) {
4405 case -1:version(enet_debug
) { import core
.stdc
.stdio
: perror
; perror("Error sending outgoing packets"); } return -1;
4409 switch (enet_protocol_receive_incoming_commands(host
, event
)) {
4411 case -1: version(enet_debug
) { import core
.stdc
.stdio
: perror
; perror("Error receiving incoming packets"); } return -1;
4415 switch (enet_protocol_send_outgoing_commands(host
, event
, 1)) {
4417 case -1: version(enet_debug
) { import core
.stdc
.stdio
: perror
; perror("Error sending outgoing packets"); } return -1;
4421 if (event
!is null) {
4422 switch (enet_protocol_dispatch_incoming_commands (host
, event
)) {
4424 case -1: version(enet_debug
) { import core
.stdc
.stdio
: perror
; perror("Error dispatching incoming packets"); } return -1;
4429 if (ENET_TIME_GREATER_EQUAL(host
.serviceTime
, timeout
)) return 0;
4432 host
.serviceTime
= enet_time_get();
4433 if (ENET_TIME_GREATER_EQUAL(host
.serviceTime
, timeout
)) return 0;
4434 waitCondition
= ENET_SOCKET_WAIT_RECEIVE|ENET_SOCKET_WAIT_INTERRUPT
;
4435 if (enet_socket_wait(host
.socket
, &waitCondition
, ENET_TIME_DIFFERENCE (timeout
, host
.serviceTime
)) != 0) return -1;
4436 } while (waitCondition
&ENET_SOCKET_WAIT_INTERRUPT
);
4438 host
.serviceTime
= enet_time_get ();
4439 } while (waitCondition
&ENET_SOCKET_WAIT_RECEIVE
);
4448 * An adaptive order-2 PPM range coder
4451 // cool helper to translate C defines
4452 template cmacroFixVars(T
...) {
4453 string
cmacroFixVars (string s
, string
[] names
...) {
4454 assert(T
.length
== names
.length
, "cmacroFixVars: names and arguments count mismatch");
4457 // skip empty lines (for pretty printing)
4458 // trim trailing spaces
4459 while (s
.length
> 0 && s
[$-1] <= ' ') s
= s
[0..$-1];
4460 uint linestpos
= 0; // start of the current line
4461 while (pos
< s
.length
) {
4462 if (s
[pos
] > ' ') break;
4463 if (s
[pos
] == '\n') linestpos
= pos
+1;
4467 while (pos
+2 < s
.length
) {
4469 while (epos
+2 < s
.length
&& (s
[epos
] != '$' || s
[epos
+1] != '{')) ++epos
;
4471 if (s
.length
-epos
< 3) break;
4472 res
~= s
[pos
..epos
];
4475 assert(s
[pos
] == '$' && s
[pos
+1] == '{');
4476 bool ascode
= (pos
> 0 && s
[pos
-1] == '$');
4479 if (ascode
) res
= res
[0..$-1]; // remove dollar
4480 foreach (immutable nidx
, string oname
; T
) {
4481 static assert(oname
.length
> 0);
4482 if (s
.length
-pos
>= oname
.length
+1 && s
[pos
+oname
.length
] == '}' && s
[pos
..pos
+oname
.length
] == oname
) {
4484 pos
+= oname
.length
+1;
4486 bool hasbang
= false;
4487 foreach (immutable char ch
; names
[nidx
]) {
4488 if (ch
== '{') break;
4489 if (ch
== '!') { hasbang
= true; break; }
4491 if (hasbang
) res
~= "mixin("~names
[nidx
]~")"; else res
~= names
[nidx
];
4492 if (names
[nidx
][$-1] != '}') res
~= ";";
4499 assert(found
, "unknown variable in macro");
4501 if (pos
< s
.length
) res
~= s
[pos
..$];
4508 /* binary indexed tree of symbols */
4512 enet_uint16 left
, right
;
4514 /* context defined by this symbol */
4515 enet_uint16 symbols
;
4516 enet_uint16 escapes
;
4521 /* adaptation constants tuned aggressively for small packet sizes rather than large file compression */
4523 ENET_RANGE_CODER_TOP
= 1<<24,
4524 ENET_RANGE_CODER_BOTTOM
= 1<<16,
4526 ENET_CONTEXT_SYMBOL_DELTA
= 3,
4527 ENET_CONTEXT_SYMBOL_MINIMUM
= 1,
4528 ENET_CONTEXT_ESCAPE_MINIMUM
= 1,
4530 ENET_SUBCONTEXT_ORDER
= 2,
4531 ENET_SUBCONTEXT_SYMBOL_DELTA
= 2,
4532 ENET_SUBCONTEXT_ESCAPE_DELTA
= 5
4535 /* context exclusion roughly halves compression speed, so disable for now (k8: and i removed it's code) */
4537 struct ENetRangeCoder
{
4538 /* only allocate enough symbols for reasonable MTUs, would need to be larger for large file compression */
4539 ENetSymbol
[4096] symbols
;
4543 public extern(C
) void *enet_range_coder_create () nothrow @trusted {
4544 return enet_malloc(ENetRangeCoder
.sizeof
);
4548 public extern(C
) void enet_range_coder_destroy (void* context
) nothrow @trusted {
4549 if (context
!is null) enet_free(context
);
4552 enum ENET_SYMBOL_CREATE(string symbol
, string value_
, string count_
) = q
{{
4553 ${symbol
} = &rangeCoder
.symbols
.ptr
[nextSymbol
++];
4554 ${symbol
}.value
= ${value_
};
4555 ${symbol
}.count
= ${count_
};
4556 ${symbol
}.under
= ${count_
};
4558 ${symbol
}.right
= 0;
4559 ${symbol
}.symbols
= 0;
4560 ${symbol
}.escapes
= 0;
4561 ${symbol
}.total
= 0;
4562 ${symbol
}.parent
= 0;
4563 }}.cmacroFixVars
!("symbol", "value_", "count_")(symbol
, value_
, count_
);
4565 enum ENET_CONTEXT_CREATE(string context
, string escapes_
, string minimum
) = q
{{
4566 mixin(ENET_SYMBOL_CREATE
!("${context}", "0", "0"));
4567 (${context
}).escapes
= ${escapes_
};
4568 (${context
}).total
= ${escapes_
}+256*${minimum
};
4569 (${context
}).symbols
= 0;
4570 }}.cmacroFixVars
!("context", "escapes_", "minimum")(context
, escapes_
, minimum
);
4573 enet_uint16
enet_symbol_rescale (ENetSymbol
* symbol
) nothrow @trusted @nogc {
4574 enet_uint16 total
= 0;
4576 symbol
.count
-= symbol
.count
>>1;
4577 symbol
.under
= symbol
.count
;
4578 if (symbol
.left
) symbol
.under
+= enet_symbol_rescale(symbol
+symbol
.left
);
4579 total
+= symbol
.under
;
4580 if (!symbol
.right
) break;
4581 symbol
+= symbol
.right
;
4586 enum ENET_CONTEXT_RESCALE(string context
, string minimum
) = q
{{
4587 (${context
}).total
= (${context
}).symbols ?
enet_symbol_rescale((${context
})+(${context
}).symbols
) : 0;
4588 (${context
}).escapes
-= (${context
}).escapes
>>1;
4589 (${context
}).total
+= (${context
}).escapes
+256*${minimum
};
4590 }}.cmacroFixVars
!("context", "minimum")(context
, minimum
);
4592 enum ENET_RANGE_CODER_OUTPUT(string value
) = q
{{
4593 if (outData
>= outEnd
) return 0;
4594 *outData
++ = ${value
};
4595 }}.cmacroFixVars
!("value")(value
);
4597 enum ENET_RANGE_CODER_ENCODE(string under
, string count
, string total
) = q
{{
4598 encodeRange
/= (${total
});
4599 encodeLow
+= (${under
})*encodeRange
;
4600 encodeRange
*= (${count
});
4602 if ((encodeLow^
(encodeLow
+encodeRange
)) >= ENET_RANGE_CODER_TOP
) {
4603 if (encodeRange
>= ENET_RANGE_CODER_BOTTOM
) break;
4604 encodeRange
= -encodeLow
&(ENET_RANGE_CODER_BOTTOM
-1);
4606 mixin(ENET_RANGE_CODER_OUTPUT
!"encodeLow>>24");
4610 }}.cmacroFixVars
!("under", "count", "total")(under
, count
, total
);
4612 enum ENET_RANGE_CODER_FLUSH
= q
{{
4614 mixin(ENET_RANGE_CODER_OUTPUT
!"encodeLow>>24");
4619 enum ENET_RANGE_CODER_FREE_SYMBOLS
= q
{{
4620 if (nextSymbol
>= rangeCoder
.symbols
.sizeof
/ENetSymbol
.sizeof
-ENET_SUBCONTEXT_ORDER
) {
4622 mixin(ENET_CONTEXT_CREATE
!("root", "ENET_CONTEXT_ESCAPE_MINIMUM", "ENET_CONTEXT_SYMBOL_MINIMUM"));
4628 enum ENET_CONTEXT_ENCODE(string context
, string symbol_
, string value_
, string under_
, string count_
, string update
, string minimum
) = q
{{
4629 ${under_
} = value
*${minimum
};
4630 ${count_
} = ${minimum
};
4631 if (!(${context
}).symbols
) {
4632 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4633 (${context
}).symbols
= cast(typeof((${context
}).symbols
))(${symbol_
}-(${context
}));
4635 ENetSymbol
* node
= (${context
})+(${context
}).symbols
;
4637 if (${value_
} < node
.value
) {
4638 node
.under
+= ${update
};
4639 if (node
.left
) { node
+= node
.left
; continue; }
4640 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4641 node
.left
= cast(typeof(node
.left
))(${symbol_
}-node
);
4642 } else if (${value_
} > node
.value
) {
4643 ${under_
} += node
.under
;
4644 if (node
.right
) { node
+= node
.right
; continue; }
4645 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4646 node
.right
= cast(typeof(node
.right
))(${symbol_
}-node
);
4648 ${count_
} += node
.count
;
4649 ${under_
} += node
.under
-node
.count
;
4650 node
.under
+= ${update
};
4651 node
.count
+= ${update
};
4657 }}.cmacroFixVars
!("context","symbol_","value_","under_","count_","update","minimum")(context
,symbol_
,value_
,under_
,count_
,update
,minimum
);
4660 public extern(C
) usize
enet_range_coder_compress (void* context
, const(ENetBuffer
)* inBuffers
, usize inBufferCount
, usize inLimit
, ubyte* outData
, usize outLimit
) nothrow @trusted @nogc {
4661 ENetRangeCoder
* rangeCoder
= cast(ENetRangeCoder
*)context
;
4662 ubyte* outStart
= outData
, outEnd
= &outData
[outLimit
];
4663 const(ubyte)* inData
, inEnd
;
4664 enet_uint32 encodeLow
= 0, encodeRange
= ~0;
4666 ushort predicted
= 0;
4667 usize order
= 0, nextSymbol
= 0;
4669 if (rangeCoder
is null || inBufferCount
<= 0 || inLimit
<= 0) return 0;
4671 inData
= cast(const(ubyte)*)inBuffers
.data
;
4672 inEnd
= &inData
[inBuffers
.dataLength
];
4676 mixin(ENET_CONTEXT_CREATE
!("root", "ENET_CONTEXT_ESCAPE_MINIMUM", "ENET_CONTEXT_SYMBOL_MINIMUM"));
4679 ENetSymbol
* subcontext
, symbol
;
4681 ushort count
, under
, total
;
4682 ushort *parent
= &predicted
;
4683 if (inData
>= inEnd
) {
4684 if (inBufferCount
<= 0) break;
4685 inData
= cast(const(ubyte)*)inBuffers
.data
;
4686 inEnd
= &inData
[inBuffers
.dataLength
];
4692 for (subcontext
= &rangeCoder
.symbols
.ptr
[predicted
]; subcontext
!= root
; subcontext
= &rangeCoder
.symbols
.ptr
[subcontext
.parent
]) {
4693 mixin(ENET_CONTEXT_ENCODE
!("subcontext", "symbol", "value", "under", "count", "ENET_SUBCONTEXT_SYMBOL_DELTA", "0"));
4694 *parent
= cast(ushort)(symbol
-rangeCoder
.symbols
.ptr
);
4695 parent
= &symbol
.parent
;
4696 total
= subcontext
.total
;
4698 mixin(ENET_RANGE_CODER_ENCODE
!("subcontext.escapes+under", "count", "total"));
4700 if (subcontext
.escapes
> 0 && subcontext
.escapes
< total
) { mixin(ENET_RANGE_CODER_ENCODE
!("0", "subcontext.escapes", "total")); }
4701 subcontext
.escapes
+= ENET_SUBCONTEXT_ESCAPE_DELTA
;
4702 subcontext
.total
+= ENET_SUBCONTEXT_ESCAPE_DELTA
;
4704 subcontext
.total
+= ENET_SUBCONTEXT_SYMBOL_DELTA
;
4705 if (count
> 0xFF-2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext
.total
> ENET_RANGE_CODER_BOTTOM
-0x100) { mixin(ENET_CONTEXT_RESCALE
!("subcontext", "0")); }
4706 if (count
> 0) goto nextInput
;
4709 mixin(ENET_CONTEXT_ENCODE
!("root", "symbol", "value", "under", "count", "ENET_CONTEXT_SYMBOL_DELTA", "ENET_CONTEXT_SYMBOL_MINIMUM"));
4710 *parent
= cast(ushort)(symbol
-rangeCoder
.symbols
.ptr
);
4711 parent
= &symbol
.parent
;
4713 mixin(ENET_RANGE_CODER_ENCODE
!("root.escapes+under", "count", "total"));
4714 root
.total
+= ENET_CONTEXT_SYMBOL_DELTA
;
4715 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")); }
4718 if (order
>= ENET_SUBCONTEXT_ORDER
) {
4719 predicted
= rangeCoder
.symbols
.ptr
[predicted
].parent
;
4723 mixin(ENET_RANGE_CODER_FREE_SYMBOLS
);
4726 mixin(ENET_RANGE_CODER_FLUSH
);
4728 return cast(usize
)(outData
-outStart
);
4731 enum ENET_RANGE_CODER_SEED
= q
{{
4732 if (inData
< inEnd
) decodeCode |
= *inData
++<<24;
4733 if (inData
< inEnd
) decodeCode |
= *inData
++<<16;
4734 if (inData
< inEnd
) decodeCode |
= *inData
++<<8;
4735 if (inData
< inEnd
) decodeCode |
= *inData
++;
4738 enum ENET_RANGE_CODER_READ(string total
) = q
{((decodeCode
-decodeLow
)/(decodeRange
/= (${total
})))}.cmacroFixVars
!"total"(total
);
4740 enum ENET_RANGE_CODER_DECODE(string under
, string count
, string total
) = q
{{
4741 decodeLow
+= (${under
})*decodeRange
;
4742 decodeRange
*= (${count
});
4744 if ((decodeLow^
(decodeLow
+decodeRange
)) >= ENET_RANGE_CODER_TOP
) {
4745 if (decodeRange
>= ENET_RANGE_CODER_BOTTOM
) break;
4746 decodeRange
= -decodeLow
&(ENET_RANGE_CODER_BOTTOM
-1);
4749 if (inData
< inEnd
) decodeCode |
= *inData
++;
4753 }}.cmacroFixVars
!("under", "count", "total")(under
, count
, total
);
4755 enum ENET_CONTEXT_DECODE(string context
, string symbol_
, string code
, string value_
, string under_
, string count_
, string update
, string minimum
, string createRoot
,
4756 string visitNode
, string createRight
, string createLeft
) =
4759 ${count_
} = ${minimum
};
4760 if (!(${context
}).symbols
) {
4763 ENetSymbol
* node
= (${context
})+(${context
}).symbols
;
4765 ushort after
= cast(ushort)(${under_
}+node
.under
+(node
.value
+1)*${minimum
}), before
= cast(ushort)(node
.count
+${minimum
});
4767 if (${code
} >= after
) {
4768 ${under_
} += node
.under
;
4769 if (node
.right
) { node
+= node
.right
; continue; }
4771 } else if (${code
} < after
-before
) {
4772 node
.under
+= ${update
};
4773 if (node
.left
) { node
+= node
.left
; continue; }
4776 ${value_
} = node
.value
;
4777 ${count_
} += node
.count
;
4778 ${under_
} = cast(typeof(${under_
}))(after
-before
);
4779 node
.under
+= ${update
};
4780 node
.count
+= ${update
};
4786 }}.cmacroFixVars
!("context","symbol_","code","value_","under_","count_","update","minimum","createRoot","visitNode","createRight","createLeft")
4787 (context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
, createRoot
, visitNode
, createRight
, createLeft
);
4789 enum ENET_CONTEXT_TRY_DECODE(string context
, string symbol_
, string code
, string value_
, string under_
, string count_
, string update
, string minimum
, string exclude
) =
4790 ENET_CONTEXT_DECODE
!(context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
, "return 0", exclude
~"(`node.value`, `after`, `before`)", "return 0", "return 0");
4792 enum ENET_CONTEXT_ROOT_DECODE(string context
, string symbol_
, string code
, string value_
, string under_
, string count_
, string update
, string minimum
, string exclude
) =
4793 ENET_CONTEXT_DECODE
!(context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
,
4795 ${value_
} = cast(typeof(${value_
}))(${code
}/${minimum
});
4796 ${under_
} = cast(typeof(${under_
}))(${code
}-${code
}%${minimum
});
4797 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4798 (${context
}).symbols
= cast(typeof((${context
}).symbols
))(${symbol_
}-(${context
}));
4799 }}.cmacroFixVars
!("context","symbol_","code","value_","under_","count_","update","minimum","exclude")(context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
, exclude
),
4800 exclude
~"(`node.value`, `after`, `before`)",
4802 ${value_
} = cast(typeof(${value_
}))(node
.value
+1+(${code
}-after
)/${minimum
});
4803 ${under_
} = cast(typeof(${under_
}))(${code
}-(${code
}-after
)%${minimum
});
4804 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4805 node
.right
= cast(typeof(node
.right
))(${symbol_
}-node
);
4806 }}.cmacroFixVars
!("context","symbol_","code","value_","under_","count_","update","minimum","exclude")(context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
, exclude
),
4808 ${value_
} = cast(typeof(${value_
}))(node
.value
-1-(after
-before
-${code
}-1)/${minimum
});
4809 ${under_
} = cast(typeof(${under_
}))(${code
}-(after
-before
-${code
}-1)%${minimum
});
4810 mixin(ENET_SYMBOL_CREATE
!("${symbol_}", "${value_}", "${update}"));
4811 node
.left
= cast(typeof(node
.left
))(${symbol_
}-node
);
4812 }}.cmacroFixVars
!("context","symbol_","code","value_","under_","count_","update","minimum","exclude")(context
, symbol_
, code
, value_
, under_
, count_
, update
, minimum
, exclude
));
4815 enum ENET_CONTEXT_NOT_EXCLUDED(string value_
, string after
, string before
) = "{}";
4818 public extern(C
) usize
enet_range_coder_decompress (void* context
, const(ubyte)* inData
, usize inLimit
, ubyte* outData
, usize outLimit
) nothrow @trusted @nogc {
4819 ENetRangeCoder
* rangeCoder
= cast(ENetRangeCoder
*)context
;
4820 ubyte* outStart
= outData
, outEnd
= &outData
[outLimit
];
4821 const(ubyte)* inEnd
= &inData
[inLimit
];
4822 enet_uint32 decodeLow
= 0, decodeCode
= 0, decodeRange
= ~0;
4824 ushort predicted
= 0;
4825 usize order
= 0, nextSymbol
= 0;
4827 if (rangeCoder
is null || inLimit
<= 0) return 0;
4829 mixin(ENET_CONTEXT_CREATE
!("root", "ENET_CONTEXT_ESCAPE_MINIMUM", "ENET_CONTEXT_SYMBOL_MINIMUM"));
4831 mixin(ENET_RANGE_CODER_SEED
);
4834 ENetSymbol
* subcontext
, symbol
, patch
;
4836 ushort code
, under
, count
, bottom
, total
;
4837 ushort* parent
= &predicted
;
4839 for (subcontext
= &rangeCoder
.symbols
.ptr
[predicted
]; subcontext
!= root
; subcontext
= &rangeCoder
.symbols
.ptr
[subcontext
.parent
]) {
4840 if (subcontext
.escapes
<= 0) continue;
4841 total
= subcontext
.total
;
4842 if (subcontext
.escapes
>= total
) continue;
4843 code
= cast(ushort)(mixin(ENET_RANGE_CODER_READ
!"total"));
4844 if (code
< subcontext
.escapes
) {
4845 mixin(ENET_RANGE_CODER_DECODE
!("0", "subcontext.escapes", "total"));
4848 code
-= subcontext
.escapes
;
4850 mixin(ENET_CONTEXT_TRY_DECODE
!("subcontext", "symbol", "code", "value", "under", "count", "ENET_SUBCONTEXT_SYMBOL_DELTA", "0", "ENET_CONTEXT_NOT_EXCLUDED!"));
4852 bottom
= cast(ushort)(symbol
-rangeCoder
.symbols
.ptr
);
4853 mixin(ENET_RANGE_CODER_DECODE
!("subcontext.escapes+under", "count", "total"));
4854 subcontext
.total
+= ENET_SUBCONTEXT_SYMBOL_DELTA
;
4855 if (count
> 0xFF-2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext
.total
> ENET_RANGE_CODER_BOTTOM
-0x100) { mixin(ENET_CONTEXT_RESCALE
!("subcontext", "0")); }
4860 code
= cast(ushort)(mixin(ENET_RANGE_CODER_READ
!"total"));
4861 if (code
< root
.escapes
) {
4862 mixin(ENET_RANGE_CODER_DECODE
!("0", "root.escapes", "total"));
4865 code
-= root
.escapes
;
4867 mixin(ENET_CONTEXT_ROOT_DECODE
!("root", "symbol", "code", "value", "under", "count", "ENET_CONTEXT_SYMBOL_DELTA", "ENET_CONTEXT_SYMBOL_MINIMUM", "ENET_CONTEXT_NOT_EXCLUDED!"));
4869 bottom
= cast(ushort)(symbol
-rangeCoder
.symbols
.ptr
);
4870 mixin(ENET_RANGE_CODER_DECODE
!("root.escapes+under", "count", "total"));
4871 root
.total
+= ENET_CONTEXT_SYMBOL_DELTA
;
4872 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")); }
4875 for (patch
= &rangeCoder
.symbols
.ptr
[predicted
]; patch
!= subcontext
; patch
= &rangeCoder
.symbols
.ptr
[patch
.parent
]) {
4876 mixin(ENET_CONTEXT_ENCODE
!("patch", "symbol", "value", "under", "count", "ENET_SUBCONTEXT_SYMBOL_DELTA", "0"));
4877 *parent
= cast(ushort)(symbol
-rangeCoder
.symbols
.ptr
);
4878 parent
= &symbol
.parent
;
4880 patch
.escapes
+= ENET_SUBCONTEXT_ESCAPE_DELTA
;
4881 patch
.total
+= ENET_SUBCONTEXT_ESCAPE_DELTA
;
4883 patch
.total
+= ENET_SUBCONTEXT_SYMBOL_DELTA
;
4884 if (count
> 0xFF-2*ENET_SUBCONTEXT_SYMBOL_DELTA || patch
.total
> ENET_RANGE_CODER_BOTTOM
-0x100) { mixin(ENET_CONTEXT_RESCALE
!("patch", "0")); }
4888 mixin(ENET_RANGE_CODER_OUTPUT
!"value");
4890 if (order
>= ENET_SUBCONTEXT_ORDER
) {
4891 predicted
= rangeCoder
.symbols
.ptr
[predicted
].parent
;
4895 mixin(ENET_RANGE_CODER_FREE_SYMBOLS
);
4898 return cast(usize
)(outData
-outStart
);
4901 /** @defgroup host ENet host functions
4905 /** Sets the packet compressor the host should use to the default range coder.
4906 @param host host to enable the range coder for
4907 @returns 0 on success, < 0 on failure
4909 public int enet_host_compress_with_range_coder (ENetHost
* host
) nothrow {
4910 import core
.stdc
.string
: memset
;
4912 ENetCompressor compressor
= void;
4913 memset(&compressor
, 0, compressor
.sizeof
);
4914 compressor
.context
= enet_range_coder_create();
4915 if (compressor
.context
is null) return -1;
4916 compressor
.compress
= &enet_range_coder_compress
;
4917 compressor
.decompress
= &enet_range_coder_decompress
;
4918 compressor
.destroy
= &enet_range_coder_destroy
;
4919 enet_host_compress(host
, &compressor
);