diff --git a/Makefile b/Makefile index a6bb9b6ec6..13be2ab569 100644 --- a/Makefile +++ b/Makefile @@ -732,13 +732,16 @@ SRCS += mixer.c SRCS += music.c SRCS += music_gui.c SRCS += namegen.c -SRCS += network.c -SRCS += network_client.c -SRCS += network_data.c -SRCS += network_gamelist.c -SRCS += network_gui.c -SRCS += network_server.c -SRCS += network_udp.c +SRCS += network/core/packet.c +SRCS += network/core/tcp.c +SRCS += network/core/udp.c +SRCS += network/network.c +SRCS += network/network_client.c +SRCS += network/network_data.c +SRCS += network/network_gamelist.c +SRCS += network/network_gui.c +SRCS += network/network_server.c +SRCS += network/network_udp.c SRCS += newgrf.c SRCS += newgrf_cargo.c SRCS += newgrf_config.c diff --git a/ai/ai.c b/ai/ai.c index f06ba06f6c..58b97ad39c 100644 --- a/ai/ai.c +++ b/ai/ai.c @@ -4,7 +4,7 @@ #include "../openttd.h" #include "../variables.h" #include "../command.h" -#include "../network.h" +#include "../network/network.h" #include "ai.h" #include "default/default.h" diff --git a/ai/ai.h b/ai/ai.h index aedb5b5cd1..6123970ac3 100644 --- a/ai/ai.h +++ b/ai/ai.h @@ -2,7 +2,7 @@ #define AI_H #include "../functions.h" -#include "../network.h" +#include "../network/network.h" #include "../player.h" #include "../command.h" diff --git a/command.c b/command.c index 7c07c5d371..f99371946f 100644 --- a/command.c +++ b/command.c @@ -8,7 +8,7 @@ #include "gui.h" #include "command.h" #include "player.h" -#include "network.h" +#include "network/network.h" #include "variables.h" #include "genworld.h" diff --git a/console.c b/console.c index 9335472165..07d2181306 100644 --- a/console.c +++ b/console.c @@ -13,9 +13,9 @@ #include #include #include "console.h" -#include "network.h" -#include "network_data.h" -#include "network_server.h" +#include "network/network.h" +#include "network/network_data.h" +#include "network/network_server.h" #define ICON_BUFFER 79 #define ICON_HISTORY_SIZE 20 diff --git a/console_cmds.c b/console_cmds.c index addc9a799a..7ec55c6b97 100644 --- a/console_cmds.c +++ b/console_cmds.c @@ -9,10 +9,10 @@ #include "saveload.h" #include "string.h" #include "variables.h" -#include "network_data.h" -#include "network_client.h" -#include "network_server.h" -#include "network_udp.h" +#include "network/network_data.h" +#include "network/network_client.h" +#include "network/network_server.h" +#include "network/network_udp.h" #include "command.h" #include "settings.h" #include "fios.h" @@ -22,7 +22,7 @@ #include "screenshot.h" #include "genworld.h" #include "date.h" -#include "network.h" +#include "network/network.h" // ** scriptfile handling ** // static FILE *_script_file; diff --git a/date.c b/date.c index 66bade3c94..856ca45283 100644 --- a/date.c +++ b/date.c @@ -6,9 +6,9 @@ #include "variables.h" #include "macros.h" #include "vehicle.h" -#include "network.h" -#include "network_data.h" -#include "network_server.h" +#include "network/network.h" +#include "network/network_data.h" +#include "network/network_server.h" #include "functions.h" #include "currency.h" diff --git a/date.h b/date.h index 37691d24a2..488a9dc3ad 100644 --- a/date.h +++ b/date.h @@ -3,6 +3,8 @@ #ifndef DATE_H #define DATE_H +#include "openttd.h" + /** * 1 day is 74 ticks; _date_fract used to be uint16 and incremented by 885. On * an overflow the new day begun and 65535 / 885 = 74. diff --git a/economy.c b/economy.c index 8e8d8c3b88..bcd3ac5520 100644 --- a/economy.c +++ b/economy.c @@ -19,10 +19,10 @@ #include "economy.h" #include "industry.h" #include "town.h" -#include "network.h" +#include "network/network.h" #include "sound.h" #include "engine.h" -#include "network_data.h" +#include "network/network_data.h" #include "variables.h" #include "vehicle_gui.h" #include "ai/ai.h" diff --git a/genworld.c b/genworld.c index 1d802d996e..ba9fe126f5 100644 --- a/genworld.c +++ b/genworld.c @@ -11,7 +11,7 @@ #include "gfx.h" #include "gfxinit.h" #include "gui.h" -#include "network.h" +#include "network/network.h" #include "debug.h" #include "settings.h" #include "heightmap.h" diff --git a/genworld_gui.c b/genworld_gui.c index bbd0cb31bf..83d0f4cf1a 100644 --- a/genworld_gui.c +++ b/genworld_gui.c @@ -19,7 +19,7 @@ #include "settings.h" #include "debug.h" #include "genworld.h" -#include "network.h" +#include "network/network.h" #include "thread.h" #include "date.h" #include "newgrf_config.h" diff --git a/intro_gui.c b/intro_gui.c index 364b81f5f8..5f78e3a654 100644 --- a/intro_gui.c +++ b/intro_gui.c @@ -9,12 +9,12 @@ #include "gui.h" #include "gfx.h" #include "player.h" -#include "network.h" +#include "network/network.h" #include "variables.h" #include "settings.h" #include "heightmap.h" #include "genworld.h" -#include "network_gui.h" +#include "network/network_gui.h" #include "newgrf.h" static const Widget _select_game_widgets[] = { diff --git a/main_gui.c b/main_gui.c index caebe5afa2..e2b816e754 100644 --- a/main_gui.c +++ b/main_gui.c @@ -23,7 +23,7 @@ #include "vehicle.h" #include "console.h" #include "sound.h" -#include "network.h" +#include "network/network.h" #include "signs.h" #include "waypoint.h" #include "variables.h" @@ -37,10 +37,10 @@ #include "vehicle_gui.h" #include "newgrf_config.h" -#include "network_data.h" -#include "network_client.h" -#include "network_server.h" -#include "network_gui.h" +#include "network/network_data.h" +#include "network/network_client.h" +#include "network/network_server.h" +#include "network/network_gui.h" #include "industry.h" static int _rename_id = 1; diff --git a/misc.c b/misc.c index 7f06943ca2..fd3a74b79b 100644 --- a/misc.c +++ b/misc.c @@ -24,7 +24,7 @@ char _name_array[512][32]; #ifndef MERSENNE_TWISTER #ifdef RANDOM_DEBUG -#include "network_data.h" +#include "network/network_data.h" uint32 DoRandom(int line, const char *file) #else // RANDOM_DEBUG uint32 Random(void) diff --git a/misc_cmd.c b/misc_cmd.c index 4293706ba0..94b6755311 100644 --- a/misc_cmd.c +++ b/misc_cmd.c @@ -11,7 +11,7 @@ #include "window.h" #include "gui.h" #include "economy.h" -#include "network.h" +#include "network/network.h" #include "variables.h" #include "livery.h" diff --git a/misc_gui.c b/misc_gui.c index 94917cfdf6..3f84192ada 100644 --- a/misc_gui.c +++ b/misc_gui.c @@ -22,7 +22,7 @@ #include "player.h" #include "town.h" #include "sound.h" -#include "network.h" +#include "network/network.h" #include "string.h" #include "variables.h" #include "vehicle.h" diff --git a/network/core/config.h b/network/core/config.h new file mode 100644 index 0000000000..0b80800f07 --- /dev/null +++ b/network/core/config.h @@ -0,0 +1,49 @@ +/* $Id$ */ + +#ifndef NETWORK_CORE_CONFIG_H +#define NETWORK_CORE_CONFIG_H + +#ifdef ENABLE_NETWORK + +/** DNS hostname of the masterserver */ +#define NETWORK_MASTER_SERVER_HOST "master.openttd.org" +/** Message sent to the masterserver to 'identify' this client as OpenTTD */ +#define NETWORK_MASTER_SERVER_WELCOME_MESSAGE "OpenTTDRegister" + +enum { + NETWORK_MASTER_SERVER_PORT = 3978, ///< The default port of the master server (UDP) + NETWORK_DEFAULT_PORT = 3979, ///< The default port of the game server (TCP & UDP) + + SEND_MTU = 1460, ///< Number of bytes we can pack in a single packet + + NETWORK_GAME_INFO_VERSION = 4, ///< What version of game-info do we use? + NETWORK_COMPANY_INFO_VERSION = 4, ///< What version of company info is this? + NETWORK_MASTER_SERVER_VERSION = 1, ///< What version of master-server-protocol do we use? + + NETWORK_NAME_LENGTH = 80, ///< The maximum length of the server name and map name, in bytes including '\0' + NETWORK_HOSTNAME_LENGTH = 80, ///< The maximum length of the host name, in bytes including '\0' + NETWORK_REVISION_LENGTH = 15, ///< The maximum length of the revision, in bytes including '\0' + NETWORK_PASSWORD_LENGTH = 20, ///< The maximum length of the password, in bytes including '\0' + NETWORK_PLAYERS_LENGTH = 200, ///< The maximum length for the list of players that controls a company, in bytes including '\0' + NETWORK_CLIENT_NAME_LENGTH = 25, ///< The maximum length of a player, in bytes including '\0' + NETWORK_RCONCOMMAND_LENGTH = 500, ///< The maximum length of a rconsole command, in bytes including '\0' + + NETWORK_GRF_NAME_LENGTH = 80, ///< Maximum length of the name of a GRF + /** + * Maximum number of GRFs that can be sent. + * This value is related to number of handles (files) OpenTTD can open. + * This is currently 64 and about 10 are currently used when OpenTTD loads + * without any NewGRFs. Therefore one can only load about 55 NewGRFs, so + * this is not a limit, but rather a way to easily check whether the limit + * imposed by the handle count is reached. Secondly it isn't possible to + * send much more GRF IDs + MD5sums in the PACKET_UDP_SERVER_RESPONSE, due + * to the limited size of UDP packets. + */ + NETWORK_MAX_GRF_COUNT = 55, + + NETWORK_NUM_LANGUAGES = 4, ///< Number of known languages (to the network protocol) + 1 for 'any'. +}; + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_CONFIG_H */ diff --git a/network/core/game.h b/network/core/game.h new file mode 100644 index 0000000000..71268f7d2a --- /dev/null +++ b/network/core/game.h @@ -0,0 +1,47 @@ +/* $Id$ */ + +#ifndef NETWORK_CORE_GAME_H +#define NETWORK_CORE_GAME_H + +#ifdef ENABLE_NETWORK + +/** + * @file game.h Information about a game that is sent between a + * game server, game client and masterserver. + */ + +/** + * This is the struct used by both client and server + * some fields will be empty on the client (like game_password) by default + * and only filled with data a player enters. + */ +typedef struct NetworkGameInfo { + byte game_info_version; ///< Version of the game info + char server_name[NETWORK_NAME_LENGTH]; ///< Server name + char hostname[NETWORK_HOSTNAME_LENGTH]; ///< Hostname of the server (if any) + char server_revision[NETWORK_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0) + bool version_compatible; ///< Can we connect to this server or not? (based on server_revision) + bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match + byte server_lang; ///< Language of the server (we should make a nice table for this) + byte use_password; ///< Is set to != 0 if it uses a password + char server_password[NETWORK_PASSWORD_LENGTH]; ///< On the server: the game password, on the client: != "" if server has password + byte clients_max; ///< Max clients allowed on server + byte clients_on; ///< Current count of clients on server + byte companies_max; ///< Max companies allowed on server + byte companies_on; ///< How many started companies do we have + byte spectators_max; ///< Max spectators allowed on server + byte spectators_on; ///< How many spectators do we have? + Date game_date; ///< Current date + Date start_date; ///< When the game started + char map_name[NETWORK_NAME_LENGTH]; ///< Map which is played ["random" for a randomized map] + uint16 map_width; ///< Map width + uint16 map_height; ///< Map height + byte map_set; ///< Graphical set + bool dedicated; ///< Is this a dedicated server? + char rcon_password[NETWORK_PASSWORD_LENGTH]; ///< RCon password for the server. "" if rcon is disabled + struct GRFConfig *grfconfig; ///< List of NewGRF files used +} NetworkGameInfo; + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_GAME_H */ diff --git a/network_core.h b/network/core/os_abstraction.h similarity index 69% rename from network_core.h rename to network/core/os_abstraction.h index cdc79c1688..c7df16a939 100644 --- a/network_core.h +++ b/network/core/os_abstraction.h @@ -1,40 +1,37 @@ /* $Id$ */ -#ifndef NETWORK_CORE_H -#define NETWORK_CORE_H +#ifndef NETWORK_CORE_OS_ABSTRACTION_H +#define NETWORK_CORE_OS_ABSTRACTION_H -// Network stuff has many things that needs to be included -// by default. All those things are in this file. +/** + * @file os_abstraction.h Network stuff has many things that needs to be + * included and/or implemented by default. + * All those things are in this file. + */ -// ============================= -// Include standard stuff per OS +/* Include standard stuff per OS */ #ifdef ENABLE_NETWORK -#if defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_2) - // OSX 10.2 don't have socklen_t defined, so we will define it here - typedef int socklen_t; -#endif - -// Windows stuff +/* Windows stuff */ #if defined(WIN32) || defined(WIN64) #include #include #include #if !(defined(__MINGW32__) || defined(__CYGWIN__)) - // Windows has some different names for some types.. + /* Windows has some different names for some types */ typedef SSIZE_T ssize_t; typedef int socklen_t; #endif #define GET_LAST_ERROR() WSAGetLastError() #define EWOULDBLOCK WSAEWOULDBLOCK -// Windows has some different names for some types.. +/* Windows has some different names for some types */ typedef unsigned long in_addr_t; -#endif // WIN32 +#endif /* WIN32 */ -// UNIX stuff +/* UNIX stuff */ #if defined(UNIX) # define SOCKET int # define INVALID_SOCKET -1 @@ -45,10 +42,10 @@ typedef unsigned long in_addr_t; # endif # define GET_LAST_ERROR() (errno) # endif -// Need this for FIONREAD on solaris +/* Need this for FIONREAD on solaris */ # define BSD_COMP -// Includes needed for UNIX-like systems +/* Includes needed for UNIX-like systems */ # include # include # if defined(__BEOS__) && defined(BEOS_NET_SERVER) @@ -63,12 +60,12 @@ typedef unsigned long in_addr_t; # include # include # include -// According to glibc/NEWS, appeared in glibc-2.3. +/* According to glibc/NEWS, appeared in glibc-2.3. */ # if !defined(__sgi__) && !defined(SUNOS) && !defined(__MORPHOS__) && !defined(__BEOS__) && !defined(__INNOTEK_LIBC__) \ && !(defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 2)) && !defined(__dietlibc__) -// If for any reason ifaddrs.h does not exist on your system, comment out -// the following two lines and an alternative way will be used to fetch -// the list of IPs from the system. +/* If for any reason ifaddrs.h does not exist on your system, comment out + * the following two lines and an alternative way will be used to fetch + * the list of IPs from the system. */ # include # define HAVE_GETIFADDRS # endif @@ -76,10 +73,10 @@ typedef unsigned long in_addr_t; # define INADDR_NONE 0xffffffff # endif # if defined(__BEOS__) && !defined(BEOS_NET_SERVER) - // needed on Zeta + /* needed on Zeta */ # include # endif -# endif // BEOS_NET_SERVER +# endif /* BEOS_NET_SERVER */ # if !defined(__BEOS__) && defined(__GLIBC__) && (__GLIBC__ <= 2) && (__GLIBC_MINOR__ <= 1) typedef uint32_t in_addr_t; @@ -94,7 +91,7 @@ typedef unsigned long in_addr_t; typedef int socklen_t; #endif -// OS/2 stuff +/* OS/2 stuff */ #if defined(__OS2__) # define SOCKET int # define INVALID_SOCKET -1 @@ -102,7 +99,7 @@ typedef unsigned long in_addr_t; # define closesocket close # define GET_LAST_ERROR() (sock_errno()) -// Includes needed for OS/2 systems +/* Includes needed for OS/2 systems */ # include # include # include @@ -121,21 +118,21 @@ typedef int socklen_t; #if !defined(__INNOTEK_LIBC__) typedef unsigned long in_addr_t; #endif /* __INNOTEK_LIBC__ */ -#endif // OS/2 +#endif /* OS/2 */ -// MorphOS and Amiga stuff +/* MorphOS and Amiga stuff */ #if defined(__MORPHOS__) || defined(__AMIGA__) # include -# include // required for Open/CloseLibrary() +# include // required for Open/CloseLibrary() # if defined(__MORPHOS__) -# include // FIO* defines -# include // SIO* defines +# include // FIO* defines +# include // SIO* defines # include -# else // __AMIGA__ +# else /* __AMIGA__ */ # include # endif -// Make the names compatible +/* Make the names compatible */ # define closesocket(s) CloseSocket(s) # define GET_LAST_ERROR() Errno() # define ioctlsocket(s,request,status) IoctlSocket((LONG)s,(ULONG)request,(char*)status) @@ -146,7 +143,7 @@ typedef unsigned long in_addr_t; extern struct Library *SocketBase; # ifdef __AMIGA__ - // for usleep() implementation + /* for usleep() implementation */ extern struct Device *TimerBase; extern struct MsgPort *TimerPort; extern struct timerequest *TimerRequest; @@ -155,30 +152,30 @@ typedef unsigned long in_addr_t; static inline bool SetNonBlocking(int d) { - #ifdef WIN32 +#ifdef WIN32 u_long nonblocking = 1; - #else +#else int nonblocking = 1; - #endif - #if defined(__BEOS__) && defined(BEOS_NET_SERVER) +#endif +#if defined(__BEOS__) && defined(BEOS_NET_SERVER) return setsockopt(d, SOL_SOCKET, SO_NONBLOCK, &nonblocking, sizeof(nonblocking)) == 0; - #else +#else return ioctlsocket(d, FIONBIO, &nonblocking) == 0; - #endif +#endif } static inline bool SetNoDelay(int d) { - // XXX should this be done at all? - #if !defined(BEOS_NET_SERVER) // not implemented on BeOS net_server + /* XXX should this be done at all? */ +#if !defined(BEOS_NET_SERVER) // not implemented on BeOS net_server int b = 1; - // The (const char*) cast is needed for windows + /* The (const char*) cast is needed for windows */ return setsockopt(d, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) == 0; - #else +#else return true; - #endif +#endif } #endif /* ENABLE_NETWORK */ -#endif /* NETWORK_CORE_H */ +#endif /* NETWORK_CORE_OS_ABSTRACTION_H */ diff --git a/network/core/packet.c b/network/core/packet.c new file mode 100644 index 0000000000..957bd2ad6a --- /dev/null +++ b/network/core/packet.c @@ -0,0 +1,216 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../../stdafx.h" +#include "../../macros.h" +#include "../../string.h" + +#include "os_abstraction.h" +#include "config.h" +#include "packet.h" + +/** + * @file packet.h Basic functions to create, fill and read packets. + */ + + +/* Do not want to include functions.h and all required headers */ +extern void NORETURN CDECL error(const char *str, ...); + + +/** + * Create a packet for sending + * @param type the of packet + * @return the newly created packet + */ +Packet *NetworkSend_Init(PacketType type) +{ + Packet *packet = malloc(sizeof(Packet)); + /* An error is inplace here, because it simply means we ran out of memory. */ + if (packet == NULL) error("Failed to allocate Packet"); + + /* Skip the size so we can write that in before sending the packet */ + packet->size = sizeof(packet->size); + packet->buffer[packet->size++] = type; + packet->pos = 0; + + return packet; +} + +/** + * Writes the packet size from the raw packet from packet->size + * @param packet the packet to write the size of + */ +void NetworkSend_FillPacketSize(Packet *packet) +{ + packet->buffer[0] = GB(packet->size, 0, 8); + packet->buffer[1] = GB(packet->size, 8, 8); +} + +/** + * The next couple of functions make sure we can send + * uint8, uint16, uint32 and uint64 endian-safe + * over the network. The least significant bytes are + * sent first. + * + * So 0x01234567 would be sent as 67 45 23 01. + */ + +void NetworkSend_uint8(Packet *packet, uint8 data) +{ + assert(packet->size < sizeof(packet->buffer) - sizeof(data)); + packet->buffer[packet->size++] = data; +} + +void NetworkSend_uint16(Packet *packet, uint16 data) +{ + assert(packet->size < sizeof(packet->buffer) - sizeof(data)); + packet->buffer[packet->size++] = GB(data, 0, 8); + packet->buffer[packet->size++] = GB(data, 8, 8); +} + +void NetworkSend_uint32(Packet *packet, uint32 data) +{ + assert(packet->size < sizeof(packet->buffer) - sizeof(data)); + packet->buffer[packet->size++] = GB(data, 0, 8); + packet->buffer[packet->size++] = GB(data, 8, 8); + packet->buffer[packet->size++] = GB(data, 16, 8); + packet->buffer[packet->size++] = GB(data, 24, 8); +} + +void NetworkSend_uint64(Packet *packet, uint64 data) +{ + assert(packet->size < sizeof(packet->buffer) - sizeof(data)); + packet->buffer[packet->size++] = GB(data, 0, 8); + packet->buffer[packet->size++] = GB(data, 8, 8); + packet->buffer[packet->size++] = GB(data, 16, 8); + packet->buffer[packet->size++] = GB(data, 24, 8); + packet->buffer[packet->size++] = GB(data, 32, 8); + packet->buffer[packet->size++] = GB(data, 40, 8); + packet->buffer[packet->size++] = GB(data, 48, 8); + packet->buffer[packet->size++] = GB(data, 56, 8); +} + +/** + * Sends a string over the network. It sends out + * the string + '\0'. No size-byte or something. + */ +void NetworkSend_string(Packet *packet, const char* data) +{ + assert(data != NULL); + assert(packet->size < sizeof(packet->buffer) - strlen(data) - 1); + while ((packet->buffer[packet->size++] = *data++) != '\0') {} +} + + +/** + * Receiving commands + * Again, the next couple of functions are endian-safe + * see the comment before NetworkSend_uint8 for more info. + */ + + +extern uint CloseConnection(NetworkClientState *cs); + +/** Is it safe to read from the packet, i.e. didn't we run over the buffer ? */ +static inline bool CanReadFromPacket(NetworkClientState *cs, Packet *packet, uint bytes_to_read) +{ + /* Don't allow reading from a closed socket */ + if (HasClientQuit(cs)) return false; + + /* Check if variable is within packet-size */ + if (packet->pos + bytes_to_read > packet->size) { + CloseConnection(cs); + return false; + } + + return true; +} + +/** + * Reads the packet size from the raw packet and stores it in the packet->size + * @param packet the packet to read the size of + */ +void NetworkRecv_ReadPacketSize(Packet *packet) +{ + packet->size = (uint16)packet->buffer[0]; + packet->size += (uint16)packet->buffer[1] << 8; +} + +uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet) +{ + uint8 n; + + if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0; + + n = packet->buffer[packet->pos++]; + return n; +} + +uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet) +{ + uint16 n; + + if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0; + + n = (uint16)packet->buffer[packet->pos++]; + n += (uint16)packet->buffer[packet->pos++] << 8; + return n; +} + +uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet) +{ + uint32 n; + + if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0; + + n = (uint32)packet->buffer[packet->pos++]; + n += (uint32)packet->buffer[packet->pos++] << 8; + n += (uint32)packet->buffer[packet->pos++] << 16; + n += (uint32)packet->buffer[packet->pos++] << 24; + return n; +} + +uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet) +{ + uint64 n; + + if (!CanReadFromPacket(cs, packet, sizeof(n))) return 0; + + n = (uint64)packet->buffer[packet->pos++]; + n += (uint64)packet->buffer[packet->pos++] << 8; + n += (uint64)packet->buffer[packet->pos++] << 16; + n += (uint64)packet->buffer[packet->pos++] << 24; + n += (uint64)packet->buffer[packet->pos++] << 32; + n += (uint64)packet->buffer[packet->pos++] << 40; + n += (uint64)packet->buffer[packet->pos++] << 48; + n += (uint64)packet->buffer[packet->pos++] << 56; + return n; +} + +/** Reads a string till it finds a '\0' in the stream */ +void NetworkRecv_string(NetworkClientState *cs, Packet *p, char *buffer, size_t size) +{ + PacketSize pos; + char *bufp = buffer; + + /* Don't allow reading from a closed socket */ + if (HasClientQuit(cs)) return; + + pos = p->pos; + while (--size > 0 && pos < p->size && (*buffer++ = p->buffer[pos++]) != '\0') {} + + if (size == 0 || pos == p->size) { + *buffer = '\0'; + /* If size was sooner to zero then the string in the stream + * skip till the \0, so than packet can be read out correctly for the rest */ + while (pos < p->size && p->buffer[pos] != '\0') pos++; + pos++; + } + p->pos = pos; + + str_validate(bufp); +} + +#endif /* ENABLE_NETWORK */ diff --git a/network/core/packet.h b/network/core/packet.h new file mode 100644 index 0000000000..2510c69a7f --- /dev/null +++ b/network/core/packet.h @@ -0,0 +1,67 @@ +/* $Id$ */ + +#ifndef NETWORK_CORE_PACKET_H +#define NETWORK_CORE_PACKET_H + +#ifdef ENABLE_NETWORK + +/** + * @file packet.h Basic functions to create, fill and read packets. + */ + +typedef struct NetworkClientState NetworkClientState; + +/** + * Queries the network client state struct to determine whether + * the client has quit. It indirectly also queries whether the + * packet is corrupt as the connection will be closed if it is + * reading beyond the boundary of the received packet. + * @param cs the state to query + * @param true if the connection should be considered dropped + */ +bool HasClientQuit(NetworkClientState *cs); + +typedef uint16 PacketSize; ///< Size of the whole packet. +typedef uint8 PacketType; ///< Identifier for the packet + +/** + * Internal entity of a packet. As everything is sent as a packet, + * all network communication will need to call the functions that + * populate the packet. + * Every packet can be at most SEND_MTU bytes. Overflowing this + * limit will give an assertion when sending (i.e. writing) the + * packet. Reading past the size of the packet when receiving + * will return all 0 values and "" in case of the string. + */ +typedef struct Packet { + /** The next packet. Used for queueing packets before sending. */ + struct Packet *next; + /** The size of the whole packet for received packets. For packets + * that will be sent, the value is filled in just before the + * actual transmission. */ + PacketSize size; + /** The current read/write position in the packet */ + PacketSize pos; + /** The buffer of this packet */ + byte buffer[SEND_MTU]; +} Packet; + + +Packet *NetworkSend_Init(PacketType type); +void NetworkSend_FillPacketSize(Packet *packet); +void NetworkSend_uint8 (Packet *packet, uint8 data); +void NetworkSend_uint16(Packet *packet, uint16 data); +void NetworkSend_uint32(Packet *packet, uint32 data); +void NetworkSend_uint64(Packet *packet, uint64 data); +void NetworkSend_string(Packet *packet, const char* data); + +void NetworkRecv_ReadPacketSize(Packet *packet); +uint8 NetworkRecv_uint8 (NetworkClientState *cs, Packet *packet); +uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet); +uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet); +uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet); +void NetworkRecv_string(NetworkClientState *cs, Packet *packet, char* buffer, size_t size); + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_PACKET_H */ diff --git a/network/core/tcp.c b/network/core/tcp.c new file mode 100644 index 0000000000..493a97dfff --- /dev/null +++ b/network/core/tcp.c @@ -0,0 +1,227 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../../stdafx.h" +#include "../../debug.h" +#include "../../openttd.h" +#include "../../variables.h" +#include "../../table/strings.h" +#include "../../functions.h" + +#include "os_abstraction.h" +#include "config.h" +#include "packet.h" +#include "../network_data.h" +#include "tcp.h" + +/** + * @file tcp.c Basic functions to receive and send TCP packets. + */ + +/** + * Functions to help NetworkRecv_Packet/NetworkSend_Packet a bit + * A socket can make errors. When that happens this handles what to do. + * For clients: close connection and drop back to main-menu + * For servers: close connection and that is it + * @param cs the client to close the connection of + * @return the new status + */ +NetworkRecvStatus CloseConnection(NetworkClientState *cs) +{ + NetworkCloseClient(cs); + + /* Clients drop back to the main menu */ + if (!_network_server && _networking) { + _switch_mode = SM_MENU; + _networking = false; + _switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION; + + return NETWORK_RECV_STATUS_CONN_LOST; + } + + return NETWORK_RECV_STATUS_OKAY; +} + +/** + * Whether the client has quit or not (used in packet.c) + * @param cs the client to check + * @return true if the client has quit + */ +bool HasClientQuit(NetworkClientState *cs) +{ + return cs->has_quit; +} + +/** + * This function puts the packet in the send-queue and it is send as + * soon as possible. This is the next tick, or maybe one tick later + * if the OS-network-buffer is full) + * @param packet the packet to send + * @param cs the client to send to + */ +void NetworkSend_Packet(Packet *packet, NetworkClientState *cs) +{ + Packet *p; + assert(packet != NULL); + + packet->pos = 0; + packet->next = NULL; + + NetworkSend_FillPacketSize(packet); + + /* Locate last packet buffered for the client */ + p = cs->packet_queue; + if (p == NULL) { + /* No packets yet */ + cs->packet_queue = packet; + } else { + /* Skip to the last packet */ + while (p->next != NULL) p = p->next; + p->next = packet; + } +} + +/** + * Sends all the buffered packets out for this client. It stops when: + * 1) all packets are send (queue is empty) + * 2) the OS reports back that it can not send any more + * data right now (full network-buffer, it happens ;)) + * 3) sending took too long + * @param cs the client to send the packets for + */ +bool NetworkSend_Packets(NetworkClientState *cs) +{ + ssize_t res; + Packet *p; + + /* We can not write to this socket!! */ + if (!cs->writable) return false; + if (cs->socket == INVALID_SOCKET) return false; + + p = cs->packet_queue; + while (p != NULL) { + res = send(cs->socket, p->buffer + p->pos, p->size - p->pos, 0); + if (res == -1) { + int err = GET_LAST_ERROR(); + if (err != EWOULDBLOCK) { + /* Something went wrong.. close client! */ + DEBUG(net, 0, "send failed with error %d", err); + CloseConnection(cs); + return false; + } + return true; + } + if (res == 0) { + /* Client/server has left us :( */ + CloseConnection(cs); + return false; + } + + p->pos += res; + + /* Is this packet sent? */ + if (p->pos == p->size) { + /* Go to the next packet */ + cs->packet_queue = p->next; + free(p); + p = cs->packet_queue; + } else { + return true; + } + } + + return true; +} + +/** + * Receives a packet for the given client + * @param cs the client to (try to) receive a packet for + * @param status the variable to store the status into + * @return the received packet (or NULL when it didn't receive one) + */ +Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status) +{ + ssize_t res; + Packet *p; + + *status = NETWORK_RECV_STATUS_OKAY; + + if (cs->socket == INVALID_SOCKET) return NULL; + + if (cs->packet_recv == NULL) { + cs->packet_recv = malloc(sizeof(Packet)); + if (cs->packet_recv == NULL) error("Failed to allocate packet"); + /* Set pos to zero! */ + cs->packet_recv->pos = 0; + cs->packet_recv->size = 0; // Can be ommited, just for safety reasons + } + + p = cs->packet_recv; + + /* Read packet size */ + if (p->pos < sizeof(PacketSize)) { + while (p->pos < sizeof(PacketSize)) { + /* Read the size of the packet */ + res = recv(cs->socket, p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0); + if (res == -1) { + int err = GET_LAST_ERROR(); + if (err != EWOULDBLOCK) { + /* Something went wrong... (104 is connection reset by peer) */ + if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); + *status = CloseConnection(cs); + return NULL; + } + /* Connection would block, so stop for now */ + return NULL; + } + if (res == 0) { + /* Client/server has left */ + *status = CloseConnection(cs); + return NULL; + } + p->pos += res; + } + + NetworkRecv_ReadPacketSize(p); + + if (p->size > SEND_MTU) { + *status = CloseConnection(cs); + return NULL; + } + } + + /* Read rest of packet */ + while (p->pos < p->size) { + res = recv(cs->socket, p->buffer + p->pos, p->size - p->pos, 0); + if (res == -1) { + int err = GET_LAST_ERROR(); + if (err != EWOULDBLOCK) { + /* Something went wrong... (104 is connection reset by peer) */ + if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); + *status = CloseConnection(cs); + return NULL; + } + /* Connection would block */ + return NULL; + } + if (res == 0) { + /* Client/server has left */ + *status = CloseConnection(cs); + return NULL; + } + + p->pos += res; + } + + /* We have a complete packet, return it! */ + p->pos = 2; + p->next = NULL; // Should not be needed, but who knows... + + /* Prepare for receiving a new packet */ + cs->packet_recv = NULL; + + return p; +} + +#endif /* ENABLE_NETWORK */ diff --git a/network/core/tcp.h b/network/core/tcp.h new file mode 100644 index 0000000000..e3c3073531 --- /dev/null +++ b/network/core/tcp.h @@ -0,0 +1,60 @@ +/* $Id$ */ + +#ifndef NETWORK_CORE_TCP_H +#define NETWORK_CORE_TCP_H + +#ifdef ENABLE_NETWORK + +/** + * @file tcp.h Basic functions to receive and send TCP packets. + */ + +/** + * Enum with all types of UDP packets. + * The order of the first 4 packets MUST not be changed, as + * it protects old clients from joining newer servers + * (because SERVER_ERROR is the respond to a wrong revision) + */ +enum { + PACKET_SERVER_FULL, + PACKET_SERVER_BANNED, + PACKET_CLIENT_JOIN, + PACKET_SERVER_ERROR, + PACKET_CLIENT_COMPANY_INFO, + PACKET_SERVER_COMPANY_INFO, + PACKET_SERVER_CLIENT_INFO, + PACKET_SERVER_NEED_PASSWORD, + PACKET_CLIENT_PASSWORD, + PACKET_SERVER_WELCOME, + PACKET_CLIENT_GETMAP, + PACKET_SERVER_WAIT, + PACKET_SERVER_MAP, + PACKET_CLIENT_MAP_OK, + PACKET_SERVER_JOIN, + PACKET_SERVER_FRAME, + PACKET_SERVER_SYNC, + PACKET_CLIENT_ACK, + PACKET_CLIENT_COMMAND, + PACKET_SERVER_COMMAND, + PACKET_CLIENT_CHAT, + PACKET_SERVER_CHAT, + PACKET_CLIENT_SET_PASSWORD, + PACKET_CLIENT_SET_NAME, + PACKET_CLIENT_QUIT, + PACKET_CLIENT_ERROR, + PACKET_SERVER_QUIT, + PACKET_SERVER_ERROR_QUIT, + PACKET_SERVER_SHUTDOWN, + PACKET_SERVER_NEWGAME, + PACKET_SERVER_RCON, + PACKET_CLIENT_RCON, + PACKET_END ///< Must ALWAYS be on the end of this list!! (period) +}; + +void NetworkSend_Packet(Packet *packet, NetworkClientState *cs); +Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status); +bool NetworkSend_Packets(NetworkClientState *cs); + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_TCP_H */ diff --git a/network/core/udp.c b/network/core/udp.c new file mode 100644 index 0000000000..badd9a532e --- /dev/null +++ b/network/core/udp.c @@ -0,0 +1,277 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../../stdafx.h" +#include "../../date.h" +#include "../../debug.h" +#include "../../macros.h" +#include "../../newgrf_config.h" + +#include "os_abstraction.h" +#include "config.h" +#include "game.h" +#include "packet.h" +#include "udp.h" + +/** + * @file udp.c Basic functions to receive and send UDP packets. + */ + +/** + * Send a packet over UDP + * @param udp the socket to send over + * @param p the packet to send + * @param recv the receiver (target) of the packet + */ +void NetworkSendUDP_Packet(SOCKET udp, Packet *p, struct sockaddr_in *recv) +{ + int res; + + NetworkSend_FillPacketSize(p); + + /* Send the buffer */ + res = sendto(udp, p->buffer, p->size, 0, (struct sockaddr *)recv, sizeof(*recv)); + + /* Check for any errors, but ignore it otherwise */ + if (res == -1) DEBUG(net, 1, "[udp] sendto failed with: %i", GET_LAST_ERROR()); +} + +/** + * Start listening on the given host and port. + * @param udp the place where the (references to the) UDP are stored + * @param host the host (ip) to listen on + * @param port the port to listen on + * @param broadcast whether to allow broadcast sending/receiving + * @return true if the listening succeeded + */ +bool NetworkUDPListen(SOCKET *udp, uint32 host, uint16 port, bool broadcast) +{ + struct sockaddr_in sin; + + /* Make sure socket is closed */ + closesocket(*udp); + + *udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (*udp == INVALID_SOCKET) { + DEBUG(net, 0, "[udp] failed to start UDP listener"); + return false; + } + + /* set nonblocking mode for socket */ + { + unsigned long blocking = 1; +#ifndef BEOS_NET_SERVER + ioctlsocket(*udp, FIONBIO, &blocking); +#else + setsockopt(*udp, SOL_SOCKET, SO_NONBLOCK, &blocking, NULL); +#endif + } + + sin.sin_family = AF_INET; + /* Listen on all IPs */ + sin.sin_addr.s_addr = host; + sin.sin_port = htons(port); + + if (bind(*udp, (struct sockaddr*)&sin, sizeof(sin)) != 0) { + DEBUG(net, 0, "[udp] bind failed on %s:%i", inet_ntoa(*(struct in_addr *)&host), port); + return false; + } + + if (broadcast) { + /* Enable broadcast */ + unsigned long val = 1; +#ifndef BEOS_NET_SERVER // will work around this, some day; maybe. + setsockopt(*udp, SOL_SOCKET, SO_BROADCAST, (char *) &val , sizeof(val)); +#endif + } + + DEBUG(net, 1, "[udp] listening on port %s:%d", inet_ntoa(*(struct in_addr *)&host), port); + + return true; +} + +/** + * Receive a packet at UDP level + * @param udp the socket to receive the packet on + */ +void NetworkUDPReceive(SOCKET udp) +{ + struct sockaddr_in client_addr; + socklen_t client_len; + int nbytes; + Packet p; + int packet_len; + + packet_len = sizeof(p.buffer); + client_len = sizeof(client_addr); + + /* Try to receive anything */ + nbytes = recvfrom(udp, p.buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len); + + /* We got some bytes for the base header of the packet. + * Assume we received the whole packet. */ + if (nbytes > 2) { + NetworkRecv_ReadPacketSize(&p); + + /* Put the position on the right place */ + p.pos = 2; + p.next = NULL; + + /* Handle the packet */ + NetworkHandleUDPPacket(&p, &client_addr); + } +} + + +/** + * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet + * @param p the packet to write the data to + * @param c the configuration to write the GRF ID and MD5 checksum from + */ +void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c) +{ + uint j; + NetworkSend_uint32(p, c->grfid); + for (j = 0; j < sizeof(c->md5sum); j++) { + NetworkSend_uint8 (p, c->md5sum[j]); + } +} + +/** + * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet + * @param cs the client state (for closing connect on out-of-bounds reading etc) + * @param p the packet to read the data from + * @param c the configuration to write the GRF ID and MD5 checksum to + */ +void NetworkRecv_GRFIdentifier(NetworkClientState *cs, Packet *p, GRFConfig *c) +{ + uint j; + c->grfid = NetworkRecv_uint32(cs, p); + for (j = 0; j < sizeof(c->md5sum); j++) { + c->md5sum[j] = NetworkRecv_uint8(cs, p); + } +} + + +/** + * Serializes the NetworkGameInfo struct to the packet + * @param p the packet to write the data to + * @param info the NetworkGameInfo struct to serialize + */ +void NetworkSend_NetworkGameInfo(Packet *p, const NetworkGameInfo *info) +{ + NetworkSend_uint8 (p, NETWORK_GAME_INFO_VERSION); + + /* + * Please observe the order. + * The parts must be read in the same order as they are sent! + */ + + + /* NETWORK_GAME_INFO_VERSION = 4 */ + { + /* Only send the GRF Identification (GRF_ID and MD5 checksum) of + * the GRFs that are needed, i.e. the ones that the server has + * selected in the NewGRF GUI and not the ones that are used due + * to the fact that they are in [newgrf-static] in openttd.cfg */ + const GRFConfig *c; + uint count = 0; + + /* Count number of GRFs to send information about */ + for (c = info->grfconfig; c != NULL; c = c->next) { + if (!HASBIT(c->flags, GCF_STATIC)) count++; + } + NetworkSend_uint8 (p, count); // Send number of GRFs + + /* Send actual GRF Identifications */ + for (c = info->grfconfig; c != NULL; c = c->next) { + if (!HASBIT(c->flags, GCF_STATIC)) NetworkSend_GRFIdentifier(p, c); + } + } + + /* NETWORK_GAME_INFO_VERSION = 3 */ + NetworkSend_uint32(p, info->game_date); + NetworkSend_uint32(p, info->start_date); + + /* NETWORK_GAME_INFO_VERSION = 2 */ + NetworkSend_uint8 (p, info->companies_max); + NetworkSend_uint8 (p, info->companies_on); + NetworkSend_uint8 (p, info->spectators_max); + + /* NETWORK_GAME_INFO_VERSION = 1 */ + NetworkSend_string(p, info->server_name); + NetworkSend_string(p, info->server_revision); + NetworkSend_uint8 (p, info->server_lang); + NetworkSend_uint8 (p, info->use_password); + NetworkSend_uint8 (p, info->clients_max); + NetworkSend_uint8 (p, info->clients_on); + NetworkSend_uint8 (p, info->spectators_on); + NetworkSend_string(p, info->map_name); + NetworkSend_uint16(p, info->map_width); + NetworkSend_uint16(p, info->map_height); + NetworkSend_uint8 (p, info->map_set); + NetworkSend_uint8 (p, info->dedicated); +} + +/** + * Deserializes the NetworkGameInfo struct from the packet + * @param cs the client state (for closing connect on out-of-bounds reading etc) + * @param p the packet to read the data from + * @param info the NetworkGameInfo to deserialize into + */ +void NetworkRecv_NetworkGameInfo(NetworkClientState *cs, Packet *p, NetworkGameInfo *info) +{ + info->game_info_version = NetworkRecv_uint8(cs, p); + + /* + * Please observe the order. + * The parts must be read in the same order as they are sent! + */ + + switch (info->game_info_version) { + case 4: { + GRFConfig *c, **dst = &info->grfconfig; + uint i; + uint num_grfs = NetworkRecv_uint8(cs, p); + + for (i = 0; i < num_grfs; i++) { + c = calloc(1, sizeof(*c)); + NetworkRecv_GRFIdentifier(cs, p, c); + HandleIncomingNetworkGameInfoGRFConfig(c); + + /* Append GRFConfig to the list */ + *dst = c; + dst = &c->next; + } + } /* Fallthrough */ + case 3: + info->game_date = NetworkRecv_uint32(cs, p); + info->start_date = NetworkRecv_uint32(cs, p); + /* Fallthrough */ + case 2: + info->companies_max = NetworkRecv_uint8 (cs, p); + info->companies_on = NetworkRecv_uint8 (cs, p); + info->spectators_max = NetworkRecv_uint8 (cs, p); + /* Fallthrough */ + case 1: + NetworkRecv_string(cs, p, info->server_name, sizeof(info->server_name)); + NetworkRecv_string(cs, p, info->server_revision, sizeof(info->server_revision)); + info->server_lang = NetworkRecv_uint8 (cs, p); + info->use_password = NetworkRecv_uint8 (cs, p); + info->clients_max = NetworkRecv_uint8 (cs, p); + info->clients_on = NetworkRecv_uint8 (cs, p); + info->spectators_on = NetworkRecv_uint8 (cs, p); + if (info->game_info_version < 3) { // 16 bits dates got scrapped and are read earlier + info->game_date = NetworkRecv_uint16(cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR; + info->start_date = NetworkRecv_uint16(cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR; + } + NetworkRecv_string(cs, p, info->map_name, sizeof(info->map_name)); + info->map_width = NetworkRecv_uint16(cs, p); + info->map_height = NetworkRecv_uint16(cs, p); + info->map_set = NetworkRecv_uint8 (cs, p); + info->dedicated = NetworkRecv_uint8 (cs, p); + } +} + +#endif /* ENABLE_NETWORK */ diff --git a/network/core/udp.h b/network/core/udp.h new file mode 100644 index 0000000000..3221e664f6 --- /dev/null +++ b/network/core/udp.h @@ -0,0 +1,62 @@ +/* $Id$ */ + +#ifndef NETWORK_CORE_UDP_H +#define NETWORK_CORE_UDP_H + +#ifdef ENABLE_NETWORK + +/** + * @file udp.h Basic functions to receive and send UDP packets. + */ + +///** Sending/receiving of UDP packets **//// + +void NetworkSendUDP_Packet(SOCKET udp, Packet *p, struct sockaddr_in *recv); +bool NetworkUDPListen(SOCKET *udp, uint32 host, uint16 port, bool broadcast); +void NetworkUDPReceive(SOCKET udp); + +/** + * Function that is called for every received UDP packet. + * @param packet the received packet + * @param client_addr the address of the sender of the packet + */ +void NetworkHandleUDPPacket(Packet *p, struct sockaddr_in *client_addr); + + +///** Sending/receiving of (large) chuncks of UDP packets **//// + + +/** Enum with all types of UDP packets. The order MUST not be changed **/ +enum { + PACKET_UDP_CLIENT_FIND_SERVER, ///< Queries a game server for game information + PACKET_UDP_SERVER_RESPONSE, ///< Reply of the game server with game information + PACKET_UDP_CLIENT_DETAIL_INFO, ///< Queries a game server about details of the game, such as companies + PACKET_UDP_SERVER_DETAIL_INFO, ///< Reply of the game server about details of the game, such as companies + PACKET_UDP_SERVER_REGISTER, ///< Packet to register itself to the master server + PACKET_UDP_MASTER_ACK_REGISTER, ///< Packet indicating registration has succedeed + PACKET_UDP_CLIENT_GET_LIST, ///< Request for serverlist from master server + PACKET_UDP_MASTER_RESPONSE_LIST, ///< Response from master server with server ip's + port's + PACKET_UDP_SERVER_UNREGISTER, ///< Request to be removed from the server-list + PACKET_UDP_CLIENT_GET_NEWGRFS, ///< Requests the name for a list of GRFs (GRF_ID and MD5) + PACKET_UDP_SERVER_NEWGRFS, ///< Sends the list of NewGRF's requested. + PACKET_UDP_END ///< Must ALWAYS be on the end of this list!! (period) +}; + +void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c); +void NetworkSend_NetworkGameInfo(Packet *p, const NetworkGameInfo *info); + +void NetworkRecv_GRFIdentifier(NetworkClientState *cs, Packet *p, GRFConfig *c); +void NetworkRecv_NetworkGameInfo(NetworkClientState *cs, Packet *p, NetworkGameInfo *info); + +/** + * Function that is called for every GRFConfig that is read when receiving + * a NetworkGameInfo. Only grfid and md5sum are set, the rest is zero. This + * function must set all appropriate fields. This GRF is later appended to + * the grfconfig list of the NetworkGameInfo. + * @param config the GRF to handle + */ +void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config); + +#endif /* ENABLE_NETWORK */ + +#endif /* NETWORK_CORE_UDP_H */ diff --git a/network.c b/network/network.c similarity index 98% rename from network.c rename to network/network.c index 8b5b9ceef8..83f7eedcd7 100644 --- a/network.c +++ b/network/network.c @@ -1,6 +1,6 @@ /* $Id$ */ -#include "stdafx.h" +#include "../stdafx.h" #include "network_data.h" #if defined(WITH_REV) @@ -15,24 +15,27 @@ #ifdef ENABLE_NETWORK -#include "openttd.h" -#include "debug.h" -#include "functions.h" -#include "string.h" -#include "strings.h" -#include "map.h" -#include "command.h" -#include "variables.h" -#include "date.h" -#include "table/strings.h" +#include "../openttd.h" +#include "../debug.h" +#include "../functions.h" +#include "../string.h" +#include "../strings.h" +#include "../map.h" +#include "../command.h" +#include "../variables.h" +#include "../date.h" +#include "../newgrf_config.h" +#include "../table/strings.h" #include "network_client.h" #include "network_server.h" #include "network_udp.h" #include "network_gamelist.h" +#include "core/udp.h" +#include "core/tcp.h" #include "network_gui.h" -#include "console.h" /* IConsoleCmdExec */ +#include "../console.h" /* IConsoleCmdExec */ #include /* va_list */ -#include "md5.h" +#include "../md5.h" #ifdef __MORPHOS__ // the library base is required here diff --git a/network.h b/network/network.h similarity index 68% rename from network.h rename to network/network.h index 5453658e42..779fe393ec 100644 --- a/network.h +++ b/network/network.h @@ -7,7 +7,9 @@ #ifdef ENABLE_NETWORK -#include "player.h" +#include "../player.h" +#include "core/config.h" +#include "core/game.h" // If this line is enable, every frame will have a sync test // this is not needed in normal games. Normal is like 1 sync in 100 @@ -31,13 +33,6 @@ // Do not change this next line. It should _ALWAYS_ be MAX_CLIENTS + 1 #define MAX_CLIENT_INFO (MAX_CLIENTS + 1) -/* Stuff for the master-server */ -#define NETWORK_MASTER_SERVER_PORT 3978 -#define NETWORK_MASTER_SERVER_HOST "master.openttd.org" -#define NETWORK_MASTER_SERVER_WELCOME_MESSAGE "OpenTTDRegister" - -#define NETWORK_DEFAULT_PORT 3979 - #define MAX_INTERFACES 9 @@ -45,60 +40,6 @@ #define NETWORK_VEHICLE_TYPES 5 #define NETWORK_STATION_TYPES 5 -enum { - NETWORK_NAME_LENGTH = 80, - NETWORK_HOSTNAME_LENGTH = 80, - NETWORK_REVISION_LENGTH = 15, - NETWORK_PASSWORD_LENGTH = 20, - NETWORK_PLAYERS_LENGTH = 200, - NETWORK_CLIENT_NAME_LENGTH = 25, - NETWORK_RCONCOMMAND_LENGTH = 500, - - NETWORK_GRF_NAME_LENGTH = 80, ///< Maximum length of the name of a GRF - /* Maximum number of GRFs that can be sent. - * This value is related to number of handles (files) OpenTTD can open. - * This is currently 64 and about 10 are currently used when OpenTTD loads - * without any NewGRFs. Therefore one can only load about 55 NewGRFs, so - * this is not a limit, but rather a way to easily check whether the limit - * imposed by the handle count is reached. Secondly it isn't possible to - * send much more GRF IDs + MD5sums in the PACKET_UDP_SERVER_RESPONSE, due - * to the limited size of UDP packets. */ - NETWORK_MAX_GRF_COUNT = 55, - - NETWORK_NUM_LANGUAGES = 4, -}; - -// This is the struct used by both client and server -// some fields will be empty on the client (like game_password) by default -// and only filled with data a player enters. -typedef struct NetworkGameInfo { - char server_name[NETWORK_NAME_LENGTH]; // Server name - char hostname[NETWORK_HOSTNAME_LENGTH]; // Hostname of the server (if any) - char server_revision[NETWORK_REVISION_LENGTH]; // The SVN version number the server is using (e.g.: 'r304') - // It even shows a SVN version in release-version, so - // it is easy to compare if a server is of the correct version - bool version_compatible; // Can we connect to this server or not? (based on server_revision) - bool compatible; // Can we connect to this server or not? (based on server_revision _and_ grf_match - byte server_lang; // Language of the server (we should make a nice table for this) - byte use_password; // Is set to != 0 if it uses a password - char server_password[NETWORK_PASSWORD_LENGTH]; // On the server: the game password, on the client: != "" if server has password - byte clients_max; // Max clients allowed on server - byte clients_on; // Current count of clients on server - byte companies_max; // Max companies allowed on server - byte companies_on; // How many started companies do we have (XXX - disabled for server atm, use ActivePlayerCount()) - byte spectators_max; // Max spectators allowed on server - byte spectators_on; // How many spectators do we have? (XXX - disabled for server atm, use NetworkSpectatorCount()) - Date game_date; // Current date - Date start_date; // When the game started - char map_name[NETWORK_NAME_LENGTH]; // Map which is played ["random" for a randomized map] - uint16 map_width; // Map width - uint16 map_height; // Map height - byte map_set; // Graphical set - bool dedicated; // Is this a dedicated server? - char rcon_password[NETWORK_PASSWORD_LENGTH]; // RCon password for the server. "" if rcon is disabled - struct GRFConfig *grfconfig; // List of NewGRF files required -} NetworkGameInfo; - typedef struct NetworkPlayerInfo { char company_name[NETWORK_NAME_LENGTH]; // Company name char password[NETWORK_PASSWORD_LENGTH]; // The password for the player diff --git a/network_client.c b/network/network_client.c similarity index 98% rename from network_client.c rename to network/network_client.c index 39a12c28c9..ce2a71ac19 100644 --- a/network_client.c +++ b/network/network_client.c @@ -2,23 +2,24 @@ #ifdef ENABLE_NETWORK -#include "stdafx.h" -#include "debug.h" -#include "string.h" -#include "strings.h" +#include "../stdafx.h" +#include "../debug.h" +#include "../string.h" +#include "../strings.h" #include "network_data.h" -#include "date.h" -#include "table/strings.h" -#include "functions.h" +#include "core/tcp.h" +#include "../date.h" +#include "../table/strings.h" +#include "../functions.h" #include "network_client.h" #include "network_gamelist.h" #include "network_gui.h" -#include "saveload.h" -#include "command.h" -#include "window.h" -#include "console.h" -#include "variables.h" -#include "ai/ai.h" +#include "../saveload.h" +#include "../command.h" +#include "../window.h" +#include "../console.h" +#include "../variables.h" +#include "../ai/ai.h" // This file handles all the client-commands diff --git a/network_client.h b/network/network_client.h similarity index 100% rename from network_client.h rename to network/network_client.h diff --git a/network/network_data.c b/network/network_data.c new file mode 100644 index 0000000000..9e5e6424d3 --- /dev/null +++ b/network/network_data.c @@ -0,0 +1,106 @@ +/* $Id$ */ + +#ifdef ENABLE_NETWORK + +#include "../stdafx.h" +#include "../debug.h" +#include "network_data.h" +#include "../string.h" +#include "network_client.h" +#include "../command.h" +#include "../callback_table.h" + +// Add a command to the local command queue +void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp) +{ + CommandPacket* new_cp = malloc(sizeof(*new_cp)); + + *new_cp = *cp; + + if (cs->command_queue == NULL) { + cs->command_queue = new_cp; + } else { + CommandPacket *c = cs->command_queue; + while (c->next != NULL) c = c->next; + c->next = new_cp; + } +} + +// Prepare a DoCommand to be send over the network +void NetworkSend_Command(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback) +{ + CommandPacket *c = malloc(sizeof(CommandPacket)); + byte temp_callback; + + c->player = _local_player; + c->next = NULL; + c->tile = tile; + c->p1 = p1; + c->p2 = p2; + c->cmd = cmd; + c->callback = 0; + + temp_callback = 0; + + while (temp_callback < _callback_table_count && _callback_table[temp_callback] != callback) + temp_callback++; + if (temp_callback == _callback_table_count) { + DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", callback); + temp_callback = 0; /* _callback_table[0] == NULL */ + } + + if (_network_server) { + // We are the server, so set the command to be executed next possible frame + c->frame = _frame_counter_max + 1; + } else { + c->frame = 0; // The client can't tell which frame, so just make it 0 + } + + ttd_strlcpy(c->text, (_cmd_text != NULL) ? _cmd_text : "", lengthof(c->text)); + + if (_network_server) { + // If we are the server, we queue the command in our 'special' queue. + // In theory, we could execute the command right away, but then the + // client on the server can do everything 1 tick faster than others. + // So to keep the game fair, we delay the command with 1 tick + // which gives about the same speed as most clients. + NetworkClientState *cs; + + // And we queue it for delivery to the clients + FOR_ALL_CLIENTS(cs) { + if (cs->status > STATUS_AUTH) NetworkAddCommandQueue(cs, c); + } + + // Only the server gets the callback, because clients should not get them + c->callback = temp_callback; + if (_local_command_queue == NULL) { + _local_command_queue = c; + } else { + // Find last packet + CommandPacket *cp = _local_command_queue; + while (cp->next != NULL) cp = cp->next; + cp->next = c; + } + + return; + } + + // Clients send their command to the server and forget all about the packet + c->callback = temp_callback; + SEND_COMMAND(PACKET_CLIENT_COMMAND)(c); +} + +// Execute a DoCommand we received from the network +void NetworkExecuteCommand(CommandPacket *cp) +{ + _current_player = cp->player; + _cmd_text = cp->text; + /* cp->callback is unsigned. so we don't need to do lower bounds checking. */ + if (cp->callback > _callback_table_count) { + DEBUG(net, 0, "Received out-of-bounds callback (%d)", cp->callback); + cp->callback = 0; + } + DoCommandP(cp->tile, cp->p1, cp->p2, _callback_table[cp->callback], cp->cmd | CMD_NETWORK_COMMAND); +} + +#endif /* ENABLE_NETWORK */ diff --git a/network_data.h b/network/network_data.h similarity index 69% rename from network_data.h rename to network/network_data.h index 16263c7762..3e42e00cf1 100644 --- a/network_data.h +++ b/network/network_data.h @@ -3,36 +3,21 @@ #ifndef NETWORK_DATA_H #define NETWORK_DATA_H -#include "openttd.h" -#include "network.h" -#include "network_core.h" - // Is the network enabled? #ifdef ENABLE_NETWORK -#define SEND_MTU 1460 +#include "../openttd.h" +#include "network.h" +#include "core/os_abstraction.h" +#include "core/config.h" +#include "core/packet.h" + #define MAX_TEXT_MSG_LEN 1024 /* long long long long sentences :-) */ // The client-info-server-index is always 1 #define NETWORK_SERVER_INDEX 1 #define NETWORK_EMPTY_INDEX 0 -// What version of game-info do we use? -#define NETWORK_GAME_INFO_VERSION 4 -// What version of company info is this? -#define NETWORK_COMPANY_INFO_VERSION 4 -// What version of master-server-protocol do we use? -#define NETWORK_MASTER_SERVER_VERSION 1 - -typedef uint16 PacketSize; - -typedef struct Packet { - struct Packet *next; - PacketSize size; - PacketSize pos; - byte buffer[SEND_MTU]; -} Packet; - typedef struct CommandPacket { struct CommandPacket *next; PlayerID player; /// player that is executing the command @@ -112,7 +97,7 @@ typedef enum { } NetworkPasswordType; // To keep the clients all together -typedef struct NetworkClientState { +struct NetworkClientState { // Typedeffed in network_core/packet.h SOCKET socket; uint16 index; uint32 last_frame; @@ -127,47 +112,7 @@ typedef struct NetworkClientState { Packet *packet_recv; // Partially received packet CommandPacket *command_queue; // The command-queue awaiting delivery -} NetworkClientState; - -// What packet types are there -// WARNING: The first 3 packets can NEVER change order again -// it protects old clients from joining newer servers (because SERVER_ERROR -// is the respond to a wrong revision) -typedef enum { - PACKET_SERVER_FULL, - PACKET_SERVER_BANNED, - PACKET_CLIENT_JOIN, - PACKET_SERVER_ERROR, - PACKET_CLIENT_COMPANY_INFO, - PACKET_SERVER_COMPANY_INFO, - PACKET_SERVER_CLIENT_INFO, - PACKET_SERVER_NEED_PASSWORD, - PACKET_CLIENT_PASSWORD, - PACKET_SERVER_WELCOME, - PACKET_CLIENT_GETMAP, - PACKET_SERVER_WAIT, - PACKET_SERVER_MAP, - PACKET_CLIENT_MAP_OK, - PACKET_SERVER_JOIN, - PACKET_SERVER_FRAME, - PACKET_SERVER_SYNC, - PACKET_CLIENT_ACK, - PACKET_CLIENT_COMMAND, - PACKET_SERVER_COMMAND, - PACKET_CLIENT_CHAT, - PACKET_SERVER_CHAT, - PACKET_CLIENT_SET_PASSWORD, - PACKET_CLIENT_SET_NAME, - PACKET_CLIENT_QUIT, - PACKET_CLIENT_ERROR, - PACKET_SERVER_QUIT, - PACKET_SERVER_ERROR_QUIT, - PACKET_SERVER_SHUTDOWN, - PACKET_SERVER_NEWGAME, - PACKET_SERVER_RCON, - PACKET_CLIENT_RCON, - PACKET_END // Should ALWAYS be on the end of this list!! (period) -} PacketType; +}; typedef enum { DESTTYPE_BROADCAST, ///< Send message/notice to all players (All) @@ -202,22 +147,6 @@ NetworkClientState _clients[MAX_CLIENTS]; #define FOR_ALL_CLIENTS(cs) for (cs = _clients; cs != endof(_clients) && cs->socket != INVALID_SOCKET; cs++) #define FOR_ALL_ACTIVE_CLIENT_INFOS(ci) for (ci = _network_client_info; ci != endof(_network_client_info); ci++) if (ci->client_index != NETWORK_EMPTY_INDEX) -Packet *NetworkSend_Init(PacketType type); -void NetworkSend_uint8(Packet *packet, uint8 data); -void NetworkSend_uint16(Packet *packet, uint16 data); -void NetworkSend_uint32(Packet *packet, uint32 data); -void NetworkSend_uint64(Packet *packet, uint64 data); -void NetworkSend_string(Packet *packet, const char* data); -void NetworkSend_Packet(Packet *packet, NetworkClientState *cs); - -uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet); -uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet); -uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet); -uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet); -void NetworkRecv_string(NetworkClientState *cs, Packet *packet, char* buffer, size_t size); -Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status); - -bool NetworkSend_Packets(NetworkClientState *cs); void NetworkExecuteCommand(CommandPacket *cp); void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp); diff --git a/network_gamelist.c b/network/network_gamelist.c similarity index 95% rename from network_gamelist.c rename to network/network_gamelist.c index 15fd7aa573..a830073adb 100644 --- a/network_gamelist.c +++ b/network/network_gamelist.c @@ -2,10 +2,10 @@ #ifdef ENABLE_NETWORK -#include "stdafx.h" -#include "debug.h" +#include "../stdafx.h" +#include "../debug.h" #include "network_data.h" -#include "newgrf_config.h" +#include "../newgrf_config.h" // This file handles the GameList // Also, it handles the request to a server for data about the server diff --git a/network_gamelist.h b/network/network_gamelist.h similarity index 100% rename from network_gamelist.h rename to network/network_gamelist.h diff --git a/network_gui.c b/network/network_gui.c similarity index 99% rename from network_gui.c rename to network/network_gui.c index d0dd5df4cb..91c990bbca 100644 --- a/network_gui.c +++ b/network/network_gui.c @@ -1,32 +1,32 @@ /* $Id$ */ #ifdef ENABLE_NETWORK -#include "stdafx.h" -#include "openttd.h" -#include "string.h" -#include "strings.h" -#include "table/sprites.h" +#include "../stdafx.h" +#include "../openttd.h" +#include "../string.h" +#include "../strings.h" +#include "../table/sprites.h" #include "network.h" -#include "date.h" +#include "../date.h" -#include "fios.h" -#include "table/strings.h" -#include "functions.h" +#include "../fios.h" +#include "../table/strings.h" +#include "../functions.h" #include "network_data.h" #include "network_client.h" #include "network_gui.h" #include "network_gamelist.h" -#include "window.h" -#include "gui.h" -#include "gfx.h" -#include "command.h" -#include "variables.h" +#include "../window.h" +#include "../gui.h" +#include "../gfx.h" +#include "../command.h" +#include "../variables.h" #include "network_server.h" #include "network_udp.h" -#include "settings.h" -#include "string.h" -#include "town.h" -#include "newgrf.h" +#include "../settings.h" +#include "../string.h" +#include "../town.h" +#include "../newgrf.h" #define BGC 5 #define BTC 15 diff --git a/network_gui.h b/network/network_gui.h similarity index 100% rename from network_gui.h rename to network/network_gui.h diff --git a/network_server.c b/network/network_server.c similarity index 99% rename from network_server.c rename to network/network_server.c index f1179ce2fa..2a75d15feb 100644 --- a/network_server.c +++ b/network/network_server.c @@ -2,25 +2,26 @@ #ifdef ENABLE_NETWORK -#include "stdafx.h" -#include "openttd.h" // XXX StringID -#include "debug.h" -#include "string.h" -#include "strings.h" +#include "../stdafx.h" +#include "../openttd.h" // XXX StringID +#include "../debug.h" +#include "../string.h" +#include "../strings.h" #include "network_data.h" -#include "train.h" -#include "date.h" -#include "table/strings.h" -#include "functions.h" +#include "core/tcp.h" +#include "../train.h" +#include "../date.h" +#include "../table/strings.h" +#include "../functions.h" #include "network_server.h" #include "network_udp.h" -#include "console.h" -#include "command.h" -#include "saveload.h" -#include "vehicle.h" -#include "station.h" -#include "variables.h" -#include "genworld.h" +#include "../console.h" +#include "../command.h" +#include "../saveload.h" +#include "../vehicle.h" +#include "../station.h" +#include "../variables.h" +#include "../genworld.h" // This file handles all the server-commands diff --git a/network_server.h b/network/network_server.h similarity index 100% rename from network_server.h rename to network/network_server.h diff --git a/network_udp.c b/network/network_udp.c similarity index 64% rename from network_udp.c rename to network/network_udp.c index a2d6ed3955..aeef75e775 100644 --- a/network_udp.c +++ b/network/network_udp.c @@ -2,37 +2,25 @@ #ifdef ENABLE_NETWORK -#include "stdafx.h" -#include "debug.h" -#include "string.h" +#include "../stdafx.h" +#include "../debug.h" +#include "../string.h" #include "network_data.h" -#include "date.h" -#include "map.h" +#include "../date.h" +#include "../map.h" #include "network_gamelist.h" #include "network_udp.h" -#include "variables.h" -#include "newgrf_config.h" +#include "../variables.h" +#include "../newgrf_config.h" -// -// This file handles all the LAN-stuff -// Stuff like: -// - UDP search over the network -// +#include "core/udp.h" -typedef enum { - PACKET_UDP_CLIENT_FIND_SERVER, - PACKET_UDP_SERVER_RESPONSE, - PACKET_UDP_CLIENT_DETAIL_INFO, - PACKET_UDP_SERVER_DETAIL_INFO, // Is not used in OpenTTD itself, only for external querying - PACKET_UDP_SERVER_REGISTER, // Packet to register itself to the master server - PACKET_UDP_MASTER_ACK_REGISTER, // Packet indicating registration has succedeed - PACKET_UDP_CLIENT_GET_LIST, // Request for serverlist from master server - PACKET_UDP_MASTER_RESPONSE_LIST, // Response from master server with server ip's + port's - PACKET_UDP_SERVER_UNREGISTER, // Request to be removed from the server-list - PACKET_UDP_CLIENT_GET_NEWGRFS, // Requests the name for a list of GRFs (GRF_ID and MD5) - PACKET_UDP_SERVER_NEWGRFS, // Sends the list of NewGRF's requested. - PACKET_UDP_END -} PacketUDPType; +/** + * @file network_udp.c This file handles the UDP related communication. + * + * This is the GameServer <-> MasterServer and GameServer <-> GameClient + * communication before the game is being joined. + */ enum { ADVERTISE_NORMAL_INTERVAL = 30000, // interval between advertising in ticks (15 minutes) @@ -41,38 +29,9 @@ enum { }; #define DEF_UDP_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(Packet *p, struct sockaddr_in *client_addr) -static void NetworkSendUDP_Packet(SOCKET udp, Packet* p, struct sockaddr_in* recv); static NetworkClientState _udp_cs; -/** - * Serializes the GRFIdentifier (GRF ID and MD5 checksum) to the packet - * @param p the packet to write the data to - * @param c the configuration to write the GRF ID and MD5 checksum from - */ -static void NetworkSend_GRFIdentifier(Packet *p, const GRFConfig *c) -{ - uint j; - NetworkSend_uint32(p, c->grfid); - for (j = 0; j < sizeof(c->md5sum); j++) { - NetworkSend_uint8 (p, c->md5sum[j]); - } -} - -/** - * Deserializes the GRFIdentifier (GRF ID and MD5 checksum) from the packet - * @param p the packet to read the data from - * @param c the configuration to write the GRF ID and MD5 checksum to - */ -static void NetworkRecv_GRFIdentifier(Packet *p, GRFConfig *c) -{ - uint j; - c->grfid = NetworkRecv_uint32(&_udp_cs, p); - for (j = 0; j < sizeof(c->md5sum); j++) { - c->md5sum[j] = NetworkRecv_uint8(&_udp_cs, p); - } -} - DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER) { Packet *packet; @@ -83,56 +42,15 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER) packet = NetworkSend_Init(PACKET_UDP_SERVER_RESPONSE); // Update some game_info - _network_game_info.game_date = _date; - _network_game_info.map_width = MapSizeX(); - _network_game_info.map_height = MapSizeY(); - _network_game_info.map_set = _opt.landscape; + _network_game_info.game_date = _date; + _network_game_info.map_width = MapSizeX(); + _network_game_info.map_height = MapSizeY(); + _network_game_info.map_set = _opt.landscape; + _network_game_info.companies_on = ActivePlayerCount(); + _network_game_info.spectators_on = NetworkSpectatorCount(); + _network_game_info.grfconfig = _grfconfig; - NetworkSend_uint8 (packet, NETWORK_GAME_INFO_VERSION); - - /* NETWORK_GAME_INFO_VERSION = 4 */ - { - /* Only send the GRF Identification (GRF_ID and MD5 checksum) of - * the GRFs that are needed, i.e. the ones that the server has - * selected in the NewGRF GUI and not the ones that are used due - * to the fact that they are in [newgrf-static] in openttd.cfg */ - const GRFConfig *c; - uint i = 0; - - /* Count number of GRFs to send information about */ - for (c = _grfconfig; c != NULL; c = c->next) { - if (!HASBIT(c->flags, GCF_STATIC)) i++; - } - NetworkSend_uint8 (packet, i); // Send number of GRFs - - /* Send actual GRF Identifications */ - for (c = _grfconfig; c != NULL; c = c->next) { - if (!HASBIT(c->flags, GCF_STATIC)) NetworkSend_GRFIdentifier(packet, c); - } - } - - /* NETWORK_GAME_INFO_VERSION = 3 */ - NetworkSend_uint32(packet, _network_game_info.game_date); - NetworkSend_uint32(packet, _network_game_info.start_date); - - /* NETWORK_GAME_INFO_VERSION = 2 */ - NetworkSend_uint8 (packet, _network_game_info.companies_max); - NetworkSend_uint8 (packet, ActivePlayerCount()); - NetworkSend_uint8 (packet, _network_game_info.spectators_max); - - /* NETWORK_GAME_INFO_VERSION = 1 */ - NetworkSend_string(packet, _network_game_info.server_name); - NetworkSend_string(packet, _network_game_info.server_revision); - NetworkSend_uint8 (packet, _network_game_info.server_lang); - NetworkSend_uint8 (packet, _network_game_info.use_password); - NetworkSend_uint8 (packet, _network_game_info.clients_max); - NetworkSend_uint8 (packet, _network_game_info.clients_on); - NetworkSend_uint8 (packet, NetworkSpectatorCount()); - NetworkSend_string(packet, _network_game_info.map_name); - NetworkSend_uint16(packet, _network_game_info.map_width); - NetworkSend_uint16(packet, _network_game_info.map_height); - NetworkSend_uint8 (packet, _network_game_info.map_set); - NetworkSend_uint8 (packet, _network_game_info.dedicated); + NetworkSend_NetworkGameInfo(p, &_network_game_info); // Let the client know that we are here NetworkSendUDP_Packet(_udp_server_socket, packet, client_addr); @@ -142,101 +60,40 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER) DEBUG(net, 2, "[udp] queried from '%s'", inet_ntoa(client_addr->sin_addr)); } +void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) +{ + /* Find the matching GRF file */ + const GRFConfig *f = FindGRFConfig(config->grfid, config->md5sum); + if (f == NULL) { + /* Don't know the GRF, so mark game incompatible and the (possibly) + * already resolved name for this GRF (another server has sent the + * name of the GRF already */ + config->name = FindUnknownGRFName(config->grfid, config->md5sum, true); + SETBIT(config->flags, GCF_NOT_FOUND); + } else { + config->filename = f->filename; + config->name = f->name; + config->info = f->info; + } + SETBIT(config->flags, GCF_COPY); +} + DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE) { extern const char _openttd_revision[]; NetworkGameList *item; - byte game_info_version; // Just a fail-safe.. should never happen - if (_network_udp_server) - return; - - game_info_version = NetworkRecv_uint8(&_udp_cs, p); - - if (_udp_cs.has_quit) return; + if (_network_udp_server || _udp_cs.has_quit) return; DEBUG(net, 4, "[udp] server response from %s:%d", inet_ntoa(client_addr->sin_addr),ntohs(client_addr->sin_port)); // Find next item item = NetworkGameListAddItem(inet_addr(inet_ntoa(client_addr->sin_addr)), ntohs(client_addr->sin_port)); + NetworkRecv_NetworkGameInfo(&_udp_cs, p, &item->info); + item->info.compatible = true; - /* Please observer the order. In the order in which packets are sent - * they are to be received */ - switch (game_info_version) { - case 4: { - GRFConfig *c, **dst = &item->info.grfconfig; - const GRFConfig *f; - uint i; - uint num_grfs = NetworkRecv_uint8(&_udp_cs, p); - - for (i = 0; i < num_grfs; i++) { - c = calloc(1, sizeof(*c)); - NetworkRecv_GRFIdentifier(p, c); - - /* Find the matching GRF file */ - f = FindGRFConfig(c->grfid, c->md5sum); - if (f == NULL) { - /* Don't know the GRF, so mark game incompatible and the (possibly) - * already resolved name for this GRF (another server has sent the - * name of the GRF already */ - item->info.compatible = false; - c->name = FindUnknownGRFName(c->grfid, c->md5sum, true); - SETBIT(c->flags, GCF_NOT_FOUND); - } else { - c->filename = f->filename; - c->name = f->name; - c->info = f->info; - } - SETBIT(c->flags, GCF_COPY); - - /* Append GRFConfig to the list */ - *dst = c; - dst = &c->next; - } - } /* Fallthrough */ - case 3: - item->info.game_date = NetworkRecv_uint32(&_udp_cs, p); - item->info.start_date = NetworkRecv_uint32(&_udp_cs, p); - /* Fallthrough */ - case 2: - item->info.companies_max = NetworkRecv_uint8(&_udp_cs, p); - item->info.companies_on = NetworkRecv_uint8(&_udp_cs, p); - item->info.spectators_max = NetworkRecv_uint8(&_udp_cs, p); - /* Fallthrough */ - case 1: - NetworkRecv_string(&_udp_cs, p, item->info.server_name, sizeof(item->info.server_name)); - NetworkRecv_string(&_udp_cs, p, item->info.server_revision, sizeof(item->info.server_revision)); - item->info.server_lang = NetworkRecv_uint8(&_udp_cs, p); - item->info.use_password = NetworkRecv_uint8(&_udp_cs, p); - item->info.clients_max = NetworkRecv_uint8(&_udp_cs, p); - item->info.clients_on = NetworkRecv_uint8(&_udp_cs, p); - item->info.spectators_on = NetworkRecv_uint8(&_udp_cs, p); - if (game_info_version < 3) { // 16 bits dates got scrapped and are read earlier - item->info.game_date = NetworkRecv_uint16(&_udp_cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR; - item->info.start_date = NetworkRecv_uint16(&_udp_cs, p) + DAYS_TILL_ORIGINAL_BASE_YEAR; - } - NetworkRecv_string(&_udp_cs, p, item->info.map_name, sizeof(item->info.map_name)); - item->info.map_width = NetworkRecv_uint16(&_udp_cs, p); - item->info.map_height = NetworkRecv_uint16(&_udp_cs, p); - item->info.map_set = NetworkRecv_uint8(&_udp_cs, p); - item->info.dedicated = NetworkRecv_uint8(&_udp_cs, p); - - if (item->info.server_lang >= NETWORK_NUM_LANGUAGES) item->info.server_lang = 0; - if (item->info.map_set >= NUM_LANDSCAPE ) item->info.map_set = 0; - - if (item->info.hostname[0] == '\0') - snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr)); - - /* Check if we are allowed on this server based on the revision-match */ - item->info.version_compatible = - strcmp(item->info.server_revision, _openttd_revision) == 0 || - strcmp(item->info.server_revision, NOREV_STRING) == 0; - item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs - break; - } - { /* Checks whether there needs to be a request for names of GRFs and makes * the request if necessary. GRFs that need to be requested are the GRFs @@ -251,6 +108,7 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE) struct sockaddr_in out_addr; for (c = item->info.grfconfig; c != NULL; c = c->next) { + if (HASBIT(c->flags, GCF_NOT_FOUND)) item->info.compatible = false; if (!HASBIT(c->flags, GCF_NOT_FOUND) || strcmp(c->name, UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue; in_request[in_request_count] = c; in_request_count++; @@ -274,6 +132,18 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE) } } + if (item->info.server_lang >= NETWORK_NUM_LANGUAGES) item->info.server_lang = 0; + if (item->info.map_set >= NUM_LANDSCAPE ) item->info.map_set = 0; + + if (item->info.hostname[0] == '\0') + snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr)); + + /* Check if we are allowed on this server based on the revision-match */ + item->info.version_compatible = + strcmp(item->info.server_revision, _openttd_revision) == 0 || + strcmp(item->info.server_revision, NOREV_STRING) == 0; + item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs + item->online = true; UpdateNetworkGameWindow(false); @@ -455,7 +325,7 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_GET_NEWGRFS) GRFConfig c; const GRFConfig *f; - NetworkRecv_GRFIdentifier(p, &c); + NetworkRecv_GRFIdentifier(&_udp_cs, p, &c); /* Find the matching GRF file */ f = FindGRFConfig(c.grfid, c.md5sum); @@ -510,7 +380,7 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_NEWGRFS) char name[NETWORK_GRF_NAME_LENGTH]; GRFConfig c; - NetworkRecv_GRFIdentifier(p, &c); + NetworkRecv_GRFIdentifier(&_udp_cs, p, &c); NetworkRecv_string(&_udp_cs, p, name, sizeof(name)); /* An empty name is not possible under normal circumstances @@ -550,7 +420,7 @@ static NetworkUDPPacket* const _network_udp_packet[] = { assert_compile(lengthof(_network_udp_packet) == PACKET_UDP_END); -static void NetworkHandleUDPPacket(Packet* p, struct sockaddr_in* client_addr) +void NetworkHandleUDPPacket(Packet *p, struct sockaddr_in *client_addr) { byte type; @@ -572,69 +442,6 @@ static void NetworkHandleUDPPacket(Packet* p, struct sockaddr_in* client_addr) } -// Send a packet over UDP -static void NetworkSendUDP_Packet(SOCKET udp, Packet* p, struct sockaddr_in* recv) -{ - int res; - - // Put the length in the buffer - p->buffer[0] = p->size & 0xFF; - p->buffer[1] = p->size >> 8; - - // Send the buffer - res = sendto(udp, p->buffer, p->size, 0, (struct sockaddr *)recv, sizeof(*recv)); - - // Check for any errors, but ignore it otherwise - if (res == -1) DEBUG(net, 1, "[udp] sendto failed with: %i", GET_LAST_ERROR()); -} - -// Start UDP listener -bool NetworkUDPListen(SOCKET *udp, uint32 host, uint16 port, bool broadcast) -{ - struct sockaddr_in sin; - - // Make sure socket is closed - closesocket(*udp); - - *udp = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - if (*udp == INVALID_SOCKET) { - DEBUG(net, 0, "[udp] failed to start UDP listener"); - return false; - } - - // set nonblocking mode for socket - { - unsigned long blocking = 1; -#ifndef BEOS_NET_SERVER - ioctlsocket(*udp, FIONBIO, &blocking); -#else - setsockopt(*udp, SOL_SOCKET, SO_NONBLOCK, &blocking, NULL); -#endif - } - - sin.sin_family = AF_INET; - // Listen on all IPs - sin.sin_addr.s_addr = host; - sin.sin_port = htons(port); - - if (bind(*udp, (struct sockaddr*)&sin, sizeof(sin)) != 0) { - DEBUG(net, 0, "[udp] bind failed on %s:%i", inet_ntoa(*(struct in_addr *)&host), port); - return false; - } - - if (broadcast) { - /* Enable broadcast */ - unsigned long val = 1; -#ifndef BEOS_NET_SERVER // will work around this, some day; maybe. - setsockopt(*udp, SOL_SOCKET, SO_BROADCAST, (char *) &val , sizeof(val)); -#endif - } - - DEBUG(net, 1, "[udp] listening on port %s:%d", inet_ntoa(*(struct in_addr *)&host), port); - - return true; -} - // Close UDP connection void NetworkUDPClose(void) { @@ -662,42 +469,6 @@ void NetworkUDPClose(void) } } -// Receive something on UDP level -void NetworkUDPReceive(SOCKET udp) -{ - struct sockaddr_in client_addr; - socklen_t client_len; - int nbytes; - static Packet *p = NULL; - int packet_len; - - // If p is NULL, malloc him.. this prevents unneeded mallocs - if (p == NULL) p = malloc(sizeof(*p)); - - packet_len = sizeof(p->buffer); - client_len = sizeof(client_addr); - - // Try to receive anything - nbytes = recvfrom(udp, p->buffer, packet_len, 0, (struct sockaddr *)&client_addr, &client_len); - - // We got some bytes.. just asume we receive the whole packet - if (nbytes > 0) { - // Get the size of the buffer - p->size = (uint16)p->buffer[0]; - p->size += (uint16)p->buffer[1] << 8; - // Put the position on the right place - p->pos = 2; - p->next = NULL; - - // Handle the packet - NetworkHandleUDPPacket(p, &client_addr); - - // Free the packet - free(p); - p = NULL; - } -} - // Broadcast to all ips static void NetworkUDPBroadCast(SOCKET udp) { diff --git a/network_udp.h b/network/network_udp.h similarity index 77% rename from network_udp.h rename to network/network_udp.h index b7814d3b23..4488d19d49 100644 --- a/network_udp.h +++ b/network/network_udp.h @@ -6,8 +6,6 @@ #ifdef ENABLE_NETWORK void NetworkUDPInitialize(void); -bool NetworkUDPListen(SOCKET *udp, uint32 host, uint16 port, bool broadcast); -void NetworkUDPReceive(SOCKET udp); void NetworkUDPSearchGame(void); void NetworkUDPQueryMasterServer(void); NetworkGameList *NetworkUDPQueryServer(const char* host, unsigned short port); diff --git a/network_data.c b/network_data.c deleted file mode 100644 index 62e95e2cd3..0000000000 --- a/network_data.c +++ /dev/null @@ -1,473 +0,0 @@ -/* $Id$ */ - -#ifdef ENABLE_NETWORK - -#include "stdafx.h" -#include "debug.h" -#include "network_data.h" -#include "functions.h" -#include "string.h" -#include "table/strings.h" -#include "network_client.h" -#include "command.h" -#include "callback_table.h" -#include "variables.h" - -// This files handles the send/receive of all packets - -// Create a packet for sending -Packet *NetworkSend_Init(PacketType type) -{ - Packet *packet = malloc(sizeof(Packet)); - // An error is inplace here, because it simply means we ran out of memory. - if (packet == NULL) error("Failed to allocate Packet"); - - // Skip the size so we can write that in before sending the packet - packet->size = sizeof(packet->size); - packet->buffer[packet->size++] = type; - packet->pos = 0; - - return packet; -} - -// The next couple of functions make sure we can send -// uint8, uint16, uint32 and uint64 endian-safe -// over the network. The order it uses is: -// -// 1 2 3 4 -// - -void NetworkSend_uint8(Packet *packet, uint8 data) -{ - assert(packet->size < sizeof(packet->buffer) - sizeof(data)); - packet->buffer[packet->size++] = data; -} - -void NetworkSend_uint16(Packet *packet, uint16 data) -{ - assert(packet->size < sizeof(packet->buffer) - sizeof(data)); - packet->buffer[packet->size++] = GB(data, 0, 8); - packet->buffer[packet->size++] = GB(data, 8, 8); -} - -void NetworkSend_uint32(Packet *packet, uint32 data) -{ - assert(packet->size < sizeof(packet->buffer) - sizeof(data)); - packet->buffer[packet->size++] = GB(data, 0, 8); - packet->buffer[packet->size++] = GB(data, 8, 8); - packet->buffer[packet->size++] = GB(data, 16, 8); - packet->buffer[packet->size++] = GB(data, 24, 8); -} - -void NetworkSend_uint64(Packet *packet, uint64 data) -{ - assert(packet->size < sizeof(packet->buffer) - sizeof(data)); - packet->buffer[packet->size++] = GB(data, 0, 8); - packet->buffer[packet->size++] = GB(data, 8, 8); - packet->buffer[packet->size++] = GB(data, 16, 8); - packet->buffer[packet->size++] = GB(data, 24, 8); - packet->buffer[packet->size++] = GB(data, 32, 8); - packet->buffer[packet->size++] = GB(data, 40, 8); - packet->buffer[packet->size++] = GB(data, 48, 8); - packet->buffer[packet->size++] = GB(data, 56, 8); -} - -// Sends a string over the network. It sends out -// the string + '\0'. No size-byte or something. -void NetworkSend_string(Packet *packet, const char* data) -{ - assert(data != NULL); - assert(packet->size < sizeof(packet->buffer) - strlen(data) - 1); - while ((packet->buffer[packet->size++] = *data++) != '\0') {} -} - -// If PacketSize changes of size, you have to change the 2 packet->size -// lines below matching the size of packet->size/PacketSize! -// (line 'packet->buffer[0] = packet->size & 0xFF;' and below) -assert_compile(sizeof(PacketSize) == 2); - -// This function puts the packet in the send-queue and it is send -// as soon as possible -// (that is: the next tick, or maybe one tick later if the -// OS-network-buffer is full) -void NetworkSend_Packet(Packet *packet, NetworkClientState *cs) -{ - Packet *p; - assert(packet != NULL); - - packet->pos = 0; - packet->next = NULL; - - packet->buffer[0] = GB(packet->size, 0, 8); - packet->buffer[1] = GB(packet->size, 8, 8); - - // Locate last packet buffered for the client - p = cs->packet_queue; - if (p == NULL) { - // No packets yet - cs->packet_queue = packet; - } else { - // Skip to the last packet - while (p->next != NULL) p = p->next; - p->next = packet; - } -} - -// Functions to help NetworkRecv_Packet/NetworkSend_Packet a bit -// A socket can make errors. When that happens -// this handles what to do. -// For clients: close connection and drop back to main-menu -// For servers: close connection and that is it -static NetworkRecvStatus CloseConnection(NetworkClientState *cs) -{ - NetworkCloseClient(cs); - - // Clients drop back to the main menu - if (!_network_server && _networking) { - _switch_mode = SM_MENU; - _networking = false; - _switch_mode_errorstr = STR_NETWORK_ERR_LOSTCONNECTION; - - return NETWORK_RECV_STATUS_CONN_LOST; - } - - return NETWORK_RECV_STATUS_OKAY; -} - -// Sends all the buffered packets out for this client -// it stops when: -// 1) all packets are send (queue is empty) -// 2) the OS reports back that it can not send any more -// data right now (full network-buffer, it happens ;)) -// 3) sending took too long -bool NetworkSend_Packets(NetworkClientState *cs) -{ - ssize_t res; - Packet *p; - - // We can not write to this socket!! - if (!cs->writable) return false; - if (cs->socket == INVALID_SOCKET) return false; - - p = cs->packet_queue; - while (p != NULL) { - res = send(cs->socket, p->buffer + p->pos, p->size - p->pos, 0); - if (res == -1) { - int err = GET_LAST_ERROR(); - if (err != EWOULDBLOCK) { // Something went wrong.. close client! - DEBUG(net, 0, "send failed with error %d", err); - CloseConnection(cs); - return false; - } - return true; - } - if (res == 0) { - // Client/server has left us :( - CloseConnection(cs); - return false; - } - - p->pos += res; - - // Is this packet sent? - if (p->pos == p->size) { - // Go to the next packet - cs->packet_queue = p->next; - free(p); - p = cs->packet_queue; - } else { - return true; - } - } - - return true; -} - - -// Receiving commands -// Again, the next couple of functions are endian-safe -// see the comment around NetworkSend_uint8 for more info. -uint8 NetworkRecv_uint8(NetworkClientState *cs, Packet *packet) -{ - /* Don't allow reading from a closed socket */ - if (cs->has_quit) return 0; - - /* Check if variable is within packet-size */ - if (packet->pos + 1 > packet->size) { - CloseConnection(cs); - return 0; - } - - return packet->buffer[packet->pos++]; -} - -uint16 NetworkRecv_uint16(NetworkClientState *cs, Packet *packet) -{ - uint16 n; - - /* Don't allow reading from a closed socket */ - if (cs->has_quit) return 0; - - /* Check if variable is within packet-size */ - if (packet->pos + 2 > packet->size) { - CloseConnection(cs); - return 0; - } - - n = (uint16)packet->buffer[packet->pos++]; - n += (uint16)packet->buffer[packet->pos++] << 8; - return n; -} - -uint32 NetworkRecv_uint32(NetworkClientState *cs, Packet *packet) -{ - uint32 n; - - /* Don't allow reading from a closed socket */ - if (cs->has_quit) return 0; - - /* Check if variable is within packet-size */ - if (packet->pos + 4 > packet->size) { - CloseConnection(cs); - return 0; - } - - n = (uint32)packet->buffer[packet->pos++]; - n += (uint32)packet->buffer[packet->pos++] << 8; - n += (uint32)packet->buffer[packet->pos++] << 16; - n += (uint32)packet->buffer[packet->pos++] << 24; - return n; -} - -uint64 NetworkRecv_uint64(NetworkClientState *cs, Packet *packet) -{ - uint64 n; - - /* Don't allow reading from a closed socket */ - if (cs->has_quit) return 0; - - /* Check if variable is within packet-size */ - if (packet->pos + 8 > packet->size) { - CloseConnection(cs); - return 0; - } - - n = (uint64)packet->buffer[packet->pos++]; - n += (uint64)packet->buffer[packet->pos++] << 8; - n += (uint64)packet->buffer[packet->pos++] << 16; - n += (uint64)packet->buffer[packet->pos++] << 24; - n += (uint64)packet->buffer[packet->pos++] << 32; - n += (uint64)packet->buffer[packet->pos++] << 40; - n += (uint64)packet->buffer[packet->pos++] << 48; - n += (uint64)packet->buffer[packet->pos++] << 56; - return n; -} - -// Reads a string till it finds a '\0' in the stream -void NetworkRecv_string(NetworkClientState *cs, Packet *p, char *buffer, size_t size) -{ - PacketSize pos; - char *bufp = buffer; - - /* Don't allow reading from a closed socket */ - if (cs->has_quit) return; - - pos = p->pos; - while (--size > 0 && pos < p->size && (*buffer++ = p->buffer[pos++]) != '\0') {} - - if (size == 0 || pos == p->size) { - *buffer = '\0'; - // If size was sooner to zero then the string in the stream - // skip till the \0, so the packet can be read out correctly for the rest - while (pos < p->size && p->buffer[pos] != '\0') pos++; - pos++; - } - p->pos = pos; - - str_validate(bufp); -} - -// If PacketSize changes of size, you have to change the 2 packet->size -// lines below matching the size of packet->size/PacketSize! -// (the line: 'p->size = (uint16)p->buffer[0];' and below) -assert_compile(sizeof(PacketSize) == 2); - -Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status) -{ - ssize_t res; - Packet *p; - - *status = NETWORK_RECV_STATUS_OKAY; - - if (cs->socket == INVALID_SOCKET) return NULL; - - if (cs->packet_recv == NULL) { - cs->packet_recv = malloc(sizeof(Packet)); - if (cs->packet_recv == NULL) error("Failed to allocate packet"); - // Set pos to zero! - cs->packet_recv->pos = 0; - cs->packet_recv->size = 0; // Can be ommited, just for safety reasons - } - - p = cs->packet_recv; - - // Read packet size - if (p->pos < sizeof(PacketSize)) { - while (p->pos < sizeof(PacketSize)) { - // Read the size of the packet - res = recv(cs->socket, p->buffer + p->pos, sizeof(PacketSize) - p->pos, 0); - if (res == -1) { - int err = GET_LAST_ERROR(); - if (err != EWOULDBLOCK) { - /* Something went wrong... (104 is connection reset by peer) */ - if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); - *status = CloseConnection(cs); - return NULL; - } - // Connection would block, so stop for now - return NULL; - } - if (res == 0) { - // Client/server has left - *status = CloseConnection(cs); - return NULL; - } - p->pos += res; - } - - p->size = (uint16)p->buffer[0]; - p->size += (uint16)p->buffer[1] << 8; - - if (p->size > SEND_MTU) { - *status = CloseConnection(cs); - return NULL; - } - } - - // Read rest of packet - while (p->pos < p->size) { - res = recv(cs->socket, p->buffer + p->pos, p->size - p->pos, 0); - if (res == -1) { - int err = GET_LAST_ERROR(); - if (err != EWOULDBLOCK) { - /* Something went wrong... (104 is connection reset by peer) */ - if (err != 104) DEBUG(net, 0, "recv failed with error %d", err); - *status = CloseConnection(cs); - return NULL; - } - // Connection would block - return NULL; - } - if (res == 0) { - // Client/server has left - *status = CloseConnection(cs); - return NULL; - } - - p->pos += res; - } - - // We have a complete packet, return it! - p->pos = 2; - p->next = NULL; // Should not be needed, but who knows... - - // Prepare for receiving a new packet - cs->packet_recv = NULL; - - return p; -} - -// Add a command to the local command queue -void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp) -{ - CommandPacket* new_cp = malloc(sizeof(*new_cp)); - - *new_cp = *cp; - - if (cs->command_queue == NULL) { - cs->command_queue = new_cp; - } else { - CommandPacket *c = cs->command_queue; - while (c->next != NULL) c = c->next; - c->next = new_cp; - } -} - -// Prepare a DoCommand to be send over the network -void NetworkSend_Command(TileIndex tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback) -{ - CommandPacket *c = malloc(sizeof(CommandPacket)); - byte temp_callback; - - c->player = _local_player; - c->next = NULL; - c->tile = tile; - c->p1 = p1; - c->p2 = p2; - c->cmd = cmd; - c->callback = 0; - - temp_callback = 0; - - while (temp_callback < _callback_table_count && _callback_table[temp_callback] != callback) - temp_callback++; - if (temp_callback == _callback_table_count) { - DEBUG(net, 0, "Unknown callback. (Pointer: %p) No callback sent", callback); - temp_callback = 0; /* _callback_table[0] == NULL */ - } - - if (_network_server) { - // We are the server, so set the command to be executed next possible frame - c->frame = _frame_counter_max + 1; - } else { - c->frame = 0; // The client can't tell which frame, so just make it 0 - } - - ttd_strlcpy(c->text, (_cmd_text != NULL) ? _cmd_text : "", lengthof(c->text)); - - if (_network_server) { - // If we are the server, we queue the command in our 'special' queue. - // In theory, we could execute the command right away, but then the - // client on the server can do everything 1 tick faster than others. - // So to keep the game fair, we delay the command with 1 tick - // which gives about the same speed as most clients. - NetworkClientState *cs; - - // And we queue it for delivery to the clients - FOR_ALL_CLIENTS(cs) { - if (cs->status > STATUS_AUTH) NetworkAddCommandQueue(cs, c); - } - - // Only the server gets the callback, because clients should not get them - c->callback = temp_callback; - if (_local_command_queue == NULL) { - _local_command_queue = c; - } else { - // Find last packet - CommandPacket *cp = _local_command_queue; - while (cp->next != NULL) cp = cp->next; - cp->next = c; - } - - return; - } - - // Clients send their command to the server and forget all about the packet - c->callback = temp_callback; - SEND_COMMAND(PACKET_CLIENT_COMMAND)(c); -} - -// Execute a DoCommand we received from the network -void NetworkExecuteCommand(CommandPacket *cp) -{ - _current_player = cp->player; - _cmd_text = cp->text; - /* cp->callback is unsigned. so we don't need to do lower bounds checking. */ - if (cp->callback > _callback_table_count) { - DEBUG(net, 0, "Received out-of-bounds callback (%d)", cp->callback); - cp->callback = 0; - } - DoCommandP(cp->tile, cp->p1, cp->p2, _callback_table[cp->callback], cp->cmd | CMD_NETWORK_COMMAND); -} - -#endif /* ENABLE_NETWORK */ diff --git a/newgrf_config.c b/newgrf_config.c index aa15ffb773..a6ab2fae5d 100644 --- a/newgrf_config.c +++ b/newgrf_config.c @@ -9,7 +9,7 @@ #include "string.h" #include "saveload.h" #include "md5.h" -#include "network_data.h" +#include "network/network_data.h" #include "newgrf.h" #include "newgrf_config.h" diff --git a/npf.c b/npf.c index eabce79625..97b9bf367a 100644 --- a/npf.c +++ b/npf.c @@ -14,7 +14,7 @@ #include "tile.h" #include "depot.h" #include "tunnel_map.h" -#include "network.h" +#include "network/network.h" #include "water_map.h" static AyStar _npf_aystar; diff --git a/oldloader.c b/oldloader.c index e0579eb60a..f6a56fdd6a 100644 --- a/oldloader.c +++ b/oldloader.c @@ -16,7 +16,7 @@ #include "signs.h" #include "debug.h" #include "depot.h" -#include "network.h" +#include "network/network.h" #include "ai/ai.h" #include "date.h" diff --git a/openttd.c b/openttd.c index 023d9588bf..3f15a944e4 100644 --- a/openttd.c +++ b/openttd.c @@ -41,7 +41,7 @@ #include "airport.h" #include "console.h" #include "screenshot.h" -#include "network.h" +#include "network/network.h" #include "signs.h" #include "depot.h" #include "waypoint.h" diff --git a/openttd.vcproj b/openttd.vcproj index c044a60eed..a2b99aa1fc 100644 --- a/openttd.vcproj +++ b/openttd.vcproj @@ -292,22 +292,31 @@ RelativePath=".\namegen.c"> + RelativePath=".\network\core\packet.c"> + RelativePath=".\network\core\tcp.c"> + RelativePath=".\network\core\udp.c"> + RelativePath=".\network\network.c"> + RelativePath=".\network\network_client.c"> + RelativePath=".\network\network_data.c"> + + + + + + @@ -542,22 +551,37 @@ RelativePath=".\music.h"> + RelativePath=".\network\core\config.h"> + RelativePath=".\network\core\game.h"> + RelativePath=".\network\core\os_abstraction.h"> + RelativePath=".\network\core\packet.h"> + RelativePath=".\network\core\tcp.h"> + RelativePath=".\network\core\udp.h"> + + + + + + + + + + diff --git a/openttd_vs80.vcproj b/openttd_vs80.vcproj index 77e91ecffe..11daa722ca 100644 --- a/openttd_vs80.vcproj +++ b/openttd_vs80.vcproj @@ -653,27 +653,39 @@ > + + + + + + + + + + + + + + + + @@ -1042,7 +1042,6 @@ static void UninitNoComp(void) //********** START OF MEMORY CODE (in ram)**** //******************************************** -#include "network.h" #include "table/strings.h" #include "table/sprites.h" #include "gfx.h" diff --git a/settings.c b/settings.c index af40febfad..b6d7fa895c 100644 --- a/settings.c +++ b/settings.c @@ -28,7 +28,7 @@ #include "sound.h" #include "string.h" #include "variables.h" -#include "network.h" +#include "network/network.h" #include "settings.h" #include "command.h" #include "console.h" diff --git a/settings_gui.c b/settings_gui.c index 1c1bdcb7da..f6806f4247 100644 --- a/settings_gui.c +++ b/settings_gui.c @@ -15,7 +15,7 @@ #include "engine.h" #include "screenshot.h" #include "newgrf.h" -#include "network.h" +#include "network/network.h" #include "town.h" #include "variables.h" #include "settings.h" diff --git a/town_gui.c b/town_gui.c index 10fef991be..f580cd3245 100644 --- a/town_gui.c +++ b/town_gui.c @@ -14,7 +14,7 @@ #include "gui.h" #include "command.h" #include "player.h" -#include "network.h" +#include "network/network.h" #include "variables.h" static const Widget _town_authority_widgets[] = { diff --git a/vehicle.c b/vehicle.c index b6239b4aa9..c2a2175f82 100644 --- a/vehicle.c +++ b/vehicle.c @@ -30,7 +30,7 @@ #include "industry_map.h" #include "station_map.h" #include "water_map.h" -#include "network.h" +#include "network/network.h" #include "yapf/yapf.h" #include "date.h" #include "newgrf_engine.h" diff --git a/video/cocoa_v.m b/video/cocoa_v.m index 0c4c6d9f1e..f93f86ca4b 100644 --- a/video/cocoa_v.m +++ b/video/cocoa_v.m @@ -54,7 +54,7 @@ extern void HideMenuBar(void); #include "../macros.h" #include "../sdl.h" #include "../window.h" -#include "../network.h" +#include "../network/network.h" #include "../variables.h" #include "../os/macosx/splash.h" diff --git a/video/dedicated_v.c b/video/dedicated_v.c index 824ca2936d..caa1c89639 100644 --- a/video/dedicated_v.c +++ b/video/dedicated_v.c @@ -8,7 +8,7 @@ #include "../debug.h" #include "../functions.h" #include "../gfx.h" -#include "../network.h" +#include "../network/network.h" #include "../window.h" #include "../console.h" #include "../variables.h" diff --git a/video/sdl_v.c b/video/sdl_v.c index d94819dedf..e88de85a57 100644 --- a/video/sdl_v.c +++ b/video/sdl_v.c @@ -11,7 +11,7 @@ #include "../macros.h" #include "../sdl.h" #include "../window.h" -#include "../network.h" +#include "../network/network.h" #include "../variables.h" #include "sdl_v.h" #include diff --git a/video/win32_v.c b/video/win32_v.c index e9fb1ca78e..7588653f04 100644 --- a/video/win32_v.c +++ b/video/win32_v.c @@ -5,7 +5,7 @@ #include "../functions.h" #include "../gfx.h" #include "../macros.h" -#include "../network.h" +#include "../network/network.h" #include "../variables.h" #include "../win32.h" #include "../window.h"