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