Initial commit
This commit is contained in:
29
Include/ZNet/ZNet.hpp
Normal file
29
Include/ZNet/ZNet.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
ZNet.hpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/4/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
ZNet main include
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZNET_HPP
|
||||
#define _ZNET_HPP
|
||||
|
||||
|
||||
#include <ZNet/ZNetConsts.hpp>
|
||||
#include <ZNet/ZNetHost.hpp>
|
||||
#include <ZNet/ZNetServer.hpp>
|
||||
#include <ZNet/ZNetClient.hpp>
|
||||
#include <ZNet/ZNetPacket.hpp>
|
||||
#include <ZNet/ZNetPeer.hpp>
|
||||
|
||||
#endif
|
||||
|
||||
57
Include/ZNet/ZNetBandwidthMeter.hpp
Normal file
57
Include/ZNet/ZNetBandwidthMeter.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
ZNetBandwidthMeter.hpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 7/10/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
** NOT PART OF PUBLIC SDK **
|
||||
This class is not part of the public SDK; its fields and methods are not present
|
||||
in the documentation and cannot be guaranteed in future revisions.
|
||||
** NOT PART OF PUBLIC SDK **
|
||||
|
||||
Bandwidth metering using a simple token bucket algorithm. A single value is
|
||||
metered, so a incoming / outgoing each need an instance.
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZNETBANDWIDTHMETER_HPP
|
||||
#define _ZNETBANDWIDTHMETER_HPP
|
||||
|
||||
|
||||
#include <pstdint.h>
|
||||
|
||||
class ZNetBandwidthMeter
|
||||
{
|
||||
public:
|
||||
/* Sets the new bandwidth limit */
|
||||
void SetLimit(uint32_t newLimit);
|
||||
|
||||
/* Resets the meter for reuse. Takes the current time */
|
||||
void Reset(uint64_t newStartTime);
|
||||
|
||||
/* Try to allocate a given number of bytes */
|
||||
bool TryAllocate(uint32_t bytes);
|
||||
|
||||
/* Update the token bucket */
|
||||
void Update(uint64_t newTime);
|
||||
|
||||
/* Get the bandwidth limit */
|
||||
uint32_t GetLimit() const { return limit; }
|
||||
|
||||
/* Get the available instantaneous bandwidth */
|
||||
uint32_t GetAvailable() const { return tokens; }
|
||||
|
||||
private: //Should be POD basically
|
||||
uint64_t lastTime; //The last time this was updated
|
||||
uint32_t limit; //The bandwidth limit, in bytes per second
|
||||
uint32_t tokens; //The available bandwidth within this 1 second timeframe
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
98
Include/ZNet/ZNetClient.hpp
Normal file
98
Include/ZNet/ZNetClient.hpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
ZNetClient.hpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 7/11/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
ZNetClient -- extends ZNetHost to provide a client
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZNETCLIENT_HPP
|
||||
#define _ZNETCLIENT_HPP
|
||||
|
||||
#include <ZNet/ZNetHost.hpp>
|
||||
#include <ZNet/ZNetPeer.hpp>
|
||||
|
||||
class ZNetClient : public ZNetHost
|
||||
{
|
||||
public:
|
||||
ZNetClient();
|
||||
~ZNetClient();
|
||||
|
||||
/*
|
||||
ZNetClient::Update()
|
||||
|
||||
Implements ZNetHost::Update().
|
||||
|
||||
This should be called to read incoming network data and send outgoing traffic. Events
|
||||
are only generated by calling Update().
|
||||
|
||||
@return (int) - Less than 0: error. 0: OK
|
||||
*/
|
||||
int Update();
|
||||
|
||||
/*
|
||||
ZNetClient::Connect()
|
||||
|
||||
Initiates a connection to the given host. This method is asynchronous, so an event is
|
||||
generated. However, if this returns false, then no events will be generated because
|
||||
an error has occurred locally.
|
||||
*/
|
||||
bool Connect(SST_Socket socket, SST_NetAddress* addr, uint32_t nrChannels, uint32_t userData);
|
||||
|
||||
/*
|
||||
ZNetClient::SendPacket()
|
||||
|
||||
Sends a packet to the server via a certain channel. Use ZNetPacket::Release()
|
||||
when the packet is no longer needed.
|
||||
|
||||
@param packet - The packet to broadcast
|
||||
@param channelId - The channel ID
|
||||
*/
|
||||
void SendPacket(ZNetPacket* packet, uint32_t channelId);
|
||||
|
||||
|
||||
/*
|
||||
ZNetClient::Disconnect()
|
||||
|
||||
Begins a graceful disconnect. Update() should be called until an event of type DISCONNECT occurs,
|
||||
or a timeout happens. If a timeout is reached, Reset() should be used.
|
||||
|
||||
*/
|
||||
void Disconnect();
|
||||
|
||||
/*
|
||||
ZNetClient::Reset()
|
||||
|
||||
Disconnects from the server, but does not inform him/her that the disconnect has occurred.
|
||||
This should only be used when a graceful disconnect does not work or when aborting
|
||||
the client. No local event is generated, so any cleanup must be done immediately.
|
||||
*/
|
||||
void Reset();
|
||||
|
||||
/*
|
||||
ZNetClient::GetServer()
|
||||
|
||||
Gets the ZNetPeer object that represents the server. If the client is
|
||||
not connected, then this returns NULL.
|
||||
*/
|
||||
ZNetPeer* GetServer() const;
|
||||
|
||||
bool IsConnected() const { return connectedFlag; }
|
||||
|
||||
private:
|
||||
ZNetPeer server;
|
||||
bool connectedFlag;
|
||||
|
||||
/* Handle a raw packet sent by the server */
|
||||
void HandlePacket(const uint8_t* data, uint32_t dataSize);
|
||||
};
|
||||
|
||||
#endif
|
||||
44
Include/ZNet/ZNetConsts.hpp
Normal file
44
Include/ZNet/ZNetConsts.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
ZNetConsts.hpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/5/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
ZNet symbolic constants
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZNETCONSTS_HPP
|
||||
#define _ZNETCONSTS_HPP
|
||||
|
||||
#define ZNET_MTU_IPV4SAFE 512 //Like ZNET_MTU_IPV4, but with slightly less space, allowing for 64 bytes of IP overhead via optional sections
|
||||
#define ZNET_MTU_IPV4 548 //Minimum maximum reassembly buffer size of 576 minus 28 bytes of overhead for UDPv4
|
||||
#define ZNET_MTU_ETHERNET 1500
|
||||
#define ZNET_MTU_IPV6 1280
|
||||
#define ZNET_MTU_IPV6SAFE 1232 //IPv6 required 1280 minus 48 for UDPv6+IPv6 header
|
||||
|
||||
#define ZNET_MAX_SERVER_SOCKETS 4 //Maximum number of sockets a server may listen on
|
||||
|
||||
//Flags for ZNetPacket::Initialize()
|
||||
#define ZNET_TRANSIENT 0x00000000u //< Default value. The packet is unreliable, but transient, so the newest copy is presented and older version discarded.
|
||||
#define ZNET_RELIABLE 0x00000001u //< This packet will be reliable.
|
||||
|
||||
|
||||
|
||||
//Peer state
|
||||
enum ZNetConnectionState
|
||||
{
|
||||
STATE_UNCONNECTED, //No connection(s) established
|
||||
STATE_HANDSHAKE, //Machine has attempted connection, awaiting handshake
|
||||
STATE_CONNECTED, //Machine is connected actively to a remote machine
|
||||
STATE_SERVING //Clients connected, actively serving them
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
45
Include/ZNet/ZNetEvent.hpp
Normal file
45
Include/ZNet/ZNetEvent.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
ZNetEvent.hpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/5/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
ZNet event structure
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZNETEVENT_HPP
|
||||
#define _ZNETEVENT_HPP
|
||||
|
||||
class ZNetPeer;
|
||||
struct ZNetPacket;
|
||||
|
||||
enum ZNetEventType
|
||||
{
|
||||
ZNETEVENT_NONE, //No event
|
||||
ZNETEVENT_CONNECT, //A new incoming connection was made
|
||||
ZNETEVENT_DISCONNECT, //A graceful disconnection occurred
|
||||
ZNETEVENT_TIMEOUT, //A timeout occurred
|
||||
ZNETEVENT_DATA //Data was received
|
||||
};
|
||||
|
||||
//Event when connected
|
||||
struct ZNetEvent
|
||||
{
|
||||
ZNetPeer* remote; //The remote host
|
||||
ZNetPacket* packet; //The packet data
|
||||
uint32_t userdata; //The user data (if applicable)
|
||||
ZNetEventType type; //The type
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
184
Include/ZNet/ZNetHost.hpp
Normal file
184
Include/ZNet/ZNetHost.hpp
Normal file
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
ZNetHost.hpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 7/10/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
ZNet base class for shared client/server data
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZNETHOST_HPP
|
||||
#define _ZNETHOST_HPP
|
||||
|
||||
#include <ZNet/ZNetBandwidthMeter.hpp>
|
||||
#include <ZNet/ZNetEvent.hpp>
|
||||
#include <ZSTL/ZList.hpp>
|
||||
|
||||
struct ZNetPacket;
|
||||
|
||||
class ZNetHost
|
||||
{
|
||||
public:
|
||||
ZNetHost();
|
||||
virtual ~ZNetHost() { }
|
||||
|
||||
/*
|
||||
ZNetHost::Update()
|
||||
|
||||
Fetches and sends data as necessary to perform the given role. See the
|
||||
documentation for the specific class. Generally, you need to call this
|
||||
each frame.
|
||||
|
||||
@return (int) - Less than 0: error. 0: OK
|
||||
*/
|
||||
virtual int Update() = 0;
|
||||
|
||||
/*
|
||||
ZNetHost::CreatePacket()
|
||||
|
||||
Creates a packet and copies the given initialization data (if any).
|
||||
|
||||
@param initData - Data to copy to the new packet, or NULL for uninitialized packet.
|
||||
@param dataSize - The size of the packet's payload
|
||||
@param flags - The flags. No flags defined, so must be 0
|
||||
*/
|
||||
ZNetPacket* CreatePacket(const void* initData, uint32_t dataSize, uint32_t flags);
|
||||
|
||||
/*
|
||||
ZNetHost::HasEvent()
|
||||
|
||||
Returns true if there are queued events. The next call to GetNextEvent()
|
||||
is guaranteed to succeed.
|
||||
|
||||
@return (bool) - True if at least one event is pending
|
||||
*/
|
||||
bool HasEvent() { return events.Size() > 0; }
|
||||
|
||||
/*
|
||||
ZNetHost::GetNextEvent()
|
||||
|
||||
Attempt to fetch the next event form the queue and returns
|
||||
whether one was fetched or not.
|
||||
|
||||
@param eventReturn - Pointer to ZNetEvent structure to receive event data
|
||||
@return (bool) - True if an event was returned, false if none was available (and eventReturn is not modified)
|
||||
*/
|
||||
bool GetNextEvent(ZNetEvent* eventReturn);
|
||||
|
||||
//======================================================================
|
||||
// TRIVIAL GETTER / SETTER
|
||||
//======================================================================
|
||||
|
||||
/*
|
||||
ZNetHost::SetIncomingBandwidth()
|
||||
|
||||
Sets the desired incoming bandwidth cap.
|
||||
|
||||
Note that this is a request made of the remote host; malicious hosts can still
|
||||
attempt DoS attacks by sending far above this limit.
|
||||
|
||||
@param bwIn - The target incoming bandwidth, measured in bytes per second.
|
||||
*/
|
||||
void SetIncomingBandwidth(uint32_t bwIn) { inBW.SetLimit(bwIn); }
|
||||
|
||||
/*
|
||||
ZNetHost::SetOutgoingBandwidth()
|
||||
|
||||
Sets the desired outgoing bandwidth cap.
|
||||
|
||||
@param bwOut - The target outgoing bandwidth, measured in bytes per second.
|
||||
*/
|
||||
void SetOutgoingBandwidth(uint32_t bwOut) { outBW.SetLimit(bwOut); }
|
||||
|
||||
/*
|
||||
ZNetHost::SetDropChance()
|
||||
|
||||
** DEBUG ONLY **
|
||||
|
||||
Sets the chance that a packet will be intentionally dropped. This is used to
|
||||
simulate high packet loss networks; it should not be used in production. As
|
||||
such, the percent chance defaults to 0. Values over 100 are treated as 100%.
|
||||
|
||||
@param _dropChance - The percent chance to drop. The value should be 0-99.
|
||||
*/
|
||||
void SetDropChance(uint32_t _dropChance) { dropChance = _dropChance; }
|
||||
|
||||
/*
|
||||
ZNetHost::SetMTU()
|
||||
|
||||
Sets the MTU used by ZNet. ZNet will not send raw packets larger than this;
|
||||
they will be fragmented into multiple calls into libsst-net. This typically less
|
||||
the MTU on the adapter, since the "path MTU" is minimum of all nodes between the
|
||||
two endpoints. The minimum MTU is clamped to 256 bytes.
|
||||
*/
|
||||
void SetMTU(uint32_t _mtu) { mtu = _mtu; if(mtu<256) mtu = 256; }
|
||||
|
||||
/*
|
||||
ZNetHost::GetIncomingBandwidth()
|
||||
|
||||
Gets the incoming bandwidth, in bytes per second.
|
||||
|
||||
@return (uint32_t) - The incoming bandwidth
|
||||
*/
|
||||
uint32_t GetIncomingBandwidth() const { return inBW.GetLimit(); }
|
||||
|
||||
/*
|
||||
ZNetHost::GetOutgoingBandwidth()
|
||||
|
||||
Gets the outgoing bandwidth, in bytes per second.
|
||||
|
||||
@return (uint32_t) - The outgoing bandwidth
|
||||
*/
|
||||
uint32_t GetOutgoingBandwidth() const { return outBW.GetLimit(); }
|
||||
|
||||
/*
|
||||
ZNetHost::GetDropChance()
|
||||
|
||||
** DEBUG ONLY **
|
||||
|
||||
Gets the chance to drop intentionally drop a packet. This should
|
||||
be zero unless testing network code.
|
||||
|
||||
@return (uint32_t) - The chance to drop a packet.
|
||||
*/
|
||||
uint32_t GetDropChance() const { return dropChance; }
|
||||
|
||||
/*
|
||||
ZNetHost::GetMTU()
|
||||
|
||||
Gets the ZNet maximum transmission unit.
|
||||
*/
|
||||
uint32_t GetMTU() const { return mtu; }
|
||||
|
||||
|
||||
protected: //These are used by ZNetServer/ZNetClient
|
||||
|
||||
void Reset(uint64_t time);
|
||||
|
||||
void AddEvent(const ZNetEvent* newEvent) { events.PushBack(*newEvent); }
|
||||
|
||||
//Send all channel data to peer
|
||||
bool SendToPeer(ZNetPeer* peer);
|
||||
|
||||
void TrySendPing(bool isReply, uint32_t givenToken, ZNetPeer* peer);
|
||||
void TrySendConnResp(uint32_t flags, uint32_t code);
|
||||
|
||||
ZNetBandwidthMeter inBW;
|
||||
ZNetBandwidthMeter outBW;
|
||||
|
||||
private:
|
||||
ZList<ZNetEvent> events;
|
||||
uint32_t mtu; //< Maximum (wire) size packet
|
||||
uint32_t dropChance; //< Chance to drop a packet
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
46
Include/ZNet/ZNetPacket.hpp
Normal file
46
Include/ZNet/ZNetPacket.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
ZNetPacket.hpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/4/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
ZNet packet class, represents a packet
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZNETPACKET_HPP
|
||||
#define _ZNETPACKET_HPP
|
||||
|
||||
#include <pstdint.h>
|
||||
|
||||
/*
|
||||
ZNetPacket defines a logical packet that is to be sent or has been received. The data is appended
|
||||
at the end of the structure, so getting the address requires pointer manipulation. It does
|
||||
not represent the wire format of what is sent, since packets may be merged.
|
||||
*/
|
||||
|
||||
struct ZNetPacket
|
||||
{
|
||||
uint32_t dataSize; //< Size of the packet (logically)
|
||||
uint32_t flags; //< The flags. ZNET_TRANSIENT, ZNET_RELIABLE, etc.
|
||||
int32_t refCount; //< Reference count
|
||||
|
||||
uint8_t* GetData() { return (uint8_t*) ((uintptr_t)this + sizeof(ZNetPacket)); }
|
||||
void AddReference() { refCount++; }
|
||||
void ReleaseReference()
|
||||
{
|
||||
refCount--;
|
||||
if(refCount == 0)
|
||||
free(this);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
165
Include/ZNet/ZNetPacketChannel.hpp
Normal file
165
Include/ZNet/ZNetPacketChannel.hpp
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
ZNetPacketChannel.hpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/14/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
** NOT PART OF PUBLIC SDK **
|
||||
This class is not part of the public SDK; its fields and methods are not present
|
||||
in the documentation and cannot be guaranteed in future revisions.
|
||||
** NOT PART OF PUBLIC SDK **
|
||||
|
||||
Queue of incoming and outgoing packets.
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZNETPACKETCHANNEL_HPP
|
||||
#define _ZNETPACKETCHANNEL_HPP
|
||||
|
||||
#include <ZSTL/ZList.hpp>
|
||||
#include <ZNet/ZNetConsts.hpp>
|
||||
|
||||
struct ZNetPacket;
|
||||
class ZNetHost;
|
||||
|
||||
namespace ZNetPrivate { struct ZNetMessageContainer; } //urgh
|
||||
|
||||
class ZNetPacketChannel
|
||||
{
|
||||
public:
|
||||
struct ZNetQueuedPacket
|
||||
{
|
||||
uint64_t timeSent; //< Time this packet was sent (or 0 for never)
|
||||
ZNetPacket* packet; //< Logical packet data (payload)
|
||||
uint32_t subsequence; //< For data packets, this is the number of bytes successfully acked on the remote end
|
||||
uint32_t command; //< Logical packet command such as ZNETCMD_CONNECT, ZNETCMD_DATA, ...
|
||||
uint16_t sequence; //< Logical packet sequence
|
||||
};
|
||||
|
||||
ZNetPacketChannel() :
|
||||
packetCount(0), overflowLimit(1024), localAck(0), remoteAck(0), nextSequenceNumber(1), critical(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SetOverflowThreshold(uint32_t _overflowLimit) { overflowLimit = _overflowLimit; }
|
||||
|
||||
|
||||
/*
|
||||
ZNetPacketChannel::QueueForSending()
|
||||
|
||||
Attempts to queue a new packet to the channel. If the overflow limit is reached,
|
||||
this returns false and the client should be disconnected.
|
||||
*/
|
||||
bool QueueForSending(ZNetPacket* packet, uint32_t command);
|
||||
|
||||
bool QueueForReceiving();
|
||||
|
||||
|
||||
/*
|
||||
ZNetPacketChannel::SetChannelId()
|
||||
|
||||
Sets the channel's ID value for use in outgoing packets.
|
||||
*/
|
||||
void SetChannelId(uint32_t chId) { channelId = chId; }
|
||||
|
||||
/*
|
||||
ZNetPacketChannel::FillBuffer()
|
||||
|
||||
Fills a buffer with as many packets as the buffer can hold. If all packets
|
||||
have been added, this returns true. If there was not enough space to hold
|
||||
all of the packets, this returns false and the index to resume at is provided.
|
||||
|
||||
@param buffer - Input buffer pointer
|
||||
@param bufferSize - The size of the buffer pointed to by buffer[]
|
||||
@param packetStartIndex - The starting index. Should start at 0, and use the value returned in restartIndexReturn to resume
|
||||
@param restartIndexReturn - The index to resume packet storage.
|
||||
@param bytesWritten - The number of bytes written
|
||||
*/
|
||||
bool FillBuffer(uint8_t* buffer, uint32_t bufferSize, uint32_t packetStartIndex, uint32_t* restartIndexReturn, uint32_t* bytesWritten);
|
||||
|
||||
/*
|
||||
ZNetPacketChannel::Deinitialize()
|
||||
*/
|
||||
void Deinitialize();
|
||||
|
||||
|
||||
/*
|
||||
ZNetPacketChannel::UpdateRemoteAck()
|
||||
|
||||
Updates the remote ack counter and dequeues packets as necessary.
|
||||
|
||||
@param newHighest - The new highest sequence number
|
||||
@param pingAdjust - Set to the current ping value, this value is adjusted by the RTT on a per-packet basis
|
||||
*/
|
||||
void UpdateRemoteAck(uint16_t newHighest, int32_t* pingAdjust);
|
||||
|
||||
/*
|
||||
ZNetPacketChannel::UpdateLocalAck()
|
||||
|
||||
Updates the local sequence counter for this time period.
|
||||
*/
|
||||
void UpdateLocalAck(uint16_t seq);
|
||||
|
||||
/*
|
||||
ZNetPacketChannel::QueueLocally()
|
||||
|
||||
Queue a received packet for local consumption. Since packets have an ordering and they may be received out of
|
||||
order (e.g. send 1, 2, 3 may be processed as 2, 1, 3), this allows ZNet to reorder them and generate the
|
||||
appropriate sequence of events.
|
||||
*/
|
||||
bool QueueLocally(const ZNetPacketChannel::ZNetQueuedPacket* container);
|
||||
|
||||
/*
|
||||
ZNetPacketChannel::QueueData()
|
||||
|
||||
Queue a received data packet. This has one of three effects:
|
||||
1) Full data packet received (e.g. short packet), so it just acts like QueueLocally()
|
||||
2) Fragmented data packet, did not exist before now -- creates a reassembly buffer.
|
||||
3) Fragmented data packet, did exist -- adds to reassembly and check if reassembly is complete. If it is, QueueLocally().
|
||||
*/
|
||||
bool QueueData(ZNetPrivate::ZNetMessageContainer* data);
|
||||
|
||||
void ProcessLocalAcks();
|
||||
|
||||
void SetHost(ZNetHost* _host) { host = _host; }
|
||||
|
||||
ZNetHost* GetHost() const { return host; }
|
||||
|
||||
uint16_t GetLocalAck() { return localAck; }
|
||||
|
||||
//Return the highest sequence number for this channel. This is one less than the "next", intuitively.
|
||||
uint16_t GetHighestSent() { return nextSequenceNumber == 0 ? UINT16_MAX : nextSequenceNumber; }
|
||||
private:
|
||||
|
||||
struct ZNetDataReassemblyPacket
|
||||
{
|
||||
ZNetPacket* packet; //< Logical packet data (not yet fully assembled)
|
||||
uint32_t subsequence; //< Highest contiguous amount of data received
|
||||
uint16_t sequence; //< The sequence number of this packet
|
||||
};
|
||||
|
||||
ZList<ZNetQueuedPacket> packets; //List of packets we've sent (or will send) but have not yet been acknowledged
|
||||
ZList<ZNetDataReassemblyPacket> reassembly;
|
||||
ZList<ZNetQueuedPacket> assembled;
|
||||
ZList<uint16_t> sequencesFound; //The sequence numbers found this time around (sorted)
|
||||
ZNetHost* host; //Owner (used for memory allocations)
|
||||
uint32_t packetCount; //ZList::Size() is O(n), keep track manually
|
||||
uint32_t overflowLimit; //When this many outgoing packets are unacknowledged,
|
||||
uint32_t channelId; //This channel's ID value for outgoing packets
|
||||
uint16_t localAck; //Local acknowledge counter (i.e. highest number of incoming packets we've confirmed)
|
||||
uint16_t remoteAck; //Remote acknowledge counter (i.e. highest number the remote host has told us it has confirmed)
|
||||
uint16_t nextSequenceNumber; //Next outgoing sequence number
|
||||
|
||||
bool critical; //Is the remote host in a critical state?
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
143
Include/ZNet/ZNetPeer.hpp
Normal file
143
Include/ZNet/ZNetPeer.hpp
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
ZNetPeer.hpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/5/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
ZNet peer class, representing a remote host
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZNETPEER_HPP
|
||||
#define _ZNETPEER_HPP
|
||||
|
||||
#include <SST/SST_Net.h>
|
||||
#include <ZNet/ZNetConsts.hpp>
|
||||
#include <ZNet/ZNetPacketChannel.hpp>
|
||||
|
||||
class ZNetPeer;
|
||||
class ZNetServer;
|
||||
|
||||
class ZNetPeer
|
||||
{
|
||||
public:
|
||||
ZNetPeer();
|
||||
~ZNetPeer() { Deinitialize(); }
|
||||
|
||||
/*
|
||||
ZNetPeer::SetUserData()
|
||||
|
||||
Sets the user data for this peer. This value is not
|
||||
modified or inspected by ZNet. It defaults to NULL.
|
||||
|
||||
@param ud - The user data
|
||||
*/
|
||||
void SetUserData(void* ud) { userdata = ud; }
|
||||
|
||||
/*
|
||||
ZNetPeer:GetUserData()
|
||||
|
||||
Gets the user data for this peer.
|
||||
|
||||
@return (void*) - The user data
|
||||
*/
|
||||
void* GetUserData() { return userdata; }
|
||||
|
||||
/*
|
||||
ZNetPeer::GetNetAddress()
|
||||
|
||||
Gets the network address that this remote host uses.
|
||||
|
||||
@return (const SST_NetAddress*) - The remote host's network address
|
||||
*/
|
||||
const SST_NetAddress* GetNetAddress() const { return &addr; }
|
||||
|
||||
|
||||
/*
|
||||
ZNetPeer::GetState()
|
||||
|
||||
Gets the remote host's state. TODO: Is this necessary for public API?
|
||||
|
||||
@return (ZNetConnectionState) - The connection state
|
||||
*/
|
||||
ZNetConnectionState GetState() const { return state; }
|
||||
|
||||
/*
|
||||
ZNetPeer::GetSocket()
|
||||
|
||||
Gets the socket that was is used to send/receive from the remote host.
|
||||
*/
|
||||
SST_Socket GetSocket() const { return socketCopy; }
|
||||
|
||||
/*
|
||||
ZNetPeer::GetPing()
|
||||
|
||||
Gets the approximate ping. Note that the ping value is only updated
|
||||
when a packet is received, so during a disconnect event, this would not
|
||||
be accurate. Use GetLastReceived() to find the time since the last packet.
|
||||
|
||||
@return (int32_t) - The last known ping value. If < 0, then the ping is unknown.
|
||||
*/
|
||||
int32_t GetPing() { return ping; }
|
||||
|
||||
/*
|
||||
Gets the timestamp at which the last valid packet was received. Applications
|
||||
can use this as a sort of "health" meter for the link and decide how to change
|
||||
things such as client predictions during times of high latency. A value of 0
|
||||
indicates that no valid packet has yet been received. To compare timestamps,
|
||||
use SST_OS_GetMilliTime(). Note that only *valid* packets are considered; so
|
||||
hosts sending incompatible data are not considered.
|
||||
|
||||
@return (uint64_t) - The timestamp of the last valid packet.
|
||||
*/
|
||||
uint64_t GetLastReceived() { return lastValidIncoming; }
|
||||
|
||||
private:
|
||||
|
||||
/* Initialize the peer */
|
||||
bool Initialize(ZNetHost* _host, const SST_NetAddress* newAddr, SST_Socket s, uint32_t nrChannels);
|
||||
|
||||
void Deinitialize();
|
||||
|
||||
void SetState(ZNetConnectionState s) { state = s; }
|
||||
void SetLastReceived(uint64_t ts) { lastValidIncoming = ts; }
|
||||
void SetPing(int32_t _ping) { ping = _ping; }
|
||||
|
||||
|
||||
uint32_t GetNumberChannels() const { return nrChannels; }
|
||||
|
||||
ZNetPacketChannel* GetPacketChannel(uint32_t chId);
|
||||
|
||||
|
||||
//Process all received packets' sequence number to come up with a
|
||||
//new sequence number to tell the remote server that we've received.
|
||||
void ProcessLocalAcks();
|
||||
|
||||
void SendAcksForAllChannels();
|
||||
|
||||
friend class ZNetHost;
|
||||
friend class ZNetClient;
|
||||
friend class ZNetServer;
|
||||
|
||||
SST_NetAddress addr; //Remote address
|
||||
uint64_t lastValidIncoming; //Last time a valid packet was received
|
||||
uint64_t lastOutgoingAck; //Last time an outgoing ACK was sent, or 0 for never.
|
||||
SST_Socket socketCopy; //Copy of the socket that was used connect to this peer
|
||||
ZNetPacketChannel* channels; //The packet channels
|
||||
void* userdata; //User data
|
||||
uint32_t nrChannels; //Size of channels[] array
|
||||
int32_t ping; //Estimated ping
|
||||
ZNetConnectionState state; //Connection state
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
240
Include/ZNet/ZNetServer.hpp
Normal file
240
Include/ZNet/ZNetServer.hpp
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
ZNetServer.hpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 7/10/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
ZNetServer -- extends ZNetHost to provide a server
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZNETSERVER_HPP
|
||||
#define _ZNETSERVER_HPP
|
||||
|
||||
#include <ZNet/ZNetHost.hpp>
|
||||
#include <ZNet/ZNetConsts.hpp>
|
||||
#include <ZSTL/ZHashMap.hpp>
|
||||
#include <SST/SST_Net.h>
|
||||
|
||||
typedef uint32_t (*ZNetConnectCallback)(const SST_NetAddress* addr, uint32_t userdata, void* callbackParam);
|
||||
|
||||
|
||||
class ZNetServer : public ZNetHost
|
||||
{
|
||||
public:
|
||||
|
||||
ZNetServer();
|
||||
~ZNetServer();
|
||||
|
||||
/*
|
||||
ZNetServer::Initialize()
|
||||
|
||||
Initializes the ZNetServer instance.
|
||||
|
||||
*/
|
||||
bool Initialize(uint32_t peerCount, uint32_t channelCount);
|
||||
|
||||
/*
|
||||
ZNetServer::AddSocket()
|
||||
|
||||
Adds a socket for ZNet to listen on. ZNet may listen on multiple
|
||||
sockets, but once a socket is added, it cannot be removed. This
|
||||
limit may be lifted. Only up to ZNET_MAX_SERVER_SOCKETS can be
|
||||
added.
|
||||
|
||||
@param s - The socket to listen on.
|
||||
@return (bool) - True if successful, false otherwise
|
||||
*/
|
||||
bool AddSocket(SST_Socket s);
|
||||
|
||||
/*
|
||||
ZNetServer::Update()
|
||||
|
||||
Checks sockets and packet queues for incoming/outgoing traffic. Use GetEvent() to
|
||||
fetch events generated.
|
||||
|
||||
@return (int) - Less than 0: error. 0: OK
|
||||
*/
|
||||
int Update();
|
||||
|
||||
/*
|
||||
ZNetServer::SendPacket()
|
||||
|
||||
Sends a packet to a peer via a certain channel. Use ZNetPacket::Release()
|
||||
when the packet is no longer needed.
|
||||
|
||||
@param packet - The packet to broadcast
|
||||
@param peer - The remote host to send to
|
||||
@param channelId - The channel ID
|
||||
*/
|
||||
void SendPacket(ZNetPacket* packet, ZNetPeer* peer, uint8_t channelId);
|
||||
|
||||
/*
|
||||
ZNetServer::BroadcastPacket()
|
||||
|
||||
Sends a packet to all peers via a certain channel. Use ZNetPacket::Release()
|
||||
when the packet is no longer needed.
|
||||
|
||||
@param packet - The packet to broadcast
|
||||
@param channelId - The channel ID
|
||||
*/
|
||||
void BroadcastPacket(ZNetPacket* packet, uint8_t channelId);
|
||||
|
||||
/*
|
||||
ZNetServer::DisconnectPeer()
|
||||
|
||||
Gracefully disconnects a peer. The peer is sent a message letting him/her
|
||||
that he/she has been disconnected and awaiting confirmation. The reason code
|
||||
parameter is sent to the peer.
|
||||
|
||||
@param peer - The peer to signal a disconnect to
|
||||
@param reasonCode - The application-specific reason code. This is not interpreted by ZNet in any way.
|
||||
*/
|
||||
void DisconnectPeer(ZNetPeer* peer, uint32_t reasonCode);
|
||||
|
||||
/*
|
||||
ZNetServer::ResetPeer()
|
||||
|
||||
Disconnects the peer, but does not inform him/her that the disconnect has occurred.
|
||||
This should only be used when a graceful disconnect does not work or when aborting
|
||||
the server. No local event is generated, so any cleanup of the peer must be done
|
||||
immediately.
|
||||
|
||||
@param packet - The packet to broadcast
|
||||
@param channelId - The channel ID
|
||||
*/
|
||||
void ResetPeer(ZNetPeer* peer);
|
||||
|
||||
/*
|
||||
ZNetServer::NextPeer()
|
||||
|
||||
Gets the next peer in list of peers. The ordering is completely arbitrary and should not be
|
||||
relied on, thus you should only pass NULL or the return value from an earlier NextPeer() call.
|
||||
|
||||
This can be used to iterate through the list of peers:
|
||||
|
||||
ZNetPeer* p = Server->NextPeer(NULL);
|
||||
while(p)
|
||||
{
|
||||
DoSomethingWithPeer(p);
|
||||
p = Server->NextPeer(p);
|
||||
}
|
||||
|
||||
@param thisPeer - The peer to get the next of, or NULL to start.
|
||||
@return (ZNetPeer*) - The next peer, or NULL if reached the end.
|
||||
*/
|
||||
ZNetPeer* NextPeer(ZNetPeer* thisPeer);
|
||||
|
||||
//======================================================================
|
||||
// TRIVIAL GETTER / SETTER
|
||||
//======================================================================
|
||||
|
||||
/*
|
||||
ZNetServer::SetListenFlag()
|
||||
|
||||
Sets the listen flag. When true, the server reports incoming connections
|
||||
for normal processing. When false, the server does not report incoming connections
|
||||
and automatically rejects them.
|
||||
|
||||
@param _listenFlag - The new value for the listen flag
|
||||
*/
|
||||
void SetListenFlag(bool _listenFlag) { listenFlag = _listenFlag; }
|
||||
|
||||
/*
|
||||
ZNetServer::SetConnectCallback()
|
||||
|
||||
Sets the connection callback. When non-NULL, the server calls this function when
|
||||
a connection attempt is made. Returning 0 indicates the client should be accepted,
|
||||
while any other value indicates that the client should be rejected. If no function
|
||||
is present, the server automatically accepts the client. This should be used to
|
||||
implement ban lists.
|
||||
|
||||
@param fn - The new callback function, or NULL to disable it
|
||||
*/
|
||||
void SetConnectCallback(ZNetConnectCallback fn) { connectCallback = fn; }
|
||||
|
||||
/*
|
||||
ZNetServer::SetCallbackParam()
|
||||
|
||||
Sets the parameter that is passed to the callback. It defaults to NULL.
|
||||
|
||||
@param param - The callback parameter
|
||||
*/
|
||||
void SetCallbackParam(void* param) { callbackParam = param; }
|
||||
|
||||
/*
|
||||
ZNetServer::GetListenFlag()
|
||||
|
||||
Gets the listen flag. See ZNetServer::SetListenFlag() for a description of the
|
||||
listen flag.
|
||||
|
||||
@return (bool) - The value of the listen flag
|
||||
*/
|
||||
bool GetListenFlag() const { return listenFlag; }
|
||||
|
||||
/*
|
||||
ZNetServer::GetMaximumClientCount()
|
||||
|
||||
Gets the maximum number of clients that may be simultaneously connected.
|
||||
|
||||
@return (uint32_t) - The maximum number of clients
|
||||
*/
|
||||
uint32_t GetMaximumClientCount() const { return maxClients; }
|
||||
|
||||
/*
|
||||
ZNetServer::GetClientCount()
|
||||
|
||||
Gets the number of clients who are currently connected.
|
||||
|
||||
@return (uint32_t) - The number of clients who are connected.
|
||||
*/
|
||||
uint32_t GetClientCount() const { return clientCount; }
|
||||
|
||||
/*
|
||||
ZNetServer::GetConnectCallback()
|
||||
|
||||
Gets the currently installed callback function, or NULL if none is
|
||||
present.
|
||||
|
||||
@return (ZNetConnectCallback) - The connect callback
|
||||
*/
|
||||
ZNetConnectCallback GetConnectCallback() { return connectCallback; }
|
||||
|
||||
/*
|
||||
ZNetServer::GetCallbackParam()
|
||||
|
||||
Gets the parameter that is passed to the callback function. This
|
||||
defaults to NULL.
|
||||
|
||||
@return (void*) - The callback parameter
|
||||
*/
|
||||
void* GetCallbackParam() { return callbackParam; }
|
||||
private:
|
||||
ZNetPeer* peers; //< The number of peers
|
||||
SST_Socket sockets[ZNET_MAX_SERVER_SOCKETS]; //< The sockets that ZNet can listen on
|
||||
ZNetConnectCallback connectCallback;
|
||||
void* callbackParam;
|
||||
uint32_t channelCount; //< The number of channels
|
||||
uint32_t maxClients; //< The maximum number of clients
|
||||
uint32_t clientCount; //< The current number of clients
|
||||
bool listenFlag; //< The listen flag
|
||||
|
||||
|
||||
|
||||
void HandlePacket(SST_Socket s, const SST_NetAddress* addr, const uint8_t* data, uint32_t length);
|
||||
|
||||
void TrySendConnResp(SST_Socket s, const SST_NetAddress* addr, uint32_t reasonCode, uint32_t flags);
|
||||
|
||||
ZNetPeer* PeerForAddress(const SST_NetAddress* addr) const;
|
||||
|
||||
ZNetPeer* FindEmptyPeerSlot();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
49
Include/ZNet/ZNetUtil.hpp
Normal file
49
Include/ZNet/ZNetUtil.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
ZNetUtil.hpp
|
||||
Author: Patrick Baggett <ptbaggett@762studios.com>
|
||||
Created: 6/5/2013
|
||||
|
||||
Purpose:
|
||||
|
||||
ZNet utility functions
|
||||
|
||||
License:
|
||||
|
||||
Copyright 2013, 762 Studios
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _ZNETUTIL_HPP
|
||||
#define _ZNETUTIL_HPP
|
||||
|
||||
#include <ZUtil/ZBinaryBufferReader.hpp>
|
||||
#include <ZUtil/ZBinaryBufferWriter.hpp>
|
||||
#include <ZNet/ZNetPacket.hpp>
|
||||
|
||||
namespace ZNetUtil
|
||||
{
|
||||
/*
|
||||
ZNetUtil::ReaderForPacket
|
||||
|
||||
Constructs a ZBinaryBufferReader for the given packet to read it.
|
||||
|
||||
@param packet - The packet to read
|
||||
@return (ZBinaryBufferReader) - The reader class
|
||||
*/
|
||||
inline ZBinaryBufferReader ReaderForPacket(ZNetPacket* packet) { return ZBinaryBufferReader(packet->data, packet->dataSize, ZNET_BYTEORDER); }
|
||||
|
||||
/*
|
||||
ZNetUtil::WriterForPacket
|
||||
|
||||
Constructs a ZBinaryBufferWriter for the given packet to read it.
|
||||
|
||||
@param packet - The packet to read
|
||||
@return (ZBinaryBufferWriter) - The writer class
|
||||
*/
|
||||
inline ZBinaryBufferWriter WriterForPacket(ZNetPacket* packet) { return ZBinaryBufferWriter(packet->data, packet->dataSize, ZNET_BYTEORDER); }
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user