2,303 changes: 2,303 additions & 0 deletions Externals/enet/Doxyfile

Large diffs are not rendered by default.

191 changes: 191 additions & 0 deletions Externals/enet/DoxygenLayout.xml
@@ -0,0 +1,191 @@
<doxygenlayout version="1.0">
<!-- Generated by doxygen 1.8.6 -->
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title="Home"/>
<tab type="user" visible="yes" title="Features" url="@ref Features" />
<tab type="user" visible="yes" title="Downloads" url="@ref Downloads" />
<tab type="user" visible="yes" title="Installation" url="@ref Installation" />
<tab type="user" visible="yes" title="Tutorial" url="@ref Tutorial" />
<tab type="user" visible="yes" title="Mailing List" url="@ref MailingList" />
<tab type="user" visible="yes" title="IRC Channel" url="@ref IRCChannel" />
<tab type="user" visible="yes" title="FAQ" url="@ref FAQ" />
<tab type="user" visible="yes" title="License" url="@ref License" />
<tab type="usergroup" visible="yes" title="Documentation" briefdescription="Documentation">
<tab type="modules" visible="yes" title="Functions" intro=""/>
<tab type="classlist" visible="yes" title="Data Structures" intro=""/>
<tab type="filelist" visible="yes" title="Files" intro=""/>
<tab type="globals" visible="yes" title="" intro=""/>
</tab>
</navindex>

<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<services title=""/>
<interfaces title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<services title=""/>
<interfaces title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>

<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<classes visible="yes" title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>

<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<memberdecl>
<classes visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>

<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<groupgraph visible="$GROUP_GRAPHS"/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>

<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
</directory>
</doxygenlayout>
7 changes: 7 additions & 0 deletions Externals/enet/LICENSE
@@ -0,0 +1,7 @@
Copyright (c) 2002-2015 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.
22 changes: 22 additions & 0 deletions Externals/enet/Makefile.am
@@ -0,0 +1,22 @@
pkgconfigdir = $(libdir)/pkgconfig
nodist_pkgconfig_DATA = libenet.pc

enetincludedir=$(includedir)/enet
enetinclude_HEADERS = \
include/enet/callbacks.h \
include/enet/enet.h \
include/enet/list.h \
include/enet/protocol.h \
include/enet/time.h \
include/enet/types.h \
include/enet/unix.h \
include/enet/utility.h \
include/enet/win32.h

lib_LTLIBRARIES = libenet.la
libenet_la_SOURCES = callbacks.c compress.c host.c list.c packet.c peer.c protocol.c unix.c win32.c
# see info '(libtool) Updating version info' before making a release
libenet_la_LDFLAGS = $(AM_LDFLAGS) -version-info 7:0:0
AM_CPPFLAGS = -I$(top_srcdir)/include

ACLOCAL_AMFLAGS = -Im4
15 changes: 15 additions & 0 deletions Externals/enet/README
@@ -0,0 +1,15 @@
Please visit the ENet homepage at http://enet.bespin.org for installation
and usage instructions.

If you obtained this package from github, the quick description on how to build
is:

# Generate the build system.

autoreconf -vfi

# Compile and install the library.

./configure && make && make install


53 changes: 53 additions & 0 deletions Externals/enet/callbacks.c
@@ -0,0 +1,53 @@
/**
@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);
}

654 changes: 654 additions & 0 deletions Externals/enet/compress.c

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions Externals/enet/configure.ac
@@ -0,0 +1,26 @@
AC_INIT([libenet], [1.3.12])
AC_CONFIG_SRCDIR([include/enet/enet.h])
AM_INIT_AUTOMAKE([foreign])

AC_CONFIG_MACRO_DIR([m4])

AC_PROG_CC
AC_PROG_LIBTOOL

AC_CHECK_FUNC(gethostbyaddr_r, [AC_DEFINE(HAS_GETHOSTBYADDR_R)])
AC_CHECK_FUNC(gethostbyname_r, [AC_DEFINE(HAS_GETHOSTBYNAME_R)])
AC_CHECK_FUNC(poll, [AC_DEFINE(HAS_POLL)])
AC_CHECK_FUNC(fcntl, [AC_DEFINE(HAS_FCNTL)])
AC_CHECK_FUNC(inet_pton, [AC_DEFINE(HAS_INET_PTON)])
AC_CHECK_FUNC(inet_ntop, [AC_DEFINE(HAS_INET_NTOP)])

AC_CHECK_MEMBER(struct msghdr.msg_flags, [AC_DEFINE(HAS_MSGHDR_FLAGS)], , [#include <sys/socket.h>])

AC_CHECK_TYPE(socklen_t, [AC_DEFINE(HAS_SOCKLEN_T)], ,
#include <sys/types.h>
#include <sys/socket.h>
)

AC_CONFIG_FILES([Makefile
libenet.pc])
AC_OUTPUT
24 changes: 24 additions & 0 deletions Externals/enet/docs/FAQ.dox
@@ -0,0 +1,24 @@
/**
@page FAQ Frequently Answered Questions

@section Q1 Is ENet thread-safe?

ENet does not use any significant global variables, the vast majority
of state is encapsulated in the ENetHost structure. As such, as long
as the application guards access to this structure, then ENet should
operate fine in a multi-threaded environment.

@section Q2 Isn't ENet just re-inventing TCP?! What's the point?

In a perfect world, that would be true. But as many have found, using
TCP either in lieu of or in conjunction with UDP can lead to all kinds
of nightmares. TCP is a good, solid protocol, however it simply isn't
up to the task of real-time games. Too much of TCP's implementation
dictates a policy that isn't practical for games. If you want to use
TCP, then do so -- this library is for people that either don't want
to use TCP or have tried and ended up being discouraged with the
performance.

*/


126 changes: 126 additions & 0 deletions Externals/enet/docs/design.dox
@@ -0,0 +1,126 @@
/**
@page Features Features and Architecture

ENet evolved specifically as a UDP networking layer for the
multiplayer first person shooter Cube. Cube necessitated low latency
communication with data sent out very frequently, so TCP was an
unsuitable choice due to its high latency and stream orientation. UDP,
however, lacks many sometimes necessary features from TCP such as
reliability, sequencing, unrestricted packet sizes, and connection
management. So UDP by itself was not suitable as a network protocol
either. No suitable freely available networking libraries existed at
the time of ENet's creation to fill this niche.

UDP and TCP could have been used together in Cube to benefit somewhat
from both of their features, however, the resulting combinations of
protocols still leaves much to be desired. TCP lacks multiple streams
of communication without resorting to opening many sockets and
complicates delineation of packets due to its buffering behavior. UDP
lacks sequencing, connection management, management of bandwidth
resources, and imposes limitations on the size of packets. A
significant investment is required to integrate these two protocols,
and the end result is worse off in features and performance than the
uniform protocol presented by ENet.

ENet thus attempts to address these issues and provide a single,
uniform protocol layered over UDP to the developer with the best
features of UDP and TCP as well as some useful features neither
provide, with a much cleaner integration than any resulting from a
mixture of UDP and TCP.

@section CM Connection Management

ENet provides a simple connection interface over which to communicate
with a foreign host. The liveness of the connection is actively
monitored by pinging the foreign host at frequent intervals, and also
monitors the network conditions from the local host to the foreign
host such as the mean round trip time and packet loss in this fashion.

@section Sequencing Sequencing

Rather than a single byte stream that complicates the delineation of
packets, ENet presents connections as multiple, properly sequenced
packet streams that simplify the transfer of various types of data.

ENet provides sequencing for all packets by assigning to each sent
packet a sequence number that is incremented as packets are sent. ENet
guarantees that no packet with a higher sequence number will be
delivered before a packet with a lower sequence number, thus ensuring
packets are delivered exactly in the order they are sent.

For unreliable packets, ENet will simply discard the lower sequence
number packet if a packet with a higher sequence number has already
been delivered. This allows the packets to be dispatched immediately
as they arrive, and reduce latency of unreliable packets to an
absolute minimum. For reliable packets, if a higher sequence number
packet arrives, but the preceding packets in the sequence have not yet
arrived, ENet will stall delivery of the higher sequence number
packets until its predecessors have arrived.

@section Channels Channels

Since ENet will stall delivery of reliable packets to ensure proper
sequencing, and consequently any packets of higher sequence number
whether reliable or unreliable, in the event the reliable packet's
predecessors have not yet arrived, this can introduce latency into the
delivery of other packets which may not need to be as strictly ordered
with respect to the packet that stalled their delivery.

To combat this latency and reduce the ordering restrictions on
packets, ENet provides multiple channels of communication over a given
connection. Each channel is independently sequenced, and so the
delivery status of a packet in one channel will not stall the delivery
of other packets in another channel.

@section Reliability Reliability

ENet provides optional reliability of packet delivery by ensuring the
foreign host acknowledges receipt of all reliable packets. ENet will
attempt to resend the packet up to a reasonable amount of times, if no
acknowledgement of the packet's receipt happens within a specified
timeout. Retry timeouts are progressive and become more lenient with
every failed attempt to allow for temporary turbulence in network
conditions.

@section FaR Fragmentation and Reassembly

ENet will send and deliver packets regardless of size. Large packets
are fragmented into many smaller packets of suitable size, and
reassembled on the foreign host to recover the original packet for
delivery. The process is entirely transparent to the developer.

@section Aggregation Aggregation

ENet aggregates all protocol commands, including acknowledgements and
packet transfer, into larger protocol packets to ensure the proper
utilization of the connection and to limit the opportunities for
packet loss that might otherwise result in further delivery latency.

@section Adaptability Adaptability

ENet provides an in-flight data window for reliable packets to ensure
connections are not overwhelmed by volumes of packets. It also
provides a static bandwidth allocation mechanism to ensure the total
volume of packets sent and received to a host don't exceed the host's
capabilities. Further, ENet also provides a dynamic throttle that
responds to deviations from normal network connections to rectify
various types of network congestion by further limiting the volume of
packets sent.

@section Portability Portability

ENet works on Windows and any other Unix or Unix-like platform
providing a BSD sockets interface. The library has a small and stable
code base that can easily be extended to support other platforms and
integrates easily. ENet makes no assumptions about the underlying
platform's endianess or word size.

@section Freedom Freedom

ENet demands no royalties and doesn't carry a viral license that would
restrict you in how you might use it in your programs. ENet is
licensed under a short-and-sweet MIT-style license, which gives you
the freedom to do anything you want with it (well, almost anything).

*/

63 changes: 63 additions & 0 deletions Externals/enet/docs/install.dox
@@ -0,0 +1,63 @@
/**
@page Installation Installation

ENet should be trivially simple to integrate with most applications.
First, make sure you download the latest source distribution at @ref Downloads.

@section Unix Unix-like Operating Systems

If you are using an ENet release, then you should simply be able to build it
by doing the following:

./configure && make && make install

If you obtained the package from github, you must have automake and autoconf
available to generate the build system first by doing the following command
before using the above mentioned build procedure:

autoreconf -vfi


@subsection SolarisBSD Solaris and BSD

When building ENet under Solaris, you must specify the -lsocket and
-lnsl parameters to your compiler to ensure that the sockets library
is linked in.

@section Windows Microsoft Windows

You may simply use the included "enet.lib" or "enet64.lib" static libraries.
However, if you wish to build the library yourself, then the following
instructions apply:

There is an included MSVC 6 project (enet.dsp) which you may use to
build a suitable library file. Alternatively, you may simply drag all
the ENet source files into your main project.

You will have to link to the Winsock2 libraries, so make sure to add
ws2_32.lib and winmm.lib to your library list (Project Settings | Link |
Object/library modules).

@subsection enet.dsp Building with the included enet.dsp

Load the included enet.dsp. MSVC may ask you to convert it if you
are on a newer version of MSVC - just allow the conversion and save
the resulting project as "enet" or similar. After you build this
project, it will output an "enet.lib" file to either the "Debug/"
or "Release/" directory, depending on which configuration you have
selected to build. By default, it should produce "Debug/enet.lib".

You may then copy the resulting "enet.lib" file and the header files
found in the "include/" directory to your other projects and add it to
their library lists. Make sure to also link against "ws2_32.lib" and
"winmm.lib" as described above.

@subsection DLL DLL

If you wish to build ENet as a DLL you must first define ENET_DLL
within the project (Project Settings | C/C++ | Preprocessor |
Preprocessor definitions) or, more invasively, simply define ENET_DLL
at the top of enet.h.

*/

26 changes: 26 additions & 0 deletions Externals/enet/docs/license.dox
@@ -0,0 +1,26 @@
/**
@page License License

Copyright (c) 2002-2015 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.

*/

59 changes: 59 additions & 0 deletions Externals/enet/docs/mainpage.dox
@@ -0,0 +1,59 @@
/** @mainpage ENet

ENet's purpose is to provide a relatively thin, simple and robust
network communication layer on top of UDP (User Datagram Protocol).
The primary feature it provides is optional reliable, in-order
delivery of packets.

ENet omits certain higher level networking features such as authentication,
lobbying, server discovery, encryption, or other similar tasks that are
particularly application specific so that the library remains flexible,
portable, and easily embeddable.

@ref Features

@ref Downloads

@ref Installation

@ref Tutorial

@ref MailingList

@ref IRCChannel

@ref FAQ

@ref License

<a class="el" href="usergroup0.html">Documentation</a>

*/

/**
@page Downloads Downloads

You can retrieve the source to ENet by downloading it in either .tar.gz form
or accessing the github distribution directly.

The most recent stable release (1.3.12) can be downloaded <a class="el" href="download/enet-1.3.12.tar.gz">here</a>.
The last release that is protocol compatible with the 1.2 series or earlier (1.2.5) can be downloaded <a class="el" href="download/enet-1.2.5.tar.gz">here</a>.

You can find the most recent ENet source at <a class="el" href="https://github.com/lsalzman/enet">the github repository</a>.

*/

/**
@page MailingList Mailing List

The <a class="el" href="http://lists.cubik.org/mailman/listinfo/enet-discuss">enet-discuss</a> list is for discussion of ENet, including bug reports or feature requests.

*/

/**
@page IRCChannel IRC Channel

Join the \#enet channel on the <a class="el" href="http://freenode.net">freenode IRC network (irc.freenode.net)</a> for real-time discussion about the ENet library.

*/

366 changes: 366 additions & 0 deletions Externals/enet/docs/tutorial.dox
@@ -0,0 +1,366 @@
/**
@page Tutorial Tutorial

@ref Initialization

@ref CreateServer

@ref CreateClient

@ref ManageHost

@ref SendingPacket

@ref Disconnecting

@ref Connecting

@section Initialization Initialization

You should include the file <enet/enet.h> when using ENet. Do not
include <enet.h> without the directory prefix, as this may cause
file name conflicts on some systems.

Before using ENet, you must call enet_initialize() to initialize the
library. Upon program exit, you should call enet_deinitialize() so
that the library may clean up any used resources.

@code
#include <enet/enet.h>

int
main (int argc, char ** argv)
{
if (enet_initialize () != 0)
{
fprintf (stderr, "An error occurred while initializing ENet.\n");
return EXIT_FAILURE;
}
atexit (enet_deinitialize);
...
...
...
}
@endcode

@section CreateServer Creating an ENet server

Servers in ENet are constructed with enet_host_create(). You must
specify an address on which to receive data and new connections, as
well as the maximum allowable numbers of connected peers. You may
optionally specify the incoming and outgoing bandwidth of the server
in bytes per second so that ENet may try to statically manage
bandwidth resources among connected peers in addition to its dynamic
throttling algorithm; specifying 0 for these two options will cause
ENet to rely entirely upon its dynamic throttling algorithm to manage
bandwidth.

When done with a host, the host may be destroyed with
enet_host_destroy(). All connected peers to the host will be reset,
and the resources used by the host will be freed.

@code
ENetAddress address;
ENetHost * server;

/* Bind the server to the default localhost. */
/* A specific host address can be specified by */
/* enet_address_set_host (& address, "x.x.x.x"); */

address.host = ENET_HOST_ANY;
/* Bind the server to port 1234. */
address.port = 1234;

server = enet_host_create (& address /* the address to bind the server host to */,
32 /* allow up to 32 clients and/or outgoing connections */,
2 /* allow up to 2 channels to be used, 0 and 1 */,
0 /* assume any amount of incoming bandwidth */,
0 /* assume any amount of outgoing bandwidth */);
if (server == NULL)
{
fprintf (stderr,
"An error occurred while trying to create an ENet server host.\n");
exit (EXIT_FAILURE);
}
...
...
...
enet_host_destroy(server);
@endcode

@section CreateClient Creating an ENet client

Clients in ENet are similarly constructed with enet_host_create() when
no address is specified to bind the host to. Bandwidth may be
specified for the client host as in the above example. The peer count
controls the maximum number of connections to other server hosts that
may be simultaneously open.

@code
ENetHost * client;

client = enet_host_create (NULL /* create a client host */,
1 /* only allow 1 outgoing connection */,
2 /* allow up 2 channels to be used, 0 and 1 */,
57600 / 8 /* 56K modem with 56 Kbps downstream bandwidth */,
14400 / 8 /* 56K modem with 14 Kbps upstream bandwidth */);

if (client == NULL)
{
fprintf (stderr,
"An error occurred while trying to create an ENet client host.\n");
exit (EXIT_FAILURE);
}
...
...
...
enet_host_destroy(client);
@endcode

@section ManageHost Managing an ENet host

ENet uses a polled event model to notify the programmer of significant
events. ENet hosts are polled for events with enet_host_service(),
where an optional timeout value in milliseconds may be specified to
control how long ENet will poll; if a timeout of 0 is specified,
enet_host_service() will return immediately if there are no events to
dispatch. enet_host_service() will return 1 if an event was dispatched
within the specified timeout.

Beware that most processing of the network with the ENet stack is done
inside enet_host_service(). Both hosts that make up the sides of a connection
must regularly call this function to ensure packets are actually sent and
received. A common symptom of not actively calling enet_host_service()
on both ends is that one side receives events while the other does not.
The best way to schedule this activity to ensure adequate service is, for
example, to call enet_host_service() with a 0 timeout (meaning non-blocking)
at the beginning of every frame in a game loop.

Currently there are only four types of significant events in ENet:

An event of type ENET_EVENT_TYPE_NONE is returned if no event occurred
within the specified time limit. enet_host_service() will return 0
with this event.

An event of type ENET_EVENT_TYPE_CONNECT is returned when either a new client
host has connected to the server host or when an attempt to establish a
connection with a foreign host has succeeded. Only the "peer" field of the
event structure is valid for this event and contains the newly connected peer.

An event of type ENET_EVENT_TYPE_RECEIVE is returned when a packet is received
from a connected peer. The "peer" field contains the peer the packet was
received from, "channelID" is the channel on which the packet was sent, and
"packet" is the packet that was sent. The packet contained in the "packet"
field must be destroyed with enet_packet_destroy() when you are done
inspecting its contents.

An event of type ENET_EVENT_TYPE_DISCONNECT is returned when a connected peer
has either explicitly disconnected or timed out. Only the "peer" field of the
event structure is valid for this event and contains the peer that
disconnected. Only the "data" field of the peer is still valid on a
disconnect event and must be explicitly reset.

@code
ENetEvent event;

/* Wait up to 1000 milliseconds for an event. */
while (enet_host_service (client, & event, 1000) > 0)
{
switch (event.type)
{
case ENET_EVENT_TYPE_CONNECT:
printf ("A new client connected from %x:%u.\n",
event.peer -> address.host,
event.peer -> address.port);

/* Store any relevant client information here. */
event.peer -> data = "Client information";

break;

case ENET_EVENT_TYPE_RECEIVE:
printf ("A packet of length %u containing %s was received from %s on channel %u.\n",
event.packet -> dataLength,
event.packet -> data,
event.peer -> data,
event.channelID);

/* Clean up the packet now that we're done using it. */
enet_packet_destroy (event.packet);

break;

case ENET_EVENT_TYPE_DISCONNECT:
printf ("%s disconnected.\n", event.peer -> data);

/* Reset the peer's client information. */

event.peer -> data = NULL;
}
}
...
...
...
@endcode

@section SendingPacket Sending a packet to an ENet peer

Packets in ENet are created with enet_packet_create(), where the size
of the packet must be specified. Optionally, initial data may be
specified to copy into the packet.

Certain flags may also be supplied to enet_packet_create() to control
various packet features:

ENET_PACKET_FLAG_RELIABLE specifies that the packet must use reliable
delivery. A reliable packet is guaranteed to be delivered, and a
number of retry attempts will be made until an acknowledgement is
received from the foreign host the packet is sent to. If a certain
number of retry attempts is reached without any acknowledgement, ENet
will assume the peer has disconnected and forcefully reset the
connection. If this flag is not specified, the packet is assumed an
unreliable packet, and no retry attempts will be made nor
acknowledgements generated.

A packet may be resized (extended or truncated) with
enet_packet_resize().

A packet is sent to a foreign host with
enet_peer_send(). enet_peer_send() accepts a channel id over which to
send the packet to a given peer. Once the packet is handed over to
ENet with enet_peer_send(), ENet will handle its deallocation and
enet_packet_destroy() should not be used upon it.

One may also use enet_host_broadcast() to send a packet to all
connected peers on a given host over a specified channel id, as with
enet_peer_send().

Queued packets will be sent on a call to enet_host_service().
Alternatively, enet_host_flush() will send out queued packets without
dispatching any events.

@code
/* Create a reliable packet of size 7 containing "packet\0" */
ENetPacket * packet = enet_packet_create ("packet",
strlen ("packet") + 1,
ENET_PACKET_FLAG_RELIABLE);

/* Extend the packet so and append the string "foo", so it now */
/* contains "packetfoo\0" */
enet_packet_resize (packet, strlen ("packetfoo") + 1);
strcpy (& packet -> data [strlen ("packet")], "foo");

/* Send the packet to the peer over channel id 0. */
/* One could also broadcast the packet by */
/* enet_host_broadcast (host, 0, packet); */
enet_peer_send (peer, 0, packet);
...
...
...
/* One could just use enet_host_service() instead. */
enet_host_flush (host);
@endcode

@section Disconnecting Disconnecting an ENet peer

Peers may be gently disconnected with enet_peer_disconnect(). A
disconnect request will be sent to the foreign host, and ENet will
wait for an acknowledgement from the foreign host before finally
disconnecting. An event of type ENET_EVENT_TYPE_DISCONNECT will be
generated once the disconnection succeeds. Normally timeouts apply to
the disconnect acknowledgement, and so if no acknowledgement is
received after a length of time the peer will be forcefully
disconnected.

enet_peer_reset() will forcefully disconnect a peer. The foreign host
will get no notification of a disconnect and will time out on the
foreign host. No event is generated.

@code
ENetEvent event;

enet_peer_disconnect (peer, 0);

/* Allow up to 3 seconds for the disconnect to succeed
* and drop any packets received packets.
*/
while (enet_host_service (client, & event, 3000) > 0)
{
switch (event.type)
{
case ENET_EVENT_TYPE_RECEIVE:
enet_packet_destroy (event.packet);
break;

case ENET_EVENT_TYPE_DISCONNECT:
puts ("Disconnection succeeded.");
return;
...
...
...
}
}

/* We've arrived here, so the disconnect attempt didn't */
/* succeed yet. Force the connection down. */
enet_peer_reset (peer);
...
...
...
@endcode

@section Connecting Connecting to an ENet host

A connection to a foreign host is initiated with enet_host_connect().
It accepts the address of a foreign host to connect to, and the number
of channels that should be allocated for communication. If N channels
are allocated for use, their channel ids will be numbered 0 through
N-1. A peer representing the connection attempt is returned, or NULL
if there were no available peers over which to initiate the
connection. When the connection attempt succeeds, an event of type
ENET_EVENT_TYPE_CONNECT will be generated. If the connection attempt
times out or otherwise fails, an event of type
ENET_EVENT_TYPE_DISCONNECT will be generated.

@code
ENetAddress address;
ENetEvent event;
ENetPeer *peer;

/* Connect to some.server.net:1234. */
enet_address_set_host (& address, "some.server.net");
address.port = 1234;

/* Initiate the connection, allocating the two channels 0 and 1. */
peer = enet_host_connect (client, & address, 2, 0);

if (peer == NULL)
{
fprintf (stderr,
"No available peers for initiating an ENet connection.\n");
exit (EXIT_FAILURE);
}

/* Wait up to 5 seconds for the connection attempt to succeed. */
if (enet_host_service (client, & event, 5000) > 0 &&
event.type == ENET_EVENT_TYPE_CONNECT)
{
puts ("Connection to some.server.net:1234 succeeded.");
...
...
...
}
else
{
/* Either the 5 seconds are up or a disconnect event was */
/* received. Reset the peer in the event the 5 seconds */
/* had run out without any significant event. */
enet_peer_reset (peer);

puts ("Connection to some.server.net:1234 failed.");
}
...
...
...
@endcode
*/
168 changes: 168 additions & 0 deletions Externals/enet/enet.dsp
87 changes: 87 additions & 0 deletions Externals/enet/enet.vcxproj
@@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\enet\callbacks.h" />
<ClInclude Include="include\enet\enet.h" />
<ClInclude Include="include\enet\list.h" />
<ClInclude Include="include\enet\protocol.h" />
<ClInclude Include="include\enet\time.h" />
<ClInclude Include="include\enet\types.h" />
<ClInclude Include="include\enet\unix.h" />
<ClInclude Include="include\enet\utility.h" />
<ClInclude Include="include\enet\win32.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="callbacks.c" />
<ClCompile Include="compress.c" />
<ClCompile Include="host.c" />
<ClCompile Include="list.c" />
<ClCompile Include="packet.c" />
<ClCompile Include="peer.c" />
<ClCompile Include="protocol.c" />
<ClCompile Include="unix.c" />
<ClCompile Include="win32.c" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<None Include="LICENSE" />
<None Include="README" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{CBC76802-C128-4B17-BF6C-23B08C313E5E}</ProjectGuid>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'" Label="Configuration">
<UseDebugLibraries>true</UseDebugLibraries>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\..\Source\VSProps\Base.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(ExternalsDir)enet\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<AdditionalIncludeDirectories>$(ExternalsDir)enet\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
55 changes: 55 additions & 0 deletions Externals/enet/enet.vcxproj.filters
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="include">
<UniqueIdentifier>{a5756b80-36f2-45f6-b1f1-b67082477376}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="include\enet\callbacks.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="include\enet\enet.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="include\enet\list.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="include\enet\protocol.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="include\enet\time.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="include\enet\types.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="include\enet\unix.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="include\enet\utility.h">
<Filter>include</Filter>
</ClInclude>
<ClInclude Include="include\enet\win32.h">
<Filter>include</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="callbacks.c" />
<ClCompile Include="compress.c" />
<ClCompile Include="host.c" />
<ClCompile Include="list.c" />
<ClCompile Include="packet.c" />
<ClCompile Include="peer.c" />
<ClCompile Include="protocol.c" />
<ClCompile Include="unix.c" />
<ClCompile Include="win32.c" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<None Include="LICENSE" />
<None Include="README" />
</ItemGroup>
</Project>
86 changes: 86 additions & 0 deletions Externals/enet/enet_dll.cbp
@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="enet_dll" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Debug">
<Option output="bin\Debug\libenet" prefix_auto="1" extension_auto="1" />
<Option object_output="obj\Debug\" />
<Option type="3" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Option createStaticLib="1" />
<Compiler>
<Add option="-g" />
</Compiler>
</Target>
<Target title="Release">
<Option output="bin\Release\libenet" prefix_auto="1" extension_auto="1" />
<Option object_output="obj\Release\" />
<Option type="3" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Option createStaticLib="1" />
<Compiler>
<Add option="-O2" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
<Add option="-DENET_DLL" />
<Add directory="include" />
</Compiler>
<Linker>
<Add library="ws2_32" />
<Add library="Winmm" />
</Linker>
<Unit filename="callbacks.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="compress.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="host.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="include\enet\callbacks.h" />
<Unit filename="include\enet\enet.h" />
<Unit filename="include\enet\list.h" />
<Unit filename="include\enet\protocol.h" />
<Unit filename="include\enet\time.h" />
<Unit filename="include\enet\types.h" />
<Unit filename="include\enet\unix.h" />
<Unit filename="include\enet\utility.h" />
<Unit filename="include\enet\win32.h" />
<Unit filename="list.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="packet.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="peer.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="protocol.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="unix.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="win32.c">
<Option compilerVar="CC" />
</Unit>
<Extensions>
<code_completion />
<envvars />
<debugger />
</Extensions>
</Project>
</CodeBlocks_project_file>
492 changes: 492 additions & 0 deletions Externals/enet/host.c

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions Externals/enet/include/enet/callbacks.h
@@ -0,0 +1,27 @@
/**
@file callbacks.h
@brief ENet callbacks
*/
#ifndef __ENET_CALLBACKS_H__
#define __ENET_CALLBACKS_H__

#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__ */

592 changes: 592 additions & 0 deletions Externals/enet/include/enet/enet.h

Large diffs are not rendered by default.

43 changes: 43 additions & 0 deletions Externals/enet/include/enet/list.h
@@ -0,0 +1,43 @@
/**
@file list.h
@brief ENet list management
*/
#ifndef __ENET_LIST_H__
#define __ENET_LIST_H__

#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__ */

198 changes: 198 additions & 0 deletions Externals/enet/include/enet/protocol.h
@@ -0,0 +1,198 @@
/**
@file protocol.h
@brief ENet protocol
*/
#ifndef __ENET_PROTOCOL_H__
#define __ENET_PROTOCOL_H__

#include "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__ */

18 changes: 18 additions & 0 deletions Externals/enet/include/enet/time.h
@@ -0,0 +1,18 @@
/**
@file time.h
@brief ENet time constants and macros
*/
#ifndef __ENET_TIME_H__
#define __ENET_TIME_H__

#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__ */

13 changes: 13 additions & 0 deletions Externals/enet/include/enet/types.h
@@ -0,0 +1,13 @@
/**
@file types.h
@brief type definitions for ENet
*/
#ifndef __ENET_TYPES_H__
#define __ENET_TYPES_H__

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__ */

47 changes: 47 additions & 0 deletions Externals/enet/include/enet/unix.h
@@ -0,0 +1,47 @@
/**
@file unix.h
@brief ENet Unix header
*/
#ifndef __ENET_UNIX_H__
#define __ENET_UNIX_H__

#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

#ifdef MSG_MAXIOVLEN
#define ENET_BUFFER_MAXIMUM MSG_MAXIOVLEN
#endif

typedef int ENetSocket;

#define ENET_SOCKET_NULL -1

#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 fd_set ENetSocketSet;

#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset))
#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset))
#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset))
#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset))

#endif /* __ENET_UNIX_H__ */

12 changes: 12 additions & 0 deletions Externals/enet/include/enet/utility.h
@@ -0,0 +1,12 @@
/**
@file utility.h
@brief ENet utility header
*/
#ifndef __ENET_UTILITY_H__
#define __ENET_UTILITY_H__

#define ENET_MAX(x, y) ((x) > (y) ? (x) : (y))
#define ENET_MIN(x, y) ((x) < (y) ? (x) : (y))

#endif /* __ENET_UTILITY_H__ */

57 changes: 57 additions & 0 deletions Externals/enet/include/enet/win32.h
@@ -0,0 +1,57 @@
/**
@file win32.h
@brief ENet Win32 header
*/
#ifndef __ENET_WIN32_H__
#define __ENET_WIN32_H__

#ifdef _MSC_VER
#ifdef ENET_BUILDING_LIB
#pragma warning (disable: 4267) // size_t to int conversion
#pragma warning (disable: 4244) // 64bit to 32bit int
#pragma warning (disable: 4018) // signed/unsigned mismatch
#pragma warning (disable: 4146) // unary minus operator applied to unsigned type
#endif
#endif

#include <stdlib.h>
#include <winsock2.h>

typedef SOCKET ENetSocket;

#define ENET_SOCKET_NULL INVALID_SOCKET

#define ENET_HOST_TO_NET_16(value) (htons (value))
#define ENET_HOST_TO_NET_32(value) (htonl (value))

#define ENET_NET_TO_HOST_16(value) (ntohs (value))
#define ENET_NET_TO_HOST_32(value) (ntohl (value))

typedef struct
{
size_t dataLength;
void * data;
} ENetBuffer;

#define ENET_CALLBACK __cdecl

#ifdef ENET_DLL
#ifdef ENET_BUILDING_LIB
#define ENET_API __declspec( dllexport )
#else
#define ENET_API __declspec( dllimport )
#endif /* ENET_BUILDING_LIB */
#else /* !ENET_DLL */
#define ENET_API extern
#endif /* ENET_DLL */

typedef fd_set ENetSocketSet;

#define ENET_SOCKETSET_EMPTY(sockset) FD_ZERO (& (sockset))
#define ENET_SOCKETSET_ADD(sockset, socket) FD_SET (socket, & (sockset))
#define ENET_SOCKETSET_REMOVE(sockset, socket) FD_CLR (socket, & (sockset))
#define ENET_SOCKETSET_CHECK(sockset, socket) FD_ISSET (socket, & (sockset))

#endif /* __ENET_WIN32_H__ */


10 changes: 10 additions & 0 deletions Externals/enet/libenet.pc.in
@@ -0,0 +1,10 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@

Name: @PACKAGE_NAME@
Description: Low-latency UDP networking library supporting optional reliability
Version: @PACKAGE_VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -lenet
75 changes: 75 additions & 0 deletions Externals/enet/list.c
@@ -0,0 +1,75 @@
/**
@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;
}

/** @} */
Empty file added Externals/enet/m4/.keep
Empty file.
165 changes: 165 additions & 0 deletions Externals/enet/packet.c
@@ -0,0 +1,165 @@
/**
@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 int initializedCRC32 = 0;
static enet_uint32 crcTable [256];

static enet_uint32
reflect_crc (int val, int bits)
{
int result = 0, bit;

for (bit = 0; bit < bits; bit ++)
{
if(val & 1) result |= 1 << (bits - 1 - bit);
val >>= 1;
}

return result;
}

static void
initialize_crc32 (void)
{
int byte;

for (byte = 0; byte < 256; ++ byte)
{
enet_uint32 crc = reflect_crc (byte, 8) << 24;
int offset;

for(offset = 0; offset < 8; ++ offset)
{
if (crc & 0x80000000)
crc = (crc << 1) ^ 0x04c11db7;
else
crc <<= 1;
}

crcTable [byte] = reflect_crc (crc, 32);
}

initializedCRC32 = 1;
}

enet_uint32
enet_crc32 (const ENetBuffer * buffers, size_t bufferCount)
{
enet_uint32 crc = 0xFFFFFFFF;

if (! initializedCRC32) initialize_crc32 ();

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,004 changes: 1,004 additions & 0 deletions Externals/enet/peer.c

Large diffs are not rendered by default.

59 changes: 59 additions & 0 deletions Externals/enet/premake4.lua
@@ -0,0 +1,59 @@
solution "enet"
configurations { "Debug", "Release" }
platforms { "x32", "x64" }

project "enet_static"
kind "StaticLib"
language "C"

files { "*.c" }

includedirs { "include/" }

configuration "Debug"
targetsuffix "d"

defines({ "DEBUG" })

flags { "Symbols" }

configuration "Release"
defines({ "NDEBUG" })

flags { "Optimize" }

configuration { "Debug", "x64" }
targetsuffix "64d"

configuration { "Release", "x64" }
targetsuffix "64"

project "enet"
kind "SharedLib"
language "C"

files { "*.c" }

includedirs { "include/" }

defines({"ENET_DLL=1" })

configuration "Debug"
targetsuffix "d"

defines({ "DEBUG" })

flags { "Symbols" }

configuration "Release"
defines({ "NDEBUG" })

flags { "Optimize" }

configuration { "Debug", "x64" }
targetsuffix "64d"

configuration { "Release", "x64" }
targetsuffix "64"


1,909 changes: 1,909 additions & 0 deletions Externals/enet/protocol.c

Large diffs are not rendered by default.

557 changes: 557 additions & 0 deletions Externals/enet/unix.c

Large diffs are not rendered by default.

422 changes: 422 additions & 0 deletions Externals/enet/win32.c

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Source/Core/Common/CMakeLists.txt
Expand Up @@ -24,6 +24,7 @@ set(SRCS BreakPoints.cpp
SysConf.cpp
Thread.cpp
Timer.cpp
TraversalClient.cpp
Version.cpp
x64ABI.cpp
x64Analyzer.cpp
Expand All @@ -33,7 +34,7 @@ set(SRCS BreakPoints.cpp
Logging/ConsoleListener.cpp
Logging/LogManager.cpp)


set(LIBS enet)
if(_M_ARM)
if (_M_ARM_32) #ARMv7
set(SRCS ${SRCS}
Expand Down Expand Up @@ -66,3 +67,4 @@ if(NOT APPLE AND NOT ANDROID)
endif()

add_dolphin_library(common "${SRCS}" "${LIBS}")
add_executable(traversal_server TraversalServer.cpp)
5 changes: 4 additions & 1 deletion Source/Core/Common/Common.vcxproj
Expand Up @@ -80,6 +80,8 @@
<ClInclude Include="SysConf.h" />
<ClInclude Include="Thread.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="TraversalClient.h" />
<ClInclude Include="TraversalProto.h" />
<ClInclude Include="x64ABI.h" />
<ClInclude Include="x64Analyzer.h" />
<ClInclude Include="x64Emitter.h" />
Expand Down Expand Up @@ -116,6 +118,7 @@
<ClCompile Include="SysConf.cpp" />
<ClCompile Include="Thread.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="TraversalClient.cpp" />
<ClCompile Include="Version.cpp" />
<ClCompile Include="x64ABI.cpp" />
<ClCompile Include="x64Analyzer.cpp" />
Expand All @@ -142,4 +145,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
7 changes: 6 additions & 1 deletion Source/Core/Common/Common.vcxproj.filters
Expand Up @@ -71,6 +71,9 @@
</ClInclude>
<ClInclude Include="GekkoDisassembler.h" />
<ClInclude Include="Event.h" />
<ClInclude Include="JitRegister.h" />
<ClInclude Include="TraversalClient.h" />
<ClInclude Include="TraversalProto.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="BreakPoints.cpp" />
Expand Down Expand Up @@ -117,8 +120,10 @@
</ClCompile>
<ClCompile Include="XSaveWorkaround.cpp" />
<ClCompile Include="GekkoDisassembler.cpp" />
<ClCompile Include="JitRegister.cpp" />
<ClCompile Include="TraversalClient.cpp" />
</ItemGroup>
<ItemGroup>
<Text Include="CMakeLists.txt" />
</ItemGroup>
</Project>
</Project>
356 changes: 356 additions & 0 deletions Source/Core/Common/TraversalClient.cpp
@@ -0,0 +1,356 @@
// This file is public domain, in case it's useful to anyone. -comex

#include "Common/Timer.h"
#include "Common/TraversalClient.h"

static void GetRandomishBytes(u8* buf, size_t size)
{
// We don't need high quality random numbers (which might not be available),
// just non-repeating numbers!
srand(enet_time_get());
for (size_t i = 0; i < size; i++)
buf[i] = rand() & 0xff;
}

TraversalClient::TraversalClient(ENetHost* netHost, const std::string& server, const u16 port)
: m_NetHost(netHost)
, m_Client(nullptr)
, m_FailureReason(0)
, m_ConnectRequestId(0)
, m_PendingConnect(false)
, m_Server(server)
, m_port(port)
, m_PingTime(0)
{
netHost->intercept = TraversalClient::InterceptCallback;

Reset();

ReconnectToServer();
}

TraversalClient::~TraversalClient()
{
}

void TraversalClient::ReconnectToServer()
{
if (enet_address_set_host(&m_ServerAddress, m_Server.c_str()))
{
OnFailure(BadHost);
return;
}
m_ServerAddress.port = m_port;

m_State = Connecting;

TraversalPacket hello = {};
hello.type = TraversalPacketHelloFromClient;
hello.helloFromClient.protoVersion = TraversalProtoVersion;
SendTraversalPacket(hello);
if (m_Client)
m_Client->OnTraversalStateChanged();
}

static ENetAddress MakeENetAddress(TraversalInetAddress* address)
{
ENetAddress eaddr;
if (address->isIPV6)
{
eaddr.port = 0; // no support yet :(
}
else
{
eaddr.host = address->address[0];
eaddr.port = ntohs(address->port);
}
return eaddr;
}

void TraversalClient::ConnectToClient(const std::string& host)
{
if (host.size() > sizeof(TraversalHostId))
{
PanicAlert("host too long");
return;
}
TraversalPacket packet = {};
packet.type = TraversalPacketConnectPlease;
memcpy(packet.connectPlease.hostId.data(), host.c_str(), host.size());
m_ConnectRequestId = SendTraversalPacket(packet);
m_PendingConnect = true;
}

bool TraversalClient::TestPacket(u8* data, size_t size, ENetAddress* from)
{
if (from->host == m_ServerAddress.host &&
from->port == m_ServerAddress.port)
{
if (size < sizeof(TraversalPacket))
{
ERROR_LOG(NETPLAY, "Received too-short traversal packet.");
}
else
{
HandleServerPacket((TraversalPacket*) data);
return true;
}
}
return false;
}

//--Temporary until more of the old netplay branch is moved over
void TraversalClient::Update()
{
ENetEvent netEvent;
if (enet_host_service(m_NetHost, &netEvent, 4) > 0)
{
switch (netEvent.type)
{
case ENET_EVENT_TYPE_RECEIVE:
TestPacket(netEvent.packet->data, netEvent.packet->dataLength, &netEvent.peer->address);

enet_packet_destroy(netEvent.packet);
break;
default:
break;
}
}
HandleResends();
}

void TraversalClient::HandleServerPacket(TraversalPacket* packet)
{
u8 ok = 1;
switch (packet->type)
{
case TraversalPacketAck:
if (!packet->ack.ok)
{
OnFailure(ServerForgotAboutUs);
break;
}
for (auto it = m_OutgoingTraversalPackets.begin(); it != m_OutgoingTraversalPackets.end(); ++it)
{
if (it->packet.requestId == packet->requestId)
{
m_OutgoingTraversalPackets.erase(it);
break;
}
}
break;
case TraversalPacketHelloFromServer:
if (m_State != Connecting)
break;
if (!packet->helloFromServer.ok)
{
OnFailure(VersionTooOld);
break;
}
m_HostId = packet->helloFromServer.yourHostId;
m_State = Connected;
if (m_Client)
m_Client->OnTraversalStateChanged();
break;
case TraversalPacketPleaseSendPacket:
{
// security is overrated.
ENetAddress addr = MakeENetAddress(&packet->pleaseSendPacket.address);
if (addr.port != 0)
{
char message[] = "Hello from Dolphin Netplay...";
ENetBuffer buf;
buf.data = message;
buf.dataLength = sizeof(message) - 1;
enet_socket_send(m_NetHost->socket, &addr, &buf, 1);
}
else
{
// invalid IPV6
ok = 0;
}
break;
}
case TraversalPacketConnectReady:
case TraversalPacketConnectFailed:
{
if (!m_PendingConnect || packet->connectReady.requestId != m_ConnectRequestId)
break;

m_PendingConnect = false;

if (!m_Client)
break;

if (packet->type == TraversalPacketConnectReady)
m_Client->OnConnectReady(MakeENetAddress(&packet->connectReady.address));
else
m_Client->OnConnectFailed(packet->connectFailed.reason);
break;
}
default:
WARN_LOG(NETPLAY, "Received unknown packet with type %d", packet->type);
break;
}
if (packet->type != TraversalPacketAck)
{
TraversalPacket ack = {};
ack.type = TraversalPacketAck;
ack.requestId = packet->requestId;
ack.ack.ok = ok;

ENetBuffer buf;
buf.data = &ack;
buf.dataLength = sizeof(ack);
if (enet_socket_send(m_NetHost->socket, &m_ServerAddress, &buf, 1) == -1)
OnFailure(SocketSendError);
}
}

void TraversalClient::OnFailure(FailureReason reason)
{
m_State = Failure;
m_FailureReason = reason;

switch (reason)
{
case TraversalClient::BadHost:
{
PanicAlertT("Couldn't look up central server %s", m_Server.c_str());
break;
}
case TraversalClient::VersionTooOld:
PanicAlertT("Dolphin too old for traversal server");
break;
case TraversalClient::ServerForgotAboutUs:
PanicAlertT("Disconnected from traversal server");
break;
case TraversalClient::SocketSendError:
PanicAlertT("Socket error sending to traversal server");
break;
case TraversalClient::ResendTimeout:
PanicAlertT("Timeout connecting to traversal server");
break;
}

if (m_Client)
m_Client->OnTraversalStateChanged();
}

void TraversalClient::ResendPacket(OutgoingTraversalPacketInfo* info)
{
info->sendTime = enet_time_get();
info->tries++;
ENetBuffer buf;
buf.data = &info->packet;
buf.dataLength = sizeof(info->packet);
if (enet_socket_send(m_NetHost->socket, &m_ServerAddress, &buf, 1) == -1)
OnFailure(SocketSendError);
}

void TraversalClient::HandleResends()
{
enet_uint32 now = enet_time_get();
for (auto& tpi : m_OutgoingTraversalPackets)
{
if (now - tpi.sendTime >= (u32) (300 * tpi.tries))
{
if (tpi.tries >= 5)
{
OnFailure(ResendTimeout);
m_OutgoingTraversalPackets.clear();
break;
}
else
{
ResendPacket(&tpi);
}
}
}
HandlePing();
}

void TraversalClient::HandlePing()
{
enet_uint32 now = enet_time_get();
if (m_State == Connected && now - m_PingTime >= 500)
{
TraversalPacket ping = {};
ping.type = TraversalPacketPing;
ping.ping.hostId = m_HostId;
SendTraversalPacket(ping);
m_PingTime = now;
}
}

TraversalRequestId TraversalClient::SendTraversalPacket(const TraversalPacket& packet)
{
OutgoingTraversalPacketInfo info;
info.packet = packet;
GetRandomishBytes((u8*) &info.packet.requestId, sizeof(info.packet.requestId));
info.tries = 0;
m_OutgoingTraversalPackets.push_back(info);
ResendPacket(&m_OutgoingTraversalPackets.back());
return info.packet.requestId;
}

void TraversalClient::Reset()
{
m_PendingConnect = false;
m_Client = nullptr;
}

int ENET_CALLBACK TraversalClient::InterceptCallback(ENetHost* host, ENetEvent* event)
{
auto traversalClient = g_TraversalClient.get();
if (traversalClient->TestPacket(host->receivedData, host->receivedDataLength, &host->receivedAddress))
{
event->type = (ENetEventType)42;
return 1;
}
return 0;
}

std::unique_ptr<TraversalClient> g_TraversalClient;
std::unique_ptr<ENetHost> g_MainNetHost;

// The settings at the previous TraversalClient reset - notably, we
// need to know not just what port it's on, but whether it was
// explicitly requested.
static std::string g_OldServer;
static u16 g_OldPort;

bool EnsureTraversalClient(const std::string& server, u16 port)
{

if (!g_MainNetHost || !g_TraversalClient || server != g_OldServer || port != g_OldPort)
{
g_OldServer = server;
g_OldPort = port ;

ENetAddress addr = { ENET_HOST_ANY, 0 };
ENetHost* host = enet_host_create(
&addr, // address
50, // peerCount
1, // channelLimit
0, // incomingBandwidth
0); // outgoingBandwidth
if (!host)
{
g_MainNetHost.reset();
return false;
}
g_MainNetHost.reset(host);
g_TraversalClient.reset(new TraversalClient(g_MainNetHost.get(), server, port));
}
return true;
}

void ReleaseTraversalClient()
{
if (!g_TraversalClient)
return;

g_TraversalClient.release();
g_MainNetHost.release();
}
81 changes: 81 additions & 0 deletions Source/Core/Common/TraversalClient.h
@@ -0,0 +1,81 @@
// This file is public domain, in case it's useful to anyone. -comex

#pragma once
#include <functional>
#include <list>
#include <memory>
#include <enet/include/enet/enet.h>
#include "Common/Common.h"
#include "Common/Thread.h"
#include "Common/TraversalProto.h"

class TraversalClientClient
{
public:
virtual ~TraversalClientClient(){};
virtual void OnTraversalStateChanged()=0;
virtual void OnConnectReady(ENetAddress addr)=0;
virtual void OnConnectFailed(u8 reason)=0;
};

class TraversalClient
{
public:
enum State
{
Connecting,
Connected,
Failure
};
enum FailureReason
{
BadHost = 0x300,
VersionTooOld,
ServerForgotAboutUs,
SocketSendError,
ResendTimeout,
ConnectFailedError = 0x400,
};
TraversalClient(ENetHost* netHost, const std::string& server, const u16 port);
~TraversalClient();
void Reset();
void ConnectToClient(const std::string& host);
void ReconnectToServer();
void Update();
// called from NetHost
bool TestPacket(u8* data, size_t size, ENetAddress* from);
void HandleResends();

ENetHost* m_NetHost;
TraversalClientClient* m_Client;
TraversalHostId m_HostId;
State m_State;
int m_FailureReason;

private:
struct OutgoingTraversalPacketInfo
{
TraversalPacket packet;
int tries;
enet_uint32 sendTime;
};
void HandleServerPacket(TraversalPacket* packet);
void ResendPacket(OutgoingTraversalPacketInfo* info);
TraversalRequestId SendTraversalPacket(const TraversalPacket& packet);
void OnFailure(FailureReason reason);
void HandlePing();
static int ENET_CALLBACK InterceptCallback(ENetHost* host, ENetEvent* event);
TraversalRequestId m_ConnectRequestId;
bool m_PendingConnect;
std::list<OutgoingTraversalPacketInfo> m_OutgoingTraversalPackets;
ENetAddress m_ServerAddress;
std::string m_Server;
u16 m_port;
enet_uint32 m_PingTime;
};
extern std::unique_ptr<TraversalClient> g_TraversalClient;
// the NetHost connected to the TraversalClient.
extern std::unique_ptr<ENetHost> g_MainNetHost;
// Create g_TraversalClient and g_MainNetHost if necessary.
bool EnsureTraversalClient(const std::string& server, u16 port);
void ReleaseTraversalClient();
96 changes: 96 additions & 0 deletions Source/Core/Common/TraversalProto.h
@@ -0,0 +1,96 @@
// This file is public domain, in case it's useful to anyone. -comex

#pragma once
#include <array>
#include "Common/CommonTypes.h"

#define NETPLAY_CODE_SIZE 8
typedef std::array<char, NETPLAY_CODE_SIZE> TraversalHostId;
typedef u64 TraversalRequestId;

enum TraversalPacketType
{
// [*->*]
TraversalPacketAck = 0,
// [c->s]
TraversalPacketPing = 1,
// [c->s]
TraversalPacketHelloFromClient = 2,
// [s->c]
TraversalPacketHelloFromServer = 3,
// [c->s] When connecting, first the client asks the central server...
TraversalPacketConnectPlease = 4,
// [s->c] ...who asks the game host to send a UDP packet to the
// client... (an ack implies success)
TraversalPacketPleaseSendPacket = 5,
// [s->c] ...which the central server relays back to the client.
TraversalPacketConnectReady = 6,
// [s->c] Alternately, the server might not have heard of this host.
TraversalPacketConnectFailed = 7
};

enum
{
TraversalProtoVersion = 0
};

enum TraversalConnectFailedReason
{
TraversalConnectFailedClientDidntRespond = 0,
TraversalConnectFailedClientFailure,
TraversalConnectFailedNoSuchClient
};

#pragma pack(push, 1)
struct TraversalInetAddress
{
u8 isIPV6;
u32 address[4];
u16 port;
};
struct TraversalPacket
{
u8 type;
TraversalRequestId requestId;
union
{
struct
{
u8 ok;
} ack;
struct
{
TraversalHostId hostId;
} ping;
struct
{
u8 protoVersion;
} helloFromClient;
struct
{
u8 ok;
TraversalHostId yourHostId;
TraversalInetAddress yourAddress; // currently unused
} helloFromServer;
struct
{
TraversalHostId hostId;
} connectPlease;
struct
{
TraversalInetAddress address;
} pleaseSendPacket;
struct
{
TraversalRequestId requestId;
TraversalInetAddress address;
} connectReady;
struct
{
TraversalRequestId requestId;
u8 reason;
} connectFailed;
};
};
#pragma pack(pop)