Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <network/address.h>
|
||||
#include <network/client.h>
|
||||
#include <network/connection.h>
|
||||
#include <network/init.h>
|
||||
#include <network/lobby.h>
|
||||
#include <network/message.h>
|
||||
#include <network/message_handler.h>
|
||||
#include <network/message_types.h>
|
||||
#include <network/sequence.h>
|
||||
#include <network/server.h>
|
||||
#include <network/time.h>
|
||||
#include <network/transport.h>
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <functional>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
//Yay more shitty compiler implementation
|
||||
//assumptions because windows sucks.
|
||||
struct sockaddr;
|
||||
struct sockaddr_storage;
|
||||
struct addrinfo;
|
||||
typedef int socklen_t;
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
|
||||
namespace net {
|
||||
|
||||
enum AddressType {
|
||||
AT_IPv4,
|
||||
AT_IPv6,
|
||||
AT_INVALID,
|
||||
};
|
||||
|
||||
struct Address {
|
||||
AddressType type;
|
||||
int port;
|
||||
union {
|
||||
int adr4;
|
||||
uint8_t adr6[16];
|
||||
size_t adr6Hash;
|
||||
};
|
||||
|
||||
Address();
|
||||
Address(const std::string& hostname, int port, AddressType type = AT_IPv4);
|
||||
Address(int ip4, int port);
|
||||
Address(uint8_t* ip6, int port);
|
||||
|
||||
std::string toString(bool showPort = true) const;
|
||||
|
||||
void to_sockaddr(sockaddr_storage& adr, socklen_t* size = 0) const;
|
||||
void from_sockaddr(sockaddr_storage& adr);
|
||||
|
||||
bool operator<(const Address& other) const;
|
||||
bool operator==(const Address& other) const;
|
||||
bool ipEquals(const Address& other) const;
|
||||
};
|
||||
|
||||
struct addrinfo* lookup(const std::string& hostname, int port = 0, AddressType type = AT_IPv4);
|
||||
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<net::Address> {
|
||||
size_t operator() (const net::Address& addr) const {
|
||||
return addr.type == net::AT_IPv4 ? (size_t)addr.adr4 : addr.adr6Hash;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
#pragma once
|
||||
#include <network/message.h>
|
||||
#include <network/message_handler.h>
|
||||
#include <network/connection.h>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace net {
|
||||
struct LobbyHeartbeat;
|
||||
struct LobbyPunchthrough;
|
||||
|
||||
/*
|
||||
* Client
|
||||
* ------
|
||||
* Connects to a server at an address, and handles incoming
|
||||
* messages from the server to the client.
|
||||
*/
|
||||
|
||||
class Client : public MessageHandler {
|
||||
public:
|
||||
typedef std::function<void(Client&,Message&)> clMessageHandler;
|
||||
Address address;
|
||||
bool established;
|
||||
|
||||
std::string hostname;
|
||||
bool hasConnection;
|
||||
bool resolved;
|
||||
|
||||
//Connect to the server on address, if makeConnection is true,
|
||||
//establish a connection, otherwise send only connectionless messages
|
||||
Client(Address connectTo, bool makeConnection = true);
|
||||
Client(const std::string& hostname, int port, bool makeConnection = true, AddressType type = AT_IPv4);
|
||||
~Client();
|
||||
|
||||
//Handlers for any messages that are sent to this client
|
||||
void resolve();
|
||||
void handle(uint8_t type, clMessageHandler func);
|
||||
void handleClear(uint8_t type);
|
||||
|
||||
//Send and get ping for the connection
|
||||
void sendPing();
|
||||
unsigned getLastPing();
|
||||
|
||||
//Shortcut for sending messages to the server
|
||||
Client& operator<<(Message& msg);
|
||||
Connection* getConnection();
|
||||
|
||||
//Overrides to add functionality to MessageHandler
|
||||
virtual void handleMessage(Transport* transport, Address addr, Message* msg);
|
||||
virtual bool mainTick();
|
||||
virtual void stop();
|
||||
private:
|
||||
threads::Mutex handlerMutex;
|
||||
std::unordered_map<uint8_t, clMessageHandler> handlers;
|
||||
|
||||
Transport* trans;
|
||||
Connection* conn;
|
||||
|
||||
friend LobbyHeartbeat;
|
||||
friend LobbyPunchthrough;
|
||||
};
|
||||
|
||||
/*
|
||||
* BroadcastClient
|
||||
* ---------------
|
||||
* Can broadcast messages and interact with replies to broadcasts.
|
||||
*/
|
||||
class BroadcastClient : public MessageHandler {
|
||||
public:
|
||||
typedef std::function<void(BroadcastClient&,Address,Message&)> bcMessageHandler;
|
||||
|
||||
//Connect to the server on address, if makeConnection is true,
|
||||
//establish a connection, otherwise send only connectionless messages
|
||||
BroadcastClient(int Port, AddressType Type = AT_IPv4);
|
||||
~BroadcastClient();
|
||||
|
||||
//Handlers for any messages that are sent to this client
|
||||
void handle(uint8_t type, bcMessageHandler func);
|
||||
void handleClear(uint8_t type);
|
||||
|
||||
//Send messages to an address over the transport
|
||||
void send(Message& msg, Address addr);
|
||||
|
||||
//Broadcast messages on the port
|
||||
void broadcast(Message& msg);
|
||||
|
||||
//Overrides to add functionality to MessageHandler
|
||||
virtual void handleMessage(Transport* transport, Address addr, Message* msg);
|
||||
private:
|
||||
threads::Mutex handlerMutex;
|
||||
std::unordered_map<uint8_t, bcMessageHandler> handlers;
|
||||
|
||||
int port;
|
||||
Transport trans;
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,164 @@
|
||||
#pragma once
|
||||
#include "threads.h"
|
||||
#include <network/transport.h>
|
||||
#include <network/address.h>
|
||||
#include <network/time.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
namespace net {
|
||||
|
||||
#ifndef NET_RESEND_TIME
|
||||
#define NET_RESEND_TIME 100
|
||||
#endif
|
||||
|
||||
#ifndef NET_RESEND_RELIABLE_TIME
|
||||
#define NET_RESEND_RELIABLE_TIME 250
|
||||
#endif
|
||||
|
||||
#ifndef NET_RESEND_PERIOD
|
||||
#define NET_RESEND_PERIOD 5
|
||||
#endif
|
||||
|
||||
#ifndef NET_SEQUENCE_FUTURE
|
||||
#define NET_SEQUENCE_FUTURE 100
|
||||
#endif
|
||||
|
||||
#ifndef NET_PING_INTERVAL
|
||||
#define NET_PING_INTERVAL 1000
|
||||
#endif
|
||||
|
||||
#ifndef NET_PING_TIMEOUT
|
||||
#define NET_PING_TIMEOUT 5000
|
||||
#endif
|
||||
|
||||
#ifndef NET_FRAGMENT_LIMIT
|
||||
#define NET_FRAGMENT_LIMIT 1000
|
||||
#endif
|
||||
|
||||
#ifndef NET_FRAGMENT_OVERHEAD
|
||||
#define NET_FRAGMENT_OVERHEAD 10
|
||||
#endif
|
||||
|
||||
#ifndef NET_FRAGMENT_TIMEOUT
|
||||
#define NET_FRAGMENT_TIMEOUT 5000
|
||||
#endif
|
||||
|
||||
struct OutSequence;
|
||||
struct InSequence;
|
||||
|
||||
struct SeqAck {
|
||||
unsigned short seqID;
|
||||
unsigned short msgID;
|
||||
};
|
||||
class Connection {
|
||||
//Connections can send messages reliable, that is,
|
||||
//messages with flag MF_Reliable set will be resent until
|
||||
//acknowledged by the other side
|
||||
struct MessageAwaitingAck {
|
||||
Message* msg;
|
||||
time lastResend;
|
||||
};
|
||||
|
||||
mutable threads::atomic_int references;
|
||||
|
||||
threads::Mutex ackMutex;
|
||||
std::unordered_set<unsigned short> queuedAcks;
|
||||
std::vector<SeqAck> queuedSeqAcks;
|
||||
|
||||
threads::Mutex reliableMutex;
|
||||
std::list<Message*> queuedReliable;
|
||||
std::unordered_set<unsigned short> handledMessages;
|
||||
std::unordered_set<unsigned short> unorderedAcks;
|
||||
unsigned short nextOutgoingID;
|
||||
unsigned short nextAck;
|
||||
unsigned nextReliablePeriod;
|
||||
void handleAck(unsigned short id);
|
||||
|
||||
bool split(Message& msg);
|
||||
void queueReliable(Message* msg, bool immediate = false);
|
||||
bool shouldHandleID(unsigned short id);
|
||||
|
||||
threads::Mutex msgQueueLock;
|
||||
std::list<Message*> queuedMessages;
|
||||
void queue(Message* msg);
|
||||
|
||||
struct WindowPacket {
|
||||
Message* msg;
|
||||
time added, sent;
|
||||
};
|
||||
|
||||
threads::Mutex windowMutex;
|
||||
size_t windowBytes, windowUsed;
|
||||
double windowLength, windowUpdate;
|
||||
std::deque<WindowPacket> window;
|
||||
|
||||
//Connections also have sequences of ordered, reliable messages
|
||||
threads::Mutex sequenceMutex;
|
||||
unsigned nextSequenceID;
|
||||
|
||||
std::unordered_map<unsigned short, OutSequence*> outSequences;
|
||||
std::unordered_map<unsigned short, InSequence*> inSequences;
|
||||
|
||||
//Connections handle message fragmentation transparently.
|
||||
//Messages over the fragment limit are sent in multiple parts without
|
||||
//any application interaction.
|
||||
threads::Mutex fragmentMutex;
|
||||
threads::atomic_int nextFragmentID;
|
||||
struct Fragment {
|
||||
std::vector<Message*> received;
|
||||
unsigned fragmentCount;
|
||||
time lastActivity;
|
||||
};
|
||||
std::unordered_map<unsigned, Fragment*> waitingFragments;
|
||||
void handleFragment(MessageHandler& handler, Message* msg);
|
||||
|
||||
//Connections will keep themselves alive by pingponging, and time
|
||||
//out if we get no messages or responses to our pings for a certain
|
||||
//amount of time
|
||||
unsigned pingPongWait;
|
||||
time lastMessageReceived;
|
||||
time lastPingSent;
|
||||
time firstPingSent;
|
||||
bool pingSent;
|
||||
|
||||
time lastProcessTime;
|
||||
unsigned outBytes, inBytes;
|
||||
|
||||
public:
|
||||
Transport& transport;
|
||||
bool active;
|
||||
Address address;
|
||||
int id;
|
||||
|
||||
int availBytes;
|
||||
|
||||
void grab() const;
|
||||
void drop() const;
|
||||
|
||||
unsigned ping;
|
||||
void sendPing();
|
||||
|
||||
bool preHandle(MessageHandler& handler, Message* msg);
|
||||
void postHandle(MessageHandler& handler, Message* msg);
|
||||
void process(MessageHandler& handler);
|
||||
|
||||
//Returns the total amount of traffic in bytes since the last time getTraffic was called
|
||||
void getTraffic(unsigned& in_bytes, unsigned& out_bytes, unsigned& queuedPackets);
|
||||
|
||||
OutSequence* sequence();
|
||||
void queueSeqAck(unsigned short sequenceID, unsigned short messageID);
|
||||
|
||||
Connection(Transport& trans, Address addr);
|
||||
Connection& operator<<(Message& msg);
|
||||
//Sends a messsage through the pipe, immediately if possible
|
||||
// Returns true if the message should be considered sent
|
||||
bool send(Message& msg, bool isResend);
|
||||
~Connection();
|
||||
|
||||
friend OutSequence;
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace net {
|
||||
|
||||
typedef void (*netErrorCallback)(const char* message, int code);
|
||||
|
||||
void setErrorCallback(netErrorCallback cb);
|
||||
void netError(const char* err, int code);
|
||||
|
||||
bool prepare();
|
||||
void clear();
|
||||
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
#pragma once
|
||||
#include <network/message.h>
|
||||
#include <network/client.h>
|
||||
#include <network/server.h>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
#include "threads.h"
|
||||
|
||||
namespace net {
|
||||
|
||||
#ifndef NET_LOBBY_HEARTBEAT_INTERVAL
|
||||
#define NET_LOBBY_HEARTBEAT_INTERVAL 1000
|
||||
#endif
|
||||
|
||||
#ifndef NET_LOBBY_HEARTBEAT_TIMEOUT
|
||||
#define NET_LOBBY_HEARTBEAT_TIMEOUT 5000
|
||||
#endif
|
||||
|
||||
#ifndef NET_LOBBY_QUERY_TIMEOUT
|
||||
#define NET_LOBBY_QUERY_TIMEOUT 3000
|
||||
#endif
|
||||
|
||||
enum LobbyMessage {
|
||||
LM_Heartbeat = MT_Application,
|
||||
LM_Query,
|
||||
LM_Result,
|
||||
LM_Results_End,
|
||||
LM_Identify,
|
||||
};
|
||||
|
||||
enum LobbyFilterMode {
|
||||
LFM_Ignore,
|
||||
LFM_True,
|
||||
LFM_False,
|
||||
};
|
||||
|
||||
struct Game {
|
||||
Address address;
|
||||
std::string name, mod;
|
||||
unsigned short players, maxPlayers;
|
||||
bool started, isLocal, password, listed;
|
||||
int punchPort, version;
|
||||
|
||||
Game() : players(0), maxPlayers(0), started(false), isLocal(false), listed(true), password(false), punchPort(-1), version(0) {
|
||||
}
|
||||
void write(Message& msg);
|
||||
void read(Message& msg);
|
||||
};
|
||||
|
||||
struct LobbyQuery {
|
||||
typedef std::function<void(Game&)> ResultHandler;
|
||||
|
||||
Client client;
|
||||
BroadcastClient broadcast;
|
||||
int broadcastPort;
|
||||
ResultHandler handler;
|
||||
|
||||
threads::Signal running;
|
||||
bool active;
|
||||
bool doUpdate;
|
||||
bool queryServer;
|
||||
bool queryBroadcast;
|
||||
|
||||
std::set<Address> handled_lobbies;
|
||||
unsigned short receivedFromServer;
|
||||
unsigned short totalFromServer;
|
||||
|
||||
LobbyQuery(Address ServerAddress, int BroadcastPort = -1);
|
||||
LobbyQuery(const std::string& hostname, int port, int BroadcastPort = -1, AddressType type = AT_IPv4);
|
||||
void bind();
|
||||
~LobbyQuery();
|
||||
|
||||
LobbyFilterMode full, started;
|
||||
std::string name, mod;
|
||||
|
||||
bool updating;
|
||||
void refresh(bool queryServer = true, bool queryBroadcast = true);
|
||||
void update(bool clear);
|
||||
void stop();
|
||||
};
|
||||
|
||||
struct LobbyPunchthrough {
|
||||
Client* client;
|
||||
|
||||
threads::Signal running;
|
||||
Address lobbyAddress;
|
||||
bool active;
|
||||
uint64_t interval;
|
||||
bool established;
|
||||
|
||||
LobbyPunchthrough(Address ServerAddress, Client* client);
|
||||
void stop();
|
||||
void heartbeat();
|
||||
|
||||
~LobbyPunchthrough();
|
||||
};
|
||||
|
||||
struct LobbyHeartbeat : public Game {
|
||||
Client client;
|
||||
Transport* transport;
|
||||
Server broadcast;
|
||||
int broadcastPort;
|
||||
threads::Signal running;
|
||||
int fullCounter;
|
||||
bool active;
|
||||
uint64_t interval;
|
||||
|
||||
bool identified;
|
||||
unsigned externalIP;
|
||||
unsigned short externalPort;
|
||||
|
||||
LobbyHeartbeat(Address ServerAddress, int BroadcastPort = -1);
|
||||
void enablePunchthrough(Server* server);
|
||||
void run(bool doQuery = true, bool doBroadcast = true);
|
||||
void stop();
|
||||
void heartbeat();
|
||||
void identRequest();
|
||||
|
||||
~LobbyHeartbeat();
|
||||
};
|
||||
|
||||
struct LobbyServer {
|
||||
struct GameDesc : public Game {
|
||||
time lastHeartbeat;
|
||||
};
|
||||
|
||||
Server server;
|
||||
threads::ReadWriteMutex mutex;
|
||||
threads::Signal running;
|
||||
std::map<Address, GameDesc> games;
|
||||
bool active, logging;
|
||||
|
||||
LobbyServer(int port, const std::string& address = "", bool logging = true);
|
||||
void listen(int port, const std::string& address = "");
|
||||
|
||||
void runThreads(int workerThreads = 4);
|
||||
void stop();
|
||||
|
||||
~LobbyServer();
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,331 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <network/message_types.h>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace net {
|
||||
|
||||
|
||||
//Message
|
||||
//======
|
||||
//Handles memory between the Network and Application
|
||||
//
|
||||
//Use 'message >> variable' to read from the Message
|
||||
//Use 'message << variable' to write to the Message
|
||||
//
|
||||
//To send a message,
|
||||
//Message msg(MessageType);
|
||||
//msg << data;
|
||||
|
||||
class MessageReadError {
|
||||
};
|
||||
|
||||
typedef unsigned msize_t;
|
||||
|
||||
struct Message {
|
||||
//Prepares a message for sending
|
||||
Message();
|
||||
Message(uint8_t type, uint8_t flags = 0);
|
||||
Message(uint8_t* data, msize_t bytes);
|
||||
Message(Message& other);
|
||||
|
||||
void setType(uint8_t type);
|
||||
uint8_t getType() const;
|
||||
|
||||
uint8_t getFlags() const;
|
||||
void setFlags(uint8_t flags);
|
||||
|
||||
bool hasFlags() const;
|
||||
bool getFlag(uint8_t flag) const;
|
||||
|
||||
bool hasID() const;
|
||||
unsigned short getID() const;
|
||||
void setID(unsigned short id);
|
||||
|
||||
unsigned short getSeqID() const;
|
||||
void setSeqID(unsigned short id);
|
||||
|
||||
msize_t size() const;
|
||||
|
||||
//Reserve space on the message for filling in later
|
||||
msize_t reserve(size_t bytes);
|
||||
|
||||
template<class T>
|
||||
msize_t reserve() {
|
||||
return reserve(sizeof(T));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void fill(msize_t pos, const T& value) {
|
||||
memcpy(buffer->data() + pos, (void*)&value, sizeof(T));
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool canRead() const {
|
||||
return used_bytes * 8 + used_bits >= (read_bytes + sizeof(T)) * 8 + read_bits;
|
||||
}
|
||||
|
||||
//Easy write functions (msg << data)
|
||||
template<class T>
|
||||
void write(T value) {
|
||||
writeBits((uint8_t*)&value, sizeof(T) * 8);
|
||||
}
|
||||
|
||||
void write(void* ptr, unsigned bytes) {
|
||||
writeBits((uint8_t*)ptr, bytes * 8);
|
||||
}
|
||||
|
||||
void read(void* ptr, unsigned bytes) {
|
||||
readBits((uint8_t*)ptr, bytes * 8);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Message& operator<<(const T& value) {
|
||||
writeBits((uint8_t*)&value, sizeof(T) * 8);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& operator<<(bool bit);
|
||||
Message& operator<<(const char* str);
|
||||
Message& operator<<(const std::string& str);
|
||||
|
||||
//Easy read functions (msg >> data)
|
||||
template<class T>
|
||||
Message& operator>>(T& value) {
|
||||
readBits((uint8_t*)&value, sizeof(T) * 8);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Message& operator>>(bool& bit);
|
||||
Message& operator>>(char*& str);
|
||||
Message& operator>>(std::string& str);
|
||||
|
||||
//Writing and reading vectors
|
||||
template<class T>
|
||||
Message& operator<<(const std::vector<T>& arr) {
|
||||
*this << (unsigned short)arr.size();
|
||||
for(auto it = arr.begin(), end = arr.end(); it != end; ++it)
|
||||
*this << *it;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Message& operator>>(const std::vector<T>& arr) {
|
||||
unsigned short size;
|
||||
*this >> size;
|
||||
arr.reserve(size);
|
||||
|
||||
for(unsigned short i = 0; i < size; ++i) {
|
||||
T elem;
|
||||
*this >> elem;
|
||||
arr.push_back(elem);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Writing and reading lists
|
||||
template<class T>
|
||||
Message& operator<<(const std::list<T>& arr) {
|
||||
*this << (unsigned short)arr.size();
|
||||
for(auto it = arr.begin(), end = arr.end(); it != end; ++it)
|
||||
*this << *it;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
Message& operator>>(const std::list<T>& arr) {
|
||||
unsigned short size;
|
||||
*this >> size;
|
||||
arr.reserve(size);
|
||||
|
||||
for(unsigned short i = 0; i < size; ++i) {
|
||||
T elem;
|
||||
*this >> elem;
|
||||
arr.push_back(elem);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Writing and reading maps
|
||||
template<class K, class V>
|
||||
Message& operator<<(const std::map<K,V>& mp) {
|
||||
*this << (unsigned short)mp.size();
|
||||
for(auto it = mp.begin(), end = mp.end(); it != end; ++it) {
|
||||
*this << it->first;
|
||||
*this << it->second;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class K, class V>
|
||||
Message& operator>>(const std::map<K,V>& mp) {
|
||||
unsigned short size;
|
||||
*this >> size;
|
||||
|
||||
for(unsigned short i = 0; i < size; ++i) {
|
||||
K key; V value;
|
||||
*this >> key;
|
||||
*this >> value;
|
||||
|
||||
mp[key] = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Writing and reading unordered maps
|
||||
template<class K, class V>
|
||||
Message& operator<<(const std::unordered_map<K,V>& mp) {
|
||||
*this << (unsigned short)mp.size();
|
||||
for(auto it = mp.begin(), end = mp.end(); it != end; ++it) {
|
||||
*this << it->first;
|
||||
*this << it->second;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class K, class V>
|
||||
Message& operator>>(const std::unordered_map<K,V>& mp) {
|
||||
unsigned short size;
|
||||
*this >> size;
|
||||
|
||||
for(unsigned short i = 0; i < size; ++i) {
|
||||
K key; V value;
|
||||
*this >> key;
|
||||
*this >> value;
|
||||
|
||||
mp[key] = value;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T readIn() {
|
||||
T v;
|
||||
*this >> v;
|
||||
return v;
|
||||
}
|
||||
|
||||
void writeSmall(unsigned value);
|
||||
unsigned readSmall();
|
||||
|
||||
void writeSignedSmall(int value);
|
||||
int readSignedSmall();
|
||||
|
||||
void writeBitValue(unsigned value, uint8_t bits);
|
||||
unsigned readBitValue(uint8_t bits);
|
||||
|
||||
void writeLimited(unsigned value, unsigned limit);
|
||||
void writeLimited(unsigned value, unsigned min, unsigned max);
|
||||
unsigned readLimited(unsigned limit);
|
||||
unsigned readLimited(unsigned min, unsigned max);
|
||||
|
||||
void writeFixed(double value, double min, double max, uint8_t bits = 16);
|
||||
double readFixed(double min, double max, uint8_t bits = 16);
|
||||
|
||||
//Writes a vec3 to a much smaller version without sacrificing signicant quality
|
||||
void writeSmallVec3(double x, double y, double z);
|
||||
void readSmallVec3(double& x, double& y, double& z);
|
||||
|
||||
//Writes a vec3 to a smaller version without sacrificing noticeable quality
|
||||
void writeMedVec3(double x, double y, double z);
|
||||
void readMedVec3(double& x, double& y, double& z);
|
||||
|
||||
//Writes a direction (unit vector) in a very small size
|
||||
void writeDirection(double x, double y, double z, unsigned acc = 12);
|
||||
void readDirection(double& x, double& y, double& z, unsigned acc = 12);
|
||||
|
||||
//Writes a rotation (unit quaterniond) in a very small size
|
||||
void writeRotation(double x, double y, double z, double w);
|
||||
void readRotation(double& x, double& y, double& z, double& w);
|
||||
|
||||
void finalize();
|
||||
|
||||
void writeAlign();
|
||||
void writeBits(uint8_t* ptr, unsigned bits);
|
||||
|
||||
void readAlign();
|
||||
void readBits(uint8_t* ptr, unsigned bits);
|
||||
|
||||
void writeBit(bool bit);
|
||||
void write1();
|
||||
void write0();
|
||||
|
||||
bool readBit();
|
||||
|
||||
~Message();
|
||||
|
||||
bool hasError() const;
|
||||
|
||||
void clear();
|
||||
void dump();
|
||||
|
||||
void reset();
|
||||
|
||||
void advance(unsigned bits);
|
||||
void rewind();
|
||||
void rewind(unsigned bytes, unsigned bits = 0);
|
||||
|
||||
struct Position {
|
||||
msize_t bytes;
|
||||
uint8_t bits;
|
||||
};
|
||||
|
||||
Position getReadPosition();
|
||||
Position getWritePosition();
|
||||
|
||||
void setReadPosition(Position pos);
|
||||
void setWritePosition(Position pos);
|
||||
|
||||
void copyTo(Message& to, msize_t fromPos = 0, msize_t toPos = 0) const;
|
||||
|
||||
void move(Message& other);
|
||||
void operator=(const Message& other);
|
||||
|
||||
uint8_t& operator[](msize_t byte);
|
||||
const uint8_t& operator[](msize_t byte) const;
|
||||
|
||||
void getAsPacket(char*& pBytes, msize_t& bytes);
|
||||
void setPacket(char* pBytes, msize_t bytes);
|
||||
private:
|
||||
|
||||
void allocate(msize_t size);
|
||||
|
||||
//Prepares the write stage for the addition of <bytes> bytes
|
||||
void _prepwrite(msize_t bytes);
|
||||
|
||||
struct Buffer {
|
||||
//Values in every message
|
||||
uint8_t type : 8;
|
||||
|
||||
//Not all types have flags, but most do
|
||||
uint8_t flags : 8;
|
||||
|
||||
//Optional values, check the flags first
|
||||
unsigned short id : 16;
|
||||
unsigned short seqID : 16;
|
||||
|
||||
uint8_t* data();
|
||||
|
||||
static Buffer* create(msize_t bytes);
|
||||
static Buffer* copyPacket(uint8_t* pBytes, msize_t bytes);
|
||||
static void resize(Buffer*& buff, msize_t prevSize, msize_t bytes);
|
||||
}* buffer;
|
||||
|
||||
msize_t allocated;
|
||||
|
||||
msize_t used_bytes;
|
||||
uint8_t used_bits;
|
||||
msize_t read_bytes;
|
||||
uint8_t read_bits;
|
||||
|
||||
bool HasID, readError;
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
#include "threads.h"
|
||||
#include <network/message.h>
|
||||
#include <network/transport.h>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace net {
|
||||
|
||||
#ifndef NET_SELECT_TIMEOUT
|
||||
#define NET_SELECT_TIMEOUT 0
|
||||
#endif
|
||||
|
||||
#ifndef NET_IDLE_SLEEP
|
||||
#define NET_IDLE_SLEEP 1
|
||||
#endif
|
||||
|
||||
class MessageHandler {
|
||||
struct QueuedMessage {
|
||||
Transport* transport;
|
||||
Address addr;
|
||||
Message* msg;
|
||||
};
|
||||
|
||||
threads::Mutex queueMutex;
|
||||
threads::Mutex transportMutex;
|
||||
|
||||
std::queue<QueuedMessage> messageQueue;
|
||||
std::vector<Transport*> transports;
|
||||
public:
|
||||
threads::Signal threadsRunning;
|
||||
bool active;
|
||||
|
||||
std::function<void(bool)> threadInit;
|
||||
std::function<void(bool)> threadExit;
|
||||
|
||||
MessageHandler();
|
||||
virtual ~MessageHandler();
|
||||
|
||||
void addTransport(Transport* transport);
|
||||
void clearTransports();
|
||||
|
||||
virtual void queueMessage(Transport* transport, Address addr, Message* msg);
|
||||
virtual void handleMessage(Transport* transport, Address addr, Message* msg);
|
||||
|
||||
virtual bool queueTick();
|
||||
virtual bool mainTick();
|
||||
|
||||
virtual void runThreads(int workerThreads = 4);
|
||||
virtual void stop();
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
#include <limits.h>
|
||||
|
||||
namespace net {
|
||||
|
||||
enum MessageType : unsigned char {
|
||||
//Builtin message types
|
||||
MT_Invalid = 0,
|
||||
MT_Connect,
|
||||
MT_Disconnect,
|
||||
MT_Close_Sequence,
|
||||
|
||||
MT_Ping,
|
||||
MT_Pong,
|
||||
MT_Ack,
|
||||
MT_SeqAck,
|
||||
|
||||
MT_Fragment,
|
||||
MT_LastFragment,
|
||||
MT_Punchthrough,
|
||||
|
||||
//The application starts defining message types here
|
||||
MT_Application = 0x10,
|
||||
};
|
||||
|
||||
enum DisconnectReason : unsigned char {
|
||||
DR_Timeout,
|
||||
DR_Error,
|
||||
DR_Close,
|
||||
DR_Kick,
|
||||
DR_Version,
|
||||
DR_Password,
|
||||
DR_NULL
|
||||
};
|
||||
|
||||
const bool MessageHasFlags[] = {
|
||||
false, //MT_Invalid
|
||||
true, //MT_Connect
|
||||
true, //MT_Disconnect
|
||||
true, //MT_Close_Sequence
|
||||
false, //MT_Ping
|
||||
false, //MT_Pong
|
||||
false, //MT_Ack
|
||||
false, //MT_SeqAck
|
||||
true, //MT_Fragment
|
||||
true, //MT_LastFragment
|
||||
false, //MT_Punchthrough
|
||||
};
|
||||
|
||||
const int MessageFlagsAll = sizeof(MessageHasFlags) / sizeof(bool);
|
||||
|
||||
enum MessageFlags : unsigned char {
|
||||
MF_Reliable = 0x1,
|
||||
MF_Sequenced = 0x2,
|
||||
MF_Acknowledged = 0x80,
|
||||
MF_Managed = MF_Reliable | MF_Sequenced,
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
#include <network/message.h>
|
||||
#include <network/client.h>
|
||||
#include <network/message_handler.h>
|
||||
#include <network/connection.h>
|
||||
#include <network/time.h>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace net {
|
||||
|
||||
//Handles queueing and resending outgoing messages
|
||||
struct OutSequence {
|
||||
Connection& conn;
|
||||
unsigned short id;
|
||||
unsigned short nextOutgoingID;
|
||||
unsigned short nextAck;
|
||||
unsigned resendPeriod;
|
||||
bool closed;
|
||||
|
||||
struct MessageAwaitingAck {
|
||||
Message* msg;
|
||||
time lastResend;
|
||||
bool sent;
|
||||
};
|
||||
|
||||
void queue(Message* mess);
|
||||
std::list<Message*> queuedMessages;
|
||||
std::unordered_set<unsigned short> waitingAcks;
|
||||
|
||||
OutSequence(Connection& connection);
|
||||
|
||||
void handleAck(unsigned short num);
|
||||
|
||||
//Tries to pull a message from the sequence.
|
||||
// If it succeeds, the requester owns the message
|
||||
// Otherwise, returns a nullptr
|
||||
Message* getNextMessage();
|
||||
|
||||
OutSequence& operator<<(Message& message);
|
||||
void close();
|
||||
};
|
||||
|
||||
//Handles receiving and reordering incoming messages
|
||||
struct InSequence {
|
||||
Connection& conn;
|
||||
unsigned short id;
|
||||
bool closed;
|
||||
|
||||
std::unordered_map<unsigned short, Message*> unhandledMessages;
|
||||
unsigned short nextHandleID;
|
||||
unsigned short handlingID;
|
||||
|
||||
InSequence(Connection& connection, unsigned short id);
|
||||
|
||||
bool preHandle(MessageHandler& handler, Message* msg);
|
||||
void postHandle(MessageHandler& handler, Message* msg);
|
||||
void process(MessageHandler& handler, time& now);
|
||||
};
|
||||
|
||||
//Wrapper class to easily create new outgoing sequences and
|
||||
//close them when the wrapper goes out of scope
|
||||
struct Sequence {
|
||||
OutSequence* ws;
|
||||
|
||||
Sequence(Client& client);
|
||||
Sequence(Connection& connection);
|
||||
~Sequence();
|
||||
|
||||
unsigned short id();
|
||||
Sequence& operator<<(Message& message);
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
#include <network/message.h>
|
||||
#include <network/message_handler.h>
|
||||
#include <network/transport.h>
|
||||
#include <network/connection.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include "threads.h"
|
||||
|
||||
namespace net {
|
||||
|
||||
/*
|
||||
* Server
|
||||
* ------
|
||||
* Handles incoming connections and messages from
|
||||
* listening on one or multiple addresses/ports.
|
||||
*/
|
||||
|
||||
class Server : public MessageHandler {
|
||||
public:
|
||||
typedef std::function<void(Server&,Connection&,Message&)> connMessageHandler;
|
||||
typedef std::function<void(Server&,Transport&,Address,Message&)> genMessageHandler;
|
||||
typedef std::function<void(Connection&)> connFunction;
|
||||
|
||||
Server();
|
||||
~Server();
|
||||
|
||||
//Listen on everything associated with the passed address and port
|
||||
Server(int port, const std::string& address = "", bool broadcast = false);
|
||||
void listen(int port, const std::string& address = "", bool broadcast = false);
|
||||
|
||||
//Handlers for messages that arrive on a specific connection
|
||||
void connHandle(uint8_t type, connMessageHandler func);
|
||||
void connHandleClear(uint8_t type);
|
||||
|
||||
//Handlers for connection-less messages arriving on a transport
|
||||
void genHandle(uint8_t type, genMessageHandler func);
|
||||
void genHandleClear(uint8_t type);
|
||||
|
||||
//Send to the connection with the given id
|
||||
void send(int connId, Message& message);
|
||||
|
||||
//Send to all active connections
|
||||
void sendAll(Message& message);
|
||||
|
||||
//Send a ping to all connected clients
|
||||
void pingAll();
|
||||
|
||||
//Find the connection with the given id
|
||||
// NOTE: Grabs the connection before returning it
|
||||
Connection* getConnectionByID(int id);
|
||||
void doAll(connFunction func);
|
||||
|
||||
//Kick a connection
|
||||
void kick(Connection& conn, DisconnectReason reason = DR_Kick);
|
||||
|
||||
virtual void handleMessage(Transport* transport, Address addr, Message* msg);
|
||||
virtual bool mainTick();
|
||||
virtual void stop();
|
||||
private:
|
||||
threads::Mutex connMutex;
|
||||
threads::Mutex handlerMutex;
|
||||
|
||||
unsigned nextConnectionID;
|
||||
|
||||
std::unordered_map<Address, Connection*> connections;
|
||||
std::unordered_map<int, Connection*> connectionIDs;
|
||||
|
||||
std::unordered_map<uint8_t, connMessageHandler> connHandlers;
|
||||
std::unordered_map<uint8_t, genMessageHandler> genHandlers;
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
namespace net {
|
||||
|
||||
#ifdef __GNUC__
|
||||
typedef unsigned int time;
|
||||
#else
|
||||
typedef unsigned int time;
|
||||
#endif
|
||||
|
||||
void time_now(time& time);
|
||||
uint64_t time_diff(time& from, time& to);
|
||||
void time_add(time& base, int64_t add_ms);
|
||||
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
#include <network/address.h>
|
||||
#include <network/message.h>
|
||||
#include "threads.h"
|
||||
#include <queue>
|
||||
|
||||
namespace net {
|
||||
|
||||
class MessageHandler;
|
||||
class Transport {
|
||||
|
||||
mutable threads::atomic_int references;
|
||||
threads::Mutex queueMutex;
|
||||
std::queue<std::pair<Message*,Address>> queuedSends;
|
||||
std::queue<std::pair<Message*,int>> queuedBroadcasts;
|
||||
|
||||
int sockfd;
|
||||
public:
|
||||
bool active;
|
||||
bool canBroadcast;
|
||||
AddressType type;
|
||||
|
||||
int rate;
|
||||
|
||||
Transport(AddressType Type = AT_IPv4);
|
||||
~Transport();
|
||||
|
||||
void grab() const;
|
||||
void drop() const;
|
||||
|
||||
void listen(Address& addr, bool rcvBroadcast = false);
|
||||
void process();
|
||||
|
||||
void close();
|
||||
bool send(Message& msg, Address& adr, bool queue = true);
|
||||
bool broadcast(Message& msg, int port, bool queue = true);
|
||||
bool receive(Message& msg, Address& adr);
|
||||
|
||||
static int RATE_LIMIT;
|
||||
|
||||
friend class MessageHandler;
|
||||
};
|
||||
|
||||
};
|
||||
Reference in New Issue
Block a user