cosmetix
[iv.d.git] / enet.d
blob50ab4b123fa3d35c850baa76d05c59d4cb5db925
1 /*
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*/;
43 import iv.alice;
46 version(BigEndian) {
47 ushort ENET_HOST_TO_NET_16 (ushort x) @safe pure @nogc nothrow {
48 pragma(inline, true);
49 return x;
52 uint ENET_HOST_TO_NET_32 (uint x) @safe pure @nogc nothrow {
53 pragma(inline, true);
54 return x;
56 } else version(LittleEndian) {
57 ushort ENET_HOST_TO_NET_16 (ushort x) @safe pure @nogc nothrow {
58 pragma(inline, true);
59 return ((x&255)<<8)|(x>>8);
62 uint ENET_HOST_TO_NET_32 (uint x) @safe pure @nogc nothrow {
63 pragma(inline, true);
64 import core.bitop : bswap;
65 return bswap(x);
67 } else {
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;
76 version(Windows) {
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;
85 struct ENetBuffer {
86 usize dataLength;
87 void* data;
91 version(X86_64) {
92 alias SOCKET = ulong;
93 } else {
94 alias SOCKET = uint;
97 alias ENetSocket = SOCKET;
99 enum ENET_SOCKET_NULL = ~0;
101 align(1) struct ENetBuffer {
102 align(1):
103 //usize dataLength;
104 //void *data;
105 void* data;
106 usize dataLength;
109 enum FD_SETSIZE = 64;
111 struct fd_set {
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;
126 ++sockset.fd_count;
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;
132 return false;
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];
140 ++i;
142 --sockset.fd_count;
143 return;
148 } else {
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 {
157 align(1):
158 void* data;
159 usize dataLength;
164 // types.h
165 alias enet_uint8 = ubyte;
166 alias enet_uint16 = ushort;
167 alias enet_uint32 = uint;
170 // protocol.h
171 enum {
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 {
223 align(1):
224 enet_uint16 peerID;
225 enet_uint16 sentTime;
228 align(1) struct ENetProtocolCommandHeader {
229 align(1):
230 enet_uint8 command;
231 enet_uint8 channelID;
232 enet_uint16 reliableSequenceNumber;
235 align(1) struct ENetProtocolAcknowledge {
236 align(1):
237 ENetProtocolCommandHeader header;
238 enet_uint16 receivedReliableSequenceNumber;
239 enet_uint16 receivedSentTime;
242 align(1) struct ENetProtocolConnect {
243 align(1):
244 ENetProtocolCommandHeader header;
245 enet_uint16 outgoingPeerID;
246 enet_uint8 incomingSessionID;
247 enet_uint8 outgoingSessionID;
248 enet_uint32 mtu;
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;
257 enet_uint32 data;
260 align(1) struct ENetProtocolVerifyConnect {
261 align(1):
262 ENetProtocolCommandHeader header;
263 enet_uint16 outgoingPeerID;
264 enet_uint8 incomingSessionID;
265 enet_uint8 outgoingSessionID;
266 enet_uint32 mtu;
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 {
278 align(1):
279 ENetProtocolCommandHeader header;
280 enet_uint32 incomingBandwidth;
281 enet_uint32 outgoingBandwidth;
284 align(1) struct ENetProtocolThrottleConfigure {
285 align(1):
286 ENetProtocolCommandHeader header;
287 enet_uint32 packetThrottleInterval;
288 enet_uint32 packetThrottleAcceleration;
289 enet_uint32 packetThrottleDeceleration;
292 align(1) struct ENetProtocolDisconnect {
293 align(1):
294 ENetProtocolCommandHeader header;
295 enet_uint32 data;
298 align(1) struct ENetProtocolPing {
299 align(1):
300 ENetProtocolCommandHeader header;
303 align(1) struct ENetProtocolSendReliable {
304 align(1):
305 ENetProtocolCommandHeader header;
306 enet_uint16 dataLength;
309 align(1) struct ENetProtocolSendUnreliable {
310 align(1):
311 ENetProtocolCommandHeader header;
312 enet_uint16 unreliableSequenceNumber;
313 enet_uint16 dataLength;
316 align(1) struct ENetProtocolSendUnsequenced {
317 align(1):
318 ENetProtocolCommandHeader header;
319 enet_uint16 unsequencedGroup;
320 enet_uint16 dataLength;
323 align(1) struct ENetProtocolSendFragment {
324 align(1):
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 {
335 align(1):
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;
351 // list.h
352 struct ENetListNode {
353 ENetListNode* next;
354 ENetListNode* previous;
357 struct ENetList {
358 ENetListNode sentinel;
362 // callbacks.h
363 struct ENetCallbacks {
364 extern(C) nothrow:
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;
374 // enet.h
375 enum {
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,
439 enum {
440 ENET_HOST_ANY = 0,
441 ENET_HOST_BROADCAST = 0xFFFFFFFFU,
442 ENET_PORT_ANY = 0,
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.
456 struct ENetAddress {
457 enet_uint32 host;
458 enet_uint16 port;
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
511 struct ENetPacket {
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;
537 ENetPacket* packet;
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;
548 ENetPacket* packet;
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;
567 enum : int {
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,
597 struct ENetChannel {
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.
613 struct ENetPeer {
614 ENetListNode dispatchList;
615 ENetHost* host;
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 */
623 ENetPeerState state;
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;
658 enet_uint32 mtu;
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;
668 bool needsDispatch;
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. */
680 void* context;
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()
714 struct ENetHost {
715 ENetSocket socket;
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;
720 enet_uint32 mtu;
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;
728 int continueSending;
729 usize packetSize;
730 enet_uint16 headerFlags;
731 ENetProtocol[ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS] commands;
732 usize commandCount;
733 ENetBuffer[ENET_BUFFER_MAXIMUM] buffers;
734 usize bufferCount;
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().
787 struct ENetEvent {
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 () {
809 WSADATA wsaData;
810 if (WSAStartup(0x0101, &wsaData)) return;
811 if ((wsaData.wVersion&0xffff) != 0x0101) {
812 WSACleanup ();
813 return;
815 timeBeginPeriod(1);
816 shitdozeinited = true;
819 shared static ~this () {
820 if (shitdozeinited) {
821 timeEndPeriod(1);
822 WSACleanup();
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) {
847 auto anchor = name;
848 enet_uint8[4] vals = 0;
849 foreach (immutable i, ref ubyte v; vals[]) {
850 int val = 0;
851 while (name.length) {
852 char ch = name.ptr[0];
853 name = name[1..$];
854 if (ch < '0' || ch > '9') return -1;
855 val = val*10+ch-'0';
856 if (val > 255) return -1;
858 v = cast(ubyte)val;
859 if (name.length) {
860 if (name.ptr[0] != '.') return -1;
861 name = name[1..$];
865 import core.stdc.string : memcpy;
866 memcpy(&address.host, vals.ptr, enet_uint32.sizeof);
867 return 0;
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];
876 return 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);
886 return 0;
889 int enet_address_get_host (const ENetAddress* address, char* name, usize nameLength) {
890 in_addr in_;
891 hostent* hostEntry;
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);
898 } else {
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);
905 return 0;
908 int enet_socket_bind (ENetSocket socket, const ENetAddress* address) {
909 import core.stdc.string : memset;
911 sockaddr_in sin;
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;
917 } else {
918 sin.sin_port = 0;
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) {
926 sockaddr_in sin;
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);
934 return 0;
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;
947 switch (option) {
948 case ENET_SOCKOPT_NONBLOCK:
949 uint nonBlocking = cast(uint)value;
950 result = ioctlsocket(socket, FIONBIO, &nonBlocking);
951 break;
952 case ENET_SOCKOPT_BROADCAST:
953 result = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, cast(void*)&value, int.sizeof);
954 break;
955 case ENET_SOCKOPT_REUSEADDR:
956 result = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, cast(void*)&value, int.sizeof);
957 break;
958 case ENET_SOCKOPT_RCVBUF:
959 result = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, cast(void*)&value, int.sizeof);
960 break;
961 case ENET_SOCKOPT_SNDBUF:
962 result = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, cast(void*)&value, int.sizeof);
963 break;
964 case ENET_SOCKOPT_RCVTIMEO:
965 result = setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, cast(void*)&value, int.sizeof);
966 break;
967 case ENET_SOCKOPT_SNDTIMEO:
968 result = setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, cast(void*)&value, int.sizeof);
969 break;
970 case ENET_SOCKOPT_NODELAY:
971 result = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, cast(void*)&value, int.sizeof);
972 break;
973 default:
974 break;
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;
981 switch (option) {
982 case ENET_SOCKOPT_ERROR:
983 len = int.sizeof;
984 result = getsockopt(socket, SOL_SOCKET, SO_ERROR, cast(void*)value, &len);
985 break;
986 default:
987 break;
989 return (result == SOCKET_ERROR ? -1 : 0);
992 int enet_socket_connect (ENetSocket socket, const ENetAddress* address) {
993 import core.stdc.string : memset;
994 sockaddr_in sin;
995 int result;
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;
1006 return 0;
1009 ENetSocket enet_socket_accept (ENetSocket socket, ENetAddress* address) {
1010 SOCKET result;
1011 sockaddr_in sin;
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);
1023 return result;
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 (
1035 SOCKET s,
1036 const ENetBuffer* lpBuffers,
1037 DWORD dwBufferCount,
1038 LPDWORD lpNumberOfBytesSent,
1039 DWORD dwFlags,
1040 const sockaddr* lpTo,
1041 int iToLen,
1042 /*LPWSAOVERLAPPED*/void* lpOverlapped=null,
1043 /*LPWSAOVERLAPPED_COMPLETION_ROUTINE*/void* lpCompletionRoutine=null
1046 private extern(Windows) nothrow @nogc int WSARecvFrom (
1047 SOCKET s,
1048 ENetBuffer* lpBuffers,
1049 DWORD dwBufferCount,
1050 LPDWORD lpNumberOfBytesRecvd,
1051 LPDWORD lpFlags,
1052 sockaddr* lpFrom,
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;
1061 sockaddr_in sin;
1062 DWORD sentLength;
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;
1073 return -1;
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;
1083 sockaddr_in sin;
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:
1088 case WSAECONNRESET:
1089 return 0;
1090 default:
1092 return -1;
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) {
1106 timeval timeVal;
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;
1114 timeval timeVal;
1115 int selectCount;
1117 timeVal.tv_sec = timeout / 1000;
1118 timeVal.tv_usec = (timeout % 1000) * 1000;
1120 FD_ZERO(&readSet);
1121 FD_ZERO(&writeSet);
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;
1136 return 0;
1138 } else extern(C) nothrow @nogc {
1139 // unix.c
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 () {
1164 return 0;
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);
1217 return 0;
1221 if (resultList !is null) freeaddrinfo(resultList);
1223 if (!inet_pton(AF_INET, name, &address.host)) return -1;
1225 return 0;
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
1234 return 0;
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;
1245 int err;
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
1252 if (!err) {
1253 if (name !is null && nameLength > 0 && !memchr(name, 0, nameLength)) return -1;
1254 return 0;
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;
1272 } else {
1273 sin.sin_port = 0;
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);
1289 return 0;
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;
1314 int result = -1;
1315 switch (option) {
1316 case ENET_SOCKOPT_NONBLOCK:
1317 result = fcntl(socket, F_SETFL, (value ? O_NONBLOCK : 0)|(fcntl(socket, F_GETFL)&~O_NONBLOCK));
1318 break;
1319 case ENET_SOCKOPT_BROADCAST:
1320 result = setsockopt(socket, SOL_SOCKET, SO_BROADCAST, cast(void*)&value, int.sizeof);
1321 break;
1322 case ENET_SOCKOPT_REUSEADDR:
1323 result = setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, cast(void*)&value, int.sizeof);
1324 break;
1325 case ENET_SOCKOPT_RCVBUF:
1326 result = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, cast(void*)&value, int.sizeof);
1327 break;
1328 case ENET_SOCKOPT_SNDBUF:
1329 result = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, cast(void*)&value, int.sizeof);
1330 break;
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);
1335 break;
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);
1340 break;
1341 case ENET_SOCKOPT_NODELAY:
1342 result = setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, cast(void*)&value, int.sizeof);
1343 break;
1344 default:
1345 break;
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;
1353 socklen_t len;
1354 int result = -1;
1355 switch (option) {
1356 case ENET_SOCKOPT_ERROR:
1357 len = int.sizeof;
1358 result = getsockopt(socket, SOL_SOCKET, SO_ERROR, value, &len);
1359 break;
1360 default:
1361 break;
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;
1372 int result;
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);
1381 if (result == -1) {
1382 import core.stdc.errno : errno, EINPROGRESS;
1383 if (errno == EINPROGRESS) return 0;
1386 return result;
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;
1394 int result;
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);
1406 return result;
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;
1430 int sentLength;
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;
1452 return -1;
1455 return sentLength;
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;
1466 sockaddr_in sin;
1467 int recvLength;
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;
1484 return -1;
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);
1494 return recvLength;
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;
1513 int pollCount;
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;
1527 return 0;
1529 return -1;
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;
1539 return 0;
1544 // callbacks.c
1545 extern(C) nothrow {
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();
1577 return memory;
1581 void enet_free (void* memory) nothrow {
1582 callbacks.free(memory);
1587 // list.c
1588 extern(C) @nogc nothrow {
1589 alias ENetListIterator = ENetListNode*;
1592 @safe pure {
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
1631 @ingroup private
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;
1648 return result;
1651 void* enet_list_remove (ENetListIterator position) {
1652 position.previous.next = position.next;
1653 position.next.previous = position.previous;
1654 return position;
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;
1670 return first;
1673 usize enet_list_size (ENetList* list) {
1674 usize size = 0;
1675 ENetListIterator position;
1676 for (position = enet_list_begin(list); position != enet_list_end(list); position = enet_list_next(position)) ++size;
1677 return size;
1682 // packet.c
1683 extern(C) nothrow {
1684 /** Creates a packet that may be sent to a peer.
1686 * Params:
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
1691 * Returns:
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) {
1701 packet.data = null;
1702 } else {
1703 packet.data = cast(enet_uint8*)enet_malloc(dataLength);
1704 if (packet.data is null) {
1705 enet_free(packet);
1706 return null;
1708 if (data !is null) {
1709 import core.stdc.string : memcpy;
1710 memcpy(packet.data, data, dataLength);
1714 //FIXME
1715 packet.referenceCount = 0;
1716 packet.flags = flags;
1717 packet.dataLength = dataLength;
1718 packet.freeCallback = null;
1719 packet.userData = null;
1721 return packet;
1725 /** Destroys the packet and deallocates its data.
1727 * Params:
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);
1734 enet_free(packet);
1738 /** Attempts to resize the data in the packet to length specified in the dataLength parameter.
1740 * Params:
1741 * packet = packet to resize
1742 * dataLength = new size for the packet data
1744 * Returns:
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;
1754 return 0;
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;
1766 return 0;
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);
1775 val >>= 1;
1777 return result;
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);
1788 return crcTable;
1789 }());
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++];
1798 ++buffers;
1800 return ENET_HOST_TO_NET_32(~crc);
1805 // peer.c
1806 extern(C) nothrow {
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.
1831 * Params:
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;
1861 return 1;
1862 } else if (rtt > peer.lastRoundTripTime+2*peer.lastRoundTripTimeVariance) {
1863 if (peer.packetThrottle > peer.packetThrottleDeceleration) {
1864 peer.packetThrottle -= peer.packetThrottleDeceleration;
1865 } else {
1866 peer.packetThrottle = 0;
1868 return -1;
1870 return 0;
1874 /** Queues a packet to be sent.
1876 * Params:
1877 * peer = destination for the packet
1878 * channelID = channel on which to send
1879 * packet = packet to send
1881 * Returns:
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;
1899 ENetList fragments;
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));
1907 } else {
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);
1923 return -1;
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);
1948 return 0;
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);
1959 } else {
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;
1966 return 0;
1970 /** Attempts to dequeue any incoming queued packet.
1972 * Params:
1973 * peer = peer to dequeue packets from
1974 * channelID = holds the channel ID of the channel the packet was received on success
1976 * Returns:
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;
1981 ENetPacket* packet;
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;
1992 return packet;
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.
2077 * Params:
2078 * peer = peer to forcefully disconnect
2080 * Remarks:
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;
2090 peer.connectID = 0;
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;
2132 peer.eventData = 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.
2143 * Params:
2144 * peer = destination for the ping request
2146 * Remarks:
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.
2170 * Params:
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.
2190 * Params:
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.
2205 * Params:
2206 * peer = peer to disconnect
2207 * data = data describing the disconnection
2209 * Remarks:
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.
2237 * Params:
2238 * peer = peer to request a disconnection
2239 * data = data describing the disconnection
2241 * Remarks:
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)
2252 return;
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;
2262 } else {
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;
2271 } else {
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.
2280 * Params:
2281 * peer = peer to request a disconnection
2282 * data = data describing the disconnection
2284 * Remarks:
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;
2296 } else {
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;
2347 } else {
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);
2362 break;
2363 case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
2364 outgoingCommand.command.sendUnsequenced.unsequencedGroup = ENET_HOST_TO_NET_16(peer.outgoingUnsequencedGroup);
2365 break;
2366 default:
2367 break;
2370 if (outgoingCommand.command.header.command&ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE) {
2371 enet_list_insert(enet_list_end(&peer.outgoingReliableCommands), outgoingCommand);
2372 } else {
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;
2407 continue;
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);
2419 } else {
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;
2519 break;
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;
2540 break;
2541 case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
2542 currentCommand = enet_list_end(&channel.incomingUnreliableCommands);
2543 break;
2544 default:
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);
2570 goto notifyError;
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);
2587 break;
2588 default:
2589 enet_peer_dispatch_incoming_unreliable_commands (peer, channel);
2590 break;
2593 return incomingCommand;
2595 discardCommand:
2596 if (fragmentCount > 0) goto notifyError;
2597 if (packet !is null && packet.referenceCount == 0) enet_packet_destroy(packet);
2598 return &dummyCommand;
2600 notifyError:
2601 if (packet !is null && packet.referenceCount == 0) enet_packet_destroy(packet);
2602 return null;
2607 // host.c
2608 extern(C) nothrow {
2609 /** Creates a host for communicating to peers.
2611 * Params:
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.
2618 * Returns:
2619 * the host on success and null on failure
2621 * Remarks:
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;
2630 ENetHost* host;
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) {
2641 enet_free(host);
2642 return 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);
2650 enet_free(host);
2651 return null;
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(&currentPeer.acknowledgements);
2709 enet_list_clear(&currentPeer.sentReliableCommands);
2710 enet_list_clear(&currentPeer.sentUnreliableCommands);
2711 enet_list_clear(&currentPeer.outgoingReliableCommands);
2712 enet_list_clear(&currentPeer.outgoingUnreliableCommands);
2713 enet_list_clear(&currentPeer.dispatchedCommands);
2715 enet_peer_reset(currentPeer);
2718 return host;
2722 /** Destroys the host and all resources associated with it.
2724 * Params:
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);
2741 enet_free(host);
2745 /** Initiates a connection to a foreign host.
2747 * Params:
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
2753 * Returns:
2754 * a peer representing the foreign host on success, null on failure
2756 * Remarks:
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;
2783 } else {
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 < &currentPeer.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);
2823 return currentPeer;
2827 /** Queues a packet to be sent to all peers associated with the host.
2829 * Params:
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.
2848 * Params:
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.
2860 * Params:
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.
2873 * Params:
2874 * host = host to adjust
2875 * incomingBandwidth = new incoming bandwidth
2876 * outgoingBandwidth = new outgoing bandwidth
2878 * Remarks:
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);
2898 ENetPeer* peer;
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) {
2908 dataTotal = 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)
2928 continue;
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;
2945 --peersRemaining;
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)
2957 continue;
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) {
2976 bandwidthLimit = 0;
2977 } else {
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)
2985 continue;
2987 if (peer.outgoingBandwidth > 0 && peer.outgoingBandwidth >= bandwidthLimit) continue;
2989 peer.incomingBandwidthThrottleEpoch = timeCurrent;
2991 needsAdjustment = 1;
2992 --peersRemaining;
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)
3000 continue;
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);
3008 } else {
3009 command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32(bandwidthLimit);
3012 enet_peer_queue_outgoing_command(peer, &command, null, 0, 0);
3019 // protocol.c
3020 extern(C) nothrow {
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);
3062 } else {
3063 enet_peer_on_disconnect(peer);
3065 peer.state = state;
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;
3087 event.peer = peer;
3088 event.data = peer.eventData;
3089 return 1;
3090 case ENET_PEER_STATE_ZOMBIE:
3091 host.recalculateBandwidthLimits = 1;
3092 event.type = ENET_EVENT_TYPE_DISCONNECT;
3093 event.peer = peer;
3094 event.data = peer.eventData;
3095 enet_peer_reset(peer);
3096 return 1;
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;
3102 event.peer = peer;
3103 if (!enet_list_empty(&peer.dispatchedCommands)) {
3104 peer.needsDispatch = true;
3105 enet_list_insert(enet_list_end(&host.dispatchQueue), &peer.dispatchList);
3107 return 1;
3108 default:
3109 break;
3112 return 0;
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;
3121 event.peer = peer;
3122 event.data = peer.eventData;
3123 } else {
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;
3135 event.peer = peer;
3136 event.data = 0;
3137 enet_peer_reset(peer);
3138 } else {
3139 peer.eventData = 0;
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;
3166 int wasSent = 1;
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;
3186 wasSent = 0;
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;
3242 ++duplicatePeers;
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;
3294 peer.mtu = 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;
3300 } else {
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);
3331 return peer;
3335 private int enet_protocol_handle_send_reliable (ENetHost* host, ENetPeer* peer, const ENetProtocol* command, enet_uint8** currentData) {
3336 usize dataLength;
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;
3342 return 0;
3346 private int enet_protocol_handle_send_unsequenced (ENetHost* host, ENetPeer* peer, const ENetProtocol* command, enet_uint8** currentData) {
3347 enet_uint32 unsequencedGroup, index;
3348 usize dataLength;
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))) {
3370 return 0;
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);
3377 return 0;
3381 private int enet_protocol_handle_send_unreliable (ENetHost* host, ENetPeer* peer, const ENetProtocol* command, enet_uint8** currentData) {
3382 usize dataLength;
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;
3392 return 0;
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)
3428 return -1;
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)
3443 return -1;
3444 startCommand = incomingCommand;
3445 break;
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);
3465 return 0;
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)
3505 return -1;
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)
3522 return -1;
3523 startCommand = incomingCommand;
3524 break;
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);
3542 return 0;
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;
3548 return 0;
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;
3566 } else {
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;
3573 return 0;
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);
3584 return 0;
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);
3600 } else {
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);
3606 return 0;
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;
3634 } else {
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);
3659 break;
3660 case ENET_PEER_STATE_DISCONNECTING:
3661 if (commandNumber != ENET_PROTOCOL_COMMAND_DISCONNECT) return -1;
3662 enet_protocol_notify_disconnect (host, peer, event);
3663 break;
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);
3668 break;
3669 default:
3670 break;
3673 return 0;
3677 private int enet_protocol_handle_verify_connect (ENetHost* host, ENetEvent* event, ENetPeer* peer, const ENetProtocol* command) {
3678 enet_uint32 mtu, windowSize;
3679 usize channelCount;
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)
3691 peer.eventData = 0;
3692 enet_protocol_dispatch_state(host, peer, ENET_PEER_STATE_ZOMBIE);
3693 return -1;
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);
3722 return 0;
3726 private int enet_protocol_handle_incoming_commands (ENetHost* host, ENetEvent* event) {
3727 ENetProtocolHeader* header;
3728 ENetProtocol* command;
3729 ENetPeer* peer;
3730 enet_uint8* currentData;
3731 usize headerSize;
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) {
3748 peer = null;
3749 } else if (peerID >= host.peerCount) {
3750 return 0;
3751 } else {
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))
3758 return 0;
3761 if (flags&ENET_PROTOCOL_HEADER_FLAG_COMPRESSED) {
3762 usize originalSize;
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;
3781 ENetBuffer buffer;
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;
3801 usize commandSize;
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;
3822 break;
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;
3827 break;
3828 case ENET_PROTOCOL_COMMAND_VERIFY_CONNECT:
3829 if (enet_protocol_handle_verify_connect(host, event, peer, command)) goto commandError;
3830 break;
3831 case ENET_PROTOCOL_COMMAND_DISCONNECT:
3832 if (enet_protocol_handle_disconnect(host, peer, command)) goto commandError;
3833 break;
3834 case ENET_PROTOCOL_COMMAND_PING:
3835 if (enet_protocol_handle_ping(host, peer, command)) goto commandError;
3836 break;
3837 case ENET_PROTOCOL_COMMAND_SEND_RELIABLE:
3838 if (enet_protocol_handle_send_reliable(host, peer, command, &currentData)) goto commandError;
3839 break;
3840 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:
3841 if (enet_protocol_handle_send_unreliable(host, peer, command, &currentData)) goto commandError;
3842 break;
3843 case ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:
3844 if (enet_protocol_handle_send_unsequenced(host, peer, command, &currentData)) goto commandError;
3845 break;
3846 case ENET_PROTOCOL_COMMAND_SEND_FRAGMENT:
3847 if (enet_protocol_handle_send_fragment(host, peer, command, &currentData)) goto commandError;
3848 break;
3849 case ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT:
3850 if (enet_protocol_handle_bandwidth_limit(host, peer, command)) goto commandError;
3851 break;
3852 case ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE:
3853 if (enet_protocol_handle_throttle_configure(host, peer, command)) goto commandError;
3854 break;
3855 case ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT:
3856 if (enet_protocol_handle_send_unreliable_fragment(host, peer, command, &currentData)) goto commandError;
3857 break;
3858 default:
3859 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:
3872 break;
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);
3877 break;
3878 default:
3879 enet_peer_queue_acknowledgement(peer, command, sentTime);
3880 break;
3885 commandError:
3886 if (event !is null && event.type != ENET_EVENT_TYPE_NONE) return 1;
3887 return 0;
3891 private int enet_protocol_receive_incoming_commands (ENetHost* host, ENetEvent* event) {
3892 for (int packets = 0; packets < 256; ++packets) {
3893 int receivedLength;
3894 ENetBuffer buffer;
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)) {
3906 case 1:
3907 if (event !is null && event.type != ENET_EVENT_TYPE_NONE) return 1;
3908 continue;
3909 case -1:
3910 return -1;
3911 default:
3912 break;
3915 switch (enet_protocol_handle_incoming_commands(host, event)) {
3916 case 1: return 1;
3917 case -1: return -1;
3918 default: break;
3921 return -1;
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;
3940 break;
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);
3967 ++command;
3968 ++buffer;
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)) {
3985 usize commandSize;
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;
3996 break;
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;
4007 for (;;) {
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)
4020 break;
4022 currentCommand = enet_list_next(currentCommand);
4024 continue;
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) {
4038 ++buffer;
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);
4046 } else {
4047 enet_free(outgoingCommand);
4050 ++command;
4051 ++buffer;
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);
4087 return 1;
4090 if (outgoingCommand.packet !is null) peer.reliableDataInTransit -= outgoingCommand.fragmentLength;
4092 ++peer.packetsLost;
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;
4104 return 0;
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;
4115 usize commandSize;
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)))))
4131 windowWrap = 1;
4133 if (windowWrap) {
4134 currentCommand = enet_list_next(currentCommand);
4135 continue;
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);
4146 continue;
4150 canPing = 0;
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;
4160 break;
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) {
4192 ++buffer;
4194 buffer.data = outgoingCommand.packet.data+outgoingCommand.fragmentOffset;
4195 buffer.dataLength = outgoingCommand.fragmentLength;
4197 host.packetSize += outgoingCommand.fragmentLength;
4199 peer.reliableDataInTransit += outgoingCommand.fragmentLength;
4202 ++peer.packetsSent;
4204 ++command;
4205 ++buffer;
4208 host.commandCount = command-host.commands.ptr;
4209 host.bufferCount = buffer-host.buffers.ptr;
4211 return canPing;
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;
4219 int sentLength;
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(&currentPeer.acknowledgements)) enet_protocol_send_acknowledgements(host, currentPeer);
4235 if (checkForTimeouts != 0 && !enet_list_empty(&currentPeer.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;
4239 continue;
4242 if ((enet_list_empty(&currentPeer.outgoingReliableCommands) || enet_protocol_send_reliable_outgoing_commands(host, currentPeer)) &&
4243 enet_list_empty(&currentPeer.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(&currentPeer.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(&currentPeer.outgoingReliableCommands), enet_list_size(&currentPeer.outgoingUnreliableCommands),
4265 (currentPeer.channels !is null ? enet_list_size(&currentPeer.channels.incomingReliableCommands) : 0),
4266 (currentPeer.channels !is null ? enet_list_size(&currentPeer.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;
4274 } else {
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;
4288 } else {
4289 host.buffers.ptr[0].dataLength = cast(usize)&(cast(ENetProtocolHeader*)0).sentTime;
4292 shouldCompress = 0;
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, &currentPeer.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;
4334 return 0;
4338 /** Sends any queued packets on the host specified to its designated peers.
4340 * Params:
4341 * host = host to flush
4343 * Remarks:
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.
4354 * Params:
4355 * host = host to check for events
4356 * event = an event structure where event details will be placed if available
4358 * Returns:
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;
4364 event.peer = null;
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.
4373 * Params:
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
4379 * Returns:
4380 * > 0 if an event occurred within the specified time limit, 0 if no event occurred, < 0 on failure
4382 * Remarks:
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;
4390 event.peer = null;
4391 event.packet = null;
4392 switch (enet_protocol_dispatch_incoming_commands(host, event)) {
4393 case 1: return 1;
4394 case -1: version(enet_debug) { import core.stdc.stdio : perror; perror("Error dispatching incoming packets"); } return -1;
4395 default: break;
4399 host.serviceTime = enet_time_get();
4400 timeout += host.serviceTime;
4401 do {
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)) {
4404 case 1: return 1;
4405 case -1:version(enet_debug) { import core.stdc.stdio : perror; perror("Error sending outgoing packets"); } return -1;
4406 default: break;
4409 switch (enet_protocol_receive_incoming_commands(host, event)) {
4410 case 1: return 1;
4411 case -1: version(enet_debug) { import core.stdc.stdio : perror; perror("Error receiving incoming packets"); } return -1;
4412 default: break;
4415 switch (enet_protocol_send_outgoing_commands(host, event, 1)) {
4416 case 1: return 1;
4417 case -1: version(enet_debug) { import core.stdc.stdio : perror; perror("Error sending outgoing packets"); } return -1;
4418 default: break;
4421 if (event !is null) {
4422 switch (enet_protocol_dispatch_incoming_commands (host, event)) {
4423 case 1: return 1;
4424 case -1: version(enet_debug) { import core.stdc.stdio : perror; perror("Error dispatching incoming packets"); } return -1;
4425 default: break;
4429 if (ENET_TIME_GREATER_EQUAL(host.serviceTime, timeout)) return 0;
4431 do {
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);
4441 return 0;
4446 // compress.c
4448 * An adaptive order-2 PPM range coder
4450 private:
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");
4455 string res;
4456 uint pos = 0;
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;
4464 ++pos;
4466 pos = linestpos;
4467 while (pos+2 < s.length) {
4468 int epos = pos;
4469 while (epos+2 < s.length && (s[epos] != '$' || s[epos+1] != '{')) ++epos;
4470 if (epos > pos) {
4471 if (s.length-epos < 3) break;
4472 res ~= s[pos..epos];
4473 pos = epos;
4475 assert(s[pos] == '$' && s[pos+1] == '{');
4476 bool ascode = (pos > 0 && s[pos-1] == '$');
4477 pos += 2;
4478 bool found = false;
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) {
4483 found = true;
4484 pos += oname.length+1;
4485 if (ascode) {
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 ~= ";";
4493 } else {
4494 res ~= names[nidx];
4496 break;
4499 assert(found, "unknown variable in macro");
4501 if (pos < s.length) res ~= s[pos..$];
4502 return res;
4507 struct ENetSymbol {
4508 /* binary indexed tree of symbols */
4509 enet_uint8 value;
4510 enet_uint8 count;
4511 enet_uint16 under;
4512 enet_uint16 left, right;
4514 /* context defined by this symbol */
4515 enet_uint16 symbols;
4516 enet_uint16 escapes;
4517 enet_uint16 total;
4518 enet_uint16 parent;
4521 /* adaptation constants tuned aggressively for small packet sizes rather than large file compression */
4522 enum {
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_};
4557 ${symbol}.left = 0;
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;
4575 for (;;) {
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;
4583 return total;
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});
4601 for (;;) {
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");
4607 encodeRange <<= 8;
4608 encodeLow <<= 8;
4610 }}.cmacroFixVars!("under", "count", "total")(under, count, total);
4612 enum ENET_RANGE_CODER_FLUSH = q{{
4613 while (encodeLow) {
4614 mixin(ENET_RANGE_CODER_OUTPUT!"encodeLow>>24");
4615 encodeLow <<= 8;
4619 enum ENET_RANGE_CODER_FREE_SYMBOLS = q{{
4620 if (nextSymbol >= rangeCoder.symbols.sizeof/ENetSymbol.sizeof-ENET_SUBCONTEXT_ORDER) {
4621 nextSymbol = 0;
4622 mixin(ENET_CONTEXT_CREATE!("root", "ENET_CONTEXT_ESCAPE_MINIMUM", "ENET_CONTEXT_SYMBOL_MINIMUM"));
4623 predicted = 0;
4624 order = 0;
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}));
4634 } else {
4635 ENetSymbol* node = (${context})+(${context}).symbols;
4636 for (;;) {
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);
4647 } else {
4648 ${count_} += node.count;
4649 ${under_} += node.under-node.count;
4650 node.under += ${update};
4651 node.count += ${update};
4652 ${symbol_} = node;
4654 break;
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;
4665 ENetSymbol* root;
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];
4673 ++inBuffers;
4674 --inBufferCount;
4676 mixin(ENET_CONTEXT_CREATE!("root", "ENET_CONTEXT_ESCAPE_MINIMUM", "ENET_CONTEXT_SYMBOL_MINIMUM"));
4678 for (;;) {
4679 ENetSymbol* subcontext, symbol;
4680 ubyte value;
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];
4687 ++inBuffers;
4688 --inBufferCount;
4690 value = *inData++;
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;
4697 if (count > 0) {
4698 mixin(ENET_RANGE_CODER_ENCODE!("subcontext.escapes+under", "count", "total"));
4699 } else {
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;
4712 total = root.total;
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")); }
4717 nextInput:
4718 if (order >= ENET_SUBCONTEXT_ORDER) {
4719 predicted = rangeCoder.symbols.ptr[predicted].parent;
4720 } else {
4721 ++order;
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});
4743 for (;;) {
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);
4748 decodeCode <<= 8;
4749 if (inData < inEnd) decodeCode |= *inData++;
4750 decodeRange <<= 8;
4751 decodeLow <<= 8;
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) =
4758 ${under_} = 0;
4759 ${count_} = ${minimum};
4760 if (!(${context}).symbols) {
4761 $${createRoot}
4762 } else {
4763 ENetSymbol* node = (${context})+(${context}).symbols;
4764 for (;;) {
4765 ushort after = cast(ushort)(${under_}+node.under+(node.value+1)*${minimum}), before = cast(ushort)(node.count+${minimum});
4766 $${visitNode}
4767 if (${code} >= after) {
4768 ${under_} += node.under;
4769 if (node.right) { node += node.right; continue; }
4770 $${createRight}
4771 } else if (${code} < after-before) {
4772 node.under += ${update};
4773 if (node.left) { node += node.left; continue; }
4774 $${createLeft}
4775 } else {
4776 ${value_} = node.value;
4777 ${count_} += node.count;
4778 ${under_} = cast(typeof(${under_}))(after-before);
4779 node.under += ${update};
4780 node.count += ${update};
4781 ${symbol_} = node;
4783 break;
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;
4823 ENetSymbol* root;
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);
4833 for (;;) {
4834 ENetSymbol* subcontext, symbol, patch;
4835 ubyte value = 0;
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"));
4846 continue;
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")); }
4856 goto patchContexts;
4859 total = root.total;
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"));
4863 break;
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")); }
4874 patchContexts:
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;
4879 if (count <= 0) {
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")); }
4886 *parent = bottom;
4888 mixin(ENET_RANGE_CODER_OUTPUT!"value");
4890 if (order >= ENET_SUBCONTEXT_ORDER) {
4891 predicted = rangeCoder.symbols.ptr[predicted].parent;
4892 } else {
4893 ++order;
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);
4920 return 0;