mirror of
https://github.com/Relintai/pandemonium_engine_minimal.git
synced 2024-11-17 22:17:19 +01:00
Removed the enet module.
This commit is contained in:
parent
f825e580aa
commit
5d0ce5dc5e
@ -1,43 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import("env")
|
||||
Import("env_modules")
|
||||
|
||||
env_enet = env_modules.Clone()
|
||||
|
||||
# Thirdparty source files
|
||||
|
||||
thirdparty_obj = []
|
||||
|
||||
if env["builtin_enet"]:
|
||||
thirdparty_dir = "enet/"
|
||||
thirdparty_sources = [
|
||||
"pandemonium.cpp",
|
||||
"callbacks.c",
|
||||
"compress.c",
|
||||
"host.c",
|
||||
"list.c",
|
||||
"packet.c",
|
||||
"peer.c",
|
||||
"protocol.c",
|
||||
]
|
||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||
|
||||
env_enet.Prepend(CPPPATH=[thirdparty_dir])
|
||||
env_enet.Append(CPPDEFINES=["PANDEMONIUM_ENET"])
|
||||
|
||||
env_thirdparty = env_enet.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
|
||||
env.modules_sources += thirdparty_obj
|
||||
|
||||
|
||||
# Pandemonium source files
|
||||
|
||||
module_obj = []
|
||||
|
||||
env_enet.add_source_files(module_obj, "*.cpp")
|
||||
env.modules_sources += module_obj
|
||||
|
||||
# Needed to force rebuilding the module files when the thirdparty library is updated.
|
||||
env.Depends(module_obj, thirdparty_obj)
|
@ -1,16 +0,0 @@
|
||||
def can_build(env, platform):
|
||||
return True
|
||||
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
|
||||
|
||||
def get_doc_classes():
|
||||
return [
|
||||
"NetworkedMultiplayerENet",
|
||||
]
|
||||
|
||||
|
||||
def get_doc_path():
|
||||
return "doc_classes"
|
@ -1,138 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="NetworkedMultiplayerENet" inherits="NetworkedMultiplayerPeer" version="4.2">
|
||||
<brief_description>
|
||||
PacketPeer implementation using the [url=http://enet.bespin.org/index.html]ENet[/url] library.
|
||||
</brief_description>
|
||||
<description>
|
||||
A PacketPeer implementation that should be passed to [member SceneTree.network_peer] after being initialized as either a client or server. Events can then be handled by connecting to [SceneTree] signals.
|
||||
ENet's purpose is to provide a relatively thin, simple and robust network communication layer on top of UDP (User Datagram Protocol).
|
||||
[b]Note:[/b] ENet only uses UDP, not TCP. When forwarding the server port to make your server accessible on the public Internet, you only need to forward the server port in UDP. You can use the [UPNP] class to try to forward the server port automatically when starting the server.
|
||||
</description>
|
||||
<tutorials>
|
||||
<link>$DOCS_URL/tutorials/networking/high_level_multiplayer.md</link>
|
||||
<link>http://enet.bespin.org/usergroup0.html</link>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="close_connection">
|
||||
<return type="void" />
|
||||
<argument index="0" name="wait_usec" type="int" default="100" />
|
||||
<description>
|
||||
Closes the connection. Ignored if no connection is currently established. If this is a server it tries to notify all clients before forcibly disconnecting them. If this is a client it simply closes the connection to the server.
|
||||
</description>
|
||||
</method>
|
||||
<method name="create_client">
|
||||
<return type="int" enum="Error" />
|
||||
<argument index="0" name="address" type="String" />
|
||||
<argument index="1" name="port" type="int" />
|
||||
<argument index="2" name="in_bandwidth" type="int" default="0" />
|
||||
<argument index="3" name="out_bandwidth" type="int" default="0" />
|
||||
<argument index="4" name="client_port" type="int" default="0" />
|
||||
<description>
|
||||
Create client that connects to a server at [code]address[/code] using specified [code]port[/code]. The given address needs to be either a fully qualified domain name (e.g. [code]"www.example.com"[/code]) or an IP address in IPv4 or IPv6 format (e.g. [code]"192.168.1.1"[/code]). The [code]port[/code] is the port the server is listening on. The [code]in_bandwidth[/code] and [code]out_bandwidth[/code] parameters can be used to limit the incoming and outgoing bandwidth to the given number of bytes per second. The default of 0 means unlimited bandwidth. Note that ENet will strategically drop packets on specific sides of a connection between peers to ensure the peer's bandwidth is not overwhelmed. The bandwidth parameters also determine the window size of a connection which limits the amount of reliable packets that may be in transit at any given time. Returns [constant OK] if a client was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the client could not be created. If [code]client_port[/code] is specified, the client will also listen to the given port; this is useful for some NAT traversal techniques.
|
||||
</description>
|
||||
</method>
|
||||
<method name="create_server">
|
||||
<return type="int" enum="Error" />
|
||||
<argument index="0" name="port" type="int" />
|
||||
<argument index="1" name="max_clients" type="int" default="32" />
|
||||
<argument index="2" name="in_bandwidth" type="int" default="0" />
|
||||
<argument index="3" name="out_bandwidth" type="int" default="0" />
|
||||
<description>
|
||||
Create server that listens to connections via [code]port[/code]. The port needs to be an available, unused port between 0 and 65535. Note that ports below 1024 are privileged and may require elevated permissions depending on the platform. To change the interface the server listens on, use [method set_bind_ip]. The default IP is the wildcard [code]"*"[/code], which listens on all available interfaces. [code]max_clients[/code] is the maximum number of clients that are allowed at once, any number up to 4095 may be used, although the achievable number of simultaneous clients may be far lower and depends on the application. For additional details on the bandwidth parameters, see [method create_client]. Returns [constant OK] if a server was created, [constant ERR_ALREADY_IN_USE] if this NetworkedMultiplayerENet instance already has an open connection (in which case you need to call [method close_connection] first) or [constant ERR_CANT_CREATE] if the server could not be created.
|
||||
</description>
|
||||
</method>
|
||||
<method name="disconnect_peer">
|
||||
<return type="void" />
|
||||
<argument index="0" name="id" type="int" />
|
||||
<argument index="1" name="now" type="bool" default="false" />
|
||||
<description>
|
||||
Disconnect the given peer. If "now" is set to [code]true[/code], the connection will be closed immediately without flushing queued messages.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_last_packet_channel" qualifiers="const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Returns the channel of the last packet fetched via [method PacketPeer.get_packet].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_packet_channel" qualifiers="const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
Returns the channel of the next packet that will be retrieved via [method PacketPeer.get_packet].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_peer_address" qualifiers="const">
|
||||
<return type="String" />
|
||||
<argument index="0" name="id" type="int" />
|
||||
<description>
|
||||
Returns the IP address of the given peer.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_peer_port" qualifiers="const">
|
||||
<return type="int" />
|
||||
<argument index="0" name="id" type="int" />
|
||||
<description>
|
||||
Returns the remote port of the given peer.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_bind_ip">
|
||||
<return type="void" />
|
||||
<argument index="0" name="ip" type="String" />
|
||||
<description>
|
||||
The IP used when creating a server. This is set to the wildcard [code]"*"[/code] by default, which binds to all available interfaces. The given IP needs to be in IPv4 or IPv6 address format, for example: [code]"192.168.1.1"[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_dtls_certificate">
|
||||
<return type="void" />
|
||||
<argument index="0" name="certificate" type="X509Certificate" />
|
||||
<description>
|
||||
Configure the [X509Certificate] to use when [member use_dtls] is [code]true[/code]. For servers, you must also setup the [CryptoKey] via [method set_dtls_key].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_dtls_key">
|
||||
<return type="void" />
|
||||
<argument index="0" name="key" type="CryptoKey" />
|
||||
<description>
|
||||
Configure the [CryptoKey] to use when [member use_dtls] is [code]true[/code]. Remember to also call [method set_dtls_certificate] to setup your [X509Certificate].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_peer_timeout">
|
||||
<return type="void" />
|
||||
<argument index="0" name="id" type="int" />
|
||||
<argument index="1" name="timeout_limit" type="int" />
|
||||
<argument index="2" name="timeout_min" type="int" />
|
||||
<argument index="3" name="timeout_max" type="int" />
|
||||
<description>
|
||||
Sets the timeout parameters for a peer. The timeout parameters control how and when a peer will timeout from a failure to acknowledge reliable traffic. Timeout values are expressed in milliseconds.
|
||||
The [code]timeout_limit[/code] is a factor that, multiplied by a value based on the average round trip time, will determine the timeout limit for a reliable packet. When that limit is reached, the timeout will be doubled, and the peer will be disconnected if that limit has reached [code]timeout_min[/code]. The [code]timeout_max[/code] parameter, on the other hand, defines a fixed timeout for which any packet must be acknowledged or the peer will be dropped.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="always_ordered" type="bool" setter="set_always_ordered" getter="is_always_ordered" default="false">
|
||||
Enforce ordered packets when using [constant NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE] (thus behaving similarly to [constant NetworkedMultiplayerPeer.TRANSFER_MODE_UNRELIABLE_ORDERED]). This is the only way to use ordering with the RPC system.
|
||||
</member>
|
||||
<member name="channel_count" type="int" setter="set_channel_count" getter="get_channel_count" default="3">
|
||||
The number of channels to be used by ENet. Channels are used to separate different kinds of data. In reliable or ordered mode, for example, the packet delivery order is ensured on a per-channel basis. This is done to combat latency and reduces ordering restrictions on packets. The delivery status of a packet in one channel won't stall the delivery of other packets in another channel.
|
||||
</member>
|
||||
<member name="dtls_hostname" type="String" setter="set_dtls_hostname" getter="get_dtls_hostname" default="""">
|
||||
The hostname used for DTLS verification, to be compared against the "CN" value in the certificate provided by the server.
|
||||
When set to an empty string, the [code]address[/code] parameter passed to [method create_client] is used instead.
|
||||
</member>
|
||||
<member name="dtls_verify" type="bool" setter="set_dtls_verify_enabled" getter="is_dtls_verify_enabled" default="true">
|
||||
Enable or disable certificate verification when [member use_dtls] [code]true[/code].
|
||||
</member>
|
||||
<member name="server_relay" type="bool" setter="set_server_relay_enabled" getter="is_server_relay_enabled" default="true">
|
||||
Enable or disable the server feature that notifies clients of other peers' connection/disconnection, and relays messages between them. When this option is [code]false[/code], clients won't be automatically notified of other peers and won't be able to send them packets through the server.
|
||||
</member>
|
||||
<member name="transfer_channel" type="int" setter="set_transfer_channel" getter="get_transfer_channel" default="-1">
|
||||
Set the default channel to be used to transfer data. By default, this value is [code]-1[/code] which means that ENet will only use 2 channels: one for reliable packets, and one for unreliable packets. The channel [code]0[/code] is reserved and cannot be used. Setting this member to any value between [code]0[/code] and [member channel_count] (excluded) will force ENet to use that channel for sending data. See [member channel_count] for more information about ENet channels.
|
||||
</member>
|
||||
<member name="use_dtls" type="bool" setter="set_dtls_enabled" getter="is_dtls_enabled" default="false">
|
||||
When enabled, the client or server created by this peer, will use [PacketPeerDTLS] instead of raw UDP sockets for communicating with the remote peer. This will make the communication encrypted with DTLS at the cost of higher resource usage and potentially larger packet size.
|
||||
[b]Note:[/b] When creating a DTLS server, make sure you setup the key/certificate pair via [method set_dtls_key] and [method set_dtls_certificate]. For DTLS clients, have a look at the [member dtls_verify] option, and configure the certificate accordingly via [method set_dtls_certificate].
|
||||
</member>
|
||||
</members>
|
||||
<constants>
|
||||
</constants>
|
||||
</class>
|
@ -1,7 +0,0 @@
|
||||
Copyright (c) 2002-2020 Lee Salzman
|
||||
|
||||
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.
|
@ -1,53 +0,0 @@
|
||||
/**
|
||||
@file callbacks.c
|
||||
@brief ENet callback functions
|
||||
*/
|
||||
#define ENET_BUILDING_LIB 1
|
||||
#include "enet/enet.h"
|
||||
|
||||
static ENetCallbacks callbacks = { malloc, free, abort };
|
||||
|
||||
int
|
||||
enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits)
|
||||
{
|
||||
if (version < ENET_VERSION_CREATE (1, 3, 0))
|
||||
return -1;
|
||||
|
||||
if (inits -> malloc != NULL || inits -> free != NULL)
|
||||
{
|
||||
if (inits -> malloc == NULL || inits -> free == NULL)
|
||||
return -1;
|
||||
|
||||
callbacks.malloc = inits -> malloc;
|
||||
callbacks.free = inits -> free;
|
||||
}
|
||||
|
||||
if (inits -> no_memory != NULL)
|
||||
callbacks.no_memory = inits -> no_memory;
|
||||
|
||||
return enet_initialize ();
|
||||
}
|
||||
|
||||
ENetVersion
|
||||
enet_linked_version (void)
|
||||
{
|
||||
return ENET_VERSION;
|
||||
}
|
||||
|
||||
void *
|
||||
enet_malloc (size_t size)
|
||||
{
|
||||
void * memory = callbacks.malloc (size);
|
||||
|
||||
if (memory == NULL)
|
||||
callbacks.no_memory ();
|
||||
|
||||
return memory;
|
||||
}
|
||||
|
||||
void
|
||||
enet_free (void * memory)
|
||||
{
|
||||
callbacks.free (memory);
|
||||
}
|
||||
|
@ -1,654 +0,0 @@
|
||||
/**
|
||||
@file compress.c
|
||||
@brief An adaptive order-2 PPM range coder
|
||||
*/
|
||||
#define ENET_BUILDING_LIB 1
|
||||
#include <string.h>
|
||||
#include "enet/enet.h"
|
||||
|
||||
typedef struct _ENetSymbol
|
||||
{
|
||||
/* binary indexed tree of symbols */
|
||||
enet_uint8 value;
|
||||
enet_uint8 count;
|
||||
enet_uint16 under;
|
||||
enet_uint16 left, right;
|
||||
|
||||
/* context defined by this symbol */
|
||||
enet_uint16 symbols;
|
||||
enet_uint16 escapes;
|
||||
enet_uint16 total;
|
||||
enet_uint16 parent;
|
||||
} ENetSymbol;
|
||||
|
||||
/* adaptation constants tuned aggressively for small packet sizes rather than large file compression */
|
||||
enum
|
||||
{
|
||||
ENET_RANGE_CODER_TOP = 1<<24,
|
||||
ENET_RANGE_CODER_BOTTOM = 1<<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
|
||||
};
|
||||
|
||||
/* context exclusion roughly halves compression speed, so disable for now */
|
||||
#undef ENET_CONTEXT_EXCLUSION
|
||||
|
||||
typedef struct _ENetRangeCoder
|
||||
{
|
||||
/* only allocate enough symbols for reasonable MTUs, would need to be larger for large file compression */
|
||||
ENetSymbol symbols[4096];
|
||||
} ENetRangeCoder;
|
||||
|
||||
void *
|
||||
enet_range_coder_create (void)
|
||||
{
|
||||
ENetRangeCoder * rangeCoder = (ENetRangeCoder *) enet_malloc (sizeof (ENetRangeCoder));
|
||||
if (rangeCoder == NULL)
|
||||
return NULL;
|
||||
|
||||
return rangeCoder;
|
||||
}
|
||||
|
||||
void
|
||||
enet_range_coder_destroy (void * context)
|
||||
{
|
||||
ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
|
||||
if (rangeCoder == NULL)
|
||||
return;
|
||||
|
||||
enet_free (rangeCoder);
|
||||
}
|
||||
|
||||
#define ENET_SYMBOL_CREATE(symbol, value_, count_) \
|
||||
{ \
|
||||
symbol = & rangeCoder -> symbols [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; \
|
||||
}
|
||||
|
||||
#define ENET_CONTEXT_CREATE(context, escapes_, minimum) \
|
||||
{ \
|
||||
ENET_SYMBOL_CREATE (context, 0, 0); \
|
||||
(context) -> escapes = escapes_; \
|
||||
(context) -> total = escapes_ + 256*minimum; \
|
||||
(context) -> symbols = 0; \
|
||||
}
|
||||
|
||||
static enet_uint16
|
||||
enet_symbol_rescale (ENetSymbol * symbol)
|
||||
{
|
||||
enet_uint16 total = 0;
|
||||
for (;;)
|
||||
{
|
||||
symbol -> count -= symbol->count >> 1;
|
||||
symbol -> under = symbol -> count;
|
||||
if (symbol -> left)
|
||||
symbol -> under += enet_symbol_rescale (symbol + symbol -> left);
|
||||
total += symbol -> under;
|
||||
if (! symbol -> right) break;
|
||||
symbol += symbol -> right;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
#define ENET_CONTEXT_RESCALE(context, minimum) \
|
||||
{ \
|
||||
(context) -> total = (context) -> symbols ? enet_symbol_rescale ((context) + (context) -> symbols) : 0; \
|
||||
(context) -> escapes -= (context) -> escapes >> 1; \
|
||||
(context) -> total += (context) -> escapes + 256*minimum; \
|
||||
}
|
||||
|
||||
#define ENET_RANGE_CODER_OUTPUT(value) \
|
||||
{ \
|
||||
if (outData >= outEnd) \
|
||||
return 0; \
|
||||
* outData ++ = value; \
|
||||
}
|
||||
|
||||
#define ENET_RANGE_CODER_ENCODE(under, count, total) \
|
||||
{ \
|
||||
encodeRange /= (total); \
|
||||
encodeLow += (under) * encodeRange; \
|
||||
encodeRange *= (count); \
|
||||
for (;;) \
|
||||
{ \
|
||||
if((encodeLow ^ (encodeLow + encodeRange)) >= ENET_RANGE_CODER_TOP) \
|
||||
{ \
|
||||
if(encodeRange >= ENET_RANGE_CODER_BOTTOM) break; \
|
||||
encodeRange = -encodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \
|
||||
} \
|
||||
ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \
|
||||
encodeRange <<= 8; \
|
||||
encodeLow <<= 8; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ENET_RANGE_CODER_FLUSH \
|
||||
{ \
|
||||
while (encodeLow) \
|
||||
{ \
|
||||
ENET_RANGE_CODER_OUTPUT (encodeLow >> 24); \
|
||||
encodeLow <<= 8; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ENET_RANGE_CODER_FREE_SYMBOLS \
|
||||
{ \
|
||||
if (nextSymbol >= sizeof (rangeCoder -> symbols) / sizeof (ENetSymbol) - ENET_SUBCONTEXT_ORDER ) \
|
||||
{ \
|
||||
nextSymbol = 0; \
|
||||
ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM); \
|
||||
predicted = 0; \
|
||||
order = 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ENET_CONTEXT_ENCODE(context, symbol_, value_, under_, count_, update, minimum) \
|
||||
{ \
|
||||
under_ = value*minimum; \
|
||||
count_ = minimum; \
|
||||
if (! (context) -> symbols) \
|
||||
{ \
|
||||
ENET_SYMBOL_CREATE (symbol_, value_, update); \
|
||||
(context) -> symbols = symbol_ - (context); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
ENetSymbol * node = (context) + (context) -> symbols; \
|
||||
for (;;) \
|
||||
{ \
|
||||
if (value_ < node -> value) \
|
||||
{ \
|
||||
node -> under += update; \
|
||||
if (node -> left) { node += node -> left; continue; } \
|
||||
ENET_SYMBOL_CREATE (symbol_, value_, update); \
|
||||
node -> left = symbol_ - node; \
|
||||
} \
|
||||
else \
|
||||
if (value_ > node -> value) \
|
||||
{ \
|
||||
under_ += node -> under; \
|
||||
if (node -> right) { node += node -> right; continue; } \
|
||||
ENET_SYMBOL_CREATE (symbol_, value_, update); \
|
||||
node -> right = symbol_ - node; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
count_ += node -> count; \
|
||||
under_ += node -> under - node -> count; \
|
||||
node -> under += update; \
|
||||
node -> count += update; \
|
||||
symbol_ = node; \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
static const ENetSymbol emptyContext = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
#define ENET_CONTEXT_WALK(context, body) \
|
||||
{ \
|
||||
const ENetSymbol * node = (context) + (context) -> symbols; \
|
||||
const ENetSymbol * stack [256]; \
|
||||
size_t stackSize = 0; \
|
||||
while (node -> left) \
|
||||
{ \
|
||||
stack [stackSize ++] = node; \
|
||||
node += node -> left; \
|
||||
} \
|
||||
for (;;) \
|
||||
{ \
|
||||
body; \
|
||||
if (node -> right) \
|
||||
{ \
|
||||
node += node -> right; \
|
||||
while (node -> left) \
|
||||
{ \
|
||||
stack [stackSize ++] = node; \
|
||||
node += node -> left; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
if (stackSize <= 0) \
|
||||
break; \
|
||||
else \
|
||||
node = stack [-- stackSize]; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ENET_CONTEXT_ENCODE_EXCLUDE(context, value_, under, total, minimum) \
|
||||
ENET_CONTEXT_WALK(context, { \
|
||||
if (node -> value != value_) \
|
||||
{ \
|
||||
enet_uint16 parentCount = rangeCoder -> symbols [node -> parent].count + minimum; \
|
||||
if (node -> value < value_) \
|
||||
under -= parentCount; \
|
||||
total -= parentCount; \
|
||||
} \
|
||||
})
|
||||
#endif
|
||||
|
||||
size_t
|
||||
enet_range_coder_compress (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit)
|
||||
{
|
||||
ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
|
||||
enet_uint8 * outStart = outData, * outEnd = & outData [outLimit];
|
||||
const enet_uint8 * inData, * inEnd;
|
||||
enet_uint32 encodeLow = 0, encodeRange = ~0;
|
||||
ENetSymbol * root;
|
||||
enet_uint16 predicted = 0;
|
||||
size_t order = 0, nextSymbol = 0;
|
||||
|
||||
if (rangeCoder == NULL || inBufferCount <= 0 || inLimit <= 0)
|
||||
return 0;
|
||||
|
||||
inData = (const enet_uint8 *) inBuffers -> data;
|
||||
inEnd = & inData [inBuffers -> dataLength];
|
||||
inBuffers ++;
|
||||
inBufferCount --;
|
||||
|
||||
ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ENetSymbol * subcontext, * symbol;
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
const ENetSymbol * childContext = & emptyContext;
|
||||
#endif
|
||||
enet_uint8 value;
|
||||
enet_uint16 count, under, * parent = & predicted, total;
|
||||
if (inData >= inEnd)
|
||||
{
|
||||
if (inBufferCount <= 0)
|
||||
break;
|
||||
inData = (const enet_uint8 *) inBuffers -> data;
|
||||
inEnd = & inData [inBuffers -> dataLength];
|
||||
inBuffers ++;
|
||||
inBufferCount --;
|
||||
}
|
||||
value = * inData ++;
|
||||
|
||||
for (subcontext = & rangeCoder -> symbols [predicted];
|
||||
subcontext != root;
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
childContext = subcontext,
|
||||
#endif
|
||||
subcontext = & rangeCoder -> symbols [subcontext -> parent])
|
||||
{
|
||||
ENET_CONTEXT_ENCODE (subcontext, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0);
|
||||
* parent = symbol - rangeCoder -> symbols;
|
||||
parent = & symbol -> parent;
|
||||
total = subcontext -> total;
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA)
|
||||
ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, 0);
|
||||
#endif
|
||||
if (count > 0)
|
||||
{
|
||||
ENET_RANGE_CODER_ENCODE (subcontext -> escapes + under, count, total);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (subcontext -> escapes > 0 && subcontext -> escapes < total)
|
||||
ENET_RANGE_CODER_ENCODE (0, subcontext -> escapes, total);
|
||||
subcontext -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA;
|
||||
subcontext -> total += ENET_SUBCONTEXT_ESCAPE_DELTA;
|
||||
}
|
||||
subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
|
||||
if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
|
||||
ENET_CONTEXT_RESCALE (subcontext, 0);
|
||||
if (count > 0) goto nextInput;
|
||||
}
|
||||
|
||||
ENET_CONTEXT_ENCODE (root, symbol, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM);
|
||||
* parent = symbol - rangeCoder -> symbols;
|
||||
parent = & symbol -> parent;
|
||||
total = root -> total;
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
if (childContext -> total > ENET_SUBCONTEXT_SYMBOL_DELTA + ENET_SUBCONTEXT_ESCAPE_DELTA)
|
||||
ENET_CONTEXT_ENCODE_EXCLUDE (childContext, value, under, total, ENET_CONTEXT_SYMBOL_MINIMUM);
|
||||
#endif
|
||||
ENET_RANGE_CODER_ENCODE (root -> escapes + under, count, total);
|
||||
root -> total += ENET_CONTEXT_SYMBOL_DELTA;
|
||||
if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
|
||||
ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM);
|
||||
|
||||
nextInput:
|
||||
if (order >= ENET_SUBCONTEXT_ORDER)
|
||||
predicted = rangeCoder -> symbols [predicted].parent;
|
||||
else
|
||||
order ++;
|
||||
ENET_RANGE_CODER_FREE_SYMBOLS;
|
||||
}
|
||||
|
||||
ENET_RANGE_CODER_FLUSH;
|
||||
|
||||
return (size_t) (outData - outStart);
|
||||
}
|
||||
|
||||
#define ENET_RANGE_CODER_SEED \
|
||||
{ \
|
||||
if (inData < inEnd) decodeCode |= * inData ++ << 24; \
|
||||
if (inData < inEnd) decodeCode |= * inData ++ << 16; \
|
||||
if (inData < inEnd) decodeCode |= * inData ++ << 8; \
|
||||
if (inData < inEnd) decodeCode |= * inData ++; \
|
||||
}
|
||||
|
||||
#define ENET_RANGE_CODER_READ(total) ((decodeCode - decodeLow) / (decodeRange /= (total)))
|
||||
|
||||
#define ENET_RANGE_CODER_DECODE(under, count, total) \
|
||||
{ \
|
||||
decodeLow += (under) * decodeRange; \
|
||||
decodeRange *= (count); \
|
||||
for (;;) \
|
||||
{ \
|
||||
if((decodeLow ^ (decodeLow + decodeRange)) >= ENET_RANGE_CODER_TOP) \
|
||||
{ \
|
||||
if(decodeRange >= ENET_RANGE_CODER_BOTTOM) break; \
|
||||
decodeRange = -decodeLow & (ENET_RANGE_CODER_BOTTOM - 1); \
|
||||
} \
|
||||
decodeCode <<= 8; \
|
||||
if (inData < inEnd) \
|
||||
decodeCode |= * inData ++; \
|
||||
decodeRange <<= 8; \
|
||||
decodeLow <<= 8; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ENET_CONTEXT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, createRoot, visitNode, createRight, createLeft) \
|
||||
{ \
|
||||
under_ = 0; \
|
||||
count_ = minimum; \
|
||||
if (! (context) -> symbols) \
|
||||
{ \
|
||||
createRoot; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
ENetSymbol * node = (context) + (context) -> symbols; \
|
||||
for (;;) \
|
||||
{ \
|
||||
enet_uint16 after = under_ + node -> under + (node -> value + 1)*minimum, before = node -> count + minimum; \
|
||||
visitNode; \
|
||||
if (code >= after) \
|
||||
{ \
|
||||
under_ += node -> under; \
|
||||
if (node -> right) { node += node -> right; continue; } \
|
||||
createRight; \
|
||||
} \
|
||||
else \
|
||||
if (code < after - before) \
|
||||
{ \
|
||||
node -> under += update; \
|
||||
if (node -> left) { node += node -> left; continue; } \
|
||||
createLeft; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
value_ = node -> value; \
|
||||
count_ += node -> count; \
|
||||
under_ = after - before; \
|
||||
node -> under += update; \
|
||||
node -> count += update; \
|
||||
symbol_ = node; \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ENET_CONTEXT_TRY_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \
|
||||
ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, return 0, exclude (node -> value, after, before), return 0, return 0)
|
||||
|
||||
#define ENET_CONTEXT_ROOT_DECODE(context, symbol_, code, value_, under_, count_, update, minimum, exclude) \
|
||||
ENET_CONTEXT_DECODE (context, symbol_, code, value_, under_, count_, update, minimum, \
|
||||
{ \
|
||||
value_ = code / minimum; \
|
||||
under_ = code - code%minimum; \
|
||||
ENET_SYMBOL_CREATE (symbol_, value_, update); \
|
||||
(context) -> symbols = symbol_ - (context); \
|
||||
}, \
|
||||
exclude (node -> value, after, before), \
|
||||
{ \
|
||||
value_ = node->value + 1 + (code - after)/minimum; \
|
||||
under_ = code - (code - after)%minimum; \
|
||||
ENET_SYMBOL_CREATE (symbol_, value_, update); \
|
||||
node -> right = symbol_ - node; \
|
||||
}, \
|
||||
{ \
|
||||
value_ = node->value - 1 - (after - before - code - 1)/minimum; \
|
||||
under_ = code - (after - before - code - 1)%minimum; \
|
||||
ENET_SYMBOL_CREATE (symbol_, value_, update); \
|
||||
node -> left = symbol_ - node; \
|
||||
}) \
|
||||
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
typedef struct _ENetExclude
|
||||
{
|
||||
enet_uint8 value;
|
||||
enet_uint16 under;
|
||||
} ENetExclude;
|
||||
|
||||
#define ENET_CONTEXT_DECODE_EXCLUDE(context, total, minimum) \
|
||||
{ \
|
||||
enet_uint16 under = 0; \
|
||||
nextExclude = excludes; \
|
||||
ENET_CONTEXT_WALK (context, { \
|
||||
under += rangeCoder -> symbols [node -> parent].count + minimum; \
|
||||
nextExclude -> value = node -> value; \
|
||||
nextExclude -> under = under; \
|
||||
nextExclude ++; \
|
||||
}); \
|
||||
total -= under; \
|
||||
}
|
||||
|
||||
#define ENET_CONTEXT_EXCLUDED(value_, after, before) \
|
||||
{ \
|
||||
size_t low = 0, high = nextExclude - excludes; \
|
||||
for(;;) \
|
||||
{ \
|
||||
size_t mid = (low + high) >> 1; \
|
||||
const ENetExclude * exclude = & excludes [mid]; \
|
||||
if (value_ < exclude -> value) \
|
||||
{ \
|
||||
if (low + 1 < high) \
|
||||
{ \
|
||||
high = mid; \
|
||||
continue; \
|
||||
} \
|
||||
if (exclude > excludes) \
|
||||
after -= exclude [-1].under; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if (value_ > exclude -> value) \
|
||||
{ \
|
||||
if (low + 1 < high) \
|
||||
{ \
|
||||
low = mid; \
|
||||
continue; \
|
||||
} \
|
||||
} \
|
||||
else \
|
||||
before = 0; \
|
||||
after -= exclude -> under; \
|
||||
} \
|
||||
break; \
|
||||
} \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ENET_CONTEXT_NOT_EXCLUDED(value_, after, before)
|
||||
|
||||
size_t
|
||||
enet_range_coder_decompress (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit)
|
||||
{
|
||||
ENetRangeCoder * rangeCoder = (ENetRangeCoder *) context;
|
||||
enet_uint8 * outStart = outData, * outEnd = & outData [outLimit];
|
||||
const enet_uint8 * inEnd = & inData [inLimit];
|
||||
enet_uint32 decodeLow = 0, decodeCode = 0, decodeRange = ~0;
|
||||
ENetSymbol * root;
|
||||
enet_uint16 predicted = 0;
|
||||
size_t order = 0, nextSymbol = 0;
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
ENetExclude excludes [256];
|
||||
ENetExclude * nextExclude = excludes;
|
||||
#endif
|
||||
|
||||
if (rangeCoder == NULL || inLimit <= 0)
|
||||
return 0;
|
||||
|
||||
ENET_CONTEXT_CREATE (root, ENET_CONTEXT_ESCAPE_MINIMUM, ENET_CONTEXT_SYMBOL_MINIMUM);
|
||||
|
||||
ENET_RANGE_CODER_SEED;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ENetSymbol * subcontext, * symbol, * patch;
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
const ENetSymbol * childContext = & emptyContext;
|
||||
#endif
|
||||
enet_uint8 value = 0;
|
||||
enet_uint16 code, under, count, bottom, * parent = & predicted, total;
|
||||
|
||||
for (subcontext = & rangeCoder -> symbols [predicted];
|
||||
subcontext != root;
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
childContext = subcontext,
|
||||
#endif
|
||||
subcontext = & rangeCoder -> symbols [subcontext -> parent])
|
||||
{
|
||||
if (subcontext -> escapes <= 0)
|
||||
continue;
|
||||
total = subcontext -> total;
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
if (childContext -> total > 0)
|
||||
ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, 0);
|
||||
#endif
|
||||
if (subcontext -> escapes >= total)
|
||||
continue;
|
||||
code = ENET_RANGE_CODER_READ (total);
|
||||
if (code < subcontext -> escapes)
|
||||
{
|
||||
ENET_RANGE_CODER_DECODE (0, subcontext -> escapes, total);
|
||||
continue;
|
||||
}
|
||||
code -= subcontext -> escapes;
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
if (childContext -> total > 0)
|
||||
{
|
||||
ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_EXCLUDED);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ENET_CONTEXT_TRY_DECODE (subcontext, symbol, code, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0, ENET_CONTEXT_NOT_EXCLUDED);
|
||||
}
|
||||
bottom = symbol - rangeCoder -> symbols;
|
||||
ENET_RANGE_CODER_DECODE (subcontext -> escapes + under, count, total);
|
||||
subcontext -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
|
||||
if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || subcontext -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
|
||||
ENET_CONTEXT_RESCALE (subcontext, 0);
|
||||
goto patchContexts;
|
||||
}
|
||||
|
||||
total = root -> total;
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
if (childContext -> total > 0)
|
||||
ENET_CONTEXT_DECODE_EXCLUDE (childContext, total, ENET_CONTEXT_SYMBOL_MINIMUM);
|
||||
#endif
|
||||
code = ENET_RANGE_CODER_READ (total);
|
||||
if (code < root -> escapes)
|
||||
{
|
||||
ENET_RANGE_CODER_DECODE (0, root -> escapes, total);
|
||||
break;
|
||||
}
|
||||
code -= root -> escapes;
|
||||
#ifdef ENET_CONTEXT_EXCLUSION
|
||||
if (childContext -> total > 0)
|
||||
{
|
||||
ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_EXCLUDED);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ENET_CONTEXT_ROOT_DECODE (root, symbol, code, value, under, count, ENET_CONTEXT_SYMBOL_DELTA, ENET_CONTEXT_SYMBOL_MINIMUM, ENET_CONTEXT_NOT_EXCLUDED);
|
||||
}
|
||||
bottom = symbol - rangeCoder -> symbols;
|
||||
ENET_RANGE_CODER_DECODE (root -> escapes + under, count, total);
|
||||
root -> total += ENET_CONTEXT_SYMBOL_DELTA;
|
||||
if (count > 0xFF - 2*ENET_CONTEXT_SYMBOL_DELTA + ENET_CONTEXT_SYMBOL_MINIMUM || root -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
|
||||
ENET_CONTEXT_RESCALE (root, ENET_CONTEXT_SYMBOL_MINIMUM);
|
||||
|
||||
patchContexts:
|
||||
for (patch = & rangeCoder -> symbols [predicted];
|
||||
patch != subcontext;
|
||||
patch = & rangeCoder -> symbols [patch -> parent])
|
||||
{
|
||||
ENET_CONTEXT_ENCODE (patch, symbol, value, under, count, ENET_SUBCONTEXT_SYMBOL_DELTA, 0);
|
||||
* parent = symbol - rangeCoder -> symbols;
|
||||
parent = & symbol -> parent;
|
||||
if (count <= 0)
|
||||
{
|
||||
patch -> escapes += ENET_SUBCONTEXT_ESCAPE_DELTA;
|
||||
patch -> total += ENET_SUBCONTEXT_ESCAPE_DELTA;
|
||||
}
|
||||
patch -> total += ENET_SUBCONTEXT_SYMBOL_DELTA;
|
||||
if (count > 0xFF - 2*ENET_SUBCONTEXT_SYMBOL_DELTA || patch -> total > ENET_RANGE_CODER_BOTTOM - 0x100)
|
||||
ENET_CONTEXT_RESCALE (patch, 0);
|
||||
}
|
||||
* parent = bottom;
|
||||
|
||||
ENET_RANGE_CODER_OUTPUT (value);
|
||||
|
||||
if (order >= ENET_SUBCONTEXT_ORDER)
|
||||
predicted = rangeCoder -> symbols [predicted].parent;
|
||||
else
|
||||
order ++;
|
||||
ENET_RANGE_CODER_FREE_SYMBOLS;
|
||||
}
|
||||
|
||||
return (size_t) (outData - outStart);
|
||||
}
|
||||
|
||||
/** @defgroup host ENet host functions
|
||||
@{
|
||||
*/
|
||||
|
||||
/** Sets the packet compressor the host should use to the default range coder.
|
||||
@param host host to enable the range coder for
|
||||
@returns 0 on success, < 0 on failure
|
||||
*/
|
||||
int
|
||||
enet_host_compress_with_range_coder (ENetHost * host)
|
||||
{
|
||||
ENetCompressor compressor;
|
||||
memset (& compressor, 0, sizeof (compressor));
|
||||
compressor.context = enet_range_coder_create();
|
||||
if (compressor.context == NULL)
|
||||
return -1;
|
||||
compressor.compress = enet_range_coder_compress;
|
||||
compressor.decompress = enet_range_coder_decompress;
|
||||
compressor.destroy = enet_range_coder_destroy;
|
||||
enet_host_compress (host, & compressor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
|
@ -1,29 +0,0 @@
|
||||
#ifndef __ENET_CALLBACKS_H__
|
||||
#define __ENET_CALLBACKS_H__
|
||||
/**
|
||||
@file callbacks.h
|
||||
@brief ENet callbacks
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct _ENetCallbacks
|
||||
{
|
||||
void * (ENET_CALLBACK * malloc) (size_t size);
|
||||
void (ENET_CALLBACK * free) (void * memory);
|
||||
void (ENET_CALLBACK * no_memory) (void);
|
||||
} ENetCallbacks;
|
||||
|
||||
/** @defgroup callbacks ENet internal callbacks
|
||||
@{
|
||||
@ingroup private
|
||||
*/
|
||||
extern void * enet_malloc (size_t);
|
||||
extern void enet_free (void *);
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* __ENET_CALLBACKS_H__ */
|
||||
|
@ -1,632 +0,0 @@
|
||||
#ifndef __ENET_ENET_H__
|
||||
#define __ENET_ENET_H__
|
||||
/**
|
||||
@file enet.h
|
||||
@brief ENet public header file
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// -- Pandemonium start --
|
||||
#if 0
|
||||
#ifdef _WIN32
|
||||
#include "enet/win32.h"
|
||||
#else
|
||||
#include "enet/unix.h"
|
||||
#endif
|
||||
#endif
|
||||
#include "enet/pandemonium.h"
|
||||
// -- Pandemonium end --
|
||||
|
||||
#include "enet/types.h"
|
||||
#include "enet/protocol.h"
|
||||
#include "enet/list.h"
|
||||
#include "enet/callbacks.h"
|
||||
|
||||
#define ENET_VERSION_MAJOR 1
|
||||
#define ENET_VERSION_MINOR 3
|
||||
#define ENET_VERSION_PATCH 17
|
||||
#define ENET_VERSION_CREATE(major, minor, patch) (((major)<<16) | ((minor)<<8) | (patch))
|
||||
#define ENET_VERSION_GET_MAJOR(version) (((version)>>16)&0xFF)
|
||||
#define ENET_VERSION_GET_MINOR(version) (((version)>>8)&0xFF)
|
||||
#define ENET_VERSION_GET_PATCH(version) ((version)&0xFF)
|
||||
#define ENET_VERSION ENET_VERSION_CREATE(ENET_VERSION_MAJOR, ENET_VERSION_MINOR, ENET_VERSION_PATCH)
|
||||
|
||||
typedef enet_uint32 ENetVersion;
|
||||
|
||||
struct _ENetHost;
|
||||
struct _ENetEvent;
|
||||
struct _ENetPacket;
|
||||
|
||||
typedef enum _ENetSocketType
|
||||
{
|
||||
ENET_SOCKET_TYPE_STREAM = 1,
|
||||
ENET_SOCKET_TYPE_DATAGRAM = 2
|
||||
} ENetSocketType;
|
||||
|
||||
typedef enum _ENetSocketWait
|
||||
{
|
||||
ENET_SOCKET_WAIT_NONE = 0,
|
||||
ENET_SOCKET_WAIT_SEND = (1 << 0),
|
||||
ENET_SOCKET_WAIT_RECEIVE = (1 << 1),
|
||||
ENET_SOCKET_WAIT_INTERRUPT = (1 << 2)
|
||||
} ENetSocketWait;
|
||||
|
||||
typedef enum _ENetSocketOption
|
||||
{
|
||||
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_SOCKOPT_TTL = 10
|
||||
} ENetSocketOption;
|
||||
|
||||
typedef enum _ENetSocketShutdown
|
||||
{
|
||||
ENET_SOCKET_SHUTDOWN_READ = 0,
|
||||
ENET_SOCKET_SHUTDOWN_WRITE = 1,
|
||||
ENET_SOCKET_SHUTDOWN_READ_WRITE = 2
|
||||
} ENetSocketShutdown;
|
||||
|
||||
#define ENET_HOST_ANY 0
|
||||
#define ENET_HOST_BROADCAST 0xFFFFFFFFU
|
||||
#define ENET_PORT_ANY 0
|
||||
|
||||
/**
|
||||
* Portable internet address structure.
|
||||
*
|
||||
* The host must be specified in network byte-order, and the port must be in host
|
||||
* byte-order. The constant ENET_HOST_ANY may be used to specify the default
|
||||
* server host. The constant ENET_HOST_BROADCAST may be used to specify the
|
||||
* broadcast address (255.255.255.255). This makes sense for enet_host_connect,
|
||||
* but not for enet_host_create. Once a server responds to a broadcast, the
|
||||
* address is updated from ENET_HOST_BROADCAST to the server's actual IP address.
|
||||
*/
|
||||
// -- Pandemonium start --
|
||||
#if 0
|
||||
typedef struct _ENetAddress
|
||||
{
|
||||
enet_uint32 host;
|
||||
enet_uint16 port;
|
||||
} ENetAddress;
|
||||
#endif
|
||||
// -- Pandemonium end --
|
||||
|
||||
/**
|
||||
* Packet flag bit constants.
|
||||
*
|
||||
* The host must be specified in network byte-order, and the port must be in
|
||||
* host byte-order. The constant ENET_HOST_ANY may be used to specify the
|
||||
* default server host.
|
||||
|
||||
@sa ENetPacket
|
||||
*/
|
||||
typedef enum _ENetPacketFlag
|
||||
{
|
||||
/** packet must be received by the target peer and resend attempts should be
|
||||
* made until the packet is delivered */
|
||||
ENET_PACKET_FLAG_RELIABLE = (1 << 0),
|
||||
/** packet will not be sequenced with other packets
|
||||
* not supported for reliable packets
|
||||
*/
|
||||
ENET_PACKET_FLAG_UNSEQUENCED = (1 << 1),
|
||||
/** packet will not allocate data, and user must supply it instead */
|
||||
ENET_PACKET_FLAG_NO_ALLOCATE = (1 << 2),
|
||||
/** packet will be fragmented using unreliable (instead of reliable) sends
|
||||
* if it exceeds the MTU */
|
||||
ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT = (1 << 3),
|
||||
|
||||
/** whether the packet has been sent from all queues it has been entered into */
|
||||
ENET_PACKET_FLAG_SENT = (1<<8)
|
||||
} ENetPacketFlag;
|
||||
|
||||
typedef void (ENET_CALLBACK * ENetPacketFreeCallback) (struct _ENetPacket *);
|
||||
|
||||
/**
|
||||
* ENet packet structure.
|
||||
*
|
||||
* An ENet data packet that may be sent to or received from a peer. The shown
|
||||
* fields should only be read and never modified. The data field contains the
|
||||
* allocated data for the packet. The dataLength fields specifies the length
|
||||
* of the allocated data. The flags field is either 0 (specifying no flags),
|
||||
* or a bitwise-or of any combination of the following flags:
|
||||
*
|
||||
* ENET_PACKET_FLAG_RELIABLE - packet must be received by the target peer
|
||||
* and resend attempts should be made until the packet is delivered
|
||||
*
|
||||
* ENET_PACKET_FLAG_UNSEQUENCED - packet will not be sequenced with other packets
|
||||
* (not supported for reliable packets)
|
||||
*
|
||||
* ENET_PACKET_FLAG_NO_ALLOCATE - packet will not allocate data, and user must supply it instead
|
||||
*
|
||||
* ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT - packet will be fragmented using unreliable
|
||||
* (instead of reliable) sends if it exceeds the MTU
|
||||
*
|
||||
* ENET_PACKET_FLAG_SENT - whether the packet has been sent from all queues it has been entered into
|
||||
@sa ENetPacketFlag
|
||||
*/
|
||||
typedef struct _ENetPacket
|
||||
{
|
||||
size_t referenceCount; /**< internal use only */
|
||||
enet_uint32 flags; /**< bitwise-or of ENetPacketFlag constants */
|
||||
enet_uint8 * data; /**< allocated data for packet */
|
||||
size_t dataLength; /**< length of data */
|
||||
ENetPacketFreeCallback freeCallback; /**< function to be called when the packet is no longer in use */
|
||||
void * userData; /**< application private data, may be freely modified */
|
||||
} ENetPacket;
|
||||
|
||||
typedef struct _ENetAcknowledgement
|
||||
{
|
||||
ENetListNode acknowledgementList;
|
||||
enet_uint32 sentTime;
|
||||
ENetProtocol command;
|
||||
} ENetAcknowledgement;
|
||||
|
||||
typedef struct _ENetOutgoingCommand
|
||||
{
|
||||
ENetListNode outgoingCommandList;
|
||||
enet_uint16 reliableSequenceNumber;
|
||||
enet_uint16 unreliableSequenceNumber;
|
||||
enet_uint32 sentTime;
|
||||
enet_uint32 roundTripTimeout;
|
||||
enet_uint32 queueTime;
|
||||
enet_uint32 fragmentOffset;
|
||||
enet_uint16 fragmentLength;
|
||||
enet_uint16 sendAttempts;
|
||||
ENetProtocol command;
|
||||
ENetPacket * packet;
|
||||
} ENetOutgoingCommand;
|
||||
|
||||
typedef struct _ENetIncomingCommand
|
||||
{
|
||||
ENetListNode incomingCommandList;
|
||||
enet_uint16 reliableSequenceNumber;
|
||||
enet_uint16 unreliableSequenceNumber;
|
||||
ENetProtocol command;
|
||||
enet_uint32 fragmentCount;
|
||||
enet_uint32 fragmentsRemaining;
|
||||
enet_uint32 * fragments;
|
||||
ENetPacket * packet;
|
||||
} ENetIncomingCommand;
|
||||
|
||||
typedef enum _ENetPeerState
|
||||
{
|
||||
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
|
||||
} ENetPeerState;
|
||||
|
||||
#ifndef ENET_BUFFER_MAXIMUM
|
||||
#define ENET_BUFFER_MAXIMUM (1 + 2 * ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS)
|
||||
#endif
|
||||
|
||||
enum
|
||||
{
|
||||
ENET_HOST_RECEIVE_BUFFER_SIZE = 256 * 1024,
|
||||
ENET_HOST_SEND_BUFFER_SIZE = 256 * 1024,
|
||||
ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL = 1000,
|
||||
ENET_HOST_DEFAULT_MTU = 1392,
|
||||
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 << 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 = 0x1000,
|
||||
ENET_PEER_FREE_RELIABLE_WINDOWS = 8
|
||||
};
|
||||
|
||||
typedef struct _ENetChannel
|
||||
{
|
||||
enet_uint16 outgoingReliableSequenceNumber;
|
||||
enet_uint16 outgoingUnreliableSequenceNumber;
|
||||
enet_uint16 usedReliableWindows;
|
||||
enet_uint16 reliableWindows [ENET_PEER_RELIABLE_WINDOWS];
|
||||
enet_uint16 incomingReliableSequenceNumber;
|
||||
enet_uint16 incomingUnreliableSequenceNumber;
|
||||
ENetList incomingReliableCommands;
|
||||
ENetList incomingUnreliableCommands;
|
||||
} ENetChannel;
|
||||
|
||||
typedef enum _ENetPeerFlag
|
||||
{
|
||||
ENET_PEER_FLAG_NEEDS_DISPATCH = (1 << 0),
|
||||
ENET_PEER_FLAG_CONTINUE_SENDING = (1 << 1)
|
||||
} ENetPeerFlag;
|
||||
|
||||
/**
|
||||
* An ENet peer which data packets may be sent or received from.
|
||||
*
|
||||
* No fields should be modified unless otherwise specified.
|
||||
*/
|
||||
typedef struct _ENetPeer
|
||||
{
|
||||
ENetListNode dispatchList;
|
||||
struct _ENetHost * host;
|
||||
enet_uint16 outgoingPeerID;
|
||||
enet_uint16 incomingPeerID;
|
||||
enet_uint32 connectID;
|
||||
enet_uint8 outgoingSessionID;
|
||||
enet_uint8 incomingSessionID;
|
||||
ENetAddress address; /**< Internet address of the peer */
|
||||
void * data; /**< Application private data, may be freely modified */
|
||||
ENetPeerState state;
|
||||
ENetChannel * channels;
|
||||
size_t channelCount; /**< Number of channels allocated for communication with peer */
|
||||
enet_uint32 incomingBandwidth; /**< Downstream bandwidth of the client in bytes/second */
|
||||
enet_uint32 outgoingBandwidth; /**< Upstream bandwidth of the client in bytes/second */
|
||||
enet_uint32 incomingBandwidthThrottleEpoch;
|
||||
enet_uint32 outgoingBandwidthThrottleEpoch;
|
||||
enet_uint32 incomingDataTotal;
|
||||
enet_uint32 outgoingDataTotal;
|
||||
enet_uint32 lastSendTime;
|
||||
enet_uint32 lastReceiveTime;
|
||||
enet_uint32 nextTimeout;
|
||||
enet_uint32 earliestTimeout;
|
||||
enet_uint32 packetLossEpoch;
|
||||
enet_uint32 packetsSent;
|
||||
enet_uint32 packetsLost;
|
||||
enet_uint32 packetLoss; /**< mean packet loss of reliable packets as a ratio with respect to the constant ENET_PEER_PACKET_LOSS_SCALE */
|
||||
enet_uint32 packetLossVariance;
|
||||
enet_uint32 packetThrottle;
|
||||
enet_uint32 packetThrottleLimit;
|
||||
enet_uint32 packetThrottleCounter;
|
||||
enet_uint32 packetThrottleEpoch;
|
||||
enet_uint32 packetThrottleAcceleration;
|
||||
enet_uint32 packetThrottleDeceleration;
|
||||
enet_uint32 packetThrottleInterval;
|
||||
enet_uint32 pingInterval;
|
||||
enet_uint32 timeoutLimit;
|
||||
enet_uint32 timeoutMinimum;
|
||||
enet_uint32 timeoutMaximum;
|
||||
enet_uint32 lastRoundTripTime;
|
||||
enet_uint32 lowestRoundTripTime;
|
||||
enet_uint32 lastRoundTripTimeVariance;
|
||||
enet_uint32 highestRoundTripTimeVariance;
|
||||
enet_uint32 roundTripTime; /**< mean round trip time (RTT), in milliseconds, between sending a reliable packet and receiving its acknowledgement */
|
||||
enet_uint32 roundTripTimeVariance;
|
||||
enet_uint32 mtu;
|
||||
enet_uint32 windowSize;
|
||||
enet_uint32 reliableDataInTransit;
|
||||
enet_uint16 outgoingReliableSequenceNumber;
|
||||
ENetList acknowledgements;
|
||||
ENetList sentReliableCommands;
|
||||
ENetList outgoingSendReliableCommands;
|
||||
ENetList outgoingCommands;
|
||||
ENetList dispatchedCommands;
|
||||
enet_uint16 flags;
|
||||
enet_uint16 reserved;
|
||||
enet_uint16 incomingUnsequencedGroup;
|
||||
enet_uint16 outgoingUnsequencedGroup;
|
||||
enet_uint32 unsequencedWindow [ENET_PEER_UNSEQUENCED_WINDOW_SIZE / 32];
|
||||
enet_uint32 eventData;
|
||||
size_t totalWaitingData;
|
||||
} ENetPeer;
|
||||
|
||||
/** An ENet packet compressor for compressing UDP packets before socket sends or receives.
|
||||
*/
|
||||
typedef struct _ENetCompressor
|
||||
{
|
||||
/** Context data for the compressor. Must be non-NULL. */
|
||||
void * context;
|
||||
/** Compresses from inBuffers[0:inBufferCount-1], containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */
|
||||
size_t (ENET_CALLBACK * compress) (void * context, const ENetBuffer * inBuffers, size_t inBufferCount, size_t inLimit, enet_uint8 * outData, size_t outLimit);
|
||||
/** Decompresses from inData, containing inLimit bytes, to outData, outputting at most outLimit bytes. Should return 0 on failure. */
|
||||
size_t (ENET_CALLBACK * decompress) (void * context, const enet_uint8 * inData, size_t inLimit, enet_uint8 * outData, size_t outLimit);
|
||||
/** Destroys the context when compression is disabled or the host is destroyed. May be NULL. */
|
||||
void (ENET_CALLBACK * destroy) (void * context);
|
||||
} ENetCompressor;
|
||||
|
||||
/** Callback that computes the checksum of the data held in buffers[0:bufferCount-1] */
|
||||
typedef enet_uint32 (ENET_CALLBACK * ENetChecksumCallback) (const ENetBuffer * buffers, size_t bufferCount);
|
||||
|
||||
/** Callback for intercepting received raw UDP packets. Should return 1 to intercept, 0 to ignore, or -1 to propagate an error. */
|
||||
typedef int (ENET_CALLBACK * ENetInterceptCallback) (struct _ENetHost * host, struct _ENetEvent * event);
|
||||
|
||||
/** An ENet host for communicating with peers.
|
||||
*
|
||||
* No fields should be modified unless otherwise stated.
|
||||
|
||||
@sa enet_host_create()
|
||||
@sa enet_host_destroy()
|
||||
@sa enet_host_connect()
|
||||
@sa enet_host_service()
|
||||
@sa enet_host_flush()
|
||||
@sa enet_host_broadcast()
|
||||
@sa enet_host_compress()
|
||||
@sa enet_host_compress_with_range_coder()
|
||||
@sa enet_host_channel_limit()
|
||||
@sa enet_host_bandwidth_limit()
|
||||
@sa enet_host_bandwidth_throttle()
|
||||
*/
|
||||
typedef struct _ENetHost
|
||||
{
|
||||
ENetSocket socket;
|
||||
ENetAddress address; /**< Internet address of the host */
|
||||
enet_uint32 incomingBandwidth; /**< downstream bandwidth of the host */
|
||||
enet_uint32 outgoingBandwidth; /**< upstream bandwidth of the host */
|
||||
enet_uint32 bandwidthThrottleEpoch;
|
||||
enet_uint32 mtu;
|
||||
enet_uint32 randomSeed;
|
||||
int recalculateBandwidthLimits;
|
||||
ENetPeer * peers; /**< array of peers allocated for this host */
|
||||
size_t peerCount; /**< number of peers allocated for this host */
|
||||
size_t channelLimit; /**< maximum number of channels allowed for connected peers */
|
||||
enet_uint32 serviceTime;
|
||||
ENetList dispatchQueue;
|
||||
enet_uint32 totalQueued;
|
||||
size_t packetSize;
|
||||
enet_uint16 headerFlags;
|
||||
ENetProtocol commands [ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS];
|
||||
size_t commandCount;
|
||||
ENetBuffer buffers [ENET_BUFFER_MAXIMUM];
|
||||
size_t bufferCount;
|
||||
ENetChecksumCallback checksum; /**< callback the user can set to enable packet checksums for this host */
|
||||
ENetCompressor compressor;
|
||||
enet_uint8 packetData [2][ENET_PROTOCOL_MAXIMUM_MTU];
|
||||
ENetAddress receivedAddress;
|
||||
enet_uint8 * receivedData;
|
||||
size_t receivedDataLength;
|
||||
enet_uint32 totalSentData; /**< total data sent, user should reset to 0 as needed to prevent overflow */
|
||||
enet_uint32 totalSentPackets; /**< total UDP packets sent, user should reset to 0 as needed to prevent overflow */
|
||||
enet_uint32 totalReceivedData; /**< total data received, user should reset to 0 as needed to prevent overflow */
|
||||
enet_uint32 totalReceivedPackets; /**< total UDP packets received, user should reset to 0 as needed to prevent overflow */
|
||||
ENetInterceptCallback intercept; /**< callback the user can set to intercept received raw UDP packets */
|
||||
size_t connectedPeers;
|
||||
size_t bandwidthLimitedPeers;
|
||||
size_t duplicatePeers; /**< optional number of allowed peers from duplicate IPs, defaults to ENET_PROTOCOL_MAXIMUM_PEER_ID */
|
||||
size_t maximumPacketSize; /**< the maximum allowable packet size that may be sent or received on a peer */
|
||||
size_t maximumWaitingData; /**< the maximum aggregate amount of buffer space a peer may use waiting for packets to be delivered */
|
||||
} ENetHost;
|
||||
|
||||
/**
|
||||
* An ENet event type, as specified in @ref ENetEvent.
|
||||
*/
|
||||
typedef enum _ENetEventType
|
||||
{
|
||||
/** no event occurred within the specified time limit */
|
||||
ENET_EVENT_TYPE_NONE = 0,
|
||||
|
||||
/** a connection request initiated by enet_host_connect has completed.
|
||||
* The peer field contains the peer which successfully connected.
|
||||
*/
|
||||
ENET_EVENT_TYPE_CONNECT = 1,
|
||||
|
||||
/** a peer has disconnected. This event is generated on a successful
|
||||
* completion of a disconnect initiated by enet_peer_disconnect, if
|
||||
* a peer has timed out, or if a connection request intialized by
|
||||
* enet_host_connect has timed out. The peer field contains the peer
|
||||
* which disconnected. The data field contains user supplied data
|
||||
* describing the disconnection, or 0, if none is available.
|
||||
*/
|
||||
ENET_EVENT_TYPE_DISCONNECT = 2,
|
||||
|
||||
/** a packet has been received from a peer. The peer field specifies the
|
||||
* peer which sent the packet. The channelID field specifies the channel
|
||||
* number upon which the packet was received. The packet field contains
|
||||
* the packet that was received; this packet must be destroyed with
|
||||
* enet_packet_destroy after use.
|
||||
*/
|
||||
ENET_EVENT_TYPE_RECEIVE = 3
|
||||
} ENetEventType;
|
||||
|
||||
/**
|
||||
* An ENet event as returned by enet_host_service().
|
||||
|
||||
@sa enet_host_service
|
||||
*/
|
||||
typedef struct _ENetEvent
|
||||
{
|
||||
ENetEventType type; /**< type of the event */
|
||||
ENetPeer * peer; /**< peer that generated a connect, disconnect or receive event */
|
||||
enet_uint8 channelID; /**< channel on the peer that generated the event, if appropriate */
|
||||
enet_uint32 data; /**< data associated with the event, if appropriate */
|
||||
ENetPacket * packet; /**< packet associated with the event, if appropriate */
|
||||
} ENetEvent;
|
||||
|
||||
/** @defgroup global ENet global functions
|
||||
@{
|
||||
*/
|
||||
|
||||
/**
|
||||
Initializes ENet globally. Must be called prior to using any functions in
|
||||
ENet.
|
||||
@returns 0 on success, < 0 on failure
|
||||
*/
|
||||
ENET_API int enet_initialize (void);
|
||||
|
||||
/**
|
||||
Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in ENet. Do not use enet_initialize() if you use this variant. Make sure the ENetCallbacks structure is zeroed out so that any additional callbacks added in future versions will be properly ignored.
|
||||
|
||||
@param version the constant ENET_VERSION should be supplied so ENet knows which version of ENetCallbacks struct to use
|
||||
@param inits user-overridden callbacks where any NULL callbacks will use ENet's defaults
|
||||
@returns 0 on success, < 0 on failure
|
||||
*/
|
||||
ENET_API int enet_initialize_with_callbacks (ENetVersion version, const ENetCallbacks * inits);
|
||||
|
||||
/**
|
||||
Shuts down ENet globally. Should be called when a program that has
|
||||
initialized ENet exits.
|
||||
*/
|
||||
ENET_API void enet_deinitialize (void);
|
||||
|
||||
/**
|
||||
Gives the linked version of the ENet library.
|
||||
@returns the version number
|
||||
*/
|
||||
ENET_API ENetVersion enet_linked_version (void);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @defgroup private ENet private implementation functions */
|
||||
|
||||
/**
|
||||
Returns the wall-time in milliseconds. Its initial value is unspecified
|
||||
unless otherwise set.
|
||||
*/
|
||||
ENET_API enet_uint32 enet_time_get (void);
|
||||
/**
|
||||
Sets the current wall-time in milliseconds.
|
||||
*/
|
||||
ENET_API void enet_time_set (enet_uint32);
|
||||
|
||||
/** @defgroup socket ENet socket functions
|
||||
@{
|
||||
*/
|
||||
ENET_API ENetSocket enet_socket_create (ENetSocketType);
|
||||
ENET_API int enet_socket_bind (ENetSocket, const ENetAddress *);
|
||||
ENET_API int enet_socket_get_address (ENetSocket, ENetAddress *);
|
||||
ENET_API int enet_socket_listen (ENetSocket, int);
|
||||
ENET_API ENetSocket enet_socket_accept (ENetSocket, ENetAddress *);
|
||||
ENET_API int enet_socket_connect (ENetSocket, const ENetAddress *);
|
||||
ENET_API int enet_socket_send (ENetSocket, const ENetAddress *, const ENetBuffer *, size_t);
|
||||
ENET_API int enet_socket_receive (ENetSocket, ENetAddress *, ENetBuffer *, size_t);
|
||||
ENET_API int enet_socket_wait (ENetSocket, enet_uint32 *, enet_uint32);
|
||||
ENET_API int enet_socket_set_option (ENetSocket, ENetSocketOption, int);
|
||||
ENET_API int enet_socket_get_option (ENetSocket, ENetSocketOption, int *);
|
||||
ENET_API int enet_socket_shutdown (ENetSocket, ENetSocketShutdown);
|
||||
ENET_API void enet_socket_destroy (ENetSocket);
|
||||
ENET_API int enet_socketset_select (ENetSocket, ENetSocketSet *, ENetSocketSet *, enet_uint32);
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @defgroup Address ENet address functions
|
||||
@{
|
||||
*/
|
||||
|
||||
/** Attempts to parse the printable form of the IP address in the parameter hostName
|
||||
and sets the host field in the address parameter if successful.
|
||||
@param address destination to store the parsed IP address
|
||||
@param hostName IP address to parse
|
||||
@retval 0 on success
|
||||
@retval < 0 on failure
|
||||
@returns the address of the given hostName in address on success
|
||||
*/
|
||||
ENET_API int enet_address_set_host_ip (ENetAddress * address, const char * hostName);
|
||||
|
||||
/** Attempts to resolve the host named by the parameter hostName and sets
|
||||
the host field in the address parameter if successful.
|
||||
@param address destination to store resolved address
|
||||
@param hostName host name to lookup
|
||||
@retval 0 on success
|
||||
@retval < 0 on failure
|
||||
@returns the address of the given hostName in address on success
|
||||
*/
|
||||
ENET_API int enet_address_set_host (ENetAddress * address, const char * hostName);
|
||||
|
||||
/** Gives the printable form of the IP address specified in the address parameter.
|
||||
@param address address printed
|
||||
@param hostName destination for name, must not be NULL
|
||||
@param nameLength maximum length of hostName.
|
||||
@returns the null-terminated name of the host in hostName on success
|
||||
@retval 0 on success
|
||||
@retval < 0 on failure
|
||||
*/
|
||||
ENET_API int enet_address_get_host_ip (const ENetAddress * address, char * hostName, size_t nameLength);
|
||||
|
||||
/** Attempts to do a reverse lookup of the host field in the address parameter.
|
||||
@param address address used for reverse lookup
|
||||
@param hostName destination for name, must not be NULL
|
||||
@param nameLength maximum length of hostName.
|
||||
@returns the null-terminated name of the host in hostName on success
|
||||
@retval 0 on success
|
||||
@retval < 0 on failure
|
||||
*/
|
||||
ENET_API int enet_address_get_host (const ENetAddress * address, char * hostName, size_t nameLength);
|
||||
|
||||
/** @} */
|
||||
|
||||
ENET_API ENetPacket * enet_packet_create (const void *, size_t, enet_uint32);
|
||||
ENET_API void enet_packet_destroy (ENetPacket *);
|
||||
ENET_API int enet_packet_resize (ENetPacket *, size_t);
|
||||
ENET_API enet_uint32 enet_crc32 (const ENetBuffer *, size_t);
|
||||
|
||||
ENET_API ENetHost * enet_host_create (const ENetAddress *, size_t, size_t, enet_uint32, enet_uint32);
|
||||
ENET_API void enet_host_destroy (ENetHost *);
|
||||
ENET_API ENetPeer * enet_host_connect (ENetHost *, const ENetAddress *, size_t, enet_uint32);
|
||||
ENET_API int enet_host_check_events (ENetHost *, ENetEvent *);
|
||||
ENET_API int enet_host_service (ENetHost *, ENetEvent *, enet_uint32);
|
||||
ENET_API void enet_host_flush (ENetHost *);
|
||||
ENET_API void enet_host_broadcast (ENetHost *, enet_uint8, ENetPacket *);
|
||||
ENET_API void enet_host_compress (ENetHost *, const ENetCompressor *);
|
||||
ENET_API int enet_host_compress_with_range_coder (ENetHost * host);
|
||||
ENET_API void enet_host_channel_limit (ENetHost *, size_t);
|
||||
ENET_API void enet_host_bandwidth_limit (ENetHost *, enet_uint32, enet_uint32);
|
||||
extern void enet_host_bandwidth_throttle (ENetHost *);
|
||||
extern enet_uint32 enet_host_random_seed (void);
|
||||
extern enet_uint32 enet_host_random (ENetHost *);
|
||||
|
||||
ENET_API int enet_peer_send (ENetPeer *, enet_uint8, ENetPacket *);
|
||||
ENET_API ENetPacket * enet_peer_receive (ENetPeer *, enet_uint8 * channelID);
|
||||
ENET_API void enet_peer_ping (ENetPeer *);
|
||||
ENET_API void enet_peer_ping_interval (ENetPeer *, enet_uint32);
|
||||
ENET_API void enet_peer_timeout (ENetPeer *, enet_uint32, enet_uint32, enet_uint32);
|
||||
ENET_API void enet_peer_reset (ENetPeer *);
|
||||
ENET_API void enet_peer_disconnect (ENetPeer *, enet_uint32);
|
||||
ENET_API void enet_peer_disconnect_now (ENetPeer *, enet_uint32);
|
||||
ENET_API void enet_peer_disconnect_later (ENetPeer *, enet_uint32);
|
||||
ENET_API void enet_peer_throttle_configure (ENetPeer *, enet_uint32, enet_uint32, enet_uint32);
|
||||
extern int enet_peer_throttle (ENetPeer *, enet_uint32);
|
||||
extern void enet_peer_reset_queues (ENetPeer *);
|
||||
extern int enet_peer_has_outgoing_commands (ENetPeer *);
|
||||
extern void enet_peer_setup_outgoing_command (ENetPeer *, ENetOutgoingCommand *);
|
||||
extern ENetOutgoingCommand * enet_peer_queue_outgoing_command (ENetPeer *, const ENetProtocol *, ENetPacket *, enet_uint32, enet_uint16);
|
||||
extern ENetIncomingCommand * enet_peer_queue_incoming_command (ENetPeer *, const ENetProtocol *, const void *, size_t, enet_uint32, enet_uint32);
|
||||
extern ENetAcknowledgement * enet_peer_queue_acknowledgement (ENetPeer *, const ENetProtocol *, enet_uint16);
|
||||
extern void enet_peer_dispatch_incoming_unreliable_commands (ENetPeer *, ENetChannel *, ENetIncomingCommand *);
|
||||
extern void enet_peer_dispatch_incoming_reliable_commands (ENetPeer *, ENetChannel *, ENetIncomingCommand *);
|
||||
extern void enet_peer_on_connect (ENetPeer *);
|
||||
extern void enet_peer_on_disconnect (ENetPeer *);
|
||||
|
||||
ENET_API void * enet_range_coder_create (void);
|
||||
ENET_API void enet_range_coder_destroy (void *);
|
||||
ENET_API size_t enet_range_coder_compress (void *, const ENetBuffer *, size_t, size_t, enet_uint8 *, size_t);
|
||||
ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t, enet_uint8 *, size_t);
|
||||
|
||||
extern size_t enet_protocol_command_size (enet_uint8);
|
||||
|
||||
// -- Pandemonium start --
|
||||
#include "enet/pandemonium_ext.h"
|
||||
// -- Pandemonium end --
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __ENET_ENET_H__ */
|
||||
|
@ -1,45 +0,0 @@
|
||||
#ifndef __ENET_LIST_H__
|
||||
#define __ENET_LIST_H__
|
||||
/**
|
||||
@file list.h
|
||||
@brief ENet list management
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct _ENetListNode
|
||||
{
|
||||
struct _ENetListNode * next;
|
||||
struct _ENetListNode * previous;
|
||||
} ENetListNode;
|
||||
|
||||
typedef ENetListNode * ENetListIterator;
|
||||
|
||||
typedef struct _ENetList
|
||||
{
|
||||
ENetListNode sentinel;
|
||||
} ENetList;
|
||||
|
||||
extern void enet_list_clear (ENetList *);
|
||||
|
||||
extern ENetListIterator enet_list_insert (ENetListIterator, void *);
|
||||
extern void * enet_list_remove (ENetListIterator);
|
||||
extern ENetListIterator enet_list_move (ENetListIterator, void *, void *);
|
||||
|
||||
extern size_t enet_list_size (ENetList *);
|
||||
|
||||
#define enet_list_begin(list) ((list) -> sentinel.next)
|
||||
#define enet_list_end(list) (& (list) -> sentinel)
|
||||
|
||||
#define enet_list_empty(list) (enet_list_begin (list) == enet_list_end (list))
|
||||
|
||||
#define enet_list_next(iterator) ((iterator) -> next)
|
||||
#define enet_list_previous(iterator) ((iterator) -> previous)
|
||||
|
||||
#define enet_list_front(list) ((void *) (list) -> sentinel.next)
|
||||
#define enet_list_back(list) ((void *) (list) -> sentinel.previous)
|
||||
|
||||
#endif /* __ENET_LIST_H__ */
|
||||
|
@ -1,82 +0,0 @@
|
||||
#ifndef __ENET_PANDEMONIUM_H__
|
||||
#define __ENET_PANDEMONIUM_H__
|
||||
|
||||
/* pandemonium.h */
|
||||
|
||||
/* This file is part of: */
|
||||
/* PANDEMONIUM ENGINE */
|
||||
/* https://godotengine.org */
|
||||
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
/**
|
||||
@file pandemonium.h
|
||||
@brief ENet Pandemonium header
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
#include <stdint.h>
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
#ifdef UNIX_ENABLED
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef MSG_MAXIOVLEN
|
||||
#define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN
|
||||
#endif
|
||||
|
||||
typedef void *ENetSocket;
|
||||
|
||||
#define ENET_SOCKET_NULL NULL
|
||||
|
||||
#define ENET_HOST_TO_NET_16(value) (htons(value)) /**< macro that converts host to net byte-order of a 16-bit value */
|
||||
#define ENET_HOST_TO_NET_32(value) (htonl(value)) /**< macro that converts host to net byte-order of a 32-bit value */
|
||||
|
||||
#define ENET_NET_TO_HOST_16(value) (ntohs(value)) /**< macro that converts net to host byte-order of a 16-bit value */
|
||||
#define ENET_NET_TO_HOST_32(value) (ntohl(value)) /**< macro that converts net to host byte-order of a 32-bit value */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *data;
|
||||
size_t dataLength;
|
||||
} ENetBuffer;
|
||||
|
||||
#define ENET_CALLBACK
|
||||
|
||||
#define ENET_API extern
|
||||
|
||||
typedef void ENetSocketSet;
|
||||
|
||||
typedef struct _ENetAddress
|
||||
{
|
||||
uint8_t host[16];
|
||||
uint16_t port;
|
||||
uint8_t wildcard;
|
||||
} ENetAddress;
|
||||
#define enet_host_equal(host_a, host_b) (memcmp(&host_a, &host_b,16) == 0)
|
||||
|
||||
#endif /* __ENET_PANDEMONIUM_H__ */
|
@ -1,18 +0,0 @@
|
||||
#ifndef __ENET_PANDEMONIUM_EXT_H__
|
||||
#define __ENET_PANDEMONIUM_EXT_H__
|
||||
|
||||
/** Sets the host field in the address parameter from ip struct.
|
||||
@param address destination to store resolved address
|
||||
@param ip the ip struct to read from
|
||||
@param size the size of the ip struct.
|
||||
@retval 0 on success
|
||||
@retval != 0 on failure
|
||||
@returns the address of the given ip in address on success.
|
||||
*/
|
||||
ENET_API void enet_address_set_ip(ENetAddress * address, const uint8_t * ip, size_t size);
|
||||
|
||||
ENET_API void enet_host_dtls_server_setup (ENetHost *, void *, void *);
|
||||
ENET_API void enet_host_dtls_client_setup (ENetHost *, void *, uint8_t, const char *);
|
||||
ENET_API void enet_host_refuse_new_connections (ENetHost *, int);
|
||||
|
||||
#endif // __ENET_PANDEMONIUM_EXT_H__
|
@ -1,200 +0,0 @@
|
||||
#ifndef __ENET_PROTOCOL_H__
|
||||
#define __ENET_PROTOCOL_H__
|
||||
/**
|
||||
@file protocol.h
|
||||
@brief ENet protocol
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "enet/types.h"
|
||||
|
||||
enum
|
||||
{
|
||||
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 = 0xFFF,
|
||||
ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024
|
||||
};
|
||||
|
||||
typedef enum _ENetProtocolCommand
|
||||
{
|
||||
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 = 0x0F
|
||||
} ENetProtocolCommand;
|
||||
|
||||
typedef enum _ENetProtocolFlag
|
||||
{
|
||||
ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7),
|
||||
ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6),
|
||||
|
||||
ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14),
|
||||
ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15),
|
||||
ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME,
|
||||
|
||||
ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12),
|
||||
ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12
|
||||
} ENetProtocolFlag;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#define ENET_PACKED
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#define ENET_PACKED __attribute__ ((packed))
|
||||
#else
|
||||
#define ENET_PACKED
|
||||
#endif
|
||||
|
||||
typedef struct _ENetProtocolHeader
|
||||
{
|
||||
enet_uint16 peerID;
|
||||
enet_uint16 sentTime;
|
||||
} ENET_PACKED ENetProtocolHeader;
|
||||
|
||||
typedef struct _ENetProtocolCommandHeader
|
||||
{
|
||||
enet_uint8 command;
|
||||
enet_uint8 channelID;
|
||||
enet_uint16 reliableSequenceNumber;
|
||||
} ENET_PACKED ENetProtocolCommandHeader;
|
||||
|
||||
typedef struct _ENetProtocolAcknowledge
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
enet_uint16 receivedReliableSequenceNumber;
|
||||
enet_uint16 receivedSentTime;
|
||||
} ENET_PACKED ENetProtocolAcknowledge;
|
||||
|
||||
typedef struct _ENetProtocolConnect
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
enet_uint16 outgoingPeerID;
|
||||
enet_uint8 incomingSessionID;
|
||||
enet_uint8 outgoingSessionID;
|
||||
enet_uint32 mtu;
|
||||
enet_uint32 windowSize;
|
||||
enet_uint32 channelCount;
|
||||
enet_uint32 incomingBandwidth;
|
||||
enet_uint32 outgoingBandwidth;
|
||||
enet_uint32 packetThrottleInterval;
|
||||
enet_uint32 packetThrottleAcceleration;
|
||||
enet_uint32 packetThrottleDeceleration;
|
||||
enet_uint32 connectID;
|
||||
enet_uint32 data;
|
||||
} ENET_PACKED ENetProtocolConnect;
|
||||
|
||||
typedef struct _ENetProtocolVerifyConnect
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
enet_uint16 outgoingPeerID;
|
||||
enet_uint8 incomingSessionID;
|
||||
enet_uint8 outgoingSessionID;
|
||||
enet_uint32 mtu;
|
||||
enet_uint32 windowSize;
|
||||
enet_uint32 channelCount;
|
||||
enet_uint32 incomingBandwidth;
|
||||
enet_uint32 outgoingBandwidth;
|
||||
enet_uint32 packetThrottleInterval;
|
||||
enet_uint32 packetThrottleAcceleration;
|
||||
enet_uint32 packetThrottleDeceleration;
|
||||
enet_uint32 connectID;
|
||||
} ENET_PACKED ENetProtocolVerifyConnect;
|
||||
|
||||
typedef struct _ENetProtocolBandwidthLimit
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
enet_uint32 incomingBandwidth;
|
||||
enet_uint32 outgoingBandwidth;
|
||||
} ENET_PACKED ENetProtocolBandwidthLimit;
|
||||
|
||||
typedef struct _ENetProtocolThrottleConfigure
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
enet_uint32 packetThrottleInterval;
|
||||
enet_uint32 packetThrottleAcceleration;
|
||||
enet_uint32 packetThrottleDeceleration;
|
||||
} ENET_PACKED ENetProtocolThrottleConfigure;
|
||||
|
||||
typedef struct _ENetProtocolDisconnect
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
enet_uint32 data;
|
||||
} ENET_PACKED ENetProtocolDisconnect;
|
||||
|
||||
typedef struct _ENetProtocolPing
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
} ENET_PACKED ENetProtocolPing;
|
||||
|
||||
typedef struct _ENetProtocolSendReliable
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
enet_uint16 dataLength;
|
||||
} ENET_PACKED ENetProtocolSendReliable;
|
||||
|
||||
typedef struct _ENetProtocolSendUnreliable
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
enet_uint16 unreliableSequenceNumber;
|
||||
enet_uint16 dataLength;
|
||||
} ENET_PACKED ENetProtocolSendUnreliable;
|
||||
|
||||
typedef struct _ENetProtocolSendUnsequenced
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
enet_uint16 unsequencedGroup;
|
||||
enet_uint16 dataLength;
|
||||
} ENET_PACKED ENetProtocolSendUnsequenced;
|
||||
|
||||
typedef struct _ENetProtocolSendFragment
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
enet_uint16 startSequenceNumber;
|
||||
enet_uint16 dataLength;
|
||||
enet_uint32 fragmentCount;
|
||||
enet_uint32 fragmentNumber;
|
||||
enet_uint32 totalLength;
|
||||
enet_uint32 fragmentOffset;
|
||||
} ENET_PACKED ENetProtocolSendFragment;
|
||||
|
||||
typedef union _ENetProtocol
|
||||
{
|
||||
ENetProtocolCommandHeader header;
|
||||
ENetProtocolAcknowledge acknowledge;
|
||||
ENetProtocolConnect connect;
|
||||
ENetProtocolVerifyConnect verifyConnect;
|
||||
ENetProtocolDisconnect disconnect;
|
||||
ENetProtocolPing ping;
|
||||
ENetProtocolSendReliable sendReliable;
|
||||
ENetProtocolSendUnreliable sendUnreliable;
|
||||
ENetProtocolSendUnsequenced sendUnsequenced;
|
||||
ENetProtocolSendFragment sendFragment;
|
||||
ENetProtocolBandwidthLimit bandwidthLimit;
|
||||
ENetProtocolThrottleConfigure throttleConfigure;
|
||||
} ENET_PACKED ENetProtocol;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
#endif /* __ENET_PROTOCOL_H__ */
|
||||
|
@ -1,20 +0,0 @@
|
||||
#ifndef __ENET_TIME_H__
|
||||
#define __ENET_TIME_H__
|
||||
/**
|
||||
@file time.h
|
||||
@brief ENet time constants and macros
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define ENET_TIME_OVERFLOW 86400000
|
||||
|
||||
#define ENET_TIME_LESS(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW)
|
||||
#define ENET_TIME_GREATER(a, b) ((b) - (a) >= ENET_TIME_OVERFLOW)
|
||||
#define ENET_TIME_LESS_EQUAL(a, b) (! ENET_TIME_GREATER (a, b))
|
||||
#define ENET_TIME_GREATER_EQUAL(a, b) (! ENET_TIME_LESS (a, b))
|
||||
|
||||
#define ENET_TIME_DIFFERENCE(a, b) ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b))
|
||||
|
||||
#endif /* __ENET_TIME_H__ */
|
||||
|
@ -1,15 +0,0 @@
|
||||
#ifndef __ENET_TYPES_H__
|
||||
#define __ENET_TYPES_H__
|
||||
/**
|
||||
@file types.h
|
||||
@brief type definitions for ENet
|
||||
*/
|
||||
|
||||
|
||||
|
||||
typedef unsigned char enet_uint8; /**< unsigned 8-bit type */
|
||||
typedef unsigned short enet_uint16; /**< unsigned 16-bit type */
|
||||
typedef unsigned int enet_uint32; /**< unsigned 32-bit type */
|
||||
|
||||
#endif /* __ENET_TYPES_H__ */
|
||||
|
@ -1,15 +0,0 @@
|
||||
#ifndef __ENET_UTILITY_H__
|
||||
#define __ENET_UTILITY_H__
|
||||
/**
|
||||
@file utility.h
|
||||
@brief ENet utility header
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#define ENET_DIFFERENCE(x, y) ((x) < (y) ? (y) - (x) : (x) - (y))
|
||||
|
||||
#endif /* __ENET_UTILITY_H__ */
|
||||
|
@ -1,503 +0,0 @@
|
||||
/**
|
||||
@file host.c
|
||||
@brief ENet host management functions
|
||||
*/
|
||||
#define ENET_BUILDING_LIB 1
|
||||
#include <string.h>
|
||||
#include "enet/enet.h"
|
||||
|
||||
/** @defgroup host ENet host functions
|
||||
@{
|
||||
*/
|
||||
|
||||
/** Creates a host for communicating to peers.
|
||||
|
||||
@param address the address at which other peers may connect to this host. If NULL, then no peers may connect to the host.
|
||||
@param peerCount the maximum number of peers that should be allocated for the host.
|
||||
@param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
|
||||
@param incomingBandwidth downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
|
||||
@param outgoingBandwidth upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited bandwidth.
|
||||
|
||||
@returns the host on success and NULL on failure
|
||||
|
||||
@remarks ENet will strategically drop packets on specific sides of a connection between hosts
|
||||
to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine
|
||||
the window size of a connection which limits the amount of reliable packets that may be in transit
|
||||
at any given time.
|
||||
*/
|
||||
ENetHost *
|
||||
enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelLimit, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
|
||||
{
|
||||
ENetHost * host;
|
||||
ENetPeer * currentPeer;
|
||||
|
||||
if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID)
|
||||
return NULL;
|
||||
|
||||
host = (ENetHost *) enet_malloc (sizeof (ENetHost));
|
||||
if (host == NULL)
|
||||
return NULL;
|
||||
memset (host, 0, sizeof (ENetHost));
|
||||
|
||||
host -> peers = (ENetPeer *) enet_malloc (peerCount * sizeof (ENetPeer));
|
||||
if (host -> peers == NULL)
|
||||
{
|
||||
enet_free (host);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
memset (host -> peers, 0, peerCount * sizeof (ENetPeer));
|
||||
|
||||
host -> socket = enet_socket_create (ENET_SOCKET_TYPE_DATAGRAM);
|
||||
if (host -> socket == ENET_SOCKET_NULL || (address != NULL && enet_socket_bind (host -> socket, address) < 0))
|
||||
{
|
||||
if (host -> socket != ENET_SOCKET_NULL)
|
||||
enet_socket_destroy (host -> socket);
|
||||
|
||||
enet_free (host -> peers);
|
||||
enet_free (host);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enet_socket_set_option (host -> socket, ENET_SOCKOPT_NONBLOCK, 1);
|
||||
enet_socket_set_option (host -> socket, ENET_SOCKOPT_BROADCAST, 1);
|
||||
enet_socket_set_option (host -> socket, ENET_SOCKOPT_RCVBUF, ENET_HOST_RECEIVE_BUFFER_SIZE);
|
||||
enet_socket_set_option (host -> socket, ENET_SOCKOPT_SNDBUF, ENET_HOST_SEND_BUFFER_SIZE);
|
||||
|
||||
if (address != NULL && enet_socket_get_address (host -> socket, & host -> address) < 0)
|
||||
host -> address = * address;
|
||||
|
||||
if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
|
||||
channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
|
||||
else
|
||||
if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
|
||||
channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
|
||||
|
||||
host -> randomSeed = (enet_uint32) (size_t) host;
|
||||
host -> randomSeed += enet_host_random_seed ();
|
||||
host -> randomSeed = (host -> randomSeed << 16) | (host -> randomSeed >> 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 = NULL;
|
||||
memset(host -> receivedAddress.host, 0, 16);
|
||||
host -> receivedAddress.port = 0;
|
||||
host -> receivedData = NULL;
|
||||
host -> receivedDataLength = 0;
|
||||
|
||||
host -> totalSentData = 0;
|
||||
host -> totalSentPackets = 0;
|
||||
host -> totalReceivedData = 0;
|
||||
host -> totalReceivedPackets = 0;
|
||||
host -> totalQueued = 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 = NULL;
|
||||
host -> compressor.compress = NULL;
|
||||
host -> compressor.decompress = NULL;
|
||||
host -> compressor.destroy = NULL;
|
||||
|
||||
host -> intercept = NULL;
|
||||
|
||||
enet_list_clear (& host -> dispatchQueue);
|
||||
|
||||
for (currentPeer = host -> peers;
|
||||
currentPeer < & host -> peers [host -> peerCount];
|
||||
++ currentPeer)
|
||||
{
|
||||
currentPeer -> host = host;
|
||||
currentPeer -> incomingPeerID = currentPeer - host -> peers;
|
||||
currentPeer -> outgoingSessionID = currentPeer -> incomingSessionID = 0xFF;
|
||||
currentPeer -> data = NULL;
|
||||
|
||||
enet_list_clear (& currentPeer -> acknowledgements);
|
||||
enet_list_clear (& currentPeer -> sentReliableCommands);
|
||||
enet_list_clear (& currentPeer -> outgoingCommands);
|
||||
enet_list_clear (& currentPeer -> outgoingSendReliableCommands);
|
||||
enet_list_clear (& currentPeer -> dispatchedCommands);
|
||||
|
||||
enet_peer_reset (currentPeer);
|
||||
}
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
/** Destroys the host and all resources associated with it.
|
||||
@param host pointer to the host to destroy
|
||||
*/
|
||||
void
|
||||
enet_host_destroy (ENetHost * host)
|
||||
{
|
||||
ENetPeer * currentPeer;
|
||||
|
||||
if (host == NULL)
|
||||
return;
|
||||
|
||||
enet_socket_destroy (host -> socket);
|
||||
|
||||
for (currentPeer = host -> peers;
|
||||
currentPeer < & host -> peers [host -> peerCount];
|
||||
++ currentPeer)
|
||||
{
|
||||
enet_peer_reset (currentPeer);
|
||||
}
|
||||
|
||||
if (host -> compressor.context != NULL && host -> compressor.destroy)
|
||||
(* host -> compressor.destroy) (host -> compressor.context);
|
||||
|
||||
enet_free (host -> peers);
|
||||
enet_free (host);
|
||||
}
|
||||
|
||||
enet_uint32
|
||||
enet_host_random (ENetHost * host)
|
||||
{
|
||||
/* Mulberry32 by Tommy Ettinger */
|
||||
enet_uint32 n = (host -> randomSeed += 0x6D2B79F5U);
|
||||
n = (n ^ (n >> 15)) * (n | 1U);
|
||||
n ^= n + (n ^ (n >> 7)) * (n | 61U);
|
||||
return n ^ (n >> 14);
|
||||
}
|
||||
|
||||
/** Initiates a connection to a foreign host.
|
||||
@param host host seeking the connection
|
||||
@param address destination for the connection
|
||||
@param channelCount number of channels to allocate
|
||||
@param data user data supplied to the receiving host
|
||||
@returns a peer representing the foreign host on success, NULL on failure
|
||||
@remarks The peer returned will have not completed the connection until enet_host_service()
|
||||
notifies of an ENET_EVENT_TYPE_CONNECT event for the peer.
|
||||
*/
|
||||
ENetPeer *
|
||||
enet_host_connect (ENetHost * host, const ENetAddress * address, size_t channelCount, enet_uint32 data)
|
||||
{
|
||||
ENetPeer * currentPeer;
|
||||
ENetChannel * channel;
|
||||
ENetProtocol command;
|
||||
|
||||
if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
|
||||
channelCount = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
|
||||
else
|
||||
if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
|
||||
channelCount = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
|
||||
|
||||
for (currentPeer = host -> peers;
|
||||
currentPeer < & host -> peers [host -> peerCount];
|
||||
++ currentPeer)
|
||||
{
|
||||
if (currentPeer -> state == ENET_PEER_STATE_DISCONNECTED)
|
||||
break;
|
||||
}
|
||||
|
||||
if (currentPeer >= & host -> peers [host -> peerCount])
|
||||
return NULL;
|
||||
|
||||
currentPeer -> channels = (ENetChannel *) enet_malloc (channelCount * sizeof (ENetChannel));
|
||||
if (currentPeer -> channels == NULL)
|
||||
return NULL;
|
||||
currentPeer -> channelCount = channelCount;
|
||||
currentPeer -> state = ENET_PEER_STATE_CONNECTING;
|
||||
currentPeer -> address = * address;
|
||||
currentPeer -> connectID = enet_host_random (host);
|
||||
currentPeer -> mtu = host -> mtu;
|
||||
|
||||
if (host -> outgoingBandwidth == 0)
|
||||
currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
|
||||
else
|
||||
currentPeer -> windowSize = (host -> outgoingBandwidth /
|
||||
ENET_PEER_WINDOW_SIZE_SCALE) *
|
||||
ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
|
||||
|
||||
if (currentPeer -> windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE)
|
||||
currentPeer -> windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE;
|
||||
else
|
||||
if (currentPeer -> windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE)
|
||||
currentPeer -> windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE;
|
||||
|
||||
for (channel = currentPeer -> channels;
|
||||
channel < & currentPeer -> channels [channelCount];
|
||||
++ channel)
|
||||
{
|
||||
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;
|
||||
memset (channel -> reliableWindows, 0, sizeof (channel -> reliableWindows));
|
||||
}
|
||||
|
||||
command.header.command = ENET_PROTOCOL_COMMAND_CONNECT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
|
||||
command.header.channelID = 0xFF;
|
||||
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, NULL, 0, 0);
|
||||
|
||||
return currentPeer;
|
||||
}
|
||||
|
||||
/** Queues a packet to be sent to all peers associated with the host.
|
||||
@param host host on which to broadcast the packet
|
||||
@param channelID channel on which to broadcast
|
||||
@param packet packet to broadcast
|
||||
*/
|
||||
void
|
||||
enet_host_broadcast (ENetHost * host, enet_uint8 channelID, ENetPacket * packet)
|
||||
{
|
||||
ENetPeer * currentPeer;
|
||||
|
||||
for (currentPeer = host -> peers;
|
||||
currentPeer < & host -> peers [host -> peerCount];
|
||||
++ currentPeer)
|
||||
{
|
||||
if (currentPeer -> state != ENET_PEER_STATE_CONNECTED)
|
||||
continue;
|
||||
|
||||
enet_peer_send (currentPeer, channelID, packet);
|
||||
}
|
||||
|
||||
if (packet -> referenceCount == 0)
|
||||
enet_packet_destroy (packet);
|
||||
}
|
||||
|
||||
/** Sets the packet compressor the host should use to compress and decompress packets.
|
||||
@param host host to enable or disable compression for
|
||||
@param compressor callbacks for for the packet compressor; if NULL, then compression is disabled
|
||||
*/
|
||||
void
|
||||
enet_host_compress (ENetHost * host, const ENetCompressor * compressor)
|
||||
{
|
||||
if (host -> compressor.context != NULL && host -> compressor.destroy)
|
||||
(* host -> compressor.destroy) (host -> compressor.context);
|
||||
|
||||
if (compressor)
|
||||
host -> compressor = * compressor;
|
||||
else
|
||||
host -> compressor.context = NULL;
|
||||
}
|
||||
|
||||
/** Limits the maximum allowed channels of future incoming connections.
|
||||
@param host host to limit
|
||||
@param channelLimit the maximum number of channels allowed; if 0, then this is equivalent to ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT
|
||||
*/
|
||||
void
|
||||
enet_host_channel_limit (ENetHost * host, size_t channelLimit)
|
||||
{
|
||||
if (! channelLimit || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT)
|
||||
channelLimit = ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT;
|
||||
else
|
||||
if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT)
|
||||
channelLimit = ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT;
|
||||
|
||||
host -> channelLimit = channelLimit;
|
||||
}
|
||||
|
||||
|
||||
/** Adjusts the bandwidth limits of a host.
|
||||
@param host host to adjust
|
||||
@param incomingBandwidth new incoming bandwidth
|
||||
@param outgoingBandwidth new outgoing bandwidth
|
||||
@remarks the incoming and outgoing bandwidth parameters are identical in function to those
|
||||
specified in enet_host_create().
|
||||
*/
|
||||
void
|
||||
enet_host_bandwidth_limit (ENetHost * host, enet_uint32 incomingBandwidth, enet_uint32 outgoingBandwidth)
|
||||
{
|
||||
host -> incomingBandwidth = incomingBandwidth;
|
||||
host -> outgoingBandwidth = outgoingBandwidth;
|
||||
host -> recalculateBandwidthLimits = 1;
|
||||
}
|
||||
|
||||
void
|
||||
enet_host_bandwidth_throttle (ENetHost * host)
|
||||
{
|
||||
enet_uint32 timeCurrent = enet_time_get (),
|
||||
elapsedTime = timeCurrent - host -> bandwidthThrottleEpoch,
|
||||
peersRemaining = (enet_uint32) host -> connectedPeers,
|
||||
dataTotal = ~0,
|
||||
bandwidth = ~0,
|
||||
throttle = 0,
|
||||
bandwidthLimit = 0;
|
||||
int needsAdjustment = host -> bandwidthLimitedPeers > 0 ? 1 : 0;
|
||||
ENetPeer * peer;
|
||||
ENetProtocol command;
|
||||
|
||||
if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL)
|
||||
return;
|
||||
|
||||
host -> bandwidthThrottleEpoch = timeCurrent;
|
||||
|
||||
if (peersRemaining == 0)
|
||||
return;
|
||||
|
||||
if (host -> outgoingBandwidth != 0)
|
||||
{
|
||||
dataTotal = 0;
|
||||
bandwidth = (host -> outgoingBandwidth * elapsedTime) / 1000;
|
||||
|
||||
for (peer = host -> peers;
|
||||
peer < & host -> peers [host -> peerCount];
|
||||
++ peer)
|
||||
{
|
||||
if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
|
||||
continue;
|
||||
|
||||
dataTotal += peer -> outgoingDataTotal;
|
||||
}
|
||||
}
|
||||
|
||||
while (peersRemaining > 0 && needsAdjustment != 0)
|
||||
{
|
||||
needsAdjustment = 0;
|
||||
|
||||
if (dataTotal <= bandwidth)
|
||||
throttle = ENET_PEER_PACKET_THROTTLE_SCALE;
|
||||
else
|
||||
throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal;
|
||||
|
||||
for (peer = host -> peers;
|
||||
peer < & host -> peers [host -> peerCount];
|
||||
++ peer)
|
||||
{
|
||||
enet_uint32 peerBandwidth;
|
||||
|
||||
if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
|
||||
peer -> incomingBandwidth == 0 ||
|
||||
peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
|
||||
continue;
|
||||
|
||||
peerBandwidth = (peer -> incomingBandwidth * elapsedTime) / 1000;
|
||||
if ((throttle * peer -> outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth)
|
||||
continue;
|
||||
|
||||
peer -> packetThrottleLimit = (peerBandwidth *
|
||||
ENET_PEER_PACKET_THROTTLE_SCALE) / peer -> outgoingDataTotal;
|
||||
|
||||
if (peer -> packetThrottleLimit == 0)
|
||||
peer -> packetThrottleLimit = 1;
|
||||
|
||||
if (peer -> packetThrottle > peer -> packetThrottleLimit)
|
||||
peer -> packetThrottle = peer -> packetThrottleLimit;
|
||||
|
||||
peer -> outgoingBandwidthThrottleEpoch = timeCurrent;
|
||||
|
||||
peer -> incomingDataTotal = 0;
|
||||
peer -> outgoingDataTotal = 0;
|
||||
|
||||
needsAdjustment = 1;
|
||||
-- peersRemaining;
|
||||
bandwidth -= peerBandwidth;
|
||||
dataTotal -= peerBandwidth;
|
||||
}
|
||||
}
|
||||
|
||||
if (peersRemaining > 0)
|
||||
{
|
||||
if (dataTotal <= bandwidth)
|
||||
throttle = ENET_PEER_PACKET_THROTTLE_SCALE;
|
||||
else
|
||||
throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal;
|
||||
|
||||
for (peer = host -> peers;
|
||||
peer < & host -> peers [host -> peerCount];
|
||||
++ peer)
|
||||
{
|
||||
if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
|
||||
peer -> outgoingBandwidthThrottleEpoch == timeCurrent)
|
||||
continue;
|
||||
|
||||
peer -> packetThrottleLimit = throttle;
|
||||
|
||||
if (peer -> packetThrottle > peer -> packetThrottleLimit)
|
||||
peer -> packetThrottle = peer -> packetThrottleLimit;
|
||||
|
||||
peer -> incomingDataTotal = 0;
|
||||
peer -> outgoingDataTotal = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (host -> recalculateBandwidthLimits)
|
||||
{
|
||||
host -> recalculateBandwidthLimits = 0;
|
||||
|
||||
peersRemaining = (enet_uint32) host -> connectedPeers;
|
||||
bandwidth = host -> incomingBandwidth;
|
||||
needsAdjustment = 1;
|
||||
|
||||
if (bandwidth == 0)
|
||||
bandwidthLimit = 0;
|
||||
else
|
||||
while (peersRemaining > 0 && needsAdjustment != 0)
|
||||
{
|
||||
needsAdjustment = 0;
|
||||
bandwidthLimit = bandwidth / peersRemaining;
|
||||
|
||||
for (peer = host -> peers;
|
||||
peer < & host -> peers [host -> peerCount];
|
||||
++ peer)
|
||||
{
|
||||
if ((peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER) ||
|
||||
peer -> incomingBandwidthThrottleEpoch == timeCurrent)
|
||||
continue;
|
||||
|
||||
if (peer -> outgoingBandwidth > 0 &&
|
||||
peer -> outgoingBandwidth >= bandwidthLimit)
|
||||
continue;
|
||||
|
||||
peer -> incomingBandwidthThrottleEpoch = timeCurrent;
|
||||
|
||||
needsAdjustment = 1;
|
||||
-- peersRemaining;
|
||||
bandwidth -= peer -> outgoingBandwidth;
|
||||
}
|
||||
}
|
||||
|
||||
for (peer = host -> peers;
|
||||
peer < & host -> peers [host -> peerCount];
|
||||
++ peer)
|
||||
{
|
||||
if (peer -> state != ENET_PEER_STATE_CONNECTED && peer -> state != ENET_PEER_STATE_DISCONNECT_LATER)
|
||||
continue;
|
||||
|
||||
command.header.command = ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE;
|
||||
command.header.channelID = 0xFF;
|
||||
command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32 (host -> outgoingBandwidth);
|
||||
|
||||
if (peer -> incomingBandwidthThrottleEpoch == timeCurrent)
|
||||
command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (peer -> outgoingBandwidth);
|
||||
else
|
||||
command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32 (bandwidthLimit);
|
||||
|
||||
enet_peer_queue_outgoing_command (peer, & command, NULL, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @} */
|
@ -1,75 +0,0 @@
|
||||
/**
|
||||
@file list.c
|
||||
@brief ENet linked list functions
|
||||
*/
|
||||
#define ENET_BUILDING_LIB 1
|
||||
#include "enet/enet.h"
|
||||
|
||||
/**
|
||||
@defgroup list ENet linked list utility functions
|
||||
@ingroup private
|
||||
@{
|
||||
*/
|
||||
void
|
||||
enet_list_clear (ENetList * list)
|
||||
{
|
||||
list -> sentinel.next = & list -> sentinel;
|
||||
list -> sentinel.previous = & list -> sentinel;
|
||||
}
|
||||
|
||||
ENetListIterator
|
||||
enet_list_insert (ENetListIterator position, void * data)
|
||||
{
|
||||
ENetListIterator result = (ENetListIterator) data;
|
||||
|
||||
result -> previous = position -> previous;
|
||||
result -> next = position;
|
||||
|
||||
result -> previous -> next = result;
|
||||
position -> previous = result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void *
|
||||
enet_list_remove (ENetListIterator position)
|
||||
{
|
||||
position -> previous -> next = position -> next;
|
||||
position -> next -> previous = position -> previous;
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
ENetListIterator
|
||||
enet_list_move (ENetListIterator position, void * dataFirst, void * dataLast)
|
||||
{
|
||||
ENetListIterator first = (ENetListIterator) dataFirst,
|
||||
last = (ENetListIterator) dataLast;
|
||||
|
||||
first -> previous -> next = last -> next;
|
||||
last -> next -> previous = first -> previous;
|
||||
|
||||
first -> previous = position -> previous;
|
||||
last -> next = position;
|
||||
|
||||
first -> previous -> next = first;
|
||||
position -> previous = last;
|
||||
|
||||
return first;
|
||||
}
|
||||
|
||||
size_t
|
||||
enet_list_size (ENetList * list)
|
||||
{
|
||||
size_t size = 0;
|
||||
ENetListIterator position;
|
||||
|
||||
for (position = enet_list_begin (list);
|
||||
position != enet_list_end (list);
|
||||
position = enet_list_next (position))
|
||||
++ size;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/** @} */
|
@ -1,158 +0,0 @@
|
||||
/**
|
||||
@file packet.c
|
||||
@brief ENet packet management functions
|
||||
*/
|
||||
#include <string.h>
|
||||
#define ENET_BUILDING_LIB 1
|
||||
#include "enet/enet.h"
|
||||
|
||||
/** @defgroup Packet ENet packet functions
|
||||
@{
|
||||
*/
|
||||
|
||||
/** Creates a packet that may be sent to a peer.
|
||||
@param data initial contents of the packet's data; the packet's data will remain uninitialized if data is NULL.
|
||||
@param dataLength size of the data allocated for this packet
|
||||
@param flags flags for this packet as described for the ENetPacket structure.
|
||||
@returns the packet on success, NULL on failure
|
||||
*/
|
||||
ENetPacket *
|
||||
enet_packet_create (const void * data, size_t dataLength, enet_uint32 flags)
|
||||
{
|
||||
ENetPacket * packet = (ENetPacket *) enet_malloc (sizeof (ENetPacket));
|
||||
if (packet == NULL)
|
||||
return NULL;
|
||||
|
||||
if (flags & ENET_PACKET_FLAG_NO_ALLOCATE)
|
||||
packet -> data = (enet_uint8 *) data;
|
||||
else
|
||||
if (dataLength <= 0)
|
||||
packet -> data = NULL;
|
||||
else
|
||||
{
|
||||
packet -> data = (enet_uint8 *) enet_malloc (dataLength);
|
||||
if (packet -> data == NULL)
|
||||
{
|
||||
enet_free (packet);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (data != NULL)
|
||||
memcpy (packet -> data, data, dataLength);
|
||||
}
|
||||
|
||||
packet -> referenceCount = 0;
|
||||
packet -> flags = flags;
|
||||
packet -> dataLength = dataLength;
|
||||
packet -> freeCallback = NULL;
|
||||
packet -> userData = NULL;
|
||||
|
||||
return packet;
|
||||
}
|
||||
|
||||
/** Destroys the packet and deallocates its data.
|
||||
@param packet packet to be destroyed
|
||||
*/
|
||||
void
|
||||
enet_packet_destroy (ENetPacket * packet)
|
||||
{
|
||||
if (packet == NULL)
|
||||
return;
|
||||
|
||||
if (packet -> freeCallback != NULL)
|
||||
(* packet -> freeCallback) (packet);
|
||||
if (! (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE) &&
|
||||
packet -> data != NULL)
|
||||
enet_free (packet -> data);
|
||||
enet_free (packet);
|
||||
}
|
||||
|
||||
/** Attempts to resize the data in the packet to length specified in the
|
||||
dataLength parameter
|
||||
@param packet packet to resize
|
||||
@param dataLength new size for the packet data
|
||||
@returns 0 on success, < 0 on failure
|
||||
*/
|
||||
int
|
||||
enet_packet_resize (ENetPacket * packet, size_t dataLength)
|
||||
{
|
||||
enet_uint8 * newData;
|
||||
|
||||
if (dataLength <= packet -> dataLength || (packet -> flags & ENET_PACKET_FLAG_NO_ALLOCATE))
|
||||
{
|
||||
packet -> dataLength = dataLength;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
newData = (enet_uint8 *) enet_malloc (dataLength);
|
||||
if (newData == NULL)
|
||||
return -1;
|
||||
|
||||
memcpy (newData, packet -> data, packet -> dataLength);
|
||||
enet_free (packet -> data);
|
||||
|
||||
packet -> data = newData;
|
||||
packet -> dataLength = dataLength;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const enet_uint32 crcTable [256] =
|
||||
{
|
||||
0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
||||
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
||||
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
||||
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
||||
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
||||
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
||||
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
||||
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
||||
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
||||
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
||||
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
||||
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
||||
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
||||
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
||||
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
||||
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x5005713,
|
||||
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0xBDBDF21,
|
||||
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
||||
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
||||
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
|
||||
enet_uint32
|
||||
enet_crc32 (const ENetBuffer * buffers, size_t bufferCount)
|
||||
{
|
||||
enet_uint32 crc = 0xFFFFFFFF;
|
||||
|
||||
while (bufferCount -- > 0)
|
||||
{
|
||||
const enet_uint8 * data = (const enet_uint8 *) buffers -> data,
|
||||
* dataEnd = & data [buffers -> dataLength];
|
||||
|
||||
while (data < dataEnd)
|
||||
{
|
||||
crc = (crc >> 8) ^ crcTable [(crc & 0xFF) ^ *data++];
|
||||
}
|
||||
|
||||
++ buffers;
|
||||
}
|
||||
|
||||
return ENET_HOST_TO_NET_32 (~ crc);
|
||||
}
|
||||
|
||||
/** @} */
|
@ -1,535 +0,0 @@
|
||||
|
||||
/* pandemonium.cpp */
|
||||
|
||||
/**
|
||||
@file pandemonium.cpp
|
||||
@brief ENet Pandemonium specific functions
|
||||
*/
|
||||
|
||||
#include "core/io/dtls_server.h"
|
||||
#include "core/io/ip.h"
|
||||
#include "core/io/net_socket.h"
|
||||
#include "core/io/packet_peer_dtls.h"
|
||||
#include "core/io/udp_server.h"
|
||||
#include "core/os/os.h"
|
||||
|
||||
// This must be last for windows to compile (tested with MinGW)
|
||||
#include "enet/enet.h"
|
||||
|
||||
/// Abstract ENet interface for UDP/DTLS.
|
||||
class ENetPandemoniumSocket {
|
||||
|
||||
public:
|
||||
virtual Error bind(IP_Address p_ip, uint16_t p_port) = 0;
|
||||
virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) = 0;
|
||||
virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) = 0;
|
||||
virtual int set_option(ENetSocketOption p_option, int p_value) = 0;
|
||||
virtual void close() = 0;
|
||||
virtual void set_refuse_new_connections(bool p_refuse) { /* Only used by dtls server */ }
|
||||
virtual ~ENetPandemoniumSocket(){};
|
||||
};
|
||||
|
||||
class ENetDTLSClient;
|
||||
class ENetDTLSServer;
|
||||
|
||||
/// NetSocket interface
|
||||
class ENetUDP : public ENetPandemoniumSocket {
|
||||
|
||||
friend class ENetDTLSClient;
|
||||
friend class ENetDTLSServer;
|
||||
|
||||
private:
|
||||
Ref<NetSocket> sock;
|
||||
IP_Address address;
|
||||
uint16_t port;
|
||||
bool bound;
|
||||
|
||||
public:
|
||||
ENetUDP() {
|
||||
sock = Ref<NetSocket>(NetSocket::create());
|
||||
IP::Type ip_type = IP::TYPE_ANY;
|
||||
bound = false;
|
||||
sock->open(NetSocket::TYPE_UDP, ip_type);
|
||||
}
|
||||
|
||||
~ENetUDP() {
|
||||
sock->close();
|
||||
}
|
||||
|
||||
Error bind(IP_Address p_ip, uint16_t p_port) {
|
||||
address = p_ip;
|
||||
port = p_port;
|
||||
bound = true;
|
||||
return sock->bind(address, port);
|
||||
}
|
||||
|
||||
Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
|
||||
return sock->sendto(p_buffer, p_len, r_sent, p_ip, p_port);
|
||||
}
|
||||
|
||||
Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) {
|
||||
Error err = sock->poll(NetSocket::POLL_TYPE_IN, 0);
|
||||
if (err != OK) {
|
||||
return err;
|
||||
}
|
||||
return sock->recvfrom(p_buffer, p_len, r_read, r_ip, r_port);
|
||||
}
|
||||
|
||||
int set_option(ENetSocketOption p_option, int p_value) {
|
||||
switch (p_option) {
|
||||
case ENET_SOCKOPT_NONBLOCK: {
|
||||
sock->set_blocking_enabled(p_value ? false : true);
|
||||
return 0;
|
||||
} break;
|
||||
|
||||
case ENET_SOCKOPT_BROADCAST: {
|
||||
sock->set_broadcasting_enabled(p_value ? true : false);
|
||||
return 0;
|
||||
} break;
|
||||
|
||||
case ENET_SOCKOPT_REUSEADDR: {
|
||||
sock->set_reuse_address_enabled(p_value ? true : false);
|
||||
return 0;
|
||||
} break;
|
||||
|
||||
case ENET_SOCKOPT_RCVBUF: {
|
||||
return -1;
|
||||
} break;
|
||||
|
||||
case ENET_SOCKOPT_SNDBUF: {
|
||||
return -1;
|
||||
} break;
|
||||
|
||||
case ENET_SOCKOPT_RCVTIMEO: {
|
||||
return -1;
|
||||
} break;
|
||||
|
||||
case ENET_SOCKOPT_SNDTIMEO: {
|
||||
return -1;
|
||||
} break;
|
||||
|
||||
case ENET_SOCKOPT_NODELAY: {
|
||||
sock->set_tcp_no_delay_enabled(p_value ? true : false);
|
||||
return 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void close() {
|
||||
sock->close();
|
||||
}
|
||||
};
|
||||
|
||||
/// DTLS Client ENet interface
|
||||
class ENetDTLSClient : public ENetPandemoniumSocket {
|
||||
|
||||
bool connected;
|
||||
Ref<PacketPeerUDP> udp;
|
||||
Ref<PacketPeerDTLS> dtls;
|
||||
bool verify;
|
||||
String for_hostname;
|
||||
Ref<X509Certificate> cert;
|
||||
|
||||
public:
|
||||
ENetDTLSClient(ENetUDP *p_base, Ref<X509Certificate> p_cert, bool p_verify, String p_for_hostname) {
|
||||
verify = p_verify;
|
||||
for_hostname = p_for_hostname;
|
||||
cert = p_cert;
|
||||
udp.instance();
|
||||
dtls = Ref<PacketPeerDTLS>(PacketPeerDTLS::create());
|
||||
p_base->close();
|
||||
if (p_base->bound) {
|
||||
bind(p_base->address, p_base->port);
|
||||
}
|
||||
connected = false;
|
||||
}
|
||||
|
||||
~ENetDTLSClient() {
|
||||
close();
|
||||
}
|
||||
|
||||
Error bind(IP_Address p_ip, uint16_t p_port) {
|
||||
return udp->listen(p_port, p_ip);
|
||||
}
|
||||
|
||||
Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
|
||||
if (!connected) {
|
||||
udp->connect_to_host(p_ip, p_port);
|
||||
dtls->connect_to_peer(udp, verify, for_hostname, cert);
|
||||
connected = true;
|
||||
}
|
||||
dtls->poll();
|
||||
if (dtls->get_status() == PacketPeerDTLS::STATUS_HANDSHAKING) {
|
||||
return ERR_BUSY;
|
||||
} else if (dtls->get_status() != PacketPeerDTLS::STATUS_CONNECTED) {
|
||||
return FAILED;
|
||||
}
|
||||
r_sent = p_len;
|
||||
return dtls->put_packet(p_buffer, p_len);
|
||||
}
|
||||
|
||||
Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) {
|
||||
dtls->poll();
|
||||
if (dtls->get_status() == PacketPeerDTLS::STATUS_HANDSHAKING) {
|
||||
return ERR_BUSY;
|
||||
}
|
||||
if (dtls->get_status() != PacketPeerDTLS::STATUS_CONNECTED) {
|
||||
return FAILED;
|
||||
}
|
||||
int pc = dtls->get_available_packet_count();
|
||||
if (pc == 0) {
|
||||
return ERR_BUSY;
|
||||
} else if (pc < 0) {
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
const uint8_t *buffer;
|
||||
Error err = dtls->get_packet(&buffer, r_read);
|
||||
ERR_FAIL_COND_V(err != OK, err);
|
||||
ERR_FAIL_COND_V(p_len < r_read, ERR_OUT_OF_MEMORY);
|
||||
|
||||
memcpy(p_buffer, buffer, r_read);
|
||||
r_ip = udp->get_packet_address();
|
||||
r_port = udp->get_packet_port();
|
||||
return err;
|
||||
}
|
||||
|
||||
int set_option(ENetSocketOption p_option, int p_value) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void close() {
|
||||
dtls->disconnect_from_peer();
|
||||
udp->close();
|
||||
}
|
||||
};
|
||||
|
||||
/// DTLSServer - ENet interface
|
||||
class ENetDTLSServer : public ENetPandemoniumSocket {
|
||||
|
||||
Ref<DTLSServer> server;
|
||||
Ref<UDPServer> udp_server;
|
||||
RBMap<String, Ref<PacketPeerDTLS> > peers;
|
||||
int last_service;
|
||||
|
||||
public:
|
||||
ENetDTLSServer(ENetUDP *p_base, Ref<CryptoKey> p_key, Ref<X509Certificate> p_cert) {
|
||||
last_service = 0;
|
||||
udp_server.instance();
|
||||
p_base->close();
|
||||
if (p_base->bound) {
|
||||
bind(p_base->address, p_base->port);
|
||||
}
|
||||
server = Ref<DTLSServer>(DTLSServer::create());
|
||||
server->setup(p_key, p_cert);
|
||||
}
|
||||
|
||||
~ENetDTLSServer() {
|
||||
close();
|
||||
}
|
||||
|
||||
void set_refuse_new_connections(bool p_refuse) {
|
||||
udp_server->set_max_pending_connections(p_refuse ? 0 : 16);
|
||||
}
|
||||
|
||||
Error bind(IP_Address p_ip, uint16_t p_port) {
|
||||
return udp_server->listen(p_port, p_ip);
|
||||
}
|
||||
|
||||
Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) {
|
||||
String key = String(p_ip) + ":" + itos(p_port);
|
||||
ERR_FAIL_COND_V(!peers.has(key), ERR_UNAVAILABLE);
|
||||
Ref<PacketPeerDTLS> peer = peers[key];
|
||||
Error err = peer->put_packet(p_buffer, p_len);
|
||||
if (err == OK) {
|
||||
r_sent = p_len;
|
||||
} else if (err == ERR_BUSY) {
|
||||
r_sent = 0;
|
||||
} else {
|
||||
r_sent = -1;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) {
|
||||
udp_server->poll();
|
||||
// TODO limits? Maybe we can better enforce allowed connections!
|
||||
if (udp_server->is_connection_available()) {
|
||||
Ref<PacketPeerUDP> udp = udp_server->take_connection();
|
||||
IP_Address peer_ip = udp->get_packet_address();
|
||||
int peer_port = udp->get_packet_port();
|
||||
Ref<PacketPeerDTLS> peer = server->take_connection(udp);
|
||||
PacketPeerDTLS::Status status = peer->get_status();
|
||||
if (status == PacketPeerDTLS::STATUS_HANDSHAKING || status == PacketPeerDTLS::STATUS_CONNECTED) {
|
||||
String key = String(peer_ip) + ":" + itos(peer_port);
|
||||
peers[key] = peer;
|
||||
}
|
||||
}
|
||||
|
||||
List<String> remove;
|
||||
Error err = ERR_BUSY;
|
||||
// TODO this needs to be fair!
|
||||
for (RBMap<String, Ref<PacketPeerDTLS> >::Element *E = peers.front(); E; E = E->next()) {
|
||||
Ref<PacketPeerDTLS> peer = E->get();
|
||||
peer->poll();
|
||||
|
||||
if (peer->get_status() == PacketPeerDTLS::STATUS_HANDSHAKING) {
|
||||
continue;
|
||||
} else if (peer->get_status() != PacketPeerDTLS::STATUS_CONNECTED) {
|
||||
// Peer disconnected, removing it.
|
||||
remove.push_back(E->key());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (peer->get_available_packet_count() > 0) {
|
||||
const uint8_t *buffer;
|
||||
err = peer->get_packet(&buffer, r_read);
|
||||
if (err != OK || p_len < r_read) {
|
||||
// Something wrong with this peer, removing it.
|
||||
remove.push_back(E->key());
|
||||
err = FAILED;
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector<String> s = E->key().rsplit(":", false, 1);
|
||||
ERR_CONTINUE(s.size() != 2); // BUG!
|
||||
|
||||
memcpy(p_buffer, buffer, r_read);
|
||||
r_ip = s[0];
|
||||
r_port = s[1].to_int();
|
||||
break; // err = OK
|
||||
}
|
||||
}
|
||||
|
||||
// Remove disconnected peers from map.
|
||||
for (List<String>::Element *E = remove.front(); E; E = E->next()) {
|
||||
peers.erase(E->get());
|
||||
}
|
||||
|
||||
return err; // OK, ERR_BUSY, or possibly an error.
|
||||
}
|
||||
|
||||
int set_option(ENetSocketOption p_option, int p_value) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
void close() {
|
||||
for (RBMap<String, Ref<PacketPeerDTLS> >::Element *E = peers.front(); E; E = E->next()) {
|
||||
E->get()->disconnect_from_peer();
|
||||
}
|
||||
peers.clear();
|
||||
udp_server->stop();
|
||||
server->stop();
|
||||
}
|
||||
};
|
||||
|
||||
static enet_uint32 timeBase = 0;
|
||||
|
||||
int enet_initialize(void) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enet_deinitialize(void) {
|
||||
}
|
||||
|
||||
enet_uint32 enet_host_random_seed(void) {
|
||||
|
||||
return (enet_uint32)OS::get_singleton()->get_unix_time();
|
||||
}
|
||||
|
||||
enet_uint32 enet_time_get(void) {
|
||||
|
||||
return OS::get_singleton()->get_ticks_msec() - timeBase;
|
||||
}
|
||||
|
||||
void enet_time_set(enet_uint32 newTimeBase) {
|
||||
|
||||
timeBase = OS::get_singleton()->get_ticks_msec() - newTimeBase;
|
||||
}
|
||||
|
||||
int enet_address_set_host(ENetAddress *address, const char *name) {
|
||||
|
||||
IP_Address ip = IP::get_singleton()->resolve_hostname(name);
|
||||
ERR_FAIL_COND_V(!ip.is_valid(), -1);
|
||||
|
||||
enet_address_set_ip(address, ip.get_ipv6(), 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enet_address_set_ip(ENetAddress *address, const uint8_t *ip, size_t size) {
|
||||
|
||||
int len = size > 16 ? 16 : size;
|
||||
memset(address->host, 0, 16);
|
||||
memcpy(address->host, ip, len);
|
||||
}
|
||||
|
||||
int enet_address_get_host_ip(const ENetAddress *address, char *name, size_t nameLength) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int enet_address_get_host(const ENetAddress *address, char *name, size_t nameLength) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ENetSocket enet_socket_create(ENetSocketType type) {
|
||||
|
||||
ENetUDP *socket = memnew(ENetUDP);
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
void enet_host_dtls_server_setup(ENetHost *host, void *p_key, void *p_cert) {
|
||||
ENetUDP *sock = (ENetUDP *)host->socket;
|
||||
host->socket = memnew(ENetDTLSServer(sock, Ref<CryptoKey>((CryptoKey *)p_key), Ref<X509Certificate>((X509Certificate *)p_cert)));
|
||||
memdelete(sock);
|
||||
}
|
||||
|
||||
void enet_host_dtls_client_setup(ENetHost *host, void *p_cert, uint8_t p_verify, const char *p_for_hostname) {
|
||||
ENetUDP *sock = (ENetUDP *)host->socket;
|
||||
host->socket = memnew(ENetDTLSClient(sock, Ref<X509Certificate>((X509Certificate *)p_cert), p_verify, String(p_for_hostname)));
|
||||
memdelete(sock);
|
||||
}
|
||||
|
||||
void enet_host_refuse_new_connections(ENetHost *host, int p_refuse) {
|
||||
ERR_FAIL_COND(!host->socket);
|
||||
((ENetPandemoniumSocket *)host->socket)->set_refuse_new_connections(p_refuse);
|
||||
}
|
||||
|
||||
int enet_socket_bind(ENetSocket socket, const ENetAddress *address) {
|
||||
|
||||
IP_Address ip;
|
||||
if (address->wildcard) {
|
||||
ip = IP_Address("*");
|
||||
} else {
|
||||
ip.set_ipv6(address->host);
|
||||
}
|
||||
|
||||
ENetPandemoniumSocket *sock = (ENetPandemoniumSocket *)socket;
|
||||
if (sock->bind(ip, address->port) != OK) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enet_socket_destroy(ENetSocket socket) {
|
||||
ENetPandemoniumSocket *sock = (ENetPandemoniumSocket *)socket;
|
||||
sock->close();
|
||||
memdelete(sock);
|
||||
}
|
||||
|
||||
int enet_socket_send(ENetSocket socket, const ENetAddress *address, const ENetBuffer *buffers, size_t bufferCount) {
|
||||
|
||||
ERR_FAIL_COND_V(address == nullptr, -1);
|
||||
|
||||
ENetPandemoniumSocket *sock = (ENetPandemoniumSocket *)socket;
|
||||
IP_Address dest;
|
||||
Error err;
|
||||
size_t i = 0;
|
||||
|
||||
dest.set_ipv6(address->host);
|
||||
|
||||
// Create a single packet.
|
||||
PoolVector<uint8_t> out;
|
||||
PoolVector<uint8_t>::Write w;
|
||||
int size = 0;
|
||||
int pos = 0;
|
||||
for (i = 0; i < bufferCount; i++) {
|
||||
size += buffers[i].dataLength;
|
||||
}
|
||||
|
||||
out.resize(size);
|
||||
w = out.write();
|
||||
for (i = 0; i < bufferCount; i++) {
|
||||
memcpy(&w[pos], buffers[i].data, buffers[i].dataLength);
|
||||
pos += buffers[i].dataLength;
|
||||
}
|
||||
|
||||
int sent = 0;
|
||||
err = sock->sendto((const uint8_t *)&w[0], size, sent, dest, address->port);
|
||||
if (err != OK) {
|
||||
|
||||
if (err == ERR_BUSY) { // Blocking call
|
||||
return 0;
|
||||
}
|
||||
|
||||
WARN_PRINT("Sending failed!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
int enet_socket_receive(ENetSocket socket, ENetAddress *address, ENetBuffer *buffers, size_t bufferCount) {
|
||||
|
||||
ERR_FAIL_COND_V(bufferCount != 1, -1);
|
||||
|
||||
ENetPandemoniumSocket *sock = (ENetPandemoniumSocket *)socket;
|
||||
|
||||
int read;
|
||||
IP_Address ip;
|
||||
|
||||
Error err = sock->recvfrom((uint8_t *)buffers[0].data, buffers[0].dataLength, read, ip, address->port);
|
||||
if (err == ERR_BUSY) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (err != OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
enet_address_set_ip(address, ip.get_ipv6(), 16);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
// Not implemented
|
||||
int enet_socket_wait(ENetSocket socket, enet_uint32 *condition, enet_uint32 timeout) {
|
||||
|
||||
return 0; // do we need this function?
|
||||
}
|
||||
|
||||
int enet_socket_get_address(ENetSocket socket, ENetAddress *address) {
|
||||
|
||||
return -1; // do we need this function?
|
||||
}
|
||||
|
||||
int enet_socketset_select(ENetSocket maxSocket, ENetSocketSet *readSet, ENetSocketSet *writeSet, enet_uint32 timeout) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int enet_socket_listen(ENetSocket socket, int backlog) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int enet_socket_set_option(ENetSocket socket, ENetSocketOption option, int value) {
|
||||
|
||||
ENetPandemoniumSocket *sock = (ENetPandemoniumSocket *)socket;
|
||||
return sock->set_option(option, value);
|
||||
}
|
||||
|
||||
int enet_socket_get_option(ENetSocket socket, ENetSocketOption option, int *value) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int enet_socket_connect(ENetSocket socket, const ENetAddress *address) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ENetSocket enet_socket_accept(ENetSocket socket, ENetAddress *address) {
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int enet_socket_shutdown(ENetSocket socket, ENetSocketShutdown how) {
|
||||
|
||||
return -1;
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
diff --git a/thirdparty/enet/enet/enet.h b/thirdparty/enet/enet/enet.h
|
||||
index fc45cbd0c9..77f8004b80 100644
|
||||
--- a/thirdparty/enet/enet/enet.h
|
||||
+++ b/thirdparty/enet/enet/enet.h
|
||||
@@ -10,13 +10,19 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
+#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
+// -- Pandemonium start --
|
||||
+#if 0
|
||||
#ifdef _WIN32
|
||||
#include "enet/win32.h"
|
||||
#else
|
||||
#include "enet/unix.h"
|
||||
#endif
|
||||
+#endif
|
||||
+#include "enet/pandemonium.h"
|
||||
+// -- Pandemonium end --
|
||||
|
||||
#include "enet/types.h"
|
||||
#include "enet/protocol.h"
|
||||
@@ -86,11 +92,15 @@ typedef enum _ENetSocketShutdown
|
||||
* but not for enet_host_create. Once a server responds to a broadcast, the
|
||||
* address is updated from ENET_HOST_BROADCAST to the server's actual IP address.
|
||||
*/
|
||||
+// -- Pandemonium start --
|
||||
+#if 0
|
||||
typedef struct _ENetAddress
|
||||
{
|
||||
enet_uint32 host;
|
||||
enet_uint16 port;
|
||||
} ENetAddress;
|
||||
+#endif
|
||||
+// -- Pandemonium end --
|
||||
|
||||
/**
|
||||
* Packet flag bit constants.
|
||||
@@ -604,6 +614,10 @@ ENET_API size_t enet_range_coder_decompress (void *, const enet_uint8 *, size_t,
|
||||
|
||||
extern size_t enet_protocol_command_size (enet_uint8);
|
||||
|
||||
+// -- Pandemonium start --
|
||||
+#include "enet/pandemonium_ext.h"
|
||||
+// -- Pandemonium end --
|
||||
+
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
diff --git a/thirdparty/enet/host.c b/thirdparty/enet/host.c
|
||||
index 3b2180f7fd..21ab27e247 100644
|
||||
--- a/thirdparty/enet/host.c
|
||||
+++ b/thirdparty/enet/host.c
|
||||
@@ -87,7 +87,7 @@ enet_host_create (const ENetAddress * address, size_t peerCount, size_t channelL
|
||||
host -> commandCount = 0;
|
||||
host -> bufferCount = 0;
|
||||
host -> checksum = NULL;
|
||||
- host -> receivedAddress.host = ENET_HOST_ANY;
|
||||
+ memset(host -> receivedAddress.host, 0, 16);
|
||||
host -> receivedAddress.port = 0;
|
||||
host -> receivedData = NULL;
|
||||
host -> receivedDataLength = 0;
|
||||
diff --git a/thirdparty/enet/protocol.c b/thirdparty/enet/protocol.c
|
||||
index 9d654f1d96..d7fe80f117 100644
|
||||
--- a/thirdparty/enet/protocol.c
|
||||
+++ b/thirdparty/enet/protocol.c
|
||||
@@ -309,7 +309,7 @@ enet_protocol_handle_connect (ENetHost * host, ENetProtocolHeader * header, ENet
|
||||
}
|
||||
else
|
||||
if (currentPeer -> state != ENET_PEER_STATE_CONNECTING &&
|
||||
- currentPeer -> address.host == host -> receivedAddress.host)
|
||||
+ enet_host_equal(currentPeer -> address.host, host -> receivedAddress.host))
|
||||
{
|
||||
if (currentPeer -> address.port == host -> receivedAddress.port &&
|
||||
currentPeer -> connectID == command -> connect.connectID)
|
||||
@@ -1031,9 +1031,8 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
|
||||
|
||||
if (peer -> state == ENET_PEER_STATE_DISCONNECTED ||
|
||||
peer -> state == ENET_PEER_STATE_ZOMBIE ||
|
||||
- ((host -> receivedAddress.host != peer -> address.host ||
|
||||
- host -> receivedAddress.port != peer -> address.port) &&
|
||||
- peer -> address.host != ENET_HOST_BROADCAST) ||
|
||||
+ (!enet_host_equal(host -> receivedAddress.host, peer -> address.host) ||
|
||||
+ host -> receivedAddress.port != peer -> address.port) ||
|
||||
(peer -> outgoingPeerID < ENET_PROTOCOL_MAXIMUM_PEER_ID &&
|
||||
sessionID != peer -> incomingSessionID))
|
||||
return 0;
|
||||
@@ -1075,7 +1074,7 @@ enet_protocol_handle_incoming_commands (ENetHost * host, ENetEvent * event)
|
||||
|
||||
if (peer != NULL)
|
||||
{
|
||||
- peer -> address.host = host -> receivedAddress.host;
|
||||
+ enet_address_set_ip(&(peer -> address), host -> receivedAddress.host, 16);
|
||||
peer -> address.port = host -> receivedAddress.port;
|
||||
peer -> incomingDataTotal += host -> receivedDataLength;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,851 +0,0 @@
|
||||
|
||||
/* networked_multiplayer_enet.cpp */
|
||||
|
||||
/* This file is part of: */
|
||||
/* PANDEMONIUM ENGINE */
|
||||
/* https://godotengine.org */
|
||||
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
|
||||
/* */
|
||||
/* 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. */
|
||||
|
||||
|
||||
#include "networked_multiplayer_enet.h"
|
||||
#include "core/io/ip.h"
|
||||
#include "core/io/marshalls.h"
|
||||
#include "core/os/os.h"
|
||||
|
||||
void NetworkedMultiplayerENet::set_transfer_mode(TransferMode p_mode) {
|
||||
transfer_mode = p_mode;
|
||||
}
|
||||
NetworkedMultiplayerPeer::TransferMode NetworkedMultiplayerENet::get_transfer_mode() const {
|
||||
return transfer_mode;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_target_peer(int p_peer) {
|
||||
target_peer = p_peer;
|
||||
}
|
||||
|
||||
int NetworkedMultiplayerENet::get_packet_peer() const {
|
||||
ERR_FAIL_COND_V_MSG(!active, 1, "The multiplayer instance isn't currently active.");
|
||||
ERR_FAIL_COND_V(incoming_packets.size() == 0, 1);
|
||||
|
||||
return incoming_packets.front()->get().from;
|
||||
}
|
||||
|
||||
int NetworkedMultiplayerENet::get_packet_channel() const {
|
||||
ERR_FAIL_COND_V_MSG(!active, -1, "The multiplayer instance isn't currently active.");
|
||||
ERR_FAIL_COND_V(incoming_packets.size() == 0, -1);
|
||||
|
||||
return incoming_packets.front()->get().channel;
|
||||
}
|
||||
|
||||
int NetworkedMultiplayerENet::get_last_packet_channel() const {
|
||||
ERR_FAIL_COND_V_MSG(!active, -1, "The multiplayer instance isn't currently active.");
|
||||
ERR_FAIL_COND_V(!current_packet.packet, -1);
|
||||
|
||||
return current_packet.channel;
|
||||
}
|
||||
|
||||
Error NetworkedMultiplayerENet::create_server(int p_port, int p_max_clients, int p_in_bandwidth, int p_out_bandwidth) {
|
||||
ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
|
||||
ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The port number must be set between 0 and 65535 (inclusive).");
|
||||
ERR_FAIL_COND_V_MSG(p_max_clients < 1 || p_max_clients > 4095, ERR_INVALID_PARAMETER, "The number of clients must be set between 1 and 4095 (inclusive).");
|
||||
ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
|
||||
ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
|
||||
ERR_FAIL_COND_V(dtls_enabled && (dtls_key.is_null() || dtls_cert.is_null()), ERR_INVALID_PARAMETER);
|
||||
|
||||
ENetAddress address;
|
||||
memset(&address, 0, sizeof(address));
|
||||
|
||||
#ifdef PANDEMONIUM_ENET
|
||||
if (bind_ip.is_wildcard()) {
|
||||
address.wildcard = 1;
|
||||
} else {
|
||||
enet_address_set_ip(&address, bind_ip.get_ipv6(), 16);
|
||||
}
|
||||
#else
|
||||
if (bind_ip.is_wildcard()) {
|
||||
address.host = 0;
|
||||
} else {
|
||||
ERR_FAIL_COND_V(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER);
|
||||
address.host = *(uint32_t *)bind_ip.get_ipv4();
|
||||
}
|
||||
#endif
|
||||
address.port = p_port;
|
||||
|
||||
host = enet_host_create(&address /* the address to bind the server host to */,
|
||||
p_max_clients /* allow up to 32 clients and/or outgoing connections */,
|
||||
channel_count /* allow up to channel_count to be used */,
|
||||
p_in_bandwidth /* limit incoming bandwidth if > 0 */,
|
||||
p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
|
||||
|
||||
ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create an ENet multiplayer server.");
|
||||
#ifdef PANDEMONIUM_ENET
|
||||
if (dtls_enabled) {
|
||||
enet_host_dtls_server_setup(host, dtls_key.ptr(), dtls_cert.ptr());
|
||||
}
|
||||
enet_host_refuse_new_connections(host, refuse_connections);
|
||||
#endif
|
||||
|
||||
active = true;
|
||||
server = true;
|
||||
refuse_connections = false;
|
||||
unique_id = 1;
|
||||
connection_status = CONNECTION_CONNECTED;
|
||||
return OK;
|
||||
}
|
||||
Error NetworkedMultiplayerENet::create_client(const String &p_address, int p_port, int p_in_bandwidth, int p_out_bandwidth, int p_client_port) {
|
||||
ERR_FAIL_COND_V_MSG(active, ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
|
||||
ERR_FAIL_COND_V_MSG(p_port < 0 || p_port > 65535, ERR_INVALID_PARAMETER, "The server port number must be set between 0 and 65535 (inclusive).");
|
||||
ERR_FAIL_COND_V_MSG(p_client_port < 0 || p_client_port > 65535, ERR_INVALID_PARAMETER, "The client port number must be set between 0 and 65535 (inclusive).");
|
||||
ERR_FAIL_COND_V_MSG(p_in_bandwidth < 0, ERR_INVALID_PARAMETER, "The incoming bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
|
||||
ERR_FAIL_COND_V_MSG(p_out_bandwidth < 0, ERR_INVALID_PARAMETER, "The outgoing bandwidth limit must be greater than or equal to 0 (0 disables the limit).");
|
||||
|
||||
if (p_client_port != 0) {
|
||||
ENetAddress c_client;
|
||||
|
||||
#ifdef PANDEMONIUM_ENET
|
||||
if (bind_ip.is_wildcard()) {
|
||||
c_client.wildcard = 1;
|
||||
} else {
|
||||
enet_address_set_ip(&c_client, bind_ip.get_ipv6(), 16);
|
||||
}
|
||||
#else
|
||||
if (bind_ip.is_wildcard()) {
|
||||
c_client.host = 0;
|
||||
} else {
|
||||
ERR_FAIL_COND_V_MSG(!bind_ip.is_ipv4(), ERR_INVALID_PARAMETER, "Wildcard IP addresses are only permitted in IPv4, not IPv6.");
|
||||
c_client.host = *(uint32_t *)bind_ip.get_ipv4();
|
||||
}
|
||||
#endif
|
||||
|
||||
c_client.port = p_client_port;
|
||||
|
||||
host = enet_host_create(&c_client /* create a client host */,
|
||||
1 /* only allow 1 outgoing connection */,
|
||||
channel_count /* allow up to channel_count to be used */,
|
||||
p_in_bandwidth /* limit incoming bandwidth if > 0 */,
|
||||
p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
|
||||
} else {
|
||||
host = enet_host_create(nullptr /* create a client host */,
|
||||
1 /* only allow 1 outgoing connection */,
|
||||
channel_count /* allow up to channel_count to be used */,
|
||||
p_in_bandwidth /* limit incoming bandwidth if > 0 */,
|
||||
p_out_bandwidth /* limit outgoing bandwidth if > 0 */);
|
||||
}
|
||||
|
||||
ERR_FAIL_COND_V_MSG(!host, ERR_CANT_CREATE, "Couldn't create the ENet client host.");
|
||||
#ifdef PANDEMONIUM_ENET
|
||||
if (dtls_enabled) {
|
||||
enet_host_dtls_client_setup(host, dtls_cert.ptr(), dtls_verify, dtls_hostname.empty() ? p_address.utf8().get_data() : dtls_hostname.utf8().get_data());
|
||||
}
|
||||
enet_host_refuse_new_connections(host, refuse_connections);
|
||||
#endif
|
||||
|
||||
IP_Address ip;
|
||||
if (p_address.is_valid_ip_address()) {
|
||||
ip = p_address;
|
||||
} else {
|
||||
#ifdef PANDEMONIUM_ENET
|
||||
ip = IP::get_singleton()->resolve_hostname(p_address);
|
||||
#else
|
||||
ip = IP::get_singleton()->resolve_hostname(p_address, IP::TYPE_IPV4);
|
||||
#endif
|
||||
|
||||
if (!ip.is_valid()) {
|
||||
enet_host_destroy(host);
|
||||
ERR_FAIL_V_MSG(ERR_CANT_RESOLVE, "Couldn't resolve the server IP address or domain name.");
|
||||
}
|
||||
}
|
||||
|
||||
ENetAddress address;
|
||||
#ifdef PANDEMONIUM_ENET
|
||||
enet_address_set_ip(&address, ip.get_ipv6(), 16);
|
||||
#else
|
||||
if (!ip.is_ipv4()) {
|
||||
enet_host_destroy(host);
|
||||
ERR_FAIL_V_MSG(ERR_INVALID_PARAMETER, "Connecting to an IPv6 server isn't supported when using vanilla ENet. Recompile Pandemonium with the bundled ENet library.");
|
||||
}
|
||||
address.host = *(uint32_t *)ip.get_ipv4();
|
||||
#endif
|
||||
address.port = p_port;
|
||||
|
||||
unique_id = _gen_unique_id();
|
||||
|
||||
// Initiate connection, allocating enough channels
|
||||
ENetPeer *peer = enet_host_connect(host, &address, channel_count, unique_id);
|
||||
|
||||
if (peer == nullptr) {
|
||||
enet_host_destroy(host);
|
||||
ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Couldn't connect to the ENet multiplayer server.");
|
||||
}
|
||||
|
||||
// Technically safe to ignore the peer or anything else.
|
||||
|
||||
connection_status = CONNECTION_CONNECTING;
|
||||
active = true;
|
||||
server = false;
|
||||
refuse_connections = false;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::poll() {
|
||||
ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active.");
|
||||
|
||||
_pop_current_packet();
|
||||
|
||||
if (!host || !active) { // Might be disconnected
|
||||
return;
|
||||
}
|
||||
|
||||
ENetEvent event;
|
||||
int ret = enet_host_service(host, &event, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
ERR_FAIL_MSG("Enet host service error");
|
||||
} else if (ret == 0) {
|
||||
return; // No events
|
||||
}
|
||||
|
||||
/* Keep servicing until there are no available events left in the queue. */
|
||||
do {
|
||||
if (!host || !active) { // Check again after every event
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.type) {
|
||||
case ENET_EVENT_TYPE_CONNECT: {
|
||||
// Store any relevant client information here.
|
||||
|
||||
if (server && refuse_connections) {
|
||||
enet_peer_reset(event.peer);
|
||||
break;
|
||||
}
|
||||
|
||||
// A client joined with an invalid ID (negative values, 0, and 1 are reserved).
|
||||
// Probably trying to exploit us.
|
||||
if (server && ((int)event.data < 2 || peer_map.has((int)event.data))) {
|
||||
enet_peer_reset(event.peer);
|
||||
ERR_CONTINUE(true);
|
||||
}
|
||||
|
||||
int *new_id = memnew(int);
|
||||
*new_id = event.data;
|
||||
|
||||
if (*new_id == 0) { // Data zero is sent by server (enet won't let you configure this). Server is always 1.
|
||||
*new_id = 1;
|
||||
}
|
||||
|
||||
event.peer->data = new_id;
|
||||
|
||||
peer_map[*new_id] = event.peer;
|
||||
|
||||
connection_status = CONNECTION_CONNECTED; // If connecting, this means it connected to something!
|
||||
|
||||
emit_signal("peer_connected", *new_id);
|
||||
|
||||
if (server) {
|
||||
// Do not notify other peers when server_relay is disabled.
|
||||
if (!server_relay) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Someone connected, notify all the peers available
|
||||
for (RBMap<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) {
|
||||
if (E->key() == *new_id) {
|
||||
continue;
|
||||
}
|
||||
// Send existing peers to new peer
|
||||
ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE);
|
||||
encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]);
|
||||
encode_uint32(E->key(), &packet->data[4]);
|
||||
enet_peer_send(event.peer, SYSCH_CONFIG, packet);
|
||||
// Send the new peer to existing peers
|
||||
packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE);
|
||||
encode_uint32(SYSMSG_ADD_PEER, &packet->data[0]);
|
||||
encode_uint32(*new_id, &packet->data[4]);
|
||||
enet_peer_send(E->get(), SYSCH_CONFIG, packet);
|
||||
}
|
||||
} else {
|
||||
emit_signal("connection_succeeded");
|
||||
}
|
||||
|
||||
} break;
|
||||
case ENET_EVENT_TYPE_DISCONNECT: {
|
||||
// Reset the peer's client information.
|
||||
|
||||
int *id = (int *)event.peer->data;
|
||||
|
||||
if (!id) {
|
||||
if (!server) {
|
||||
emit_signal("connection_failed");
|
||||
}
|
||||
// Never fully connected.
|
||||
break;
|
||||
}
|
||||
|
||||
if (!server) {
|
||||
// Client just disconnected from server.
|
||||
emit_signal("server_disconnected");
|
||||
close_connection();
|
||||
return;
|
||||
} else if (server_relay) {
|
||||
// Server just received a client disconnect and is in relay mode, notify everyone else.
|
||||
for (RBMap<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) {
|
||||
if (E->key() == *id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE);
|
||||
encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]);
|
||||
encode_uint32(*id, &packet->data[4]);
|
||||
enet_peer_send(E->get(), SYSCH_CONFIG, packet);
|
||||
}
|
||||
}
|
||||
|
||||
emit_signal("peer_disconnected", *id);
|
||||
peer_map.erase(*id);
|
||||
memdelete(id);
|
||||
} break;
|
||||
case ENET_EVENT_TYPE_RECEIVE: {
|
||||
if (event.channelID == SYSCH_CONFIG) {
|
||||
// Some config message
|
||||
ERR_CONTINUE(event.packet->dataLength < 8);
|
||||
|
||||
// Only server can send config messages
|
||||
ERR_CONTINUE(server);
|
||||
|
||||
int msg = decode_uint32(&event.packet->data[0]);
|
||||
int id = decode_uint32(&event.packet->data[4]);
|
||||
|
||||
switch (msg) {
|
||||
case SYSMSG_ADD_PEER: {
|
||||
peer_map[id] = NULL;
|
||||
emit_signal("peer_connected", id);
|
||||
|
||||
} break;
|
||||
case SYSMSG_REMOVE_PEER: {
|
||||
peer_map.erase(id);
|
||||
emit_signal("peer_disconnected", id);
|
||||
} break;
|
||||
}
|
||||
|
||||
enet_packet_destroy(event.packet);
|
||||
} else if (event.channelID < channel_count) {
|
||||
Packet packet;
|
||||
packet.packet = event.packet;
|
||||
|
||||
uint32_t *id = (uint32_t *)event.peer->data;
|
||||
|
||||
ERR_CONTINUE(event.packet->dataLength < 8);
|
||||
|
||||
uint32_t source = decode_uint32(&event.packet->data[0]);
|
||||
int target = decode_uint32(&event.packet->data[4]);
|
||||
|
||||
packet.from = source;
|
||||
packet.channel = event.channelID;
|
||||
|
||||
if (server) {
|
||||
// Someone is cheating and trying to fake the source!
|
||||
ERR_CONTINUE(source != *id);
|
||||
|
||||
packet.from = *id;
|
||||
|
||||
if (target == 1) {
|
||||
// To myself and only myself
|
||||
incoming_packets.push_back(packet);
|
||||
} else if (!server_relay) {
|
||||
// When relaying is disabled, other destinations will only be processed by the server.
|
||||
if (target == 0 || target < -1) {
|
||||
incoming_packets.push_back(packet);
|
||||
}
|
||||
continue;
|
||||
} else if (target == 0) {
|
||||
// Re-send to everyone but sender :|
|
||||
|
||||
incoming_packets.push_back(packet);
|
||||
// And make copies for sending
|
||||
for (RBMap<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) {
|
||||
if (uint32_t(E->key()) == source) { // Do not resend to self
|
||||
continue;
|
||||
}
|
||||
|
||||
ENetPacket *packet2 = enet_packet_create(packet.packet->data, packet.packet->dataLength, packet.packet->flags);
|
||||
|
||||
enet_peer_send(E->get(), event.channelID, packet2);
|
||||
}
|
||||
|
||||
} else if (target < 0) {
|
||||
// To all but one
|
||||
|
||||
// And make copies for sending
|
||||
for (RBMap<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) {
|
||||
if (uint32_t(E->key()) == source || E->key() == -target) { // Do not resend to self, also do not send to excluded
|
||||
continue;
|
||||
}
|
||||
|
||||
ENetPacket *packet2 = enet_packet_create(packet.packet->data, packet.packet->dataLength, packet.packet->flags);
|
||||
|
||||
enet_peer_send(E->get(), event.channelID, packet2);
|
||||
}
|
||||
|
||||
if (-target != 1) {
|
||||
// Server is not excluded
|
||||
incoming_packets.push_back(packet);
|
||||
} else {
|
||||
// Server is excluded, erase packet
|
||||
enet_packet_destroy(packet.packet);
|
||||
}
|
||||
|
||||
} else {
|
||||
// To someone else, specifically
|
||||
ERR_CONTINUE(!peer_map.has(target));
|
||||
enet_peer_send(peer_map[target], event.channelID, packet.packet);
|
||||
}
|
||||
} else {
|
||||
incoming_packets.push_back(packet);
|
||||
}
|
||||
|
||||
// Destroy packet later
|
||||
} else {
|
||||
ERR_CONTINUE(true);
|
||||
}
|
||||
|
||||
} break;
|
||||
case ENET_EVENT_TYPE_NONE: {
|
||||
// Do nothing
|
||||
} break;
|
||||
}
|
||||
} while (enet_host_check_events(host, &event) > 0);
|
||||
}
|
||||
|
||||
bool NetworkedMultiplayerENet::is_server() const {
|
||||
ERR_FAIL_COND_V_MSG(!active, false, "The multiplayer instance isn't currently active.");
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::close_connection(uint32_t wait_usec) {
|
||||
if (!active) {
|
||||
return;
|
||||
}
|
||||
|
||||
_pop_current_packet();
|
||||
|
||||
bool peers_disconnected = false;
|
||||
for (RBMap<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) {
|
||||
if (E->get()) {
|
||||
enet_peer_disconnect_now(E->get(), unique_id);
|
||||
int *id = (int *)(E->get()->data);
|
||||
memdelete(id);
|
||||
peers_disconnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (peers_disconnected) {
|
||||
enet_host_flush(host);
|
||||
|
||||
if (wait_usec > 0) {
|
||||
OS::get_singleton()->delay_usec(wait_usec); // Wait for disconnection packets to send
|
||||
}
|
||||
}
|
||||
|
||||
enet_host_destroy(host);
|
||||
active = false;
|
||||
incoming_packets.clear();
|
||||
peer_map.clear();
|
||||
unique_id = 1; // Server is 1
|
||||
connection_status = CONNECTION_DISCONNECTED;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::disconnect_peer(int p_peer, bool now) {
|
||||
ERR_FAIL_COND_MSG(!active, "The multiplayer instance isn't currently active.");
|
||||
ERR_FAIL_COND_MSG(!is_server(), "Can't disconnect a peer when not acting as a server.");
|
||||
ERR_FAIL_COND_MSG(!peer_map.has(p_peer), vformat("Peer ID %d not found in the list of peers.", p_peer));
|
||||
|
||||
if (now) {
|
||||
int *id = (int *)peer_map[p_peer]->data;
|
||||
enet_peer_disconnect_now(peer_map[p_peer], 0);
|
||||
|
||||
// enet_peer_disconnect_now doesn't generate ENET_EVENT_TYPE_DISCONNECT,
|
||||
// notify everyone else, send disconnect signal & remove from peer_map like in poll()
|
||||
if (server_relay) {
|
||||
for (RBMap<int, ENetPeer *>::Element *E = peer_map.front(); E; E = E->next()) {
|
||||
if (E->key() == p_peer) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ENetPacket *packet = enet_packet_create(nullptr, 8, ENET_PACKET_FLAG_RELIABLE);
|
||||
encode_uint32(SYSMSG_REMOVE_PEER, &packet->data[0]);
|
||||
encode_uint32(p_peer, &packet->data[4]);
|
||||
enet_peer_send(E->get(), SYSCH_CONFIG, packet);
|
||||
}
|
||||
}
|
||||
|
||||
if (id) {
|
||||
memdelete(id);
|
||||
}
|
||||
|
||||
emit_signal("peer_disconnected", p_peer);
|
||||
peer_map.erase(p_peer);
|
||||
} else {
|
||||
enet_peer_disconnect_later(peer_map[p_peer], 0);
|
||||
}
|
||||
}
|
||||
|
||||
int NetworkedMultiplayerENet::get_available_packet_count() const {
|
||||
return incoming_packets.size();
|
||||
}
|
||||
|
||||
Error NetworkedMultiplayerENet::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
|
||||
ERR_FAIL_COND_V_MSG(incoming_packets.size() == 0, ERR_UNAVAILABLE, "No incoming packets available.");
|
||||
|
||||
_pop_current_packet();
|
||||
|
||||
current_packet = incoming_packets.front()->get();
|
||||
incoming_packets.pop_front();
|
||||
|
||||
*r_buffer = (const uint8_t *)(¤t_packet.packet->data[8]);
|
||||
r_buffer_size = current_packet.packet->dataLength - 8;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error NetworkedMultiplayerENet::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
|
||||
ERR_FAIL_COND_V_MSG(!active, ERR_UNCONFIGURED, "The multiplayer instance isn't currently active.");
|
||||
ERR_FAIL_COND_V_MSG(connection_status != CONNECTION_CONNECTED, ERR_UNCONFIGURED, "The multiplayer instance isn't currently connected to any server or client.");
|
||||
|
||||
int packet_flags = 0;
|
||||
int channel = SYSCH_RELIABLE;
|
||||
|
||||
switch (transfer_mode) {
|
||||
case TRANSFER_MODE_UNRELIABLE: {
|
||||
if (always_ordered) {
|
||||
packet_flags = 0;
|
||||
} else {
|
||||
packet_flags = ENET_PACKET_FLAG_UNSEQUENCED;
|
||||
}
|
||||
channel = SYSCH_UNRELIABLE;
|
||||
packet_flags |= ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT;
|
||||
} break;
|
||||
case TRANSFER_MODE_UNRELIABLE_ORDERED: {
|
||||
packet_flags = ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT;
|
||||
channel = SYSCH_UNRELIABLE;
|
||||
} break;
|
||||
case TRANSFER_MODE_RELIABLE: {
|
||||
packet_flags = ENET_PACKET_FLAG_RELIABLE;
|
||||
channel = SYSCH_RELIABLE;
|
||||
} break;
|
||||
}
|
||||
|
||||
if (transfer_channel > SYSCH_CONFIG) {
|
||||
channel = transfer_channel;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if ((packet_flags & ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT) && p_buffer_size + 8 > ENET_HOST_DEFAULT_MTU) {
|
||||
WARN_PRINT_ONCE(vformat("Sending %d bytes unrealiably which is above the MTU (%d), this will result in higher packet loss", p_buffer_size + 8, host->mtu));
|
||||
}
|
||||
#endif
|
||||
|
||||
RBMap<int, ENetPeer *>::Element *E = nullptr;
|
||||
|
||||
if (target_peer != 0) {
|
||||
E = peer_map.find(ABS(target_peer));
|
||||
ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, vformat("Invalid target peer: %d", target_peer));
|
||||
}
|
||||
|
||||
ENetPacket *packet = enet_packet_create(nullptr, p_buffer_size + 8, packet_flags);
|
||||
encode_uint32(unique_id, &packet->data[0]); // Source ID
|
||||
encode_uint32(target_peer, &packet->data[4]); // Dest ID
|
||||
memcpy(&packet->data[8], p_buffer, p_buffer_size);
|
||||
|
||||
if (server) {
|
||||
if (target_peer == 0) {
|
||||
enet_host_broadcast(host, channel, packet);
|
||||
} else if (target_peer < 0) {
|
||||
// Send to all but one
|
||||
// and make copies for sending
|
||||
|
||||
int exclude = -target_peer;
|
||||
|
||||
for (RBMap<int, ENetPeer *>::Element *F = peer_map.front(); F; F = F->next()) {
|
||||
if (F->key() == exclude) { // Exclude packet
|
||||
continue;
|
||||
}
|
||||
|
||||
ENetPacket *packet2 = enet_packet_create(packet->data, packet->dataLength, packet_flags);
|
||||
|
||||
enet_peer_send(F->get(), channel, packet2);
|
||||
}
|
||||
|
||||
enet_packet_destroy(packet); // Original packet no longer needed
|
||||
} else {
|
||||
enet_peer_send(E->get(), channel, packet);
|
||||
}
|
||||
} else {
|
||||
ERR_FAIL_COND_V(!peer_map.has(1), ERR_BUG);
|
||||
enet_peer_send(peer_map[1], channel, packet); // Send to server for broadcast
|
||||
}
|
||||
|
||||
enet_host_flush(host);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int NetworkedMultiplayerENet::get_max_packet_size() const {
|
||||
return 1 << 24; // Anything is good
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::_pop_current_packet() {
|
||||
if (current_packet.packet) {
|
||||
enet_packet_destroy(current_packet.packet);
|
||||
current_packet.packet = nullptr;
|
||||
current_packet.from = 0;
|
||||
current_packet.channel = -1;
|
||||
}
|
||||
}
|
||||
|
||||
NetworkedMultiplayerPeer::ConnectionStatus NetworkedMultiplayerENet::get_connection_status() const {
|
||||
return connection_status;
|
||||
}
|
||||
|
||||
uint32_t NetworkedMultiplayerENet::_gen_unique_id() const {
|
||||
uint32_t hash = 0;
|
||||
|
||||
while (hash == 0 || hash == 1) {
|
||||
hash = hash_djb2_one_32(
|
||||
(uint32_t)OS::get_singleton()->get_ticks_usec());
|
||||
hash = hash_djb2_one_32(
|
||||
(uint32_t)OS::get_singleton()->get_unix_time(), hash);
|
||||
hash = hash_djb2_one_32(
|
||||
(uint32_t)OS::get_singleton()->get_user_data_dir().hash64(), hash);
|
||||
hash = hash_djb2_one_32(
|
||||
(uint32_t)((uint64_t)this), hash); // Rely on ASLR heap
|
||||
hash = hash_djb2_one_32(
|
||||
(uint32_t)((uint64_t)&hash), hash); // Rely on ASLR stack
|
||||
|
||||
hash = hash & 0x7FFFFFFF; // Make it compatible with unsigned, since negative ID is used for exclusion
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
int NetworkedMultiplayerENet::get_unique_id() const {
|
||||
ERR_FAIL_COND_V_MSG(!active, 0, "The multiplayer instance isn't currently active.");
|
||||
return unique_id;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_refuse_new_connections(bool p_enable) {
|
||||
refuse_connections = p_enable;
|
||||
#ifdef PANDEMONIUM_ENET
|
||||
if (active) {
|
||||
enet_host_refuse_new_connections(host, p_enable);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool NetworkedMultiplayerENet::is_refusing_new_connections() const {
|
||||
return refuse_connections;
|
||||
}
|
||||
|
||||
IP_Address NetworkedMultiplayerENet::get_peer_address(int p_peer_id) const {
|
||||
ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), IP_Address(), vformat("Peer ID %d not found in the list of peers.", p_peer_id));
|
||||
ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, IP_Address(), "Can't get the address of peers other than the server (ID -1) when acting as a client.");
|
||||
ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == NULL, IP_Address(), vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
|
||||
|
||||
IP_Address out;
|
||||
#ifdef PANDEMONIUM_ENET
|
||||
out.set_ipv6((uint8_t *)&(peer_map[p_peer_id]->address.host));
|
||||
#else
|
||||
out.set_ipv4((uint8_t *)&(peer_map[p_peer_id]->address.host));
|
||||
#endif
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
int NetworkedMultiplayerENet::get_peer_port(int p_peer_id) const {
|
||||
ERR_FAIL_COND_V_MSG(!peer_map.has(p_peer_id), 0, vformat("Peer ID %d not found in the list of peers.", p_peer_id));
|
||||
ERR_FAIL_COND_V_MSG(!is_server() && p_peer_id != 1, 0, "Can't get the address of peers other than the server (ID -1) when acting as a client.");
|
||||
ERR_FAIL_COND_V_MSG(peer_map[p_peer_id] == NULL, 0, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
|
||||
#ifdef PANDEMONIUM_ENET
|
||||
return peer_map[p_peer_id]->address.port;
|
||||
#else
|
||||
return peer_map[p_peer_id]->address.port;
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max) {
|
||||
ERR_FAIL_COND_MSG(!peer_map.has(p_peer_id), vformat("Peer ID %d not found in the list of peers.", p_peer_id));
|
||||
ERR_FAIL_COND_MSG(!is_server() && p_peer_id != 1, "Can't change the timeout of peers other then the server when acting as a client.");
|
||||
ERR_FAIL_COND_MSG(peer_map[p_peer_id] == nullptr, vformat("Peer ID %d found in the list of peers, but is null.", p_peer_id));
|
||||
ERR_FAIL_COND_MSG(p_timeout_limit > p_timeout_min || p_timeout_min > p_timeout_max, "Timeout limit must be less than minimum timeout, which itself must be less then maximum timeout");
|
||||
enet_peer_timeout(peer_map[p_peer_id], p_timeout_limit, p_timeout_min, p_timeout_max);
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_transfer_channel(int p_channel) {
|
||||
ERR_FAIL_COND_MSG(p_channel < -1 || p_channel >= channel_count, vformat("The transfer channel must be set between 0 and %d, inclusive (got %d).", channel_count - 1, p_channel));
|
||||
ERR_FAIL_COND_MSG(p_channel == SYSCH_CONFIG, vformat("The channel %d is reserved.", SYSCH_CONFIG));
|
||||
transfer_channel = p_channel;
|
||||
}
|
||||
|
||||
int NetworkedMultiplayerENet::get_transfer_channel() const {
|
||||
return transfer_channel;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_channel_count(int p_channel) {
|
||||
ERR_FAIL_COND_MSG(active, "The channel count can't be set while the multiplayer instance is active.");
|
||||
ERR_FAIL_COND_MSG(p_channel < SYSCH_MAX, vformat("The channel count must be greater than or equal to %d to account for reserved channels (got %d).", SYSCH_MAX, p_channel));
|
||||
channel_count = p_channel;
|
||||
}
|
||||
|
||||
int NetworkedMultiplayerENet::get_channel_count() const {
|
||||
return channel_count;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_always_ordered(bool p_ordered) {
|
||||
always_ordered = p_ordered;
|
||||
}
|
||||
|
||||
bool NetworkedMultiplayerENet::is_always_ordered() const {
|
||||
return always_ordered;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_server_relay_enabled(bool p_enabled) {
|
||||
ERR_FAIL_COND_MSG(active, "Server relaying can't be toggled while the multiplayer instance is active.");
|
||||
|
||||
server_relay = p_enabled;
|
||||
}
|
||||
|
||||
bool NetworkedMultiplayerENet::is_server_relay_enabled() const {
|
||||
return server_relay;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("create_server", "port", "max_clients", "in_bandwidth", "out_bandwidth"), &NetworkedMultiplayerENet::create_server, DEFVAL(32), DEFVAL(0), DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("create_client", "address", "port", "in_bandwidth", "out_bandwidth", "client_port"), &NetworkedMultiplayerENet::create_client, DEFVAL(0), DEFVAL(0), DEFVAL(0));
|
||||
ClassDB::bind_method(D_METHOD("close_connection", "wait_usec"), &NetworkedMultiplayerENet::close_connection, DEFVAL(100));
|
||||
ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "now"), &NetworkedMultiplayerENet::disconnect_peer, DEFVAL(false));
|
||||
ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &NetworkedMultiplayerENet::set_bind_ip);
|
||||
ClassDB::bind_method(D_METHOD("set_dtls_enabled", "enabled"), &NetworkedMultiplayerENet::set_dtls_enabled);
|
||||
ClassDB::bind_method(D_METHOD("is_dtls_enabled"), &NetworkedMultiplayerENet::is_dtls_enabled);
|
||||
ClassDB::bind_method(D_METHOD("set_dtls_key", "key"), &NetworkedMultiplayerENet::set_dtls_key);
|
||||
ClassDB::bind_method(D_METHOD("set_dtls_certificate", "certificate"), &NetworkedMultiplayerENet::set_dtls_certificate);
|
||||
ClassDB::bind_method(D_METHOD("set_dtls_verify_enabled", "enabled"), &NetworkedMultiplayerENet::set_dtls_verify_enabled);
|
||||
ClassDB::bind_method(D_METHOD("is_dtls_verify_enabled"), &NetworkedMultiplayerENet::is_dtls_verify_enabled);
|
||||
ClassDB::bind_method(D_METHOD("set_dtls_hostname", "hostname"), &NetworkedMultiplayerENet::set_dtls_hostname);
|
||||
ClassDB::bind_method(D_METHOD("get_dtls_hostname"), &NetworkedMultiplayerENet::get_dtls_hostname);
|
||||
ClassDB::bind_method(D_METHOD("get_peer_address", "id"), &NetworkedMultiplayerENet::get_peer_address);
|
||||
ClassDB::bind_method(D_METHOD("get_peer_port", "id"), &NetworkedMultiplayerENet::get_peer_port);
|
||||
ClassDB::bind_method(D_METHOD("set_peer_timeout", "id", "timeout_limit", "timeout_min", "timeout_max"), &NetworkedMultiplayerENet::set_peer_timeout);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_packet_channel"), &NetworkedMultiplayerENet::get_packet_channel);
|
||||
ClassDB::bind_method(D_METHOD("get_last_packet_channel"), &NetworkedMultiplayerENet::get_last_packet_channel);
|
||||
ClassDB::bind_method(D_METHOD("set_transfer_channel", "channel"), &NetworkedMultiplayerENet::set_transfer_channel);
|
||||
ClassDB::bind_method(D_METHOD("get_transfer_channel"), &NetworkedMultiplayerENet::get_transfer_channel);
|
||||
ClassDB::bind_method(D_METHOD("set_channel_count", "channels"), &NetworkedMultiplayerENet::set_channel_count);
|
||||
ClassDB::bind_method(D_METHOD("get_channel_count"), &NetworkedMultiplayerENet::get_channel_count);
|
||||
ClassDB::bind_method(D_METHOD("set_always_ordered", "ordered"), &NetworkedMultiplayerENet::set_always_ordered);
|
||||
ClassDB::bind_method(D_METHOD("is_always_ordered"), &NetworkedMultiplayerENet::is_always_ordered);
|
||||
ClassDB::bind_method(D_METHOD("set_server_relay_enabled", "enabled"), &NetworkedMultiplayerENet::set_server_relay_enabled);
|
||||
ClassDB::bind_method(D_METHOD("is_server_relay_enabled"), &NetworkedMultiplayerENet::is_server_relay_enabled);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "transfer_channel"), "set_transfer_channel", "get_transfer_channel");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "channel_count"), "set_channel_count", "get_channel_count");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "always_ordered"), "set_always_ordered", "is_always_ordered");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "server_relay"), "set_server_relay_enabled", "is_server_relay_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dtls_verify"), "set_dtls_verify_enabled", "is_dtls_verify_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING, "dtls_hostname"), "set_dtls_hostname", "get_dtls_hostname");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_dtls"), "set_dtls_enabled", "is_dtls_enabled");
|
||||
}
|
||||
|
||||
NetworkedMultiplayerENet::NetworkedMultiplayerENet() {
|
||||
active = false;
|
||||
server = false;
|
||||
refuse_connections = false;
|
||||
server_relay = true;
|
||||
unique_id = 0;
|
||||
target_peer = 0;
|
||||
current_packet.packet = nullptr;
|
||||
transfer_mode = TRANSFER_MODE_RELIABLE;
|
||||
channel_count = SYSCH_MAX;
|
||||
transfer_channel = -1;
|
||||
always_ordered = false;
|
||||
connection_status = CONNECTION_DISCONNECTED;
|
||||
|
||||
bind_ip = IP_Address("*");
|
||||
|
||||
dtls_enabled = false;
|
||||
dtls_verify = true;
|
||||
}
|
||||
|
||||
NetworkedMultiplayerENet::~NetworkedMultiplayerENet() {
|
||||
if (active) {
|
||||
close_connection();
|
||||
}
|
||||
}
|
||||
|
||||
// Sets IP for ENet to bind when using create_server or create_client
|
||||
// if no IP is set, then ENet bind to ENET_HOST_ANY
|
||||
void NetworkedMultiplayerENet::set_bind_ip(const IP_Address &p_ip) {
|
||||
ERR_FAIL_COND_MSG(!p_ip.is_valid() && !p_ip.is_wildcard(), vformat("Invalid bind IP address: %s", String(p_ip)));
|
||||
|
||||
bind_ip = p_ip;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_dtls_enabled(bool p_enabled) {
|
||||
ERR_FAIL_COND(active);
|
||||
dtls_enabled = p_enabled;
|
||||
}
|
||||
|
||||
bool NetworkedMultiplayerENet::is_dtls_enabled() const {
|
||||
return dtls_enabled;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_dtls_verify_enabled(bool p_enabled) {
|
||||
ERR_FAIL_COND(active);
|
||||
dtls_verify = p_enabled;
|
||||
}
|
||||
|
||||
bool NetworkedMultiplayerENet::is_dtls_verify_enabled() const {
|
||||
return dtls_verify;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_dtls_key(Ref<CryptoKey> p_key) {
|
||||
ERR_FAIL_COND(active);
|
||||
dtls_key = p_key;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_dtls_certificate(Ref<X509Certificate> p_cert) {
|
||||
ERR_FAIL_COND(active);
|
||||
dtls_cert = p_cert;
|
||||
}
|
||||
|
||||
void NetworkedMultiplayerENet::set_dtls_hostname(const String &p_hostname) {
|
||||
ERR_FAIL_COND(active);
|
||||
dtls_hostname = p_hostname;
|
||||
}
|
||||
|
||||
String NetworkedMultiplayerENet::get_dtls_hostname() const {
|
||||
return dtls_hostname;
|
||||
}
|
@ -1,137 +0,0 @@
|
||||
#ifndef NETWORKED_MULTIPLAYER_ENET_H
|
||||
#define NETWORKED_MULTIPLAYER_ENET_H
|
||||
|
||||
/* networked_multiplayer_enet.h */
|
||||
|
||||
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/io/networked_multiplayer_peer.h"
|
||||
|
||||
#include <enet/enet.h>
|
||||
|
||||
class NetworkedMultiplayerENet : public NetworkedMultiplayerPeer {
|
||||
GDCLASS(NetworkedMultiplayerENet, NetworkedMultiplayerPeer);
|
||||
|
||||
private:
|
||||
enum {
|
||||
SYSMSG_ADD_PEER,
|
||||
SYSMSG_REMOVE_PEER
|
||||
};
|
||||
|
||||
enum {
|
||||
SYSCH_CONFIG,
|
||||
SYSCH_RELIABLE,
|
||||
SYSCH_UNRELIABLE,
|
||||
SYSCH_MAX
|
||||
};
|
||||
|
||||
bool active;
|
||||
bool server;
|
||||
|
||||
uint32_t unique_id;
|
||||
|
||||
int target_peer;
|
||||
TransferMode transfer_mode;
|
||||
int transfer_channel;
|
||||
int channel_count;
|
||||
bool always_ordered;
|
||||
|
||||
ENetEvent event;
|
||||
ENetPeer *peer;
|
||||
ENetHost *host;
|
||||
|
||||
bool refuse_connections;
|
||||
bool server_relay;
|
||||
|
||||
ConnectionStatus connection_status;
|
||||
|
||||
RBMap<int, ENetPeer *> peer_map;
|
||||
|
||||
struct Packet {
|
||||
ENetPacket *packet;
|
||||
int from;
|
||||
int channel;
|
||||
};
|
||||
|
||||
List<Packet> incoming_packets;
|
||||
|
||||
Packet current_packet;
|
||||
|
||||
uint32_t _gen_unique_id() const;
|
||||
void _pop_current_packet();
|
||||
|
||||
Vector<uint8_t> src_compressor_mem;
|
||||
Vector<uint8_t> dst_compressor_mem;
|
||||
|
||||
IP_Address bind_ip;
|
||||
|
||||
bool dtls_enabled;
|
||||
Ref<CryptoKey> dtls_key;
|
||||
Ref<X509Certificate> dtls_cert;
|
||||
bool dtls_verify;
|
||||
String dtls_hostname;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
virtual void set_transfer_mode(TransferMode p_mode);
|
||||
virtual TransferMode get_transfer_mode() const;
|
||||
virtual void set_target_peer(int p_peer);
|
||||
|
||||
virtual int get_packet_peer() const;
|
||||
|
||||
virtual IP_Address get_peer_address(int p_peer_id) const;
|
||||
virtual int get_peer_port(int p_peer_id) const;
|
||||
void set_peer_timeout(int p_peer_id, int p_timeout_limit, int p_timeout_min, int p_timeout_max);
|
||||
|
||||
Error create_server(int p_port, int p_max_clients = 32, int p_in_bandwidth = 0, int p_out_bandwidth = 0);
|
||||
Error create_client(const String &p_address, int p_port, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_client_port = 0);
|
||||
|
||||
void close_connection(uint32_t wait_usec = 100);
|
||||
|
||||
void disconnect_peer(int p_peer, bool now = false);
|
||||
|
||||
virtual void poll();
|
||||
|
||||
virtual bool is_server() const;
|
||||
|
||||
virtual int get_available_packet_count() const;
|
||||
virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); ///< buffer is GONE after next get_packet
|
||||
virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
|
||||
|
||||
virtual int get_max_packet_size() const;
|
||||
|
||||
virtual ConnectionStatus get_connection_status() const;
|
||||
|
||||
virtual void set_refuse_new_connections(bool p_enable);
|
||||
virtual bool is_refusing_new_connections() const;
|
||||
|
||||
virtual int get_unique_id() const;
|
||||
|
||||
int get_packet_channel() const;
|
||||
int get_last_packet_channel() const;
|
||||
void set_transfer_channel(int p_channel);
|
||||
int get_transfer_channel() const;
|
||||
void set_channel_count(int p_channel);
|
||||
int get_channel_count() const;
|
||||
void set_always_ordered(bool p_ordered);
|
||||
bool is_always_ordered() const;
|
||||
void set_server_relay_enabled(bool p_enabled);
|
||||
bool is_server_relay_enabled() const;
|
||||
|
||||
NetworkedMultiplayerENet();
|
||||
~NetworkedMultiplayerENet();
|
||||
|
||||
void set_bind_ip(const IP_Address &p_ip);
|
||||
void set_dtls_enabled(bool p_enabled);
|
||||
bool is_dtls_enabled() const;
|
||||
void set_dtls_verify_enabled(bool p_enabled);
|
||||
bool is_dtls_verify_enabled() const;
|
||||
void set_dtls_key(Ref<CryptoKey> p_key);
|
||||
void set_dtls_certificate(Ref<X509Certificate> p_cert);
|
||||
void set_dtls_hostname(const String &p_hostname);
|
||||
String get_dtls_hostname() const;
|
||||
};
|
||||
|
||||
#endif // NETWORKED_MULTIPLAYER_ENET_H
|
@ -1,31 +0,0 @@
|
||||
|
||||
/* register_types.cpp */
|
||||
|
||||
|
||||
#include "register_types.h"
|
||||
#include "core/error/error_macros.h"
|
||||
#include "networked_multiplayer_enet.h"
|
||||
|
||||
static bool enet_ok = false;
|
||||
|
||||
void register_enet_types(ModuleRegistrationLevel p_level) {
|
||||
if (p_level == MODULE_REGISTRATION_LEVEL_SINGLETON) {
|
||||
if (enet_initialize() != 0) {
|
||||
ERR_PRINT("ENet initialization failure");
|
||||
} else {
|
||||
enet_ok = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_level == MODULE_REGISTRATION_LEVEL_SCENE) {
|
||||
ClassDB::register_class<NetworkedMultiplayerENet>();
|
||||
}
|
||||
}
|
||||
|
||||
void unregister_enet_types(ModuleRegistrationLevel p_level) {
|
||||
if (p_level == MODULE_REGISTRATION_LEVEL_SINGLETON) {
|
||||
if (enet_ok) {
|
||||
enet_deinitialize();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#ifndef ENET_REGISTER_TYPES_H
|
||||
#define ENET_REGISTER_TYPES_H
|
||||
|
||||
/* register_types.h */
|
||||
|
||||
|
||||
#include "modules/register_module_types.h"
|
||||
|
||||
void register_enet_types(ModuleRegistrationLevel p_level);
|
||||
void unregister_enet_types(ModuleRegistrationLevel p_level);
|
||||
|
||||
#endif // ENET_REGISTER_TYPES_H
|
Loading…
Reference in New Issue
Block a user