[LYN-4366] Add API documentation for AzNetworking, Mutiplayer Gem, and Multiplayer Compression Gem classes.

Signed-off-by: stramer <stramer@amazon.com>
main
stramer 5 years ago committed by stramer
parent aa2c27b22d
commit c7a0e7b930

@ -44,6 +44,12 @@ namespace AzNetworking
//! @class IConnection
//! @brief interface class for network connections.
//!
//! IConnection provides a pure-virtual interface for all network connection types. The two child classes are TcpConnection
//! and UdpConnection, though the pure-virtual interface operates largely the same for both. IConnections provide access to
//! a ConnectionMetrics object which provides a variety of metrics on the connection itself such as data rate, RTT and
//! packet statistics.
class IConnection
{
public:

@ -22,6 +22,12 @@ namespace AzNetworking
{
//! @class IConnectionListener
//! @brief interface class for application layer dealing with connection level events.
//!
//! IConnectionListener defines an abstract interface that the user of AzNetworking is expected to implement to react and
//! handle all IConnection related events, including the handling of any received IPacket derived packets. The AzNetworking
//! user should derive a handler class from IConnectionListener, and provide an instance of that handler to any
//! INetworkInterface the user instantiates. The lifetime of the IConnectionListener must outlive the lifetime of the
//! INetworkInterface.
class IConnectionListener
{
public:

@ -18,6 +18,11 @@ namespace AzNetworking
{
//! @class IConnectionSet
//! @brief interface class for managing a set of connections.
//!
//! IConnectionSet defines a simple interface for working with an abstract set of IConnections bound to an
//! INetworkInterface. Generally users of AzNetworking will not have reason to interact directly with the IConnectionSet,
//! as its interface is completely wrapped by INetworkInterface.
class IConnectionSet
{
public:

@ -23,10 +23,10 @@ namespace AzNetworking
//! Collection of compression related error codes
enum class CompressorError
{
Ok, ///< No error, operation finished successfully
InsufficientBuffer, ///< Buffer size is insufficient for the operation to complete, increase the size and try again
CorruptData, ///< Malformed or hacked packet, potentially security issue
Uninitialized ///< Compressor or supplied buffers are uninitialized
Ok, //!< No error, operation finished successfully
InsufficientBuffer, //!< Buffer size is insufficient for the operation to complete, increase the size and try again
CorruptData, //!< Malformed or hacked packet, potentially security issue
Uninitialized //!< Compressor or supplied buffers are uninitialized
};
//! Unique identifier of a given compressor
@ -34,6 +34,12 @@ namespace AzNetworking
//! @class ICompressor
//! @brief Packet data compressor interface.
//!
//! ICompressor is an abstract compression interface meant for user provided GEMs to implement (such as the [Multiplayer
//! Compression Gem](http://docs.o3de.org/docs/user-guide/gems/reference/multiplayer-compression)).
//! Compression is currently supported on Udp and Tcp connections. Instantiation of a compressor is controlled by the
//! `net_UdpCompressor` or `net_TcpCompressor` cvar for their respective protocols.
class ICompressor
{
public:
@ -87,8 +93,16 @@ namespace AzNetworking
) = 0;
};
//! Abstract factory to instantiate compressors.
//! Used by the network interface to create a compressor
//! @class ICompressorFactory
//! @brief Abstract factory to instantiate compressors.
//!
//! ICompressorFactory is an abstract compression interface meant for user provided GEMs to implement. ICompressorFactory
//! implementations can be registered to classes implementing INetworking. Registered factories can then be used to create
//! ICompressor implementations on demand. The [Multiplayer Compression
//! Gem](http://docs.o3de.org/docs/user-guide/gems/reference/multiplayer-compression) is an example of an ICompressorFactory
//! for an LZ4 Compressor. In it, MultiplayerCompressionSystemComponent registers its ICompressorFactory with
//! NetworkingSystemComponent, which is an implementation of INetworking. Registered factories are keyed by their AZ Name
//! which is accessed through the factory's GetFactoryName method.
class ICompressorFactory
{
public:

@ -22,7 +22,16 @@
namespace AzNetworking
{
//! @class INetworkInterface
//! @brief pure virtual network interface class to abstract client/server and tcp/udp concerns from application code.
//! @brief Network interface class to abstract client/server and protocol concerns from application code.
//!
//! INetworkInterface provides an abstract API capable of receiving and opening IConnection objects, sending IPacket objects with optional
//! reliability, and determining the delivery status of packets that have been sent unreliably (delivery of reliable packets
//! is guaranteed as long as the associated connection remains open). INetworkInterface must be provided an
//! IConnectionListener instance that outlives the INetworkInterface itself. The INetworkInterface also creates and manages
//! the IConnectionSet, which tracks all open connections bound to the interface. INetworkInterface also provides GetMetrics
//! functions which can be used to fetch a struct detailing a variety of metrics relating to send and receive rates for both
//! packets and bytes in addition to the effect of features on those rates (such as packet size reduction due to compression.)
class INetworkInterface
{
public:

@ -23,6 +23,17 @@ namespace AzNetworking
//! @class INetworking
//! @brief The interface for creating and working with network interfaces.
//!
//! INetworking is an Az::Interface<T> that provides applications access to higher level networking abstractions.
//! AzNetworking::INetworking can be used to instantiate new INetworkInterfaces that can be configured to operate over
//! either TCP or UDP, enable or disable encryption, and be assigned a trust level.
//!
//! INetworking is also responsible for registering ICompressorFactory implementations. This allows a developer to have
//! access to multiple ICompressorFactory implementations by name. The [MultiplayerCompressor
//! Gem](http://docs.o3de.org/docs/user-guide/gems/reference/multiplayer-compression) is an example of this using the
//! [LZ4](https://wikipedia.org/wiki/LZ4_%28compression_algorithm%29) algorithm.
//!
class INetworking
{
public:

@ -24,6 +24,15 @@ namespace AzNetworking
//! @class IPacket
//! @brief Base class for all packets.
//!
//! IPacket defines an abstract interface that all packets transmitted using AzNetworking must conform to. While there are
//! a number of core packets used internally by AzNetworking, it is fully possible for end-users to define their own custom
//! packets using this interface. PacketType should be distinct, and should be greater than
//! AzNetworking::CorePackets::MAX. The Serialize method allows the IPacket to be used by an
//! ISerializer to move data between hosts safely and efficiently.
//!
//! For more information on the packet format and best practices for extending the packet system, read
//! [Networking Packets](http://docs.o3de.org/docs/user-guide/networking/packets) on the O3DE documentation site.
class IPacket
{
public:

@ -28,6 +28,19 @@ namespace AzNetworking
//! @class IPacketHeader
//! @brief A packet header that lets us deduce packet type for any incoming packet.
//!
//! IPacketHeader defines an abstract interface for a descriptor of all AzNetworking::IPacket sent through AzNetworking. The
//! PacketHeader is used to identify and describe the contents of a Packet so that transport logic can identify what
//! additional processing steps need to be taken (if any) and what type of Packet is being inspected.
//!
//! The PacketFlags portion of the header represents the first byte of the header. While it can be encrypted it is
//! otherwise not exposed to additional processing (such as an AzNetworking::ICompressor). PacketFlags are a bitfield use to provide up
//! front information about the state of the packet. Currently there is only one flag to indicate if the Packet is
//! compressed or not.
//!
//! The remainder of the header contains the PacketType and the PacketId. While the PacketFlags byte is exempted from most
//! additional forms of processing, the remainder of the header is not.
class IPacketHeader
{
public:

@ -27,6 +27,18 @@ namespace AzNetworking
//! @class ISerializer
//! @brief Interface class for all serializers to derive from.
//!
//! ISerializer defines an abstract interface for visiting an object hierarchy and performing operations upon that hierarchy,
//! typically reading from or writing data to the object hierarchy for reasons of persistence or network transmission.
//!
//! While the most common types of serializers are provided by the AzNetworking framework, users can implement custom
//! serializers and perform complex operations on any serializable structures. A few types native to AzNetworking, many of which
//! relate to packets, demonstrate this.
//!
//! Provided serializers include NetworkInputSerializer for writing an object model into a bytestream, NetworkOutputSerializer
//! for writing to an object model, TrackChangesSerializer which is used to efficiently serialize objects without incurring significant
//! copy or comparison overhead, and HashSerializer which can be used to generate a hash of all visited data which is important for
//! automated desync detection.
class ISerializer
{
public:

@ -25,6 +25,44 @@ namespace AzNetworking
//! @class TcpNetworkInterface
//! @brief This class implements a TCP network interface.
//!
//! TcpNetworkInterface is an implementation of AzNetworking::INetworkInterface.
//! Unlike UDP, TCP implements a variety of transport features such as congestion
//! avoidance, flow control, and reliability. These features are valuable, but TCP
//! offers minimal configuration of them. This is why UdpNetworkInterface offers
//! similar features, but with greater flexibility in configuration. If your project doesn't
//! require the low latency of UDP, consider using TCP.
//!
//! ## Packet structure
//!
//! * Flags - A bitfield a receiving endpoint can quickly inspect to learn about configuration of a packet
//! * Header - Details the type of packet and other information related to reliability
//! * Payload - The actual serialized content of the packet
//!
//! For more information, read [Networking Packets](http://docs.o3de.org/docs/user-guide/networking/packets) in the O3DE documentation.
//!
//! ## Reliability
//!
//! TCP packets can only be sent reliably. This is a feature of TCP itself.
//!
//! ## Fragmentation
//!
//! TCP implements fragmentation under the hood. Consumers of TCP packets will never
//! need to worry about reconstructing the contents over multiple transmissions.
//!
//! ## Compression
//!
//! Compression here refers to content insensitive compression using libraries like
//! LZ4. If enabled, the target payload is run through the compressor and replaces
//! the original payload if it's in fact smaller. To tell if compression is enabled
//! on a given packet, we operate on a bit in the packet's Flags. The Sender writes
//! this bit while the Receiver checks it to see if a packet needs to be
//! decompressed.
//!
//! ## Encryption
//!
//! AzNetworking uses the [OpenSSL](https://www.openssl.org/) library to implement TLS encryption. If enabled,
//! the O3DE network layer handles the OpenSSL handshake under the hood using provided certificates.
class TcpNetworkInterface final
: public INetworkInterface
{

@ -27,12 +27,58 @@ namespace AzNetworking
class IConnectionListener;
class ICompressor;
// 20 byte IPv4 header + 8 byte UDP header
static const uint32_t UdpPacketHeaderSize = 20 + 8;
static const uint32_t DtlsPacketHeaderSize = 13; // DTLS1_RT_HEADER_LENGTH
static const uint32_t UdpPacketHeaderSize = 20 + 8; //!< 20 byte IPv4 header + 8 byte UDP header
static const uint32_t DtlsPacketHeaderSize = 13; //!< DTLS1_RT_HEADER_LENGTH
//! @class UdpNetworkInterface
//! @brief This class implements a UDP network interface.
//!
//! UdpNetworkInterface is an implementation of AzNetworking::INetworkInterface. Since UDP is a very bare bones protocol,
//! the Open 3D Engine implementation has to provide significantly more than its TCP counterpart (since TCP implements a
//! significant number of reliability features.)
//!
//! When sent through UDP, a packet can have additional actions performed on it depending on which features are enabled and
//! configured. Each feature listed in this description is in the order a packet will see them on Send.
//!
//! ### Packet structure
//!
//! The general structure of a UDP packet is:
//!
//! * Flags - A bitfield a receiving endpoint can quickly inspect to learn about configuration of a packet
//! * Header - Details the type of packet and other information related to reliability
//! * Payload - The actual serialized content of the packet
//!
//! For more information, read [Networking Packets](http://docs.o3de.org/docs/user-guide/networking/packets) in the O3DE documentation.
//!
//! ### Reliability
//!
//! UDP packets can be sent reliably or unreliably. Reliably sent packets are registered for tracking first. This causes the
//! reliable packet to be resent if a timeout on the packet is reached. Once the packet is acknowledged, the packet is
//! unregistered.
//!
//! ### Fragmentation
//!
//! If the raw packet size exceeds the configured maximum transmission unit (MTU) then the packet is broken into
//! multiple reliable fragments to avoid fragmentation at the routing level. Fragments are always reliable so the original
//! packet can be reconstructed. Operations that alter the payload generally follow this step so that they can be
//! separately applied to the Fragments in addition to not being applied to both the original and Fragments.
//!
//! ### Compression
//!
//! Compression here refers to content insensitive compression using libraries like LZ4. If enabled, the target payload is
//! run through the compressor and replaces the original payload if it's in fact smaller. To tell if compression is enabled
//! on a given packet, we operate on a bit in the packet's Flags. The Sender writes this bit while the Receiver checks it to
//! see if a packet needs to be decompressed.
//!
//! O3DE could potentially move from over MTU to under with compression, and the UDP interface doesn't check for this. Detecting a change
//! that would reduce the number of fragmented packets would require pre-emptively compressing payloads to tell if that change happened,
//! which could potentially lead to a lot of unnecessary calls to the compressor.
//!
//! ### Encryption
//!
//! AzNetworking uses the [OpenSSL](https://www.openssl.org/) library to implement Datagram Layer Transport Security (DTLS) encryption
//! on UDP traffic. Encryption operates as described in [O3DE Networking Encryption](http://docs.o3de.org/docs/user-guide/networking/encryption)
//! on the documentation website. Once both endpoints have completed their handshake, all traffic is expected to be fully encrypted.
class UdpNetworkInterface final
: public INetworkInterface
{

@ -30,13 +30,13 @@ namespace Multiplayer
//! Collection of types of Multiplayer Connections
enum class MultiplayerAgentType
{
Uninitialized, ///< Agent is uninitialized.
Client, ///< A Client connected to either a server or host.
ClientServer, ///< A Client that also hosts and is the authority of the session
DedicatedServer ///< A Dedicated Server which does not locally host any clients
Uninitialized, //!< Agent is uninitialized.
Client, //!< A Client connected to either a server or host.
ClientServer, //!< A Client that also hosts and is the authority of the session
DedicatedServer //!< A Dedicated Server which does not locally host any clients
};
//! Payload detailing aspects of a Connection other services may be interested in
//! @brief Payload detailing aspects of a Connection other services may be interested in
struct MultiplayerAgentDatum
{
bool m_isInvited;
@ -49,7 +49,22 @@ namespace Multiplayer
using SessionInitEvent = AZ::Event<AzNetworking::INetworkInterface*>;
using SessionShutdownEvent = AZ::Event<AzNetworking::INetworkInterface*>;
//! IMultiplayer provides insight into the Multiplayer session and its Agents
//! @class IMultiplayer
//! @brief IMultiplayer provides insight into the Multiplayer session and its Agents
//!
//! IMultiplayer is an AZ::Interface<T> that provides applications access to
//! multiplayer session information and events. IMultiplayer is implemented on the
//! MultiplayerSystemsComponent and is used to define and access information about
//! the type of session and the role held by the current agent. An Agent is defined
//! here as an actor in a session. Types of Agents included by default are a Client,
//! a Client Server and a Dedicated Server.
//!
//! IMultiplayer also provides events to allow developers to receive and respond to
//! notifications relating to the session. These include Session Init and Shutdown
//! and on acquisition of a new connection. These events are only fired on Client
//! Server or Dedicated Server. These events are useful for services that talk to
//! matchmaking services that may run in an entirely different layer which may need
//! insight to the gameplay session.
class IMultiplayer
{
public:

@ -16,7 +16,11 @@
namespace Multiplayer
{
//! IMultiplayer provides insight into the Multiplayer session and its Agents
//! @class IMultiplayerTools
//! @brief IMultiplayerTools provides interfacing between the Editor and Multiplayer Gem.
//!
//! IMultiplayerTools is an AZ::Interface<T> that provides information about
//! O3DE Editor and Tools integrations with the Multiplayer Gem.
class IMultiplayerTools
{
public:
@ -27,8 +31,8 @@ namespace Multiplayer
virtual ~IMultiplayerTools() = default;
//! Returns if network prefab processing has created currently active or pending spawnables
//! @return If network prefab processing has created currently active or pending spawnables
//! @brief Whether or not network prefab processing has created active or pending spawnable prefabs.
//! @return `true` if network prefab processing has created currently active or pending spawnables.
virtual bool DidProcessNetworkPrefabs() = 0;
private:

Loading…
Cancel
Save