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