/* Copyright (C) 2019 Mr Goldberg
This file is part of the Goldberg Emulator
The Goldberg Emulator is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
The Goldberg Emulator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the Goldberg Emulator; if not, see
. */
#include "base.h"
#ifndef NETWORK_INCLUDE
#define NETWORK_INCLUDE
#include "net.pb.h"
#include
inline bool protobuf_message_equal(const google::protobuf::MessageLite& msg_a,
const google::protobuf::MessageLite& msg_b) {
return (msg_a.GetTypeName() == msg_b.GetTypeName()) &&
(msg_a.SerializeAsString() == msg_b.SerializeAsString());
}
#define DEFAULT_PORT 47584
#if defined(STEAM_WIN32)
typedef unsigned int sock_t;
#else
typedef int sock_t;
#endif
bool check_timedout(std::chrono::high_resolution_clock::time_point old, double timeout);
struct IP_PORT {
uint32 ip;
uint16 port;
};
struct Network_Callback {
void (*message_callback)(void *object, Common_Message *msg);
void *object;
CSteamID steam_id;
};
enum Callback_Ids {
CALLBACK_ID_USER_STATUS,
CALLBACK_ID_LOBBY,
CALLBACK_ID_NETWORKING,
CALLBACK_ID_GAMESERVER,
CALLBACK_ID_FRIEND,
CALLBACK_ID_AUTH_TICKET,
CALLBACK_ID_FRIEND_MESSAGES,
CALLBACK_ID_NETWORKING_SOCKETS,
CALLBACK_IDS_MAX
};
struct Network_Callback_Container {
std::vector callbacks;
};
struct TCP_Socket {
sock_t sock = ~0;
bool received_data = false;
std::vector recv_buffer;
std::vector send_buffer;
std::chrono::high_resolution_clock::time_point last_heartbeat_sent, last_heartbeat_received;
};
struct Connection {
struct TCP_Socket tcp_socket_outgoing, tcp_socket_incoming;
bool connected = false;
IP_PORT udp_ip_port;
bool udp_pinged = false;
IP_PORT tcp_ip_port;
std::vector ids;
uint32 appid;
std::chrono::high_resolution_clock::time_point last_received;
};
class Networking {
bool enabled = false;
bool alive;
std::chrono::high_resolution_clock::time_point last_run;
sock_t udp_socket, tcp_socket;
uint16 udp_port, tcp_port;
uint32 own_ip;
std::vector connections;
struct Connection *find_connection(CSteamID id, uint32 appid = 0);
struct Connection *new_connection(CSteamID id, uint32 appid);
bool handle_announce(Common_Message *msg, IP_PORT ip_port);
bool handle_low_level_udp(Common_Message *msg, IP_PORT ip_port);
bool handle_tcp(Common_Message *msg, struct TCP_Socket &socket);
void send_announce_broadcasts();
std::vector ids;
uint32 appid;
std::chrono::high_resolution_clock::time_point last_broadcast;
std::vector custom_broadcasts;
std::vector accepted;
std::recursive_mutex mutex;
struct Network_Callback_Container callbacks[CALLBACK_IDS_MAX];
std::vector local_send;
bool add_id_connection(struct Connection *connection, CSteamID steam_id);
void run_callbacks(Callback_Ids id, Common_Message *msg);
void run_callback_user(CSteamID steam_id, bool online, uint32 appid);
void do_callbacks_message(Common_Message *msg);
Common_Message create_announce(bool request);
public:
//NOTE: for all functions ips/ports are passed/returned in host byte order
//ex: 127.0.0.1 should be passed as 0x7F000001
static std::set resolve_ip(std::string dns);
Networking(CSteamID id, uint32 appid, uint16 port, std::set *custom_broadcasts, bool disable_sockets);
void addListenId(CSteamID id);
void setAppID(uint32 appid);
void Run();
bool sendTo(Common_Message *msg, bool reliable, Connection *conn = NULL);
bool sendToAllIndividuals(Common_Message *msg, bool reliable);
bool sendToAll(Common_Message *msg, bool reliable);
bool sendToIPPort(Common_Message *msg, uint32 ip, uint16 port, bool reliable);
bool setCallback(Callback_Ids id, CSteamID steam_id, void (*message_callback)(void *object, Common_Message *msg), void *object);
uint32 getOwnIP();
void shutDown();
bool isAlive();
};
#endif