Skip to content

Instantly share code, notes, and snippets.

@BeRo1985
Last active September 26, 2015 06:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BeRo1985/48f60c9c62e871f94da3 to your computer and use it in GitHub Desktop.
Save BeRo1985/48f60c9c62e871f94da3 to your computer and use it in GitHub Desktop.
enet pascal port with IPv6 support
(*
**
** Copyright (c) 2002-2015 Lee Salzman
** Copyright (c) 2013-2015 Benjamin 'BeRo' Rosseaux (Pascal port and IPv6)
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and associated documentation files (the "Software"),
** to deal in the Software without restriction, including without limitation
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
** and/or sell copies of the Software, and to permit persons to whom the
** Software is furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in
** all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
**
*)
unit GDFWENet;
{$ifdef fpc}
{$mode delphi}
{$else}
{$IFDEF CONDITIONALEXPRESSIONS}
{$IF CompilerVersion >= 23.0}
{$WARN IMPLICIT_STRING_CAST_LOSS OFF}
{$WARN IMPLICIT_STRING_CAST OFF}
{$WARN SUSPICIOUS_TYPECAST OFF}
{$ifend}
{$endif}
{$endif}
{$j+}
interface
uses {$ifdef unix}BaseUnix,Unix,UnixType,Sockets,cnetdb,{$else}Windows,GDFWENetWinSock2,MMSystem,{$endif}SysUtils,Classes,Math;
{$ifdef fpc}
{$undef OldDelphi}
type ENETptruint=ptruint;
ENETptrint=ptrint;
{$else}
{$ifdef conditionalexpressions}
{$if CompilerVersion>=23.0}
{$undef OldDelphi}
type ENETqword=uint64;
ENETptruint=NativeUInt;
ENETptrint=NativeInt;
{$else}
{$define OldDelphi}
{$ifend}
{$else}
{$define OldDelphi}
{$endif}
{$endif}
{$ifdef OldDelphi}
type ENETqword=int64;
{$ifdef cpu64}
ENETptruint=qword;
ENETptrint=int64;
{$else}
ENETptruint=longword;
ENETptrint=longint;
{$endif}
{$endif}
const ENET_VERSION_MAJOR=1;
ENET_VERSION_MINOR=3;
ENET_VERSION_PATCH=13;
{$ifndef unix}
INVALID_SOCKET=TSocket(not(0));
{$endif}
ENET_VERSION=(ENET_VERSION_MAJOR shl 16) or (ENET_VERSION_MINOR shl 8) or ENET_VERSION_PATCH;
AI_ADDRCONFIG=$0400;
ENET_PROTOCOL_MINIMUM_MTU=576;
ENET_PROTOCOL_MAXIMUM_MTU=4096;
ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS=32;
ENET_PROTOCOL_MINIMUM_WINDOW_SIZE=4096;
ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE=65536;
ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT=1;
ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT=255;
ENET_PROTOCOL_MAXIMUM_PEER_ID=$fff;
ENET_PROTOCOL_MAXIMUM_PACKET_SIZE=1024*1024*1024;
ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT=1024*1024;
ENET_BUFFER_MAXIMUM=1+(2*ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS);
ENET_PROTOCOL_COMMAND_NONE=0;
ENET_PROTOCOL_COMMAND_ACKNOWLEDGE=1;
ENET_PROTOCOL_COMMAND_CONNECT=2;
ENET_PROTOCOL_COMMAND_VERIFY_CONNECT=3;
ENET_PROTOCOL_COMMAND_DISCONNECT=4;
ENET_PROTOCOL_COMMAND_PING=5;
ENET_PROTOCOL_COMMAND_SEND_RELIABLE=6;
ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE=7;
ENET_PROTOCOL_COMMAND_SEND_FRAGMENT=8;
ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED=9;
ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT=10;
ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE=11;
ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT=12;
ENET_PROTOCOL_COMMAND_COUNT=13;
ENET_PROTOCOL_COMMAND_MASK=$0F;
ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE=1 shl 7;
ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED=1 shl 6;
ENET_PROTOCOL_HEADER_FLAG_COMPRESSED=1 shl 14;
ENET_PROTOCOL_HEADER_FLAG_SENT_TIME=1 shl 15;
ENET_PROTOCOL_HEADER_FLAG_MASK=ENET_PROTOCOL_HEADER_FLAG_COMPRESSED or ENET_PROTOCOL_HEADER_FLAG_SENT_TIME;
ENET_PROTOCOL_HEADER_SESSION_MASK=3 shl 12;
ENET_PROTOCOL_HEADER_SESSION_SHIFT=12;
ENET_TIME_OVERFLOW=86400000;
ENET_SOCKET_NULL={$ifdef unix}-1{$else}INVALID_SOCKET{$endif};
ENET_SOCKET_TYPE_STREAM=1;
ENET_SOCKET_TYPE_DATAGRAM=2;
ENET_SOCKET_WAIT_NONE=0;
ENET_SOCKET_WAIT_SEND=1 shl 0;
ENET_SOCKET_WAIT_RECEIVE=1 shl 1;
ENET_SOCKET_WAIT_INTERRUPT=1 shl 2;
ENET_SOCKOPT_NONBLOCK=1;
ENET_SOCKOPT_BROADCAST=2;
ENET_SOCKOPT_RCVBUF=3;
ENET_SOCKOPT_SNDBUF=4;
ENET_SOCKOPT_REUSEADDR=5;
ENET_SOCKOPT_RCVTIMEO=6;
ENET_SOCKOPT_SNDTIMEO=7;
ENET_SOCKOPT_ERROR=8;
ENET_SOCKOPT_NODELAY=9;
ENET_SOCKET_SHUTDOWN_READ=0;
ENET_SOCKET_SHUTDOWN_WRITE=1;
ENET_SOCKET_SHUTDOWN_READ_WRITE=2;
ENET_IPV4MAPPED_PREFIX_LEN=12; // specifies the length of the IPv4-mapped IPv6 prefix
ENET_PORT_ANY=0; // specifies that a port should be automatically chosen
ENET_NO_ADDRESS_FAMILY=0;
ENET_IPV4=1 shl 0;
ENET_IPV6=1 shl 1;
ENET_PACKET_FLAG_RELIABLE=1 shl 0;
ENET_PACKET_FLAG_UNSEQUENCED=1 shl 1;
ENET_PACKET_FLAG_NO_ALLOCATE=1 shl 2;
ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT=1 shl 3;
ENET_PACKET_FLAG_SENT=1 shl 8;
ENET_PEER_STATE_DISCONNECTED=0;
ENET_PEER_STATE_CONNECTING=1;
ENET_PEER_STATE_ACKNOWLEDGING_CONNECT=2;
ENET_PEER_STATE_CONNECTION_PENDING=3;
ENET_PEER_STATE_CONNECTION_SUCCEEDED=4;
ENET_PEER_STATE_CONNECTED=5;
ENET_PEER_STATE_DISCONNECT_LATER=6;
ENET_PEER_STATE_DISCONNECTING=7;
ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT=8;
ENET_PEER_STATE_ZOMBIE=9;
ENET_HOST_RECEIVE_BUFFER_SIZE=256*1024;
ENET_HOST_SEND_BUFFER_SIZE=256*1024;
ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL=1000;
ENET_HOST_DEFAULT_MTU=1400;
ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE=32*1024*1024;
ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA=32*1024*1024;
ENET_PEER_DEFAULT_ROUND_TRIP_TIME=500;
ENET_PEER_DEFAULT_PACKET_THROTTLE=32;
ENET_PEER_PACKET_THROTTLE_SCALE=32;
ENET_PEER_PACKET_THROTTLE_COUNTER=7;
ENET_PEER_PACKET_THROTTLE_ACCELERATION=2;
ENET_PEER_PACKET_THROTTLE_DECELERATION=2;
ENET_PEER_PACKET_THROTTLE_INTERVAL=5000;
ENET_PEER_PACKET_LOSS_SCALE=1 shl 16;
ENET_PEER_PACKET_LOSS_INTERVAL=10000;
ENET_PEER_WINDOW_SIZE_SCALE=64*1024;
ENET_PEER_TIMEOUT_LIMIT=32;
ENET_PEER_TIMEOUT_MINIMUM=5000;
ENET_PEER_TIMEOUT_MAXIMUM=30000;
ENET_PEER_PING_INTERVAL_=500;
ENET_PEER_UNSEQUENCED_WINDOWS=64;
ENET_PEER_UNSEQUENCED_WINDOW_SIZE=1024;
ENET_PEER_FREE_UNSEQUENCED_WINDOWS=32;
ENET_PEER_RELIABLE_WINDOWS=16;
ENET_PEER_RELIABLE_WINDOW_SIZE=$1000;
ENET_PEER_FREE_RELIABLE_WINDOWS=8;
ENET_EVENT_TYPE_NONE=0;
ENET_EVENT_TYPE_CONNECT=1;
ENET_EVENT_TYPE_DISCONNECT=2;
ENET_EVENT_TYPE_RECEIVE=3;
type PENetVersion=^TENetVersion;
TENetVersion=longword;
PENetSocket=^TENetSocket;
TENetSocket=TSocket;
PENetSocketSet=^TENetSocketSet;
TENetSocketSet=TFDSet;
PENetProtocolCommand=^TENetProtocolCommand;
TENetProtocolCommand=byte;
PENetProtocolFlag=^TENetProtocolFlag;
TENetProtocolFlag=longint;
PENetCallbacks=^TENetCallbacks;
TENetCallbacks=record
malloc:function(Size:longint):pointer;
free:procedure(memory:pointer);
no_memory:procedure;
end;
PENetListNode=^TENetListNode;
TENetListNode=record
Next:PENetListNode;
Previous:PENetListNode;
end;
TENetListIterator=PENetListNode;
PENetList=^TENetList;
TENetList=record
Sentinel:TENetListNode;
end;
PENetProtocolHeader=^TENetProtocolHeader;
TENetProtocolHeader=packed record
peerID:word;
sentTime:word;
end;
PENetProtocolCommandHeader=^TENetProtocolCommandHeader;
TENetProtocolCommandHeader=packed record
command:byte;
channelID:byte;
reliableSequenceNumber:word;
end;
PENetProtocolAcknowledge=^TENetProtocolAcknowledge;
TENetProtocolAcknowledge=packed record
header:TENetProtocolCommandHeader;
receivedReliableSequenceNumber:word;
receivedSentTime:word;
end;
PENetProtocolConnect=^TENetProtocolConnect;
TENetProtocolConnect=packed record
header:TENetProtocolCommandHeader;
outgoingPeerID:word;
incomingSessionID:word;
outgoingSessionID:word;
mtu:longword;
windowSize:longword;
channelCount:longword;
incomingBandwidth:longword;
outgoingBandwidth:longword;
packetThrottleInterval:longword;
packetThrottleAcceleration:longword;
packetThrottleDeceleration:longword;
connectID:longword;
data:longword;
end;
PENetProtocolVerifyConnect=^TENetProtocolVerifyConnect;
TENetProtocolVerifyConnect=packed record
header:TENetProtocolCommandHeader;
outgoingPeerID:word;
incomingSessionID:word;
outgoingSessionID:word;
mtu:longword;
windowSize:longword;
channelCount:longword;
incomingBandwidth:longword;
outgoingBandwidth:longword;
packetThrottleInterval:longword;
packetThrottleAcceleration:longword;
packetThrottleDeceleration:longword;
connectID:longword;
end;
PENetProtocolBandwidthLimit=^TENetProtocolBandwidthLimit;
TENetProtocolBandwidthLimit=packed record
header:TENetProtocolCommandHeader;
incomingBandwidth:longword;
outgoingBandwidth:longword;
end;
PENetProtocolThrottleConfigure=^TENetProtocolThrottleConfigure;
TENetProtocolThrottleConfigure=packed record
header:TENetProtocolCommandHeader;
packetThrottleInterval:longword;
packetThrottleAcceleration:longword;
packetThrottleDeceleration:longword;
end;
PENetProtocolDisconnect=^TENetProtocolDisconnect;
TENetProtocolDisconnect=packed record
header:TENetProtocolCommandHeader;
data:longword;
end;
PENetProtocolPing=^TENetProtocolPing;
TENetProtocolPing=packed record
header:TENetProtocolCommandHeader;
end;
PENetProtocolSendReliable=^TENetProtocolSendReliable;
TENetProtocolSendReliable=packed record
header:TENetProtocolCommandHeader;
dataLength:word;
end;
PENetProtocolSendUnreliable=^TENetProtocolSendUnreliable;
TENetProtocolSendUnreliable=packed record
header:TENetProtocolCommandHeader;
unreliableSequenceNumber:word;
dataLength:word;
end;
PENetProtocolSendUnsequenced=^TENetProtocolSendUnsequenced;
TENetProtocolSendUnsequenced=packed record
header:TENetProtocolCommandHeader;
unsequencedGroup:word;
dataLength:word;
end;
PENetProtocolSendFragment=^TENetProtocolSendFragment;
TENetProtocolSendFragment=packed record
header:TENetProtocolCommandHeader;
startSequenceNumber:word;
dataLength:word;
fragmentCount:longword;
fragmentNumber:longword;
totalLength:longword;
fragmentOffset:longword;
end;
PENetProtocol=^TENetProtocol;
TENetProtocol=packed record
case TENetProtocolCommand of
ENET_PROTOCOL_COMMAND_NONE:(
header:TENetProtocolCommandHeader;
);
ENET_PROTOCOL_COMMAND_ACKNOWLEDGE:(
acknowledge:TENetProtocolAcknowledge;
);
ENET_PROTOCOL_COMMAND_CONNECT:(
connect:TENetProtocolConnect;
);
ENET_PROTOCOL_COMMAND_VERIFY_CONNECT:(
verifyConnect:TENetProtocolVerifyConnect;
);
ENET_PROTOCOL_COMMAND_DISCONNECT:(
disconnect:TENetProtocolDisconnect;
);
ENET_PROTOCOL_COMMAND_PING:(
ping:TENetProtocolPing;
);
ENET_PROTOCOL_COMMAND_SEND_RELIABLE:(
sendReliable:TENetProtocolSendReliable;
);
ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:(
sendUnreliable:TENetProtocolSendUnreliable;
);
ENET_PROTOCOL_COMMAND_SEND_FRAGMENT:(
sendFragment:TENetProtocolSendFragment;
);
ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:(
sendUnsequenced:TENetProtocolSendUnsequenced;
);
ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT:(
bandwidthLimit:TENetProtocolBandwidthLimit;
);
ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE:(
throttleConfigure:TENetProtocolThrottleConfigure;
);
end;
PENetBuffer=^TENetBuffer;
TENetBuffer=record
{$ifdef unix}
Data:pansichar;
DataLength:longword;
{$else}
DataLength:longword;
Data:pansichar;
{$endif}
end;
PENetSocketType=^TENetSocketType;
TENetSocketType=byte;
PENetSocketWait=^TENetSocketWait;
TENetSocketWait=byte;
PENetSocketOption=^TENetSocketOption;
TENetSocketOption=byte;
PENetSocketShutdown=^TENetSocketShutdown;
TENetSocketShutdown=byte;
PENetHostAddress=^TENetHostAddress;
TENetHostAddress=packed record
case byte of
0:(
addr:packed array[0..15] of byte;
);
1:(
addr16:packed array[0..7] of word;
);
2:(
addr32:packed array[0..3] of longword;
);
3:(
addr64:packed array[0..1] of int64;
);
end;
PENetAddressFamily=^TENetAddressFamily;
TENetAddressFamily=byte;
PENetPacketFlag=^TENetPacketFlag;
TENetPacketFlag=byte;
PENetAddress=^TENetAddress;
TENetAddress=record
host:TENetHostAddress;
scopeID:{$ifdef unix}longword{$else}int64{$endif};
port:word;
end;
const ENET_HOST_ANY_INIT:TENetHostAddress=(addr:(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0));
ENET_HOST_ANY:TENetHostAddress=(addr:(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0));
ENET_IPV4MAPPED_PREFIX_INIT:TENetHostAddress=(addr:(0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0));
ENET_IPV4MAPPED_PREFIX:TENetHostAddress=(addr:(0,0,0,0,0,0,0,0,0,0,255,255,0,0,0,0));
ENET_HOST_BROADCAST_INIT:TENetHostAddress=(addr:(0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255));
ENET_HOST_BROADCAST_:TENetHostAddress=(addr:(0,0,0,0,0,0,0,0,0,0,255,255,255,255,255,255));
type PENetPacket=^TENetPacket;
PLongwords=^TLongwords;
TLongwords=array[0..0] of longword;
TENetPacketFreeCallback=procedure(packet:PENetPacket);
TENetPacket=record
referenceCount:longword;
flags:longword;
data:PAnsiChar;
dataLength:longword;
freeCallback:TENetPacketFreeCallback;
userData:pointer;
end;
PENetAcknowledgement=^TENetAcknowledgement;
TENetAcknowledgement=record
acknowledgementList:TENetListNode;
sentTime:longword;
command:TENetProtocol;
end;
PENetOutgoingCommand=^TENetOutgoingCommand;
TENetOutgoingCommand=record
outgoingCommandList:TENetListNode;
reliableSequenceNumber:word;
unreliableSequenceNumber:word;
sentTime:longword;
roundTripTimeout:longword;
roundTripTimeoutLimit:longword;
fragmentOffset:longword;
fragmentLength:word;
sendAttempts:word;
command:TENetProtocol;
packet:PENetPacket;
end;
PENetIncomingCommand=^TENetIncomingCommand;
TENetIncomingCommand=record
incomingCommandList:TENetListNode;
reliableSequenceNumber:word;
unreliableSequenceNumber:word;
command:TENetProtocol;
fragmentCount:longword;
fragmentsRemaining:longword;
fragments:plongwords;
packet:PENetPacket;
end;
PENetPeerState=^TENetPeerState;
TENetPeerState=byte;
PENetChannel=^TENetChannel;
TENetChannel=record
outgoingReliableSequenceNumber:word;
outgoingUnreliableSequenceNumber:word;
usedReliableWindows:word;
reliableWindows:array[0..ENET_PEER_RELIABLE_WINDOWS-1] of word;
incomingReliableSequenceNumber:word;
incomingUnreliableSequenceNumber:word;
incomingReliableCommands:TENetList;
incomingUnreliableCommands:TENetList;
end;
PENetChannels=^TENetChannels;
TENetChannels=array[0..0] of TENetChannel;
PENetHost=^TENetHost;
PENetPeer=^TENetPeer;
TENetPeer=record
dispatchList:TENetListNode;
host:PENetHost;
outgoingPeerID:word;
incomingPeerID:word;
connectID:longword;
outgoingSessionID:byte;
incomingSessionID:byte;
address:TENetAddress;
data:pointer;
state:TENetPeerState;
channels:PENetChannels;
channelCount:longword;
incomingBandwidth:longword;
outgoingBandwidth:longword;
incomingBandwidthThrottleEpoch:longword;
outgoingBandwidthThrottleEpoch:longword;
incomingDataTotal:longword;
outgoingDataTotal:longword;
lastSendTime:longword;
lastReceiveTime:longword;
nextTimeout:longword;
earliestTimeout:longword;
packetLossEpoch:longword;
packetsSent:longword;
packetsLost:longword;
packetLoss:longword;
packetLossVariance:longword;
packetThrottle:longword;
packetThrottleLimit:longword;
packetThrottleCounter:longword;
packetThrottleEpoch:longword;
packetThrottleAcceleration:longword;
packetThrottleDeceleration:longword;
packetThrottleInterval:longword;
pingInterval:longword;
timeoutLimit:longword;
timeoutMinimum:longword;
timeoutMaximum:longword;
lastRoundTripTime:longword;
lowestRoundTripTime:longword;
lastRoundTripTimeVariance:longword;
highestRoundTripTimeVariance:longword;
roundTripTime:longword;
roundTripTimeVariance:longword;
mtu:longword;
windowSize:longword;
reliableDataInTransit:longword;
outgoingReliableSequenceNumber:word;
acknowledgements:TENetList;
sentReliableCommands:TENetList;
sentUnreliableCommands:TENetList;
outgoingReliableCommands:TENetList;
outgoingUnreliableCommands:TENetList;
dispatchedCommands:TENetList;
needsDispatch:longbool;
incomingUnsequencedGroup:word;
outgoingUnsequencedGroup:word;
unsequencedWindow:array[0..((ENET_PEER_UNSEQUENCED_WINDOW_SIZE+31) shr 5)-1] of longword;
eventData:longword;
totalWaitingData:ENETptruint;
end;
PENetPeers=^TENetPeers;
TENetPeers=array[0..0] of TENetPeer;
PENetCompressor=^TENetCompressor;
TENetCompressor=record
context:pointer;
compress:function(context:pointer;inBuffer:PENetBuffer;inBufferCount,inLimit:longint;outData:pointer;outLimit:longint):longint;
decompress:function(context:pointer;inData:pointer;inLimit:longint;outData:pointer;outLimit:longint):longint;
destroy:procedure(context:pointer);
end;
TENetChecksumCallback=function(buffers:PENetBuffer;bufferCount:longint):longword;
PENetEvent=^TENetEvent;
TENetInterceptCallback=function(host:PENetHost;event:PENetEvent):longint;
TENetHost=record
socket4:TENetSocket;
socket6:TENetSocket;
address:TENetAddress;
incomingBandwidth:longword;
outgoingBandwidth:longword;
bandwidthThrottleEpoch:longword;
mtu:longword;
randomSeed:longword;
recalculateBandwidthLimits:longint;
peers:PENetPeers;
peerCount:longint;
channelLimit:longword;
serviceTime:longword;
dispatchQueue:TENetList;
continueSending:longint;
packetSize:longint;
headerFlags:word;
commands:array[0..ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS-1] of TENetProtocol;
commandCount:longint;
buffers:array[0..ENET_BUFFER_MAXIMUM-1] of TENetBuffer;
bufferCount:longint;
checksum:TENetChecksumCallback;
compressor:TENetCompressor;
packetData:array[0..1,0..ENET_PROTOCOL_MAXIMUM_MTU-1] of byte;
receivedAddress:TENetAddress;
receivedData:PAnsiChar;
receivedDataLength:longint;
totalSentData:longword;
totalSentPackets:longword;
totalReceivedData:longword;
totalReceivedPackets:longword;
intercept:TENetInterceptCallback;
connectedPeers:ENETptruint;
bandwidthLimitedPeers:ENETptruint;
duplicatePeers:ENETptruint;
maximumPacketSize:ENETptruint;
maximumWaitingData:ENETptruint;
end;
PENetEventType=^TENetEventType;
TENetEventType=byte;
TENetEvent=record
type_:TENetEventType;
peer:PENetPeer;
channelID:byte;
data:longword;
packet:PENetPacket;
end;
function enet_list_begin(list:pointer):pointer;
function enet_list_end(list:pointer):pointer;
function enet_list_empty(list:pointer):boolean;
function enet_list_next(iterator:pointer):pointer;
function enet_list_previous(iterator:pointer):pointer;
function enet_list_front(list:pointer):pointer;
function enet_list_back(list:pointer):pointer;
procedure enet_list_clear(list:PENetList);
function enet_list_insert(position:TENetListIterator;data:pointer):TENetListIterator;
function enet_list_remove(position:TENetListIterator):pointer;
function enet_list_move(position:TENetListIterator;dataFirst,dataLast:pointer):TENetListIterator;
function enet_list_size(list:PENetList):longint;
function ENET_TIME_LESS(a,b:longword):boolean;
function ENET_TIME_GREATER(a,b:longword):boolean;
function ENET_TIME_LESS_EQUAL(a,b:longword):boolean;
function ENET_TIME_GREATER_EQUAL(a,b:longword):boolean;
function ENET_TIME_DIFFERENCE(a,b:longword):longint;
function ENET_HOST_TO_NET_16(value:word):word;
function ENET_HOST_TO_NET_32(value:longword):longword;
function ENET_NET_TO_HOST_16(value:word):word;
function ENET_NET_TO_HOST_32(value:longword):longword;
procedure ENET_SOCKETSET_EMPTY(var sockset:TFDSet);
procedure ENET_SOCKETSET_ADD(var sockset:TFDSet;socket:TSocket);
procedure ENET_SOCKETSET_REMOVE(var sockset:TFDSet;socket:TSocket);
function ENET_SOCKETSET_CHECK(var sockset:TFDSet;socket:TSocket):boolean;
function enet_address_map4(address:longword):TENetHostAddress;
function enet_compare_address(const a,b:TENetHostAddress):boolean;
function enet_get_address_family(address:PENetAddress):TENetAddressFamily;
function enet_initialize:longint;
procedure enet_deinitialize;
function enet_linked_version:TENetVersion;
function enet_host_random_seed:longword;
function enet_time_get:longword;
procedure enet_time_set(newTimeBase:longword);
function enet_af(family:TENetAddressFamily):word;
function enet_sa_size(family:TENetAddressFamily):longint;
function enet_address_set_address(address:PENetAddress;sin:pointer):TENetAddressFamily;
function enet_address_set_sin(sin:pointer;address:PENetAddress;family:TENetAddressFamily):longint;
function enet_address_set_host(address:PENetAddress;name:PAnsiChar):longint;
function enet_address_get_host_x(address:PENetAddress;name:PAnsiChar;nameLength:longint;flags:longint):longint;
function enet_address_get_host_ip(address:PENetAddress;name:PAnsiChar;nameLength:longint):longint;
function enet_address_get_host(address:PENetAddress;name:PAnsiChar;nameLength:longint):longint;
function enet_socket_bind(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):longint;
function enet_socket_get_address(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):longint;
function enet_socket_listen(socket:TENetSocket;backlog:longint):longint;
function enet_socket_create(type_:TENetSocketType;family:TENetAddressFamily):TENetSocket;
function enet_socket_set_option(socket:TENetSocket;option:TENetSocketOption;value:longint):longint;
function enet_socket_get_option(socket:TENetSocket;option:TENetSocketOption;var value:longint):longint;
function enet_socket_shutdown(socket:TENetSocket;how:TENetSocketShutdown):longint;
function enet_socket_connect(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):longint;
function enet_socket_accept(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):TENetSocket;
procedure enet_socket_destroy(socket:TENetSocket);
function enet_socket_send(socket:TENetSocket;address:PENetAddress;buffers:PENetBuffer;bufferCount:longword;family:TENetAddressFamily):longint;
function enet_socket_receive(socket:TENetSocket;address:PENetAddress;buffers:PENetBuffer;bufferCount:longword;family:TENetAddressFamily):longint;
function enet_socketset_select(maxSocket:TENetSocket;readSet,writeSet:PENetSocketSet;timeout:longword):longint;
function enet_socket_wait(socket4,socket6:TENetSocket;condition:pointer;timeout:longword):longint;
function enet_host_compress_with_range_coder(host:PENetHost):longint;
function enet_packet_create(data:pointer;dataLength:longint;flags:Longword):PENetPacket;
procedure enet_packet_destroy(packet:PENetPacket);
function enet_packet_resize(packet:PENetPacket;dataLength:longword):longint;
function enet_crc32(buffers:PENetBuffer;bufferCount:longint):longword;
procedure enet_peer_throttle_configure(peer:PENetPeer;interval,acceleration,deceleration:longword);
function enet_peer_throttle(peer:PENetPeer;rtt:longword):longint;
function enet_peer_send(peer:PENetPeer;channelID:byte;packet:PENetPacket):longint;
function enet_peer_receive(peer:PENetPeer;channelID:pbyte):PENetPacket;
procedure enet_peer_reset_outgoing_commands(queue:PENetList);
procedure enet_peer_remove_incoming_commands(queue:PENetList;startCommand,endCommand:TENetListIterator);
procedure enet_peer_reset_incoming_commands(queue:PENetList);
procedure enet_peer_reset_queues(peer:PENetPeer);
procedure enet_peer_reset(peer:PENetPeer);
procedure enet_peer_ping(peer:PENetPeer);
procedure enet_peer_ping_interval(peer:PENetPeer;pingInterval:longword);
procedure enet_peer_timeout(peer:PENetPeer;timeoutLimit,timeoutMinimum,timeoutMaximum:longword);
procedure enet_peer_disconnect_now(peer:PENetPeer;data:longword);
procedure enet_peer_disconnect(peer:PENetPeer;data:longword);
procedure enet_peer_disconnect_later(peer:PENetPeer;data:longword);
function enet_peer_queue_acknowledgement(peer:PENetPeer;command:PENetProtocol;sentTime:word):PENetAcknowledgement;
procedure enet_peer_setup_outgoing_command(peer:PENetPeer;outgoingCommand:PENetOutgoingCommand);
function enet_peer_queue_outgoing_command(peer:PENetPeer;command:PENetProtocol;packet:PENetPacket;offset:longword;length:word):PENetOutgoingCommand;
procedure enet_peer_dispatch_incoming_unreliable_commands(peer:PENetPeer;channel:PENetChannel);
procedure enet_peer_dispatch_incoming_reliable_commands(peer:PENetPeer;channel:PENetChannel);
function enet_peer_queue_incoming_command(peer:PENetPeer;command:PENetProtocol;data:pointer;dataLength:ENETptruint;flags:longword;fragmentCount:longword):PENetIncomingCommand;
procedure enet_peer_on_connect(peer:PENetPeer);
procedure enet_peer_on_disconnect(peer:PENetPeer);
function enet_socket_create_bind(address:PENetAddress;family:TENetAddressFamily):TENetSocket;
function enet_host_create(address:PENetAddress;peerCount,channelLimit,incomingBandwidth,outgoingBandwidth:longword):PENetHost;
procedure enet_host_destroy(host:PENetHost);
function enet_host_connect(host:PENetHost;address:PENetAddress;channelCount,data:longword):PENetPeer;
procedure enet_host_broadcast(host:PENetHost;channelID:byte;packet:PENetPacket);
procedure enet_host_compress(host:PENetHost;compressor:PENetCompressor);
procedure enet_host_channel_limit(host:PENetHost;channelLimit:longword);
procedure enet_host_bandwidth_limit(host:PENetHost;incomingBandwidth,outgoingBandwidth:longword);
procedure enet_host_bandwidth_throttle(host:PENetHost);
function enet_protocol_command_size(command:byte):longint;
procedure enet_protocol_change_state(host:PENetHost;peer:PENetPeer;state:TENetPeerState);
procedure enet_protocol_dispatch_state(host:PENetHost;peer:PENetPeer;state:TENetPeerState);
function enet_protocol_dispatch_incoming_commands(host:PENetHost;event:PENetEvent):longint;
procedure enet_protocol_notify_connect(host:PENetHost;peer:PENetPeer;event:PENetEvent);
procedure enet_protocol_notify_disconnect(host:PENetHost;peer:PENetPeer;event:PENetEvent);
procedure enet_protocol_remove_sent_unreliable_commands(peer:PENetPeer);
function enet_protocol_remove_sent_reliable_command(peer:PENetPeer;reliableSequenceNumber:word;channelID:byte):TENetProtocolCommand;
function enet_protocol_handle_connect(host:PENetHost;header:PENetProtocolHeader;command:PENetProtocol):PENetPeer;
function enet_protocol_handle_send_reliable(host:PENetHost;peer:PENetPeer;command:PENetProtocol;currentData:PPAnsiChar):longint;
function enet_protocol_handle_send_unsequenced(host:PENetHost;peer:PENetPeer;command:PENetProtocol;currentData:PPAnsiChar):longint;
function enet_protocol_handle_send_unreliable(host:PENetHost;peer:PENetPeer;command:PENetProtocol;currentData:PPAnsiChar):longint;
function enet_protocol_handle_send_fragment(host:PENetHost;peer:PENetPeer;command:PENetProtocol;currentData:PPAnsiChar):longint;
function enet_protocol_handle_send_unreliable_fragment(host:PENetHost;peer:PENetPeer;command:PENetProtocol;currentData:PPAnsiChar):longint;
function enet_protocol_handle_ping(host:PENetHost;peer:PENetPeer;command:PENetProtocol):longint;
function enet_protocol_handle_bandwidth_limit(host:PENetHost;peer:PENetPeer;command:PENetProtocol):longint;
function enet_protocol_handle_throttle_configure(host:PENetHost;peer:PENetPeer;command:PENetProtocol):longint;
function enet_protocol_handle_disconnect(host:PENetHost;peer:PENetPeer;command:PENetProtocol):longint;
function enet_protocol_handle_acknowledge(host:PENetHost;event:PENetEvent;peer:PENetPeer;command:PENetProtocol):longint;
function enet_protocol_handle_verify_connect(host:PENetHost;event:PENetEvent;peer:PENetPeer;command:PENetProtocol):longint;
function enet_protocol_handle_incoming_commands(host:PENetHost;event:PENetEvent):longint;
procedure enet_protocol_send_acknowledgements(host:PENetHost;peer:PENetPeer);
function enet_protocol_receive_incoming_commands(host:PENetHost;event:PENetEvent;family:TENetAddressFamily):longint;
procedure enet_protocol_send_unreliable_outgoing_commands(host:PENetHost;peer:PENetPeer);
function enet_protocol_check_timeouts(host:PENetHost;peer:PENetPeer;event:PENetEvent):longint;
function enet_protocol_send_reliable_outgoing_commands(host:PENetHost;peer:PENetPeer):longint;
function enet_protocol_send_outgoing_commands(host:PENetHost;event:PENetEvent;checkForTimeouts:longint):longint;
procedure enet_host_flush(host:PENetHost);
function enet_host_check_events(host:PENetHost;event:PENetEvent):longint;
function enet_host_service(host:PENetHost;event:PENetEvent;timeout:longword):longint;
implementation
{$ifdef fpc}
{$undef OldDelphi}
{$else}
{$ifdef conditionalexpressions}
{$if CompilerVersion>=23.0}
{$undef OldDelphi}
type qword=uint64;
ptruint=NativeUInt;
ptrint=NativeInt;
{$else}
{$define OldDelphi}
{$ifend}
{$else}
{$define OldDelphi}
{$endif}
{$endif}
{$ifdef OldDelphi}
type qword=int64;
{$ifdef cpu64}
ptruint=qword;
ptrint=int64;
{$else}
ptruint=longword;
ptrint=longint;
{$endif}
{$endif}
function enet_list_begin(list:pointer):pointer;
begin
result:=PENetList(list)^.Sentinel.Next;
end;
function enet_list_end(list:pointer):pointer;
begin
result:=@PENetList(list)^.Sentinel;
end;
function enet_list_empty(list:pointer):boolean;
begin
result:=PENetList(list)^.Sentinel.Next=@PENetList(list)^.Sentinel;
end;
function enet_list_next(iterator:pointer):pointer;
begin
result:=PENetListNode(iterator)^.Next;
end;
function enet_list_previous(iterator:pointer):pointer;
begin
result:=PENetListNode(iterator)^.Previous;
end;
function enet_list_front(list:pointer):pointer;
begin
result:=PENetList(list)^.Sentinel.Next;
end;
function enet_list_back(list:pointer):pointer;
begin
result:=PENetList(list)^.Sentinel.Previous;
end;
procedure enet_list_clear(list:PENetList);
begin
list^.sentinel.next:=@list^.sentinel;
list^.sentinel.previous:=@list^.sentinel;
end;
function enet_list_insert(position:TENetListIterator;data:pointer):TENetListIterator;
begin
result:=data;
result^.previous:=position^.previous;
result^.next:=position;
result^.previous^.next:=result;
position^.previous:=result;
end;
function enet_list_remove(position:TENetListIterator):pointer;
begin
position^.previous^.next:=position^.next;
position^.next^.previous:=position^.previous;
result:=position;
end;
function enet_list_move(position:TENetListIterator;dataFirst,dataLast:pointer):TENetListIterator;
var first,last:TENetListIterator;
begin
first:=dataFirst;
last:=dataLast;
first^.previous^.next:=last^.next;
last^.next^.previous:=first^.previous;
first^.previous:=position^.previous;
last^.next:=pointer(position);
first^.previous^.next:=first;
position^.previous:=last;
result:=first;
end;
function enet_list_size(list:PENetList):longint;
var position:TENetListIterator;
begin
result:=0;
if assigned(list) then begin
position:=enet_list_begin(list);
while position<>enet_list_end(list) do begin
inc(result);
position:=enet_list_next(position);
end;
end;
end;
function ENET_TIME_LESS(a,b:longword):boolean;
begin
result:=(a-b)>=ENET_TIME_OVERFLOW;
end;
function ENET_TIME_GREATER(a,b:longword):boolean;
begin
result:=(b-a)>=ENET_TIME_OVERFLOW;
end;
function ENET_TIME_LESS_EQUAL(a,b:longword):boolean;
begin
result:=not ((b-a)>=ENET_TIME_OVERFLOW);
end;
function ENET_TIME_GREATER_EQUAL(a,b:longword):boolean;
begin
result:=not ((a-b)>=ENET_TIME_OVERFLOW);
end;
function ENET_TIME_DIFFERENCE(a,b:longword):longint;
begin
if (a-b)>=ENET_TIME_OVERFLOW then begin
result:=b-a;
end else begin
result:=a-b;
end;
end;
function ENET_HOST_TO_NET_16(value:word):word;
begin
result:=htons(value);
end;
function ENET_HOST_TO_NET_32(value:longword):longword;
begin
result:=htonl(value);
end;
function ENET_NET_TO_HOST_16(value:word):word;
begin
result:=ntohs(value);
end;
function ENET_NET_TO_HOST_32(value:longword):longword;
begin
result:=ntohl(value);
end;
procedure ENET_SOCKETSET_EMPTY(var sockset:TFDSet);
begin
{$ifdef unix}
fpFD_ZERO(sockset);
{$else}
FD_ZERO(sockset);
{$endif}
end;
procedure ENET_SOCKETSET_ADD(var sockset:TFDSet;socket:TSocket);
begin
{$ifdef unix}
fpFD_SET(socket,sockset);
{$else}
FD_SET(socket,sockset);
{$endif}
end;
procedure ENET_SOCKETSET_REMOVE(var sockset:TFDSet;socket:TSocket);
begin
{$ifdef unix}
fpFD_CLR(socket,sockset);
{$else}
FD_CLR(socket,sockset);
{$endif}
end;
function ENET_SOCKETSET_CHECK(var sockset:TFDSet;socket:TSocket):boolean;
begin
{$ifdef unix}
result:=fpFD_ISSET(socket,sockset);
{$else}
result:=FD_ISSET(socket,sockset);
{$endif}
end;
function enet_address_map4(address:longword):TENetHostAddress;
begin
result:=ENET_IPV4MAPPED_PREFIX_INIT;
longword(pointer(@result.addr[12])^):=address;
end;
function enet_compare_address(const a,b:TENetHostAddress):boolean;
begin
result:=(a.addr64[0]=b.addr64[0]) and (a.addr64[1]=b.addr64[1]);
end;
function enet_get_address_family(address:PENetAddress):TENetAddressFamily;
begin
if (address^.host.addr[0]=ENET_IPV4MAPPED_PREFIX.addr[0]) and
(address^.host.addr[1]=ENET_IPV4MAPPED_PREFIX.addr[1]) and
(address^.host.addr[2]=ENET_IPV4MAPPED_PREFIX.addr[2]) and
(address^.host.addr[3]=ENET_IPV4MAPPED_PREFIX.addr[3]) and
(address^.host.addr[4]=ENET_IPV4MAPPED_PREFIX.addr[4]) and
(address^.host.addr[5]=ENET_IPV4MAPPED_PREFIX.addr[5]) and
(address^.host.addr[6]=ENET_IPV4MAPPED_PREFIX.addr[6]) and
(address^.host.addr[7]=ENET_IPV4MAPPED_PREFIX.addr[7]) and
(address^.host.addr[8]=ENET_IPV4MAPPED_PREFIX.addr[8]) and
(address^.host.addr[9]=ENET_IPV4MAPPED_PREFIX.addr[9]) and
(address^.host.addr[10]=ENET_IPV4MAPPED_PREFIX.addr[10]) and
(address^.host.addr[11]=ENET_IPV4MAPPED_PREFIX.addr[11]) then begin
result:=ENET_IPV4;
end else begin
result:=ENET_IPV6;
end;
end;
const timeBase:longword=0;
{$ifdef unix}
const SOCKET_ERROR=-1;
function enet_initialize:longint;
begin
result:=0;
end;
procedure enet_deinitialize;
begin
end;
function enet_host_random_seed:longword;
var tv:TTimeVal;
begin
fpgettimeofday(@tv,nil);
result:=((timeVal.tv_sec*1000)+(timeVal.tv_usec div 1000))-timeBase;
end;
function enet_time_get:longword;
var tv:TTimeVal;
begin
fpgettimeofday(@tv,nil);
result:=((timeVal.tv_sec*1000)+(timeVal.tv_usec div 1000))-timeBase;
end;
procedure enet_time_set(newTimeBase:longword);
var tv:TTimeVal;
begin
fpgettimeofday(@tv,nil);
timeBase:=((timeVal.tv_sec*1000)+(timeVal.tv_usec div 1000))-newTimeBase;
end;
function enet_af(family:TENetAddressFamily):word;
begin
case family of
ENET_IPV4:begin
result:=AF_INET;
end;
ENET_IPV6:begin
result:=AF_INET6;
end;
else begin
result:=0;
end;
end;
end;
function enet_sa_size(family:TENetAddressFamily):longint;
begin
case family of
ENET_IPV4:begin
result:=sizeof(sockaddr_in);
end;
ENET_IPV6:begin
result:=sizeof(sockaddr_in6);
end;
else begin
result:=0;
end;
end;
end;
function enet_address_set_address(address:PENetAddress;sin:pointer):TENetAddressFamily;
begin
FillChar(address^,SizeOf(TENetAddress),AnsiChar(#0));
case sockaddr_in(sin)^.sin_family of
AF_INET:begin
address^.host:=enet_address_map4(sockaddr_in(sin)^.sin_addr.S_addr);
address^.scopeID:=0;
address^.port:=ENET_NET_TO_HOST_16(sockaddr_in(sin)^.sin_port);
result:=ENET_IPV4;
end;
AF_INET6:begin
address^.host:=PENetHostAddress(pointer(@sockaddr_in6(sin)^.sin6_addr))^;
address^.scopeID:=sockaddr_in6(sin)^.sin6_scope_id;
address^.port:=ENET_NET_TO_HOST_16(sockaddr_in6(sin)^.sin6_port);
result:=ENET_IPV6;
end;
else begin
result:=ENET_NO_ADDRESS_FAMILY;
end;
end;
end;
function enet_address_set_sin(sin:pointer;address:PENetAddress;family:TENetAddressFamily):longint;
begin
FillChar(sin^,enet_sa_size(family),AnsiChar(#0));
if (family=ENET_IPV4) and ((enet_get_address_family(address)=ENET_IPV4) or
((address^.host.addr[0]=ENET_HOST_ANY.addr[0]) and
(address^.host.addr[1]=ENET_HOST_ANY.addr[1]) and
(address^.host.addr[2]=ENET_HOST_ANY.addr[2]) and
(address^.host.addr[3]=ENET_HOST_ANY.addr[3]) and
(address^.host.addr[4]=ENET_HOST_ANY.addr[4]) and
(address^.host.addr[5]=ENET_HOST_ANY.addr[5]) and
(address^.host.addr[6]=ENET_HOST_ANY.addr[6]) and
(address^.host.addr[7]=ENET_HOST_ANY.addr[7]) and
(address^.host.addr[8]=ENET_HOST_ANY.addr[8]) and
(address^.host.addr[9]=ENET_HOST_ANY.addr[9]) and
(address^.host.addr[10]=ENET_HOST_ANY.addr[10]) and
(address^.host.addr[11]=ENET_HOST_ANY.addr[11]) and
(address^.host.addr[12]=ENET_HOST_ANY.addr[12]) and
(address^.host.addr[13]=ENET_HOST_ANY.addr[13]) and
(address^.host.addr[14]=ENET_HOST_ANY.addr[14]) and
(address^.host.addr[15]=ENET_HOST_ANY.addr[15]))) then begin
sockaddr_in(sin)^.sin_family:=AF_INET;
sockaddr_in(sin)^.sin_addr.S_addr:=longword(pointer(@address^.host.addr[12])^);
sockaddr_in(sin)^.sin_port:=ENET_HOST_TO_NET_16(address^.port);
result:=0;
end else if family=ENET_IPV6 then begin
sockaddr_in6(sin)^.sin6_family:=AF_INET6;
PENetHostAddress(pointer(@sockaddr_in6(sin)^.sin6_addr))^:=address^.host;
sockaddr_in6(sin)^.sin6_scope_id:=address^.scopeID;
sockaddr_in6(sin)^.sin6_port:=ENET_HOST_TO_NET_16(address^.port);
result:=0;
end else begin
result:=-1;
end;
end;
function enet_address_set_host(address:PENetAddress;name:PAnsiChar):longint;
var port:word;
Hints:TAddrInfo;
r,res:PAddrInfo;
begin
port:=address^.port;
FillChar(Hints,SizeOf(TAddrInfo),AnsiChar(#0));
hints.ai_flags:=AI_ADDRCONFIG;
hints.ai_family:=AF_UNSPEC;
if getaddrinfo(name,nil,@hints,@r)=0 then begin
result:=-1;
exit;
end;
res:=r;
while assigned(res) do begin
if enet_address_set_address(address,res^.ai_addr)<>ENET_NO_ADDRESS_FAMILY then begin
break;
end;
res:=res^.ai_next;
end;
address^.port:=port;
freeaddrinfo(r);
if not assigned(res) then begin
result:=-1;
exit;
end;
result:=0;
end;
function enet_address_get_host_x(address:PENetAddress;name:PAnsiChar;nameLength:longint;flags:longint):longint;
var sin:TSockaddrStorage;
begin
enet_address_set_sin(@sin,address,ENET_IPV6);
if getnameinfo(pointer(@sin),enet_sa_size(ENET_IPV6),name,nameLength,nil,0,flags)=0 then begin
result:=-1;
exit;
end;
result:=0;
end;
function enet_address_get_host_ip(address:PENetAddress;name:PAnsiChar;nameLength:longint):longint;
begin
result:=enet_address_get_host_x(address,name,nameLength,NI_NUMERICHOST);
end;
function enet_address_get_host(address:PENetAddress;name:PAnsiChar;nameLength:longint):longint;
begin
result:=enet_address_get_host_x(address,name,nameLength,0);
end;
function enet_socket_bind(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):longint;
var sin:TSockaddrStorage;
address_:TENetAddress;
begin
if assigned(address) then begin
enet_address_set_sin(pointer(@sin),address,family);
end else begin
address_.host:=ENET_HOST_ANY_INIT;
address_.scopeID:=0;
address_.port:=0;
enet_address_set_sin(pointer(@sin),@address_,family);
end;
if fpbind(socket,pointer(@sin),enet_sa_size(family))=SOCKET_ERROR then begin
result:=-1;
end else begin
result:=0;
end;
end;
function enet_socket_get_address(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):longint;
var sin:TSockaddrStorage;
sinLength:longint;
addressTemp:TENetAddress;
begin
sinLength:=enet_sa_size(family);
if fpgetsockname(socket,pointer(@sin),sinLength)=-1 then begin
result:=-1;
end else begin
if enet_address_set_address(@addressTemp,pointer(@sin))=ENET_NO_ADDRESS_FAMILY then begin
result:=-1;
end else begin
address^:=addressTemp;
result:=0;
end;
end;
end;
function enet_socket_listen(socket:TENetSocket;backlog:longint):longint;
begin
if backlog<0 then begin
backlog:=SOMAXCONN;
end;
if fplisten(socket,backlog)=SOCKET_ERROR then begin
result:=-1;
end else begin
result:=0;
end;
end;
function enet_socket_create(type_:TENetSocketType;family:TENetAddressFamily):TENetSocket;
begin
if type_=ENET_SOCKET_TYPE_DATAGRAM then begin
result:=fpsocket(enet_af(family),SOCK_DGRAM,0);
end else begin
result:=fpsocket(enet_af(family),SOCK_STREAM,0);
end;
end;
function enet_socket_set_option(socket:TENetSocket;option:TENetSocketOption;value:longint):longint;
var nonBlocking:longword;
tv:TTimeVal;
begin
result:=SOCKET_ERROR;
case option of
ENET_SOCKOPT_NONBLOCK:begin
nonBlocking:=value;
result:=fpioctl(socket,FIONBIO,pointer(@nonBlocking));
end;
ENET_SOCKOPT_BROADCAST:begin
result:=fpsetsockopt(socket,SOL_SOCKET,SO_BROADCAST,pointer(@value),SizeOf(longint));
end;
ENET_SOCKOPT_REUSEADDR:begin
result:=fpsetsockopt(socket,SOL_SOCKET,SO_REUSEADDR,pointer(@value),SizeOf(longint));
end;
ENET_SOCKOPT_RCVBUF:begin
result:=fpsetsockopt(socket,SOL_SOCKET,SO_RCVBUF,pointer(@value),SizeOf(longint));
end;
ENET_SOCKOPT_SNDBUF:begin
result:=fpsetsockopt(socket,SOL_SOCKET,SO_SNDBUF,pointer(@value),SizeOf(longint));
end;
ENET_SOCKOPT_RCVTIMEO:begin
tv.tv_sec:=Value div 1000;
tv.tv_usec:=(Value mod 1000)*1000;
result:=fpsetsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,pointer(@tv),SizeOf(TTimeVal));
end;
ENET_SOCKOPT_SNDTIMEO:begin
tv.tv_sec:=Value div 1000;
tv.tv_usec:=(Value mod 1000)*1000;
result:=fpsetsockopt(socket,SOL_SOCKET,SO_SNDTIMEO,pointer(@tv),SizeOf(TTimeVal));
end;
ENET_SOCKOPT_NODELAY:begin
result:=fpsetsockopt(socket,IPPROTO_TCP,TCP_NODELAY,pointer(@value),SizeOf(longint));
end;
end;
if result=SOCKET_ERROR then begin
result:=-1;
end else begin
result:=0;
end;
end;
function enet_socket_get_option(socket:TENetSocket;option:TENetSocketOption;var value:longint):longint;
var nonBlocking:longword;
begin
result:=SOCKET_ERROR;
case option of
ENET_SOCKOPT_ERROR:begin
result:=fpgetsockopt(socket,SOL_SOCKET,SO_ERROR,pointer(@value),SizeOf(longint));
end;
end;
if result=SOCKET_ERROR then begin
result:=-1;
end else begin
result:=0;
end;
end;
function enet_socket_shutdown(socket:TENetSocket;how:TENetSocketShutdown):longint;
begin
result:=fpshutdown(socket,how);
end;
function enet_socket_connect(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):longint;
var sin:TSockaddrStorage;
begin
enet_address_set_sin(pointer(@sin),address,family);
result:=fpconnect(socket,pointer(@sin),enet_sa_size(family));
if (result=SOCKET_ERROR) and (fpgeterrno=EINPROGRESS) then begin
result:=0;
end;
end;
function enet_socket_accept(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):TENetSocket;
var sin:TSockaddrStorage;
sinLength:longint;
begin
sinLength:=enet_sa_size(family);
if assigned(address) then begin
result:=fpaccept(socket,TSockAddr(pointer(@sin)^),sinLength);
end else begin
result:=fpaccept(socket,TSockAddr(pointer(nil)^),longint(pointer(nil)^));
end;
if result=INVALID_SOCKET then begin
result:=ENET_SOCKET_NULL;
exit;
end;
if assigned(address) then begin
enet_address_set_address(address,pointer(@sin));
end;
end;
procedure enet_socket_destroy(socket:TENetSocket);
begin
if socket<>INVALID_SOCKET then begin
CloseSocket(socket);
end;
end;
function enet_socket_send(socket:TENetSocket;address:PENetAddress;buffers:PENetBuffer;bufferCount:longword;family:TENetAddressFamily):longint;
var sin:TSockaddrStorage;
sentLength:longint;
begin
if assigned(address) then begin
enet_address_set_sin(pointer(@sin),address,family);
sentLength:=fpSendTo(socket,pointer(buffers),bufferCount,MSG_NOSIGNAL,pointer(@sin),enet_sa_size(family));
if sentLength=SOCKET_ERROR then begin
if socketerror=EsockEWOULDBLOCK then begin
result:=0;
end else begin
result:=-1;
end;
exit;
end;
end else begin
sentLength:=fpSendTo(socket,pointer(buffers),bufferCount,MSG_NOSIGNAL,nil,0);
if sentLength=SOCKET_ERROR then begin
if socketerror=EsockEWOULDBLOCK then begin
result:=0;
end else begin
result:=-1;
end;
exit;
end;
end;
result:=sentLength;
end;
function enet_socket_receive(socket:TENetSocket;address:PENetAddress;buffers:PENetBuffer;bufferCount:longword;family:TENetAddressFamily):longint;
var sin:TSockaddrStorage;
sinLength,recvLength:longint;
begin
sinLength:=enet_sa_size(family);
flags:=0;
recvLength:=0;
if assigned(address) then begin
recvLength:=fpRecvFrom(socket,pointer(buffers),bufferCount,MSG_NOSIGNAL,pointer(@sin),@sinLength);
if recvLength=SOCKET_ERROR then begin
case sockerror of
EsockEWOULDBLOCK{,EsockECONNRESET}:begin
result:=0;
end;
else begin
result:=-1;
end;
end;
exit;
end;
end else begin
recvLength:=fpRecvFrom(socket,pointer(buffers),bufferCount,MSG_NOSIGNAL,nil,nil);
if recvLength=SOCKET_ERROR then begin
case WSAGetLastError of
EsockEWOULDBLOCK{,EsockECONNRESET}:begin
result:=0;
end;
else begin
result:=-1;
end;
end;
exit;
end;
end;
{if (flags and MSG_PARTIAL)<>0 then begin
result:=-1;
exit;
end;}
if assigned(address) then begin
enet_address_set_address(address,pointer(@sin));
end;
result:=recvLength;
end;
function enet_socketset_select(maxSocket:TENetSocket;readSet,writeSet:PENetSocketSet;timeout:longword):longint;
var tv:TTimeVal;
begin
tv.tv_sec:=timeout div 1000;
tv.tv_usec:=(timeout mod 1000)*1000;
result:=fpselect(maxSocket+1,@readSet,@writeSet,nil,@tv);
end;
function enet_socket_wait(socket4,socket6:TENetSocket;condition:pointer;timeout:longword):longint;
var readSet,writeSet:TFDSet;
tv:TTimeVal;
selectCount:longint;
maxSocket:TENetSocket;
begin
tv.tv_sec:=timeout div 1000;
tv.tv_usec:=(timeout mod 1000)*1000;
{$ifdef unix}
fpFD_ZERO(readSet);
fpFD_ZERO(writeSet);
{$else}
FD_ZERO(readSet);
FD_ZERO(writeSet);
{$endif}
if (longword(condition^) and ENET_SOCKET_WAIT_SEND)<>0 then begin
if socket4<>ENET_SOCKET_NULL then begin
{$ifdef unix}
fpFD_SET(socket4,writeSet);
{$else}
FD_SET(socket4,writeSet);
{$endif}
end;
if socket6<>ENET_SOCKET_NULL then begin
{$ifdef unix}
fpFD_SET(socket6,writeSet);
{$else}
FD_SET(socket6,writeSet);
{$endif}
end;
end;
if (longword(condition^) and ENET_SOCKET_WAIT_RECEIVE)<>0 then begin
if socket4<>ENET_SOCKET_NULL then begin
{$ifdef unix}
fpFD_SET(socket4,readSet);
{$else}
FD_SET(socket4,readSet);
{$endif}
end;
if socket6<>ENET_SOCKET_NULL then begin
{$ifdef unix}
fpFD_SET(socket6,readSet);
{$else}
FD_SET(socket6,readSet);
{$endif}
end;
end;
if socket4<>ENET_SOCKET_NULL then begin
maxSocket:=socket4;
end else begin
maxSocket:=0;
end;
if (socket6<>ENET_SOCKET_NULL) and (maxSocket<socket6) then begin
maxSocket:=socket6;
end;
selectCount:=fpselect(maxSocket+1,@readSet,@writeSet,nil,@tv);
if selectCount<0 then begin
if (errno=EINTR) and ((longword(condition^) and ENET_SOCKET_WAIT_INTERRUPT)<>0) then begin
longword(condition^):=ENET_SOCKET_WAIT_INTERRUPT;
result:=0;
end else begin
result:=-1;
end;
exit;
end;
longword(condition^):=ENET_SOCKET_WAIT_NONE;
if selectCount=0 then begin
result:=0;
exit;
end;
if ((socket4<>ENET_SOCKET_NULL) and FD_ISSET(socket4,writeSet)) or ((socket6<>ENET_SOCKET_NULL) and FD_ISSET(socket6,writeSet)) then begin
longword(condition^):=longword(condition^) or ENET_SOCKET_WAIT_SEND;
end;
if ((socket4<>ENET_SOCKET_NULL) and FD_ISSET(socket4,readSet)) or ((socket6<>ENET_SOCKET_NULL) and FD_ISSET(socket6,readSet)) then begin
longword(condition^):=longword(condition^) or ENET_SOCKET_WAIT_RECEIVE;
end;
result:=0;
end;
{$else}
const AF_UNSPEC=0;
AF_INET=2;
AF_INET6=23;
AF_MAX=24;
NI_NUMERICHOST=$2;
type TInAddr=packed record
case longint of
0:(
S_bytes:packed array [0..3] of byte;
);
1:(
S_addr:longword;
);
end;
PSockAddrIn=^TSockAddrIn;
TSockAddrIn=record
case longint of
0:(
sin_family:word;
sin_port:word;
sin_addr:TInAddr;
sin_zero:array[0..7] of byte;
);
1:(
sa_family:word;
sa_data:array[0..13] of byte;
);
end;
PInAddr6=^TInAddr6;
TInAddr6=packed record
case integer of
0:(
S6_addr:packed array [0..15] of shortint;
);
1:(
u6_addr8:packed array [0..15] of byte;
);
2:(
u6_addr16:packed array [0..7] of word;
);
3:(
u6_addr32:packed array [0..3] of longword;
);
end;
PSockAddrIn6=^TSockAddrIn6;
TSockAddrIn6=packed record
sin6_family:word;
sin6_port:word;
sin6_flowinfo:longword;
sin6_addr:TInAddr6;
sin6_scope_id:longword;
end;
PPAddrInfo=^PAddrInfo;
PAddrInfo=^TAddrInfo;
TAddrInfo=packed record
ai_flags:longint;
ai_family:longint;
ai_socktype:longint;
ai_protocol:longint;
ai_addrlen:longword;
ai_canonname:PAnsiChar;
ai_addr:PSockAddr;
ai_next:PAddrInfo;
end;
PSockaddrStorage=^TSockaddrStorage;
TSockaddrStorage=record
ss_family:word;
_ss_pad1:array[0..5] of byte;
_ss_align:int64;
_ss_pad2:array[0..119] of byte;
end;
TGetAddrInfo=function(NodeName:PAnsiChar;ServName:PAnsiChar;Hints:PAddrInfo;Addrinfo:PPAddrInfo):longint; stdcall;
TFreeAddrInfo=procedure(ai:PAddrInfo); stdcall;
TGetNameInfo=function(addr:PSockAddr;namelen:Integer;host:PAnsiChar;hostlen:longword;serv:PAnsiChar;servlen:longword;flags:longint):longint; stdcall;
const GetAddrInfo:TGetAddrInfo=nil;
FreeAddrInfo:TFreeAddrInfo=nil;
GetNameInfo:TGetNameInfo=nil;
LibHandle:THandle=0;
function enet_initialize:longint;
var versionRequested:word;
vWSAData:TWSAData;
begin
LibHandle:=0;
versionRequested:=MAKEWORD(2,2);
if WSAStartup(versionRequested,vWSAData)<>0 then begin
result:=-1;
exit;
end;
LibHandle:=LoadLibrary(PChar('ws2_32.dll'));
if (LibHandle=0) or ((LOBYTE(vWSAData.wVersion)<>2) or (HIBYTE(vWSAData.wVersion)<>2)) then begin
WSACleanup;
result:=-1;
exit;
end;
GetAddrInfo:=GetProcAddress(LibHandle,PAnsiChar(AnsiString('getaddrinfo')));
FreeAddrInfo:=GetProcAddress(LibHandle,PAnsiChar(AnsiString('freeaddrinfo')));
GetNameInfo:=GetProcAddress(LibHandle,PAnsiChar(AnsiString('getnameinfo')));
if not (assigned(GetAddrInfo) and assigned(FreeAddrInfo) and assigned(GetNameInfo)) then begin
FreeLibrary(LibHandle);
LibHandle:=LoadLibrary(PChar('wship6.dll'));
GetAddrInfo:=GetProcAddress(LibHandle,PAnsiChar(AnsiString('getaddrinfo')));
FreeAddrInfo:=GetProcAddress(LibHandle,PAnsiChar(AnsiString('freeaddrinfo')));
GetNameInfo:=GetProcAddress(LibHandle,PAnsiChar(AnsiString('getnameinfo')));
if not (assigned(GetAddrInfo) and assigned(FreeAddrInfo) and assigned(GetNameInfo)) then begin
FreeLibrary(LibHandle);
LibHandle:=0;
WSACleanup;
result:=-1;
exit;
end;
end;
timeBeginPeriod(1);
result:=0;
end;
procedure enet_deinitialize;
begin
FreeLibrary(LibHandle);
timeEndPeriod(1);
WSACleanup;
end;
function enet_host_random_seed:longword;
begin
result:=timeGetTime-timeBase;
end;
function enet_time_get:longword;
begin
result:=timeGetTime-timeBase;
end;
procedure enet_time_set(newTimeBase:longword);
begin
timeBase:=timeGetTime-newTimeBase;
end;
function enet_af(family:TENetAddressFamily):word;
begin
case family of
ENET_IPV4:begin
result:=AF_INET;
end;
ENET_IPV6:begin
result:=AF_INET6;
end;
else begin
result:=0;
end;
end;
end;
function enet_sa_size(family:TENetAddressFamily):longint;
begin
case family of
ENET_IPV4:begin
result:=sizeof(TSockAddrIn);
end;
ENET_IPV6:begin
result:=sizeof(TSockAddrIn6);
end;
else begin
result:=0;
end;
end;
end;
function enet_address_set_address(address:PENetAddress;sin:pointer):TENetAddressFamily;
begin
FillChar(address^,SizeOf(TENetAddress),AnsiChar(#0));
case PSockAddrIn(sin)^.sin_family of
AF_INET:begin
address^.host:=enet_address_map4(PSockAddrIn(sin)^.sin_addr.S_addr);
address^.scopeID:=0;
address^.port:=ENET_NET_TO_HOST_16(PSockAddrIn(sin)^.sin_port);
result:=ENET_IPV4;
end;
AF_INET6:begin
address^.host:=PENetHostAddress(pointer(@PSockAddrIn6(sin)^.sin6_addr))^;
address^.scopeID:=PSockAddrIn6(sin)^.sin6_scope_id;
address^.port:=ENET_NET_TO_HOST_16(PSockAddrIn6(sin)^.sin6_port);
result:=ENET_IPV6;
end;
else begin
result:=ENET_NO_ADDRESS_FAMILY;
end;
end;
end;
function enet_address_set_sin(sin:pointer;address:PENetAddress;family:TENetAddressFamily):longint;
begin
FillChar(sin^,enet_sa_size(family),AnsiChar(#0));
if (family=ENET_IPV4) and ((enet_get_address_family(address)=ENET_IPV4) or
((address^.host.addr[0]=ENET_HOST_ANY.addr[0]) and
(address^.host.addr[1]=ENET_HOST_ANY.addr[1]) and
(address^.host.addr[2]=ENET_HOST_ANY.addr[2]) and
(address^.host.addr[3]=ENET_HOST_ANY.addr[3]) and
(address^.host.addr[4]=ENET_HOST_ANY.addr[4]) and
(address^.host.addr[5]=ENET_HOST_ANY.addr[5]) and
(address^.host.addr[6]=ENET_HOST_ANY.addr[6]) and
(address^.host.addr[7]=ENET_HOST_ANY.addr[7]) and
(address^.host.addr[8]=ENET_HOST_ANY.addr[8]) and
(address^.host.addr[9]=ENET_HOST_ANY.addr[9]) and
(address^.host.addr[10]=ENET_HOST_ANY.addr[10]) and
(address^.host.addr[11]=ENET_HOST_ANY.addr[11]) and
(address^.host.addr[12]=ENET_HOST_ANY.addr[12]) and
(address^.host.addr[13]=ENET_HOST_ANY.addr[13]) and
(address^.host.addr[14]=ENET_HOST_ANY.addr[14]) and
(address^.host.addr[15]=ENET_HOST_ANY.addr[15]))) then begin
PSockAddrIn(sin)^.sin_family:=AF_INET;
PSockAddrIn(sin)^.sin_addr.S_addr:=longword(pointer(@address^.host.addr[12])^);
PSockAddrIn(sin)^.sin_port:=ENET_HOST_TO_NET_16(address^.port);
result:=0;
end else if family=ENET_IPV6 then begin
PSockAddrIn6(sin)^.sin6_family:=AF_INET6;
PENetHostAddress(pointer(@PSockAddrIn6(sin)^.sin6_addr))^:=address^.host;
PSockAddrIn6(sin)^.sin6_scope_id:=address^.scopeID;
PSockAddrIn6(sin)^.sin6_port:=ENET_HOST_TO_NET_16(address^.port);
result:=0;
end else begin
result:=-1;
end;
end;
function enet_address_set_host(address:PENetAddress;name:PAnsiChar):longint;
var port:word;
Hints:TAddrInfo;
r,res:PAddrInfo;
begin
port:=address^.port;
FillChar(Hints,SizeOf(TAddrInfo),AnsiChar(#0));
hints.ai_flags:=AI_ADDRCONFIG;
hints.ai_family:=AF_UNSPEC;
if getaddrinfo(name,nil,@hints,@r)=0 then begin
result:=-1;
exit;
end;
res:=r;
while assigned(res) do begin
if enet_address_set_address(address,res^.ai_addr)<>ENET_NO_ADDRESS_FAMILY then begin
break;
end;
res:=res^.ai_next;
end;
address^.port:=port;
freeaddrinfo(r);
if not assigned(res) then begin
result:=-1;
exit;
end;
result:=0;
end;
function enet_address_get_host_x(address:PENetAddress;name:PAnsiChar;nameLength:longint;flags:longint):longint;
var sin:TSockaddrStorage;
begin
enet_address_set_sin(@sin,address,ENET_IPV6);
if getnameinfo(pointer(@sin),enet_sa_size(ENET_IPV6),name,nameLength,nil,0,flags)=0 then begin
result:=-1;
exit;
end;
result:=0;
end;
function enet_address_get_host_ip(address:PENetAddress;name:PAnsiChar;nameLength:longint):longint;
begin
result:=enet_address_get_host_x(address,name,nameLength,NI_NUMERICHOST);
end;
function enet_address_get_host(address:PENetAddress;name:PAnsiChar;nameLength:longint):longint;
begin
result:=enet_address_get_host_x(address,name,nameLength,0);
end;
function enet_socket_bind(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):longint;
var sin:TSockaddrStorage;
address_:TENetAddress;
begin
if assigned(address) then begin
enet_address_set_sin(pointer(@sin),address,family);
end else begin
address_.host:=ENET_HOST_ANY_INIT;
address_.scopeID:=0;
address_.port:=0;
enet_address_set_sin(pointer(@sin),@address_,family);
end;
if bind(socket,pointer(@sin),enet_sa_size(family))=SOCKET_ERROR then begin
result:=-1;
end else begin
result:=0;
end;
end;
function enet_socket_get_address(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):longint;
var sin:TSockaddrStorage;
sinLength:longint;
addressTemp:TENetAddress;
begin
sinLength:=enet_sa_size(family);
if getsockname(socket,TSockAddr(pointer(@sin)^),sinLength)=-1 then begin
result:=-1;
end else begin
if enet_address_set_address(@addressTemp,pointer(@sin))=ENET_NO_ADDRESS_FAMILY then begin
result:=-1;
end else begin
address^:=addressTemp;
result:=0;
end;
end;
end;
function enet_socket_listen(socket:TENetSocket;backlog:longint):longint;
begin
if backlog<0 then begin
backlog:=SOMAXCONN;
end;
if listen(socket,backlog)=SOCKET_ERROR then begin
result:=-1;
end else begin
result:=0;
end;
end;
function enet_socket_create(type_:TENetSocketType;family:TENetAddressFamily):TENetSocket;
begin
if type_=ENET_SOCKET_TYPE_DATAGRAM then begin
result:=socket(enet_af(family),SOCK_DGRAM,0);
end else begin
result:=socket(enet_af(family),SOCK_STREAM,0);
end;
end;
function enet_socket_set_option(socket:TENetSocket;option:TENetSocketOption;value:longint):longint;
var nonBlocking:longword;
begin
result:=SOCKET_ERROR;
case option of
ENET_SOCKOPT_NONBLOCK:begin
nonBlocking:=value;
result:=ioctlsocket(socket,FIONBIO,nonBlocking);
end;
ENET_SOCKOPT_BROADCAST:begin
result:=setsockopt(socket,SOL_SOCKET,SO_BROADCAST,pointer(@value),SizeOf(longint));
end;
ENET_SOCKOPT_REUSEADDR:begin
result:=setsockopt(socket,SOL_SOCKET,SO_REUSEADDR,pointer(@value),SizeOf(longint));
end;
ENET_SOCKOPT_RCVBUF:begin
result:=setsockopt(socket,SOL_SOCKET,SO_RCVBUF,pointer(@value),SizeOf(longint));
end;
ENET_SOCKOPT_SNDBUF:begin
result:=setsockopt(socket,SOL_SOCKET,SO_SNDBUF,pointer(@value),SizeOf(longint));
end;
ENET_SOCKOPT_RCVTIMEO:begin
result:=setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,pointer(@value),SizeOf(longint));
end;
ENET_SOCKOPT_SNDTIMEO:begin
result:=setsockopt(socket,SOL_SOCKET,SO_SNDTIMEO,pointer(@value),SizeOf(longint));
end;
ENET_SOCKOPT_NODELAY:begin
result:=setsockopt(socket,IPPROTO_TCP,TCP_NODELAY,pointer(@value),SizeOf(longint));
end;
end;
if result=SOCKET_ERROR then begin
result:=-1;
end else begin
result:=0;
end;
end;
function enet_socket_get_option(socket:TENetSocket;option:TENetSocketOption;var value:longint):longint;
var nonBlocking:longword;
begin
result:=SOCKET_ERROR;
case option of
ENET_SOCKOPT_ERROR:begin
result:=setsockopt(socket,SOL_SOCKET,SO_ERROR,pointer(@value),SizeOf(longint));
end;
end;
if result=SOCKET_ERROR then begin
result:=-1;
end else begin
result:=0;
end;
end;
function enet_socket_shutdown(socket:TENetSocket;how:TENetSocketShutdown):longint;
begin
if shutdown(socket,how)=SOCKET_ERROR then begin
result:=-1;
end else begin
result:=0;
end;
end;
function enet_socket_connect(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):longint;
var sin:TSockaddrStorage;
begin
enet_address_set_sin(pointer(@sin),address,family);
result:=connect(socket,pointer(@sin),enet_sa_size(family));
if (result=SOCKET_ERROR) and (WSAGetLastError<>WSAEWOULDBLOCK) then begin
result:=-1;
end else begin
result:=0;
end;
end;
function enet_socket_accept(socket:TENetSocket;address:PENetAddress;family:TENetAddressFamily):TENetSocket;
var sin:TSockaddrStorage;
sinLength:longint;
begin
sinLength:=enet_sa_size(family);
if assigned(address) then begin
result:=accept(socket,TSockAddr(pointer(@sin)^),sinLength);
end else begin
result:=accept(socket,TSockAddr(pointer(nil)^),longint(pointer(nil)^));
end;
if result=INVALID_SOCKET then begin
result:=ENET_SOCKET_NULL;
exit;
end;
if assigned(address) then begin
enet_address_set_address(address,pointer(@sin));
end;
end;
procedure enet_socket_destroy(socket:TENetSocket);
begin
if socket<>INVALID_SOCKET then begin
closesocket(socket);
end;
end;
function enet_socket_send(socket:TENetSocket;address:PENetAddress;buffers:PENetBuffer;bufferCount:longword;family:TENetAddressFamily):longint;
var sin:TSockaddrStorage;
sentLength:longword;
begin
if assigned(address) then begin
enet_address_set_sin(pointer(@sin),address,family);
if WSASendTo(socket,LPWSABUF(buffers),bufferCount,sentLength,0,pointer(@sin),enet_sa_size(family),nil,nil)=SOCKET_ERROR then begin
if WSAGetLastError=WSAEWOULDBLOCK then begin
result:=0;
end else begin
result:=-1;
end;
exit;
end;
end else begin
if WSASendTo(socket,LPWSABUF(buffers),bufferCount,sentLength,0,nil,0,nil,nil)=SOCKET_ERROR then begin
if WSAGetLastError=WSAEWOULDBLOCK then begin
result:=0;
end else begin
result:=-1;
end;
exit;
end;
end;
result:=sentLength;
end;
function enet_socket_receive(socket:TENetSocket;address:PENetAddress;buffers:PENetBuffer;bufferCount:longword;family:TENetAddressFamily):longint;
var sin:TSockaddrStorage;
sinLength:longint;
flags,recvLength:longword;
begin
sinLength:=enet_sa_size(family);
flags:=0;
if assigned(address) then begin
if WSARecvFrom(socket,LPWSABUF(buffers),bufferCount,recvLength,flags,pointer(@sin),@sinLength,nil,nil)=SOCKET_ERROR then begin
case WSAGetLastError of
WSAEWOULDBLOCK,WSAECONNRESET:begin
result:=0;
end;
else begin
result:=-1;
end;
end;
exit;
end;
end else begin
if WSARecvFrom(socket,LPWSABUF(buffers),bufferCount,recvLength,flags,nil,nil,nil,nil)=SOCKET_ERROR then begin
case WSAGetLastError of
WSAEWOULDBLOCK,WSAECONNRESET:begin
result:=0;
end;
else begin
result:=-1;
end;
end;
exit;
end;
end;
if (flags and MSG_PARTIAL)<>0 then begin
result:=-1;
exit;
end;
if assigned(address) then begin
enet_address_set_address(address,pointer(@sin));
end;
result:=recvLength;
end;
function enet_socketset_select(maxSocket:TENetSocket;readSet,writeSet:PENetSocketSet;timeout:longword):longint;
var tv:TTimeVal;
begin
tv.tv_sec:=timeout div 1000;
tv.tv_usec:=(timeout mod 1000)*1000;
result:=select(maxSocket+1,@readSet,@writeSet,nil,@tv);
end;
function enet_socket_wait(socket4,socket6:TENetSocket;condition:pointer;timeout:longword):longint;
var readSet,writeSet:TFDSet;
tv:TTimeVal;
selectCount:longint;
maxSocket:TENetSocket;
begin
tv.tv_sec:=timeout div 1000;
tv.tv_usec:=(timeout mod 1000)*1000;
FD_ZERO(readSet);
FD_ZERO(writeSet);
if (longword(condition^) and ENET_SOCKET_WAIT_SEND)<>0 then begin
if socket4<>ENET_SOCKET_NULL then begin
FD_SET(socket4,writeSet);
end;
if socket6<>ENET_SOCKET_NULL then begin
FD_SET(socket6,writeSet);
end;
end;
if (longword(condition^) and ENET_SOCKET_WAIT_RECEIVE)<>0 then begin
if socket4<>ENET_SOCKET_NULL then begin
FD_SET(socket4,readSet);
end;
if socket6<>ENET_SOCKET_NULL then begin
FD_SET(socket6,readSet);
end;
end;
if socket4<>ENET_SOCKET_NULL then begin
maxSocket:=socket4;
end else begin
maxSocket:=0;
end;
if (socket6<>ENET_SOCKET_NULL) and (maxSocket<socket6) then begin
maxSocket:=socket6;
end;
selectCount:=select(maxSocket+1,@readSet,@writeSet,nil,@tv);
if selectCount<0 then begin
result:=-1;
exit;
end;
longword(condition^):=ENET_SOCKET_WAIT_NONE;
if selectCount=0 then begin
result:=0;
exit;
end;
if ((socket4<>ENET_SOCKET_NULL) and FD_ISSET(socket4,writeSet)) or ((socket6<>ENET_SOCKET_NULL) and FD_ISSET(socket6,writeSet)) then begin
longword(condition^):=longword(condition^) or ENET_SOCKET_WAIT_SEND;
end;
if ((socket4<>ENET_SOCKET_NULL) and FD_ISSET(socket4,readSet)) or ((socket6<>ENET_SOCKET_NULL) and FD_ISSET(socket6,readSet)) then begin
longword(condition^):=longword(condition^) or ENET_SOCKET_WAIT_RECEIVE;
end;
result:=0;
end;
{$endif}
function enet_linked_version:TENetVersion;
begin
result:=ENET_VERSION;
end;
type PENetSymbol=^TENetSymbol;
TENetSymbol=record
value:byte;
count:byte;
under:word;
left:word;
right:word;
symbols:word;
escapes:word;
total:word;
parent:word;
end;
PENetSymbols=^TENetSymbols;
TENetSymbols=array[0..0] of TENetSymbol;
const ENET_RANGE_CODER_TOP=1 shl 24;
ENET_RANGE_CODER_BOTTOM=1 shl 16;
ENET_CONTEXT_SYMBOL_DELTA=3;
ENET_CONTEXT_SYMBOL_MINIMUM=1;
ENET_CONTEXT_ESCAPE_MINIMUM=1;
ENET_SUBCONTEXT_ORDER=2;
ENET_SUBCONTEXT_SYMBOL_DELTA=2;
ENET_SUBCONTEXT_ESCAPE_DELTA=5;
type PENetRangeCoder=^TENetRangeCoder;
TENetRangeCoder=record
symbols:array[0..4092] of TENetSymbol;
end;
function enet_range_coder_create:PENetRangeCoder;
begin
GetMem(result,sizeof(TENetRangeCoder));
end;
procedure enet_range_coder_destroy(context:pointer);
begin
if not assigned(context) then begin
FreeMem(context);
end;
end;
procedure ENET_SYMBOL_CREATE(rangeCoder:PENetRangeCoder;symbol:PENetSymbol;value_,count_:word;var nextSymbol:longint);
begin
symbol:=@rangeCoder^.symbols[nextSymbol];
inc(nextSymbol);
symbol^.value:=value_;
symbol^.count:=count_;
symbol^.under:=count_;
symbol^.left:=0;
symbol^.right:=0;
symbol^.symbols:=0;
symbol^.escapes:=0;
symbol^.total:=0;
symbol^.parent:=0;
end;
procedure ENET_CONTEXT_CREATE(rangecoder:PENetRangeCoder;context:PENetSymbol;escapes,minimum:word;var nextSymbol:longint);
begin
ENET_SYMBOL_CREATE(rangecoder,context,0,0,nextSymbol);
context^.escapes:=escapes;
context^.total:=escapes+(256*minimum);
context^.symbols:=0;
end;
function enet_symbol_rescale(symbol:PENetSymbol):word;
begin
result:=0;
while true do begin
dec(symbol^.count,symbol^.count shr 1);
symbol^.under:=symbol^.count;
if symbol^.left<>0 then begin
inc(symbol^.under,enet_symbol_rescale(@PENetSymbols(symbol)^[symbol^.left]));
end;
inc(result,symbol^.under);
if symbol^.right=0 then begin
break;
end;
inc(symbol,symbol^.right);
end;
end;
procedure ENET_CONTEXT_RESCALE(context:PENetSymbol;minimum:word);
begin
if context^.symbols<>0 then begin
context^.total:=enet_symbol_rescale(@PENetSymbols(pointer(context))^[context^.symbols]);
end else begin
context^.total:=0;
end;
dec(context^.escapes,context^.escapes shr 1);
inc(context^.total,context^.escapes+(256*minimum));
end;
function ENET_RANGE_CODER_OUTPUT(var outData:pbyte;outEnd:pbyte;value:byte):boolean;
begin
result:=false;
if ptruint(outData)>=ptruint(outEnd) then begin
exit;
end;
outData^:=value;
inc(outData);
result:=true;
end;
function ENET_RANGE_CODER_ENCODE(var outData:pbyte;outEnd:pbyte;var encodeLow,encodeRange:longword;under,count,total:word):boolean;
begin
result:=false;
encodeRange:=encodeRange div total;
inc(encodeLow,under*encodeRange);
encodeRange:=encodeRange*count;
while true do begin
if (encodeLow xor (encodeLow+encodeRange))>=ENET_RANGE_CODER_TOP then begin
if encodeRange>=ENET_RANGE_CODER_BOTTOM then begin
break;
end;
encodeRange:=(-encodeLow) and (ENET_RANGE_CODER_BOTTOM-1);
end;
if not ENET_RANGE_CODER_OUTPUT(outData,outEnd,encodeLow shr 24) then begin
exit;
end;
encodeRange:=encodeRange shl 8;
encodeLow:=encodeLow shl 8;
end;
result:=true;
end;
function ENET_RANGE_CODER_FLUSH(var outData:pbyte;outEnd:pbyte;var encodeLow:longword):boolean;
begin
result:=false;
while encodeLow<>0 do begin
if not ENET_RANGE_CODER_OUTPUT(outData,outEnd,encodeLow shr 24) then begin
exit;
end;
encodeLow:=encodeLow shl 8;
end;
result:=true;
end;
procedure ENET_RANGE_CODER_FREE_SYMBOLS(rangeCoder:PENetRangeCoder;var root:PENetSymbol;var nextSymbol:longint;var predicted:word;var order:longint);
begin
if nextSymbol>=((sizeof(rangeCoder^.symbols) div sizeof(TENetSymbol))-ENET_SUBCONTEXT_ORDER) then begin
nextSymbol:=0;
ENET_CONTEXT_CREATE(rangeCoder,root,ENET_CONTEXT_ESCAPE_MINIMUM,ENET_CONTEXT_SYMBOL_MINIMUM,nextSymbol);
predicted:=0;
order:=0;
end;
end;
procedure ENET_CONTEXT_ENCODE(rangeCoder:PENetRangeCoder;var context:PENetSymbol;var symbol_:PENetSymbol;var value_:byte;var under_:word;var count_:word;update:word;minimum:word;var nextSymbol:longint);
var node:PENetSymbol;
begin
under_:=value_*minimum;
count_:=minimum;
if context^.symbols=0 then begin
ENET_SYMBOL_CREATE(rangeCoder,symbol_,value_,update,nextSymbol);
context^.symbols:=(ptrint(symbol_)-ptrint(context)) div sizeof(TENetSymbol);
end else begin
node:=@PENetSymbols(pointer(context))^[context^.symbols];
while true do begin
if value_<node^.value then begin
inc(node^.under,update);
if node^.left<>0 then begin
inc(node,node^.left);
continue;
end;
ENET_SYMBOL_CREATE(rangeCoder,symbol_,value_,update,nextSymbol);
node^.left:=(ptrint(symbol_)-ptrint(node)) div sizeof(TENetSymbol);
end else if value_>node^.value then begin
inc(under_,node^.under);
if node^.right<>0 then begin
inc(node,node^.right);
continue;
end;
ENET_SYMBOL_CREATE(rangeCoder,symbol_,value_,update,nextSymbol);
node^.right:=(ptrint(symbol_)-ptrint(node)) div sizeof(TENetSymbol);
end else begin
inc(count_,node^.count);
inc(under_,node^.under-node^.count);
inc(node^.under,update);
inc(node^.count,update);
symbol_:=node;
end;
break;
end;
end;
end;
function enet_range_coder_compress(context:pointer;inBuffers:PENetBuffer;inBufferCount,inLimit:longint;outData:pointer;outLimit:longint):longint;
label nextInput;
type pword=^word;
var rangeCoder:PENetRangeCoder;
outStart,outEnd,inData,inEnd:pbyte;
encodeLow,encodeRange:longword;
root,subcontext,symbol:PENetSymbol;
predicted,count,under,total:word;
parent:pword;
order,nextSymbol:longint;
value:byte;
begin
rangeCoder:=context;
outStart:=outData;
outEnd:=pointer(@pansichar(outData)[outLimit]);
encodeLow:=0;
encodeRange:=$ffffffff;
predicted:=0;
order:=0;
nextSymbol:=0;
if (not assigned(rangeCoder)) or (inBufferCount<=0) or (inLimit<=0) then begin
result:=0;
exit;
end;
inData:=pointer(inBuffers^.data);
inEnd:=pointer(@pansichar(inData)[inBuffers^.dataLength]);
inc(inBuffers);
dec(inBufferCount);
ENET_CONTEXT_CREATE(rangeCoder,root,ENET_CONTEXT_ESCAPE_MINIMUM,ENET_CONTEXT_SYMBOL_MINIMUM,nextSymbol);
while true do begin
parent:=@predicted;
if ptruint(inData)>=ptruint(inEnd) then begin
if inBufferCount<=0 then begin
break;
end;
inData:=pointer(inBuffers^.data);
inEnd:=pointer(@pansichar(inData)[inBuffers^.dataLength]);
inc(inBuffers);
dec(inBufferCount);
end;
value:=inData^;
inc(inData);
subContext:=@rangeCoder^.symbols[predicted];
while subcontext<>root do begin
ENET_CONTEXT_ENCODE(rangeCoder,subcontext,symbol,value,under,count,ENET_SUBCONTEXT_SYMBOL_DELTA,0,nextSymbol);
parent^:=(ptrint(symbol)-ptrint(@rangeCoder^.symbols[0])) div sizeof(TENetSymbol);
parent:=@symbol^.parent;
total:=subcontext^.total;
if count>0 then begin
if not ENET_RANGE_CODER_ENCODE(pbyte(outData),outEnd,encodeLow,encodeRange,subcontext^.escapes+under,count,total) then begin
result:=0;
exit;
end;
end else begin
if (subcontext^.escapes>0) and (subcontext^.escapes<total) then begin
if not ENET_RANGE_CODER_ENCODE(pbyte(outData),outEnd,encodeLow,encodeRange,0,subcontext^.escapes,total) then begin
result:=0;
exit;
end;
end;
inc(subcontext^.escapes,ENET_SUBCONTEXT_ESCAPE_DELTA);
inc(subcontext^.total,ENET_SUBCONTEXT_ESCAPE_DELTA);
end;
inc(subcontext^.total,ENET_SUBCONTEXT_SYMBOL_DELTA);
if (count>($FF-(2*ENET_SUBCONTEXT_SYMBOL_DELTA))) or (subcontext^.total>(ENET_RANGE_CODER_BOTTOM-$100)) then begin
ENET_CONTEXT_RESCALE(subcontext,0);
end;
if count>0 then begin
goto nextInput;
end;
subcontext:=@rangeCoder^.symbols[subcontext^.parent];
end;
ENET_CONTEXT_ENCODE(rangeCoder,subcontext,symbol,value,under,count,ENET_SUBCONTEXT_SYMBOL_DELTA,ENET_CONTEXT_SYMBOL_MINIMUM,nextSymbol);
parent^:=(ptrint(symbol)-ptrint(@rangeCoder^.symbols[0])) div sizeof(TENetSymbol);
parent:=@symbol^.parent;
total:=root^.total;
if not ENET_RANGE_CODER_ENCODE(pbyte(outData),outEnd,encodeLow,encodeRange,root^.escapes+under,count,total) then begin
result:=0;
exit;
end;
inc(root^.total,ENET_CONTEXT_SYMBOL_DELTA);
if (count>(($FF-(2*ENET_CONTEXT_SYMBOL_DELTA))+ENET_CONTEXT_SYMBOL_MINIMUM)) or (root^.total>(ENET_RANGE_CODER_BOTTOM-$100)) then begin
ENET_CONTEXT_RESCALE(root,ENET_CONTEXT_SYMBOL_MINIMUM);
end;
nextInput:
if order>=ENET_SUBCONTEXT_ORDER then begin
predicted:=rangeCoder^.symbols[predicted].parent;
end else begin
inc(order);
end;
ENET_RANGE_CODER_FREE_SYMBOLS(rangeCoder,root,nextSymbol,predicted,order);
end;
if not ENET_RANGE_CODER_FLUSH(pbyte(outData),outEnd,encodeLow) then begin
result:=0;
exit;
end;
result:=ptrint(outData)-ptrint(outStart);
end;
procedure ENET_RANGE_CODER_SEED(var inData:pbyte;inEnd:pbyte;var decodeCode:longword);
begin
if ptruint(inData)<ptruint(inEnd) then begin
decodeCode:=decodeCode or (inData^ shl 24);
inc(inData);
end;
if ptruint(inData)<ptruint(inEnd) then begin
decodeCode:=decodeCode or (inData^ shl 16);
inc(inData);
end;
if ptruint(inData)<ptruint(inEnd) then begin
decodeCode:=decodeCode or (inData^ shl 8);
inc(inData);
end;
if ptruint(inData)<ptruint(inEnd) then begin
decodeCode:=decodeCode or inData^;
inc(inData);
end;
end;
function ENET_RANGE_CODER_READ(decodeCode,decodeLow:longword;var decodeRange:longword;total:word):word;
begin
decodeRange:=decodeRange div total;
result:=(decodeCode-decodeLow)-decodeRange;
end;
procedure ENET_RANGE_CODER_DECODE(var inData:pbyte;inEnd:pbyte;var decodeCode,decodeLow,decodeRange:longword;under:word;var count,total:word);
begin
inc(decodeLow,under*decodeRange);
decodeRange:=decodeRange*count;
while true do begin
if (decodeLow xor (decodeLow+decodeRange))>=ENET_RANGE_CODER_TOP then begin
if decodeRange>=ENET_RANGE_CODER_BOTTOM then begin
break;
end;
decodeRange:=(-decodeLow) and (ENET_RANGE_CODER_BOTTOM-1);
end;
decodeCode:=decodeCode shl 8;
if ptruint(inData)<ptruint(inEnd) then begin
decodeCode:=decodeCode or inData^;
inc(inData);
end;
decodeRange:=decodeRange shl 8;
decodeLow:=decodeLow shl 8;
end;
end;
function ENET_CONTEXT_TRY_DECODE(rangeCoder:PENetRangeCoder;context:PENetSymbol;var symbol_:PENetSymbol;var code:word;var value_:byte;var under_,count_:word;update,minimum:word):boolean;
var node:PENetSymbol;
after,before:word;
begin
result:=false;
under_:=0;
count_:=minimum;
if context^.symbols=0 then begin
exit;
end else begin
node:=@PENetSymbols(pointer(context))^[context^.symbols];
while true do begin
after:=under_+node^.under+((node^.value+1)*minimum);
before:=node^.count+minimum;
if code>=after then begin
inc(under_,node^.under);
if node^.right<>0 then begin
inc(node,node^.right);
continue;
end;
exit;
end else if code<(after-before) then begin
inc(node^.under,update);
if node^.left<>0 then begin
inc(node,node^.left);
continue;
end;
exit;
end else begin
value_:=node^.value;
inc(count_,node^.count);
under_:=after-before;
inc(node^.under,update);
inc(node^.count,update);
symbol_:=node;
end;
break;
end;
end;
result:=true;
end;
procedure ENET_CONTEXT_ROOT_DECODE(rangeCoder:PENetRangeCoder;context:PENetSymbol;var symbol_:PENetSymbol;var code:word;var value_:byte;var under_,count_:word;update,minimum:word;var nextSymbol:longint);
var node:PENetSymbol;
after,before:word;
begin
under_:=0;
count_:=minimum;
if context^.symbols=0 then begin
value_:=code div minimum;
under_:=code-(code mod minimum);
ENET_SYMBOL_CREATE(rangeCoder,symbol_,value_,update,nextSymbol);
context^.symbols:=(ptrint(symbol_)-ptrint(context)) div sizeof(TENetSymbol);
end else begin
node:=@PENetSymbols(pointer(context))^[context^.symbols];
while true do begin
after:=under_+node^.under+((node^.value+1)*minimum);
before:=node^.count+minimum;
if code>=after then begin
inc(under_,node^.under);
if node^.right<>0 then begin
inc(node,node^.right);
continue;
end;
value_:=(node^.value+1)+((code-after) div minimum);
under_:=code-((code-after) mod minimum);
ENET_SYMBOL_CREATE(rangeCoder,symbol_,value_,update,nextSymbol);
node^.right:=(ptrint(symbol_)-ptrint(node)) div sizeof(TENetSymbol);
end else if code<(after-before) then begin
inc(node^.under,update);
if node^.left<>0 then begin
inc(node,node^.left);
continue;
end;
value_:=(node^.value-1)-((((after-before)-code)-1) div minimum);
under_:=code-((((after-before)-code)-1) mod minimum);
ENET_SYMBOL_CREATE(rangeCoder,symbol_,value_,update,nextSymbol);
node^.left:=(ptrint(symbol_)-ptrint(node)) div sizeof(TENetSymbol);
end else begin
value_:=node^.value;
inc(count_,node^.count);
under_:=after-before;
inc(node^.under,update);
inc(node^.count,update);
symbol_:=node;
end;
break;
end;
end;
end;
function enet_range_coder_decompress(context:pointer;inData:pointer;inLimit:longint;outData:pointer;outLimit:longint):longint;
label patchContexts;
type pword=^word;
var rangeCoder:PENetRangeCoder;
outStart,outEnd,inEnd:pbyte;
decodeLow,decodeCode,decodeRange:longword;
root,subcontext,symbol,patch:PENetSymbol;
predicted,count,under,bottom,total,code:word;
parent:pword;
order,nextSymbol:longint;
value:byte;
begin
rangeCoder:=context;
outStart:=outData;
outEnd:=pointer(@pansichar(outData)[outLimit]);
inEnd:=pointer(@pansichar(inData)[inLimit]);
decodeLow:=0;
decodeCode:=0;
decodeRange:=$ffffffff;
predicted:=0;
order:=0;
nextSymbol:=0;
if (not assigned(rangeCoder)) or (inLimit<=0) then begin
result:=0;
exit;
end;
ENET_CONTEXT_CREATE(rangeCoder,root,ENET_CONTEXT_ESCAPE_MINIMUM,ENET_CONTEXT_SYMBOL_MINIMUM,nextSymbol);
ENET_RANGE_CODER_SEED(pbyte(inData),inEnd,decodeCode);
while true do begin
value:=0;
parent:=@predicted;
subcontext:=@rangeCoder^.symbols[predicted];
while subcontext<>root do begin
if subcontext^.escapes<=0 then begin
continue;
end;
total:=subcontext^.total;
if subcontext^.escapes>=total then begin
continue;
end;
code:=ENET_RANGE_CODER_READ(decodeCode,decodeLow,decodeRange,total);
if code<subcontext^.escapes then begin
ENET_RANGE_CODER_DECODE(pbyte(inData),inEnd,decodeCode,decodeLow,decodeRange,0,subcontext^.escapes,total);
continue;
end;
dec(code,subcontext^.escapes);
if not ENET_CONTEXT_TRY_DECODE(rangeCoder,subcontext,symbol,code,value,under,count,ENET_SUBCONTEXT_SYMBOL_DELTA,0) then begin
result:=0;
exit;
end;
bottom:=(ptrint(symbol)-ptrint(@rangeCoder^.symbols[0])) div sizeof(TENetSymbol);
ENET_RANGE_CODER_DECODE(pbyte(inData),inEnd,decodeCode,decodeLow,decodeRange,subcontext^.escapes+under,count,total);
inc(subcontext^.total,ENET_SUBCONTEXT_SYMBOL_DELTA);
if (count>($FF-(2*ENET_SUBCONTEXT_SYMBOL_DELTA))) or (subcontext^.total>(ENET_RANGE_CODER_BOTTOM-$100)) then begin
ENET_CONTEXT_RESCALE(subcontext,0);
end;
goto patchContexts;
subcontext:=@rangeCoder^.symbols[subcontext^.parent];
end;
total:=root^.total;
code:=ENET_RANGE_CODER_READ(decodeCode,decodeLow,decodeRange,total);
if code<root^.escapes then begin
ENET_RANGE_CODER_DECODE(pbyte(inData),inEnd,decodeCode,decodeLow,decodeRange,0,root^.escapes,total);
break;
end;
dec(code,root^.escapes);
ENET_CONTEXT_ROOT_DECODE(rangeCoder,root,symbol,code,value,under,count,ENET_CONTEXT_SYMBOL_DELTA,ENET_CONTEXT_SYMBOL_MINIMUM,nextSymbol);
bottom:=(ptrint(symbol)-ptrint(@rangeCoder^.symbols[0])) div sizeof(TENetSymbol);
ENET_RANGE_CODER_DECODE(pbyte(inData),inEnd,decodeCode,decodeLow,decodeRange,root^.escapes+under,count,total);
inc(root^.total,ENET_CONTEXT_SYMBOL_DELTA);
if (count>(($FF-(2*ENET_CONTEXT_SYMBOL_DELTA))+ENET_CONTEXT_SYMBOL_MINIMUM)) or (root^.total>(ENET_RANGE_CODER_BOTTOM-$100)) then begin
ENET_CONTEXT_RESCALE(root,ENET_CONTEXT_SYMBOL_MINIMUM);
end;
patchContexts:
patch:=@rangeCoder^.symbols[predicted];
while patch<>subcontext do begin
ENET_CONTEXT_ENCODE(rangeCoder,patch,symbol,value,under,count,ENET_SUBCONTEXT_SYMBOL_DELTA,0,nextSymbol);
parent^:=(ptrint(symbol)-ptrint(@rangeCoder^.symbols[0])) div sizeof(TENetSymbol);
parent:=@symbol^.parent;
if count<=0 then begin
inc(patch^.escapes,ENET_SUBCONTEXT_ESCAPE_DELTA);
inc(patch^.total,ENET_SUBCONTEXT_ESCAPE_DELTA);
end;
inc(patch^.total,ENET_SUBCONTEXT_SYMBOL_DELTA);
if (count>($FF-(2*ENET_SUBCONTEXT_SYMBOL_DELTA))) or (patch^.total>(ENET_RANGE_CODER_BOTTOM-$100)) then begin
ENET_CONTEXT_RESCALE(patch,0);
end;
patch:=@rangeCoder^.symbols[patch^.parent];
end;
parent^:=bottom;
ENET_RANGE_CODER_OUTPUT(pbyte(outData),outEnd,value);
if order>=ENET_SUBCONTEXT_ORDER then begin
predicted:=rangeCoder^.symbols [predicted].parent;
end else begin
inc(order);
end;
ENET_RANGE_CODER_FREE_SYMBOLS(rangeCoder,root,nextSymbol,predicted,order);
end;
result:=ptrint(outData)-ptrint(outStart);
end;
function enet_host_compress_with_range_coder(host:PENetHost):longint;
var compressor:TENetCompressor;
begin
FillChar(compressor,sizeof(TENetcompressor),#0);
compressor.context:=enet_range_coder_create();
if not assigned(compressor.context) then begin
result:=-1;
end else begin
compressor.compress:=enet_range_coder_compress;
compressor.decompress:=enet_range_coder_decompress;
compressor.destroy:=enet_range_coder_destroy;
enet_host_compress(host,@compressor);
result:=0;
end;
end;
function enet_packet_create(data:pointer;dataLength:longint;flags:Longword):PENetPacket;
var packet:PENetPacket;
begin
GetMem(packet,sizeof(TENetPacket));
if assigned(packet) then begin
FillCHar(packet^,sizeof(TENetPacket),AnsiChar(#0));
end else begin
result:=nil;
exit;
end;
if (flags and ENET_PACKET_FLAG_NO_ALLOCATE)<>0 then begin
packet^.data:=data;
end else if dataLength<=0 then begin
packet^.data:=nil;
end else begin
GetMem(packet^.data,dataLength);
if not assigned(packet^.data) then begin
FreeMem(packet);
result:=nil;
exit;
end;
if assigned(data) then begin
Move(data^,packet^.data^,dataLength);
end else begin
FillChar(packet^.data^,dataLength,AnsiChar(#0));
end;
end;
packet^.referenceCount:=0;
packet^.flags:=flags;
packet^.dataLength:=dataLength;
packet^.freeCallback:=nil;
packet^.userData:=nil;
result:=packet;
end;
procedure enet_packet_destroy(packet:PENetPacket);
begin
if not assigned(packet) then begin
exit;
end;
if assigned(packet^.freeCallback) then begin
packet^.freeCallback(packet);
end;
if ((packet^.flags and ENET_PACKET_FLAG_NO_ALLOCATE)=0) and assigned(packet^.data) then begin
FreeMem(packet^.data);
end;
FreeMem(packet);
end;
function enet_packet_resize(packet:PENetPacket;dataLength:longword):longint;
var newData:pointer;
begin
if (dataLength<=packet^.dataLength) or ((packet^.flags and ENET_PACKET_FLAG_NO_ALLOCATE)<>0) then begin
packet^.dataLength:=dataLength;
result:=0;
exit;
end;
GetMem(newData,DataLength);
if not assigned(newData) then begin
result:=-1;
exit;
end;
FillChar(newData^,DataLength,AnsiChar(#0));
Move(packet^.data^,newData^,packet^.dataLength);
FreeMem(packet^.data);
packet^.data:=newData;
packet^.dataLength:=dataLength;
result:=0;
end;
const initializedCRC32:boolean=false;
var crcTable:array[byte] of longword;
function reflect_crc(val:longword;bits:longint):longword;
var bit:longint;
begin
result:=0;
for bit:=0 to bits-1 do begin
if (val and 1)<>0 then begin
result:=result or (1 shl ((bits-1)-bit));
end;
val:=val shr 1;
end;
end;
procedure initialize_crc32;
var b,o:longint;
crc:longword;
begin
for b:=0 to 255 do begin
crc:=reflect_crc(b,8) shl 24;
for o:=0 to 7 do begin
if (crc and $80000000)<>0 then begin
crc:=(crc shl 1) xor $04c11db7;
end else begin
crc:=crc shl 1;
end;
end;
crcTable[b]:=reflect_crc(crc,32);
end;
initializedCRC32:=true;
end;
function enet_crc32(buffers:PENetBuffer;bufferCount:longint):longword;
var crc:longword;
data,dataEnd:pansichar;
begin
crc:=$FFFFFFFF;
if not initializedCRC32 then begin
initialize_crc32;
end;
while bufferCount>0 do begin
dec(bufferCount);
data:=buffers^.data;
dataEnd:=@data[buffers^.dataLength];
while data<dataEnd do begin
crc:=(crc shr 8) xor crcTable[(crc and $FF) xor byte(data^)];
inc(data);
end;
inc(buffers);
end;
result:=ENET_HOST_TO_NET_32(not crc);
end;
procedure enet_peer_throttle_configure(peer:PENetPeer;interval,acceleration,deceleration:longword);
var command:PENetProtocol;
begin
peer^.packetThrottleInterval:=interval;
peer^.packetThrottleAcceleration:=acceleration;
peer^.packetThrottleDeceleration:=deceleration;
command.header.command:=ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE or ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
command.header.channelID:=$FF;
command.throttleConfigure.packetThrottleInterval:=ENET_HOST_TO_NET_32(interval);
command.throttleConfigure.packetThrottleAcceleration:=ENET_HOST_TO_NET_32(acceleration);
command.throttleConfigure.packetThrottleDeceleration:=ENET_HOST_TO_NET_32(deceleration);
enet_peer_queue_outgoing_command(peer,@command,nil,0,0);
end;
function enet_peer_throttle(peer:PENetPeer;rtt:longword):longint;
begin
if peer^.lastRoundTripTime<=peer^.lastRoundTripTimeVariance then begin
peer^.packetThrottle:=peer^.packetThrottleLimit;
result:=0;
end else if rtt<peer^.lastRoundTripTime then begin
inc(peer^.packetThrottle,peer^.packetThrottleAcceleration);
if peer^.packetThrottle>peer^.packetThrottleLimit then begin
peer^.packetThrottle:=peer^.packetThrottleLimit;
end;
result:=1;
end else if rtt>(peer^.lastRoundTripTime+(2*peer^.lastRoundTripTimeVariance)) then begin
if peer^.packetThrottle>peer^.packetThrottleDeceleration then begin
dec(peer^.packetThrottle,peer^.packetThrottleDeceleration);
end else begin
peer^.packetThrottle:=0;
end;
result:=-1;
end else begin
result:=0;
end;
end;
function enet_peer_send(peer:PENetPeer;channelID:byte;packet:PENetPacket):longint;
var channel:PENetChannel;
command:TENetProtocol;
fragmentLength:longword;
fragmentCount,fragmentNumber,fragmentOffset:longword;
commandNumber:byte;
startSequenceNumber:word;
fragments:TENetList;
fragment:PENetOutgoingCommand;
begin
channel:=@peer^.channels[channelID];
if (peer^.state<>ENET_PEER_STATE_CONNECTED) or (channelID>=peer^.channelCount) or (packet^.dataLength>peer^.host^.maximumPacketSize) then begin
result:=-1;
exit;
end;
fragmentLength:=(peer^.mtu-sizeof(TENetProtocolHeader))-sizeof(TENetProtocolSendFragment);
if assigned(peer^.host^.checksum) then begin
dec(fragmentLength,sizeof(longword));
end;
if packet^.dataLength>fragmentLength then begin
fragmentCount:=(packet^.dataLength+(fragmentLength-1)) div fragmentLength;
if fragmentCount>ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT then begin
result:=-1;
exit;
end;
if ((packet^.flags and (ENET_PACKET_FLAG_RELIABLE or ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT))=ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT) and (channel^.outgoingUnreliableSequenceNumber<$FFFF) then begin
commandNumber:=ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT;
startSequenceNumber:=ENET_HOST_TO_NET_16 (channel^.outgoingUnreliableSequenceNumber+1);
end else begin
commandNumber:=ENET_PROTOCOL_COMMAND_SEND_FRAGMENT or ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
startSequenceNumber:=ENET_HOST_TO_NET_16(channel^.outgoingReliableSequenceNumber+1);
end;
enet_list_clear(@fragments);
fragmentNumber:=0;
fragmentOffset:=0;
while fragmentOffset<packet^.dataLength do begin
if (packet^.dataLength-fragmentOffset)<fragmentLength then begin
fragmentLength:=packet^.dataLength-fragmentOffset;
end;
GetMem(fragment,sizeof(TENetOutgoingCommand));
if assigned(Fragment) then begin
FillChar(fragment^,sizeof(TENetOutgoingCommand),AnsiChar(#0));
end else begin
while not enet_list_empty(@fragments) do begin
fragment:=PENetOutgoingCommand(enet_list_remove(enet_list_begin(@fragments)));
FreeMem(fragment);
end;
result:=-1;
exit;
end;
fragment^.fragmentOffset:=fragmentOffset;
fragment^.fragmentLength:=fragmentLength;
fragment^.packet:=packet;
fragment^.command.header.command:=commandNumber;
fragment^.command.header.channelID:=channelID;
fragment^.command.sendFragment.startSequenceNumber:=startSequenceNumber;
fragment^.command.sendFragment.dataLength:=ENET_HOST_TO_NET_16(fragmentLength);
fragment^.command.sendFragment.fragmentCount:=ENET_HOST_TO_NET_32(fragmentCount);
fragment^.command.sendFragment.fragmentNumber:=ENET_HOST_TO_NET_32(fragmentNumber);
fragment^.command.sendFragment.totalLength:=ENET_HOST_TO_NET_32(packet^.dataLength);
fragment^.command.sendFragment.fragmentOffset:=ENET_NET_TO_HOST_32(fragmentOffset);
enet_list_insert(enet_list_end(@fragments),fragment);
inc(fragmentNumber);
inc(fragmentOffset,fragmentLength);
end;
inc(packet^.referenceCount,fragmentNumber);
while not enet_list_empty(@fragments) do begin
fragment:=PENetOutgoingCommand(enet_list_remove(enet_list_begin(@fragments)));
enet_peer_setup_outgoing_command(peer,fragment);
end;
result:=0;
exit;
end;
command.header.channelID:=channelID;
if (packet^.flags and (ENET_PACKET_FLAG_RELIABLE or ENET_PACKET_FLAG_UNSEQUENCED))=ENET_PACKET_FLAG_UNSEQUENCED then begin
command.header.command:=ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED or ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED;
command.sendUnsequenced.dataLength:=ENET_HOST_TO_NET_16(packet^.dataLength);
end else if ((packet^.flags and ENET_PACKET_FLAG_RELIABLE)<>0) or (channel^.outgoingUnreliableSequenceNumber>=$FFFF) then begin
command.header.command:=ENET_PROTOCOL_COMMAND_SEND_RELIABLE or ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
command.sendReliable.dataLength:=ENET_HOST_TO_NET_16 (packet^.dataLength);
end else begin
command.header.command:=ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE;
command.sendUnreliable.dataLength:=ENET_HOST_TO_NET_16(packet^.dataLength);
end;
if assigned(enet_peer_queue_outgoing_command(peer,@command,packet,0,packet^.dataLength)) then begin
result:=0;
end else begin
result:=-1;
end;
end;
function enet_peer_receive(peer:PENetPeer;channelID:pbyte):PENetPacket;
var incomingCommand:PENetIncomingCommand;
packet:PENetPacket;
begin
if enet_list_empty(@peer^.dispatchedCommands) then begin
result:=nil;
exit;
end;
incomingCommand:=PENetIncomingCommand(enet_list_remove(enet_list_begin(@peer^.dispatchedCommands)));
if assigned(channelID) then begin
channelID^:=incomingCommand^.command.header.channelID;
end;
packet:=incomingCommand^.packet;
dec(packet^.referenceCount);
if assigned(incomingCommand^.fragments) then begin
FreeMem(incomingCommand^.fragments);
end;
FreeMem(incomingCommand);
dec(peer^.totalWaitingData,packet^.dataLength);
result:=packet;
end;
procedure enet_peer_reset_outgoing_commands(queue:PENetList);
var outgoingCommand:PENetOutgoingCommand;
begin
while not enet_list_empty(queue) do begin
outgoingCommand:=PENetOutgoingCommand(enet_list_remove(enet_list_begin(queue)));
if assigned(outgoingCommand^.packet) then begin
dec(outgoingCommand^.packet^.referenceCount);
if outgoingCommand^.packet^.referenceCount=0 then begin
enet_packet_destroy(outgoingCommand^.packet);
end;
end;
FreeMem(outgoingCommand);
end;
end;
procedure enet_peer_remove_incoming_commands(queue:PENetList;startCommand,endCommand:TENetListIterator);
var currentCommand:TENetListIterator;
incomingCommand:PENetIncomingCommand;
begin
currentCommand:=startCommand;
while currentCommand<>endCommand do begin
incomingCommand:=PENetIncomingCommand(currentCommand);
currentCommand:=enet_list_next(currentCommand);
enet_list_remove(@incomingCommand^.incomingCommandList);
if assigned(incomingCommand^.packet) then begin
dec(incomingCommand^.packet^.referenceCount);
if incomingCommand^.packet^.referenceCount=0 then begin
enet_packet_destroy(incomingCommand^.packet);
end;
end;
if assigned(incomingCommand^.fragments) then begin
FreeMem(incomingCommand^.fragments);
end;
FreeMem(incomingCommand);
end;
end;
procedure enet_peer_reset_incoming_commands(queue:PENetList);
begin
enet_peer_remove_incoming_commands(queue,enet_list_begin(queue),enet_list_end(queue));
end;
procedure enet_peer_reset_queues(peer:PENetPeer);
var channel:PENetChannel;
i:longint;
begin
if peer^.needsDispatch then begin
enet_list_remove(@peer^.dispatchList);
peer^.needsDispatch:=false;
end;
while not enet_list_empty(@peer^.acknowledgements) do begin
FreeMem(enet_list_remove(enet_list_begin(@peer^.acknowledgements)));
end;
enet_peer_reset_outgoing_commands(@peer^.sentReliableCommands);
enet_peer_reset_outgoing_commands(@peer^.sentUnreliableCommands);
enet_peer_reset_outgoing_commands(@peer^.outgoingReliableCommands);
enet_peer_reset_outgoing_commands(@peer^.outgoingUnreliableCommands);
enet_peer_reset_incoming_commands(@peer^.dispatchedCommands);
if assigned(peer^.channels) and (peer^.channelCount>0) then begin
for i:=0 to peer^.channelCount-1 do begin
channel:=@peer^.channels[i];
enet_peer_reset_incoming_commands(@channel^.incomingReliableCommands);
enet_peer_reset_incoming_commands(@channel^.incomingUnreliableCommands);
end;
FreeMem(peer^.channels);
end;
peer^.channels:=nil;
peer^.channelCount:=0;
end;
procedure enet_peer_reset(peer:PENetPeer);
begin
enet_peer_on_disconnect(peer);
peer^.outgoingPeerID:=ENET_PROTOCOL_MAXIMUM_PEER_ID;
peer^.connectID:=0;
peer^.state:=ENET_PEER_STATE_DISCONNECTED;
peer^.incomingBandwidth:=0;
peer^.outgoingBandwidth:=0;
peer^.incomingBandwidthThrottleEpoch:=0;
peer^.outgoingBandwidthThrottleEpoch:=0;
peer^.incomingDataTotal:=0;
peer^.outgoingDataTotal:=0;
peer^.lastSendTime:=0;
peer^.lastReceiveTime:=0;
peer^.nextTimeout:=0;
peer^.earliestTimeout:=0;
peer^.packetLossEpoch:=0;
peer^.packetsSent:=0;
peer^.packetsLost:=0;
peer^.packetLoss:=0;
peer^.packetLossVariance:=0;
peer^.packetThrottle:=ENET_PEER_DEFAULT_PACKET_THROTTLE;
peer^.packetThrottleLimit:=ENET_PEER_PACKET_THROTTLE_SCALE;
peer^.packetThrottleCounter:=0;
peer^.packetThrottleEpoch:=0;
peer^.packetThrottleAcceleration:=ENET_PEER_PACKET_THROTTLE_ACCELERATION;
peer^.packetThrottleDeceleration:=ENET_PEER_PACKET_THROTTLE_DECELERATION;
peer^.packetThrottleInterval:=ENET_PEER_PACKET_THROTTLE_INTERVAL;
peer^.pingInterval:=ENET_PEER_PING_INTERVAL_;
peer^.timeoutLimit:=ENET_PEER_TIMEOUT_LIMIT;
peer^.timeoutMinimum:=ENET_PEER_TIMEOUT_MINIMUM;
peer^.timeoutMaximum:=ENET_PEER_TIMEOUT_MAXIMUM;
peer^.lastRoundTripTime:=ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
peer^.lowestRoundTripTime:=ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
peer^.lastRoundTripTimeVariance:=0;
peer^.highestRoundTripTimeVariance:=0;
peer^.roundTripTime:=ENET_PEER_DEFAULT_ROUND_TRIP_TIME;
peer^.roundTripTimeVariance:=0;
peer^.mtu:=peer^.host^.mtu;
peer^.reliableDataInTransit:=0;
peer^.outgoingReliableSequenceNumber:=0;
peer^.windowSize:=ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
peer^.incomingUnsequencedGroup:=0;
peer^.outgoingUnsequencedGroup:=0;
peer^.eventData:=0;
peer^.totalWaitingData:=0;
FillChar(peer^.unsequencedWindow,sizeof(peer^.unsequencedWindow),AnsiChar(#0));
enet_peer_reset_queues(peer);
end;
procedure enet_peer_ping(peer:PENetPeer);
var command:TENetProtocol;
begin
if peer^.state=ENET_PEER_STATE_CONNECTED then begin
command.header.command:=ENET_PROTOCOL_COMMAND_PING or ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
command.header.channelID:=$FF;
enet_peer_queue_outgoing_command(peer,@command,nil,0,0);
end;
end;
procedure enet_peer_ping_interval(peer:PENetPeer;pingInterval:longword);
begin
if pingInterval<>0 then begin
peer^.pingInterval:=pingInterval;
end else begin
peer^.pingInterval:=ENET_PEER_PING_INTERVAL_;
end;
end;
procedure enet_peer_timeout(peer:PENetPeer;timeoutLimit,timeoutMinimum,timeoutMaximum:longword);
begin
if timeoutLimit<>0 then begin
peer^.timeoutLimit:=timeoutLimit;
end else begin
peer^.timeoutLimit:=ENET_PEER_TIMEOUT_LIMIT;
end;
if timeoutMinimum<>0 then begin
peer^.timeoutMinimum:=timeoutMinimum;
end else begin
peer^.timeoutMinimum:=ENET_PEER_TIMEOUT_MINIMUM;
end;
if timeoutMaximum<>0 then begin
peer^.timeoutMaximum:=timeoutMaximum;
end else begin
peer^.timeoutMaximum:=ENET_PEER_TIMEOUT_MAXIMUM;
end;
end;
procedure enet_peer_disconnect_now(peer:PENetPeer;data:longword);
var command:TENetProtocol;
begin
if peer^.state=ENET_PEER_STATE_DISCONNECTED then begin
exit;
end;
if (peer^.state<>ENET_PEER_STATE_ZOMBIE) and (peer^.state<>ENET_PEER_STATE_DISCONNECTING) then begin
enet_peer_reset_queues(peer);
command.header.command:=ENET_PROTOCOL_COMMAND_DISCONNECT or ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED;
command.header.channelID:=$FF;
command.disconnect.data:=ENET_HOST_TO_NET_32(data);
enet_peer_queue_outgoing_command(peer,@command,nil,0,0);
enet_host_flush(peer^.host);
end;
enet_peer_reset(peer);
end;
procedure enet_peer_disconnect(peer:PENetPeer;data:longword);
var command:TENetProtocol;
begin
if peer^.state in [ENET_PEER_STATE_DISCONNECTING,ENET_PEER_STATE_DISCONNECTED,ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT,ENET_PEER_STATE_ZOMBIE] then begin
exit;
end;
enet_peer_reset_queues(peer);
command.header.command:=ENET_PROTOCOL_COMMAND_DISCONNECT;
command.header.channelID:=$FF;
command.disconnect.data:=ENET_HOST_TO_NET_32(data);
if peer^.state in [ENET_PEER_STATE_CONNECTED,ENET_PEER_STATE_DISCONNECT_LATER] then begin
command.header.command:=command.header.command or ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
end else begin
command.header.command:=command.header.command or ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED;
end;
enet_peer_queue_outgoing_command(peer,@command,nil,0,0);
if peer^.state in [ENET_PEER_STATE_CONNECTED,ENET_PEER_STATE_DISCONNECT_LATER] then begin
enet_peer_on_disconnect(peer);
peer^.state:=ENET_PEER_STATE_DISCONNECTING;
end else begin
enet_host_flush(peer^.host);
enet_peer_reset(peer);
end;
end;
procedure enet_peer_disconnect_later(peer:PENetPeer;data:longword);
begin
if (peer^.state in [ENET_PEER_STATE_CONNECTED,ENET_PEER_STATE_DISCONNECT_LATER]) and not (enet_list_empty(@peer^.outgoingReliableCommands) and enet_list_empty(@peer^.outgoingUnreliableCommands) and enet_list_empty(@peer^.sentReliableCommands)) then begin
peer^.state:=ENET_PEER_STATE_DISCONNECT_LATER;
peer^.eventData:=data;
end else begin
enet_peer_disconnect(peer,data);
end;
end;
function enet_peer_queue_acknowledgement(peer:PENetPeer;command:PENetProtocol;sentTime:word):PENetAcknowledgement;
var acknowledgement:PENetAcknowledgement;
channel:PENetChannel;
reliableWindow,currentWindow:word;
begin
if command^.header.channelID<peer^.channelCount then begin
channel:=@peer^.channels[command^.header.channelID];
reliableWindow:=command^.header.reliableSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
currentWindow:=channel^.incomingReliableSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
if command^.header.reliableSequenceNumber<channel^.incomingReliableSequenceNumber then begin
inc(reliableWindow,ENET_PEER_RELIABLE_WINDOWS);
end;
if (reliableWindow>=(currentWindow+(ENET_PEER_FREE_RELIABLE_WINDOWS-1))) and (reliableWindow<=(currentWindow+ENET_PEER_FREE_RELIABLE_WINDOWS)) then begin
result:=nil;
exit;
end;
end;
GetMem(acknowledgement,SizeOf(TENetAcknowledgement));
if assigned(acknowledgement) then begin
FillChar(acknowledgement^,SizeOf(TENetAcknowledgement),AnsiChar(#0));
end else begin
result:=nil;
exit;
end;
inc(peer^.outgoingDataTotal,sizeof(TENetProtocolAcknowledge));
acknowledgement^.sentTime:=sentTime;
acknowledgement^.command:=command^;
enet_list_insert(enet_list_end(@peer^.acknowledgements),acknowledgement);
result:=acknowledgement;
end;
procedure enet_peer_setup_outgoing_command(peer:PENetPeer;outgoingCommand:PENetOutgoingCommand);
var channel:PENetChannel;
begin
channel:=@peer^.channels[outgoingCommand^.command.header.channelID];
inc(peer^.outgoingDataTotal,enet_protocol_command_size(outgoingCommand^.command.header.command)+outgoingCommand^.fragmentLength);
if outgoingCommand^.command.header.channelID=$FF then begin
inc(peer^.outgoingReliableSequenceNumber);
outgoingCommand^.reliableSequenceNumber:=peer^.outgoingReliableSequenceNumber;
outgoingCommand^.unreliableSequenceNumber:=0;
end else if (outgoingCommand^.command.header.command and ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)<>0 then begin
inc(channel^.outgoingReliableSequenceNumber);
channel^.outgoingUnreliableSequenceNumber:=0;
outgoingCommand^.reliableSequenceNumber:=channel^.outgoingReliableSequenceNumber;
outgoingCommand^.unreliableSequenceNumber:=0;
end else if (outgoingCommand^.command.header.command and ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED)<>0 then begin
inc(peer^.outgoingUnsequencedGroup);
outgoingCommand^.reliableSequenceNumber:=0;
outgoingCommand^.unreliableSequenceNumber:=0;
end else begin
if outgoingCommand^.fragmentOffset=0 then begin
inc(channel^.outgoingUnreliableSequenceNumber);
end;
outgoingCommand^.reliableSequenceNumber:=channel^.outgoingReliableSequenceNumber;
outgoingCommand^.unreliableSequenceNumber:=channel^.outgoingUnreliableSequenceNumber;
end;
outgoingCommand^.sendAttempts:=0;
outgoingCommand^.sentTime:=0;
outgoingCommand^.roundTripTimeout:=0;
outgoingCommand^.roundTripTimeoutLimit:=0;
outgoingCommand^.command.header.reliableSequenceNumber:=ENET_HOST_TO_NET_16(outgoingCommand^.reliableSequenceNumber);
case outgoingCommand^.command.header.command and ENET_PROTOCOL_COMMAND_MASK of
ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:begin
outgoingCommand^.command.sendUnreliable.unreliableSequenceNumber:=ENET_HOST_TO_NET_16 (outgoingCommand^.unreliableSequenceNumber);
end;
ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:begin
outgoingCommand^.command.sendUnsequenced.unsequencedGroup:=ENET_HOST_TO_NET_16 (peer^.outgoingUnsequencedGroup);
end;
end;
if (outgoingCommand^.command.header.command and ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)<>0 then begin
enet_list_insert(enet_list_end(@peer^.outgoingReliableCommands),outgoingCommand);
end else begin
enet_list_insert(enet_list_end(@peer^.outgoingUnreliableCommands),outgoingCommand);
end;
end;
function enet_peer_queue_outgoing_command(peer:PENetPeer;command:PENetProtocol;packet:PENetPacket;offset:longword;length:word):PENetOutgoingCommand;
var outgoingCommand:PENetOutgoingCommand;
begin
GetMem(outgoingCommand,SizeOf(TENetOutgoingCommand));
if assigned(outgoingCommand) then begin
FillChar(outgoingCommand^,SizeOf(TENetOutgoingCommand),AnsiChar(#0));
end else begin
result:=nil;
exit;
end;
outgoingCommand^.command:=command^;
outgoingCommand^.fragmentOffset:=offset;
outgoingCommand^.fragmentLength:=length;
outgoingCommand^.packet:=packet;
if assigned(packet) then begin
inc(packet^.referenceCount);
end;
enet_peer_setup_outgoing_command(peer,outgoingCommand);
result:=outgoingCommand;
end;
procedure enet_peer_dispatch_incoming_unreliable_commands(peer:PENetPeer;channel:PENetChannel);
var droppedCommand,startCommand,currentCommand:TENetListIterator;
incomingCommand:PENetIncomingCommand;
reliableWindow,currentWindow:word;
begin
droppedCommand:=enet_list_begin(@channel^.incomingUnreliableCommands);
startCommand:=droppedCommand;
currentCommand:=droppedCommand;
while currentCommand<>enet_list_end(@channel^.incomingUnreliableCommands) do begin
incomingCommand:=PENetIncomingCommand(currentCommand);
if (incomingCommand^.command.header.command and ENET_PROTOCOL_COMMAND_MASK)=ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED then begin
currentCommand:=enet_list_next(currentCommand);
continue;
end;
if incomingCommand^.reliableSequenceNumber=channel^.incomingReliableSequenceNumber then begin
if incomingCommand^.fragmentsRemaining<=0 then begin
channel^.incomingUnreliableSequenceNumber:=incomingCommand^.unreliableSequenceNumber;
currentCommand:=enet_list_next(currentCommand);
continue;
end;
if startCommand<>currentCommand then begin
enet_list_move(enet_list_end(@peer^.dispatchedCommands),startCommand,enet_list_previous(currentCommand));
if not peer^.needsDispatch then begin
enet_list_insert(enet_list_end(@peer^.host^.dispatchQueue),@peer^.dispatchList);
peer^.needsDispatch:=true;
end;
droppedCommand:=currentCommand;
end else if droppedCommand<>currentCommand then begin
droppedCommand:=enet_list_previous(currentCommand);
end;
end else begin
reliableWindow:=incomingCommand^.reliableSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
currentWindow:=channel^.incomingReliableSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
if incomingCommand^.reliableSequenceNumber<channel^.incomingReliableSequenceNumber then begin
inc(reliableWindow,ENET_PEER_RELIABLE_WINDOWS);
end;
if (reliableWindow>=currentWindow) and (reliableWindow<(currentWindow+(ENET_PEER_FREE_RELIABLE_WINDOWS-1))) then begin
break;
end;
droppedCommand:=enet_list_next(currentCommand);
if startCommand<>currentCommand then begin
enet_list_move(enet_list_end(@peer^.dispatchedCommands),startCommand,enet_list_previous(currentCommand));
if not peer^.needsDispatch then begin
enet_list_insert(enet_list_end(@peer^.host^.dispatchQueue),@peer^.dispatchList);
peer^.needsDispatch:=true;
end;
end;
end;
startCommand:=enet_list_next(currentCommand);
currentCommand:=enet_list_next(currentCommand);
end;
if startCommand<>currentCommand then begin
enet_list_move(enet_list_end(@peer^.dispatchedCommands),startCommand,enet_list_previous(currentCommand));
if not peer^.needsDispatch then begin
enet_list_insert(enet_list_end(@peer^.host^.dispatchQueue),@peer^.dispatchList);
peer^.needsDispatch:=true;
end;
droppedCommand:=currentCommand;
end;
enet_peer_remove_incoming_commands(@channel^.incomingUnreliableCommands,enet_list_begin(@channel^.incomingUnreliableCommands),droppedCommand);
end;
procedure enet_peer_dispatch_incoming_reliable_commands(peer:PENetPeer;channel:PENetChannel);
var currentCommand:TENetListIterator;
incomingCommand:PENetIncomingCommand;
begin
currentCommand:=enet_list_begin(@channel^.incomingReliableCommands);
while currentCommand<>enet_list_end(@channel^.incomingReliableCommands) do begin
incomingCommand:=PENetIncomingCommand(currentCommand);
if (incomingCommand^.fragmentsRemaining>0) or (incomingCommand^.reliableSequenceNumber<>(channel^.incomingReliableSequenceNumber+1)) then begin
break;
end;
channel^.incomingReliableSequenceNumber:=incomingCommand^.reliableSequenceNumber;
if incomingCommand^.fragmentCount>0 then begin
inc(channel^.incomingReliableSequenceNumber,incomingCommand^.fragmentCount-1);
end;
currentCommand:=enet_list_next(currentCommand);
end;
if currentCommand=enet_list_begin(@channel^.incomingReliableCommands) then begin
exit;
end;
channel^.incomingUnreliableSequenceNumber:=0;
enet_list_move(enet_list_end(@peer^.dispatchedCommands),enet_list_begin(@channel^.incomingReliableCommands),enet_list_previous(currentCommand));
if not peer^.needsDispatch then begin
enet_list_insert(enet_list_end(@peer^.host^.dispatchQueue),@peer^.dispatchList);
peer^.needsDispatch:=true;
end;
if not enet_list_empty(@channel^.incomingUnreliableCommands) then begin
enet_peer_dispatch_incoming_unreliable_commands(peer,channel);
end;
end;
function enet_peer_queue_incoming_command(peer:PENetPeer;command:PENetProtocol;data:pointer;dataLength:ENETptruint;flags:longword;fragmentCount:longword):PENetIncomingCommand;
label discardCommand,notifyError;
var dummyCommand:TENetIncomingCommand;
channel:PENetChannel;
unreliableSequenceNumber,reliableSequenceNumber:longword;
reliableWindow,currentWindow:word;
incomingCommand:PENetIncomingCommand;
currentCommand:TENetListIterator;
packet:PENetPacket;
begin
channel:=@peer^.channels[command^.header.channelID];
unreliableSequenceNumber:=0;
reliableSequenceNumber:=0;
packet:=nil;
if peer^.state=ENET_PEER_STATE_DISCONNECT_LATER then begin
goto discardCommand;
end;
if (command^.header.command and ENET_PROTOCOL_COMMAND_MASK)<>ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED then begin
reliableSequenceNumber:=command^.header.reliableSequenceNumber;
reliableWindow:=reliableSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
currentWindow:=channel^.incomingReliableSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
if reliableSequenceNumber<channel^.incomingReliableSequenceNumber then begin
inc(reliableWindow,ENET_PEER_RELIABLE_WINDOWS);
end;
if (reliableWindow<currentWindow) or (reliableWindow>=(currentWindow+(ENET_PEER_FREE_RELIABLE_WINDOWS-1))) then begin
goto discardCommand;
end;
end;
case command^.header.command and ENET_PROTOCOL_COMMAND_MASK of
ENET_PROTOCOL_COMMAND_SEND_FRAGMENT,ENET_PROTOCOL_COMMAND_SEND_RELIABLE:begin
if reliableSequenceNumber=channel^.incomingReliableSequenceNumber then begin
goto discardCommand;
end;
currentCommand:=enet_list_previous(enet_list_end(@channel^.incomingReliableCommands));
while currentCommand<>enet_list_end(@channel^.incomingReliableCommands) do begin
incomingCommand:=PENetIncomingCommand(currentCommand);
if reliableSequenceNumber>=channel^.incomingReliableSequenceNumber then begin
if incomingCommand^.reliableSequenceNumber<channel^.incomingReliableSequenceNumber then begin
currentCommand:=enet_list_previous(currentCommand);
continue;
end;
end else if incomingCommand^.reliableSequenceNumber>=channel^.incomingReliableSequenceNumber then begin
break;
end;
if incomingCommand^.reliableSequenceNumber<=reliableSequenceNumber then begin
if incomingCommand^.reliableSequenceNumber<reliableSequenceNumber then begin
break;
end;
goto discardCommand;
end;
currentCommand:=enet_list_previous(currentCommand);
end;
end;
ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE,ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT:begin
unreliableSequenceNumber:=ENET_NET_TO_HOST_16(command^.sendUnreliable.unreliableSequenceNumber);
if (reliableSequenceNumber=channel^.incomingReliableSequenceNumber) and (unreliableSequenceNumber<=channel^.incomingUnreliableSequenceNumber) then begin
goto discardCommand;
end;
currentCommand:=enet_list_previous(enet_list_end(@channel^.incomingUnreliableCommands));
while currentCommand<>enet_list_end(@channel^.incomingUnreliableCommands) do begin
incomingCommand:=PENetIncomingCommand(currentCommand);
if (command^.header.command and ENET_PROTOCOL_COMMAND_MASK)=ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED then begin
currentCommand:=enet_list_previous(currentCommand);
continue;
end;
if reliableSequenceNumber>=channel^.incomingReliableSequenceNumber then begin
if incomingCommand^.reliableSequenceNumber<channel^.incomingReliableSequenceNumber then begin
currentCommand:=enet_list_previous(currentCommand);
continue;
end;
end else if incomingCommand^.reliableSequenceNumber>=channel^.incomingReliableSequenceNumber then begin
break;
end;
if incomingCommand^.reliableSequenceNumber<reliableSequenceNumber then begin
break;
end;
if incomingCommand^.reliableSequenceNumber>reliableSequenceNumber then begin
currentCommand:=enet_list_previous(currentCommand);
continue;
end;
if incomingCommand^.unreliableSequenceNumber<=unreliableSequenceNumber then begin
if incomingCommand^.unreliableSequenceNumber<unreliableSequenceNumber then begin
break;
end;
goto discardCommand;
end;
currentCommand:=enet_list_previous(currentCommand);
end;
end;
ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:begin
currentCommand:=enet_list_end(@channel^.incomingUnreliableCommands);
end;
else begin
goto discardCommand;
end;
end;
if peer^.totalWaitingData>=peer^.host^.maximumWaitingData then begin
goto notifyError;
end;
packet:=enet_packet_create(data,dataLength,flags);
if not assigned(packet) then begin
goto notifyError;
end;
GetMem(incomingCommand,SizeOf(TENetincomingCommand));
if assigned(incomingCommand) then begin
FillChar(incomingCommand^,SizeOf(TENetincomingCommand),AnsiChar(#0));
end else begin
goto notifyError;
end;
incomingCommand^.reliableSequenceNumber:=command^.header.reliableSequenceNumber;
incomingCommand^.unreliableSequenceNumber:=unreliableSequenceNumber and $FFFF;
incomingCommand^.command:=command^;
incomingCommand^.fragmentCount:=fragmentCount;
incomingCommand^.fragmentsRemaining:=fragmentCount;
incomingCommand^.packet:=packet;
incomingCommand^.fragments:=nil;
if fragmentCount>0 then begin
if fragmentCount<=ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT then begin
GetMem(incomingCommand^.fragments,((fragmentCount+31) div 32)*sizeof(longword));
end;
if not assigned(incomingCommand^.fragments) then begin
FreeMem(incomingCommand);
goto notifyError;
end;
FillChar(incomingCommand^.fragments^,((fragmentCount+31) div 32)*sizeof(longword),AnsiChar(#0));
end;
if assigned(packet) then begin
inc(packet^.referenceCount);
inc(peer^.totalWaitingData,packet^.dataLength);
end;
enet_list_insert(enet_list_next(currentCommand),incomingCommand);
case command^.header.command and ENET_PROTOCOL_COMMAND_MASK of
ENET_PROTOCOL_COMMAND_SEND_FRAGMENT,ENET_PROTOCOL_COMMAND_SEND_RELIABLE:begin
enet_peer_dispatch_incoming_reliable_commands(peer,channel);
end;
else begin
enet_peer_dispatch_incoming_unreliable_commands(peer,channel);
end;
end;
result:=incomingCommand;
exit;
discardCommand:
if fragmentCount>0 then begin
goto notifyError;
end;
if assigned(packet) and (packet^.referenceCount=0) then begin
enet_packet_destroy(packet);
end;
result:=@dummyCommand;
exit;
notifyError:
if assigned(packet) and (packet^.referenceCount=0) then begin
enet_packet_destroy(packet);
end;
result:=nil;
end;
procedure enet_peer_on_connect(peer:PENetPeer);
begin
if (peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER) then begin
if peer^.incomingBandwidth<>0 then begin
inc(peer^.host^.bandwidthLimitedPeers);
end;
inc(peer^.host^.connectedPeers);
end;
end;
procedure enet_peer_on_disconnect(peer:PENetPeer);
begin
if (peer^.state=ENET_PEER_STATE_CONNECTED) or (peer^.state=ENET_PEER_STATE_DISCONNECT_LATER) then begin
if peer^.incomingBandwidth<>0 then begin
dec(peer^.host^.bandwidthLimitedPeers);
end;
dec(peer^.host^.connectedPeers);
end;
end;
function enet_socket_create_bind(address:PENetAddress;family:TENetAddressFamily):TENetSocket;
begin
result:=enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM,family);
if result=ENET_SOCKET_NULL then begin
exit;
end;
if enet_socket_bind(result,address,family)<0 then begin
enet_socket_destroy(result);
result:=ENET_SOCKET_NULL;
exit;
end;
enet_socket_set_option(result,ENET_SOCKOPT_NONBLOCK,1);
enet_socket_set_option(result,ENET_SOCKOPT_BROADCAST,1);
enet_socket_set_option(result,ENET_SOCKOPT_RCVBUF,ENET_HOST_RECEIVE_BUFFER_SIZE);
enet_socket_set_option(result,ENET_SOCKOPT_SNDBUF,ENET_HOST_SEND_BUFFER_SIZE);
end;
function enet_host_create(address:PENetAddress;peerCount,channelLimit,incomingBandwidth,outgoingBandwidth:longword):PENetHost;
var host:PENetHost;
currentPeer:PENetPeer;
family:longint;
begin
if peerCount>ENET_PROTOCOL_MAXIMUM_PEER_ID then begin
result:=nil;
exit;
end;
GetMem(host,SizeOf(TENetHost));
if not assigned(host) then begin
result:=nil;
exit;
end;
FillChar(host^,SizeOf(TENetHost),AnsiChar(#0));
GetMem(host^.peers,peerCount*sizeof(TENetPeer));
if not assigned(host^.peers) then begin
FreeMem(host);
result:=nil;
exit;
end;
FillChar(host^.peers^,peerCount*sizeof(TENetPeer),AnsiChar(#0));
if (not assigned(address)) or enet_compare_address(address^.host,ENET_HOST_ANY) then begin
family:=ENET_IPV4 or ENET_IPV6;
end else begin
family:=enet_get_address_family(address);
end;
if (family and ENET_IPV4)<>0 then begin
host^.socket4:=enet_socket_create_bind(address,ENET_IPV4);
end else begin
host^.socket4:=ENET_SOCKET_NULL;
end;
if (family and ENET_IPV6)<>0 then begin
host^.socket6:=enet_socket_create_bind(address,ENET_IPV6);
end else begin
host^.socket6:=ENET_SOCKET_NULL;
end;
if (host^.socket4=ENET_SOCKET_NULL) and (host^.socket6=ENET_SOCKET_NULL) then begin
FreeMem(host^.peers);
FreeMem(host);
result:=nil;
exit;
end;
if host^.socket4<>ENET_SOCKET_NULL then begin
enet_socket_set_option(host^.socket4,ENET_SOCKOPT_NONBLOCK,1);
enet_socket_set_option(host^.socket4,ENET_SOCKOPT_BROADCAST,1);
enet_socket_set_option(host^.socket4,ENET_SOCKOPT_RCVBUF,ENET_HOST_RECEIVE_BUFFER_SIZE);
enet_socket_set_option(host^.socket4,ENET_SOCKOPT_SNDBUF,ENET_HOST_SEND_BUFFER_SIZE);
end;
if host^.socket6<>ENET_SOCKET_NULL then begin
enet_socket_set_option(host^.socket6,ENET_SOCKOPT_NONBLOCK,1);
enet_socket_set_option(host^.socket6,ENET_SOCKOPT_BROADCAST,1);
enet_socket_set_option(host^.socket6,ENET_SOCKOPT_RCVBUF,ENET_HOST_RECEIVE_BUFFER_SIZE);
enet_socket_set_option(host^.socket6,ENET_SOCKOPT_SNDBUF,ENET_HOST_SEND_BUFFER_SIZE);
end;
if assigned(address) and
(((host^.socket4<>ENET_SOCKET_NULL) and (enet_socket_get_address(host^.socket4,@host^.address,ENET_IPV4)<0)) or
((host^.socket6<>ENET_SOCKET_NULL) and (enet_socket_get_address(host^.socket6,@host^.address,ENET_IPV6)<0))) then begin
host^.address:=address^;
end;
if (channelLimit=0) or (channelLimit>ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) then begin
channelLimit:=ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
end else if channelLimit<ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT then begin
channelLimit:=ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
end;
host^.randomSeed:=longword(enet_host_random_seed)+host^.address.host.addr32[0];
host^.randomSeed:=(host^.randomSeed shl 16) or (host^.randomSeed shr 16);
host^.channelLimit:=channelLimit;
host^.incomingBandwidth:=incomingBandwidth;
host^.outgoingBandwidth:=outgoingBandwidth;
host^.bandwidthThrottleEpoch:=0;
host^.recalculateBandwidthLimits:=0;
host^.mtu:=ENET_HOST_DEFAULT_MTU;
host^.peerCount:=peerCount;
host^.commandCount:=0;
host^.bufferCount:=0;
host^.checksum:=nil;
host^.receivedAddress.host:=ENET_HOST_ANY;
host^.receivedAddress.port:=0;
host^.receivedData:=nil;
host^.receivedDataLength:=0;
host^.totalSentData:=0;
host^.totalSentPackets:=0;
host^.totalReceivedData:=0;
host^.totalReceivedPackets:=0;
host^.connectedPeers:=0;
host^.bandwidthLimitedPeers:=0;
host^.duplicatePeers:=ENET_PROTOCOL_MAXIMUM_PEER_ID;
host^.maximumPacketSize:=ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE;
host^.maximumWaitingData:=ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA;
host^.compressor.context:=nil;
host^.compressor.compress:=nil;
host^.compressor.decompress:=nil;
host^.compressor.destroy:=nil;
host^.intercept:=nil;
enet_list_clear(@host^.dispatchQueue);
currentPeer:=@host^.peers[0];
while ptruint(pointer(currentPeer))<ptruint(pointer(@host^.peers[host^.peerCount])) do begin
currentPeer^.host:=host;
currentPeer^.incomingPeerID:=(ptruint(pointer(currentPeer))-ptruint(pointer(@host^.peers[0]))) div sizeof(TENetPeer);
currentPeer^.outgoingSessionID:=$ff;
currentPeer^.incomingSessionID:=$ff;
currentPeer^.data:=nil;
enet_list_clear(@currentPeer^.acknowledgements);
enet_list_clear(@currentPeer^.sentReliableCommands);
enet_list_clear(@currentPeer^.sentUnreliableCommands);
enet_list_clear(@currentPeer^.outgoingReliableCommands);
enet_list_clear(@currentPeer^.outgoingUnreliableCommands);
enet_list_clear(@currentPeer^.dispatchedCommands);
enet_peer_reset(currentPeer);
inc(currentPeer);
end;
result:=host;
end;
procedure enet_host_destroy(host:PENetHost);
var currentPeer:PENetPeer;
begin
if not assigned(host) then begin
exit;
end;
if host^.socket4<>ENET_SOCKET_NULL then begin
enet_socket_destroy(host^.socket4);
end;
if host^.socket6<>ENET_SOCKET_NULL then begin
enet_socket_destroy(host^.socket6);
end;
currentPeer:=@host^.peers[0];
while ptruint(pointer(currentPeer))<ptruint(pointer(@host^.peers[host^.peerCount])) do begin
enet_peer_reset(currentPeer);
inc(currentPeer);
end;
if assigned(host^.compressor.context) and assigned(host^.compressor.destroy) then begin
host^.compressor.destroy(host^.compressor.context);
end;
FreeMem(host^.peers);
FreeMem(host);
end;
function enet_host_connect(host:PENetHost;address:PENetAddress;channelCount,data:longword):PENetPeer;
var currentPeer:PENetPeer;
channel:PENetChannel;
command:TENetProtocol;
begin
if channelCount<ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT then begin
channelCount:=ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
end else if channelCount>ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT then begin
channelCount:=ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
end;
currentPeer:=@host^.peers[0];
while ptruint(pointer(currentPeer))<ptruint(pointer(@host^.peers[host^.peerCount])) do begin
if currentPeer^.state=ENET_PEER_STATE_DISCONNECTED then begin
break;
end;
inc(currentPeer);
end;
if ptruint(pointer(currentPeer))>=ptruint(pointer(@host^.peers[host^.peerCount])) then begin
result:=nil;
exit;
end;
GetMem(currentPeer^.channels,channelCount*sizeof(TENetChannel));
if not assigned(currentPeer^.channels) then begin
result:=nil;
exit;
end;
currentPeer^.channelCount:=channelCount;
currentPeer^.state:=ENET_PEER_STATE_CONNECTING;
currentPeer^.address:=address^;
inc(host^.randomSeed);
currentPeer^.connectID:=host^.randomSeed;
if host^.outgoingBandwidth=0 then begin
currentPeer^.windowSize:=ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
end else begin
currentPeer^.windowSize:=(host^.outgoingBandwidth div ENET_PEER_WINDOW_SIZE_SCALE)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
end;
if currentPeer^.windowSize<ENET_PROTOCOL_MINIMUM_WINDOW_SIZE then begin
currentPeer^.windowSize:=ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
end else if currentPeer^.windowSize>ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE then begin
currentPeer^.windowSize:=ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
end;
channel:=@currentPeer^.channels^[0];
while ptruint(pointer(channel))<ptruint(pointer(@currentPeer^.channels^[channelCount])) do begin
channel^.outgoingReliableSequenceNumber:=0;
channel^.outgoingUnreliableSequenceNumber:=0;
channel^.incomingReliableSequenceNumber:=0;
channel^.incomingUnreliableSequenceNumber:=0;
enet_list_clear(@channel^.incomingReliableCommands);
enet_list_clear(@channel^.incomingUnreliableCommands);
channel^.usedReliableWindows:=0;
FillChar(channel^.reliableWindows,sizeof(channel^.reliableWindows),#0);
inc(Channel);
end;
command.header.command:=ENET_PROTOCOL_COMMAND_CONNECT or ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
command.header.channelID:=$FF;
command.connect.outgoingPeerID:=ENET_HOST_TO_NET_16(currentPeer^.incomingPeerID);
command.connect.incomingSessionID:=currentPeer^.incomingSessionID;
command.connect.outgoingSessionID:=currentPeer^.outgoingSessionID;
command.connect.mtu:=ENET_HOST_TO_NET_32(currentPeer^.mtu);
command.connect.windowSize:=ENET_HOST_TO_NET_32(currentPeer^.windowSize);
command.connect.channelCount:=ENET_HOST_TO_NET_32(channelCount);
command.connect.incomingBandwidth:=ENET_HOST_TO_NET_32(host^.incomingBandwidth);
command.connect.outgoingBandwidth:=ENET_HOST_TO_NET_32(host^.outgoingBandwidth);
command.connect.packetThrottleInterval:=ENET_HOST_TO_NET_32(currentPeer^.packetThrottleInterval);
command.connect.packetThrottleAcceleration:=ENET_HOST_TO_NET_32(currentPeer^.packetThrottleAcceleration);
command.connect.packetThrottleDeceleration:=ENET_HOST_TO_NET_32(currentPeer^.packetThrottleDeceleration);
command.connect.connectID:=currentPeer^.connectID;
command.connect.data:=ENET_HOST_TO_NET_32(data);
enet_peer_queue_outgoing_command(currentPeer,@command,nil,0,0);
result:=currentPeer;
end;
procedure enet_host_broadcast(host:PENetHost;channelID:byte;packet:PENetPacket);
var currentPeer:PENetPeer;
begin
currentPeer:=@host^.peers[0];
while ptruint(pointer(currentPeer))<ptruint(pointer(@host^.peers[host^.peerCount])) do begin
if currentPeer^.state<>ENET_PEER_STATE_CONNECTED then begin
inc(currentPeer);
continue;
end;
enet_peer_send(currentPeer,channelID,packet);
inc(currentPeer);
end;
if packet^.referenceCount=0 then begin
enet_packet_destroy(packet);
end;
end;
procedure enet_host_compress(host:PENetHost;compressor:PENetCompressor);
begin
if assigned(host^.compressor.context) and assigned(host^.compressor.destroy) then begin
host^.compressor.destroy(host^.compressor.context);
end;
if assigned(compressor) then begin
host^.compressor:=compressor^;
end else begin
host^.compressor.context:=nil;
end;
end;
procedure enet_host_channel_limit(host:PENetHost;channelLimit:longword);
begin
if (channelLimit=0) or (channelLimit>ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) then begin
channelLimit:=ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
end else if channelLimit<ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT then begin
channelLimit:=ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
end;
host^.channelLimit:=channelLimit;
end;
procedure enet_host_bandwidth_limit(host:PENetHost;incomingBandwidth,outgoingBandwidth:longword);
begin
host^.incomingBandwidth:=incomingBandwidth;
host^.outgoingBandwidth:=outgoingBandwidth;
host^.recalculateBandwidthLimits:=1;
end;
procedure enet_host_bandwidth_throttle(host:PENetHost);
var timeCurrent,elapsedTime,dataTotal,peersRemaining,bandwidth,throttle,bandwidthLimit,
peerBandwidth:longword;
needsAdjustment:longint;
peer:PENetPeer;
command:TENetProtocol;
begin
timeCurrent:=enet_time_get;
elapsedTime:=timeCurrent-host^.bandwidthThrottleEpoch;
peersRemaining:=host^.connectedPeers;
dataTotal:=longword(not 0);
bandwidth:=longword(not 0);
throttle:=0;
bandwidthLimit:=0;
if host^.bandwidthLimitedPeers>0 then begin
needsAdjustment:=1;
end else begin
needsAdjustment:=0;
end;
if elapsedTime<ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL then begin
exit;
end;
host^.bandwidthThrottleEpoch:=timeCurrent;
if peersRemaining=0 then begin
exit;
end;
if host^.outgoingBandwidth<>0 then begin
dataTotal:=0;
bandwidth:=(host^.outgoingBandwidth*elapsedTime) div 1000;
peer:=@host^.peers[0];
while ptruint(pointer(peer))<ptruint(pointer(@host^.peers[host^.peerCount])) do begin
if (peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER) then begin
inc(peer);
continue;
end;
inc(dataTotal,peer^.outgoingDataTotal);
inc(peer);
end;
end;
while (peersRemaining>0) and (needsAdjustment<>0) do begin
needsAdjustment:=0;
if dataTotal<=bandwidth then begin
throttle:=ENET_PEER_PACKET_THROTTLE_SCALE;
end else begin
throttle:=(bandwidth*ENET_PEER_PACKET_THROTTLE_SCALE) div dataTotal;
end;
peer:=@host^.peers[0];
while ptruint(pointer(peer))<ptruint(pointer(@host^.peers[host^.peerCount])) do begin
if ((peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER)) or
(peer^.incomingBandwidth=0) or (peer^.outgoingBandwidthThrottleEpoch=timeCurrent) then begin
inc(peer);
continue;
end;
peerBandwidth:=(peer^.incomingBandwidth*elapsedTime) div 1000;
if ((throttle*peer^.outgoingDataTotal) div ENET_PEER_PACKET_THROTTLE_SCALE)<=peerBandwidth then begin
inc(peer);
continue;
end;
peer^.packetThrottleLimit:=(peerBandwidth*ENET_PEER_PACKET_THROTTLE_SCALE) div peer^.outgoingDataTotal;
if peer^.packetThrottleLimit=0 then begin
peer^.packetThrottleLimit:=1;
end;
if peer^.packetThrottle>peer^.packetThrottleLimit then begin
peer^.packetThrottle:=peer^.packetThrottleLimit;
end;
peer^.outgoingBandwidthThrottleEpoch:=timeCurrent;
peer^.incomingDataTotal:=0;
peer^.outgoingDataTotal:=0;
needsAdjustment:=1;
dec(peersRemaining);
dec(bandwidth,peerBandwidth);
dec(dataTotal,peerBandwidth);
inc(peer);
end;
end;
if peersRemaining>0 then begin
if dataTotal<=bandwidth then begin
throttle:=ENET_PEER_PACKET_THROTTLE_SCALE;
end else begin
throttle:=(bandwidth*ENET_PEER_PACKET_THROTTLE_SCALE) div dataTotal;
end;
peer:=@host^.peers[0];
while ptruint(pointer(peer))<ptruint(pointer(@host^.peers[host^.peerCount])) do begin
if ((peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER)) or
(peer^.outgoingBandwidthThrottleEpoch=timeCurrent) then begin
inc(peer);
continue;
end;
peer^.packetThrottleLimit:=throttle;
if peer^.packetThrottle>peer^.packetThrottleLimit then begin
peer^.packetThrottle:=peer^.packetThrottleLimit;
end;
peer^.incomingDataTotal:=0;
peer^.outgoingDataTotal:=0;
inc(peer);
end;
end;
if host^.recalculateBandwidthLimits<>0 then begin
host^.recalculateBandwidthLimits:=0;
peersRemaining:=host^.connectedPeers;
bandwidth:=host^.incomingBandwidth;
needsAdjustment:=1;
if bandwidth=0 then begin
bandwidthLimit:=0;
end else begin
while (peersRemaining>0) and (needsAdjustment<>0) do begin
needsAdjustment:=0;
bandwidthLimit:=bandwidth div peersRemaining;
peer:=@host^.peers[0];
while ptruint(pointer(peer))<ptruint(pointer(@host^.peers[host^.peerCount])) do begin
if ((peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER)) or (peer^.incomingBandwidthThrottleEpoch=timeCurrent) then begin
inc(peer);
continue;
end;
if (peer^.outgoingBandwidth>0) and (peer^.outgoingBandwidth>=bandwidthLimit) then begin
inc(peer);
continue;
end;
peer^.incomingBandwidthThrottleEpoch:=timeCurrent;
needsAdjustment:=1;
dec(peersRemaining);
inc(bandwidth,peer^.outgoingBandwidth);
inc(peer);
end;
end;
end;
peer:=@host^.peers[0];
while ptruint(pointer(peer))<ptruint(pointer(@host^.peers[host^.peerCount])) do begin
if (peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER) then begin
inc(peer);
continue;
end;
command.header.command:=ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT or ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
command.header.channelID:=$ff;
command.bandwidthLimit.outgoingBandwidth:=ENET_HOST_TO_NET_32 (host^.outgoingBandwidth);
if peer^.incomingBandwidthThrottleEpoch=timeCurrent then begin
command.bandwidthLimit.incomingBandwidth:=ENET_HOST_TO_NET_32(peer^.outgoingBandwidth);
end else begin
command.bandwidthLimit.incomingBandwidth:=ENET_HOST_TO_NET_32(bandwidthLimit);
end;
enet_peer_queue_outgoing_command(peer,@command,nil,0,0);
inc(peer);
end;
end;
end;
const commandSizes:array[0..ENET_PROTOCOL_COMMAND_COUNT-1] of longint=
(
0,
sizeof(TENetProtocolAcknowledge),
sizeof(TENetProtocolConnect),
sizeof(TENetProtocolVerifyConnect),
sizeof(TENetProtocolDisconnect),
sizeof(TENetProtocolPing),
sizeof(TENetProtocolSendReliable),
sizeof(TENetProtocolSendUnreliable),
sizeof(TENetProtocolSendFragment),
sizeof(TENetProtocolSendUnsequenced),
sizeof(TENetProtocolBandwidthLimit),
sizeof(TENetProtocolThrottleConfigure),
0
);
function enet_protocol_command_size(command:byte):longint;
begin
result:=commandSizes[command];
end;
procedure enet_protocol_change_state(host:PENetHost;peer:PENetPeer;state:TENetPeerState);
begin
if (state=ENET_PEER_STATE_CONNECTED) or (state=ENET_PEER_STATE_DISCONNECT_LATER) then begin
enet_peer_on_connect(peer);
end else begin
enet_peer_on_disconnect(peer);
end;
peer^.state:=state;
end;
procedure enet_protocol_dispatch_state(host:PENetHost;peer:PENetPeer;state:TENetPeerState);
begin
enet_protocol_change_state(host,peer,state);
if not peer^.needsDispatch then begin
enet_list_insert(enet_list_end(@host^.dispatchQueue),@peer^.dispatchList);
peer^.needsDispatch:=true;
end;
end;
function enet_protocol_dispatch_incoming_commands(host:PENetHost;event:PENetEvent):longint;
var peer:PENetPeer;
begin
while not enet_list_empty(@host^.dispatchQueue) do begin
peer:=enet_list_remove(enet_list_begin(@host^.dispatchQueue));
peer^.needsDispatch:=false;
case peer^.state of
ENET_PEER_STATE_CONNECTION_PENDING,ENET_PEER_STATE_CONNECTION_SUCCEEDED:begin
enet_protocol_change_state(host,peer,ENET_PEER_STATE_CONNECTED);
event^.type_:=ENET_EVENT_TYPE_CONNECT;
event^.peer:=peer;
event^.data:=peer^.eventData;
result:=1;
exit;
end;
ENET_PEER_STATE_ZOMBIE:begin
host^.recalculateBandwidthLimits:=1;
event^.type_:=ENET_EVENT_TYPE_DISCONNECT;
event^.peer:=peer;
event^.data:=peer^.eventData;
enet_peer_reset(peer);
result:=1;
exit;
end;
ENET_PEER_STATE_CONNECTED:begin
if enet_list_empty(@peer^.dispatchedCommands) then begin
continue;
end;
event^.packet:=enet_peer_receive(peer,@event^.channelID);
if assigned(event^.packet) then begin
continue;
end;
event^.type_:=ENET_EVENT_TYPE_RECEIVE;
event^.peer:=peer;
if not enet_list_empty(@peer^.dispatchedCommands) then begin
peer^.needsDispatch:=true;
enet_list_insert(enet_list_end(@host^.dispatchQueue),@peer^.dispatchList);
end;
result:=1;
exit;
end;
end;
end;
result:=0;
end;
procedure enet_protocol_notify_connect(host:PENetHost;peer:PENetPeer;event:PENetEvent);
begin
host^.recalculateBandwidthLimits:=1;
if assigned(event) then begin
enet_protocol_change_state(host,peer,ENET_PEER_STATE_CONNECTED);
event^.type_:=ENET_EVENT_TYPE_CONNECT;
event^.peer:=peer;
event^.data:=peer^.eventData;
end else begin
if peer^.state=ENET_PEER_STATE_CONNECTING then begin
enet_protocol_dispatch_state(host,peer,ENET_PEER_STATE_CONNECTION_SUCCEEDED);
end else begin
enet_protocol_dispatch_state(host,peer,ENET_PEER_STATE_CONNECTION_PENDING);
end;
end;
end;
procedure enet_protocol_notify_disconnect(host:PENetHost;peer:PENetPeer;event:PENetEvent);
begin
if peer^.state>=ENET_PEER_STATE_CONNECTION_PENDING then begin
host^.recalculateBandwidthLimits:=1;
end;
if (peer^.state<>ENET_PEER_STATE_CONNECTING) and (peer^.state<ENET_PEER_STATE_CONNECTION_SUCCEEDED) then begin
enet_peer_reset(peer);
end else if assigned(event) then begin
event^.type_:=ENET_EVENT_TYPE_DISCONNECT;
event^.peer:=peer;
event^.data:=0;
enet_peer_reset(peer);
end else begin
peer^.eventData:=0;
enet_protocol_dispatch_state(host,peer,ENET_PEER_STATE_ZOMBIE);
end;
end;
procedure enet_protocol_remove_sent_unreliable_commands(peer:PENetPeer);
var outgoingCommand:PENetOutgoingCommand;
begin
while not enet_list_empty(@peer^.sentUnreliableCommands) do begin
outgoingCommand:=PENetOutgoingCommand(enet_list_front(@peer^.sentUnreliableCommands));
enet_list_remove(@outgoingCommand^.outgoingCommandList);
if assigned(outgoingCommand^.packet) then begin
dec(outgoingCommand^.packet^.referenceCount);
if outgoingCommand^.packet^.referenceCount=0 then begin
outgoingCommand^.packet^.flags:=outgoingCommand^.packet^.flags or ENET_PACKET_FLAG_SENT;
enet_packet_destroy(outgoingCommand^.packet);
end;
end;
FreeMem(outgoingCommand);
end;
end;
function enet_protocol_remove_sent_reliable_command(peer:PENetPeer;reliableSequenceNumber:word;channelID:byte):TENetProtocolCommand;
var outgoingCommand:PENetOutgoingCommand;
currentCommand:TENetListIterator;
commandNumber:TENetProtocolCommand;
wasSent:boolean;
channel:PENetChannel;
reliableWindow:word;
begin
outgoingCommand:=nil;
wasSent:=true;
currentCommand:=enet_list_begin(@peer^.sentReliableCommands);
while currentCommand<>enet_list_end(@peer^.sentReliableCommands) do begin
outgoingCommand:=PENetOutgoingCommand(currentCommand);
if (outgoingCommand^.reliableSequenceNumber=reliableSequenceNumber) and (outgoingCommand^.command.header.channelID=channelID) then begin
break;
end;
currentCommand:=enet_list_next (currentCommand);
end;
if currentCommand=enet_list_end(@peer^.sentReliableCommands) then begin
currentCommand:=enet_list_begin(@peer^.outgoingReliableCommands);
while currentCommand<>enet_list_end(@peer^.outgoingReliableCommands) do begin
outgoingCommand:=PENetOutgoingCommand(CurrentCommand);
if outgoingCommand^.sendAttempts<1 then begin
result:=ENET_PROTOCOL_COMMAND_NONE;
exit;
end;
if (outgoingCommand^.reliableSequenceNumber=reliableSequenceNumber) and (outgoingCommand^.command.header.channelID=channelID) then begin
break;
end;
currentCommand:=enet_list_next(currentCommand);
end;
if currentCommand=enet_list_end(@peer^.outgoingReliableCommands) then begin
result:=ENET_PROTOCOL_COMMAND_NONE;
exit;
end;
wasSent:=false;
end;
if not assigned(outgoingCommand) then begin
result:=ENET_PROTOCOL_COMMAND_NONE;
exit;
end;
if channelID<peer^.channelCount then begin
channel:=@peer^.channels[channelID];
reliableWindow:=reliableSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
if channel^.reliableWindows[reliableWindow]>0 then begin
dec(channel^.reliableWindows [reliableWindow]);
if channel^.reliableWindows[reliableWindow]=0 then begin
channel^.usedReliableWindows:=channel^.usedReliableWindows and not (1 shl reliableWindow);
end;
end;
end;
commandNumber:=TENetProtocolCommand(outgoingCommand^.command.header.command and ENET_PROTOCOL_COMMAND_MASK);
enet_list_remove(@outgoingCommand^.outgoingCommandList);
if assigned(outgoingCommand^.packet) then begin
if wasSent then begin
dec(peer^.reliableDataInTransit,outgoingCommand^.fragmentLength);
end;
dec(outgoingCommand^.packet^.referenceCount);
if outgoingCommand^.packet^.referenceCount=0 then begin
outgoingCommand^.packet^.flags:=outgoingCommand^.packet^.flags or ENET_PACKET_FLAG_SENT;
enet_packet_destroy(outgoingCommand^.packet);
end;
end;
FreeMem(outgoingCommand);
if enet_list_empty(@peer^.sentReliableCommands) then begin
result:=commandNumber;
exit;
end;
outgoingCommand:=PENetOutgoingCommand(enet_list_front(@peer^.sentReliableCommands));
peer^.nextTimeout:=outgoingCommand^.sentTime+outgoingCommand^.roundTripTimeout;
result:=commandNumber;
end;
function enet_protocol_handle_connect(host:PENetHost;header:PENetProtocolHeader;command:PENetProtocol):PENetPeer;
var incomingSessionID,outgoingSessionID:byte;
mtu,windowSize:longword;
channelCount,duplicatePeers:ENETptruint;
channel:PENetChannel;
currentPeer:PENetPeer;
verifyCommand:TENetProtocol;
i:longint;
begin
result:=nil;
channelCount:=ENET_NET_TO_HOST_32(command^.connect.channelCount);
duplicatePeers:=0;
if (channelCount<ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) or (channelCount>ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) then begin
result:=nil;
exit;
end;
for i:=0 to host^.peerCount-1 do begin
currentPeer:=@host^.peers^[i];
if currentPeer^.state=ENET_PEER_STATE_DISCONNECTED then begin
if not assigned(result) then begin
result:=currentPeer;
end;
end else if (currentPeer^.state<>ENET_PEER_STATE_CONNECTING) and
(currentPeer^.address.host.addr[0]=host^.receivedAddress.host.addr[0]) and
(currentPeer^.address.host.addr[1]=host^.receivedAddress.host.addr[1]) and
(currentPeer^.address.host.addr[2]=host^.receivedAddress.host.addr[2]) and
(currentPeer^.address.host.addr[3]=host^.receivedAddress.host.addr[3]) and
(currentPeer^.address.host.addr[4]=host^.receivedAddress.host.addr[4]) and
(currentPeer^.address.host.addr[5]=host^.receivedAddress.host.addr[5]) and
(currentPeer^.address.host.addr[6]=host^.receivedAddress.host.addr[6]) and
(currentPeer^.address.host.addr[7]=host^.receivedAddress.host.addr[7]) and
(currentPeer^.address.host.addr[8]=host^.receivedAddress.host.addr[8]) and
(currentPeer^.address.host.addr[9]=host^.receivedAddress.host.addr[9]) and
(currentPeer^.address.host.addr[10]=host^.receivedAddress.host.addr[10]) and
(currentPeer^.address.host.addr[11]=host^.receivedAddress.host.addr[11]) and
(currentPeer^.address.host.addr[12]=host^.receivedAddress.host.addr[12]) and
(currentPeer^.address.host.addr[13]=host^.receivedAddress.host.addr[13]) and
(currentPeer^.address.host.addr[14]=host^.receivedAddress.host.addr[14]) and
(currentPeer^.address.host.addr[15]=host^.receivedAddress.host.addr[15]) then begin
if (currentPeer^.address.port=host^.receivedAddress.port) and
(currentPeer^.connectID=command^.connect.connectID) then begin
result:=nil;
exit;
end;
inc(duplicatePeers);
end;
end;
if (not assigned(result)) or (duplicatePeers>=host^.duplicatePeers) then begin
result:=nil;
exit;
end;
if channelCount>host^.channelLimit then begin
channelCount:=host^.channelLimit;
end;
GetMem(result^.channels,channelCount*sizeof(TENetChannel));
if not assigned(result^.channels) then begin
result:=nil;
exit;
end;
FillChar(result^.channels^,channelCount*sizeof(TENetChannel),AnsiChar(#0));
result^.channelCount:=channelCount;
result^.state:=ENET_PEER_STATE_ACKNOWLEDGING_CONNECT;
result^.connectID:=command^.connect.connectID;
result^.address:=host^.receivedAddress;
result^.outgoingPeerID:=ENET_NET_TO_HOST_16(command^.connect.outgoingPeerID);
result^.incomingBandwidth:=ENET_NET_TO_HOST_32(command^.connect.incomingBandwidth);
result^.outgoingBandwidth:=ENET_NET_TO_HOST_32(command^.connect.outgoingBandwidth);
result^.packetThrottleInterval:=ENET_NET_TO_HOST_32(command^.connect.packetThrottleInterval);
result^.packetThrottleAcceleration:=ENET_NET_TO_HOST_32(command^.connect.packetThrottleAcceleration);
result^.packetThrottleDeceleration:=ENET_NET_TO_HOST_32(command^.connect.packetThrottleDeceleration);
result^.eventData:=ENET_NET_TO_HOST_32 (command^.connect.data);
if command^.connect.incomingSessionID=$ff then begin
incomingSessionID:=result^.outgoingSessionID;
end else begin
incomingSessionID:=command^.connect.incomingSessionID;
end;
incomingSessionID:=(incomingSessionID+1) and (ENET_PROTOCOL_HEADER_SESSION_MASK shr ENET_PROTOCOL_HEADER_SESSION_SHIFT);
if incomingSessionID=result^.outgoingSessionID then begin
incomingSessionID:=(incomingSessionID+1) and (ENET_PROTOCOL_HEADER_SESSION_MASK shr ENET_PROTOCOL_HEADER_SESSION_SHIFT);
end;
result^.outgoingSessionID:=incomingSessionID;
if command^.connect.outgoingSessionID=$ff then begin
outgoingSessionID:=result^.incomingSessionID;
end else begin
outgoingSessionID:=command^.connect.outgoingSessionID;
end;
outgoingSessionID:=(outgoingSessionID+1) and (ENET_PROTOCOL_HEADER_SESSION_MASK shr ENET_PROTOCOL_HEADER_SESSION_SHIFT);
if outgoingSessionID=currentPeer^.incomingSessionID then begin
outgoingSessionID:=(outgoingSessionID+1) and (ENET_PROTOCOL_HEADER_SESSION_MASK shr ENET_PROTOCOL_HEADER_SESSION_SHIFT);
end;
result^.incomingSessionID:=outgoingSessionID;
for i:=0 to channelCount-1 do begin
channel:=@result^.channels^[i];
channel^.outgoingReliableSequenceNumber:=0;
channel^.outgoingUnreliableSequenceNumber:=0;
channel^.incomingReliableSequenceNumber:=0;
channel^.incomingUnreliableSequenceNumber:=0;
enet_list_clear(@channel^.incomingReliableCommands);
enet_list_clear(@channel^.incomingUnreliableCommands);
channel^.usedReliableWindows:=0;
FillChar(channel^.reliableWindows,sizeof(channel^.reliableWindows),AnsiChar(#0));
end;
mtu:=ENET_NET_TO_HOST_32(command^.connect.mtu);
if mtu<ENET_PROTOCOL_MINIMUM_MTU then begin
mtu:=ENET_PROTOCOL_MINIMUM_MTU;
end else if mtu>ENET_PROTOCOL_MAXIMUM_MTU then begin
mtu:=ENET_PROTOCOL_MAXIMUM_MTU;
end;
result^.mtu:=mtu;
if (host^.outgoingBandwidth=0) and (result^.incomingBandwidth=0) then begin
result^.windowSize:=ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
end else if (host^.outgoingBandwidth=0) or (result^.incomingBandwidth=0) then begin
result^.windowSize:=(Max(host^.outgoingBandwidth,result^.incomingBandwidth) div ENET_PEER_WINDOW_SIZE_SCALE)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
end else begin
result^.windowSize:=(Min(host^.outgoingBandwidth,result^.incomingBandwidth) div ENET_PEER_WINDOW_SIZE_SCALE)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
end;
if result^.windowSize<ENET_PROTOCOL_MINIMUM_WINDOW_SIZE then begin
result^.windowSize:=ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
end else if result^.windowSize>ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE then begin
result^.windowSize:=ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
end;
if host^.incomingBandwidth=0 then begin
windowSize:=ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
end else begin
windowSize:=(host^.incomingBandwidth div ENET_PEER_WINDOW_SIZE_SCALE)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
end;
if windowSize>ENET_NET_TO_HOST_32(command^.connect.windowSize) then begin
windowSize:=ENET_NET_TO_HOST_32(command^.connect.windowSize);
end;
if windowSize<ENET_PROTOCOL_MINIMUM_WINDOW_SIZE then begin
windowSize:=ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
end else if windowSize>ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE then begin
windowSize:=ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
end;
verifyCommand.header.command:=ENET_PROTOCOL_COMMAND_VERIFY_CONNECT or ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
verifyCommand.header.channelID:=$ff;
verifyCommand.verifyConnect.outgoingPeerID:=ENET_HOST_TO_NET_16(result^.incomingPeerID);
verifyCommand.verifyConnect.incomingSessionID:=incomingSessionID;
verifyCommand.verifyConnect.outgoingSessionID:=outgoingSessionID;
verifyCommand.verifyConnect.mtu:=ENET_HOST_TO_NET_32(result^.mtu);
verifyCommand.verifyConnect.windowSize:=ENET_HOST_TO_NET_32(windowSize);
verifyCommand.verifyConnect.channelCount:=ENET_HOST_TO_NET_32(channelCount);
verifyCommand.verifyConnect.incomingBandwidth:=ENET_HOST_TO_NET_32(host^.incomingBandwidth);
verifyCommand.verifyConnect.outgoingBandwidth:=ENET_HOST_TO_NET_32(host^.outgoingBandwidth);
verifyCommand.verifyConnect.packetThrottleInterval:=ENET_HOST_TO_NET_32(result^.packetThrottleInterval);
verifyCommand.verifyConnect.packetThrottleAcceleration:=ENET_HOST_TO_NET_32(result^.packetThrottleAcceleration);
verifyCommand.verifyConnect.packetThrottleDeceleration:=ENET_HOST_TO_NET_32(result^.packetThrottleDeceleration);
verifyCommand.verifyConnect.connectID:=result^.connectID;
enet_peer_queue_outgoing_command(result,@verifyCommand,nil,0,0);
result:=currentPeer;
end;
function enet_protocol_handle_send_reliable(host:PENetHost;peer:PENetPeer;command:PENetProtocol;currentData:PPAnsiChar):longint;
var dataLength:longint;
begin
if (command^.header.channelID>=peer^.channelCount) or ((peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER)) then begin
result:=-1;
exit;
end;
dataLength:=ENET_NET_TO_HOST_16(command^.sendReliable.dataLength);
inc(currentData^,dataLength);
if (dataLength>host^.maximumPacketSize) or (currentData^<host^.receivedData) or (currentData^>@host^.receivedData[host^.receivedDataLength]) then begin
result:=-1;
exit;
end;
if not assigned(enet_peer_queue_incoming_command(peer,command,@PAnsiChar(pointer(command))[sizeof(TENetProtocolSendReliable)],dataLength,ENET_PACKET_FLAG_RELIABLE,0)) then begin
result:=-1;
exit;
end;
result:=0;
end;
function enet_protocol_handle_send_unsequenced(host:PENetHost;peer:PENetPeer;command:PENetProtocol;currentData:PPAnsiChar):longint;
var unsequencedGroup,index:longword;
dataLength:Longint;
begin
if (command^.header.channelID>=peer^.channelCount) or ((peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER)) then begin
result:=-1;
exit;
end;
dataLength:=ENET_NET_TO_HOST_16(command^.sendUnsequenced.dataLength);
inc(currentData^,dataLength);
if (dataLength>host^.maximumPacketSize) or (currentData^<host^.receivedData) or (currentData^>@host^.receivedData[host^.receivedDataLength]) then begin
result:=-1;
exit;
end;
unsequencedGroup:=ENET_NET_TO_HOST_16(command^.sendUnsequenced.unsequencedGroup);
index:=unsequencedGroup mod ENET_PEER_UNSEQUENCED_WINDOW_SIZE;
if unsequencedGroup<peer^.incomingUnsequencedGroup then begin
inc(unsequencedGroup,$10000);
end;
if unsequencedGroup>=(peer^.incomingUnsequencedGroup+(ENET_PEER_FREE_UNSEQUENCED_WINDOWS*ENET_PEER_UNSEQUENCED_WINDOW_SIZE)) then begin
result:=0;
exit;
end;
unsequencedGroup:=unsequencedGroup and $FFFF;
if (unsequencedGroup-index)<>peer^.incomingUnsequencedGroup then begin
peer^.incomingUnsequencedGroup:=unsequencedGroup-index;
FillChar(peer^.unsequencedWindow,sizeof(peer^.unsequencedWindow),AnsiChar(#0));
end else if (peer^.unsequencedWindow[index shr 5] and (1 shl (index and 31)))<>0 then begin
result:=0;
exit;
end;
if not assigned(enet_peer_queue_incoming_command(peer,command,@PAnsiChar(pointer(command))[sizeof(TENetProtocolSendUnsequenced)],dataLength,ENET_PACKET_FLAG_UNSEQUENCED,0)) then begin
result:=-1;
exit;
end;
peer^.unsequencedWindow[index shr 5]:=peer^.unsequencedWindow[index shr 5] or (1 shl (index and 31));
result:=0;
end;
function enet_protocol_handle_send_unreliable(host:PENetHost;peer:PENetPeer;command:PENetProtocol;currentData:PPAnsiChar):longint;
var dataLength:longint;
begin
if (command^.header.channelID>=peer^.channelCount) or ((peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER)) then begin
result:=-1;
exit;
end;
dataLength:=ENET_NET_TO_HOST_16(command^.sendUnreliable.dataLength);
inc(currentData^,dataLength);
if (dataLength>host^.maximumPacketSize) or (currentData^<host^.receivedData) or (currentData^>@host^.receivedData[host^.receivedDataLength]) then begin
result:=-1;
exit;
end;
if not assigned(enet_peer_queue_incoming_command(peer,command,@PAnsiChar(pointer(command))[sizeof(TENetProtocolSendUnreliable)],dataLength,0,0)) then begin
result:=-1;
exit;
end;
result:=0;
end;
function enet_protocol_handle_send_fragment(host:PENetHost;peer:PENetPeer;command:PENetProtocol;currentData:PPAnsiChar):longint;
var fragmentNumber,fragmentCount,fragmentOffset,fragmentLength,startSequenceNumber,totalLength:longword;
channel:PENetChannel;
startWindow,currentWindow:word;
currentCommand:TENetListIterator;
startCommand:PENetIncomingCommand;
incomingCommand:PENetIncomingCommand;
hostCommand:TENetProtocol;
begin
startCommand:=nil;
if (command^.header.channelID>=peer^.channelCount) or ((peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER)) then begin
result:=-1;
exit;
end;
fragmentLength:=ENET_NET_TO_HOST_16(command^.sendFragment.dataLength);
inc(currentData^,fragmentLength);
if (fragmentLength>host^.maximumPacketSize) or (currentData^<host^.receivedData) or (currentData^>@host^.receivedData[host^.receivedDataLength]) then begin
result:=-1;
exit;
end;
channel:=@peer^.channels[command^.header.channelID];
startSequenceNumber:=ENET_NET_TO_HOST_16(command^.sendFragment.startSequenceNumber);
startWindow:=startSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
currentWindow:=channel^.incomingReliableSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
if startSequenceNumber<channel^.incomingReliableSequenceNumber then begin
inc(startWindow,ENET_PEER_RELIABLE_WINDOWS);
end;
if (startWindow<currentWindow) or (startWindow>=(currentWindow+(ENET_PEER_FREE_RELIABLE_WINDOWS-1))) then begin
result:=0;
exit;
end;
fragmentNumber:=ENET_NET_TO_HOST_32(command^.sendFragment.fragmentNumber);
fragmentCount:=ENET_NET_TO_HOST_32(command^.sendFragment.fragmentCount);
fragmentOffset:=ENET_NET_TO_HOST_32(command^.sendFragment.fragmentOffset);
totalLength:=ENET_NET_TO_HOST_32(command^.sendFragment.totalLength);
if (fragmentCount>ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) or (fragmentNumber>=fragmentCount) or
(totalLength>host^.maximumPacketSize) or (fragmentOffset>=totalLength) or
(fragmentLength>(totalLength-fragmentOffset)) then begin
result:=-1;
exit;
end;
currentCommand:=enet_list_previous(enet_list_end(@channel^.incomingReliableCommands));
while currentCommand<>enet_list_end(@channel^.incomingReliableCommands) do begin
incomingCommand:=PENetIncomingCommand(currentCommand);
if startSequenceNumber>=channel^.incomingReliableSequenceNumber then begin
if incomingCommand^.reliableSequenceNumber<channel^.incomingReliableSequenceNumber then begin
currentCommand:=enet_list_previous(currentCommand);
continue;
end;
end else if incomingCommand^.reliableSequenceNumber>=channel^.incomingReliableSequenceNumber then begin
break;
end;
if incomingCommand^.reliableSequenceNumber<=startSequenceNumber then begin
if incomingCommand^.reliableSequenceNumber<startSequenceNumber then begin
break;
end;
if ((incomingCommand^.command.header.command and ENET_PROTOCOL_COMMAND_MASK)<>ENET_PROTOCOL_COMMAND_SEND_FRAGMENT) or
(totalLength<>incomingCommand^.packet^.dataLength) or (fragmentCount<>incomingCommand^.fragmentCount) then begin
result:=-1;
exit;
end;
startCommand:=incomingCommand;
break;
end;
currentCommand:=enet_list_previous(currentCommand);
end;
if not assigned(startCommand) then begin
hostCommand:=command^;
hostCommand.header.reliableSequenceNumber:=startSequenceNumber;
startCommand:=enet_peer_queue_incoming_command(peer,@hostCommand,nil,totalLength,ENET_PACKET_FLAG_RELIABLE,fragmentCount);
if not assigned(startCommand) then begin
result:=-1;
exit;
end;
end;
if (startCommand^.fragments[fragmentNumber shr 5] and (1 shl (fragmentNumber and 31)))=0 then begin
dec(startCommand^.fragmentsRemaining);
startCommand^.fragments[fragmentNumber shr 5]:=startCommand^.fragments[fragmentNumber shr 5] or (1 shl (fragmentNumber and 31));
if (fragmentOffset+fragmentLength)>startCommand^.packet^.dataLength then begin
fragmentLength:=startCommand^.packet^.dataLength-fragmentOffset;
end;
Move(PAnsiChar(pointer(command))[sizeof(TENetProtocolSendFragment)],PAnsiChar(pointer(startCommand^.packet^.data))[fragmentOffset],fragmentLength);
if startCommand^.fragmentsRemaining<=0 then begin
enet_peer_dispatch_incoming_reliable_commands(peer,channel);
end;
end;
result:=0;
end;
function enet_protocol_handle_send_unreliable_fragment(host:PENetHost;peer:PENetPeer;command:PENetProtocol;currentData:PPAnsiChar):longint;
var fragmentNumber,fragmentCount,fragmentOffset,fragmentLength,reliableSequenceNumber,startSequenceNumber,totalLength:longword;
reliableWindow,currentWindow:word;
channel:PENetChannel;
currentCommand:TENetListIterator;
startCommand:PENetIncomingCommand;
incomingCommand:PENetIncomingCommand;
begin
startCommand:=nil;
if (command^.header.channelID>=peer^.channelCount) or ((peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER)) then begin
result:=-1;
exit;
end;
fragmentLength:=ENET_NET_TO_HOST_16(command^.sendFragment.dataLength);
inc(currentData^,fragmentLength);
if (fragmentLength>host^.maximumPacketSize) or (currentData^<host^.receivedData) or (currentData^>@host^.receivedData[host^.receivedDataLength]) then begin
result:=-1;
exit;
end;
channel:=@peer^.channels[command^.header.channelID];
reliableSequenceNumber:=command^.header.reliableSequenceNumber;
startSequenceNumber:=ENET_NET_TO_HOST_16(command^.sendFragment.startSequenceNumber);
reliableWindow:=reliableSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
currentWindow:=channel^.incomingReliableSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
if reliableSequenceNumber<channel^.incomingReliableSequenceNumber then begin
inc(reliableWindow,ENET_PEER_RELIABLE_WINDOWS);
end;
if (reliableWindow<currentWindow) or (reliableWindow>=(currentWindow+(ENET_PEER_FREE_RELIABLE_WINDOWS-1))) then begin
result:=0;
exit;
end;
if (reliableSequenceNumber=channel^.incomingReliableSequenceNumber) and (startSequenceNumber<=channel^.incomingUnreliableSequenceNumber) then begin
result:=0;
exit;
end;
fragmentNumber:=ENET_NET_TO_HOST_32(command^.sendFragment.fragmentNumber);
fragmentCount:=ENET_NET_TO_HOST_32(command^.sendFragment.fragmentCount);
fragmentOffset:=ENET_NET_TO_HOST_32(command^.sendFragment.fragmentOffset);
totalLength:=ENET_NET_TO_HOST_32(command^.sendFragment.totalLength);
if (fragmentCount>ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT) or
(fragmentNumber>=fragmentCount) or
(totalLength>host^.maximumPacketSize) or
(fragmentOffset>=totalLength) or
(fragmentLength>(totalLength-fragmentOffset)) then begin
result:=-1;
exit;
end;
currentCommand:=enet_list_previous(enet_list_end(@channel^.incomingUnreliableCommands));
while currentCommand<>enet_list_end(@channel^.incomingUnreliableCommands) do begin
incomingCommand:=PENetIncomingCommand(currentCommand);
if reliableSequenceNumber>=channel^.incomingReliableSequenceNumber then begin
if (incomingCommand^.reliableSequenceNumber<channel^.incomingReliableSequenceNumber) then begin
currentCommand:=enet_list_previous(currentCommand);
continue;
end;
end else if incomingCommand^.reliableSequenceNumber>=channel^.incomingReliableSequenceNumber then begin
break;
end;
if incomingCommand^.reliableSequenceNumber<reliableSequenceNumber then begin
break;
end;
if incomingCommand^.reliableSequenceNumber>reliableSequenceNumber then begin
currentCommand:=enet_list_previous(currentCommand);
continue;
end;
if incomingCommand^.unreliableSequenceNumber<=startSequenceNumber then begin
if incomingCommand^.unreliableSequenceNumber<startSequenceNumber then begin
break;
end;
if ((incomingCommand^.command.header.command and ENET_PROTOCOL_COMMAND_MASK)<>ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT) or
(totalLength<>incomingCommand^.packet^.dataLength) or (fragmentCount<>incomingCommand^.fragmentCount) then begin
result:=-1;
exit;
end;
startCommand:=incomingCommand;
break;
end;
currentCommand:=enet_list_previous(currentCommand);
end;
if not assigned(startCommand) then begin
startCommand:=enet_peer_queue_incoming_command(peer,command,nil,totalLength,ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT,fragmentCount);
if not assigned(startCommand) then begin
result:=-1;
exit;
end;
end;
if (startCommand^.fragments[fragmentNumber shr 5] and (1 shl (fragmentNumber and 31)))=0 then begin
dec(startCommand^.fragmentsRemaining);
startCommand^.fragments[fragmentNumber shr 5]:=startCommand^.fragments[fragmentNumber shr 5] or (1 shl (fragmentNumber and 31));
if (fragmentOffset+fragmentLength)>startCommand^.packet^.dataLength then begin
fragmentLength:=startCommand^.packet^.dataLength-fragmentOffset;
end;
Move(PAnsiChar(pointer(command))[sizeof(TENetProtocolSendFragment)],PAnsiChar(pointer(startCommand^.packet^.data))[fragmentOffset],fragmentLength);
if startCommand^.fragmentsRemaining<=0 then begin
enet_peer_dispatch_incoming_reliable_commands(peer,channel);
end;
end;
result:=0;
end;
function enet_protocol_handle_ping(host:PENetHost;peer:PENetPeer;command:PENetProtocol):longint;
begin
if (peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER) then begin
result:=-1;
end else begin
result:=0;
end;
end;
function enet_protocol_handle_bandwidth_limit(host:PENetHost;peer:PENetPeer;command:PENetProtocol):longint;
begin
if not (peer^.state in [ENET_PEER_STATE_CONNECTED,ENET_PEER_STATE_DISCONNECT_LATER]) then begin
result:=-1;
end else begin
if peer^.incomingBandwidth<>0 then begin
dec(host^.bandwidthLimitedPeers);
end;
peer^.incomingBandwidth:=ENET_NET_TO_HOST_32(command^.bandwidthLimit.incomingBandwidth);
peer^.outgoingBandwidth:=ENET_NET_TO_HOST_32(command^.bandwidthLimit.outgoingBandwidth);
if peer^.incomingBandwidth<>0 then begin
inc(host^.bandwidthLimitedPeers);
end;
if (peer^.incomingBandwidth=0) and (host^.outgoingBandwidth=0) then begin
peer^.windowSize:=ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
end else begin
peer^.windowSize:=(Min(peer^.incomingBandwidth,host^.outgoingBandwidth) div ENET_PEER_WINDOW_SIZE_SCALE)*ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
end;
if peer^.windowSize<ENET_PROTOCOL_MINIMUM_WINDOW_SIZE then begin
peer^.windowSize:=ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
end else if peer^.windowSize>ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE then begin
peer^.windowSize:=ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
end;
result:=0;
end;
end;
function enet_protocol_handle_throttle_configure(host:PENetHost;peer:PENetPeer;command:PENetProtocol):longint;
begin
if not (peer^.state in [ENET_PEER_STATE_CONNECTED,ENET_PEER_STATE_DISCONNECT_LATER]) then begin
result:=-1;
end else begin
peer^.packetThrottleInterval:=ENET_NET_TO_HOST_32(command^.throttleConfigure.packetThrottleInterval);
peer^.packetThrottleAcceleration:=ENET_NET_TO_HOST_32(command^.throttleConfigure.packetThrottleAcceleration);
peer^.packetThrottleDeceleration:=ENET_NET_TO_HOST_32(command^.throttleConfigure.packetThrottleDeceleration);
result:=0;
end;
end;
function enet_protocol_handle_disconnect(host:PENetHost;peer:PENetPeer;command:PENetProtocol):longint;
begin
if peer^.state in [ENET_PEER_STATE_DISCONNECTED,ENET_PEER_STATE_ZOMBIE,ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT] then begin
result:=0;
exit;
end;
enet_peer_reset_queues(peer);
if peer^.state in [ENET_PEER_STATE_CONNECTION_SUCCEEDED,ENET_PEER_STATE_DISCONNECTING] then begin
enet_protocol_dispatch_state(host,peer,ENET_PEER_STATE_ZOMBIE);
end else if (peer^.state<>ENET_PEER_STATE_CONNECTED) and (peer^.state<>ENET_PEER_STATE_DISCONNECT_LATER) then begin
if peer^.state=ENET_PEER_STATE_CONNECTION_PENDING then begin
host^.recalculateBandwidthLimits:=1;
end;
enet_peer_reset(peer);
end else if (command^.header.command and ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)<>0 then begin
enet_protocol_change_state(host,peer,ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT);
end else begin
enet_protocol_dispatch_state(host,peer,ENET_PEER_STATE_ZOMBIE);
end;
if peer^.state<>ENET_PEER_STATE_DISCONNECTED then begin
peer^.eventData:=ENET_NET_TO_HOST_32(command^.disconnect.data);
end;
result:=0;
end;
function enet_protocol_handle_acknowledge(host:PENetHost;event:PENetEvent;peer:PENetPeer;command:PENetProtocol):longint;
var roundTripTime,receivedSentTime,receivedReliableSequenceNumber:longword;
commandNumber:TENetProtocolCommand;
begin
if peer^.state in [ENET_PEER_STATE_DISCONNECTED,ENET_PEER_STATE_ZOMBIE] then begin
result:=0;
exit;
end;
receivedSentTime:=ENET_NET_TO_HOST_16(command^.acknowledge.receivedSentTime);
receivedSentTime:=receivedSentTime or (host^.serviceTime and $FFFF0000);
if (receivedSentTime and $8000)>(host^.serviceTime and $8000) then begin
dec(receivedSentTime,$10000);
end;
if ENET_TIME_LESS(host^.serviceTime,receivedSentTime) then begin
result:=0;
exit;
end;
peer^.lastReceiveTime:=host^.serviceTime;
peer^.earliestTimeout:=0;
roundTripTime:=ENET_TIME_DIFFERENCE(host^.serviceTime,receivedSentTime);
enet_peer_throttle(peer,roundTripTime);
dec(peer^.roundTripTimeVariance,peer^.roundTripTimeVariance div 4);
if roundTripTime>=peer^.roundTripTime then begin
inc(peer^.roundTripTime,(roundTripTime-peer^.roundTripTime) div 8);
inc(peer^.roundTripTimeVariance,(roundTripTime-peer^.roundTripTime) div 4);
end else begin
dec(peer^.roundTripTime,(peer^.roundTripTime-roundTripTime) div 8);
inc(peer^.roundTripTimeVariance,(peer^.roundTripTime-roundTripTime) div 4);
end;
if peer^.roundTripTime<peer^.lowestRoundTripTime then begin
peer^.lowestRoundTripTime:=peer^.roundTripTime;
end;
if peer^.roundTripTimeVariance>peer^.highestRoundTripTimeVariance then begin
peer^.highestRoundTripTimeVariance:=peer^.roundTripTimeVariance;
end;
if (peer^.packetThrottleEpoch=0) or (ENET_TIME_DIFFERENCE(host^.serviceTime,peer^.packetThrottleEpoch)>=longint(peer^.packetThrottleInterval)) then begin
peer^.lastRoundTripTime:=peer^.lowestRoundTripTime;
peer^.lastRoundTripTimeVariance:=peer^.highestRoundTripTimeVariance;
peer^.lowestRoundTripTime:=peer^.roundTripTime;
peer^.highestRoundTripTimeVariance:=peer^.roundTripTimeVariance;
peer^.packetThrottleEpoch:=host^.serviceTime;
end;
receivedReliableSequenceNumber:=ENET_NET_TO_HOST_16(command^.acknowledge.receivedReliableSequenceNumber);
commandNumber:=enet_protocol_remove_sent_reliable_command(peer,receivedReliableSequenceNumber,command^.header.channelID);
case peer^.state of
ENET_PEER_STATE_ACKNOWLEDGING_CONNECT:begin
if commandNumber<>ENET_PROTOCOL_COMMAND_VERIFY_CONNECT then begin
result:=-1;
exit;
end;
enet_protocol_notify_connect(host,peer,event);
end;
ENET_PEER_STATE_DISCONNECTING:begin
if commandNumber<>ENET_PROTOCOL_COMMAND_DISCONNECT then begin
result:=-1;
exit;
end;
enet_protocol_notify_disconnect(host,peer,event);
end;
ENET_PEER_STATE_DISCONNECT_LATER:begin
if enet_list_empty(@peer^.outgoingReliableCommands) and enet_list_empty(@peer^.outgoingUnreliableCommands) and enet_list_empty(@peer^.sentReliableCommands) then begin
enet_peer_disconnect(peer,peer^.eventData);
end;
end;
end;
result:=0;
end;
function enet_protocol_handle_verify_connect(host:PENetHost;event:PENetEvent;peer:PENetPeer;command:PENetProtocol):longint;
var mtu,windowSize:longword;
channelCount:longword;
begin
if peer^.state<>ENET_PEER_STATE_CONNECTING then begin
result:=0;
exit;
end;
channelCount:=ENET_NET_TO_HOST_32(command^.verifyConnect.channelCount);
if (channelCount<ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) or
(channelCount>ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) or
(ENET_NET_TO_HOST_32(command^.verifyConnect.packetThrottleInterval)<>peer^.packetThrottleInterval) or
(ENET_NET_TO_HOST_32(command^.verifyConnect.packetThrottleAcceleration)<>peer^.packetThrottleAcceleration) or
(ENET_NET_TO_HOST_32(command^.verifyConnect.packetThrottleDeceleration)<>peer^.packetThrottleDeceleration) or
(command^.verifyConnect.connectID<>peer^.connectID) then begin
peer^.eventData:=0;
enet_protocol_dispatch_state (host, peer, ENET_PEER_STATE_ZOMBIE);
result:=-1;
exit;
end;
enet_protocol_remove_sent_reliable_command(peer,1,$FF);
if channelCount<peer^.channelCount then begin
peer^.channelCount:=channelCount;
end;
peer^.outgoingPeerID:=ENET_NET_TO_HOST_16(command^.verifyConnect.outgoingPeerID);
peer^.incomingSessionID:=command^.verifyConnect.incomingSessionID;
peer^.outgoingSessionID:=command^.verifyConnect.outgoingSessionID;
mtu:=ENET_NET_TO_HOST_32(command^.verifyConnect.mtu);
if mtu<ENET_PROTOCOL_MINIMUM_MTU then begin
mtu:=ENET_PROTOCOL_MINIMUM_MTU;
end else if mtu>ENET_PROTOCOL_MAXIMUM_MTU then begin
mtu:=ENET_PROTOCOL_MAXIMUM_MTU;
end;
if mtu<peer^.mtu then begin
peer^.mtu:=mtu;
end;
windowSize:=ENET_NET_TO_HOST_32(command^.verifyConnect.windowSize);
if windowSize<ENET_PROTOCOL_MINIMUM_WINDOW_SIZE then begin
windowSize:=ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
end;
if windowSize>ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE then begin
windowSize:=ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
end;
if windowSize<peer^.windowSize then begin
peer^.windowSize:=windowSize;
end;
peer^.incomingBandwidth:=ENET_NET_TO_HOST_32(command^.verifyConnect.incomingBandwidth);
peer^.outgoingBandwidth:=ENET_NET_TO_HOST_32(command^.verifyConnect.outgoingBandwidth);
enet_protocol_notify_connect(host,peer,event);
result:=0;
end;
function enet_protocol_handle_incoming_commands(host:PENetHost;event:PENetEvent):longint;
label commandError;
var header:PENetProtocolHeader;
command:PENetProtocol;
peer:PENetPeer;
currentData:PAnsiChar;
checksum:PLongword;
headerSize,originalSize,desiredChecksum,commandSize:longword;
peerID,flags,sentTime:word;
sessionID,commandNumber:byte;
buffer:TENetBuffer;
begin
if (host^.receivedDataLength<SizeOf(longword)) and (PENetProtocolHeader(nil)^.sentTime<>0) then begin
result:=0;
exit;
end;
header:=PENetProtocolHeader(host^.receivedData);
peerID:=ENET_NET_TO_HOST_16 (header^.peerID);
sessionID:=(peerID and ENET_PROTOCOL_HEADER_SESSION_MASK) shr ENET_PROTOCOL_HEADER_SESSION_SHIFT;
flags:=peerID and ENET_PROTOCOL_HEADER_FLAG_MASK;
peerID:=peerID and not (ENET_PROTOCOL_HEADER_FLAG_MASK or ENET_PROTOCOL_HEADER_SESSION_MASK);
if (flags and ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)<>0 then begin
headerSize:=sizeof(TENetProtocolHeader);
end else begin
headerSize:=sizeof(longword);
end;
if assigned(host^.checksum) then begin
inc(headerSize,sizeof(longword));
end;
if peerID=ENET_PROTOCOL_MAXIMUM_PEER_ID then begin
peer:=nil;
end else if peerID>=host^.peerCount then begin
result:=0;
exit;
end else begin
peer:=@host^.peers[peerID];
if (peer^.state in [ENET_PEER_STATE_DISCONNECTED,ENET_PEER_STATE_ZOMBIE]) or
((peer^.outgoingPeerID<ENET_PROTOCOL_MAXIMUM_PEER_ID) and (sessionID<>peer^.incomingSessionID)) or
((not enet_compare_address(peer^.address.host,host^.receivedAddress.host)) and
(not enet_compare_address(peer^.address.host,ENET_HOST_BROADCAST_)) and
(peer^.address.host.addr[0]<>$ff)) then begin
result:=0;
exit;
end;
if (flags and ENET_PROTOCOL_HEADER_FLAG_COMPRESSED)<>0 then begin
if (not assigned(host^.compressor.context)) or not assigned(host^.compressor.decompress) then begin
result:=0;
exit;
end;
originalSize:=host^.compressor.decompress(host^.compressor.context,pointer(@pansichar(host^.receivedData)[headerSize]),longword(host^.receivedDataLength)-headerSize,@host^.packetData[1,headerSize],sizeof(host^.packetData[1])-headerSize);
if (originalSize<=0) or (originalSize>(sizeof(host^.packetData[1])-headerSize)) then begin
result:=0;
exit;
end;
move(header,host^.packetData[1],headerSize);
host^.receivedData:=@host^.packetData[1];
host^.receivedDataLength:=headerSize+originalSize;
end;
if assigned(host^.checksum) then begin
checksum:=pointer(@host^.receivedData[headerSize-sizeof(longword)]);
desiredChecksum:=checksum^;
if assigned(peer) then begin
checksum^:=peer^.connectID;
end else begin
checksum^:=0;
end;
buffer.data:=host^.receivedData;
buffer.dataLength:=host^.receivedDataLength;
if host^.checksum(@buffer,1)<>desiredChecksum then begin
result:=0;
exit;
end;
end;
if assigned(peer) then begin
peer^.address:=host^.receivedAddress;
inc(peer^.incomingDataTotal,host^.receivedDataLength);
end;
currentData:=@host^.receivedData[headerSize];
while currentData<@host^.receivedData[host^.receivedDataLength] do begin
command:=PENetProtocol(currentData);
if PAnsiChar(@currentData[sizeof(TENetProtocolCommandHeader)])>PAnsiChar(@host^.receivedData[host^.receivedDataLength]) then begin
break;
end;
commandNumber:=command^.header.command and ENET_PROTOCOL_COMMAND_MASK;
if commandNumber>=ENET_PROTOCOL_COMMAND_COUNT then begin
break;
end;
commandSize:=commandSizes[commandNumber];
if (commandSize=0) or (PAnsiChar(@currentData[commandSize])>PAnsiChar(@host^.receivedData[host^.receivedDataLength])) then begin
break;
end;
inc(currentData,commandSize);
if (not assigned(peer)) and (commandNumber<>ENET_PROTOCOL_COMMAND_CONNECT) then begin
break;
end;
command^.header.reliableSequenceNumber:=ENET_NET_TO_HOST_16(command^.header.reliableSequenceNumber);
case commandNumber of
ENET_PROTOCOL_COMMAND_ACKNOWLEDGE:begin
if enet_protocol_handle_acknowledge(host,event,peer,command)<>0 then begin
goto commandError;
end;
end;
ENET_PROTOCOL_COMMAND_CONNECT:begin
peer:=enet_protocol_handle_connect(host,header,command);
if not assigned(peer) then begin
goto commandError;
end;
end;
ENET_PROTOCOL_COMMAND_VERIFY_CONNECT:begin
if enet_protocol_handle_verify_connect(host,event,peer,command)<>0 then begin
goto commandError;
end;
end;
ENET_PROTOCOL_COMMAND_DISCONNECT:begin
if enet_protocol_handle_disconnect(host,peer,command)<>0 then begin
goto commandError;
end;
end;
ENET_PROTOCOL_COMMAND_PING:begin
if enet_protocol_handle_ping(host,peer,command)<>0 then begin
goto commandError;
end;
end;
ENET_PROTOCOL_COMMAND_SEND_RELIABLE:begin
if enet_protocol_handle_send_reliable(host,peer,command,@currentData)<>0 then begin
goto commandError;
end;
end;
ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE:begin
if enet_protocol_handle_send_unreliable(host,peer,command,@currentData)<>0 then begin
goto commandError;
end;
end;
ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED:begin
if enet_protocol_handle_send_unsequenced(host,peer,command,@currentData)<>0 then begin
goto commandError;
end;
end;
ENET_PROTOCOL_COMMAND_SEND_FRAGMENT:begin
if enet_protocol_handle_send_fragment(host,peer,command,@currentData)<>0 then begin
goto commandError;
end;
end;
ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT:begin
if enet_protocol_handle_bandwidth_limit(host,peer,command)<>0 then begin
goto commandError;
end;
end;
ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE:begin
if enet_protocol_handle_throttle_configure(host,peer,command)<>0 then begin
goto commandError;
end;
end;
ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT:begin
if enet_protocol_handle_send_unreliable_fragment(host,peer,command,@currentData)<>0 then begin
goto commandError;
end;
end;
else begin
goto commandError;
end;
end;
if assigned(peer) and ((command^.header.command and ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE)<>0) then begin
if (flags and ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)=0 then begin
break;
end;
sentTime:=ENET_NET_TO_HOST_16(header^.sentTime);
case peer^.state of
ENET_PEER_STATE_DISCONNECTING,ENET_PEER_STATE_ACKNOWLEDGING_CONNECT,ENET_PEER_STATE_DISCONNECTED,ENET_PEER_STATE_ZOMBIE:begin
end;
ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT:begin
if (command^.header.command and ENET_PROTOCOL_COMMAND_MASK)=ENET_PROTOCOL_COMMAND_DISCONNECT then begin
enet_peer_queue_acknowledgement(peer,command,sentTime);
end;
end;
else begin
enet_peer_queue_acknowledgement(peer,command,sentTime);
end;
end;
end;
end;
end;
commandError:
if assigned(event) and (event^.type_<>ENET_EVENT_TYPE_NONE) then begin
result:=1;
end else begin
result:=0;
end;
end;
function enet_protocol_receive_incoming_commands(host:PENetHost;event:PENetEvent;family:TENetAddressFamily):longint;
var packets,receivedLength:longint;
buffer:TENetBuffer;
begin
for packets:=0 to 255 do begin
buffer.data:=@host^.packetData[0];
buffer.dataLength:=sizeof(host^.packetData[0]);
if family=ENET_IPV4 then begin
receivedLength:=enet_socket_receive(host^.socket4,@host^.receivedAddress,@buffer,1,family);
end else begin
receivedLength:=enet_socket_receive(host^.socket6,@host^.receivedAddress,@buffer,1,family);
end;
if receivedLength<0 then begin
result:=-1;
exit;
end;
if receivedLength=0 then begin
result:=0;
exit;
end;
if enet_get_address_family(@host^.receivedAddress)<>family then begin
result:=-1;
exit;
end;
host^.receivedData:=@host^.packetData[0];
host^.receivedDataLength:=receivedLength;
inc(host^.totalReceivedData,receivedLength);
inc(host^.totalReceivedPackets);
if assigned(host^.intercept) then begin
case host^.intercept(host,event) of
1:begin
if assigned(event) and (event^.type_<>ENET_EVENT_TYPE_NONE) then begin
result:=1;
exit;
end;
continue;
end;
-1:begin
result:=-1;
exit;
end;
end;
end;
case enet_protocol_handle_incoming_commands(host,event) of
1:begin
result:=1;
exit;
end;
-1:begin
result:=-1;
exit;
end;
end;
end;
result:=-1;
end;
procedure enet_protocol_send_acknowledgements(host:PENetHost;peer:PENetPeer);
var command:PENetProtocol;
buffer:PENetBuffer;
acknowledgement:PENetAcknowledgement;
currentAcknowledgement:TENetListIterator;
reliableSequenceNumber:word;
begin
command:=@host^.commands[host^.commandCount];
buffer:=@host^.buffers[host^.bufferCount];
currentAcknowledgement:=enet_list_begin(@peer^.acknowledgements);
while currentAcknowledgement<>enet_list_end(@peer^.acknowledgements) do begin
if (ptruint(pointer(command))>=ptruint(pointer(@host^.commandCount))) or
(ptruint(pointer(buffer))>=ptruint(pointer(@host^.bufferCount))) or
((peer^.mtu-longword(host^.packetSize))<sizeof(TENetProtocolAcknowledge)) then begin
host^.continueSending:=1;
break;
end;
acknowledgement:=PENetAcknowledgement(currentAcknowledgement);
currentAcknowledgement:=enet_list_next(currentAcknowledgement);
buffer^.data:=pointer(command);
buffer^.dataLength:=sizeof(TENetProtocolAcknowledge);
inc(host^.packetSize,buffer^.dataLength);
reliableSequenceNumber:=ENET_HOST_TO_NET_16(acknowledgement^.command.header.reliableSequenceNumber);
command^.header.command:=ENET_PROTOCOL_COMMAND_ACKNOWLEDGE;
command^.header.channelID:=acknowledgement^.command.header.channelID;
command^.header.reliableSequenceNumber:=reliableSequenceNumber;
command^.acknowledge.receivedReliableSequenceNumber:=reliableSequenceNumber;
command^.acknowledge.receivedSentTime:=ENET_HOST_TO_NET_16(acknowledgement^.sentTime);
if (acknowledgement^.command.header.command and ENET_PROTOCOL_COMMAND_MASK)=ENET_PROTOCOL_COMMAND_DISCONNECT then begin
enet_protocol_dispatch_state(host,peer,ENET_PEER_STATE_ZOMBIE);
end;
enet_list_remove(@acknowledgement^.acknowledgementList);
FreeMem(acknowledgement);
inc(command);
inc(buffer);
end;
host^.commandCount:=(ptruint(pointer(@command))-ptruint(pointer(@host^.commands))) div SizeOf(TENetProtocol);
host^.bufferCount:=(ptruint(pointer(@buffer))-ptruint(pointer(@host^.buffers))) div SizeOf(TENetBuffer);
end;
procedure enet_protocol_send_unreliable_outgoing_commands(host:PENetHost;peer:PENetPeer);
var command:PENetProtocol;
buffer:PENetBuffer;
outgoingCommand:PENetOutgoingCommand;
currentCommand:TENetListIterator;
commandSize:longword;
reliableSequenceNumber,unreliableSequenceNumber:word;
begin
command:=@host^.commands[host^.commandCount];
buffer:=@host^.buffers[host^.bufferCount];
currentCommand:=enet_list_begin(@peer^.outgoingUnreliableCommands);
while currentCommand<>enet_list_end(@peer^.outgoingUnreliableCommands) do begin
outgoingCommand:=PENetOutgoingCommand(currentCommand);
commandSize:=commandSizes[outgoingCommand^.command.header.command and ENET_PROTOCOL_COMMAND_MASK];
if (ptruint(pointer(command))>=ptruint(pointer(@host^.commandCount))) or
((ptruint(pointer(buffer))+ptruint(sizeof(TENetBuffer)))>=ptruint(pointer(@host^.bufferCount))) or
((peer^.mtu-longword(host^.packetSize))<commandSize) or
((not assigned(outgoingCommand^.packet)) and
((peer^.mtu-longword(host^.packetSize))<(commandSize+outgoingCommand^.fragmentLength))) then begin
host^.continueSending:=1;
break;
end;
currentCommand:=enet_list_next(currentCommand);
if assigned(outgoingCommand^.packet) and (outgoingCommand^.fragmentOffset=0) then begin
peer^.packetThrottleCounter:=(peer^.packetThrottleCounter+ENET_PEER_PACKET_THROTTLE_COUNTER) mod ENET_PEER_PACKET_THROTTLE_SCALE;
if peer^.packetThrottleCounter>peer^.packetThrottle then begin
reliableSequenceNumber:=outgoingCommand^.reliableSequenceNumber;
unreliableSequenceNumber:=outgoingCommand^.unreliableSequenceNumber;
while true do begin
dec(outgoingCommand^.packet^.referenceCount);
if outgoingCommand^.packet^.referenceCount=0 then begin
enet_packet_destroy(outgoingCommand^.packet);
end;
enet_list_remove(@outgoingCommand^.outgoingCommandList);
FreeMem(outgoingCommand);
if currentCommand=enet_list_end(@peer^.outgoingUnreliableCommands) then begin
break;
end;
outgoingCommand:=PENetOutgoingCommand(currentCommand);
if (outgoingCommand^.reliableSequenceNumber<>reliableSequenceNumber) or
(outgoingCommand^.unreliableSequenceNumber<>unreliableSequenceNumber) then begin
break;
end;
currentCommand:=enet_list_next(currentCommand);
end;
continue;
end;
end;
buffer^.data:=pointer(command);
buffer^.dataLength:=commandSize;
inc(host^.packetSize,buffer^.dataLength);
command^:=outgoingCommand^.command;
enet_list_remove(@outgoingCommand^.outgoingCommandList);
if assigned(outgoingCommand^.packet) then begin
inc(buffer);
buffer^.data:=@outgoingCommand^.packet^.data[outgoingCommand^.fragmentOffset];
buffer^.dataLength:=outgoingCommand^.fragmentLength;
inc(host^.packetSize,buffer^.dataLength);
enet_list_insert(enet_list_end(@peer^.sentUnreliableCommands),outgoingCommand);
end else begin
FreeMem(outgoingCommand);
end;
inc(command);
inc(buffer);
end;
host^.commandCount:=(ptruint(pointer(@command))-ptruint(pointer(@host^.commands))) div SizeOf(TENetProtocol);
host^.bufferCount:=(ptruint(pointer(@buffer))-ptruint(pointer(@host^.buffers))) div SizeOf(TENetBuffer);
if (peer^.state=ENET_PEER_STATE_DISCONNECT_LATER) and
enet_list_empty(@peer^.outgoingReliableCommands) and
enet_list_empty(@peer^.outgoingUnreliableCommands) and
enet_list_empty(@peer^.sentReliableCommands) then begin
enet_peer_disconnect(peer,peer^.eventData);
end;
end;
function enet_protocol_check_timeouts(host:PENetHost;peer:PENetPeer;event:PENetEvent):longint;
var outgoingCommand:PENetOutgoingCommand;
currentCommand,insertPosition:TENetListIterator;
begin
currentCommand:=enet_list_begin(@peer^.sentReliableCommands);
insertPosition:=enet_list_begin(@peer^.outgoingReliableCommands);
while currentCommand<>enet_list_end(@peer^.sentReliableCommands) do begin
outgoingCommand:=PENetOutgoingCommand(currentCommand);
currentCommand:=enet_list_next(currentCommand);
if ENET_TIME_DIFFERENCE(host^.serviceTime,outgoingCommand^.sentTime)<longint(outgoingCommand^.roundTripTimeout) then begin
continue;
end;
if (peer^.earliestTimeout=0) or ENET_TIME_LESS(outgoingCommand^.sentTime,peer^.earliestTimeout) then begin
peer^.earliestTimeout:=outgoingCommand^.sentTime;
end;
if (peer^.earliestTimeout<>0) and
((ENET_TIME_DIFFERENCE(host^.serviceTime,peer^.earliestTimeout)>=longint(peer^.timeoutMaximum)) or
((outgoingCommand^.roundTripTimeout>=outgoingCommand^.roundTripTimeoutLimit) and
(ENET_TIME_DIFFERENCE(host^.serviceTime,peer^.earliestTimeout)>=longint(peer^.timeoutMinimum)))) then begin
enet_protocol_notify_disconnect(host,peer,event);
result:=1;
exit;
end;
if assigned(outgoingCommand^.packet) then begin
dec(peer^.reliableDataInTransit,outgoingCommand^.fragmentLength);
end;
inc(peer^.packetsLost);
inc(outgoingCommand^.roundTripTimeout,outgoingCommand^.roundTripTimeout);
enet_list_insert (insertPosition,enet_list_remove(@outgoingCommand^.outgoingCommandList));
if (currentCommand=enet_list_begin(@peer^.sentReliableCommands)) and not enet_list_empty(@peer^.sentReliableCommands) then begin
outgoingCommand:=PENetOutgoingCommand(currentCommand);
peer^.nextTimeout:=outgoingCommand^.sentTime+outgoingCommand^.roundTripTimeout;
end;
end;
result:=0;
end;
function enet_protocol_send_reliable_outgoing_commands(host:PENetHost;peer:PENetPeer):longint;
var command:PENetProtocol;
buffer:PENetBuffer;
outgoingCommand:PENetOutgoingCommand;
currentCommand:TENetListIterator;
channel:PENetChannel;
reliableWindow:word;
commandSize:word;
windowExceeded,windowWrap,canPing:longint;
windowSize:longword;
begin
command:=@host^.commands[host^.commandCount];
buffer:=@host^.buffers[host^.bufferCount];
windowExceeded:=0;
windowWrap:=0;
canPing:=1;
currentCommand:=enet_list_begin(@peer^.outgoingReliableCommands);
while currentCommand<>enet_list_end(@peer^.outgoingReliableCommands) do begin
outgoingCommand:=PENetOutgoingCommand(currentCommand);
if outgoingCommand^.command.header.channelID<peer^.channelCount then begin
channel:=@peer^.channels[outgoingCommand^.command.header.channelID];
end else begin
channel:=nil;
end;
reliableWindow:=outgoingCommand^.reliableSequenceNumber div ENET_PEER_RELIABLE_WINDOW_SIZE;
if assigned(channel) then begin
if ((windowWrap=0) and (outgoingCommand^.sendAttempts<1) and
((outgoingCommand^.reliableSequenceNumber mod ENET_PEER_RELIABLE_WINDOW_SIZE)=0) and
((channel^.reliableWindows[(reliableWindow+(ENET_PEER_RELIABLE_WINDOWS-1)) mod ENET_PEER_RELIABLE_WINDOWS]>=ENET_PEER_RELIABLE_WINDOW_SIZE) or
(channel^.usedReliableWindows and ((((1 shl ENET_PEER_FREE_RELIABLE_WINDOWS)-1) shl reliableWindow) or (((1 shl ENET_PEER_FREE_RELIABLE_WINDOWS)-1) shr (ENET_PEER_RELIABLE_WINDOW_SIZE-reliableWindow)))<>0))) then begin
windowWrap:=1;
end;
if windowWrap<>0 then begin
currentCommand:=enet_list_next (currentCommand);
continue;
end;
end;
if assigned(outgoingCommand^.packet) then begin
if windowExceeded=0 then begin
windowSize:=(peer^.packetThrottle*peer^.windowSize) div ENET_PEER_PACKET_THROTTLE_SCALE;
if (peer^.reliableDataInTransit+outgoingCommand^.fragmentLength)>Max(windowSize,peer^.mtu) then begin
windowExceeded:=1;
end;
end;
if windowExceeded<>0 then begin
currentCommand:=enet_list_next(currentCommand);
continue;
end;
end;
canPing:=0;
commandSize:=commandSizes[outgoingCommand^.command.header.command and ENET_PROTOCOL_COMMAND_MASK];
if (ptruint(pointer(command))>=ptruint(pointer(@host^.commandCount))) or
((ptruint(pointer(buffer))+ptruint(sizeof(TENetBuffer)))>=ptruint(pointer(@host^.bufferCount))) or
((peer^.mtu-longword(host^.packetSize))<commandSize) or
((not assigned(outgoingCommand^.packet)) and
(word(peer^.mtu-longword(host^.packetSize))<word(commandSize+outgoingCommand^.fragmentLength))) then begin
host^.continueSending:=1;
break;
end;
currentCommand:=enet_list_next(currentCommand);
if assigned(channel) and (outgoingCommand^.sendAttempts<1) then begin
channel^.usedReliableWindows:=channel^.usedReliableWindows or (1 shl reliableWindow);
inc(channel^.reliableWindows[reliableWindow]);
end;
inc(outgoingCommand^.sendAttempts);
if outgoingCommand^.roundTripTimeout=0 then begin
outgoingCommand^.roundTripTimeout:=peer^.roundTripTime+(4*peer^.roundTripTimeVariance);
outgoingCommand^.roundTripTimeoutLimit:=peer^.timeoutLimit*outgoingCommand^.roundTripTimeout;
end;
if enet_list_empty(@peer^.sentReliableCommands) then begin
peer^.nextTimeout:=host^.serviceTime+outgoingCommand^.roundTripTimeout;
end;
enet_list_insert(enet_list_end(@peer^.sentReliableCommands),enet_list_remove(@outgoingCommand^.outgoingCommandList));
outgoingCommand^.sentTime:=host^.serviceTime;
buffer^.data:=pointer(command);
buffer^.dataLength:=commandSize;
inc(host^.packetSize,buffer^.dataLength);
host^.headerFlags:=host^.headerFlags or ENET_PROTOCOL_HEADER_FLAG_SENT_TIME;
command^:=outgoingCommand^.command;
if assigned(outgoingCommand^.packet) then begin
inc(buffer);
buffer^.data:=@outgoingCommand^.packet^.data[outgoingCommand^.fragmentOffset];
buffer^.dataLength:=outgoingCommand^.fragmentLength;
inc(host^.packetSize,outgoingCommand^.fragmentLength);
inc(peer^.reliableDataInTransit,outgoingCommand^.fragmentLength);
end;
inc(peer^.packetsSent);
inc(command);
inc(buffer);
end;
host^.commandCount:=(ptruint(pointer(@command))-ptruint(pointer(@host^.commands))) div SizeOf(TENetProtocol);
host^.bufferCount:=(ptruint(pointer(@buffer))-ptruint(pointer(@host^.buffers))) div SizeOf(TENetBuffer);
result:=canPing;
end;
function enet_protocol_send_outgoing_commands(host:PENetHost;event:PENetEvent;checkForTimeouts:longint):longint;
var headerData:array[0..(sizeof(TENetProtocolHeader)+sizeof(longword))-1] of byte;
header:PENetProtocolHeader;
currentPeer:PENetPeer;
sentLength:longint;
shouldCompress,packetLoss,originalSize,compressedSize:longword;
family:TENetAddressFamily;
socket:TENetSocket;
checksum:plongword;
begin
header:=pointer(@headerData);
//shouldCompress:=0;
host^.continueSending:=1;
while host^.continueSending<>0 do begin
host^.continueSending:=0;
currentPeer:=@host^.peers[0];
while ptruint(pointer(currentPeer))<ptruint(pointer(@host^.peers [host^.peerCount])) do begin
if currentPeer^.state in [ENET_PEER_STATE_DISCONNECTED,ENET_PEER_STATE_ZOMBIE] then begin
inc(currentPeer);
continue;
end;
host^.headerFlags:=0;
host^.commandCount:=0;
host^.bufferCount:=1;
host^.packetSize:=sizeof(TENetProtocolHeader);
if not enet_list_empty(@currentPeer^.acknowledgements) then begin
enet_protocol_send_acknowledgements(host,currentPeer);
end;
if (checkForTimeouts<>0) and
(not enet_list_empty(@currentPeer^.sentReliableCommands)) and
ENET_TIME_GREATER_EQUAL(host^.serviceTime,currentPeer^.nextTimeout) and
(enet_protocol_check_timeouts(host,currentPeer,event)=1) then begin
if assigned(event) and (event^.type_<>ENET_EVENT_TYPE_NONE) then begin
result:=1;
exit;
end else begin
inc(currentPeer);
continue;
end;
end;
if ((enet_list_empty(@currentPeer^.outgoingReliableCommands) or
(enet_protocol_send_reliable_outgoing_commands(host,currentPeer)<>0)) and
enet_list_empty(@currentPeer^.sentReliableCommands) and
(ENET_TIME_DIFFERENCE(host^.serviceTime,currentPeer^.lastReceiveTime)>=longint(currentPeer^.pingInterval)) and
(longword(currentPeer^.mtu-longword(host^.packetSize))>=longword(sizeof(TENetProtocolPing)))) then begin
enet_peer_ping(currentPeer);
enet_protocol_send_reliable_outgoing_commands(host,currentPeer);
end;
if not enet_list_empty(@currentPeer^.outgoingUnreliableCommands) then begin
enet_protocol_send_unreliable_outgoing_commands(host,currentPeer);
end;
if host^.commandCount=0 then begin
inc(currentPeer);
continue;
end;
if currentPeer^.packetLossEpoch=0 then begin
currentPeer^.packetLossEpoch:=host^.serviceTime;
end else if (ENET_TIME_DIFFERENCE(host^.serviceTime,currentPeer^.packetLossEpoch)>=ENET_PEER_PACKET_LOSS_INTERVAL) and (currentPeer^.packetsSent>0) then begin
packetLoss:=(currentPeer^.packetsLost div ENET_PEER_PACKET_LOSS_SCALE) div currentPeer^.packetsSent;
{$ifdef ENET_DEBUG}
if assigned(currentPeer^.channels) then begin
writeln('peer ',currentPeer^.incomingPeerID,': ',
currentPeer^.packetLoss/ENET_PEER_PACKET_LOSS_SCALE:1:8,'+-',
currentPeer^.packetLossVariance/ENET_PEER_PACKET_LOSS_SCALE:1:8,
' packet loss ',currentPeer^.roundTripTime,'+-',currentPeer^.roundTripTimeVariance,
' ms round trip time, ',
currentPeer^.packetThrottle/ENET_PEER_PACKET_THROTTLE_SCALE:1:8,
' throttle, ',
enet_list_size(@currentPeer^.outgoingReliableCommands),'/',
enet_list_size(@currentPeer^.outgoingUnreliableCommands),' outgoing, ',
enet_list_size(@currentPeer^.channels^[0].incomingReliableCommands),'/',
enet_list_size(@currentPeer^.channels^[0].incomingUnreliableCommands),' incoming');
end else begin
writeln('peer ',currentPeer^.incomingPeerID,': ',
currentPeer^.packetLoss/ENET_PEER_PACKET_LOSS_SCALE:1:8,'+-',
currentPeer^.packetLossVariance/ENET_PEER_PACKET_LOSS_SCALE:1:8,
' packet loss ',currentPeer^.roundTripTime,'+-',currentPeer^.roundTripTimeVariance,
' ms round trip time, ',
currentPeer^.packetThrottle/ENET_PEER_PACKET_THROTTLE_SCALE:1:8,
' throttle, ',
enet_list_size(@currentPeer^.outgoingReliableCommands),'/',
enet_list_size(@currentPeer^.outgoingUnreliableCommands),' outgoing, ',
0,'/',
0,' incoming');
end;
{$endif}
dec(currentPeer^.packetLossVariance,currentPeer^.packetLossVariance div 4);
if packetLoss>=currentPeer^.packetLoss then begin
inc(currentPeer^.packetLoss,(packetLoss-currentPeer^.packetLoss) div 8);
inc(currentPeer^.packetLossVariance,(packetLoss-currentPeer^.packetLoss) div 4);
end else begin
dec(currentPeer^.packetLoss,(currentPeer^.packetLoss-packetLoss) div 8);
dec(currentPeer^.packetLossVariance,(currentPeer^.packetLoss-packetLoss) div 4);
end;
currentPeer^.packetLossEpoch:=host^.serviceTime;
currentPeer^.packetsSent:=0;
currentPeer^.packetsLost:=0;
end;
host^.buffers[0].data:=@headerData;
if (host^.headerFlags and ENET_PROTOCOL_HEADER_FLAG_SENT_TIME)<>0 then begin
header^.sentTime:=ENET_HOST_TO_NET_16(host^.serviceTime and $FFFF);
host^.buffers[0].dataLength:=sizeof(TENetProtocolHeader);
end else begin
host^.buffers[0].dataLength:=PENetProtocolHeader(nil)^.sentTime;
end;
shouldCompress:=0;
if assigned(host^.compressor.context) and assigned(host^.compressor.compress) then begin
originalSize:=host^.packetSize-sizeof(TENetProtocolHeader);
compressedSize:=host^.compressor.compress(host^.compressor.context,@host^.buffers[1],host^.bufferCount-1,originalSize,@host^.packetData[1,0],originalSize);
if (compressedSize>0) and (compressedSize<originalSize) then begin
host^.headerFlags:=host^.headerFlags or ENET_PROTOCOL_HEADER_FLAG_COMPRESSED;
shouldCompress:=compressedSize;
{$ifdef ENET_DEBUG_COMPRESS}
writeln('peer ', currentPeer^.incomingPeerID,': compressed ', originalSize,'^.', compressedSize,' (',(compressedSize*100) div originalSize,')');
{$endif}
end;
end;
if currentPeer^.outgoingPeerID<ENET_PROTOCOL_MAXIMUM_PEER_ID then begin
host^.headerFlags:=host^.headerFlags or (currentPeer^.outgoingSessionID shl ENET_PROTOCOL_HEADER_SESSION_SHIFT);
end;
header^.peerID:=ENET_HOST_TO_NET_16(currentPeer^.outgoingPeerID or host^.headerFlags);
if assigned(host^.checksum) then begin
checksum:=pointer(@headerData[host^.buffers[0].dataLength]);
if currentPeer^.outgoingPeerID<ENET_PROTOCOL_MAXIMUM_PEER_ID then begin
checksum^:=currentPeer^.connectID;
end else begin
checksum^:=0;
end;
inc(host^.buffers[0].dataLength,sizeof(longword));
checksum^:=host^.checksum(@host^.buffers[0],host^.bufferCount);
end;
if shouldCompress>0 then begin
host^.buffers[1].data:=pointer(@host^.packetData[1,0]);
host^.buffers[1].dataLength:=shouldCompress;
host^.bufferCount:=2;
end;
currentPeer^.lastSendTime:=host^.serviceTime;
family:=enet_get_address_family(@currentPeer^.address);
if family=ENET_IPV4 then begin
socket:=host^.socket4;
end else begin
socket:=host^.socket6;
end;
if socket=ENET_SOCKET_NULL then begin
result:=-1;
exit;
end;
sentLength:=enet_socket_send(socket,@currentPeer^.address,@host^.buffers[0],host^.bufferCount,family);
enet_protocol_remove_sent_unreliable_commands(currentPeer);
if sentLength<0 then begin
result:=-1;
exit;
end;
inc(host^.totalSentData,sentLength);
inc(host^.totalSentPackets);
inc(currentPeer);
end;
end;
result:=0;
end;
procedure enet_host_flush(host:PENetHost);
begin
host^.serviceTime:=enet_time_get;
enet_protocol_send_outgoing_commands(host,nil,0);
end;
function enet_host_check_events(host:PENetHost;event:PENetEvent):longint;
begin
if not assigned(event) then begin
result:=-1;
exit;
end;
event^.type_:=ENET_EVENT_TYPE_NONE;
event^.peer:=nil;
event^.packet:=nil;
result:=enet_protocol_dispatch_incoming_commands(host,event);
end;
function enet_host_service(host:PENetHost;event:PENetEvent;timeout:longword):longint;
var waitCondition:longword;
begin
if assigned(event) then begin
event^.type_:=ENET_EVENT_TYPE_NONE;
event^.peer:=nil;
event^.packet:=nil;
case enet_protocol_dispatch_incoming_commands(host,event) of
1:begin
result:=1;
exit;
end;
-1:begin
{$ifdef ENET_DEBUG}
perror('Error dispatching incoming packets');
{$endif}
result:=-1;
exit;
end;
end;
end;
host^.serviceTime:=enet_time_get;
inc(timeout,host^.serviceTime);
repeat
if ENET_TIME_DIFFERENCE(host^.serviceTime,host^.bandwidthThrottleEpoch)>=ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL then begin
enet_host_bandwidth_throttle(host);
end;
case enet_protocol_send_outgoing_commands(host,event,1) of
1:begin
result:=1;
exit;
end;
-1:begin
{$ifdef ENET_DEBUG}
perror('Error sending outgoing packets');
{$endif}
result:=-1;
exit;
end;
end;
if host^.socket4<>ENET_SOCKET_NULL then begin
case enet_protocol_receive_incoming_commands(host,event,ENET_IPV4) of
1:begin
result:=1;
exit;
end;
-1:begin
{$ifdef ENET_DEBUG}
perror('Error receiving incoming packets');
{$endif}
result:=-1;
exit;
end;
end;
end;
if host^.socket6<>ENET_SOCKET_NULL then begin
case enet_protocol_receive_incoming_commands(host,event,ENET_IPV6) of
1:begin
result:=1;
exit;
end;
-1:begin
{$ifdef ENET_DEBUG}
perror('Error receiving incoming packets');
{$endif}
result:=-1;
exit;
end;
end;
end;
case enet_protocol_send_outgoing_commands(host,event,1) of
1:begin
result:=1;
exit;
end;
-1:begin
{$ifdef ENET_DEBUG}
perror('Error sending outgoing packets');
{$endif}
result:=-1;
exit;
end;
end;
if assigned(event) then begin
case enet_protocol_dispatch_incoming_commands(host,event) of
1:begin
result:=1;
exit;
end;
-1:begin
{$ifdef ENET_DEBUG}
perror('Error dispatching incoming packets');
{$endif}
result:=-1;
exit;
end;
end;
end;
if ENET_TIME_GREATER_EQUAL(host^.serviceTime,timeout) then begin
result:=0;
exit;
end;
repeat
host^.serviceTime:=enet_time_get;
if ENET_TIME_GREATER_EQUAL(host^.serviceTime,timeout) then begin
result:=0;
exit;
end;
waitCondition:=ENET_SOCKET_WAIT_RECEIVE or ENET_SOCKET_WAIT_INTERRUPT;
if enet_socket_wait(host^.socket4,host^.socket6,@waitCondition,ENET_TIME_DIFFERENCE(timeout,host^.serviceTime))<>0 then begin
result:=-1;
exit;
end;
until (waitCondition and ENET_SOCKET_WAIT_INTERRUPT)=0;
host^.serviceTime:=enet_time_get;
until (waitCondition and ENET_SOCKET_WAIT_RECEIVE)=0;
result:=0;
end;
end.
//-------------------------------------------------------------
//
// Borland Delphi Runtime Library
// <API> interface unit
//
// Portions created by Microsoft are
// Copyright (C) 1995-1999 Microsoft Corporation.
// All Rights Reserved.
//
// The original file is: Winsock2.h from CBuilder5 distribution.
// The original Pascal code is: winsock2.pas, released 04 Mar 2000.
// The initial developer of the Pascal code is Alex Konshin
// (alexk@mtgroup.ru).
//
// Portions created by Alex Konshin are
// Copyright (C) 1998-2000 Alex Konshin
//
// Contributor(s): Alex Konshin
//
// Obtained through:
//
// Joint Endeavour of Delphi Innovators (Project JEDI)
//
// You may retrieve the latest version of this file at the Project
// JEDI home page, located at http://delphi-jedi.org
//
// The contents of this file are used with permission, subject to
// the Mozilla Public License Version 1.1 (the "License"); you may
// not use this file except in compliance with the License. You may
// obtain a copy of the License at
// http://www.mozilla.org/MPL/MPL-1.1.html
//
// Software distributed under the License is distributed on an
// "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
// implied. See the License for the specific language governing
// rights and limitations under the License.
//
//-------------------------------------------------------------
{ Winsock2.h -- definitions to be used with the WinSock 2 DLL and WinSock 2 applications.
This header file corresponds to version 2.2.x of the WinSock API specification.
This file includes parts which are Copyright (c) 1982-1986 Regents
of the University of California. All rights reserved.
The Berkeley Software License Agreement specifies the terms and
conditions for redistribution. }
// converted by Alex Konshin, mailto:alexk@mtgroup.ru
// modified March,4 2000
unit GDFWENetWinSock2;
{$ifdef fpc}
{$mode delphi}
{$endif}
interface
uses SysUtils, Windows;
{$ALIGN OFF}
{$RANGECHECKS OFF}
{$WRITEABLECONST OFF}
// Define the current Winsock version. To build an earlier Winsock version
// application redefine this value prior to including Winsock2.h
const
WINSOCK_VERSION = $0202;
WINSOCK2_DLL = 'ws2_32.dll';
type
u_char = Byte;
u_short = Word;
u_int = DWORD;
u_long = DWORD;
// The new type to be used in all instances which refer to sockets.
TSocket = u_int;
WSAEVENT = THandle;
PWSAEVENT = ^WSAEVENT;
LPWSAEVENT = PWSAEVENT;
{$IFDEF UNICODE}
PMBChar = PWideChar;
{$ELSE}
PMBChar = PChar;
{$ENDIF}
const
FD_SETSIZE = 64;
type
PFDSet = ^TFDSet;
TFDSet = packed record
fd_count: u_int;
fd_array: array[0..FD_SETSIZE-1] of TSocket;
end;
PTimeVal = ^TTimeVal;
TTimeVal = packed record
tv_sec: Longint;
tv_usec: Longint;
end;
const
IOCPARM_MASK = $7f;
IOC_VOID = $20000000;
IOC_OUT = $40000000;
IOC_IN = $80000000;
IOC_INOUT = (IOC_IN or IOC_OUT);
// get # bytes to read
FIONREAD = IOC_OUT or (SizeOf(Longint) shl 16) or (Ord('f') shl 8) or 127;
// set/clear non-blocking i/o
FIONBIO = IOC_IN or (SizeOf(Longint) shl 16) or (Ord('f') shl 8) or 126;
// set/clear async i/o
FIOASYNC = IOC_IN or (SizeOf(Longint) shl 16) or (Ord('f') shl 8) or 125;
// Socket I/O Controls
// set high watermark
SIOCSHIWAT = IOC_IN or (SizeOf(Longint) shl 16) or (Ord('s') shl 8);
// get high watermark
SIOCGHIWAT = IOC_OUT or (SizeOf(Longint) shl 16) or (Ord('s') shl 8) or 1;
// set low watermark
SIOCSLOWAT = IOC_IN or (SizeOf(Longint) shl 16) or (Ord('s') shl 8) or 2;
// get low watermark
SIOCGLOWAT = IOC_OUT or (SizeOf(Longint) shl 16) or (Ord('s') shl 8) or 3;
// at oob mark?
SIOCATMARK = IOC_OUT or (SizeOf(Longint) shl 16) or (Ord('s') shl 8) or 7;
// Structures returned by network data base library, taken from the
// BSD file netdb.h. All addresses are supplied in host order, and
// returned in network order (suitable for use in system calls).
type
PHostEnt = ^THostEnt;
THostEnt = packed record
h_name: PChar; // official name of host
h_aliases: ^PChar; // alias list
h_addrtype: Smallint; // host address type
h_length: Smallint; // length of address
case Byte of
0: (h_addr_list: ^PChar); // list of addresses
1: (h_addr: ^PChar); // address, for backward compat
end;
// It is assumed here that a network number
// fits in 32 bits.
PNetEnt = ^TNetEnt;
TNetEnt = packed record
n_name: PChar; // official name of net
n_aliases: ^PChar; // alias list
n_addrtype: Smallint; // net address type
n_net: u_long; // network #
end;
PServEnt = ^TServEnt;
TServEnt = packed record
s_name: PChar; // official service name
s_aliases: ^PChar; // alias list
s_port: Smallint; // protocol to use
s_proto: PChar; // port #
end;
PProtoEnt = ^TProtoEnt;
TProtoEnt = packed record
p_name: PChar; // official protocol name
p_aliases: ^Pchar; // alias list
p_proto: Smallint; // protocol #
end;
// Constants and structures defined by the internet system,
// Per RFC 790, September 1981, taken from the BSD file netinet/in.h.
const
// Protocols
IPPROTO_IP = 0; // dummy for IP
IPPROTO_ICMP = 1; // control message protocol
IPPROTO_IGMP = 2; // group management protocol
IPPROTO_GGP = 3; // gateway^2 (deprecated)
IPPROTO_TCP = 6; // TCP
IPPROTO_PUP = 12; // pup
IPPROTO_UDP = 17; // UDP - user datagram protocol
IPPROTO_IDP = 22; // xns idp
IPPROTO_ND = 77; // UNOFFICIAL net disk proto
IPPROTO_RAW = 255; // raw IP packet
IPPROTO_MAX = 256;
// Port/socket numbers: network standard functions
IPPORT_ECHO = 7;
IPPORT_DISCARD = 9;
IPPORT_SYSTAT = 11;
IPPORT_DAYTIME = 13;
IPPORT_NETSTAT = 15;
IPPORT_FTP = 21;
IPPORT_TELNET = 23;
IPPORT_SMTP = 25;
IPPORT_TIMESERVER = 37;
IPPORT_NAMESERVER = 42;
IPPORT_WHOIS = 43;
IPPORT_MTP = 57;
// Port/socket numbers: host specific functions
IPPORT_TFTP = 69;
IPPORT_RJE = 77;
IPPORT_FINGER = 79;
IPPORT_TTYLINK = 87;
IPPORT_SUPDUP = 95;
// UNIX TCP sockets
IPPORT_EXECSERVER = 512;
IPPORT_LOGINSERVER = 513;
IPPORT_CMDSERVER = 514;
IPPORT_EFSSERVER = 520;
// UNIX UDP sockets
IPPORT_BIFFUDP = 512;
IPPORT_WHOSERVER = 513;
IPPORT_ROUTESERVER = 520;
// Ports < IPPORT_RESERVED are reserved for privileged processes (e.g. root).
IPPORT_RESERVED =1024;
// Link numbers
IMPLINK_IP = 155;
IMPLINK_LOWEXPER = 156;
IMPLINK_HIGHEXPER = 158;
TF_DISCONNECT = $01;
TF_REUSE_SOCKET = $02;
TF_WRITE_BEHIND = $04;
// This is used instead of -1, since the TSocket type is unsigned.
INVALID_SOCKET = TSocket(not(0));
SOCKET_ERROR = -1;
// The following may be used in place of the address family, socket type, or
// protocol in a call to WSASocket to indicate that the corresponding value
// should be taken from the supplied WSAPROTOCOL_INFO structure instead of the
// parameter itself.
FROM_PROTOCOL_INFO = -1;
// Types
SOCK_STREAM = 1; { stream socket }
SOCK_DGRAM = 2; { datagram socket }
SOCK_RAW = 3; { raw-protocol interface }
SOCK_RDM = 4; { reliably-delivered message }
SOCK_SEQPACKET = 5; { sequenced packet stream }
// Option flags per-socket.
SO_DEBUG = $0001; // turn on debugging info recording
SO_ACCEPTCONN = $0002; // socket has had listen()
SO_REUSEADDR = $0004; // allow local address reuse
SO_KEEPALIVE = $0008; // keep connections alive
SO_DONTROUTE = $0010; // just use interface addresses
SO_BROADCAST = $0020; // permit sending of broadcast msgs
SO_USELOOPBACK = $0040; // bypass hardware when possible
SO_LINGER = $0080; // linger on close if data present
SO_OOBINLINE = $0100; // leave received OOB data in line
SO_DONTLINGER = not SO_LINGER;
SO_EXCLUSIVEADDRUSE = not SO_REUSEADDR; // disallow local address reuse
// Additional options.
SO_SNDBUF = $1001; // send buffer size
SO_RCVBUF = $1002; // receive buffer size
SO_SNDLOWAT = $1003; // send low-water mark
SO_RCVLOWAT = $1004; // receive low-water mark
SO_SNDTIMEO = $1005; // send timeout
SO_RCVTIMEO = $1006; // receive timeout
SO_ERROR = $1007; // get error status and clear
SO_TYPE = $1008; // get socket type
// Options for connect and disconnect data and options.
// Used only by non-TCP/IP transports such as DECNet, OSI TP4, etc.
SO_CONNDATA = $7000;
SO_CONNOPT = $7001;
SO_DISCDATA = $7002;
SO_DISCOPT = $7003;
SO_CONNDATALEN = $7004;
SO_CONNOPTLEN = $7005;
SO_DISCDATALEN = $7006;
SO_DISCOPTLEN = $7007;
// Option for opening sockets for synchronous access.
SO_OPENTYPE = $7008;
SO_SYNCHRONOUS_ALERT = $10;
SO_SYNCHRONOUS_NONALERT = $20;
// Other NT-specific options.
SO_MAXDG = $7009;
SO_MAXPATHDG = $700A;
SO_UPDATE_ACCEPT_CONTEXT = $700B;
SO_CONNECT_TIME = $700C;
// TCP options.
TCP_NODELAY = $0001;
TCP_BSDURGENT = $7000;
// WinSock 2 extension -- new options
SO_GROUP_ID = $2001; // ID of a socket group
SO_GROUP_PRIORITY = $2002; // the relative priority within a group
SO_MAX_MSG_SIZE = $2003; // maximum message size
SO_Protocol_InfoA = $2004; // WSAPROTOCOL_INFOA structure
SO_Protocol_InfoW = $2005; // WSAPROTOCOL_INFOW structure
{$IFDEF UNICODE}
SO_Protocol_Info = SO_Protocol_InfoW;
{$ELSE}
SO_Protocol_Info = SO_Protocol_InfoA;
{$ENDIF}
PVD_CONFIG = $3001; // configuration info for service provider
SO_CONDITIONAL_ACCEPT = $3002; // enable true conditional accept:
// connection is not ack-ed to the
// other side until conditional
// function returns CF_ACCEPT
// Address families.
AF_UNSPEC = 0; // unspecified
AF_UNIX = 1; // local to host (pipes, portals)
AF_INET = 2; // internetwork: UDP, TCP, etc.
AF_IMPLINK = 3; // arpanet imp addresses
AF_PUP = 4; // pup protocols: e.g. BSP
AF_CHAOS = 5; // mit CHAOS protocols
AF_IPX = 6; // IPX and SPX
AF_NS = AF_IPX; // XEROX NS protocols
AF_ISO = 7; // ISO protocols
AF_OSI = AF_ISO; // OSI is ISO
AF_ECMA = 8; // european computer manufacturers
AF_DATAKIT = 9; // datakit protocols
AF_CCITT = 10; // CCITT protocols, X.25 etc
AF_SNA = 11; // IBM SNA
AF_DECnet = 12; // DECnet
AF_DLI = 13; // Direct data link interface
AF_LAT = 14; // LAT
AF_HYLINK = 15; // NSC Hyperchannel
AF_APPLETALK = 16; // AppleTalk
AF_NETBIOS = 17; // NetBios-style addresses
AF_VOICEVIEW = 18; // VoiceView
AF_FIREFOX = 19; // FireFox
AF_UNKNOWN1 = 20; // Somebody is using this!
AF_BAN = 21; // Banyan
AF_ATM = 22; // Native ATM Services
AF_INET6 = 23; // Internetwork Version 6
AF_CLUSTER = 24; // Microsoft Wolfpack
AF_12844 = 25; // IEEE 1284.4 WG AF
AF_IRDA = 26; // IrDA
AF_NETDES = 28; // Network Designers OSI & gateway enabled protocols
AF_MAX = 29;
// Protocol families, same as address families for now.
PF_UNSPEC = AF_UNSPEC;
PF_UNIX = AF_UNIX;
PF_INET = AF_INET;
PF_IMPLINK = AF_IMPLINK;
PF_PUP = AF_PUP;
PF_CHAOS = AF_CHAOS;
PF_NS = AF_NS;
PF_IPX = AF_IPX;
PF_ISO = AF_ISO;
PF_OSI = AF_OSI;
PF_ECMA = AF_ECMA;
PF_DATAKIT = AF_DATAKIT;
PF_CCITT = AF_CCITT;
PF_SNA = AF_SNA;
PF_DECnet = AF_DECnet;
PF_DLI = AF_DLI;
PF_LAT = AF_LAT;
PF_HYLINK = AF_HYLINK;
PF_APPLETALK = AF_APPLETALK;
PF_VOICEVIEW = AF_VOICEVIEW;
PF_FIREFOX = AF_FIREFOX;
PF_UNKNOWN1 = AF_UNKNOWN1;
PF_BAN = AF_BAN;
PF_ATM = AF_ATM;
PF_INET6 = AF_INET6;
PF_MAX = AF_MAX;
type
SunB = packed record
s_b1, s_b2, s_b3, s_b4: u_char;
end;
SunW = packed record
s_w1, s_w2: u_short;
end;
TInAddr = packed record
case integer of
0: (S_un_b: SunB);
1: (S_un_w: SunW);
2: (S_addr: u_long);
end;
PInAddr = ^TInAddr;
in_addr = TInAddr ;
// Structure used by kernel to store most addresses.
TSockAddrIn = packed record
case Integer of
0: (sin_family : u_short;
sin_port : u_short;
sin_addr : TInAddr;
sin_zero : array[0..7] of Char);
1: (sa_family : u_short;
sa_data : array[0..13] of Char)
end;
PSockAddrIn = ^TSockAddrIn;
TSockAddr = TSockAddrIn;
PSockAddr = ^TSockAddr;
SOCKADDR = TSockAddr;
SOCKADDR_IN = TSockAddrIn;
// Structure used by kernel to pass protocol information in raw sockets.
PSockProto = ^TSockProto;
TSockProto = packed record
sp_family : u_short;
sp_protocol : u_short;
end;
// Structure used for manipulating linger option.
PLinger = ^TLinger;
TLinger = packed record
l_onoff: u_short;
l_linger: u_short;
end;
const
INADDR_ANY = $00000000;
INADDR_LOOPBACK = $7F000001;
INADDR_BROADCAST = $FFFFFFFF;
INADDR_NONE = $FFFFFFFF;
ADDR_ANY = INADDR_ANY;
SOL_SOCKET = $ffff; // options for socket level
MSG_OOB = $1; // process out-of-band data
MSG_PEEK = $2; // peek at incoming message
MSG_DONTROUTE = $4; // send without using routing tables
MSG_PARTIAL = $8000; // partial send or recv for message xport
// WinSock 2 extension -- new flags for WSASend(), WSASendTo(), WSARecv() and WSARecvFrom()
MSG_INTERRUPT = $10; // send/recv in the interrupt context
MSG_MAXIOVLEN = 16;
// Define constant based on rfc883, used by gethostbyxxxx() calls.
MAXGETHOSTSTRUCT = 1024;
// Maximum queue length specifiable by listen.
SOMAXCONN = $7fffffff;
// WinSock 2 extension -- bit values and indices for FD_XXX network events
FD_READ_BIT = 0;
FD_WRITE_BIT = 1;
FD_OOB_BIT = 2;
FD_ACCEPT_BIT = 3;
FD_CONNECT_BIT = 4;
FD_CLOSE_BIT = 5;
FD_QOS_BIT = 6;
FD_GROUP_QOS_BIT = 7;
FD_MAX_EVENTS = 8;
FD_READ = (1 shl FD_READ_BIT);
FD_WRITE = (1 shl FD_WRITE_BIT);
FD_OOB = (1 shl FD_OOB_BIT);
FD_ACCEPT = (1 shl FD_ACCEPT_BIT);
FD_CONNECT = (1 shl FD_CONNECT_BIT);
FD_CLOSE = (1 shl FD_CLOSE_BIT);
FD_QOS = (1 shl FD_QOS_BIT);
FD_GROUP_QOS = (1 shl FD_GROUP_QOS_BIT);
FD_ALL_EVENTS = (1 shl FD_MAX_EVENTS) - 1;
// All Windows Sockets error constants are biased by WSABASEERR from the "normal"
WSABASEERR = 10000;
// Windows Sockets definitions of regular Microsoft C error constants
WSAEINTR = WSABASEERR+ 4;
WSAEBADF = WSABASEERR+ 9;
WSAEACCES = WSABASEERR+ 13;
WSAEFAULT = WSABASEERR+ 14;
WSAEINVAL = WSABASEERR+ 22;
WSAEMFILE = WSABASEERR+ 24;
// Windows Sockets definitions of regular Berkeley error constants
WSAEWOULDBLOCK = WSABASEERR+ 35;
WSAEINPROGRESS = WSABASEERR+ 36;
WSAEALREADY = WSABASEERR+ 37;
WSAENOTSOCK = WSABASEERR+ 38;
WSAEDESTADDRREQ = WSABASEERR+ 39;
WSAEMSGSIZE = WSABASEERR+ 40;
WSAEPROTOTYPE = WSABASEERR+ 41;
WSAENOPROTOOPT = WSABASEERR+ 42;
WSAEPROTONOSUPPORT = WSABASEERR+ 43;
WSAESOCKTNOSUPPORT = WSABASEERR+ 44;
WSAEOPNOTSUPP = WSABASEERR+ 45;
WSAEPFNOSUPPORT = WSABASEERR+ 46;
WSAEAFNOSUPPORT = WSABASEERR+ 47;
WSAEADDRINUSE = WSABASEERR+ 48;
WSAEADDRNOTAVAIL = WSABASEERR+ 49;
WSAENETDOWN = WSABASEERR+ 50;
WSAENETUNREACH = WSABASEERR+ 51;
WSAENETRESET = WSABASEERR+ 52;
WSAECONNABORTED = WSABASEERR+ 53;
WSAECONNRESET = WSABASEERR+ 54;
WSAENOBUFS = WSABASEERR+ 55;
WSAEISCONN = WSABASEERR+ 56;
WSAENOTCONN = WSABASEERR+ 57;
WSAESHUTDOWN = WSABASEERR+ 58;
WSAETOOMANYREFS = WSABASEERR+ 59;
WSAETIMEDOUT = WSABASEERR+ 60;
WSAECONNREFUSED = WSABASEERR+ 61;
WSAELOOP = WSABASEERR+ 62;
WSAENAMETOOLONG = WSABASEERR+ 63;
WSAEHOSTDOWN = WSABASEERR+ 64;
WSAEHOSTUNREACH = WSABASEERR+ 65;
WSAENOTEMPTY = WSABASEERR+ 66;
WSAEPROCLIM = WSABASEERR+ 67;
WSAEUSERS = WSABASEERR+ 68;
WSAEDQUOT = WSABASEERR+ 69;
WSAESTALE = WSABASEERR+ 70;
WSAEREMOTE = WSABASEERR+ 71;
// Extended Windows Sockets error constant definitions
WSASYSNOTREADY = WSABASEERR+ 91;
WSAVERNOTSUPPORTED = WSABASEERR+ 92;
WSANOTINITIALISED = WSABASEERR+ 93;
WSAEDISCON = WSABASEERR+101;
WSAENOMORE = WSABASEERR+102;
WSAECANCELLED = WSABASEERR+103;
WSAEINVALIDPROCTABLE = WSABASEERR+104;
WSAEINVALIDPROVIDER = WSABASEERR+105;
WSAEPROVIDERFAILEDINIT = WSABASEERR+106;
WSASYSCALLFAILURE = WSABASEERR+107;
WSASERVICE_NOT_FOUND = WSABASEERR+108;
WSATYPE_NOT_FOUND = WSABASEERR+109;
WSA_E_NO_MORE = WSABASEERR+110;
WSA_E_CANCELLED = WSABASEERR+111;
WSAEREFUSED = WSABASEERR+112;
{ Error return codes from gethostbyname() and gethostbyaddr()
(when using the resolver). Note that these errors are
retrieved via WSAGetLastError() and must therefore follow
the rules for avoiding clashes with error numbers from
specific implementations or language run-time systems.
For this reason the codes are based at WSABASEERR+1001.
Note also that [WSA]NO_ADDRESS is defined only for
compatibility purposes. }
// Authoritative Answer: Host not found
WSAHOST_NOT_FOUND = WSABASEERR+1001;
HOST_NOT_FOUND = WSAHOST_NOT_FOUND;
// Non-Authoritative: Host not found, or SERVERFAIL
WSATRY_AGAIN = WSABASEERR+1002;
TRY_AGAIN = WSATRY_AGAIN;
// Non recoverable errors, FORMERR, REFUSED, NOTIMP
WSANO_RECOVERY = WSABASEERR+1003;
NO_RECOVERY = WSANO_RECOVERY;
// Valid name, no data record of requested type
WSANO_DATA = WSABASEERR+1004;
NO_DATA = WSANO_DATA;
// no address, look for MX record
WSANO_ADDRESS = WSANO_DATA;
NO_ADDRESS = WSANO_ADDRESS;
// Define QOS related error return codes
WSA_QOS_RECEIVERS = WSABASEERR+1005; // at least one Reserve has arrived
WSA_QOS_SENDERS = WSABASEERR+1006; // at least one Path has arrived
WSA_QOS_NO_SENDERS = WSABASEERR+1007; // there are no senders
WSA_QOS_NO_RECEIVERS = WSABASEERR+1008; // there are no receivers
WSA_QOS_REQUEST_CONFIRMED = WSABASEERR+1009; // Reserve has been confirmed
WSA_QOS_ADMISSION_FAILURE = WSABASEERR+1010; // error due to lack of resources
WSA_QOS_POLICY_FAILURE = WSABASEERR+1011; // rejected for administrative reasons - bad credentials
WSA_QOS_BAD_STYLE = WSABASEERR+1012; // unknown or conflicting style
WSA_QOS_BAD_OBJECT = WSABASEERR+1013; // problem with some part of the filterspec or providerspecific buffer in general
WSA_QOS_TRAFFIC_CTRL_ERROR = WSABASEERR+1014; // problem with some part of the flowspec
WSA_QOS_GENERIC_ERROR = WSABASEERR+1015; // general error
WSA_QOS_ESERVICETYPE = WSABASEERR+1016; // invalid service type in flowspec
WSA_QOS_EFLOWSPEC = WSABASEERR+1017; // invalid flowspec
WSA_QOS_EPROVSPECBUF = WSABASEERR+1018; // invalid provider specific buffer
WSA_QOS_EFILTERSTYLE = WSABASEERR+1019; // invalid filter style
WSA_QOS_EFILTERTYPE = WSABASEERR+1020; // invalid filter type
WSA_QOS_EFILTERCOUNT = WSABASEERR+1021; // incorrect number of filters
WSA_QOS_EOBJLENGTH = WSABASEERR+1022; // invalid object length
WSA_QOS_EFLOWCOUNT = WSABASEERR+1023; // incorrect number of flows
WSA_QOS_EUNKOWNPSOBJ = WSABASEERR+1024; // unknown object in provider specific buffer
WSA_QOS_EPOLICYOBJ = WSABASEERR+1025; // invalid policy object in provider specific buffer
WSA_QOS_EFLOWDESC = WSABASEERR+1026; // invalid flow descriptor in the list
WSA_QOS_EPSFLOWSPEC = WSABASEERR+1027; // inconsistent flow spec in provider specific buffer
WSA_QOS_EPSFILTERSPEC = WSABASEERR+1028; // invalid filter spec in provider specific buffer
WSA_QOS_ESDMODEOBJ = WSABASEERR+1029; // invalid shape discard mode object in provider specific buffer
WSA_QOS_ESHAPERATEOBJ = WSABASEERR+1030; // invalid shaping rate object in provider specific buffer
WSA_QOS_RESERVED_PETYPE = WSABASEERR+1031; // reserved policy element in provider specific buffer
{ WinSock 2 extension -- new error codes and type definition }
WSA_IO_PENDING = ERROR_IO_PENDING;
WSA_IO_INCOMPLETE = ERROR_IO_INCOMPLETE;
WSA_INVALID_HANDLE = ERROR_INVALID_HANDLE;
WSA_INVALID_PARAMETER = ERROR_INVALID_PARAMETER;
WSA_NOT_ENOUGH_MEMORY = ERROR_NOT_ENOUGH_MEMORY;
WSA_OPERATION_ABORTED = ERROR_OPERATION_ABORTED;
WSA_INVALID_EVENT = WSAEVENT(nil);
WSA_MAXIMUM_WAIT_EVENTS = MAXIMUM_WAIT_OBJECTS;
WSA_WAIT_FAILED = $ffffffff;
WSA_WAIT_EVENT_0 = WAIT_OBJECT_0;
WSA_WAIT_IO_COMPLETION = WAIT_IO_COMPLETION;
WSA_WAIT_TIMEOUT = WAIT_TIMEOUT;
WSA_INFINITE = INFINITE;
{ Windows Sockets errors redefined as regular Berkeley error constants.
These are commented out in Windows NT to avoid conflicts with errno.h.
Use the WSA constants instead. }
EWOULDBLOCK = WSAEWOULDBLOCK;
EINPROGRESS = WSAEINPROGRESS;
EALREADY = WSAEALREADY;
ENOTSOCK = WSAENOTSOCK;
EDESTADDRREQ = WSAEDESTADDRREQ;
EMSGSIZE = WSAEMSGSIZE;
EPROTOTYPE = WSAEPROTOTYPE;
ENOPROTOOPT = WSAENOPROTOOPT;
EPROTONOSUPPORT = WSAEPROTONOSUPPORT;
ESOCKTNOSUPPORT = WSAESOCKTNOSUPPORT;
EOPNOTSUPP = WSAEOPNOTSUPP;
EPFNOSUPPORT = WSAEPFNOSUPPORT;
EAFNOSUPPORT = WSAEAFNOSUPPORT;
EADDRINUSE = WSAEADDRINUSE;
EADDRNOTAVAIL = WSAEADDRNOTAVAIL;
ENETDOWN = WSAENETDOWN;
ENETUNREACH = WSAENETUNREACH;
ENETRESET = WSAENETRESET;
ECONNABORTED = WSAECONNABORTED;
ECONNRESET = WSAECONNRESET;
ENOBUFS = WSAENOBUFS;
EISCONN = WSAEISCONN;
ENOTCONN = WSAENOTCONN;
ESHUTDOWN = WSAESHUTDOWN;
ETOOMANYREFS = WSAETOOMANYREFS;
ETIMEDOUT = WSAETIMEDOUT;
ECONNREFUSED = WSAECONNREFUSED;
ELOOP = WSAELOOP;
ENAMETOOLONG = WSAENAMETOOLONG;
EHOSTDOWN = WSAEHOSTDOWN;
EHOSTUNREACH = WSAEHOSTUNREACH;
ENOTEMPTY = WSAENOTEMPTY;
EPROCLIM = WSAEPROCLIM;
EUSERS = WSAEUSERS;
EDQUOT = WSAEDQUOT;
ESTALE = WSAESTALE;
EREMOTE = WSAEREMOTE;
WSADESCRIPTION_LEN = 256;
WSASYS_STATUS_LEN = 128;
type
PWSAData = ^TWSAData;
TWSAData = packed record
wVersion : Word;
wHighVersion : Word;
szDescription : Array[0..WSADESCRIPTION_LEN] of Char;
szSystemStatus : Array[0..WSASYS_STATUS_LEN] of Char;
iMaxSockets : Word;
iMaxUdpDg : Word;
lpVendorInfo : PChar;
end;
{ WSAOVERLAPPED = Record
Internal: LongInt;
InternalHigh: LongInt;
Offset: LongInt;
OffsetHigh: LongInt;
hEvent: WSAEVENT;
end;}
WSAOVERLAPPED = TOverlapped;
TWSAOverlapped = WSAOverlapped;
PWSAOverlapped = ^WSAOverlapped;
LPWSAOVERLAPPED = PWSAOverlapped;
{ WinSock 2 extension -- WSABUF and QOS struct, include qos.h }
{ to pull in FLOWSPEC and related definitions }
WSABUF = packed record
len: U_LONG; { the length of the buffer }
buf: PChar; { the pointer to the buffer }
end {WSABUF};
PWSABUF = ^WSABUF;
LPWSABUF = PWSABUF;
TServiceType = LongInt;
TFlowSpec = packed record
TokenRate, // In Bytes/sec
TokenBucketSize, // In Bytes
PeakBandwidth, // In Bytes/sec
Latency, // In microseconds
DelayVariation : LongInt;// In microseconds
ServiceType : TServiceType;
MaxSduSize, MinimumPolicedSize : LongInt;// In Bytes
end;
PFlowSpec = ^TFLOWSPEC;
QOS = packed record
SendingFlowspec: TFlowSpec; { the flow spec for data sending }
ReceivingFlowspec: TFlowSpec; { the flow spec for data receiving }
ProviderSpecific: WSABUF; { additional provider specific stuff }
end;
TQualityOfService = QOS;
PQOS = ^QOS;
LPQOS = PQOS;
const
SERVICETYPE_NOTRAFFIC = $00000000; // No data in this direction
SERVICETYPE_BESTEFFORT = $00000001; // Best Effort
SERVICETYPE_CONTROLLEDLOAD = $00000002; // Controlled Load
SERVICETYPE_GUARANTEED = $00000003; // Guaranteed
SERVICETYPE_NETWORK_UNAVAILABLE = $00000004; // Used to notify change to user
SERVICETYPE_GENERAL_INFORMATION = $00000005; // corresponds to "General Parameters" defined by IntServ
SERVICETYPE_NOCHANGE = $00000006; // used to indicate that the flow spec contains no change from any previous one
// to turn on immediate traffic control, OR this flag with the ServiceType field in teh FLOWSPEC
SERVICE_IMMEDIATE_TRAFFIC_CONTROL = $80000000;
// WinSock 2 extension -- manifest constants for return values of the condition function
CF_ACCEPT = $0000;
CF_REJECT = $0001;
CF_DEFER = $0002;
// WinSock 2 extension -- manifest constants for shutdown()
SD_RECEIVE = $00;
SD_SEND = $01;
SD_BOTH = $02;
// WinSock 2 extension -- data type and manifest constants for socket groups
SG_UNCONSTRAINED_GROUP = $01;
SG_CONSTRAINED_GROUP = $02;
type
GROUP = DWORD;
// WinSock 2 extension -- data type for WSAEnumNetworkEvents()
TWSANetworkEvents = record
lNetworkEvents: LongInt;
iErrorCode: Array[0..FD_MAX_EVENTS-1] of Integer;
end;
PWSANetworkEvents = ^TWSANetworkEvents;
LPWSANetworkEvents = PWSANetworkEvents;
// WinSock 2 extension -- WSAPROTOCOL_INFO structure
{$ifndef ver130}
TGUID = packed record
D1: LongInt;
D2: Word;
D3: Word;
D4: Array[0..7] of Byte;
end;
PGUID = ^TGUID;
{$endif}
LPGUID = PGUID;
// WinSock 2 extension -- WSAPROTOCOL_INFO manifest constants
const
MAX_PROTOCOL_CHAIN = 7;
BASE_PROTOCOL = 1;
LAYERED_PROTOCOL = 0;
WSAPROTOCOL_LEN = 255;
type
TWSAProtocolChain = record
ChainLen: Integer; // the length of the chain,
// length = 0 means layered protocol,
// length = 1 means base protocol,
// length > 1 means protocol chain
ChainEntries: Array[0..MAX_PROTOCOL_CHAIN-1] of LongInt; // a list of dwCatalogEntryIds
end;
type
TWSAProtocol_InfoA = record
dwServiceFlags1: LongInt;
dwServiceFlags2: LongInt;
dwServiceFlags3: LongInt;
dwServiceFlags4: LongInt;
dwProviderFlags: LongInt;
ProviderId: TGUID;
dwCatalogEntryId: LongInt;
ProtocolChain: TWSAProtocolChain;
iVersion: Integer;
iAddressFamily: Integer;
iMaxSockAddr: Integer;
iMinSockAddr: Integer;
iSocketType: Integer;
iProtocol: Integer;
iProtocolMaxOffset: Integer;
iNetworkByteOrder: Integer;
iSecurityScheme: Integer;
dwMessageSize: LongInt;
dwProviderReserved: LongInt;
szProtocol: Array[0..WSAPROTOCOL_LEN+1-1] of Char;
end {TWSAProtocol_InfoA};
PWSAProtocol_InfoA = ^TWSAProtocol_InfoA;
LPWSAProtocol_InfoA = PWSAProtocol_InfoA;
TWSAProtocol_InfoW = record
dwServiceFlags1: LongInt;
dwServiceFlags2: LongInt;
dwServiceFlags3: LongInt;
dwServiceFlags4: LongInt;
dwProviderFlags: LongInt;
ProviderId: TGUID;
dwCatalogEntryId: LongInt;
ProtocolChain: TWSAProtocolChain;
iVersion: Integer;
iAddressFamily: Integer;
iMaxSockAddr: Integer;
iMinSockAddr: Integer;
iSocketType: Integer;
iProtocol: Integer;
iProtocolMaxOffset: Integer;
iNetworkByteOrder: Integer;
iSecurityScheme: Integer;
dwMessageSize: LongInt;
dwProviderReserved: LongInt;
szProtocol: Array[0..WSAPROTOCOL_LEN+1-1] of WideChar;
end {TWSAProtocol_InfoW};
PWSAProtocol_InfoW = ^TWSAProtocol_InfoW;
LPWSAProtocol_InfoW = PWSAProtocol_InfoW;
{$IFDEF UNICODE}
WSAProtocol_Info = TWSAProtocol_InfoW;
TWSAProtocol_Info = TWSAProtocol_InfoW;
PWSAProtocol_Info = PWSAProtocol_InfoW;
LPWSAProtocol_Info = PWSAProtocol_InfoW;
{$ELSE}
WSAProtocol_Info = TWSAProtocol_InfoA;
TWSAProtocol_Info = TWSAProtocol_InfoA;
PWSAProtocol_Info = PWSAProtocol_InfoA;
LPWSAProtocol_Info = PWSAProtocol_InfoA;
{$ENDIF}
const
// Flag bit definitions for dwProviderFlags
PFL_MULTIPLE_PROTO_ENTRIES = $00000001;
PFL_RECOMMENDED_PROTO_ENTRY = $00000002;
PFL_HIDDEN = $00000004;
PFL_MATCHES_PROTOCOL_ZERO = $00000008;
// Flag bit definitions for dwServiceFlags1
XP1_CONNECTIONLESS = $00000001;
XP1_GUARANTEED_DELIVERY = $00000002;
XP1_GUARANTEED_ORDER = $00000004;
XP1_MESSAGE_ORIENTED = $00000008;
XP1_PSEUDO_STREAM = $00000010;
XP1_GRACEFUL_CLOSE = $00000020;
XP1_EXPEDITED_DATA = $00000040;
XP1_CONNECT_DATA = $00000080;
XP1_DISCONNECT_DATA = $00000100;
XP1_SUPPORT_BROADCAST = $00000200;
XP1_SUPPORT_MULTIPOINT = $00000400;
XP1_MULTIPOINT_CONTROL_PLANE = $00000800;
XP1_MULTIPOINT_DATA_PLANE = $00001000;
XP1_QOS_SUPPORTED = $00002000;
XP1_INTERRUPT = $00004000;
XP1_UNI_SEND = $00008000;
XP1_UNI_RECV = $00010000;
XP1_IFS_HANDLES = $00020000;
XP1_PARTIAL_MESSAGE = $00040000;
BIGENDIAN = $0000;
LITTLEENDIAN = $0001;
SECURITY_PROTOCOL_NONE = $0000;
// WinSock 2 extension -- manifest constants for WSAJoinLeaf()
JL_SENDER_ONLY = $01;
JL_RECEIVER_ONLY = $02;
JL_BOTH = $04;
// WinSock 2 extension -- manifest constants for WSASocket()
WSA_FLAG_OVERLAPPED = $01;
WSA_FLAG_MULTIPOINT_C_ROOT = $02;
WSA_FLAG_MULTIPOINT_C_LEAF = $04;
WSA_FLAG_MULTIPOINT_D_ROOT = $08;
WSA_FLAG_MULTIPOINT_D_LEAF = $10;
// WinSock 2 extension -- manifest constants for WSAIoctl()
IOC_UNIX = $00000000;
IOC_WS2 = $08000000;
IOC_PROTOCOL = $10000000;
IOC_VENDOR = $18000000;
SIO_ASSOCIATE_HANDLE = 1 or IOC_WS2 or IOC_IN;
SIO_ENABLE_CIRCULAR_QUEUEING = 2 or IOC_WS2;
SIO_FIND_ROUTE = 3 or IOC_WS2 or IOC_OUT;
SIO_FLUSH = 4 or IOC_WS2;
SIO_GET_BROADCAST_ADDRESS = 5 or IOC_WS2 or IOC_OUT;
SIO_GET_EXTENSION_FUNCTION_POINTER = 6 or IOC_WS2 or IOC_INOUT;
SIO_GET_QOS = 7 or IOC_WS2 or IOC_INOUT;
SIO_GET_GROUP_QOS = 8 or IOC_WS2 or IOC_INOUT;
SIO_MULTIPOINT_LOOPBACK = 9 or IOC_WS2 or IOC_IN;
SIO_MULTICAST_SCOPE = 10 or IOC_WS2 or IOC_IN;
SIO_SET_QOS = 11 or IOC_WS2 or IOC_IN;
SIO_SET_GROUP_QOS = 12 or IOC_WS2 or IOC_IN;
SIO_TRANSLATE_HANDLE = 13 or IOC_WS2 or IOC_INOUT;
SIO_ROUTING_INTERFACE_QUERY = 20 or IOC_WS2 or IOC_INOUT;
SIO_ROUTING_INTERFACE_CHANGE = 21 or IOC_WS2 or IOC_IN;
SIO_ADDRESS_LIST_QUERY = 22 or IOC_WS2 or IOC_OUT; // see below SOCKET_ADDRESS_LIST
SIO_ADDRESS_LIST_CHANGE = 23 or IOC_WS2;
SIO_QUERY_TARGET_PNP_HANDLE = 24 or IOC_WS2 or IOC_OUT;
// WinSock 2 extension -- manifest constants for SIO_TRANSLATE_HANDLE ioctl
TH_NETDEV = $00000001;
TH_TAPI = $00000002;
type
// Manifest constants and type definitions related to name resolution and
// registration (RNR) API
TBLOB = packed record
cbSize : U_LONG;
pBlobData : PBYTE;
end;
PBLOB = ^TBLOB;
// Service Install Flags
const
SERVICE_MULTIPLE = $00000001;
// & Name Spaces
NS_ALL = 0;
NS_SAP = 1;
NS_NDS = 2;
NS_PEER_BROWSE = 3;
NS_TCPIP_LOCAL = 10;
NS_TCPIP_HOSTS = 11;
NS_DNS = 12;
NS_NETBT = 13;
NS_WINS = 14;
NS_NBP = 20;
NS_MS = 30;
NS_STDA = 31;
NS_NTDS = 32;
NS_X500 = 40;
NS_NIS = 41;
NS_NISPLUS = 42;
NS_WRQ = 50;
NS_NETDES = 60;
{ Resolution flags for WSAGetAddressByName().
Note these are also used by the 1.1 API GetAddressByName, so leave them around. }
RES_UNUSED_1 = $00000001;
RES_FLUSH_CACHE = $00000002;
RES_SERVICE = $00000004;
{ Well known value names for Service Types }
SERVICE_TYPE_VALUE_IPXPORTA = 'IpxSocket';
SERVICE_TYPE_VALUE_IPXPORTW : PWideChar = 'IpxSocket';
SERVICE_TYPE_VALUE_SAPIDA = 'SapId';
SERVICE_TYPE_VALUE_SAPIDW : PWideChar = 'SapId';
SERVICE_TYPE_VALUE_TCPPORTA = 'TcpPort';
SERVICE_TYPE_VALUE_TCPPORTW : PWideChar = 'TcpPort';
SERVICE_TYPE_VALUE_UDPPORTA = 'UdpPort';
SERVICE_TYPE_VALUE_UDPPORTW : PWideChar = 'UdpPort';
SERVICE_TYPE_VALUE_OBJECTIDA = 'ObjectId';
SERVICE_TYPE_VALUE_OBJECTIDW : PWideChar = 'ObjectId';
{$IFDEF UNICODE}
SERVICE_TYPE_VALUE_SAPID : PWideChar = 'SapId'; //= SERVICE_TYPE_VALUE_SAPIDW;
SERVICE_TYPE_VALUE_TCPPORT : PWideChar = 'TcpPort'; //= SERVICE_TYPE_VALUE_TCPPORTW;
SERVICE_TYPE_VALUE_UDPPORT : PWideChar = 'UdpPort'; //= SERVICE_TYPE_VALUE_UDPPORTW;
SERVICE_TYPE_VALUE_OBJECTID : PWideChar = 'ObjectId'; //= SERVICE_TYPE_VALUE_OBJECTIDW;
{$ELSE}
SERVICE_TYPE_VALUE_SAPID = SERVICE_TYPE_VALUE_SAPIDA;
SERVICE_TYPE_VALUE_TCPPORT = SERVICE_TYPE_VALUE_TCPPORTA;
SERVICE_TYPE_VALUE_UDPPORT = SERVICE_TYPE_VALUE_UDPPORTA;
SERVICE_TYPE_VALUE_OBJECTID = SERVICE_TYPE_VALUE_OBJECTIDA;
{$ENDIF}
// SockAddr Information
type
SOCKET_ADDRESS = packed record
lpSockaddr : PSockAddr;
iSockaddrLength : Integer;
end;
PSOCKET_ADDRESS = ^SOCKET_ADDRESS;
// CSAddr Information
CSADDR_INFO = packed record
LocalAddr, RemoteAddr : SOCKET_ADDRESS;
iSocketType, iProtocol : LongInt;
end;
PCSADDR_INFO = ^CSADDR_INFO;
LPCSADDR_INFO = ^CSADDR_INFO;
// Address list returned via WSAIoctl( SIO_ADDRESS_LIST_QUERY )
SOCKET_ADDRESS_LIST = packed record
iAddressCount : Integer;
Address : Array [0..0] of SOCKET_ADDRESS;
end;
LPSOCKET_ADDRESS_LIST = ^SOCKET_ADDRESS_LIST;
// Address Family/Protocol Tuples
AFProtocols = record
iAddressFamily : Integer;
iProtocol : Integer;
end;
TAFProtocols = AFProtocols;
PAFProtocols = ^TAFProtocols;
// Client Query API Typedefs
// The comparators
TWSAEComparator = (COMP_EQUAL {= 0}, COMP_NOTLESS );
TWSAVersion = record
dwVersion : DWORD;
ecHow : TWSAEComparator;
end;
PWSAVersion = ^TWSAVersion;
TWSAQuerySetA = packed record
dwSize : DWORD;
lpszServiceInstanceName : PChar;
lpServiceClassId : PGUID;
lpVersion : PWSAVERSION;
lpszComment : PChar;
dwNameSpace : DWORD;
lpNSProviderId : PGUID;
lpszContext : PChar;
dwNumberOfProtocols : DWORD;
lpafpProtocols : PAFProtocols;
lpszQueryString : PChar;
dwNumberOfCsAddrs : DWORD;
lpcsaBuffer : PCSADDR_INFO;
dwOutputFlags : DWORD;
lpBlob : PBLOB;
end;
PWSAQuerySetA = ^TWSAQuerySetA;
LPWSAQuerySetA = PWSAQuerySetA;
TWSAQuerySetW = packed record
dwSize : DWORD;
lpszServiceInstanceName : PWideChar;
lpServiceClassId : PGUID;
lpVersion : PWSAVERSION;
lpszComment : PWideChar;
dwNameSpace : DWORD;
lpNSProviderId : PGUID;
lpszContext : PWideChar;
dwNumberOfProtocols : DWORD;
lpafpProtocols : PAFProtocols;
lpszQueryString : PWideChar;
dwNumberOfCsAddrs : DWORD;
lpcsaBuffer : PCSADDR_INFO;
dwOutputFlags : DWORD;
lpBlob : PBLOB;
end;
PWSAQuerySetW = ^TWSAQuerySetW;
LPWSAQuerySetW = PWSAQuerySetW;
{$IFDEF UNICODE}
TWSAQuerySet = TWSAQuerySetA;
PWSAQuerySet = PWSAQuerySetW;
LPWSAQuerySet = PWSAQuerySetW;
{$ELSE}
TWSAQuerySet = TWSAQuerySetA;
PWSAQuerySet = PWSAQuerySetA;
LPWSAQuerySet = PWSAQuerySetA;
{$ENDIF}
const
LUP_DEEP = $0001;
LUP_CONTAINERS = $0002;
LUP_NOCONTAINERS = $0004;
LUP_NEAREST = $0008;
LUP_RETURN_NAME = $0010;
LUP_RETURN_TYPE = $0020;
LUP_RETURN_VERSION = $0040;
LUP_RETURN_COMMENT = $0080;
LUP_RETURN_ADDR = $0100;
LUP_RETURN_BLOB = $0200;
LUP_RETURN_ALIASES = $0400;
LUP_RETURN_QUERY_STRING = $0800;
LUP_RETURN_ALL = $0FF0;
LUP_RES_SERVICE = $8000;
LUP_FLUSHCACHE = $1000;
LUP_FLUSHPREVIOUS = $2000;
// Return flags
RESULT_IS_ALIAS = $0001;
type
// Service Address Registration and Deregistration Data Types.
TWSAeSetServiceOp = ( RNRSERVICE_REGISTER{=0}, RNRSERVICE_DEREGISTER, RNRSERVICE_DELETE );
{ Service Installation/Removal Data Types. }
TWSANSClassInfoA = packed record
lpszName : PChar;
dwNameSpace : DWORD;
dwValueType : DWORD;
dwValueSize : DWORD;
lpValue : Pointer;
end;
PWSANSClassInfoA = ^TWSANSClassInfoA;
TWSANSClassInfoW = packed record
lpszName : PWideChar;
dwNameSpace : DWORD;
dwValueType : DWORD;
dwValueSize : DWORD;
lpValue : Pointer;
end {TWSANSClassInfoW};
PWSANSClassInfoW = ^TWSANSClassInfoW;
{$IFDEF UNICODE}
WSANSClassInfo = TWSANSClassInfoW;
TWSANSClassInfo = TWSANSClassInfoW;
PWSANSClassInfo = PWSANSClassInfoW;
LPWSANSClassInfo = PWSANSClassInfoW;
{$ELSE}
WSANSClassInfo = TWSANSClassInfoA;
TWSANSClassInfo = TWSANSClassInfoA;
PWSANSClassInfo = PWSANSClassInfoA;
LPWSANSClassInfo = PWSANSClassInfoA;
{$ENDIF // UNICODE}
TWSAServiceClassInfoA = packed record
lpServiceClassId : PGUID;
lpszServiceClassName : PChar;
dwCount : DWORD;
lpClassInfos : PWSANSClassInfoA;
end;
PWSAServiceClassInfoA = ^TWSAServiceClassInfoA;
LPWSAServiceClassInfoA = PWSAServiceClassInfoA;
TWSAServiceClassInfoW = packed record
lpServiceClassId : PGUID;
lpszServiceClassName : PWideChar;
dwCount : DWORD;
lpClassInfos : PWSANSClassInfoW;
end;
PWSAServiceClassInfoW = ^TWSAServiceClassInfoW;
LPWSAServiceClassInfoW = PWSAServiceClassInfoW;
{$IFDEF UNICODE}
WSAServiceClassInfo = TWSAServiceClassInfoW;
TWSAServiceClassInfo = TWSAServiceClassInfoW;
PWSAServiceClassInfo = PWSAServiceClassInfoW;
LPWSAServiceClassInfo = PWSAServiceClassInfoW;
{$ELSE}
WSAServiceClassInfo = TWSAServiceClassInfoA;
TWSAServiceClassInfo = TWSAServiceClassInfoA;
PWSAServiceClassInfo = PWSAServiceClassInfoA;
LPWSAServiceClassInfo = PWSAServiceClassInfoA;
{$ENDIF}
TWSANameSpace_InfoA = packed record
NSProviderId : TGUID;
dwNameSpace : DWORD;
fActive : DWORD{Bool};
dwVersion : DWORD;
lpszIdentifier : PChar;
end;
PWSANameSpace_InfoA = ^TWSANameSpace_InfoA;
LPWSANameSpace_InfoA = PWSANameSpace_InfoA;
TWSANameSpace_InfoW = packed record
NSProviderId : TGUID;
dwNameSpace : DWORD;
fActive : DWORD{Bool};
dwVersion : DWORD;
lpszIdentifier : PWideChar;
end {TWSANameSpace_InfoW};
PWSANameSpace_InfoW = ^TWSANameSpace_InfoW;
LPWSANameSpace_InfoW = PWSANameSpace_InfoW;
{$IFDEF UNICODE}
WSANameSpace_Info = TWSANameSpace_InfoW;
TWSANameSpace_Info = TWSANameSpace_InfoW;
PWSANameSpace_Info = PWSANameSpace_InfoW;
LPWSANameSpace_Info = PWSANameSpace_InfoW;
{$ELSE}
WSANameSpace_Info = TWSANameSpace_InfoA;
TWSANameSpace_Info = TWSANameSpace_InfoA;
PWSANameSpace_Info = PWSANameSpace_InfoA;
LPWSANameSpace_Info = PWSANameSpace_InfoA;
{$ENDIF}
{ WinSock 2 extensions -- data types for the condition function in }
{ WSAAccept() and overlapped I/O completion routine. }
type
LPCONDITIONPROC = function (lpCallerId: LPWSABUF; lpCallerData : LPWSABUF; lpSQOS,lpGQOS : LPQOS; lpCalleeId,lpCalleeData : LPWSABUF;
g : GROUP; dwCallbackData : DWORD ) : Integer; stdcall;
LPWSAOVERLAPPED_COMPLETION_ROUTINE = procedure ( const dwError, cbTransferred : DWORD; const lpOverlapped : LPWSAOVERLAPPED; const dwFlags : DWORD ); stdcall;
function accept( const s: TSocket; var addr: TSockAddr; var addrlen: Integer ): TSocket; stdcall;
function bind( const s: TSocket; const addr: PSockAddr; const namelen: Integer ): Integer; stdcall;
function closesocket( const s: TSocket ): Integer; stdcall;
function connect( const s: TSocket; const name: PSockAddr; namelen: Integer): Integer; stdcall;
function ioctlsocket( const s: TSocket; const cmd: DWORD; var arg: u_long ): Integer; stdcall;
function getpeername( const s: TSocket; var name: TSockAddr; var namelen: Integer ): Integer; stdcall;
function getsockname( const s: TSocket; var name: TSockAddr; var namelen: Integer ): Integer; stdcall;
function getsockopt( const s: TSocket; const level, optname: Integer; optval: PChar; var optlen: Integer ): Integer; stdcall;
function htonl(hostlong: u_long): u_long; stdcall;
function htons(hostshort: u_short): u_short; stdcall;
function inet_addr(cp: PChar): u_long; stdcall;
function inet_ntoa(inaddr: TInAddr): PChar; stdcall;
function listen(s: TSocket; backlog: Integer): Integer; stdcall;
function ntohl(netlong: u_long): u_long; stdcall;
function ntohs(netshort: u_short): u_short; stdcall;
function recv(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
function recvfrom(s: TSocket; var Buf; len, flags: Integer; var from: TSockAddr; var fromlen: Integer): Integer; stdcall;
function select(nfds: Integer; readfds, writefds, exceptfds: PFDSet; timeout: PTimeVal): Integer; stdcall;
function send(s: TSocket; var Buf; len, flags: Integer): Integer; stdcall;
function sendto(s: TSocket; var Buf; len, flags: Integer; var addrto: TSockAddr; tolen: Integer): Integer; stdcall;
function setsockopt(s: TSocket; level, optname: Integer; optval: PChar; optlen: Integer): Integer; stdcall;
function shutdown(s: TSocket; how: Integer): Integer; stdcall;
function socket( const af, struct, protocol: Integer ): TSocket; stdcall;
function gethostbyaddr(addr: Pointer; len, struct: Integer): PHostEnt; stdcall;
function gethostbyname(name: PChar): PHostEnt; stdcall;
function gethostname(name: PChar; len: Integer): Integer; stdcall;
function getservbyport(port: Integer; proto: PChar): PServEnt; stdcall;
function getservbyname(const name, proto: PChar): PServEnt; stdcall;
function getprotobynumber(const proto: Integer): PProtoEnt; stdcall;
function getprotobyname(const name: PChar): PProtoEnt; stdcall;
function WSAStartup(wVersionRequired: word; var WSData: TWSAData): Integer; stdcall;
function WSACleanup: Integer; stdcall;
procedure WSASetLastError(iError: Integer); stdcall;
function WSAGetLastError: Integer; stdcall;
function WSAIsBlocking: BOOL; stdcall;
function WSAUnhookBlockingHook: Integer; stdcall;
function WSASetBlockingHook(lpBlockFunc: TFarProc): TFarProc; stdcall;
function WSACancelBlockingCall: Integer; stdcall;
function WSAAsyncGetServByName(HWindow: HWND; wMsg: u_int; name, proto, buf: PChar; buflen: Integer): THandle; stdcall;
function WSAAsyncGetServByPort( HWindow: HWND; wMsg, port: u_int; proto, buf: PChar; buflen: Integer): THandle; stdcall;
function WSAAsyncGetProtoByName(HWindow: HWND; wMsg: u_int; name, buf: PChar; buflen: Integer): THandle; stdcall;
function WSAAsyncGetProtoByNumber(HWindow: HWND; wMsg: u_int; number: Integer; buf: PChar; buflen: Integer): THandle; stdcall;
function WSAAsyncGetHostByName(HWindow: HWND; wMsg: u_int; name, buf: PChar; buflen: Integer): THandle; stdcall;
function WSAAsyncGetHostByAddr(HWindow: HWND; wMsg: u_int; addr: PChar; len, struct: Integer; buf: PChar; buflen: Integer): THandle; stdcall;
function WSACancelAsyncRequest(hAsyncTaskHandle: THandle): Integer; stdcall;
function WSAAsyncSelect(s: TSocket; HWindow: HWND; wMsg: u_int; lEvent: Longint): Integer; stdcall;
function __WSAFDIsSet(s: TSOcket; var FDSet: TFDSet): Bool; stdcall;
{ WinSock 2 API new function prototypes }
function WSAAccept( s : TSocket; addr : TSockAddr; addrlen : PInteger; lpfnCondition : LPCONDITIONPROC; dwCallbackData : DWORD ): TSocket; stdcall;
function WSACloseEvent( hEvent : WSAEVENT) : WordBool; stdcall;
function WSAConnect( s : TSocket; const name : PSockAddr; namelen : Integer; lpCallerData,lpCalleeData : LPWSABUF; lpSQOS,lpGQOS : LPQOS ) : Integer; stdcall;
function WSACreateEvent : WSAEVENT; stdcall;
function WSADuplicateSocketA( s : TSocket; dwProcessId : DWORD; lpProtocolInfo : LPWSAProtocol_InfoA ) : Integer; stdcall;
function WSADuplicateSocketW( s : TSocket; dwProcessId : DWORD; lpProtocolInfo : LPWSAProtocol_InfoW ) : Integer; stdcall;
function WSADuplicateSocket( s : TSocket; dwProcessId : DWORD; lpProtocolInfo : LPWSAProtocol_Info ) : Integer; stdcall;
function WSAEnumNetworkEvents( const s : TSocket; const hEventObject : WSAEVENT; lpNetworkEvents : LPWSANETWORKEVENTS ) :Integer; stdcall;
function WSAEnumProtocolsA( lpiProtocols : PInteger; lpProtocolBuffer : LPWSAProtocol_InfoA; var lpdwBufferLength : DWORD ) : Integer; stdcall;
function WSAEnumProtocolsW( lpiProtocols : PInteger; lpProtocolBuffer : LPWSAProtocol_InfoW; var lpdwBufferLength : DWORD ) : Integer; stdcall;
function WSAEnumProtocols( lpiProtocols : PInteger; lpProtocolBuffer : LPWSAProtocol_Info; var lpdwBufferLength : DWORD ) : Integer; stdcall;
function WSAEventSelect( s : TSocket; hEventObject : WSAEVENT; lNetworkEvents : LongInt ): Integer; stdcall;
function WSAGetOverlappedResult( s : TSocket; lpOverlapped : LPWSAOVERLAPPED; lpcbTransfer : LPDWORD; fWait : BOOL; var lpdwFlags : DWORD ) : WordBool; stdcall;
function WSAGetQosByName( s : TSocket; lpQOSName : LPWSABUF; lpQOS : LPQOS ): WordBool; stdcall;
function WSAhtonl( s : TSocket; hostlong : u_long; var lpnetlong : DWORD ): Integer; stdcall;
function WSAhtons( s : TSocket; hostshort : u_short; var lpnetshort : WORD ): Integer; stdcall;
function WSAIoctl( s : TSocket; dwIoControlCode : DWORD; lpvInBuffer : Pointer; cbInBuffer : DWORD; lpvOutBuffer : Pointer; cbOutBuffer : DWORD;
lpcbBytesReturned : LPDWORD; lpOverlapped : LPWSAOVERLAPPED; lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE ) : Integer; stdcall;
function WSAJoinLeaf( s : TSocket; name : PSockAddr; namelen : Integer; lpCallerData,lpCalleeData : LPWSABUF;
lpSQOS,lpGQOS : LPQOS; dwFlags : DWORD ) : TSocket; stdcall;
function WSANtohl( s : TSocket; netlong : u_long; var lphostlong : DWORD ): Integer; stdcall;
function WSANtohs( s : TSocket; netshort : u_short; var lphostshort : WORD ): Integer; stdcall;
function WSARecv( s : TSocket; lpBuffers : LPWSABUF; dwBufferCount : DWORD; var lpNumberOfBytesRecvd : DWORD; var lpFlags : DWORD;
lpOverlapped : LPWSAOVERLAPPED; lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE ): Integer; stdcall;
function WSARecvDisconnect( s : TSocket; lpInboundDisconnectData : LPWSABUF ): Integer; stdcall;
function WSARecvFrom( s : TSocket; lpBuffers : LPWSABUF; dwBufferCount : DWORD; var lpNumberOfBytesRecvd : DWORD; var lpFlags : DWORD;
lpFrom : PSockAddr; lpFromlen : PInteger; lpOverlapped : LPWSAOVERLAPPED; lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE ): Integer; stdcall;
function WSAResetEvent( hEvent : WSAEVENT ): WordBool; stdcall;
function WSASend( s : TSocket; lpBuffers : LPWSABUF; dwBufferCount : DWORD; var lpNumberOfBytesSent : DWORD; dwFlags : DWORD;
lpOverlapped : LPWSAOVERLAPPED; lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE ): Integer; stdcall;
function WSASendDisconnect( s : TSocket; lpOutboundDisconnectData : LPWSABUF ): Integer; stdcall;
function WSASendTo( s : TSocket; lpBuffers : LPWSABUF; dwBufferCount : DWORD; var lpNumberOfBytesSent : DWORD; dwFlags : DWORD;
lpTo : PSockAddr; iTolen : Integer; lpOverlapped : LPWSAOVERLAPPED; lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE ): Integer; stdcall;
function WSASetEvent( hEvent : WSAEVENT ): WordBool; stdcall;
function WSASocketA( af, iType, protocol : Integer; lpProtocolInfo : LPWSAProtocol_InfoA; g : GROUP; dwFlags : DWORD ): TSocket; stdcall;
function WSASocketW( af, iType, protocol : Integer; lpProtocolInfo : LPWSAProtocol_InfoW; g : GROUP; dwFlags : DWORD ): TSocket; stdcall;
function WSASocket( af, iType, protocol : Integer; lpProtocolInfo : LPWSAProtocol_Info; g : GROUP; dwFlags : DWORD ): TSocket; stdcall;
function WSAWaitForMultipleEvents( cEvents : DWORD; lphEvents : PWSAEVENT; fWaitAll : LongBool;
dwTimeout : DWORD; fAlertable : LongBool ): DWORD; stdcall;
function WSAAddressToStringA( lpsaAddress : PSockAddr; const dwAddressLength : DWORD; const lpProtocolInfo : LPWSAProtocol_InfoA;
const lpszAddressString : PChar; var lpdwAddressStringLength : DWORD ): Integer; stdcall;
function WSAAddressToStringW( lpsaAddress : PSockAddr; const dwAddressLength : DWORD; const lpProtocolInfo : LPWSAProtocol_InfoW;
const lpszAddressString : PWideChar; var lpdwAddressStringLength : DWORD ): Integer; stdcall;
function WSAAddressToString( lpsaAddress : PSockAddr; const dwAddressLength : DWORD; const lpProtocolInfo : LPWSAProtocol_Info;
const lpszAddressString : PMBChar; var lpdwAddressStringLength : DWORD ): Integer; stdcall;
function WSAStringToAddressA( const AddressString : PChar; const AddressFamily: Integer; const lpProtocolInfo : LPWSAProtocol_InfoA;
var lpAddress : TSockAddr; var lpAddressLength : Integer ): Integer; stdcall;
function WSAStringToAddressW( const AddressString : PWideChar; const AddressFamily: Integer; const lpProtocolInfo : LPWSAProtocol_InfoA;
var lpAddress : TSockAddr; var lpAddressLength : Integer ): Integer; stdcall;
function WSAStringToAddress( const AddressString : PMBChar; const AddressFamily: Integer; const lpProtocolInfo : LPWSAProtocol_Info;
var lpAddress : TSockAddr; var lpAddressLength : Integer ): Integer; stdcall;
{ Registration and Name Resolution API functions }
function WSALookupServiceBeginA( var qsRestrictions : TWSAQuerySetA; const dwControlFlags : DWORD; var hLookup : THANDLE ): Integer; stdcall;
function WSALookupServiceBeginW( var qsRestrictions : TWSAQuerySetW; const dwControlFlags : DWORD; var hLookup : THANDLE ): Integer; stdcall;
function WSALookupServiceBegin( var qsRestrictions : TWSAQuerySet; const dwControlFlags : DWORD; var hLookup : THANDLE ): Integer; stdcall;
function WSALookupServiceNextA( const hLookup : THandle; const dwControlFlags : DWORD; var dwBufferLength : DWORD; lpqsResults : PWSAQuerySetA ): Integer; stdcall;
function WSALookupServiceNextW( const hLookup : THandle; const dwControlFlags : DWORD; var dwBufferLength : DWORD; lpqsResults : PWSAQuerySetW ): Integer; stdcall;
function WSALookupServiceNext( const hLookup : THandle; const dwControlFlags : DWORD; var dwBufferLength : DWORD; lpqsResults : PWSAQuerySet ): Integer; stdcall;
function WSALookupServiceEnd( const hLookup : THandle ): Integer; stdcall;
function WSAInstallServiceClassA( const lpServiceClassInfo : LPWSAServiceClassInfoA ) : Integer; stdcall;
function WSAInstallServiceClassW( const lpServiceClassInfo : LPWSAServiceClassInfoW ) : Integer; stdcall;
function WSAInstallServiceClass( const lpServiceClassInfo : LPWSAServiceClassInfo ) : Integer; stdcall;
function WSARemoveServiceClass( const lpServiceClassId : PGUID ) : Integer; stdcall;
function WSAGetServiceClassInfoA( const lpProviderId : PGUID; const lpServiceClassId : PGUID; var lpdwBufSize : DWORD;
lpServiceClassInfo : LPWSAServiceClassInfoA ): Integer; stdcall;
function WSAGetServiceClassInfoW( const lpProviderId : PGUID; const lpServiceClassId : PGUID; var lpdwBufSize : DWORD;
lpServiceClassInfo : LPWSAServiceClassInfoW ): Integer; stdcall;
function WSAGetServiceClassInfo( const lpProviderId : PGUID; const lpServiceClassId : PGUID; var lpdwBufSize : DWORD;
lpServiceClassInfo : LPWSAServiceClassInfo ): Integer; stdcall;
function WSAEnumNameSpaceProvidersA( var lpdwBufferLength: DWORD; const lpnspBuffer: LPWSANameSpace_InfoA ): Integer; stdcall;
function WSAEnumNameSpaceProvidersW( var lpdwBufferLength: DWORD; const lpnspBuffer: LPWSANameSpace_InfoW ): Integer; stdcall;
function WSAEnumNameSpaceProviders( var lpdwBufferLength: DWORD; const lpnspBuffer: LPWSANameSpace_Info ): Integer; stdcall;
function WSAGetServiceClassNameByClassIdA( const lpServiceClassId: PGUID; lpszServiceClassName: PChar;
var lpdwBufferLength: DWORD ): Integer; stdcall;
function WSAGetServiceClassNameByClassIdW( const lpServiceClassId: PGUID; lpszServiceClassName: PWideChar;
var lpdwBufferLength: DWORD ): Integer; stdcall;
function WSAGetServiceClassNameByClassId( const lpServiceClassId: PGUID; lpszServiceClassName: PMBChar;
var lpdwBufferLength: DWORD ): Integer; stdcall;
function WSASetServiceA( const lpqsRegInfo: LPWSAQuerySetA; const essoperation: TWSAeSetServiceOp;
const dwControlFlags: DWORD ): Integer; stdcall;
function WSASetServiceW( const lpqsRegInfo: LPWSAQuerySetW; const essoperation: TWSAeSetServiceOp;
const dwControlFlags: DWORD ): Integer; stdcall;
function WSASetService( const lpqsRegInfo: LPWSAQuerySet; const essoperation: TWSAeSetServiceOp;
const dwControlFlags: DWORD ): Integer; stdcall;
function WSAProviderConfigChange( var lpNotificationHandle : THandle; lpOverlapped : LPWSAOVERLAPPED; lpCompletionRoutine : LPWSAOVERLAPPED_COMPLETION_ROUTINE ) : Integer; stdcall;
{ Macros }
function WSAMakeSyncReply(Buflen, Error: Word): Longint;
function WSAMakeSelectReply(Event, Error: Word): Longint;
function WSAGetAsyncBuflen(Param: Longint): Word;
function WSAGetAsyncError(Param: Longint): Word;
function WSAGetSelectEvent(Param: Longint): Word;
function WSAGetSelectError(Param: Longint): Word;
procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet);
function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean;
procedure FD_SET(Socket: TSocket; var FDSet: TFDSet);
procedure FD_ZERO(var FDSet: TFDSet);
//******************************************************************************
//******************************************************************************
//******************************************************************************
{
WS2TCPIP.H - WinSock2 Extension for TCP/IP protocols
This file contains TCP/IP specific information for use
by WinSock2 compatible applications.
Copyright (c) 1995-1999 Microsoft Corporation
To provide the backward compatibility, all the TCP/IP
specific definitions that were included in the WINSOCK.H
file are now included in WINSOCK2.H file. WS2TCPIP.H
file includes only the definitions introduced in the
"WinSock 2 Protocol-Specific Annex" document.
Rev 0.3 Nov 13, 1995
Rev 0.4 Dec 15, 1996
}
// Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP
type
ip_mreq = packed record
imr_multiaddr : TInAddr; // IP multicast address of group
imr_interface : TInAddr; // local IP address of interface
end;
// TCP/IP specific Ioctl codes
const
SIO_GET_INTERFACE_LIST = IOC_OUT or (SizeOf(Longint) shl 16) or (Ord('t') shl 8) or 127;
// New IOCTL with address size independent address array
SIO_GET_INTERFACE_LIST_EX = IOC_OUT or (SizeOf(Longint) shl 16) or (Ord('t') shl 8) or 126;
// Options for use with [gs]etsockopt at the IP level.
IP_OPTIONS = 1; // set/get IP options
IP_HDRINCL = 2; // header is included with data
IP_TOS = 3; // IP type of service and preced
IP_TTL = 4; // IP time to live
IP_MULTICAST_IF = 9; // set/get IP multicast i/f
IP_MULTICAST_TTL = 10; // set/get IP multicast ttl
IP_MULTICAST_LOOP = 11; // set/get IP multicast loopback
IP_ADD_MEMBERSHIP = 12; // add an IP group membership
IP_DROP_MEMBERSHIP = 13; // drop an IP group membership
IP_DONTFRAGMENT = 14; // don't fragment IP datagrams
IP_DEFAULT_MULTICAST_TTL = 1; // normally limit m'casts to 1 hop
IP_DEFAULT_MULTICAST_LOOP = 1; // normally hear sends if a member
IP_MAX_MEMBERSHIPS = 20; // per socket; must fit in one mbuf
// Option to use with [gs]etsockopt at the IPPROTO_UDP level
UDP_NOCHECKSUM = 1;
// Option to use with [gs]etsockopt at the IPPROTO_TCP level
TCP_EXPEDITED_1122 = $0002;
// IPv6 definitions
type
IN_ADDR6 = packed record
s6_addr : array[0..15] of u_char; // IPv6 address
end;
TIn6Addr = IN_ADDR6;
PIn6Addr = ^IN_ADDR6;
IN6_ADDR = IN_ADDR6;
PIN6_ADDR = ^IN_ADDR6;
LPIN6_ADDR = ^IN_ADDR6;
// Old IPv6 socket address structure (retained for sockaddr_gen definition below)
SOCKADDR_IN6_OLD = packed record
sin6_family : Smallint; // AF_INET6
sin6_port : u_short; // Transport level port number
sin6_flowinfo : u_long; // IPv6 flow information
sin6_addr : IN_ADDR6; // IPv6 address
end;
// IPv6 socket address structure, RFC 2553
SOCKADDR_IN6 = packed record
sin6_family : Smallint; // AF_INET6
sin6_port : u_short; // Transport level port number
sin6_flowinfo : u_long; // IPv6 flow information
sin6_addr : IN_ADDR6; // IPv6 address
sin6_scope_id : u_long; // set of interfaces for a scope
end;
TSockAddrIn6 = SOCKADDR_IN6;
PSockAddrIn6 = ^SOCKADDR_IN6;
PSOCKADDR_IN6 = ^SOCKADDR_IN6;
LPSOCKADDR_IN6 = ^SOCKADDR_IN6;
sockaddr_gen = packed record
case Integer of
1 : ( Address : SOCKADDR; );
2 : ( AddressIn : SOCKADDR_IN; );
3 : ( AddressIn6 : SOCKADDR_IN6_OLD; );
end;
// Structure to keep interface specific information
INTERFACE_INFO = packed record
iiFlags : u_long; // Interface flags
iiAddress : sockaddr_gen; // Interface address
iiBroadcastAddress : sockaddr_gen; // Broadcast address
iiNetmask : sockaddr_gen; // Network mask
end;
TINTERFACE_INFO = INTERFACE_INFO;
LPINTERFACE_INFO = ^INTERFACE_INFO;
// New structure that does not have dependency on the address size
INTERFACE_INFO_EX = packed record
iiFlags : u_long; // Interface flags
iiAddress : SOCKET_ADDRESS; // Interface address
iiBroadcastAddress : SOCKET_ADDRESS; // Broadcast address
iiNetmask : SOCKET_ADDRESS; // Network mask
end;
TINTERFACE_INFO_EX = INTERFACE_INFO_EX;
LPINTERFACE_INFO_EX = ^INTERFACE_INFO_EX;
// Possible flags for the iiFlags - bitmask
const
IFF_UP = $00000001; // Interface is up
IFF_BROADCAST = $00000002; // Broadcast is supported
IFF_LOOPBACK = $00000004; // this is loopback interface
IFF_POINTTOPOINT = $00000008; // this is point-to-point interface
IFF_MULTICAST = $00000010; // multicast is supported
//******************************************************************************
//******************************************************************************
//******************************************************************************
{
wsipx.h
Microsoft Windows
Copyright (C) Microsoft Corporation, 1992-1999.
Windows Sockets include file for IPX/SPX. This file contains all
standardized IPX/SPX information. Include this header file after
winsock.h.
To open an IPX socket, call socket() with an address family of
AF_IPX, a socket type of SOCK_DGRAM, and protocol NSPROTO_IPX.
Note that the protocol value must be specified, it cannot be 0.
All IPX packets are sent with the packet type field of the IPX
header set to 0.
To open an SPX or SPXII socket, call socket() with an address
family of AF_IPX, socket type of SOCK_SEQPACKET or SOCK_STREAM,
and protocol of NSPROTO_SPX or NSPROTO_SPXII. If SOCK_SEQPACKET
is specified, then the end of message bit is respected, and
recv() calls are not completed until a packet is received with
the end of message bit set. If SOCK_STREAM is specified, then
the end of message bit is not respected, and recv() completes
as soon as any data is received, regardless of the setting of the
end of message bit. Send coalescing is never performed, and sends
smaller than a single packet are always sent with the end of
message bit set. Sends larger than a single packet are packetized
with the end of message bit set on only the last packet of the
send.
}
// This is the structure of the SOCKADDR structure for IPX and SPX.
type
SOCKADDR_IPX = packed record
sa_family : u_short;
sa_netnum : Array [0..3] of Char;
sa_nodenum : Array [0..5] of Char;
sa_socket : u_short;
end;
TSOCKADDR_IPX = SOCKADDR_IPX;
PSOCKADDR_IPX = ^SOCKADDR_IPX;
LPSOCKADDR_IPX = ^SOCKADDR_IPX;
// Protocol families used in the "protocol" parameter of the socket() API.
const
NSPROTO_IPX = 1000;
NSPROTO_SPX = 1256;
NSPROTO_SPXII = 1257;
//******************************************************************************
//******************************************************************************
//******************************************************************************
{
wsnwlink.h
Microsoft Windows
Copyright (C) Microsoft Corporation, 1992-1999.
Microsoft-specific extensions to the Windows NT IPX/SPX Windows
Sockets interface. These extensions are provided for use as
necessary for compatibility with existing applications. They are
otherwise not recommended for use, as they are only guaranteed to
work over the Microsoft IPX/SPX stack. An application which
uses these extensions may not work over other IPX/SPX
implementations. Include this header file after winsock.h and
wsipx.h.
To open an IPX socket where a particular packet type is sent in
the IPX header, specify NSPROTO_IPX + n as the protocol parameter
of the socket() API. For example, to open an IPX socket that
sets the packet type to 34, use the following socket() call:
s = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX + 34);
}
// Below are socket option that may be set or retrieved by specifying
// the appropriate manifest in the "optname" parameter of getsockopt()
// or setsockopt(). Use NSPROTO_IPX as the "level" argument for the
// call.
const
// Set/get the IPX packet type. The value specified in the
// optval argument will be set as the packet type on every IPX
// packet sent from this socket. The optval parameter of
// getsockopt()/setsockopt() points to an int.
IPX_PTYPE = $4000;
// Set/get the receive filter packet type. Only IPX packets with
// a packet type equal to the value specified in the optval
// argument will be returned; packets with a packet type that
// does not match are discarded. optval points to an int.
IPX_FILTERPTYPE = $4001;
// Stop filtering on packet type set with IPX_FILTERPTYPE.
IPX_STOPFILTERPTYPE = $4003;
// Set/get the value of the datastream field in the SPX header on
// every packet sent. optval points to an int.
IPX_DSTYPE = $4002;
// Enable extended addressing. On sends, adds the element
// "unsigned char sa_ptype" to the SOCKADDR_IPX structure,
// making the total length 15 bytes. On receives, add both
// the sa_ptype and "unsigned char sa_flags" to the SOCKADDR_IPX
// structure, making the total length 16 bytes. The current
// bits defined in sa_flags are:
// 0x01 - the received frame was sent as a broadcast
// 0x02 - the received frame was sent from this machine
// optval points to a BOOL.
IPX_EXTENDED_ADDRESS = $4004;
// Send protocol header up on all receive packets. optval points
// to a BOOL.
IPX_RECVHDR = $4005;
// Get the maximum data size that can be sent. Not valid with
// setsockopt(). optval points to an int where the value is
// returned.
IPX_MAXSIZE = $4006;
// Query information about a specific adapter that IPX is bound
// to. In a system with n adapters they are numbered 0 through n-1.
// Callers can issue the IPX_MAX_ADAPTER_NUM getsockopt() to find
// out the number of adapters present, or call IPX_ADDRESS with
// increasing values of adapternum until it fails. Not valid
// with setsockopt(). optval points to an instance of the
// IPX_ADDRESS_DATA structure with the adapternum filled in.
IPX_ADDRESS = $4007;
type
IPX_ADDRESS_DATA = packed record
adapternum : Integer; // input: 0-based adapter number
netnum : Array [0..3] of Byte; // output: IPX network number
nodenum : Array [0..5] of Byte; // output: IPX node address
wan : Boolean; // output: TRUE = adapter is on a wan link
status : Boolean; // output: TRUE = wan link is up (or adapter is not wan)
maxpkt : Integer; // output: max packet size, not including IPX header
linkspeed : ULONG; // output: link speed in 100 bytes/sec (i.e. 96 == 9600 bps)
end;
PIPX_ADDRESS_DATA = ^IPX_ADDRESS_DATA;
const
// Query information about a specific IPX network number. If the
// network is in IPX's cache it will return the information directly,
// otherwise it will issue RIP requests to find it. Not valid with
// setsockopt(). optval points to an instance of the IPX_NETNUM_DATA
// structure with the netnum filled in.
IPX_GETNETINFO = $4008;
type
IPX_NETNUM_DATA = packed record
netnum : Array [0..3] of Byte; // input: IPX network number
hopcount : Word; // output: hop count to this network, in machine order
netdelay : Word; // output: tick count to this network, in machine order
cardnum : Integer; // output: 0-based adapter number used to route to this net;
// can be used as adapternum input to IPX_ADDRESS
router : Array [0..5] of Byte; // output: MAC address of the next hop router, zeroed if
// the network is directly attached
end;
PIPX_NETNUM_DATA = ^IPX_NETNUM_DATA;
const
// Like IPX_GETNETINFO except it does not issue RIP requests. If the
// network is in IPX's cache it will return the information, otherwise
// it will fail (see also IPX_RERIPNETNUMBER which always forces a
// re-RIP). Not valid with setsockopt(). optval points to an instance of
// the IPX_NETNUM_DATA structure with the netnum filled in.
IPX_GETNETINFO_NORIP = $4009;
// Get information on a connected SPX socket. optval points
// to an instance of the IPX_SPXCONNSTATUS_DATA structure.
// *** All numbers are in Novell (high-low) order. ***
IPX_SPXGETCONNECTIONSTATUS = $400B;
type
IPX_SPXCONNSTATUS_DATA = packed record
ConnectionState : Byte;
WatchDogActive : Byte;
LocalConnectionId : Word;
RemoteConnectionId : Word;
LocalSequenceNumber : Word;
LocalAckNumber : Word;
LocalAllocNumber : Word;
RemoteAckNumber : Word;
RemoteAllocNumber : Word;
LocalSocket : Word;
ImmediateAddress : Array [0..5] of Byte;
RemoteNetwork : Array [0..3] of Byte;
RemoteNode : Array [0..5] of Byte;
RemoteSocket : Word;
RetransmissionCount : Word;
EstimatedRoundTripDelay : Word; // In milliseconds
RetransmittedPackets : Word;
SuppressedPacket : Word;
end;
PIPX_SPXCONNSTATUS_DATA = ^IPX_SPXCONNSTATUS_DATA;
const
// Get notification when the status of an adapter that IPX is
// bound to changes. Typically this will happen when a wan line
// goes up or down. Not valid with setsockopt(). optval points
// to a buffer which contains an IPX_ADDRESS_DATA structure
// followed immediately by a HANDLE to an unsignaled event.
//
// When the getsockopt() query is submitted, it will complete
// successfully. However, the IPX_ADDRESS_DATA pointed to by
// optval will not be updated at that point. Instead the
// request is queued internally inside the transport.
//
// When the status of an adapter changes, IPX will locate a
// queued getsockopt() query and fill in all the fields in the
// IPX_ADDRESS_DATA structure. It will then signal the event
// pointed to by the HANDLE in the optval buffer. This handle
// should be obtained before calling getsockopt() by calling
// CreateEvent(). If multiple getsockopts() are submitted at
// once, different events must be used.
//
// The event is used because the call needs to be asynchronous
// but currently getsockopt() does not support this.
//
// WARNING: In the current implementation, the transport will
// only signal one queued query for each status change. Therefore
// only one service which uses this query should be running at
// once.
IPX_ADDRESS_NOTIFY = $400C;
// Get the maximum number of adapters present. If this call returns
// n then the adapters are numbered 0 through n-1. Not valid
// with setsockopt(). optval points to an int where the value
// is returned.
IPX_MAX_ADAPTER_NUM = $400D;
// Like IPX_GETNETINFO except it forces IPX to re-RIP even if the
// network is in its cache (but not if it is directly attached to).
// Not valid with setsockopt(). optval points to an instance of
// the IPX_NETNUM_DATA structure with the netnum filled in.
IPX_RERIPNETNUMBER = $400E;
// A hint that broadcast packets may be received. The default is
// TRUE. Applications that do not need to receive broadcast packets
// should set this sockopt to FALSE which may cause better system
// performance (note that it does not necessarily cause broadcasts
// to be filtered for the application). Not valid with getsockopt().
// optval points to a BOOL.
IPX_RECEIVE_BROADCAST = $400F;
// On SPX connections, don't delay before sending ack. Applications
// that do not tend to have back-and-forth traffic over SPX should
// set this; it will increase the number of acks sent but will remove
// delays in sending acks. optval points to a BOOL.
IPX_IMMEDIATESPXACK = $4010;
//******************************************************************************
//******************************************************************************
//******************************************************************************
// wsnetbs.h
// Copyright (c) 1994-1999, Microsoft Corp. All rights reserved.
//
// Windows Sockets include file for NETBIOS. This file contains all
// standardized NETBIOS information. Include this header file after
// winsock.h.
// To open a NetBIOS socket, call the socket() function as follows:
//
// s = socket( AF_NETBIOS, {SOCK_SEQPACKET|SOCK_DGRAM}, -Lana );
//
// where Lana is the NetBIOS Lana number of interest. For example, to
// open a socket for Lana 2, specify -2 as the "protocol" parameter
// to the socket() function.
// This is the structure of the SOCKADDR structure for NETBIOS.
const
NETBIOS_NAME_LENGTH = 16;
type
SOCKADDR_NB = packed record
snb_family : Smallint;
snb_type : u_short;
snb_name : array[0..NETBIOS_NAME_LENGTH-1] of Char;
end;
TSockAddr_NB = SOCKADDR_NB;
PSOCKADDR_NB = ^SOCKADDR_NB;
LPSOCKADDR_NB = ^PSOCKADDR_NB;
// Bit values for the snb_type field of SOCKADDR_NB.
const
NETBIOS_UNIQUE_NAME = $0000;
NETBIOS_GROUP_NAME = $0001;
NETBIOS_TYPE_QUICK_UNIQUE = $0002;
NETBIOS_TYPE_QUICK_GROUP = $0003;
// A macro convenient for setting up NETBIOS SOCKADDRs.
procedure SET_NETBIOS_SOCKADDR( snb : PSOCKADDR_NB; const SnbType : Word; const Name : PChar; const Port : Char );
//******************************************************************************
//******************************************************************************
//******************************************************************************
//=============================================================
implementation
//=============================================================
function accept; external WINSOCK2_DLL name 'accept';
function bind; external WINSOCK2_DLL name 'bind';
function closesocket; external WINSOCK2_DLL name 'closesocket';
function connect; external WINSOCK2_DLL name 'connect';
function ioctlsocket; external WINSOCK2_DLL name 'ioctlsocket';
function getpeername; external WINSOCK2_DLL name 'getpeername';
function getsockname; external WINSOCK2_DLL name 'getsockname';
function getsockopt; external WINSOCK2_DLL name 'getsockopt';
function htonl; external WINSOCK2_DLL name 'htonl';
function htons; external WINSOCK2_DLL name 'htons';
function inet_addr; external WINSOCK2_DLL name 'inet_addr';
function inet_ntoa; external WINSOCK2_DLL name 'inet_ntoa';
function listen; external WINSOCK2_DLL name 'listen';
function ntohl; external WINSOCK2_DLL name 'ntohl';
function ntohs; external WINSOCK2_DLL name 'ntohs';
function recv; external WINSOCK2_DLL name 'recv';
function recvfrom; external WINSOCK2_DLL name 'recvfrom';
function select; external WINSOCK2_DLL name 'select';
function send; external WINSOCK2_DLL name 'send';
function sendto; external WINSOCK2_DLL name 'sendto';
function setsockopt; external WINSOCK2_DLL name 'setsockopt';
function shutdown; external WINSOCK2_DLL name 'shutdown';
function socket; external WINSOCK2_DLL name 'socket';
function gethostbyaddr; external WINSOCK2_DLL name 'gethostbyaddr';
function gethostbyname; external WINSOCK2_DLL name 'gethostbyname';
function gethostname; external WINSOCK2_DLL name 'gethostname';
function getservbyport; external WINSOCK2_DLL name 'getservbyport';
function getservbyname; external WINSOCK2_DLL name 'getservbyname';
function getprotobynumber; external WINSOCK2_DLL name 'getprotobynumber';
function getprotobyname; external WINSOCK2_DLL name 'getprotobyname';
function WSAStartup; external WINSOCK2_DLL name 'WSAStartup';
function WSACleanup; external WINSOCK2_DLL name 'WSACleanup';
procedure WSASetLastError; external WINSOCK2_DLL name 'WSASetLastError';
function WSAGetLastError; external WINSOCK2_DLL name 'WSAGetLastError';
function WSAIsBlocking; external WINSOCK2_DLL name 'WSAIsBlocking';
function WSAUnhookBlockingHook; external WINSOCK2_DLL name 'WSAUnhookBlockingHook';
function WSASetBlockingHook; external WINSOCK2_DLL name 'WSASetBlockingHook';
function WSACancelBlockingCall; external WINSOCK2_DLL name 'WSACancelBlockingCall';
function WSAAsyncGetServByName; external WINSOCK2_DLL name 'WSAAsyncGetServByName';
function WSAAsyncGetServByPort; external WINSOCK2_DLL name 'WSAAsyncGetServByPort';
function WSAAsyncGetProtoByName; external WINSOCK2_DLL name 'WSAAsyncGetProtoByName';
function WSAAsyncGetProtoByNumber; external WINSOCK2_DLL name 'WSAAsyncGetProtoByNumber';
function WSAAsyncGetHostByName; external WINSOCK2_DLL name 'WSAAsyncGetHostByName';
function WSAAsyncGetHostByAddr; external WINSOCK2_DLL name 'WSAAsyncGetHostByAddr';
function WSACancelAsyncRequest; external WINSOCK2_DLL name 'WSACancelAsyncRequest';
function WSAAsyncSelect; external WINSOCK2_DLL name 'WSAAsyncSelect';
function __WSAFDIsSet; external WINSOCK2_DLL name '__WSAFDIsSet';
{ WinSock 2 API new function prototypes }
function WSAAccept; external WINSOCK2_DLL name 'WSAAccept';
function WSACloseEvent; external WINSOCK2_DLL name 'WSACloseEvent';
function WSAConnect; external WINSOCK2_DLL name 'WSAConnect';
function WSACreateEvent; external WINSOCK2_DLL name 'WSACreateEvent';
function WSADuplicateSocketA; external WINSOCK2_DLL name 'WSADuplicateSocketA';
function WSADuplicateSocketW; external WINSOCK2_DLL name 'WSADuplicateSocketW';
function WSAEnumNetworkEvents; external WINSOCK2_DLL name 'WSAEnumNetworkEvents';
function WSAEnumProtocolsA; external WINSOCK2_DLL name 'WSAEnumProtocolsA';
function WSAEnumProtocolsW; external WINSOCK2_DLL name 'WSAEnumProtocolsW';
function WSAEventSelect; external WINSOCK2_DLL name 'WSAEventSelect';
function WSAGetOverlappedResult; external WINSOCK2_DLL name 'WSAGetOverlappedResult';
function WSAGetQosByName; external WINSOCK2_DLL name 'WSAGetQosByName';
function WSAhtonl; external WINSOCK2_DLL name 'WSAhtonl';
function WSAhtons; external WINSOCK2_DLL name 'WSAhtons';
function WSAIoctl; external WINSOCK2_DLL name 'WSAIoctl';
function WSAJoinLeaf; external WINSOCK2_DLL name 'WSAJoinLeaf';
function WSANtohl; external WINSOCK2_DLL name 'WSANtohl';
function WSANtohs; external WINSOCK2_DLL name 'WSANtohs';
function WSARecv; external WINSOCK2_DLL name 'WSARecv';
function WSARecvDisconnect; external WINSOCK2_DLL name 'WSARecvDisconnect';
function WSARecvFrom; external WINSOCK2_DLL name 'WSARecvFrom';
function WSAResetEvent; external WINSOCK2_DLL name 'WSAResetEvent';
function WSASend; external WINSOCK2_DLL name 'WSASend';
function WSASendDisconnect; external WINSOCK2_DLL name 'WSASendDisconnect';
function WSASendTo; external WINSOCK2_DLL name 'WSASendTo';
function WSASetEvent; external WINSOCK2_DLL name 'WSASetEvent';
function WSASocketA; external WINSOCK2_DLL name 'WSASocketA';
function WSASocketW; external WINSOCK2_DLL name 'WSASocketW';
function WSAWaitForMultipleEvents; external WINSOCK2_DLL name 'WSAWaitForMultipleEvents';
function WSAAddressToStringA; external WINSOCK2_DLL name 'WSAAddressToStringA';
function WSAAddressToStringW; external WINSOCK2_DLL name 'WSAAddressToStringW';
function WSAStringToAddressA; external WINSOCK2_DLL name 'WSAStringToAddressA';
function WSAStringToAddressW; external WINSOCK2_DLL name 'WSAStringToAddressW';
{ Registration and Name Resolution API functions }
function WSALookupServiceBeginA; external WINSOCK2_DLL name 'WSALookupServiceBeginA';
function WSALookupServiceBeginW; external WINSOCK2_DLL name 'WSALookupServiceBeginW';
function WSALookupServiceNextA; external WINSOCK2_DLL name 'WSALookupServiceNextA';
function WSALookupServiceNextW; external WINSOCK2_DLL name 'WSALookupServiceNextW';
function WSALookupServiceEnd; external WINSOCK2_DLL name 'WSALookupServiceEnd';
function WSAInstallServiceClassA; external WINSOCK2_DLL name 'WSAInstallServiceClassA';
function WSAInstallServiceClassW; external WINSOCK2_DLL name 'WSAInstallServiceClassW';
function WSARemoveServiceClass; external WINSOCK2_DLL name 'WSARemoveServiceClass';
function WSAGetServiceClassInfoA; external WINSOCK2_DLL name 'WSAGetServiceClassInfoA';
function WSAGetServiceClassInfoW; external WINSOCK2_DLL name 'WSAGetServiceClassInfoW';
function WSAEnumNameSpaceProvidersA; external WINSOCK2_DLL name 'WSAEnumNameSpaceProvidersA';
function WSAEnumNameSpaceProvidersW; external WINSOCK2_DLL name 'WSAEnumNameSpaceProvidersW';
function WSAGetServiceClassNameByClassIdA; external WINSOCK2_DLL name 'WSAGetServiceClassNameByClassIdA';
function WSAGetServiceClassNameByClassIdW; external WINSOCK2_DLL name 'WSAGetServiceClassNameByClassIdW';
function WSASetServiceA; external WINSOCK2_DLL name 'WSASetServiceA';
function WSASetServiceW; external WINSOCK2_DLL name 'WSASetServiceW';
{$IFDEF UNICODE}
function WSADuplicateSocket; external WINSOCK2_DLL name 'WSADuplicateSocketW';
function WSAEnumProtocols; external WINSOCK2_DLL name 'WSAEnumProtocolsW';
function WSASocket; external WINSOCK2_DLL name 'WSASocketW';
function WSAAddressToString; external WINSOCK2_DLL name 'WSAAddressToStringW';
function WSAStringToAddress; external WINSOCK2_DLL name 'WSAStringToAddressW';
function WSALookupServiceBegin; external WINSOCK2_DLL name 'WSALookupServiceBeginW';
function WSALookupServiceNext; external WINSOCK2_DLL name 'WSALookupServiceNextW';
function WSAInstallServiceClass; external WINSOCK2_DLL name 'WSAInstallServiceClassW';
function WSAGetServiceClassInfo; external WINSOCK2_DLL name 'WSAGetServiceClassInfoW';
function WSAEnumNameSpaceProviders; external WINSOCK2_DLL name 'WSAEnumNameSpaceProvidersW';
function WSAGetServiceClassNameByClassId; external WINSOCK2_DLL name 'WSAGetServiceClassNameByClassIdW';
function WSASetService; external WINSOCK2_DLL name 'WSASetServiceW';
{$ELSE}
function WSADuplicateSocket; external WINSOCK2_DLL name 'WSADuplicateSocketA';
function WSAEnumProtocols; external WINSOCK2_DLL name 'WSAEnumProtocolsA';
function WSASocket; external WINSOCK2_DLL name 'WSASocketA';
function WSAAddressToString; external WINSOCK2_DLL name 'WSAAddressToStringA';
function WSAStringToAddress; external WINSOCK2_DLL name 'WSAStringToAddressA';
function WSALookupServiceBegin; external WINSOCK2_DLL name 'WSALookupServiceBeginA';
function WSALookupServiceNext; external WINSOCK2_DLL name 'WSALookupServiceNextA';
function WSAInstallServiceClass; external WINSOCK2_DLL name 'WSAInstallServiceClassA';
function WSAGetServiceClassInfo; external WINSOCK2_DLL name 'WSAGetServiceClassInfoA';
function WSAEnumNameSpaceProviders; external WINSOCK2_DLL name 'WSAEnumNameSpaceProvidersA';
function WSAGetServiceClassNameByClassId; external WINSOCK2_DLL name 'WSAGetServiceClassNameByClassIdA';
function WSASetService; external WINSOCK2_DLL name 'WSASetServiceA';
{$ENDIF}
function WSAProviderConfigChange; external WINSOCK2_DLL name 'WSAProviderConfigChange';
function WSAMakeSyncReply;
begin
WSAMakeSyncReply:= MakeLong(Buflen, Error);
end;
function WSAMakeSelectReply;
begin
WSAMakeSelectReply:= MakeLong(Event, Error);
end;
function WSAGetAsyncBuflen;
begin
WSAGetAsyncBuflen:= LOWORD(Param);
end;
function WSAGetAsyncError;
begin
WSAGetAsyncError:= HIWORD(Param);
end;
function WSAGetSelectEvent;
begin
WSAGetSelectEvent:= LOWORD(Param);
end;
function WSAGetSelectError;
begin
WSAGetSelectError:= HIWORD(Param);
end;
procedure FD_CLR(Socket: TSocket; var FDSet: TFDSet);
var i: DWORD;
begin
i := 0;
while i < FDSet.fd_count do
begin
if FDSet.fd_array[i] = Socket then
begin
while i < FDSet.fd_count - 1 do
begin
FDSet.fd_array[i] := FDSet.fd_array[i+1];
Inc(i);
end;
Dec(FDSet.fd_count);
Break;
end;
Inc(i);
end;
end;
function FD_ISSET(Socket: TSocket; var FDSet: TFDSet): Boolean;
begin
Result := __WSAFDIsSet(Socket, FDSet);
end;
procedure FD_SET(Socket: TSocket; var FDSet: TFDSet);
begin
if FDSet.fd_count < FD_SETSIZE then
begin
FDSet.fd_array[FDSet.fd_count] := Socket;
Inc(FDSet.fd_count);
end;
end;
procedure FD_ZERO(var FDSet: TFDSet);
begin
FDSet.fd_count := 0;
end;
// A macro convenient for setting up NETBIOS SOCKADDRs.
procedure SET_NETBIOS_SOCKADDR( snb : PSOCKADDR_NB; const SnbType : Word; const Name : PChar; const Port : Char );
var len : Integer;
begin
if snb<>nil then with snb^ do
begin
snb_family := AF_NETBIOS;
snb_type := SnbType;
len := StrLen(Name);
if len>=NETBIOS_NAME_LENGTH-1 then System.Move(Name^,snb_name,NETBIOS_NAME_LENGTH-1)
else
begin
if len>0 then System.Move(Name^,snb_name,len);
FillChar( (PChar(@snb_name)+len)^, NETBIOS_NAME_LENGTH-1-len, ' ' );
end;
snb_name[NETBIOS_NAME_LENGTH-1] := Port;
end;
end;
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment