Changeset - r716:ae3edbaa50e7
[Not reviewed]
master
0 15 0
truelight - 19 years ago 2004-12-19 10:17:26
truelight@openttd.org
(svn r1168) -Cleanup: [Network] Cleaned the network code a bit. Added 'const'
and 'void' where needed, prefixed all functions, typedefs and global
vars with 'Network' and organized all externals nicely.
15 files changed with 118 insertions and 116 deletions:
0 comments (0 inline, 0 general)
console_cmds.c
Show inline comments
 
@@ -126,49 +126,49 @@ DEF_CONSOLE_CMD(ConResetTile)
 
	return 0;
 
}
 
#endif
 

	
 
DEF_CONSOLE_CMD(ConScrollToTile)
 
{
 
	if (argc == 2) {
 
		TileIndex tile = (TileIndex)GetArgumentInteger(argv[1]);
 
		ScrollMainWindowToTile(tile);
 
	}
 

	
 
	return 0;
 
}
 

	
 

	
 
// ********************************* //
 
// * Network Core Console Commands * //
 
// ********************************* //
 
#ifdef ENABLE_NETWORK
 

	
 
DEF_CONSOLE_CMD(ConStatus)
 
{
 
	const char *status;
 
	int lag;
 
	const ClientState *cs;
 
	const NetworkClientState *cs;
 
	const NetworkClientInfo *ci;
 
	FOR_ALL_CLIENTS(cs) {
 
		lag = NetworkCalculateLag(cs);
 
		ci = DEREF_CLIENT_INFO(cs);
 

	
 
		switch (cs->status) {
 
			case STATUS_INACTIVE:
 
				status = "inactive";
 
				break;
 
			case STATUS_AUTH:
 
				status = "authorized";
 
				break;
 
			case STATUS_MAP:
 
				status = "loading map";
 
				break;
 
			case STATUS_DONE_MAP:
 
				status = "done map";
 
				break;
 
			case STATUS_PRE_ACTIVE:
 
				status = "ready";
 
				break;
 
			case STATUS_ACTIVE:
 
				status = "active";
 
				break;
 
@@ -196,49 +196,49 @@ DEF_CONSOLE_CMD(ConKick)
 
		if (index == 0) {
 
			IConsoleError("Invalid Client-ID");
 
			return NULL;
 
		}
 

	
 
		ci = NetworkFindClientInfoFromIndex(index);
 

	
 
		if (ci != NULL) {
 
			SEND_COMMAND(PACKET_SERVER_ERROR)(NetworkFindClientStateFromIndex(index), NETWORK_ERROR_KICKED);
 
			return NULL;
 
		} else {
 
			IConsoleError("Client-ID not found");
 
			return NULL;
 
		}
 
	}
 

	
 
	IConsolePrint(_iconsole_color_default, "Unknown usage. Usage: kick <client-id>. For client-ids, see 'clients'.");
 

	
 
	return NULL;
 
}
 

	
 
DEF_CONSOLE_CMD(ConResetCompany)
 
{
 
	Player *p;
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
	NetworkClientInfo *ci;
 

	
 
	if (argc == 2) {
 
		uint32 index = atoi(argv[1]);
 

	
 
		/* Check valid range */
 
		if (index < 1 || index > MAX_PLAYERS) {
 
			IConsolePrintF(_iconsole_color_error, "Company does not exist. Company-ID must be between 1 and %d.", MAX_PLAYERS);
 
			return NULL;
 
		}
 

	
 
		/* Check if company does exist */
 
		index--;
 
		p = DEREF_PLAYER(index);
 
		if (!p->is_active) {
 
			IConsolePrintF(_iconsole_color_error, "Company does not exist.");
 
			return NULL;
 
		}
 

	
 
		if (p->is_ai) {
 
			IConsolePrintF(_iconsole_color_error, "Company is owned by an AI.");
 
			return NULL;
 
		}
 

	
economy.c
Show inline comments
 
@@ -381,49 +381,49 @@ static void PlayersCheckBankrupt(Player 
 
				p->bankrupt_timeout = 0;
 
				break;
 
			}
 
			// Else, falltrue to case 4...
 
		}
 
		case 4: {
 
			// Close everything the owner has open
 
			DeletePlayerWindows(owner);
 

	
 
//		Show bankrupt news
 
			SetDParam(0, p->name_1);
 
			SetDParam(1, p->name_2);
 
			AddNewsItem( (StringID)(owner + 16*3), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
 

	
 
			// If the player is human, and it is no network play, leave the player playing
 
			if (IS_HUMAN_PLAYER(owner) && !_networking) {
 
				p->bankrupt_asked = 255;
 
				p->bankrupt_timeout = 0x456;
 
			} else {
 
#ifdef ENABLE_NETWORK
 
				if (IS_HUMAN_PLAYER(owner) && _network_server) {
 
					// If we are the server, make sure it is clear that his player is no
 
					//  longer with us!
 
					NetworkClientInfo *ci;
 
					ClientState *cs;
 
					NetworkClientState *cs;
 
					/* Find all clients that were in control of this company */
 
					FOR_ALL_CLIENTS(cs) {
 
						ci = DEREF_CLIENT_INFO(cs);
 
						if ((ci->client_playas-1) == owner) {
 
							ci->client_playas = OWNER_SPECTATOR;
 
							// Send the new info to all the clients
 
							NetworkUpdateClientInfo(_network_own_client_index);
 
						}
 
					}
 
				}
 
				// Make sure the player no longer controls the company
 
				if (IS_HUMAN_PLAYER(owner) && owner == _local_player) {
 
					// Switch the player to spectator..
 
					_local_player = OWNER_SPECTATOR;
 
				}
 
#endif /* ENABLE_NETWORK */
 

	
 
				// Convert everything the player owns to NO_OWNER
 
				p->money64 = p->player_money = 100000000;
 
				ChangeOwnershipOfPlayerItems(owner, 0xFF); // 255 is no owner
 
				// Register the player as not-active
 
				p->is_active = false;
 
			}
 
		}
network.c
Show inline comments
 
@@ -14,75 +14,79 @@
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
#include "table/strings.h"
 
#include "network_client.h"
 
#include "network_server.h"
 
#include "network_udp.h"
 
#include "network_gamelist.h"
 
#include "console.h" /* IConsoleCmdExec */
 
#include <stdarg.h> /* va_list */
 
#include "md5.h"
 

	
 
// The listen socket for the server
 
static SOCKET _listensocket;
 

	
 
// Network copy of patches, so the patches of a client are not fucked up
 
//  after he joined a server
 
static Patches network_tmp_patches;
 

	
 
// The amount of clients connected
 
static byte _network_clients_connected = 0;
 
// The index counter for new clients (is never decreased)
 
static uint16 _network_client_index = NETWORK_SERVER_INDEX + 1;
 

	
 
/* Some externs / forwards */
 
extern void ShowJoinStatusWindow();
 
extern void StateGameLoop();
 

	
 
// Function that looks up the CI for a given client-index
 
NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index)
 
{
 
	NetworkClientInfo *ci;
 

	
 
	for (ci = _network_client_info; ci != &_network_client_info[MAX_CLIENT_INFO]; ci++)
 
		if (ci->client_index == client_index)
 
			return ci;
 

	
 
	return NULL;
 
}
 

	
 
// Function that looks up the CS for a given client-index
 
ClientState *NetworkFindClientStateFromIndex(uint16 client_index)
 
NetworkClientState *NetworkFindClientStateFromIndex(uint16 client_index)
 
{
 
	ClientState *cs;
 
	NetworkClientState *cs;
 

	
 
	for (cs = _clients; cs != &_clients[MAX_CLIENT_INFO]; cs++)
 
		if (cs->index == client_index)
 
			return cs;
 

	
 
	return NULL;
 
}
 

	
 
// NetworkGetClientName is a server-safe function to get the name of the client
 
//  if the user did not send it yet, Client #<no> is used.
 
void NetworkGetClientName(char *client_name, size_t size, ClientState *cs)
 
void NetworkGetClientName(char *client_name, size_t size, const NetworkClientState *cs)
 
{
 
	NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
 
	if (ci->client_name[0] == '\0')
 
		snprintf(client_name, size, "Client #%d", cs->index);
 
	else
 
		snprintf(client_name, size, "%s", ci->client_name);
 
}
 

	
 
// This puts a text-message to the console, or in the future, the chat-box,
 
//  (to keep it all a bit more general)
 
void CDECL NetworkTextMessage(NetworkAction action, uint16 color, const char *name, const char *str, ...)
 
{
 
	char buf[1024];
 
	va_list va;
 
	const int duration = 10; // Game days the messages stay visible
 

	
 
	va_start(va, str);
 
	vsprintf(buf, str, va);
 
	va_end(va);
 

	
 
	switch (action) {
 
		case NETWORK_ACTION_JOIN_LEAVE:
 
			IConsolePrintF(color, "*** %s %s", name, buf);
 
			AddTextMessage(color, duration, "*** %s %s", name, buf);
 
@@ -98,114 +102,114 @@ void CDECL NetworkTextMessage(NetworkAct
 
		case NETWORK_ACTION_CHAT_CLIENT:
 
			IConsolePrintF(color, "[Private] %s: %s", name, buf);
 
			AddTextMessage(color, duration, "[Private] %s: %s", name, buf);
 
			break;
 
		case NETWORK_ACTION_CHAT_TO_CLIENT:
 
			IConsolePrintF(color, "[Private] To %s: %s", name, buf);
 
			AddTextMessage(color, duration, "[Private] To %s: %s", name, buf);
 
			break;
 
		case NETWORK_ACTION_CHAT_TO_PLAYER:
 
			IConsolePrintF(color, "[Team] To %s: %s", name, buf);
 
			AddTextMessage(color, duration, "[Team] To %s: %s", name, buf);
 
			break;
 
		case NETWORK_ACTION_NAME_CHANGE:
 
			IConsolePrintF(color, "*** %s changed his name to %s", name, buf);
 
			AddTextMessage(color, duration, "*** %s changed his name to %s", name, buf);
 
			break;
 
		default:
 
			IConsolePrintF(color, "[All] %s: %s", name, buf);
 
			AddTextMessage(color, duration, "[All] %s: %s", name, buf);
 
			break;
 
	}
 
}
 

	
 
// Calculate the frame-lag of a client
 
uint NetworkCalculateLag(const ClientState *cs)
 
uint NetworkCalculateLag(const NetworkClientState *cs)
 
{
 
	int lag = cs->last_frame_server - cs->last_frame;
 
	// This client has missed his ACK packet after 1 DAY_TICKS..
 
	//  so we increase his lag for every frame that passes!
 
	// The packet can be out by a max of _net_frame_freq
 
	if (cs->last_frame_server + DAY_TICKS + _network_frame_freq < _frame_counter)
 
		lag += _frame_counter - (cs->last_frame_server + DAY_TICKS + _network_frame_freq);
 

	
 
	return lag;
 
}
 

	
 

	
 
// There was a non-recoverable error, drop back to the main menu with a nice
 
//  error
 
void NetworkError(StringID error_string)
 
{
 
	_switch_mode = SM_MENU;
 
	_switch_mode_errorstr = error_string;
 
}
 

	
 
void ClientStartError(char *error) {
 
	DEBUG(net, 0)("[NET] Client could not start network: %s",error);
 
	NetworkError(STR_NETWORK_ERR_CLIENT_START);
 
}
 

	
 
void ServerStartError(char *error) {
 
	DEBUG(net, 0)("[NET] Server could not start network: %s",error);
 
	NetworkError(STR_NETWORK_ERR_SERVER_START);
 
}
 

	
 
void NetworkClientError(byte res, ClientState *cs) {
 
static void NetworkClientError(byte res, NetworkClientState *cs) {
 
	// First, send a CLIENT_ERROR to the server, so he knows we are
 
	//  disconnection (and why!)
 
	NetworkErrorCode errorno;
 

	
 
	// We just want to close the connection..
 
	if (res == NETWORK_RECV_STATUS_CLOSE_QUERY) {
 
		cs->quited = true;
 
		CloseClient(cs);
 
		NetworkCloseClient(cs);
 
		_networking = false;
 

	
 
		DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
 
		return;
 
	}
 

	
 
	switch(res) {
 
		case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break;
 
		case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break;
 
		default: errorno = NETWORK_ERROR_GENERAL;
 
	}
 
	// This means we fucked up and the server closed the connection
 
	if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL) {
 
		SEND_COMMAND(PACKET_CLIENT_ERROR)(errorno);
 

	
 
		// Dequeue all commands before closing the socket
 
		NetworkSend_Packets(DEREF_CLIENT(0));
 
	}
 

	
 
	_switch_mode = SM_MENU;
 
	CloseClient(cs);
 
	NetworkCloseClient(cs);
 
	_networking = false;
 
}
 

	
 
// Find all IP-aliases for this host
 
void NetworkFindIPs(void)
 
static void NetworkFindIPs(void)
 
{
 
	int i, last;
 

	
 
#if defined(BEOS_NET_SERVER) /* doesn't have neither getifaddrs or net/if.h */
 
	/* Based on Andrew Bachmann's netstat+.c. Big thanks to him! */
 
	int _netstat(int fd, char **output, int verbose);
 

	
 
	int seek_past_header(char **pos, const char *header) {
 
		char *new_pos = strstr(*pos, header);
 
		if (new_pos == 0) {
 
			return B_ERROR;
 
		}
 
		*pos += strlen(header) + new_pos - *pos + 1;
 
		return B_OK;
 
	}
 

	
 
	int output_length;
 
	char *output_pointer = NULL;
 
	char **output;
 
	int sock = socket(AF_INET, SOCK_DGRAM, 0);
 
	i = 0;
 

	
 
	// If something fails, make sure the list is empty
 
	_network_ip_list[0] = 0;
 
@@ -367,103 +371,103 @@ unsigned long NetworkResolveHost(const c
 
}
 

	
 
// Converts a string to ip/port/player
 
//  Format: IP#player:port
 
//
 
// connection_string will be re-terminated to seperate out the hostname, and player and port will
 
// be set to the player and port strings given by the user, inside the memory area originally
 
// occupied by connection_string.
 
void ParseConnectionString(const byte **player, const byte **port, byte *connection_string)
 
{
 
	byte *p;
 
	for (p = connection_string; *p != '\0'; p++) {
 
		if (*p == '#') {
 
			*player = p + 1;
 
			*p = '\0';
 
		} else if (*p == ':') {
 
			*port = p + 1;
 
			*p = '\0';
 
		}
 
	}
 
}
 

	
 
// Creates a new client from a socket
 
//   Used both by the server and the client
 
static ClientState *AllocClient(SOCKET s)
 
static NetworkClientState *NetworkAllocClient(SOCKET s)
 
{
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
	NetworkClientInfo *ci;
 
	byte client_no;
 

	
 
	client_no = 0;
 

	
 
	if (_network_server) {
 
		// Can we handle a new client?
 
		if (_network_clients_connected >= MAX_CLIENTS)
 
			return NULL;
 

	
 
		if (_network_game_info.clients_on >= _network_game_info.clients_max)
 
			return NULL;
 

	
 
		// Register the login
 
		client_no = _network_clients_connected++;
 
	}
 

	
 
	cs = &_clients[client_no];
 
	memset(cs, 0, sizeof(*cs));
 
	cs->socket = s;
 
	cs->last_frame = 0;
 
	cs->quited = false;
 

	
 
	if (_network_server) {
 
		ci = DEREF_CLIENT_INFO(cs);
 
		memset(ci, 0, sizeof(*ci));
 

	
 
		cs->index = _network_client_index++;
 
		ci->client_index = cs->index;
 
		ci->join_date = _date;
 

	
 
		InvalidateWindow(WC_CLIENT_LIST, 0);
 
	}
 

	
 
	return cs;
 
}
 

	
 
// Close a connection
 
void CloseClient(ClientState *cs)
 
void NetworkCloseClient(NetworkClientState *cs)
 
{
 
	NetworkClientInfo *ci;
 
	// Socket is already dead
 
	if (cs->socket == INVALID_SOCKET) return;
 

	
 
	DEBUG(net, 1) ("[NET] Closed client connection");
 

	
 
	if (!cs->quited && _network_server && cs->status > STATUS_INACTIVE) {
 
		// We did not receive a leave message from this client...
 
		NetworkErrorCode errorno = NETWORK_ERROR_CONNECTION_LOST;
 
		char str1[100], str2[100];
 
		char client_name[NETWORK_NAME_LENGTH];
 
		ClientState *new_cs;
 
		NetworkClientState *new_cs;
 

	
 
		NetworkGetClientName(client_name, sizeof(client_name), cs);
 

	
 
		GetString(str1, STR_NETWORK_ERR_LEFT);
 
		GetString(str2, STR_NETWORK_ERR_CLIENT_GENERAL + errorno);
 

	
 
		NetworkTextMessage(NETWORK_ACTION_JOIN_LEAVE, 1, client_name, "%s (%s)", str1, str2);
 

	
 
		// Inform other clients of this... strange leaving ;)
 
		FOR_ALL_CLIENTS(new_cs) {
 
			if (new_cs->status > STATUS_AUTH && cs != new_cs) {
 
				SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
 
			}
 
		}
 
	}
 

	
 
	closesocket(cs->socket);
 
	cs->writable = false;
 

	
 
	// Free all pending and partially received packets
 
	while (cs->packet_queue != NULL) {
 
		Packet *p = cs->packet_queue->next;
 
		free(cs->packet_queue);
 
		cs->packet_queue = p;
 
@@ -482,172 +486,170 @@ void CloseClient(ClientState *cs)
 

	
 
	if (_network_server) {
 
		// We just lost one client :(
 
		if (cs->status > STATUS_INACTIVE)
 
			_network_game_info.clients_on--;
 
		_network_clients_connected--;
 

	
 
		while ((cs + 1) != DEREF_CLIENT(MAX_CLIENTS) && (cs + 1)->socket != INVALID_SOCKET) {
 
			*cs = *(cs + 1);
 
			*ci = *(ci + 1);
 
			cs++;
 
			ci++;
 
		}
 

	
 
		InvalidateWindow(WC_CLIENT_LIST, 0);
 
	}
 

	
 
	// Reset the status of the last socket
 
	cs->socket = INVALID_SOCKET;
 
	cs->status = STATUS_INACTIVE;
 
	cs->index = NETWORK_EMPTY_INDEX;
 
	ci->client_index = NETWORK_EMPTY_INDEX;
 
}
 

	
 
extern void ShowJoinStatusWindow();
 

	
 
// A client wants to connect to a server
 
bool NetworkConnect(const char *hostname, int port)
 
static bool NetworkConnect(const char *hostname, int port)
 
{
 
	SOCKET s;
 
	struct sockaddr_in sin;
 

	
 
	DEBUG(net, 1) ("[NET] Connecting to %s %d", hostname, port);
 

	
 
	s = socket(AF_INET, SOCK_STREAM, 0);
 
	if (s == INVALID_SOCKET) {
 
		ClientStartError("socket() failed");
 
		return false;
 
	}
 

	
 
	{ // set nodelay /* 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!!
 
		if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b)) != 0)
 
			DEBUG(net, 1)("[NET] Setting TCP_NODELAY failed");
 
		#endif
 
	}
 

	
 
	sin.sin_family = AF_INET;
 
	sin.sin_addr.s_addr = NetworkResolveHost(hostname);
 
	sin.sin_port = htons(port);
 
	_network_last_host_ip = sin.sin_addr.s_addr;
 

	
 
	if (connect(s, (struct sockaddr*) &sin, sizeof(sin)) != 0) {
 
		// We failed to connect for which reason what so ever
 
		return false;
 
	}
 

	
 
	{ // set nonblocking mode for socket..
 
		unsigned long blocking = 1;
 
		#if defined(__BEOS__) && defined(BEOS_NET_SERVER)
 
		byte nonblocking = 1;
 
		if (setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &nonblocking, sizeof(blocking)) != 0)
 
		#else
 
		if (ioctlsocket(s, FIONBIO, &blocking) != 0)
 
		#endif
 
			DEBUG(net, 0)("[NET] Setting non-blocking failed"); /* XXX should this be an error? */
 
	}
 

	
 
	// in client mode, only the first client field is used. it's pointing to the server.
 
	AllocClient(s);
 
	NetworkAllocClient(s);
 

	
 
	ShowJoinStatusWindow();
 

	
 
	memcpy(&network_tmp_patches, &_patches, sizeof(_patches));
 

	
 
	return true;
 
}
 

	
 
// For the server, to accept new clients
 
static void NetworkAcceptClients(void)
 
{
 
	struct sockaddr_in sin;
 
	SOCKET s;
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
#ifndef __MORPHOS__
 
	int sin_len;
 
#else
 
	LONG sin_len; // for some reason we need a 'LONG' under MorphOS
 
#endif
 

	
 
	// Should never ever happen.. is it possible??
 
	assert(_listensocket != INVALID_SOCKET);
 

	
 
	for (;;) {
 
		sin_len = sizeof(sin);
 
		s = accept(_listensocket, (struct sockaddr*)&sin, &sin_len);
 
		if (s == INVALID_SOCKET) return;
 

	
 
		// set nonblocking mode for client socket
 
		#if defined(__BEOS__) && defined(BEOS_NET_SERVER)
 
		{ unsigned long blocking = 1; byte nonblocking = 1; setsockopt(s, SOL_SOCKET, SO_NONBLOCK, &nonblocking, sizeof(blocking)); }
 
		#else
 
		{ unsigned long blocking = 1; ioctlsocket(s, FIONBIO, &blocking); }
 
		#endif
 

	
 
		DEBUG(net, 1) ("[NET] Client connected from %s on frame %d", inet_ntoa(sin.sin_addr), _frame_counter);
 

	
 
		// set nodelay
 
		#if !defined(BEOS_NET_SERVER) // not implemented on BeOS net_server...
 
		// The (const char*) cast is needed for windows!!
 
		{int b = 1; setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char*)&b, sizeof(b));}
 
		#endif
 

	
 
		cs = AllocClient(s);
 
		cs = NetworkAllocClient(s);
 
		if (cs == NULL) {
 
			// no more clients allowed?
 
			// Send to the client that we are full!
 
			Packet *p = NetworkSend_Init(PACKET_SERVER_FULL);
 

	
 
			p->buffer[0] = p->size & 0xFF;
 
			p->buffer[1] = p->size >> 8;
 

	
 
			send(s, p->buffer, p->size, 0);
 
			closesocket(s);
 

	
 
			free(p);
 

	
 
			continue;
 
		}
 

	
 
		// a new client has connected. We set him at inactive for now
 
		//  maybe he is only requesting server-info. Till he has sent a PACKET_CLIENT_MAP_OK
 
		//  the client stays inactive
 
		cs->status = STATUS_INACTIVE;
 

	
 
		{
 
			// Save the IP of the client
 
			NetworkClientInfo *ci;
 
			ci = DEREF_CLIENT_INFO(cs);
 
			ci->client_ip = sin.sin_addr.s_addr;
 
		}
 
	}
 
}
 

	
 
// Set up the listen socket for the server
 
bool NetworkListen(void)
 
static bool NetworkListen(void)
 
{
 
	SOCKET ls;
 
	struct sockaddr_in sin;
 
	int port;
 

	
 
	port = _network_server_port;
 

	
 
	DEBUG(net, 1) ("[NET] Listening on %s:%d", _network_server_bind_ip_host, port);
 

	
 
	ls = socket(AF_INET, SOCK_STREAM, 0);
 
	if (ls == INVALID_SOCKET) {
 
		ServerStartError("socket() on listen socket failed");
 
		return false;
 
	}
 

	
 
	{ // reuse the socket
 
		int reuse = 1;
 
		// The (const char*) cast is needed for windows!!
 
		if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) == -1) {
 
			ServerStartError("setsockopt() on listen socket failed");
 
			return false;
 
		}
 
	}
 

	
 
@@ -661,190 +663,193 @@ bool NetworkListen(void)
 
		#endif
 
			DEBUG(net, 0)("[NET] Setting non-blocking failed"); /* XXX should this be an error? */
 
	}
 

	
 
	sin.sin_family = AF_INET;
 
	sin.sin_addr.s_addr = _network_server_bind_ip;
 
	sin.sin_port = htons(port);
 

	
 
	if (bind(ls, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
 
		ServerStartError("bind() failed");
 
		return false;
 
	}
 

	
 
	if (listen(ls, 1) != 0) {
 
		ServerStartError("listen() failed");
 
		return false;
 
	}
 

	
 
	_listensocket = ls;
 

	
 
	return true;
 
}
 

	
 
// Close all current connections
 
void NetworkClose(void)
 
static void NetworkClose(void)
 
{
 
	ClientState *cs;
 
	NetworkClientState *cs;
 

	
 
	FOR_ALL_CLIENTS(cs) {
 
		if (!_network_server) {
 
			SEND_COMMAND(PACKET_CLIENT_QUIT)("leaving");
 
			NetworkSend_Packets(cs);
 
		}
 
		CloseClient(cs);
 
		NetworkCloseClient(cs);
 
	}
 

	
 
	if (_network_server) {
 
		// We are a server, also close the listensocket
 
		closesocket(_listensocket);
 
		_listensocket = INVALID_SOCKET;
 
		DEBUG(net, 1) ("[NET] Closed listener");
 
		NetworkUDPClose();
 
	}
 
}
 

	
 
// Inits the network (cleans sockets and stuff)
 
void NetworkInitialize(void)
 
static void NetworkInitialize(void)
 
{
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
	uint i;
 

	
 
	_local_command_queue = NULL;
 

	
 
	// Clean all client-sockets
 
	memset(_clients, 0, sizeof(_clients));
 
	for (cs = _clients; cs != &_clients[MAX_CLIENTS]; cs++) {
 
		cs->socket = INVALID_SOCKET;
 
		cs->status = STATUS_INACTIVE;
 
		cs->command_queue = NULL;
 
	}
 

	
 
	// Clean the client_info memory
 
	memset(_network_client_info, 0, sizeof(_network_client_info));
 
	memset(_network_player_info, 0, sizeof(_network_player_info));
 

	
 
	_sync_frame = 0;
 
	_network_first_time = true;
 

	
 
	_network_reconnect = 0;
 

	
 
	InitPlayerRandoms();
 

	
 
	NetworkUDPInitialize();
 

	
 
	// add all servers from the config file to our list
 
	for (i=0; i != lengthof(_network_server_list); i++) {
 
		if (_network_server_list[i] == NULL) break;
 
		AddServer(_network_server_list[i]);
 
		NetworkAddServer(_network_server_list[i]);
 
	}
 
}
 

	
 
// Query a server to fetch his game-info
 
//  If game_info is true, only the gameinfo is fetched,
 
//   else only the client_info is fetched
 
void NetworkQueryServer(const byte* host, unsigned short port, bool game_info)
 
{
 
	if (!_network_available) return;
 

	
 
	NetworkDisconnect();
 

	
 
	if (game_info) {
 
		NetworkUDPQueryServer(host, port);
 
		return;
 
	}
 

	
 
	NetworkInitialize();
 

	
 
	_network_server = false;
 

	
 
	// Try to connect
 
	_networking = NetworkConnect(host, port);
 

	
 
//	ttd_strlcpy(_network_last_host, host, sizeof(_network_last_host));
 
//	_network_last_port = port;
 

	
 
	// We are connected
 
	if (_networking) {
 
		SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)();
 
		return;
 
	}
 

	
 
	// No networking, close everything down again
 
	NetworkDisconnect();
 
}
 

	
 
// validates an address entered as a string and adds the server to
 
// the list
 
void AddServer(byte *b)
 
void NetworkAddServer(const byte *b)
 
{
 
	if (*b != '\0') {
 
		const byte *port = NULL;
 
		const byte *player = NULL;
 
		byte host[NETWORK_HOSTNAME_LENGTH];
 
		uint16 rport;
 

	
 
		ttd_strlcpy(host, b, lengthof(host));
 

	
 
		ttd_strlcpy(_network_default_ip, b, lengthof(_network_default_ip));
 
		rport = NETWORK_DEFAULT_PORT;
 

	
 
		ParseConnectionString(&player, &port, b);
 
		ParseConnectionString(&player, &port, host);
 

	
 
		if (player != NULL) _network_playas = atoi(player);
 
		if (port != NULL) rport = atoi(port);
 

	
 
		NetworkQueryServer(b, rport, true);
 
		NetworkQueryServer(host, rport, true);
 
	}
 
}
 

	
 
// Used by clients, to connect to a server
 
bool NetworkClientConnectGame(const byte* host, unsigned short port)
 
{
 
	if (!_network_available) return false;
 

	
 
	if (port == 0) return false;
 

	
 
	ttd_strlcpy(_network_last_host, host, sizeof(_network_last_host));
 
	_network_last_port = port;
 

	
 
	NetworkDisconnect();
 
	NetworkUDPClose();
 
	NetworkInitialize();
 

	
 
	// Try to connect
 
	_networking = NetworkConnect(host, port);
 

	
 
	// We are connected
 
	if (_networking) {
 
		IConsoleCmdExec("exec scripts/on_client.scr 0");
 
		NetworkClient_Connected();
 
	} else {
 
		// Connecting failed
 
		NetworkError(STR_NETWORK_ERR_NOCONNECTION);
 
	}
 

	
 
	return _networking;
 
}
 

	
 
void NetworkInitGameInfo(void)
 
static void NetworkInitGameInfo(void)
 
{
 
	NetworkClientInfo *ci;
 

	
 
	ttd_strlcpy(_network_game_info.server_name, _network_server_name, sizeof(_network_game_info.server_name));
 
	if (_network_game_info.server_name[0] == '\0')
 
		snprintf(_network_game_info.server_name, sizeof(_network_game_info.server_name), "Unnamed Server");
 

	
 
	// The server is a client too ;)
 
	if (_network_dedicated) {
 
		_network_game_info.clients_on = 0;
 
		_network_game_info.dedicated = true;
 
	} else {
 
		_network_game_info.clients_on = 1;
 
		_network_game_info.dedicated = false;
 
	}
 
	ttd_strlcpy(_network_game_info.server_revision, _openttd_revision, sizeof(_network_game_info.server_revision));
 
	_network_game_info.spectators_on = 0;
 
	_network_game_info.game_date = _date;
 
	_network_game_info.start_date = ConvertIntDate(_patches.starting_date);
 
	_network_game_info.map_width = TILES_X;
 
	_network_game_info.map_height = TILES_Y;
 
	_network_game_info.map_set = _opt.landscape;
 

	
 
	if (_network_game_info.server_password[0] == '\0') {
 
@@ -892,102 +897,102 @@ bool NetworkServerStart(void)
 

	
 
	if (!_network_dedicated)
 
		_network_playas = 1;
 

	
 
	_network_clients_connected = 0;
 

	
 
	NetworkInitGameInfo();
 

	
 
	// execute server initialization script
 
	IConsoleCmdExec("exec scripts/on_server.scr 0");
 
	// if the server is dedicated ... add some other script
 
	if (_network_dedicated) IConsoleCmdExec("exec scripts/on_dedicated.scr 0");
 

	
 
	/* Try to register us to the master server */
 
	_network_last_advertise_date = 0;
 
	NetworkUDPAdvertise();
 
	return true;
 
}
 

	
 
// The server is rebooting...
 
// The only difference with NetworkDisconnect, is the packets that is sent
 
void NetworkReboot(void)
 
{
 
	if (_network_server) {
 
		ClientState *cs;
 
		NetworkClientState *cs;
 
		FOR_ALL_CLIENTS(cs) {
 
			SEND_COMMAND(PACKET_SERVER_NEWGAME)(cs);
 
			NetworkSend_Packets(cs);
 
		}
 
	}
 

	
 
	NetworkClose();
 

	
 
	// Free all queued commands
 
	while (_local_command_queue != NULL) {
 
		CommandPacket *p = _local_command_queue;
 
		_local_command_queue = _local_command_queue->next;
 
		free(p);
 
	}
 

	
 
	_networking = false;
 
	_network_server = false;
 
}
 

	
 
// We want to disconnect from the host/clients
 
void NetworkDisconnect(void)
 
{
 
	if (_network_server) {
 
		ClientState *cs;
 
		NetworkClientState *cs;
 
		FOR_ALL_CLIENTS(cs) {
 
			SEND_COMMAND(PACKET_SERVER_SHUTDOWN)(cs);
 
			NetworkSend_Packets(cs);
 
		}
 
	}
 

	
 
	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
	NetworkClose();
 

	
 
	// Free all queued commands
 
	while (_local_command_queue != NULL) {
 
		CommandPacket *p = _local_command_queue;
 
		_local_command_queue = _local_command_queue->next;
 
		free(p);
 
	}
 

	
 
	if (_networking && !_network_server) {
 
		memcpy(&_patches, &network_tmp_patches, sizeof(_patches));
 
	}
 

	
 
	_networking = false;
 
	_network_server = false;
 
}
 

	
 
// Receives something from the network
 
bool NetworkReceive(void)
 
static bool NetworkReceive(void)
 
{
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
	int n;
 
	fd_set read_fd, write_fd;
 
	struct timeval tv;
 

	
 
	FD_ZERO(&read_fd);
 
	FD_ZERO(&write_fd);
 

	
 
	FOR_ALL_CLIENTS(cs) {
 
		FD_SET(cs->socket, &read_fd);
 
		FD_SET(cs->socket, &write_fd);
 
	}
 

	
 
	// take care of listener port
 
	if (_network_server) {
 
		FD_SET(_listensocket, &read_fd);
 
	}
 

	
 
	tv.tv_sec = tv.tv_usec = 0; // don't block at all.
 
#if !defined(__MORPHOS__) && !defined(__AMIGA__)
 
	n = select(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv);
 
#else
 
	n = WaitSelect(FD_SETSIZE, &read_fd, &write_fd, NULL, &tv, NULL);
 
#endif
 
	if (n == -1 && !_network_server) NetworkError(STR_NETWORK_ERR_LOSTCONNECTION);
 
@@ -1001,101 +1006,98 @@ bool NetworkReceive(void)
 
		cs->writable = !!FD_ISSET(cs->socket, &write_fd);
 
		if (FD_ISSET(cs->socket, &read_fd)) {
 
			if (_network_server)
 
				NetworkServer_ReadPackets(cs);
 
			else {
 
				byte res;
 
				// The client already was quiting!
 
				if (cs->quited) return false;
 
				if ((res = NetworkClient_ReadPackets(cs)) != NETWORK_RECV_STATUS_OKAY) {
 
					// The client made an error of which we can not recover
 
					//   close the client and drop back to main menu
 

	
 
					NetworkClientError(res, cs);
 
					return false;
 
				}
 
			}
 
		}
 
	}
 
	return true;
 
}
 

	
 
// This sends all buffered commands (if possible)
 
static void NetworkSend(void)
 
{
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
	FOR_ALL_CLIENTS(cs) {
 
		if (cs->writable) {
 
			NetworkSend_Packets(cs);
 

	
 
			if (cs->status == STATUS_MAP) {
 
				// This client is in the middle of a map-send, call the function for that
 
				SEND_COMMAND(PACKET_SERVER_MAP)(cs);
 
			}
 
		}
 
	}
 
}
 

	
 
// Handle the local-command-queue
 
void NetworkHandleLocalQueue(void)
 
static void NetworkHandleLocalQueue(void)
 
{
 
	if (_local_command_queue != NULL) {
 
		CommandPacket *cp;
 
		CommandPacket *cp_prev;
 

	
 
		cp = _local_command_queue;
 
		cp_prev = NULL;
 

	
 
		while (cp != NULL) {
 
			if (_frame_counter > cp->frame) {
 
				// We can execute this command
 
				NetworkExecuteCommand(cp);
 

	
 
				if (cp_prev != NULL) {
 
					cp_prev->next = cp->next;
 
					free(cp);
 
					cp = cp_prev->next;
 
				} else {
 
					// This means we are at our first packet
 
					_local_command_queue = cp->next;
 
					free(cp);
 
					cp = _local_command_queue;
 
				}
 

	
 
			} else {
 
				// Command is in the future, skip to next
 
				//  (commands don't have to be in order in the queue!!)
 
				cp_prev = cp;
 
				cp = cp->next;
 
			}
 
		}
 
	}
 
}
 

	
 

	
 
extern void StateGameLoop();
 

	
 
bool NetworkDoClientLoop(void)
 
static bool NetworkDoClientLoop(void)
 
{
 
	_frame_counter++;
 

	
 
	NetworkHandleLocalQueue();
 

	
 
	StateGameLoop();
 

	
 
	// Check if we are in sync!
 
	if (_sync_frame != 0) {
 
		if (_sync_frame == _frame_counter) {
 
#ifdef NETWORK_SEND_DOUBLE_SEED
 
			if (_sync_seed_1 != _random_seeds[0][0] || _sync_seed_2 != _random_seeds[0][1]) {
 
#else
 
			if (_sync_seed_1 != _random_seeds[0][0]) {
 
#endif
 
				NetworkError(STR_NETWORK_ERR_DESYNC);
 
				DEBUG(net, 0)("[NET] Sync error detected!");
 
				NetworkClientError(NETWORK_RECV_STATUS_DESYNC, DEREF_CLIENT(0));
 
				return false;
 
			}
 

	
 
			// If this is the first time we have a sync-frame, we
 
			//   need to let the server know that we are ready and at the same
 
			//   frame as he is.. so we can start playing!
 
@@ -1147,49 +1149,49 @@ void NetworkGameLoop(void)
 
#ifdef NETWORK_SEND_DOUBLE_SEED
 
		_sync_seed_2 = _random_seeds[0][1];
 
#endif
 

	
 
		NetworkServer_Tick();
 
	} else {
 
		// Client
 

	
 
		// Make sure we are at the frame were the server is (quick-frames)
 
		if (_frame_counter_server > _frame_counter) {
 
			while (_frame_counter_server > _frame_counter) {
 
				if (!NetworkDoClientLoop()) break;
 
			}
 
		} else {
 
			// Else, keep on going till _frame_counter_max
 
			if (_frame_counter_max > _frame_counter) {
 
				NetworkDoClientLoop();
 
			}
 
		}
 
	}
 

	
 
	NetworkSend();
 
}
 

	
 
void NetworkGenerateUniqueId()
 
static void NetworkGenerateUniqueId(void)
 
{
 
	md5_state_t state;
 
	md5_byte_t digest[16];
 
	char hex_output[16*2 + 1];
 
	char coding_string[NETWORK_NAME_LENGTH];
 
	int di;
 

	
 
	snprintf(coding_string, sizeof(coding_string), "%d%s", (uint)Random(), "OpenTTD Unique ID");
 

	
 
	/* Generate the MD5 hash */
 
	md5_init(&state);
 
	md5_append(&state, coding_string, strlen(coding_string));
 
	md5_finish(&state, digest);
 

	
 
	for (di = 0; di < 16; ++di)
 
		sprintf(hex_output + di * 2, "%02x", digest[di]);
 

	
 
	/* _network_unique_id is our id */
 
	snprintf(_network_unique_id, sizeof(_network_unique_id), "%s", hex_output);
 
}
 

	
 
// This tries to launch the network for a given OS
 
void NetworkStartUp(void)
 
{
network.h
Show inline comments
 
@@ -172,27 +172,27 @@ VARDEF short _network_last_port;
 
VARDEF uint32 _network_last_host_ip;
 
VARDEF uint8 _network_reconnect;
 

	
 
VARDEF bool _network_udp_server;
 
VARDEF uint16 _network_udp_broadcast;
 

	
 
VARDEF bool _network_advertise;
 
VARDEF uint16 _network_last_advertise_date;
 

	
 
VARDEF bool _network_autoclean_companies;
 
VARDEF uint8 _network_autoclean_unprotected; // Remove a company after X months
 
VARDEF uint8 _network_autoclean_protected;   // Unprotect a company after X months
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 
// Those variables must always be registered!
 
VARDEF bool _networking;
 
VARDEF bool _network_available;  // is network mode available?
 
VARDEF bool _network_server; // network-server is active
 
VARDEF bool _network_dedicated; // are we a dedicated server?
 
VARDEF byte _network_playas; // an id to play as..
 

	
 
void ParseConnectionString(const byte **player, const byte **port, byte *connection_string);
 
void NetworkUpdateClientInfo(uint16 client_index);
 
void AddServer(byte *b);
 
void NetworkAddServer(const byte *b);
 

	
 
#endif /* NETWORK_H */
network_client.c
Show inline comments
 
#include "stdafx.h"
 
#include "network_data.h"
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
#include "table/strings.h"
 
#include "network_client.h"
 
#include "network_gamelist.h"
 
#include "command.h"
 
#include "gfx.h"
 
#include "window.h"
 
#include "settings.h"
 

	
 

	
 
// This file handles all the client-commands
 

	
 

	
 
extern const char _openttd_revision[];
 

	
 
// So we don't make too much typos ;)
 
#define MY_CLIENT DEREF_CLIENT(0)
 

	
 
static uint32 last_ack_frame;
 

	
 
void NetworkRecvPatchSettings(Packet *p);
 

	
 
// **********
 
// Sending functions
 
//   DEF_CLIENT_SEND_COMMAND has no parameters
 
// **********
 

	
 
DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO)
 
{
 
	//
 
	// Packet: CLIENT_COMPANY_INFO
 
	// Function: Request company-info (in detail)
 
	// Data:
 
	//    <none>
 
	//
 
	Packet *p;
 
	_network_join_status = NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO;
 
	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
	p = NetworkSend_Init(PACKET_CLIENT_COMPANY_INFO);
 
	NetworkSend_Packet(p, MY_CLIENT);
 
}
 

	
 
extern const char _openttd_revision[];
 

	
 
DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_JOIN)
 
{
 
	//
 
	// Packet: CLIENT_JOIN
 
	// Function: Try to join the server
 
	// Data:
 
	//    String: OpenTTD Revision (norev000 if no revision)
 
	//    String: Player Name (max NETWORK_NAME_LENGTH)
 
	//    uint8:  Play as Player id (1..MAX_PLAYERS)
 
	//    uint8:  Language ID
 
	//    String: Unique id to find the player back in server-listing
 
	//
 

	
 
	Packet *p;
 
	_network_join_status = NETWORK_JOIN_STATUS_AUTHORIZING;
 
	InvalidateWindow(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
	p = NetworkSend_Init(PACKET_CLIENT_JOIN);
 
	NetworkSend_string(p, _openttd_revision);
 
	NetworkSend_string(p, _network_player_name); // Player name
 
	NetworkSend_uint8(p, _network_playas); // PlayAs
 
	NetworkSend_uint8(p, NETLANG_ANY); // Language
 
	NetworkSend_string(p, _network_unique_id);
 
	NetworkSend_Packet(p, MY_CLIENT);
 
@@ -784,45 +784,45 @@ void NetworkRecvPatchSettings(Packet *p)
 
			case SDT_UINT16:
 
				*(uint16 *)(item->ptr) = NetworkRecv_uint16(p);
 
				break;
 
			case SDT_INT32:
 
			case SDT_UINT32:
 
				*(uint32 *)(item->ptr) = NetworkRecv_uint32(p);
 
				break;
 
		}
 
		item++;
 
	}
 
}
 

	
 
// Is called after a client is connected to the server
 
void NetworkClient_Connected(void)
 
{
 
	// Set the frame-counter to 0 so nothing happens till we are ready
 
	_frame_counter = 0;
 
	_frame_counter_server = 0;
 
	last_ack_frame = 0;
 
	// Request the game-info
 
	SEND_COMMAND(PACKET_CLIENT_JOIN)();
 
}
 

	
 
// Reads the packets from the socket-stream, if available
 
NetworkRecvStatus NetworkClient_ReadPackets(ClientState *cs)
 
NetworkRecvStatus NetworkClient_ReadPackets(NetworkClientState *cs)
 
{
 
	Packet *p;
 
	NetworkRecvStatus res = NETWORK_RECV_STATUS_OKAY;
 

	
 
	while (res == NETWORK_RECV_STATUS_OKAY && (p = NetworkRecv_Packet(cs, &res)) != NULL) {
 
		byte type = NetworkRecv_uint8(p);
 
		if (type < PACKET_END && _network_client_packet[type] != NULL) {
 
			res = _network_client_packet[type](p);
 
		}	else {
 
			res = NETWORK_RECV_STATUS_MALFORMED_PACKET;
 
			DEBUG(net, 0)("[NET][client] Received invalid packet type %d", type);
 
		}
 

	
 
		free(p);
 
	}
 

	
 
	return res;
 
}
 

	
 
#endif /* ENABLE_NETWORK */
network_client.h
Show inline comments
 
#ifndef NETWORK_CLIENT_H
 
#define NETWORK_CLIENT_H
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_GAME_INFO);
 
DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_COMPANY_INFO);
 
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_COMMAND)(CommandPacket *cp);
 
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_ERROR)(NetworkErrorCode errorno);
 
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_QUIT)(const char *leavemsg);
 
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_CHAT)(NetworkAction action, DestType desttype, int dest, const char *msg);
 
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_PASSWORD)(NetworkPasswordType type, const char *password);
 
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_PASSWORD)(const char *password);
 
DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_SET_NAME)(const char *name);
 
DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_ACK);
 

	
 
NetworkRecvStatus NetworkClient_ReadPackets(ClientState *cs);
 
NetworkRecvStatus NetworkClient_ReadPackets(NetworkClientState *cs);
 
void NetworkClient_Connected(void);
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 
#endif // NETWORK_CLIENT_H
network_data.c
Show inline comments
 
@@ -65,99 +65,99 @@ void NetworkSend_uint64(Packet *packet, 
 
	packet->buffer[packet->size++] = (data >>= 8) & 0xFF;
 
	packet->buffer[packet->size++] = (data >>= 8) & 0xFF;
 
	packet->buffer[packet->size++] = (data >>= 8) & 0xFF;
 
	packet->buffer[packet->size++] = (data >> 8) & 0xFF;
 
}
 

	
 
// 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, ClientState *cs)
 
void NetworkSend_Packet(Packet *packet, NetworkClientState *cs)
 
{
 
	Packet *p;
 
	assert(packet != NULL);
 

	
 
	packet->pos = 0;
 
	packet->next = NULL;
 

	
 
	packet->buffer[0] = packet->size & 0xFF;
 
	packet->buffer[1] = packet->size >> 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
 
NetworkRecvStatus CloseConnection(ClientState *cs)
 
NetworkRecvStatus CloseConnection(NetworkClientState *cs)
 
{
 
	CloseClient(cs);
 
	NetworkCloseClient(cs);
 

	
 
	// Clients drop back to the main menu
 
	if (!_network_server) {
 
		_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(ClientState *cs)
 
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) ("[NET] send() failed with error %d", err);
 
				CloseConnection(cs);
 
				return false;
 
			}
 
			return true;
 
		}
 
		if (res == 0) {
 
			// Client/server has left us :(
 
			CloseConnection(cs);
 
@@ -221,49 +221,49 @@ uint64 NetworkRecv_uint64(Packet *packet
 
}
 

	
 
// Reads a string till it finds a '\0' in the stream
 
void NetworkRecv_string(Packet *p, char* buffer, size_t size)
 
{
 
	int pos;
 
	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;
 
}
 

	
 
// 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(ClientState *cs, NetworkRecvStatus *status)
 
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) {
 
@@ -309,49 +309,49 @@ Packet *NetworkRecv_Packet(ClientState *
 
			}
 
			// Connection would block
 
			return NULL;
 
		}
 
		if (res == 0) {
 
			// Client/server has left us :(
 
			*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(ClientState *cs, CommandPacket *cp)
 
void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp)
 
{
 
	CommandPacket *new_cp = malloc(sizeof(CommandPacket));
 

	
 
	*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;
 
	}
 
}
 

	
 
// If this fails, make sure you change the following line below:
 
//   'memcpy(qp->dp, _decode_parameters, 10 * sizeof(uint32));'
 
// Also, in network_data.h, change the size of CommandPacket->dp!
 
// (this protection is there to make sure in network.h dp is of the right size!)
 
assert_compile(sizeof(_decode_parameters) == 20 * sizeof(uint32));
 

	
 
// Prepare a DoCommand to be send over the network
 
void NetworkSend_Command(uint32 tile, uint32 p1, uint32 p2, uint32 cmd, CommandCallback *callback)
 
{
 
	CommandPacket *c = malloc(sizeof(CommandPacket));
 
@@ -369,49 +369,49 @@ void NetworkSend_Command(uint32 tile, ui
 

	
 
	while (temp_callback < _callback_table_count && _callback_table[temp_callback] != callback)
 
		temp_callback++;
 
	if (temp_callback == _callback_table_count) {
 
		DEBUG(net, 0) ("[NET] 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
 
	}
 

	
 
	// Copy the _decode_parameters to dp
 
	memcpy(c->dp, _decode_parameters, 20 * sizeof(uint32));
 

	
 
	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 then others.
 
		//   So to keep the game fair, we delay the command with 1 tick
 
		//   which gives about the same speed as most clients.
 
		ClientState *cs;
 
		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;
network_data.h
Show inline comments
 
@@ -86,64 +86,64 @@ typedef enum {
 
	NETWORK_ERROR_NAME_IN_USE,
 
	NETWORK_ERROR_WRONG_PASSWORD,
 
	NETWORK_ERROR_PLAYER_MISMATCH, // Happens in CLIENT_COMMAND
 
	NETWORK_ERROR_KICKED,
 
} NetworkErrorCode;
 

	
 
// Actions that can be used for NetworkTextMessage
 
typedef enum {
 
	NETWORK_ACTION_JOIN_LEAVE,
 
	NETWORK_ACTION_CHAT,
 
	NETWORK_ACTION_CHAT_PLAYER,
 
	NETWORK_ACTION_CHAT_CLIENT,
 
	NETWORK_ACTION_CHAT_TO_CLIENT,
 
	NETWORK_ACTION_CHAT_TO_PLAYER,
 
	NETWORK_ACTION_GIVE_MONEY,
 
	NETWORK_ACTION_NAME_CHANGE,
 
} NetworkAction;
 

	
 
typedef enum {
 
	NETWORK_GAME_PASSWORD,
 
	NETWORK_COMPANY_PASSWORD,
 
} NetworkPasswordType;
 

	
 
// To keep the clients all together
 
typedef struct ClientState {
 
typedef struct NetworkClientState {
 
	int socket;
 
	uint16 index;
 
	uint32 last_frame;
 
	uint32 last_frame_server;
 
	byte lag_test; // This byte is used for lag-testing the client
 

	
 
	ClientStatus status;
 
	bool writable; // is client ready to write to?
 
	bool quited;
 

	
 
	Packet *packet_queue; // Packets that are awaiting delivery
 
	Packet *packet_recv; // Partially received packet
 

	
 
	CommandPacket *command_queue; // The command-queue awaiting delivery
 
} ClientState;
 
} 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_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,
 
@@ -152,74 +152,74 @@ typedef enum {
 
	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_END // Should ALWAYS be on the end of this list!! (period)
 
} PacketType;
 

	
 
typedef enum {
 
	DESTTYPE_BROADCAST,
 
	DESTTYPE_PLAYER,
 
	DESTTYPE_CLIENT
 
} DestType;
 

	
 
CommandPacket *_local_command_queue;
 

	
 
SOCKET _udp_client_socket; // udp client socket
 

	
 
// Here we keep track of the clients
 
//  (and the client uses [0] for his own communication)
 
ClientState _clients[MAX_CLIENTS];
 
NetworkClientState _clients[MAX_CLIENTS];
 
#define DEREF_CLIENT(i) (&_clients[i])
 
// This returns the NetworkClientInfo from a ClientState
 
// This returns the NetworkClientInfo from a NetworkClientState
 
#define DEREF_CLIENT_INFO(cs) (&_network_client_info[cs - _clients])
 

	
 
// Macros to make life a bit more easier
 
#define DEF_CLIENT_RECEIVE_COMMAND(type) NetworkRecvStatus NetworkPacketReceive_ ## type ## _command(Packet *p)
 
#define DEF_CLIENT_SEND_COMMAND(type) void NetworkPacketSend_ ## type ## _command(void)
 
#define DEF_CLIENT_SEND_COMMAND_PARAM(type) void NetworkPacketSend_ ## type ## _command
 
#define DEF_SERVER_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(ClientState *cs, Packet *p)
 
#define DEF_SERVER_SEND_COMMAND(type) void NetworkPacketSend_ ## type ## _command(ClientState *cs)
 
#define DEF_SERVER_RECEIVE_COMMAND(type) void NetworkPacketReceive_ ## type ## _command(NetworkClientState *cs, Packet *p)
 
#define DEF_SERVER_SEND_COMMAND(type) void NetworkPacketSend_ ## type ## _command(NetworkClientState *cs)
 
#define DEF_SERVER_SEND_COMMAND_PARAM(type) void NetworkPacketSend_ ## type ## _command
 

	
 
#define SEND_COMMAND(type) NetworkPacketSend_ ## type ## _command
 
#define RECEIVE_COMMAND(type) NetworkPacketReceive_ ## type ## _command
 

	
 
#define FOR_ALL_CLIENTS(cs) for (cs = _clients; cs != &_clients[MAX_CLIENTS] && cs->socket != INVALID_SOCKET; cs++)
 

	
 
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, ClientState *cs);
 
void NetworkSend_Packet(Packet *packet, NetworkClientState *cs);
 

	
 
uint8 NetworkRecv_uint8(Packet *packet);
 
uint16 NetworkRecv_uint16(Packet *packet);
 
uint32 NetworkRecv_uint32(Packet *packet);
 
uint64 NetworkRecv_uint64(Packet *packet);
 
void NetworkRecv_string(Packet *packet, char* buffer, size_t size);
 
Packet *NetworkRecv_Packet(ClientState *cs, NetworkRecvStatus *status);
 
Packet *NetworkRecv_Packet(NetworkClientState *cs, NetworkRecvStatus *status);
 

	
 
bool NetworkSend_Packets(ClientState *cs);
 
bool NetworkSend_Packets(NetworkClientState *cs);
 
void NetworkExecuteCommand(CommandPacket *cp);
 
void NetworkAddCommandQueue(ClientState *cs, CommandPacket *cp);
 
void NetworkAddCommandQueue(NetworkClientState *cs, CommandPacket *cp);
 

	
 
// from network.c
 
void CloseClient(ClientState *cs);
 
void NetworkCloseClient(NetworkClientState *cs);
 
void CDECL NetworkTextMessage(NetworkAction action, uint16 color, const char *name, const char *str, ...);
 
void NetworkGetClientName(char *clientname, size_t size, ClientState *cs);
 
uint NetworkCalculateLag(const ClientState *cs);
 
void NetworkGetClientName(char *clientname, size_t size, const NetworkClientState *cs);
 
uint NetworkCalculateLag(const NetworkClientState *cs);
 
byte NetworkGetCurrentLanguageIndex();
 
NetworkClientInfo *NetworkFindClientInfoFromIndex(uint16 client_index);
 
ClientState *NetworkFindClientStateFromIndex(uint16 client_index);
 
NetworkClientState *NetworkFindClientStateFromIndex(uint16 client_index);
 
unsigned long NetworkResolveHost(const char *hostname);
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 
#endif // NETWORK_DATA_H
network_gamelist.c
Show inline comments
 
@@ -44,40 +44,40 @@ NetworkGameList *NetworkGameListAddItem(
 
		if (item->ip == ip && item->port == port)
 
			return item;
 

	
 
		item->next = malloc(sizeof(*item));
 
		item = item->next;
 
	} else {
 
		item = malloc(sizeof(*item));
 
		_network_game_list = item;
 
	}
 

	
 
	DEBUG(net, 4) ("[NET][GameList] Added server to list");
 

	
 
	memset(item, 0, sizeof(*item));
 

	
 
	item->next = NULL;
 
	item->ip = ip;
 
	item->port = port;
 
	_network_game_count++;
 

	
 
	UpdateNetworkGameWindow(false);
 

	
 
	return item;
 
}
 

	
 
void NetworkGameListAddQueriedItem(NetworkGameInfo *info, bool server_online)
 
void NetworkGameListAddQueriedItem(const NetworkGameInfo *info, bool server_online)
 
{
 
	// We queried a server and now we are going to add it to the list
 
	NetworkGameList *item;
 

	
 
	item = NetworkGameListAddItem(_network_last_host_ip, _network_last_port);
 
	item->online = server_online;
 
	memcpy(&item->info, info, sizeof(NetworkGameInfo));
 
	ttd_strlcpy(item->info.hostname, _network_last_host, sizeof(item->info.hostname));
 

	
 
	UpdateNetworkGameWindow(false);
 
}
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 

	
network_gamelist.h
Show inline comments
 
#ifndef NETWORK_GAMELIST_H
 
#define NETWORK_GAMELIST_H
 

	
 
void NetworkGameListClear(void);
 
NetworkGameList *NetworkGameListAddItem(uint32 ip, uint16 port);
 
void NetworkGameListAddQueriedItem(NetworkGameInfo *info, bool server_online);
 
void NetworkGameListAddQueriedItem(const NetworkGameInfo *info, bool server_online);
 

	
 
#endif /* NETWORK_GAMELIST_H */
network_gui.c
Show inline comments
 
@@ -296,49 +296,49 @@ static void NetworkGameWindowWndProc(Win
 
		if (_selected_field == 3)
 
			HandleEditBox(w, 3);
 

	
 
		break;
 

	
 
	case WE_KEYPRESS:
 
		if (_selected_field != 3)
 
			break;
 

	
 
		switch (HandleEditBoxKey(w, 3, e)) {
 
		case 1:
 
			HandleButtonClick(w, 8);
 
			break;
 
		}
 

	
 
		// The name is only allowed when it starts with a letter!
 
		if (_edit_str_buf[0] != '\0' && _edit_str_buf[0] != ' ')
 
			ttd_strlcpy(_network_player_name, _edit_str_buf, lengthof(_network_player_name));
 
		else
 
			ttd_strlcpy(_network_player_name, "Player", lengthof(_network_player_name));
 

	
 
		break;
 

	
 
	case WE_ON_EDIT_TEXT: {
 
		AddServer(e->edittext.str);
 
		NetworkAddServer(e->edittext.str);
 
	} break;
 

	
 
	case WE_CREATE: {
 
		_selected_item = NULL;
 
	} break;
 
	}
 
}
 

	
 
static const Widget _network_game_window_widgets[] = {
 
{   WWT_CLOSEBOX,   BGC,     0,    10,     0,    13, STR_00C5,										STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,   BGC,    11,   479,     0,    13, STR_NETWORK_MULTIPLAYER,			STR_NULL},
 
{     WWT_IMGBTN,   BGC,     0,   479,    14,   214, 0x0,													STR_NULL},
 

	
 
/* LEFT SIDE */
 
{     WWT_IMGBTN,   BGC,    90,   230,    22,    33, 0x0,													STR_NETWORK_ENTER_NAME_TIP},
 

	
 
{  WWT_SCROLLBAR,   BGC,   220,   230,    62,   185, 0x0,													STR_0190_SCROLL_BAR_SCROLLS_LIST},
 

	
 
{     WWT_IMGBTN,   BTC,    10,   130,    62,    73, 0x0,													STR_NETWORK_GAME_NAME_TIP },
 
{     WWT_IMGBTN,   BTC,   131,   180,    62,    73, 0x0,													STR_NETWORK_CLIENTS_CAPTION_TIP },
 
{     WWT_IMGBTN,   BTC,   181,   219,    62,    73, 0x0,													STR_NETWORK_INFO_ICONS_TIP },
 

	
 
{     WWT_MATRIX,   BGC,    10,   219,    74,   185, 0x801,												STR_NETWORK_CLICK_GAME_TO_SELECT},
 

	
network_server.c
Show inline comments
 
#include "stdafx.h"
 
#include "network_data.h"
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
#include "table/strings.h"
 
#include "network_server.h"
 
#include "network_udp.h"
 
#include "console.h"
 
#include "command.h"
 
#include "gfx.h"
 
#include "vehicle.h"
 
#include "station.h"
 
#include "settings.h"
 

	
 
// This file handles all the server-commands
 

	
 
void NetworkHandleCommandQueue(ClientState *cs);
 
void NetworkHandleCommandQueue(NetworkClientState *cs);
 
void NetworkPopulateCompanyInfo(void);
 
void NetworkSendPatchSettings(ClientState *cs);
 
void NetworkSendPatchSettings(NetworkClientState *cs);
 

	
 
extern const char _openttd_revision[];
 

	
 
// Is the network enabled?
 

	
 
// **********
 
// Sending functions
 
//   DEF_SERVER_SEND_COMMAND has parameter: ClientState *cs
 
//   DEF_SERVER_SEND_COMMAND has parameter: NetworkClientState *cs
 
// **********
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CLIENT_INFO)(ClientState *cs, NetworkClientInfo *ci)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CLIENT_INFO)(NetworkClientState *cs, NetworkClientInfo *ci)
 
{
 
	//
 
	// Packet: SERVER_CLIENT_INFO
 
	// Function: Sends info about a client
 
	// Data:
 
	//    uint16:  The index of the client (always unique on a server. 1 = server)
 
	//    uint8:  As which player the client is playing
 
	//    String: The name of the client
 
	//    String: The unique id of the client
 
	//
 

	
 
	Packet *p;
 

	
 
	if (ci->client_index != NETWORK_EMPTY_INDEX) {
 
		p = NetworkSend_Init(PACKET_SERVER_CLIENT_INFO);
 
		NetworkSend_uint16(p, ci->client_index);
 
		NetworkSend_uint8 (p, ci->client_playas);
 
		NetworkSend_string(p, ci->client_name);
 
		NetworkSend_string(p, ci->unique_id);
 

	
 
		NetworkSend_Packet(p, cs);
 
	}
 
}
 

	
 
@@ -98,156 +100,156 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_CO
 
		NetworkSend_uint8 (p, current);
 

	
 
		NetworkSend_string(p, _network_player_info[player->index].company_name);
 
		NetworkSend_uint8 (p, _network_player_info[player->index].inaugurated_year);
 
		NetworkSend_uint64(p, _network_player_info[player->index].company_value);
 
		NetworkSend_uint64(p, _network_player_info[player->index].money);
 
		NetworkSend_uint64(p, _network_player_info[player->index].income);
 
		NetworkSend_uint16(p, _network_player_info[player->index].performance);
 

	
 
		for (i = 0; i < NETWORK_VEHICLE_TYPES; i++)
 
			NetworkSend_uint16(p, _network_player_info[player->index].num_vehicle[i]);
 

	
 
		for (i = 0; i < NETWORK_STATION_TYPES; i++)
 
			NetworkSend_uint16(p, _network_player_info[player->index].num_station[i]);
 

	
 
		if (_network_player_info[player->index].players[0] == '\0')
 
			NetworkSend_string(p, "<none>");
 
		else
 
			NetworkSend_string(p, _network_player_info[player->index].players);
 

	
 
		NetworkSend_Packet(p, cs);
 
	}
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(ClientState *cs, NetworkErrorCode error)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, NetworkErrorCode error)
 
{
 
	//
 
	// Packet: SERVER_ERROR
 
	// Function: The client made an error
 
	// Data:
 
	//    uint8:  ErrorID (see network_data.h, NetworkErrorCode)
 
	//
 

	
 
	ClientState *new_cs;
 
	NetworkClientState *new_cs;
 
	char str1[100], str2[100];
 
	char client_name[NETWORK_NAME_LENGTH];
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR);
 
	NetworkSend_uint8(p, error);
 
	NetworkSend_Packet(p, cs);
 

	
 
	// Only send when the current client was in game
 
	if (cs->status > STATUS_AUTH) {
 
		NetworkGetClientName(client_name, sizeof(client_name), cs);
 

	
 
		GetString(str1, STR_NETWORK_ERR_LEFT);
 
		GetString(str2, STR_NETWORK_ERR_CLIENT_GENERAL + error);
 

	
 
		DEBUG(net, 2)("[NET] %s made an error (%s) and his connection is closed", client_name, str2);
 

	
 
		NetworkTextMessage(NETWORK_ACTION_JOIN_LEAVE, 1, client_name, "%s (%s)", str1, str2);
 

	
 
		FOR_ALL_CLIENTS(new_cs) {
 
			if (new_cs->status > STATUS_AUTH && new_cs != cs) {
 
				// Some errors we filter to a more general error. Clients don't have to know the real
 
				//  reason a joining failed.
 
				if (error == NETWORK_ERROR_NOT_AUTHORIZED || error == NETWORK_ERROR_NOT_EXPECTED || error == NETWORK_ERROR_WRONG_REVISION)
 
					error = NETWORK_ERROR_ILLEGAL_PACKET;
 

	
 
				SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, error);
 
			}
 
		}
 
	} else {
 
		DEBUG(net, 2)("[NET] Clientno %d has made an error and his connection is closed", cs->index);
 
	}
 

	
 
	cs->quited = true;
 

	
 
	// Make sure the data get's there before we close the connection
 
	NetworkSend_Packets(cs);
 

	
 
	// The client made a mistake, so drop his connection now!
 
	CloseClient(cs);
 
	NetworkCloseClient(cs);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(ClientState *cs, NetworkPasswordType type)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(NetworkClientState *cs, NetworkPasswordType type)
 
{
 
	//
 
	// Packet: SERVER_NEED_PASSWORD
 
	// Function: Indication to the client that the server needs a password
 
	// Data:
 
	//    uint8:  Type of password
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_NEED_PASSWORD);
 
	NetworkSend_uint8(p, type);
 
	NetworkSend_Packet(p, cs);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WELCOME)
 
{
 
	//
 
	// Packet: SERVER_WELCOME
 
	// Function: The client is joined and ready to receive his map
 
	// Data:
 
	//    uint16:  Own ClientID
 
	//
 

	
 
	Packet *p;
 
	ClientState *new_cs;
 
	NetworkClientState *new_cs;
 

	
 
	// Invalid packet when status is AUTH or higher
 
	if (cs->status >= STATUS_AUTH)
 
		return;
 

	
 
	cs->status = STATUS_AUTH;
 
	_network_game_info.clients_on++;
 

	
 
	p = NetworkSend_Init(PACKET_SERVER_WELCOME);
 
	NetworkSend_uint16(p, cs->index);
 
	NetworkSend_Packet(p, cs);
 

	
 
		// Transmit info about all the active clients
 
	FOR_ALL_CLIENTS(new_cs) {
 
		if (new_cs != cs && new_cs->status > STATUS_AUTH)
 
			SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, DEREF_CLIENT_INFO(new_cs));
 
	}
 
	// Also send the info of the server
 
	SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX));
 
}
 

	
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_WAIT)
 
{
 
	//
 
	// Packet: PACKET_SERVER_WAIT
 
	// Function: The client can not receive the map at the moment because
 
	//             someone else is already receiving the map
 
	// Data:
 
	//    uint8:  Clients awaiting map
 
	//
 
	int waiting = 0;
 
	ClientState *new_cs;
 
	NetworkClientState *new_cs;
 
	Packet *p;
 

	
 
	// Count how many players are waiting in the queue
 
	FOR_ALL_CLIENTS(new_cs) {
 
		if (new_cs->status == STATUS_MAP_WAIT)
 
			waiting++;
 
	}
 

	
 
	p = NetworkSend_Init(PACKET_SERVER_WAIT);
 
	NetworkSend_uint8(p, waiting);
 
	NetworkSend_Packet(p, cs);
 
}
 

	
 
// This sends the map to the client
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP)
 
{
 
	//
 
	// Packet: SERVER_MAP
 
	// Function: Sends the map to the client, or a part of it (it is splitted in
 
	//   a lot of multiple packets)
 
	// Data:
 
	//    uint8:  packet-type (MAP_PACKET_START, MAP_PACKET_NORMAL and MAP_PACKET_END)
 
	//  if MAP_PACKET_START:
 
	//    uint32: The current FrameCounter
 
@@ -306,86 +308,86 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MA
 
			NetworkSend_Packet(p, cs);
 
			if (feof(file_pointer)) {
 
				// Done reading!
 
				int i;
 
				Packet *p;
 

	
 
				// XXX - Delete this when patch-settings are saved in-game
 
				NetworkSendPatchSettings(cs);
 

	
 
				p = NetworkSend_Init(PACKET_SERVER_MAP);
 
				NetworkSend_uint8(p, MAP_PACKET_END);
 
				// Send the player_seeds in this packet
 
				for (i = 0; i < MAX_PLAYERS; i++) {
 
					NetworkSend_uint32(p, _player_seeds[i][0]);
 
					NetworkSend_uint32(p, _player_seeds[i][1]);
 
				}
 
				NetworkSend_Packet(p, cs);
 

	
 
				// Set the status to DONE_MAP, no we will wait for the client
 
				//  to send it is ready (maybe that happens like never ;))
 
				cs->status = STATUS_DONE_MAP;
 
				fclose(file_pointer);
 

	
 
				{
 
					ClientState *new_cs;
 
					NetworkClientState *new_cs;
 
					bool new_map_client = false;
 
					// Check if there is a client waiting for receiving the map
 
					//  and start sending him the map
 
					FOR_ALL_CLIENTS(new_cs) {
 
						if (new_cs->status == STATUS_MAP_WAIT) {
 
							// Check if we already have a new client to send the map to
 
							if (!new_map_client) {
 
								// If not, this client will get the map
 
								new_cs->status = STATUS_AUTH;
 
								new_map_client = true;
 
								SEND_COMMAND(PACKET_SERVER_MAP)(new_cs);
 
							} else {
 
								// Else, send the other clients how many clients are in front of them
 
								SEND_COMMAND(PACKET_SERVER_WAIT)(new_cs);
 
							}
 
						}
 
					}
 
				}
 

	
 
				// There is no more data, so break the for
 
				break;
 
			}
 
		}
 

	
 
		// Send all packets (forced) and check if we have send it all
 
		NetworkSend_Packets(cs);
 
		if (cs->packet_queue == NULL) {
 
			// All are sent, increase the sent_packets
 
			sent_packets *= 2;
 
		} else {
 
			// Not everything is sent, decrease the sent_packets
 
			if (sent_packets > 1) sent_packets /= 2;
 
		}
 
	}
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_JOIN)(ClientState *cs, uint16 client_index)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_JOIN)(NetworkClientState *cs, uint16 client_index)
 
{
 
	//
 
	// Packet: SERVER_JOIN
 
	// Function: A client is joined (all active clients receive this after a
 
	//     PACKET_CLIENT_MAP_OK) Mostly what directly follows is a
 
	//     PACKET_SERVER_CLIENT_INFO
 
	// Data:
 
	//    uint16:  Client-Index
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_JOIN);
 

	
 
	NetworkSend_uint16(p, client_index);
 

	
 
	NetworkSend_Packet(p, cs);
 
}
 

	
 

	
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_FRAME)
 
{
 
	//
 
	// Packet: SERVER_FRAME
 
	// Function: Sends the current frame-counter to the client
 
	// Data:
 
@@ -409,184 +411,182 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_FR
 
}
 

	
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SYNC)
 
{
 
	//
 
	// Packet: SERVER_SYNC
 
	// Function: Sends a sync-check to the client
 
	// Data:
 
	//    uint32: Frame Counter
 
	//    uint32: General-seed-1
 
	//    [uint32: general-seed-2]
 
	//      (last one depends on compile-settings, and are not default settings)
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_SYNC);
 
	NetworkSend_uint32(p, _frame_counter);
 
	NetworkSend_uint32(p, _sync_seed_1);
 

	
 
#ifdef NETWORK_SEND_DOUBLE_SEED
 
	NetworkSend_uint32(p, _sync_seed_2);
 
#endif
 
	NetworkSend_Packet(p, cs);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_COMMAND)(ClientState *cs, CommandPacket *cp)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_COMMAND)(NetworkClientState *cs, CommandPacket *cp)
 
{
 
	//
 
	// Packet: SERVER_COMMAND
 
	// Function: Sends a DoCommand to the client
 
	// Data:
 
	//    uint8:  PlayerID (0..MAX_PLAYERS-1)
 
	//    uint32: CommandID (see command.h)
 
	//    uint32: P1 (free variables used in DoCommand)
 
	//    uint32: P2
 
	//    uint32: Tile
 
	//    uint32: decode_params
 
	//      10 times the last one (lengthof(cp->dp))
 
	//    uint8:  CallBackID (see callback_table.c)
 
	//    uint32: Frame of execution
 
	//
 

	
 
	int i;
 
	char *dparam_char;
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_COMMAND);
 

	
 
	NetworkSend_uint8(p, cp->player);
 
	NetworkSend_uint32(p, cp->cmd);
 
	NetworkSend_uint32(p, cp->p1);
 
	NetworkSend_uint32(p, cp->p2);
 
	NetworkSend_uint32(p, cp->tile);
 
	/* We are going to send them byte by byte, because dparam is misused
 
	    for chars (if it is used), and else we have a BigEndian / LittleEndian
 
	    problem.. we should fix the misuse of dparam... -- TrueLight */
 
	dparam_char = (char *)&cp->dp[0];
 
	for (i = 0; i < lengthof(cp->dp) * 4; i++) {
 
		NetworkSend_uint8(p, *dparam_char);
 
		dparam_char++;
 
	}
 
	NetworkSend_uint8(p, cp->callback);
 
	NetworkSend_uint32(p, cp->frame);
 

	
 
	NetworkSend_Packet(p, cs);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHAT)(ClientState *cs, NetworkAction action, uint16 client_index, const char *msg)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHAT)(NetworkClientState *cs, NetworkAction action, uint16 client_index, const char *msg)
 
{
 
	//
 
	// Packet: SERVER_CHAT
 
	// Function: Sends a chat-packet to the client
 
	// Data:
 
	//    uint8:  ActionID (see network_data.h, NetworkAction)
 
	//    uint16:  Client-index
 
	//    String: Message (max MAX_TEXT_MSG_LEN)
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_CHAT);
 

	
 
	NetworkSend_uint8(p, action);
 
	NetworkSend_uint16(p, client_index);
 
	NetworkSend_string(p, msg);
 

	
 
	NetworkSend_Packet(p, cs);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(ClientState *cs, uint16 client_index, NetworkErrorCode errorno)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkClientState *cs, uint16 client_index, NetworkErrorCode errorno)
 
{
 
	//
 
	// Packet: SERVER_ERROR_QUIT
 
	// Function: One of the clients made an error and is quiting the game
 
	//      This packet informs the other clients of that.
 
	// Data:
 
	//    uint16:  Client-index
 
	//    uint8:  ErrorID (see network_data.h, NetworkErrorCode)
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_ERROR_QUIT);
 

	
 
	NetworkSend_uint16(p, client_index);
 
	NetworkSend_uint8(p, errorno);
 

	
 
	NetworkSend_Packet(p, cs);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_QUIT)(ClientState *cs, uint16 client_index, const char *leavemsg)
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_QUIT)(NetworkClientState *cs, uint16 client_index, const char *leavemsg)
 
{
 
	//
 
	// Packet: SERVER_ERROR_QUIT
 
	// Function: A client left the game, and this packets informs the other clients
 
	//      of that.
 
	// Data:
 
	//    uint16:  Client-index
 
	//    String: leave-message
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_QUIT);
 

	
 
	NetworkSend_uint16(p, client_index);
 
	NetworkSend_string(p, leavemsg);
 

	
 
	NetworkSend_Packet(p, cs);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN)
 
{
 
	//
 
	// Packet: SERVER_SHUTDOWN
 
	// Function: Let the clients know that the server is closing
 
	// Data:
 
	//     <none>
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_SHUTDOWN);
 
	NetworkSend_Packet(p, cs);
 
}
 

	
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME)
 
{
 
	//
 
	// Packet: PACKET_SERVER_NEWGAME
 
	// Function: Let the clients know that the server is loading a new map
 
	// Data:
 
	//     <none>
 
	//
 

	
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_NEWGAME);
 
	NetworkSend_Packet(p, cs);
 
}
 

	
 
// **********
 
// Receiving functions
 
//   DEF_SERVER_RECEIVE_COMMAND has parameter: ClientState *cs, Packet *p
 
//   DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientState *cs, Packet *p
 
// **********
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO)
 
{
 
	SEND_COMMAND(PACKET_SERVER_COMPANY_INFO)(cs);
 
}
 

	
 
extern const char _openttd_revision[];
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN)
 
{
 
	char name[NETWORK_NAME_LENGTH];
 
	char unique_id[NETWORK_NAME_LENGTH];
 
	NetworkClientInfo *ci;
 
	char test_name[NETWORK_NAME_LENGTH];
 
	byte playas;
 
	NetworkLanguage client_lang;
 
	char client_revision[NETWORK_REVISION_LENGTH];
 

	
 

	
 
	NetworkRecv_string(p, client_revision, sizeof(client_revision));
 

	
 
#if defined(WITH_REV) || defined(WITH_REV_HACK)
 
	// Check if the client has revision control enabled
 
	if (strncmp(NOREV_STRING, client_revision, sizeof(client_revision)) != 0) {
 
		if (strncmp(_network_game_info.server_revision, client_revision, sizeof(_network_game_info.server_revision) - 1) != 0) {
 
			// Different revisions!!
 
			SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_REVISION);
 

	
 
			return;
 
		}
 
	}
 
#endif
 
@@ -661,114 +661,114 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
 

	
 
		// Valid password, allow user
 
		SEND_COMMAND(PACKET_SERVER_WELCOME)(cs);
 
		return;
 
	} else if (cs->status == STATUS_INACTIVE && type == NETWORK_COMPANY_PASSWORD) {
 
		ci = DEREF_CLIENT_INFO(cs);
 

	
 
		if (strncmp(password, _network_player_info[ci->client_playas - 1].password, sizeof(password)) != 0) {
 
			// Password is invalid
 
			SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_WRONG_PASSWORD);
 
			return;
 
		}
 

	
 
		SEND_COMMAND(PACKET_SERVER_WELCOME)(cs);
 
		return;
 
	}
 

	
 

	
 
	SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
 
	return;
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_GETMAP)
 
{
 
	ClientState *new_cs;
 
	NetworkClientState *new_cs;
 

	
 
	// The client was never joined.. so this is impossible, right?
 
	//  Ignore the packet, give the client a warning, and close his connection
 
	if (cs->status < STATUS_AUTH || cs->quited) {
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_AUTHORIZED);
 
		return;
 
	}
 

	
 
	// Check if someone else is receiving the map
 
	FOR_ALL_CLIENTS(new_cs) {
 
		if (new_cs->status == STATUS_MAP) {
 
			// Tell the new client to wait
 
			cs->status = STATUS_MAP_WAIT;
 
			SEND_COMMAND(PACKET_SERVER_WAIT)(cs);
 
			return;
 
		}
 
	}
 

	
 
	// We receive a request to upload the map.. give it to the client!
 
	SEND_COMMAND(PACKET_SERVER_MAP)(cs);
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK)
 
{
 
	// Client has the map, now start syncing
 
	if (cs->status == STATUS_DONE_MAP && !cs->quited) {
 
		char client_name[NETWORK_NAME_LENGTH];
 
		char str[100];
 
		ClientState *new_cs;
 
		NetworkClientState *new_cs;
 
		GetString(str, STR_NETWORK_CLIENT_JOINED);
 

	
 
		NetworkGetClientName(client_name, sizeof(client_name), cs);
 

	
 
		NetworkTextMessage(NETWORK_ACTION_JOIN_LEAVE, 1, client_name, str);
 

	
 
		// Mark the client as pre-active, and wait for an ACK
 
		//  so we know he is done loading and in sync with us
 
		cs->status = STATUS_PRE_ACTIVE;
 
		NetworkHandleCommandQueue(cs);
 
		SEND_COMMAND(PACKET_SERVER_FRAME)(cs);
 
		SEND_COMMAND(PACKET_SERVER_SYNC)(cs);
 

	
 
		// This is the frame the client receives
 
		//  we need it later on to make sure the client is not too slow
 
		cs->last_frame = _frame_counter;
 
		cs->last_frame_server = _frame_counter;
 

	
 
		FOR_ALL_CLIENTS(new_cs) {
 
			if (new_cs->status > STATUS_AUTH) {
 
				SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(new_cs, DEREF_CLIENT_INFO(cs));
 
				SEND_COMMAND(PACKET_SERVER_JOIN)(new_cs, cs->index);
 
			}
 
		}
 
	} else {
 
		// Wrong status for this packet, give a warning to client, and close connection
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
 
	}
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND)
 
{
 
	// The client has done a command and wants us to handle it
 
	int i;
 
	byte callback;
 
	ClientState *new_cs;
 
	NetworkClientState *new_cs;
 
	NetworkClientInfo *ci;
 
	char *dparam_char;
 

	
 
	CommandPacket *cp = malloc(sizeof(CommandPacket));
 

	
 
	// The client was never joined.. so this is impossible, right?
 
	//  Ignore the packet, give the client a warning, and close his connection
 
	if (cs->status < STATUS_DONE_MAP || cs->quited) {
 
		SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED);
 
		return;
 
	}
 

	
 
	cp->player = NetworkRecv_uint8(p);
 
	cp->cmd = NetworkRecv_uint32(p);
 
	cp->p1 = NetworkRecv_uint32(p);
 
	cp->p2 = NetworkRecv_uint32(p);
 
	cp->tile = NetworkRecv_uint32(p);
 
	/* We are going to send them byte by byte, because dparam is misused
 
	    for chars (if it is used), and else we have a BigEndian / LittleEndian
 
	    problem.. we should fix the misuse of dparam... -- TrueLight */
 
	dparam_char = (char *)&cp->dp[0];
 
	for (i = 0; i < lengthof(cp->dp) * 4; i++) {
 
		*dparam_char = NetworkRecv_uint8(p);
 
		dparam_char++;
 
@@ -811,125 +811,125 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
 
			if (new_cs != cs)
 
				cp->callback = 0;
 
			else
 
				cp->callback = callback;
 
			NetworkAddCommandQueue(new_cs, cp);
 
		}
 
	}
 

	
 
	cp->callback = 0;
 
	// Queue the command on the server
 
	if (_local_command_queue == NULL) {
 
		_local_command_queue = cp;
 
	} else {
 
		// Find last packet
 
		CommandPacket *c = _local_command_queue;
 
		while (c->next != NULL) c = c->next;
 
		c->next = cp;
 
	}
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ERROR)
 
{
 
	// This packets means a client noticed an error and is reporting this
 
	//  to us. Display the error and report it to the other clients
 
	ClientState *new_cs;
 
	NetworkClientState *new_cs;
 
	byte errorno = NetworkRecv_uint8(p);
 
	char str1[100], str2[100];
 
	char client_name[NETWORK_NAME_LENGTH];
 

	
 
	// The client was never joined.. thank the client for the packet, but ignore it
 
	if (cs->status < STATUS_DONE_MAP || cs->quited) {
 
		cs->quited = true;
 
		return;
 
	}
 

	
 
	NetworkGetClientName(client_name, sizeof(client_name), cs);
 

	
 
	GetString(str1, STR_NETWORK_ERR_LEFT);
 
	GetString(str2, STR_NETWORK_ERR_CLIENT_GENERAL + errorno);
 

	
 
	DEBUG(net, 2)("[NET] %s reported an error and is closing his connection (%s)", client_name, str2);
 

	
 
	NetworkTextMessage(NETWORK_ACTION_JOIN_LEAVE, 1, client_name, "%s (%s)", str1, str2);
 

	
 
	FOR_ALL_CLIENTS(new_cs) {
 
		if (new_cs->status > STATUS_AUTH) {
 
			SEND_COMMAND(PACKET_SERVER_ERROR_QUIT)(new_cs, cs->index, errorno);
 
		}
 
	}
 

	
 
	cs->quited = true;
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_QUIT)
 
{
 
	// The client wants to leave. Display this and report it to the other
 
	//  clients.
 
	ClientState *new_cs;
 
	NetworkClientState *new_cs;
 
	char str1[100], str2[100];
 
	char client_name[NETWORK_NAME_LENGTH];
 

	
 
	// The client was never joined.. thank the client for the packet, but ignore it
 
	if (cs->status < STATUS_DONE_MAP || cs->quited) {
 
		cs->quited = true;
 
		return;
 
	}
 

	
 
	NetworkRecv_string(p, str2, 100);
 

	
 
	NetworkGetClientName(client_name, sizeof(client_name), cs);
 

	
 
	GetString(str1, STR_NETWORK_ERR_LEFT);
 

	
 
	NetworkTextMessage(NETWORK_ACTION_JOIN_LEAVE, 1, client_name, "%s (%s)", str1, str2);
 

	
 
	FOR_ALL_CLIENTS(new_cs) {
 
		if (new_cs->status > STATUS_AUTH) {
 
			SEND_COMMAND(PACKET_SERVER_QUIT)(new_cs, cs->index, str2);
 
		}
 
	}
 

	
 
	cs->quited = true;
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_ACK)
 
{
 
	// The client received the frame, make note of it
 
	cs->last_frame = NetworkRecv_uint32(p);
 
	// With those 2 values we can calculate the lag realtime
 
	cs->last_frame_server = _frame_counter;
 

	
 
	// The client is now really active
 
	if (cs->status == STATUS_PRE_ACTIVE)
 
		cs->status = STATUS_ACTIVE;
 
}
 

	
 

	
 

	
 
void NetworkServer_HandleChat(NetworkAction action, DestType desttype, int dest, const char *msg, byte from_index)
 
{
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
	NetworkClientInfo *ci, *ci_own, *ci_to;
 

	
 
	switch (desttype) {
 
	case DESTTYPE_CLIENT:
 
		if (dest == 1) {
 
			ci = NetworkFindClientInfoFromIndex(from_index);
 
			if (ci != NULL)
 
				NetworkTextMessage(action, GetDrawStringPlayerColor(ci->client_playas-1), ci->client_name, "%s", msg);
 
		} else {
 
			FOR_ALL_CLIENTS(cs) {
 
				if (cs->index == dest) {
 
					SEND_COMMAND(PACKET_SERVER_CHAT)(cs, action, from_index, msg);
 
					break;
 
				}
 
			}
 
		}
 

	
 
		// Display the message locally (so you know you have sent it)
 
		if (from_index != dest) {
 
			if (from_index == 1) {
 
				ci = NetworkFindClientInfoFromIndex(from_index);
 
				ci_to = NetworkFindClientInfoFromIndex(dest);
 
				if (ci != NULL && ci_to != NULL)
 
					NetworkTextMessage(NETWORK_ACTION_CHAT_TO_CLIENT, GetDrawStringPlayerColor(ci->client_playas-1), ci_to->client_name, "%s", msg);
 
@@ -1015,135 +1015,135 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT
 
	if (ci->client_playas <= MAX_PLAYERS) {
 
		ttd_strlcpy(_network_player_info[ci->client_playas - 1].password, password, sizeof(_network_player_info[ci->client_playas - 1].password));
 
	}
 
}
 

	
 
DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_NAME)
 
{
 
	char name[NETWORK_NAME_LENGTH];
 
	NetworkClientInfo *ci;
 

	
 
	NetworkRecv_string(p, name, sizeof(name));
 
	ci = DEREF_CLIENT_INFO(cs);
 

	
 
	if (ci != NULL) {
 
		// Display change
 
		if (NetworkFindName(name)) {
 
			NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, ci->client_name, name);
 
			ttd_strlcpy(ci->client_name, name, sizeof(ci->client_name));
 
			NetworkUpdateClientInfo(ci->client_index);
 
		}
 
	}
 
}
 

	
 
// The layout for the receive-functions by the server
 
typedef void NetworkServerPacket(ClientState *cs, Packet *p);
 
typedef void NetworkServerPacket(NetworkClientState *cs, Packet *p);
 

	
 

	
 
// This array matches PacketType. At an incoming
 
//  packet it is matches against this array
 
//  and that way the right function to handle that
 
//  packet is found.
 
static NetworkServerPacket* const _network_server_packet[] = {
 
	NULL, /*PACKET_SERVER_FULL,*/
 
	RECEIVE_COMMAND(PACKET_CLIENT_JOIN),
 
	NULL, /*PACKET_SERVER_ERROR,*/
 
	RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO),
 
	NULL, /*PACKET_SERVER_COMPANY_INFO,*/
 
	NULL, /*PACKET_SERVER_CLIENT_INFO,*/
 
	NULL, /*PACKET_SERVER_NEED_PASSWORD,*/
 
	RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD),
 
	NULL, /*PACKET_SERVER_WELCOME,*/
 
	RECEIVE_COMMAND(PACKET_CLIENT_GETMAP),
 
	NULL, /*PACKET_SERVER_WAIT,*/
 
	NULL, /*PACKET_SERVER_MAP,*/
 
	RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK),
 
	NULL, /*PACKET_SERVER_JOIN,*/
 
	NULL, /*PACKET_SERVER_FRAME,*/
 
	NULL, /*PACKET_SERVER_SYNC,*/
 
	RECEIVE_COMMAND(PACKET_CLIENT_ACK),
 
	RECEIVE_COMMAND(PACKET_CLIENT_COMMAND),
 
	NULL, /*PACKET_SERVER_COMMAND,*/
 
	RECEIVE_COMMAND(PACKET_CLIENT_CHAT),
 
	NULL, /*PACKET_SERVER_CHAT,*/
 
	RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD),
 
	RECEIVE_COMMAND(PACKET_CLIENT_SET_NAME),
 
	RECEIVE_COMMAND(PACKET_CLIENT_QUIT),
 
	RECEIVE_COMMAND(PACKET_CLIENT_ERROR),
 
	NULL, /*PACKET_SERVER_QUIT,*/
 
	NULL, /*PACKET_SERVER_ERROR_QUIT,*/
 
	NULL, /*PACKET_SERVER_SHUTDOWN,*/
 
	NULL, /*PACKET_SERVER_NEWGAME,*/
 
};
 

	
 
// If this fails, check the array above with network_data.h
 
assert_compile(lengthof(_network_server_packet) == PACKET_END);
 

	
 

	
 
extern const SettingDesc patch_settings[];
 

	
 
// This is a TEMPORARY solution to get the patch-settings
 
//  to the client. When the patch-settings are saved in the savegame
 
//  this should be removed!!
 
void NetworkSendPatchSettings(ClientState *cs)
 
void NetworkSendPatchSettings(NetworkClientState *cs)
 
{
 
	const SettingDesc *item;
 
	Packet *p = NetworkSend_Init(PACKET_SERVER_MAP);
 
	NetworkSend_uint8(p, MAP_PACKET_PATCH);
 
	// Now send all the patch-settings in a pretty order..
 

	
 
	item = patch_settings;
 

	
 
	while (item->name != NULL) {
 
		switch (item->flags) {
 
			case SDT_BOOL:
 
			case SDT_INT8:
 
			case SDT_UINT8:
 
				NetworkSend_uint8(p, *(uint8 *)item->ptr);
 
				break;
 
			case SDT_INT16:
 
			case SDT_UINT16:
 
				NetworkSend_uint16(p, *(uint16 *)item->ptr);
 
				break;
 
			case SDT_INT32:
 
			case SDT_UINT32:
 
				NetworkSend_uint32(p, *(uint32 *)item->ptr);
 
				break;
 
		}
 
		item++;
 
	}
 

	
 
	NetworkSend_Packet(p, cs);
 
}
 

	
 
// This update the company_info-stuff
 
void NetworkPopulateCompanyInfo(void)
 
{
 
	char password[NETWORK_PASSWORD_LENGTH];
 
	Player *p;
 
	Vehicle *v;
 
	Station *s;
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
	NetworkClientInfo *ci;
 
	int i;
 
	uint16 months_empty;
 

	
 
	FOR_ALL_PLAYERS(p) {
 
		if (!p->is_active) {
 
			memset(&_network_player_info[p->index], 0, sizeof(NetworkPlayerInfo));
 
			continue;
 
		}
 

	
 
		// Clean the info but not the password
 
		ttd_strlcpy(password, _network_player_info[p->index].password, sizeof(password));
 
		months_empty = _network_player_info[p->index].months_empty;
 
		memset(&_network_player_info[p->index], 0, sizeof(NetworkPlayerInfo));
 
		_network_player_info[p->index].months_empty = months_empty;
 
		ttd_strlcpy(_network_player_info[p->index].password, password, sizeof(_network_player_info[p->index].password));
 

	
 
		// Grap the company name
 
		GetString(_network_player_info[p->index].company_name, p->name_1);
 

	
 
		// Check the income
 
		if (_cur_year - 1 == p->inaugurated_year)
 
			// The player is here just 1 year, so display [2], else display[1]
 
			for (i = 0; i < 13; i++)
 
@@ -1201,69 +1201,69 @@ void NetworkPopulateCompanyInfo(void)
 

	
 
	ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
 
	// Register local player (if not dedicated)
 
	if (ci != NULL && ci->client_playas > 0  && ci->client_playas <= MAX_PLAYERS)
 
		ttd_strlcpy(_network_player_info[ci->client_playas-1].players, ci->client_name, sizeof(_network_player_info[ci->client_playas-1].players));
 

	
 
	FOR_ALL_CLIENTS(cs) {
 
		char client_name[NETWORK_NAME_LENGTH];
 

	
 
		NetworkGetClientName(client_name, sizeof(client_name), cs);
 

	
 
		ci = DEREF_CLIENT_INFO(cs);
 
		if (ci != NULL && ci->client_playas > 0 && ci->client_playas <= MAX_PLAYERS) {
 
			if (strlen(_network_player_info[ci->client_playas-1].players) != 0)
 
				strncat(_network_player_info[ci->client_playas-1].players, ", ", sizeof(_network_player_info[ci->client_playas-1].players));
 

	
 
			strncat(_network_player_info[ci->client_playas-1].players, client_name, sizeof(_network_player_info[ci->client_playas-1].players));
 
		}
 
	}
 
}
 

	
 
// Send a packet to all clients with updated info about this client_index
 
void NetworkUpdateClientInfo(uint16 client_index)
 
{
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
	NetworkClientInfo *ci;
 

	
 
	ci = NetworkFindClientInfoFromIndex(client_index);
 

	
 
	if (ci == NULL)
 
		return;
 

	
 
	FOR_ALL_CLIENTS(cs) {
 
		SEND_COMMAND(PACKET_SERVER_CLIENT_INFO)(cs, ci);
 
	}
 
}
 

	
 
/* Check if the server has autoclean_companies activated
 
    Two things happen:
 
      1) If a company is not protected, it is closed after 1 year (for example)
 
      2) If a company is protected, protection is disabled after 3 years (for example)
 
           (and item 1. happens a year later) */
 
static void NetworkAutoCleanCompanies()
 
{
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
	NetworkClientInfo *ci;
 
	Player *p;
 
	bool clients_in_company[MAX_PLAYERS];
 

	
 
	if (!_network_autoclean_companies)
 
		return;
 

	
 
	memset(clients_in_company, 0, sizeof(clients_in_company));
 

	
 
	/* Detect the active companies */
 
	FOR_ALL_CLIENTS(cs) {
 
		ci = DEREF_CLIENT_INFO(cs);
 
		if (ci->client_playas >= 1 && ci->client_playas <= MAX_PLAYERS) {
 
			clients_in_company[ci->client_playas-1] = true;
 
		}
 
	}
 
	if (!_network_dedicated) {
 
		ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
 
		if (ci->client_playas >= 1 && ci->client_playas <= MAX_PLAYERS) {
 
			clients_in_company[ci->client_playas-1] = true;
 
		}
 
	}
 

	
 
	/* Go through all the comapnies */
 
@@ -1279,183 +1279,183 @@ static void NetworkAutoCleanCompanies()
 
			/* Is the company empty for autoclean_unprotected-months, and is there no protection? */
 
			if (_network_player_info[p->index].months_empty > _network_autoclean_unprotected && _network_player_info[p->index].password[0] == '\0') {
 
				/* Shut the company down */
 
				DoCommandP(0, 2, p->index, NULL, CMD_PLAYER_CTRL);
 
				IConsolePrintF(_iconsole_color_default, "Auto-cleaned company #%d", p->index+1);
 
			}
 
			/* Is the compnay empty for autoclean_protected-months, and there is a protection? */
 
			if (_network_player_info[p->index].months_empty > _network_autoclean_protected && _network_player_info[p->index].password[0] != '\0') {
 
				/* Unprotect the company */
 
				_network_player_info[p->index].password[0] = '\0';
 
				IConsolePrintF(_iconsole_color_default, "Auto-removed protection from company #%d", p->index+1);
 
				_network_player_info[p->index].months_empty = 0;
 
			}
 
		} else {
 
			/* It is not empty, reset the date */
 
			_network_player_info[p->index].months_empty = 0;
 
		}
 
	}
 
}
 

	
 
// This function changes new_name to a name that is unique (by adding #1 ...)
 
//  and it returns true if that succeeded.
 
bool NetworkFindName(char new_name[NETWORK_NAME_LENGTH])
 
{
 
	ClientState *new_cs;
 
	NetworkClientState *new_cs;
 
	NetworkClientInfo *ci;
 
	bool found_name = false;
 
	byte number = 0;
 
	char original_name[NETWORK_NAME_LENGTH];
 

	
 
	// We use NETWORK_NAME_LENGTH in here, because new_name is really a pointer
 
	ttd_strlcpy(original_name, new_name, NETWORK_NAME_LENGTH);
 

	
 
	while (!found_name) {
 
		found_name = true;
 
		FOR_ALL_CLIENTS(new_cs) {
 
			ci = DEREF_CLIENT_INFO(new_cs);
 
			if (strncmp(ci->client_name, new_name, NETWORK_NAME_LENGTH) == 0) {
 
				// Name already in use
 
				found_name = false;
 
				break;
 
			}
 
		}
 
		// Check if it is the same as the server-name
 
		ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
 
		if (ci != NULL) {
 
			if (strncmp(ci->client_name, new_name, NETWORK_NAME_LENGTH) == 0) {
 
				// Name already in use
 
				found_name = false;
 
			}
 
		}
 

	
 
		if (!found_name) {
 
			// Try a new name (<name> #1, <name> #2, and so on)
 

	
 
			// Stop if we tried for more then 50 times..
 
			if (number++ > 50) break;
 
			snprintf(new_name, NETWORK_NAME_LENGTH, "%s #%d", original_name, number);
 
		}
 
	}
 

	
 
	return found_name;
 
}
 

	
 
// Reads a packet from the stream
 
bool NetworkServer_ReadPackets(ClientState *cs)
 
bool NetworkServer_ReadPackets(NetworkClientState *cs)
 
{
 
	Packet *p;
 
	NetworkRecvStatus res;
 
	while((p = NetworkRecv_Packet(cs, &res)) != NULL) {
 
		byte type = NetworkRecv_uint8(p);
 
		if (type < PACKET_END && _network_server_packet[type] != NULL)
 
			_network_server_packet[type](cs, p);
 
		else
 
			DEBUG(net, 0)("[NET][Server] Received invalid packet type %d", type);
 
		free(p);
 
	}
 

	
 
	return true;
 
}
 

	
 
// Handle the local command-queue
 
void NetworkHandleCommandQueue(ClientState *cs) {
 
void NetworkHandleCommandQueue(NetworkClientState *cs) {
 
	if (cs->command_queue != NULL) {
 
		CommandPacket *cp;
 
		CommandPacket *cp_prev;
 

	
 
		cp = cs->command_queue;
 
		cp_prev = NULL;
 

	
 
		while (cp != NULL) {
 
			SEND_COMMAND(PACKET_SERVER_COMMAND)(cs, cp);
 

	
 
			if (cp_prev != NULL) {
 
				cp_prev->next = cp->next;
 
				free(cp);
 
				cp = cp_prev->next;
 
			} else {
 
				// This means we are at our first packet
 
				cs->command_queue = cp->next;
 
				free(cp);
 
				cp = cs->command_queue;
 
			}
 
		}
 
	}
 
}
 

	
 
// This is called every tick if this is a _network_server
 
void NetworkServer_Tick(void)
 
{
 
#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
 
	static uint32 last_sync_frame = 0;
 
#endif
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
	bool send_frame = false;
 

	
 
	// Update max-frame-counter
 
	if (_frame_counter > _frame_counter_max) {
 
		_frame_counter_max = _frame_counter + _network_frame_freq;
 
		send_frame = true;
 
	}
 

	
 
	// Now we are done with the frame, inform the clients that they can
 
	//  do their frame!
 
	FOR_ALL_CLIENTS(cs) {
 
		// Check if the speed of the client is what we can expect from a client
 
		if (cs->status == STATUS_ACTIVE) {
 
			// 1 lag-point per day
 
			int lag = NetworkCalculateLag(cs) / DAY_TICKS;
 
			if (lag > 0) {
 
				if (lag > 3) {
 
					// Client did still not report in after 4 game-day, drop him
 
					//  (that is, the 3 of above, + 1 before any lag is counted)
 
					IConsolePrintF(_iconsole_color_error,"Client #%d is dropped because the client did not respond for more then 4 game-days", cs->index);
 
					CloseClient(cs);
 
					NetworkCloseClient(cs);
 
					continue;
 
				}
 

	
 
				// Report once per time we detect the lag
 
				if (cs->lag_test == 0) {
 
					IConsolePrintF(_iconsole_color_warning,"[%d] Client #%d is slow, try increasing *net_frame_freq to a higher value!", _frame_counter, cs->index);
 
					cs->lag_test = 1;
 
				}
 
			} else {
 
				cs->lag_test = 0;
 
			}
 
		}
 

	
 

	
 
		// Check if we can send command, and if we have anything in the queue
 
		if (cs->status > STATUS_DONE_MAP) {
 
			NetworkHandleCommandQueue(cs);
 
		}
 

	
 
		// Do we need to send the new frame-packet?
 
		if (send_frame && cs->status == STATUS_ACTIVE) {
 
			SEND_COMMAND(PACKET_SERVER_FRAME)(cs);
 
		}
 
#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
 
		// Is it time to send a sync-packet to all clients?
 
		if (last_sync_frame + _network_sync_freq < _frame_counter) {
 
			SEND_COMMAND(PACKET_SERVER_SYNC)(cs);
 
		}
 
#endif
 
	}
 

	
 
#ifndef ENABLE_NETWORK_SYNC_EVERY_FRAME
 
	// Update the last_sync_frame if needed!
 
	if (last_sync_frame + _network_sync_freq < _frame_counter) {
 
		last_sync_frame = _frame_counter;
 
	}
 
#endif
 

	
 
	/* See if we need to advertise */
 
	NetworkUDPAdvertise();
 
}
 

	
 
void NetworkServerMonthlyLoop()
 
void NetworkServerMonthlyLoop(void)
 
{
 
	NetworkAutoCleanCompanies();
 
}
 

	
 
#endif /* ENABLE_NETWORK */
network_server.h
Show inline comments
 
#ifndef NETWORK_SERVER_H
 
#define NETWORK_SERVER_H
 

	
 
#ifdef ENABLE_NETWORK
 

	
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_MAP);
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(ClientState *cs, uint16 client_index, NetworkErrorCode errorno);
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(ClientState *cs, NetworkErrorCode error);
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR_QUIT)(NetworkClientState *cs, uint16 client_index, NetworkErrorCode errorno);
 
DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkClientState *cs, NetworkErrorCode error);
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN);
 
DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME);
 

	
 
bool NetworkFindName(char new_name[NETWORK_NAME_LENGTH]);
 
void NetworkServer_HandleChat(NetworkAction action, DestType desttype, int dest, const char *msg, byte from_index);
 

	
 
bool NetworkServer_ReadPackets(ClientState *cs);
 
void NetworkServer_Tick();
 
void NetworkServerMonthlyLoop();
 
bool NetworkServer_ReadPackets(NetworkClientState *cs);
 
void NetworkServer_Tick(void);
 
void NetworkServerMonthlyLoop(void);
 

	
 
#endif /* ENABLE_NETWORK */
 

	
 
#endif // NETWORK_SERVER_H
network_udp.c
Show inline comments
 
@@ -85,49 +85,49 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVE
 
		item->info.server_lang = NetworkRecv_uint8(p);
 
		item->info.use_password = NetworkRecv_uint8(p);
 
		item->info.clients_max = NetworkRecv_uint8(p);
 
		item->info.clients_on = NetworkRecv_uint8(p);
 
		item->info.spectators_on = NetworkRecv_uint8(p);
 
		item->info.game_date = NetworkRecv_uint16(p);
 
		item->info.start_date = NetworkRecv_uint16(p);
 
		NetworkRecv_string(p, item->info.map_name, sizeof(item->info.map_name));
 
		item->info.map_width = NetworkRecv_uint16(p);
 
		item->info.map_height = NetworkRecv_uint16(p);
 
		item->info.map_set = NetworkRecv_uint8(p);
 
		item->info.dedicated = NetworkRecv_uint8(p);
 

	
 
		if (item->info.hostname[0] == '\0')
 
			snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", inet_ntoa(client_addr->sin_addr));
 
	}
 

	
 
	item->online = true;
 

	
 
	UpdateNetworkGameWindow(false);
 
}
 

	
 
DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_DETAIL_INFO)
 
{
 
	ClientState *cs;
 
	NetworkClientState *cs;
 
	NetworkClientInfo *ci;
 
	Packet *packet;
 
	Player *player;
 
	byte active = 0;
 
	byte current = 0;
 
	int i;
 

	
 
	// Just a fail-safe.. should never happen
 
	if (!_network_udp_server)
 
		return;
 

	
 
	packet = NetworkSend_Init(PACKET_UDP_SERVER_DETAIL_INFO);
 

	
 
	FOR_ALL_PLAYERS(player) {
 
		if (player->is_active)
 
			active++;
 
	}
 

	
 
	/* Send the amount of active companies */
 
	NetworkSend_uint8 (packet, NETWORK_COMPANY_INFO_VERSION);
 
	NetworkSend_uint8 (packet, active);
 

	
 
	/* Fetch the latest version of everything */
 
	NetworkPopulateCompanyInfo();
 
@@ -450,49 +450,49 @@ void NetworkUDPQueryServer(const byte* h
 

	
 
	out_addr.sin_family = AF_INET;
 
	out_addr.sin_port = htons(port);
 
	out_addr.sin_addr.s_addr = NetworkResolveHost(host);
 

	
 
	// Clear item in gamelist
 
	item = NetworkGameListAddItem(inet_addr(inet_ntoa(out_addr.sin_addr)), ntohs(out_addr.sin_port));
 
	memset(&item->info, 0, sizeof(item->info));
 
	snprintf(item->info.server_name, sizeof(item->info.server_name), "%s", hostname);
 
	snprintf(item->info.hostname, sizeof(item->info.hostname), "%s", hostname);
 
	item->online = false;
 

	
 
	// Init the packet
 
	p = NetworkSend_Init(PACKET_UDP_CLIENT_FIND_SERVER);
 

	
 
	NetworkSendUDP_Packet(p, &out_addr);
 

	
 
	free(p);
 

	
 
	UpdateNetworkGameWindow(false);
 
}
 

	
 
/* Register us to the master server
 
     This function checks if it needs to send an advertise */
 
void NetworkUDPAdvertise()
 
void NetworkUDPAdvertise(void)
 
{
 
	struct sockaddr_in out_addr;
 
	Packet *p;
 

	
 
	/* Check if we should send an advertise */
 
	if (!_networking || !_network_server || !_network_udp_server || !_network_advertise)
 
		return;
 

	
 
	/* Only send once in the 450 game-days (about 15 minutes) */
 
	if (_network_last_advertise_date + 450 > _date)
 
		return;
 
	_network_last_advertise_date = _date;
 

	
 
	/* Find somewhere to send */
 
	out_addr.sin_family = AF_INET;
 
	out_addr.sin_port = htons(NETWORK_MASTER_SERVER_PORT);
 
	out_addr.sin_addr.s_addr = NetworkResolveHost(NETWORK_MASTER_SERVER_HOST);
 

	
 
	DEBUG(net, 1)("[NET][UDP] Advertising to master server");
 

	
 
	/* Send the packet */
 
	p = NetworkSend_Init(PACKET_UDP_SERVER_REGISTER);
 
	/* Packet is: WELCOME_MESSAGE, Version, server_port */
 
	NetworkSend_string(p, NETWORK_MASTER_SERVER_WELCOME_MESSAGE);
network_udp.h
Show inline comments
 
#ifndef NETWORK_LAN_H
 
#define NETWORK_LAN_H
 

	
 
void NetworkUDPInitialize(void);
 
bool NetworkUDPListen(uint32 host, uint16 port);
 
void NetworkUDPReceive(void);
 
void NetworkUDPSearchGame(void);
 
void NetworkUDPQueryServer(const byte* host, unsigned short port);
 
void NetworkUDPAdvertise();
 
void NetworkUDPAdvertise(void);
 

	
 
#endif /* NETWORK_LAN_H */
0 comments (0 inline, 0 general)