/***************************************************************************** * Copyright (c) 2014 Ted John * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. * * This file is part of OpenRCT2. * * OpenRCT2 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program 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 General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . *****************************************************************************/ #ifndef _NETWORK_H_ #define _NETWORK_H_ enum { NETWORK_MODE_NONE, NETWORK_MODE_CLIENT, NETWORK_MODE_SERVER }; enum { NETWORK_PLAYER_FLAG_ISSERVER = 1 << 0, }; #define NETWORK_DEFAULT_PORT 11753 #ifdef __cplusplus extern "C" { #endif // __cplusplus #include "../common.h" #include "../platform/platform.h" #ifdef __cplusplus } #endif // __cplusplus #ifndef DISABLE_NETWORK #ifndef __MINGW32__ #define USE_INET_PTON #else #warning using deprecated network functions in lieu of inet_pton, inet_ntop #endif // __MINGW32__ #ifdef _WIN32 #include #ifdef USE_INET_PTON #include #endif #define LAST_SOCKET_ERROR() WSAGetLastError() #undef EWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK #else #include #include #include #include #include typedef int SOCKET; #define SOCKET_ERROR -1 #define INVALID_SOCKET -1 #define LAST_SOCKET_ERROR() errno #define closesocket close #define ioctlsocket ioctl #endif // _WIN32 enum { NETWORK_AUTH_NONE, NETWORK_AUTH_REQUESTED, NETWORK_AUTH_OK, NETWORK_AUTH_BADVERSION, NETWORK_AUTH_BADNAME, NETWORK_AUTH_BADPASSWORD }; #ifdef __cplusplus #include #include #include #include #include template struct ByteSwapT { }; template <> struct ByteSwapT<1> { static uint8 SwapBE(uint8 value) { return value; } }; template <> struct ByteSwapT<2> { static uint16 SwapBE(uint16 value) { return SDL_SwapBE16(value); } }; template <> struct ByteSwapT<4> { static uint32 SwapBE(uint32 value) { return SDL_SwapBE32(value); } }; template T ByteSwapBE(const T& value) { return ByteSwapT::SwapBE(value); } class NetworkPacket { public: NetworkPacket(); static std::unique_ptr Allocate(); static std::unique_ptr Duplicate(NetworkPacket& packet); uint8* GetData(); template NetworkPacket& operator<<(T value) { T swapped = ByteSwapBE(value); uint8* bytes = (uint8*)&swapped; data->insert(data->end(), bytes, bytes + sizeof(value)); return *this; } void Write(uint8* bytes, unsigned int size); void WriteString(const char* string); template NetworkPacket& operator>>(T& value) { if (read + sizeof(value) > size) { value = 0; } else { value = ByteSwapBE(*((T*)&GetData()[read])); read += sizeof(value); } return *this; } const uint8* Read(unsigned int size); const char* ReadString(); void Clear(); uint16 size; std::shared_ptr> data; int transferred; int read; }; class NetworkPlayer { public: NetworkPlayer(const char* name); uint8 id; uint8 name[32 + 1]; uint16 ping; uint32 flags; }; class NetworkConnection { public: NetworkConnection(); int ReadPacket(); void QueuePacket(std::unique_ptr packet); void SendQueuedPackets(); bool SetTCPNoDelay(bool on); bool SetNonBlocking(bool on); static bool SetNonBlocking(SOCKET socket, bool on); SOCKET socket; NetworkPacket inboundpacket; int authstatus; NetworkPlayer* player; uint32 ping_time; private: bool SendPacket(NetworkPacket& packet); std::list> outboundpackets; }; class Network { public: Network(); ~Network(); bool Init(); void Close(); bool BeginClient(const char* host, unsigned short port); bool BeginServer(unsigned short port); int GetMode(); int GetAuthStatus(); uint32 GetServerTick(); uint8 GetPlayerID(); void Update(); NetworkPlayer* GetPlayerByID(int id); const char* FormatChat(NetworkPlayer* fromplayer, const char* text); void SendPacketToClients(NetworkPacket& packet); bool CheckSRAND(uint32 tick, uint32 srand0); void KickPlayer(int playerId); void Client_Send_AUTH(const char* gameversion, const char* name, const char* password); void Server_Send_MAP(NetworkConnection* connection = nullptr); void Client_Send_CHAT(const char* text); void Server_Send_CHAT(const char* text); void Client_Send_GAMECMD(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 callback); void Server_Send_GAMECMD(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 playerid, uint8 callback); void Server_Send_TICK(); void Server_Send_PLAYERLIST(); void Client_Send_PING(); void Server_Send_PING(); void Server_Send_PINGLIST(); std::vector> player_list; private: bool ProcessConnection(NetworkConnection& connection); void ProcessPacket(NetworkConnection& connection, NetworkPacket& packet); void ProcessGameCommandQueue(); void AddClient(SOCKET socket); void RemoveClient(std::unique_ptr& connection); NetworkPlayer* AddPlayer(const char* name); void PrintError(); struct GameCommand { GameCommand(uint32 t, uint32* args, uint8 p, uint8 cb) { tick = t, eax = args[0], ebx = args[1], ecx = args[2], edx = args[3], esi = args[4], edi = args[5], ebp = args[6]; playerid = p; callback = cb; }; uint32 tick; uint32 eax, ebx, ecx, edx, esi, edi, ebp; uint8 playerid; uint8 callback; bool operator<(const GameCommand& comp) const { return tick < comp.tick; } }; int mode; bool wsa_initialized; SOCKET server_socket; SOCKET listening_socket; NetworkConnection server_connection; uint32 last_tick_sent_time; uint32 last_ping_sent_time; uint32 server_tick; uint32 server_srand0; uint32 server_srand0_tick; uint8 player_id; std::list> client_connection_list; std::multiset game_command_queue; std::vector chunk_buffer; char password[33]; bool _desynchronised; void UpdateServer(); void UpdateClient(); private: std::vector client_command_handlers; std::vector server_command_handlers; int Client_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet); int Server_Handle_AUTH(NetworkConnection& connection, NetworkPacket& packet); int Client_Handle_MAP(NetworkConnection& connection, NetworkPacket& packet); int Client_Handle_CHAT(NetworkConnection& connection, NetworkPacket& packet); int Server_Handle_CHAT(NetworkConnection& connection, NetworkPacket& packet); int Client_Handle_GAMECMD(NetworkConnection& connection, NetworkPacket& packet); int Server_Handle_GAMECMD(NetworkConnection& connection, NetworkPacket& packet); int Client_Handle_TICK(NetworkConnection& connection, NetworkPacket& packet); int Client_Handle_PLAYERLIST(NetworkConnection& connection, NetworkPacket& packet); int Client_Handle_PING(NetworkConnection& connection, NetworkPacket& packet); int Server_Handle_PING(NetworkConnection& connection, NetworkPacket& packet); int Client_Handle_PINGLIST(NetworkConnection& connection, NetworkPacket& packet); }; #endif // __cplusplus #endif /* DISABLE_NETWORK */ #ifdef __cplusplus extern "C" { #endif // __cplusplus int network_init(); void network_close(); int network_begin_client(const char *host, int port); int network_begin_server(int port); int network_get_mode(); void network_update(); int network_get_authstatus(); uint32 network_get_server_tick(); uint8 network_get_current_player_id(); int network_get_num_players(); const char* network_get_player_name(unsigned int index); uint32 network_get_player_flags(unsigned int index); int network_get_player_ping(unsigned int index); int network_get_player_id(unsigned int index); void network_send_map(); void network_send_chat(const char* text); void network_send_gamecmd(uint32 eax, uint32 ebx, uint32 ecx, uint32 edx, uint32 esi, uint32 edi, uint32 ebp, uint8 callback); void network_kick_player(int playerId); void network_print_error(); #ifdef USE_INET_PTON static bool network_get_address(char *dst, size_t dstLength, const char *host); #else static char *network_getAddress(char *host); #endif // USE_INET_PTON #ifdef __cplusplus } #endif // __cplusplus #endif