Allow 256 NewGRFs in multiplayer
Add extended network format for server info Add general UDP packet fragmentation system Fix map dimensions >= 64k Increase length of server revision string Maintain backwards compatibility with trunk for advertisement/server listing
This commit is contained in:
@@ -44,6 +44,7 @@ static const uint NETWORK_COMPANY_NAME_LENGTH = 128; ///< The maxim
|
|||||||
static const uint NETWORK_HOSTNAME_LENGTH = 80; ///< The maximum length of the host name, in bytes including '\0'
|
static const uint NETWORK_HOSTNAME_LENGTH = 80; ///< The maximum length of the host name, in bytes including '\0'
|
||||||
static const uint NETWORK_SERVER_ID_LENGTH = 33; ///< The maximum length of the network id of the servers, in bytes including '\0'
|
static const uint NETWORK_SERVER_ID_LENGTH = 33; ///< The maximum length of the network id of the servers, in bytes including '\0'
|
||||||
static const uint NETWORK_REVISION_LENGTH = 15; ///< The maximum length of the revision, in bytes including '\0'
|
static const uint NETWORK_REVISION_LENGTH = 15; ///< The maximum length of the revision, in bytes including '\0'
|
||||||
|
static const uint NETWORK_LONG_REVISION_LENGTH = 64; ///< The maximum length of the revision, in bytes including '\0'
|
||||||
static const uint NETWORK_PASSWORD_LENGTH = 33; ///< The maximum length of the password, in bytes including '\0' (must be >= NETWORK_SERVER_ID_LENGTH)
|
static const uint NETWORK_PASSWORD_LENGTH = 33; ///< The maximum length of the password, in bytes including '\0' (must be >= NETWORK_SERVER_ID_LENGTH)
|
||||||
static const uint NETWORK_CLIENTS_LENGTH = 200; ///< The maximum length for the list of clients that controls a company, in bytes including '\0'
|
static const uint NETWORK_CLIENTS_LENGTH = 200; ///< The maximum length for the list of clients that controls a company, in bytes including '\0'
|
||||||
static const uint NETWORK_CLIENT_NAME_LENGTH = 25; ///< The maximum length of a client's name, in bytes including '\0'
|
static const uint NETWORK_CLIENT_NAME_LENGTH = 25; ///< The maximum length of a client's name, in bytes including '\0'
|
||||||
|
@@ -37,11 +37,12 @@ struct NetworkGameInfo : NetworkServerGameInfo {
|
|||||||
GRFConfig *grfconfig; ///< List of NewGRF files used
|
GRFConfig *grfconfig; ///< List of NewGRF files used
|
||||||
Date start_date; ///< When the game started
|
Date start_date; ///< When the game started
|
||||||
Date game_date; ///< Current date
|
Date game_date; ///< Current date
|
||||||
uint16 map_width; ///< Map width
|
uint32 map_width; ///< Map width
|
||||||
uint16 map_height; ///< Map height
|
uint32 map_height; ///< Map height
|
||||||
char server_name[NETWORK_NAME_LENGTH]; ///< Server name
|
char server_name[NETWORK_NAME_LENGTH]; ///< Server name
|
||||||
char hostname[NETWORK_HOSTNAME_LENGTH]; ///< Hostname of the server (if any)
|
char hostname[NETWORK_HOSTNAME_LENGTH]; ///< Hostname of the server (if any)
|
||||||
char server_revision[NETWORK_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0)
|
char short_server_revision[NETWORK_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0) (truncated)
|
||||||
|
char server_revision[NETWORK_LONG_REVISION_LENGTH]; ///< The version number the server is using (e.g.: 'r304' or 0.5.0)
|
||||||
bool dedicated; ///< Is this a dedicated server?
|
bool dedicated; ///< Is this a dedicated server?
|
||||||
bool version_compatible; ///< Can we connect to this server or not? (based on server_revision)
|
bool version_compatible; ///< Can we connect to this server or not? (based on server_revision)
|
||||||
bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match
|
bool compatible; ///< Can we connect to this server or not? (based on server_revision _and_ grf_match
|
||||||
|
@@ -42,14 +42,8 @@ Packet::Packet(NetworkSocketHandler *cs)
|
|||||||
*/
|
*/
|
||||||
Packet::Packet(PacketType type)
|
Packet::Packet(PacketType type)
|
||||||
{
|
{
|
||||||
this->cs = NULL;
|
|
||||||
this->next = NULL;
|
|
||||||
|
|
||||||
/* Skip the size so we can write that in before sending the packet */
|
|
||||||
this->pos = 0;
|
|
||||||
this->size = sizeof(PacketSize);
|
|
||||||
this->buffer = MallocT<byte>(SHRT_MAX);
|
this->buffer = MallocT<byte>(SHRT_MAX);
|
||||||
this->buffer[this->size++] = type;
|
this->ResetState(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -60,6 +54,17 @@ Packet::~Packet()
|
|||||||
free(this->buffer);
|
free(this->buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Packet::ResetState(PacketType type)
|
||||||
|
{
|
||||||
|
this->cs = NULL;
|
||||||
|
this->next = NULL;
|
||||||
|
|
||||||
|
/* Skip the size so we can write that in before sending the packet */
|
||||||
|
this->pos = 0;
|
||||||
|
this->size = sizeof(PacketSize);
|
||||||
|
this->buffer[this->size++] = type;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes the packet size from the raw packet from packet->size
|
* Writes the packet size from the raw packet from packet->size
|
||||||
*/
|
*/
|
||||||
@@ -181,16 +186,17 @@ void Packet::Send_binary(const char *data, const size_t size)
|
|||||||
/**
|
/**
|
||||||
* Is it safe to read from the packet, i.e. didn't we run over the buffer ?
|
* Is it safe to read from the packet, i.e. didn't we run over the buffer ?
|
||||||
* @param bytes_to_read The amount of bytes we want to try to read.
|
* @param bytes_to_read The amount of bytes we want to try to read.
|
||||||
|
* @param non_fatal True if a false return value is considered non-fatal, and will not raise an error.
|
||||||
* @return True if that is safe, otherwise false.
|
* @return True if that is safe, otherwise false.
|
||||||
*/
|
*/
|
||||||
bool Packet::CanReadFromPacket(uint bytes_to_read)
|
bool Packet::CanReadFromPacket(uint bytes_to_read, bool non_fatal)
|
||||||
{
|
{
|
||||||
/* Don't allow reading from a quit client/client who send bad data */
|
/* Don't allow reading from a quit client/client who send bad data */
|
||||||
if (this->cs->HasClientQuit()) return false;
|
if (this->cs->HasClientQuit()) return false;
|
||||||
|
|
||||||
/* Check if variable is within packet-size */
|
/* Check if variable is within packet-size */
|
||||||
if (this->pos + bytes_to_read > this->size) {
|
if (this->pos + bytes_to_read > this->size) {
|
||||||
this->cs->NetworkSocketHandler::CloseConnection();
|
if (!non_fatal) this->cs->NetworkSocketHandler::CloseConnection();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -64,6 +64,8 @@ public:
|
|||||||
Packet(PacketType type);
|
Packet(PacketType type);
|
||||||
~Packet();
|
~Packet();
|
||||||
|
|
||||||
|
void ResetState(PacketType type);
|
||||||
|
|
||||||
/* Sending/writing of packets */
|
/* Sending/writing of packets */
|
||||||
void PrepareToSend();
|
void PrepareToSend();
|
||||||
|
|
||||||
@@ -79,7 +81,7 @@ public:
|
|||||||
void ReadRawPacketSize();
|
void ReadRawPacketSize();
|
||||||
void PrepareToRead();
|
void PrepareToRead();
|
||||||
|
|
||||||
bool CanReadFromPacket (uint bytes_to_read);
|
bool CanReadFromPacket (uint bytes_to_read, bool non_fatal = false);
|
||||||
bool Recv_bool ();
|
bool Recv_bool ();
|
||||||
uint8 Recv_uint8 ();
|
uint8 Recv_uint8 ();
|
||||||
uint16 Recv_uint16();
|
uint16 Recv_uint16();
|
||||||
|
@@ -184,11 +184,6 @@ Packet *NetworkTCPSocketHandler::ReceivePacket()
|
|||||||
|
|
||||||
/* Read the packet size from the received packet */
|
/* Read the packet size from the received packet */
|
||||||
p->ReadRawPacketSize();
|
p->ReadRawPacketSize();
|
||||||
|
|
||||||
if (p->size > SEND_MTU) {
|
|
||||||
this->CloseConnection();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read rest of packet */
|
/* Read rest of packet */
|
||||||
|
@@ -16,10 +16,14 @@
|
|||||||
#include "../../stdafx.h"
|
#include "../../stdafx.h"
|
||||||
#include "../../date_func.h"
|
#include "../../date_func.h"
|
||||||
#include "../../debug.h"
|
#include "../../debug.h"
|
||||||
|
#include "../../core/random_func.hpp"
|
||||||
|
#include "../../fios.h"
|
||||||
#include "udp.h"
|
#include "udp.h"
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
|
extern const uint8 _out_of_band_grf_md5[16];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an UDP socket but don't listen yet.
|
* Create an UDP socket but don't listen yet.
|
||||||
* @param bind the addresses to bind to.
|
* @param bind the addresses to bind to.
|
||||||
@@ -37,6 +41,8 @@ NetworkUDPSocketHandler::NetworkUDPSocketHandler(NetworkAddressList *bind)
|
|||||||
*this->bind.Append() = NetworkAddress(NULL, 0, AF_INET);
|
*this->bind.Append() = NetworkAddress(NULL, 0, AF_INET);
|
||||||
*this->bind.Append() = NetworkAddress(NULL, 0, AF_INET6);
|
*this->bind.Append() = NetworkAddress(NULL, 0, AF_INET6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->fragment_token = ((uint64) InteractiveRandom()) | (((uint64) InteractiveRandom()) << 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -84,6 +90,33 @@ void NetworkUDPSocketHandler::SendPacket(Packet *p, NetworkAddress *recv, bool a
|
|||||||
{
|
{
|
||||||
if (this->sockets.Length() == 0) this->Listen();
|
if (this->sockets.Length() == 0) this->Listen();
|
||||||
|
|
||||||
|
if (p->size > SEND_MTU) {
|
||||||
|
p->PrepareToSend();
|
||||||
|
|
||||||
|
uint64 token = this->fragment_token++;
|
||||||
|
const uint PAYLOAD_MTU = SEND_MTU - (1 + 2 + 8 + 1 + 1 + 2);
|
||||||
|
|
||||||
|
const uint8 frag_count = (p->size + PAYLOAD_MTU - 1) / PAYLOAD_MTU;
|
||||||
|
|
||||||
|
Packet frag(PACKET_UDP_EX_MULTI);
|
||||||
|
uint8 current_frag = 0;
|
||||||
|
uint16 offset = 0;
|
||||||
|
while (offset < p->size) {
|
||||||
|
uint16 payload_size = min<uint>(PAYLOAD_MTU, p->size - offset);
|
||||||
|
frag.Send_uint64(token);
|
||||||
|
frag.Send_uint8 (current_frag);
|
||||||
|
frag.Send_uint8 (frag_count);
|
||||||
|
frag.Send_uint16 (payload_size);
|
||||||
|
frag.Send_binary((const char *) p->buffer + offset, payload_size);
|
||||||
|
current_frag++;
|
||||||
|
offset += payload_size;
|
||||||
|
this->SendPacket(&frag, recv, all, broadcast);
|
||||||
|
frag.ResetState(PACKET_UDP_EX_MULTI);
|
||||||
|
}
|
||||||
|
assert_msg(current_frag == frag_count, "%u, %u", current_frag, frag_count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
|
for (SocketList::iterator s = this->sockets.Begin(); s != this->sockets.End(); s++) {
|
||||||
/* Make a local copy because if we resolve it we cannot
|
/* Make a local copy because if we resolve it we cannot
|
||||||
* easily unresolve it so we can resolve it later again. */
|
* easily unresolve it so we can resolve it later again. */
|
||||||
@@ -142,7 +175,7 @@ void NetworkUDPSocketHandler::ReceivePackets()
|
|||||||
/* If the size does not match the packet must be corrupted.
|
/* If the size does not match the packet must be corrupted.
|
||||||
* Otherwise it will be marked as corrupted later on. */
|
* Otherwise it will be marked as corrupted later on. */
|
||||||
if (nbytes != p.size) {
|
if (nbytes != p.size) {
|
||||||
DEBUG(net, 1, "received a packet with mismatching size from %s", address.GetAddressAsString());
|
DEBUG(net, 1, "received a packet with mismatching size from %s, (%u, %u)", address.GetAddressAsString(), nbytes, p.size);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,11 +216,24 @@ void NetworkUDPSocketHandler::SendNetworkGameInfo(Packet *p, const NetworkGameIn
|
|||||||
for (c = info->grfconfig; c != NULL; c = c->next) {
|
for (c = info->grfconfig; c != NULL; c = c->next) {
|
||||||
if (!HasBit(c->flags, GCF_STATIC)) count++;
|
if (!HasBit(c->flags, GCF_STATIC)) count++;
|
||||||
}
|
}
|
||||||
p->Send_uint8 (count); // Send number of GRFs
|
p->Send_uint8(min<uint>(count, NETWORK_MAX_GRF_COUNT)); // Send number of GRFs
|
||||||
|
|
||||||
/* Send actual GRF Identifications */
|
/* Send actual GRF Identifications */
|
||||||
|
uint index = 0;
|
||||||
for (c = info->grfconfig; c != NULL; c = c->next) {
|
for (c = info->grfconfig; c != NULL; c = c->next) {
|
||||||
if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident);
|
if (!HasBit(c->flags, GCF_STATIC)) {
|
||||||
|
if (index == NETWORK_MAX_GRF_COUNT - 1 && count > NETWORK_MAX_GRF_COUNT) {
|
||||||
|
/* Send fake GRF ID */
|
||||||
|
|
||||||
|
p->Send_uint32(0x56D2B000);
|
||||||
|
p->Send_binary((const char*) _out_of_band_grf_md5, 16);
|
||||||
|
} else if (index >= NETWORK_MAX_GRF_COUNT) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
this->SendGRFIdentifier(p, &c->ident);
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +248,7 @@ void NetworkUDPSocketHandler::SendNetworkGameInfo(Packet *p, const NetworkGameIn
|
|||||||
|
|
||||||
/* NETWORK_GAME_INFO_VERSION = 1 */
|
/* NETWORK_GAME_INFO_VERSION = 1 */
|
||||||
p->Send_string(info->server_name);
|
p->Send_string(info->server_name);
|
||||||
p->Send_string(info->server_revision);
|
p->Send_string(info->short_server_revision);
|
||||||
p->Send_uint8 (info->server_lang);
|
p->Send_uint8 (info->server_lang);
|
||||||
p->Send_bool (info->use_password);
|
p->Send_bool (info->use_password);
|
||||||
p->Send_uint8 (info->clients_max);
|
p->Send_uint8 (info->clients_max);
|
||||||
@@ -215,6 +261,56 @@ void NetworkUDPSocketHandler::SendNetworkGameInfo(Packet *p, const NetworkGameIn
|
|||||||
p->Send_bool (info->dedicated);
|
p->Send_bool (info->dedicated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes the NetworkGameInfo struct to the packet
|
||||||
|
* @param p the packet to write the data to
|
||||||
|
* @param info the NetworkGameInfo struct to serialize
|
||||||
|
*/
|
||||||
|
void NetworkUDPSocketHandler::SendNetworkGameInfoExtended(Packet *p, const NetworkGameInfo *info, uint16 version)
|
||||||
|
{
|
||||||
|
p->Send_uint8(0); // version num
|
||||||
|
|
||||||
|
p->Send_uint32(info->game_date);
|
||||||
|
p->Send_uint32(info->start_date);
|
||||||
|
p->Send_uint8 (info->companies_max);
|
||||||
|
p->Send_uint8 (info->companies_on);
|
||||||
|
p->Send_uint8 (info->spectators_max);
|
||||||
|
p->Send_string(info->server_name);
|
||||||
|
p->Send_string(info->server_revision);
|
||||||
|
p->Send_uint8 (info->server_lang);
|
||||||
|
p->Send_bool (info->use_password);
|
||||||
|
p->Send_uint8 (info->clients_max);
|
||||||
|
p->Send_uint8 (info->clients_on);
|
||||||
|
p->Send_uint8 (info->spectators_on);
|
||||||
|
p->Send_string(info->map_name);
|
||||||
|
p->Send_uint32(info->map_width);
|
||||||
|
p->Send_uint32(info->map_height);
|
||||||
|
p->Send_uint8 (info->map_set);
|
||||||
|
p->Send_bool (info->dedicated);
|
||||||
|
|
||||||
|
{
|
||||||
|
/* Only send the GRF Identification (GRF_ID and MD5 checksum) of
|
||||||
|
* the GRFs that are needed, i.e. the ones that the server has
|
||||||
|
* selected in the NewGRF GUI and not the ones that are used due
|
||||||
|
* to the fact that they are in [newgrf-static] in openttd.cfg */
|
||||||
|
const GRFConfig *c;
|
||||||
|
uint count = 0;
|
||||||
|
|
||||||
|
/* Count number of GRFs to send information about */
|
||||||
|
for (c = info->grfconfig; c != NULL; c = c->next) {
|
||||||
|
if (!HasBit(c->flags, GCF_STATIC)) count++;
|
||||||
|
}
|
||||||
|
p->Send_uint32(count); // Send number of GRFs
|
||||||
|
|
||||||
|
/* Send actual GRF Identifications */
|
||||||
|
for (c = info->grfconfig; c != NULL; c = c->next) {
|
||||||
|
if (!HasBit(c->flags, GCF_STATIC)) {
|
||||||
|
this->SendGRFIdentifier(p, &c->ident);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deserializes the NetworkGameInfo struct from the packet
|
* Deserializes the NetworkGameInfo struct from the packet
|
||||||
* @param p the packet to read the data from
|
* @param p the packet to read the data from
|
||||||
@@ -288,6 +384,60 @@ void NetworkUDPSocketHandler::ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo
|
|||||||
if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
|
if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Deserializes the NetworkGameInfo struct from the packet
|
||||||
|
* @param p the packet to read the data from
|
||||||
|
* @param info the NetworkGameInfo to deserialize into
|
||||||
|
*/
|
||||||
|
void NetworkUDPSocketHandler::ReceiveNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info)
|
||||||
|
{
|
||||||
|
static const Date MAX_DATE = ConvertYMDToDate(MAX_YEAR, 11, 31); // December is month 11
|
||||||
|
|
||||||
|
const uint8 version = p->Recv_uint8();
|
||||||
|
if (version > 0) return; // Unknown version
|
||||||
|
|
||||||
|
info->game_info_version = 255;
|
||||||
|
|
||||||
|
info->game_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
|
||||||
|
info->start_date = Clamp(p->Recv_uint32(), 0, MAX_DATE);
|
||||||
|
info->companies_max = p->Recv_uint8 ();
|
||||||
|
info->companies_on = p->Recv_uint8 ();
|
||||||
|
info->spectators_max = p->Recv_uint8 ();
|
||||||
|
p->Recv_string(info->server_name, sizeof(info->server_name));
|
||||||
|
p->Recv_string(info->server_revision, sizeof(info->server_revision));
|
||||||
|
info->server_lang = p->Recv_uint8 ();
|
||||||
|
info->use_password = p->Recv_bool ();
|
||||||
|
info->clients_max = p->Recv_uint8 ();
|
||||||
|
info->clients_on = p->Recv_uint8 ();
|
||||||
|
info->spectators_on = p->Recv_uint8 ();
|
||||||
|
p->Recv_string(info->map_name, sizeof(info->map_name));
|
||||||
|
info->map_width = p->Recv_uint32();
|
||||||
|
info->map_height = p->Recv_uint32();
|
||||||
|
info->map_set = p->Recv_uint8 ();
|
||||||
|
info->dedicated = p->Recv_bool ();
|
||||||
|
|
||||||
|
{
|
||||||
|
GRFConfig **dst = &info->grfconfig;
|
||||||
|
uint i;
|
||||||
|
uint num_grfs = p->Recv_uint32();
|
||||||
|
|
||||||
|
/* Broken/bad data. It cannot have that many NewGRFs. */
|
||||||
|
if (num_grfs > MAX_NEWGRFS) return;
|
||||||
|
|
||||||
|
for (i = 0; i < num_grfs; i++) {
|
||||||
|
GRFConfig *c = new GRFConfig();
|
||||||
|
this->ReceiveGRFIdentifier(p, &c->ident);
|
||||||
|
this->HandleIncomingNetworkGameInfoGRFConfig(c);
|
||||||
|
|
||||||
|
/* Append GRFConfig to the list */
|
||||||
|
*dst = c;
|
||||||
|
dst = &c->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->server_lang >= NETWORK_NUM_LANGUAGES) info->server_lang = 0;
|
||||||
|
if (info->map_set >= NETWORK_NUM_LANDSCAPES) info->map_set = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle an incoming packets by sending it to the correct function.
|
* Handle an incoming packets by sending it to the correct function.
|
||||||
@@ -317,6 +467,9 @@ void NetworkUDPSocketHandler::HandleUDPPacket(Packet *p, NetworkAddress *client_
|
|||||||
case PACKET_UDP_SERVER_NEWGRFS: this->Receive_SERVER_NEWGRFS(p, client_addr); break;
|
case PACKET_UDP_SERVER_NEWGRFS: this->Receive_SERVER_NEWGRFS(p, client_addr); break;
|
||||||
case PACKET_UDP_MASTER_SESSION_KEY: this->Receive_MASTER_SESSION_KEY(p, client_addr); break;
|
case PACKET_UDP_MASTER_SESSION_KEY: this->Receive_MASTER_SESSION_KEY(p, client_addr); break;
|
||||||
|
|
||||||
|
case PACKET_UDP_EX_MULTI: this->Receive_EX_MULTI(p, client_addr); break;
|
||||||
|
case PACKET_UDP_EX_SERVER_RESPONSE: this->Receive_EX_SERVER_RESPONSE(p, client_addr); break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (this->HasClientQuit()) {
|
if (this->HasClientQuit()) {
|
||||||
DEBUG(net, 0, "[udp] received invalid packet type %d from %s", type, client_addr->GetAddressAsString());
|
DEBUG(net, 0, "[udp] received invalid packet type %d from %s", type, client_addr->GetAddressAsString());
|
||||||
@@ -327,6 +480,74 @@ void NetworkUDPSocketHandler::HandleUDPPacket(Packet *p, NetworkAddress *client_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NetworkUDPSocketHandler::Receive_EX_MULTI(Packet *p, NetworkAddress *client_addr)
|
||||||
|
{
|
||||||
|
uint64 token = p->Recv_uint64();
|
||||||
|
uint8 index = p->Recv_uint8 ();
|
||||||
|
uint8 total = p->Recv_uint8 ();
|
||||||
|
uint16 payload_size = p->Recv_uint16();
|
||||||
|
|
||||||
|
DEBUG(net, 6, "[udp] received multi-part packet from %s: " OTTD_PRINTFHEX64 ", %u/%u, %u bytes",
|
||||||
|
client_addr->GetAddressAsString(), token, index, total, payload_size);
|
||||||
|
|
||||||
|
if (total == 0 || index >= total) return;
|
||||||
|
if (!p->CanReadFromPacket(payload_size)) return;
|
||||||
|
|
||||||
|
time_t cur_time = time(NULL);
|
||||||
|
|
||||||
|
auto add_to_fragment = [&](FragmentSet &fs) {
|
||||||
|
fs.fragments[index].assign((const char *) p->buffer + p->pos, payload_size);
|
||||||
|
|
||||||
|
uint total_payload = 0;
|
||||||
|
for (auto &frag : fs.fragments) {
|
||||||
|
if (!frag.size()) return;
|
||||||
|
|
||||||
|
total_payload += frag.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG(net, 6, "[udp] merged multi-part packet from %s: " OTTD_PRINTFHEX64 ", %u bytes",
|
||||||
|
client_addr->GetAddressAsString(), token, total_payload);
|
||||||
|
|
||||||
|
Packet merged(this);
|
||||||
|
for (auto &frag : fs.fragments) {
|
||||||
|
merged.Send_binary(frag.data(), frag.size());
|
||||||
|
}
|
||||||
|
merged.PrepareToRead();
|
||||||
|
|
||||||
|
/* If the size does not match the packet must be corrupted.
|
||||||
|
* Otherwise it will be marked as corrupted later on. */
|
||||||
|
if (total_payload != merged.size) {
|
||||||
|
DEBUG(net, 1, "received an extended packet with mismatching size from %s, (%u, %u)",
|
||||||
|
client_addr->GetAddressAsString(), total_payload, merged.size);
|
||||||
|
} else {
|
||||||
|
this->HandleUDPPacket(&merged, client_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs = this->fragments.back();
|
||||||
|
this->fragments.pop_back();
|
||||||
|
};
|
||||||
|
|
||||||
|
uint i = 0;
|
||||||
|
while (i < this->fragments.size()) {
|
||||||
|
FragmentSet &fs = this->fragments[i];
|
||||||
|
if (fs.create_time < cur_time - 10) {
|
||||||
|
fs = this->fragments.back();
|
||||||
|
this->fragments.pop_back();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs.token == token && fs.address == *client_addr && fs.fragments.size() == total) {
|
||||||
|
add_to_fragment(fs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->fragments.push_back({ token, *client_addr, cur_time, {} });
|
||||||
|
this->fragments.back().fragments.resize(total);
|
||||||
|
add_to_fragment(this->fragments.back());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for logging receiving invalid packets.
|
* Helper for logging receiving invalid packets.
|
||||||
* @param type The received packet type.
|
* @param type The received packet type.
|
||||||
@@ -339,6 +560,7 @@ void NetworkUDPSocketHandler::ReceiveInvalidPacket(PacketUDPType type, NetworkAd
|
|||||||
|
|
||||||
void NetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_FIND_SERVER, client_addr); }
|
void NetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_FIND_SERVER, client_addr); }
|
||||||
void NetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_RESPONSE, client_addr); }
|
void NetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_RESPONSE, client_addr); }
|
||||||
|
void NetworkUDPSocketHandler::Receive_EX_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_EX_SERVER_RESPONSE, client_addr); }
|
||||||
void NetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_DETAIL_INFO, client_addr); }
|
void NetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_CLIENT_DETAIL_INFO, client_addr); }
|
||||||
void NetworkUDPSocketHandler::Receive_SERVER_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_DETAIL_INFO, client_addr); }
|
void NetworkUDPSocketHandler::Receive_SERVER_DETAIL_INFO(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_DETAIL_INFO, client_addr); }
|
||||||
void NetworkUDPSocketHandler::Receive_SERVER_REGISTER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_REGISTER, client_addr); }
|
void NetworkUDPSocketHandler::Receive_SERVER_REGISTER(Packet *p, NetworkAddress *client_addr) { this->ReceiveInvalidPacket(PACKET_UDP_SERVER_REGISTER, client_addr); }
|
||||||
|
@@ -18,6 +18,10 @@
|
|||||||
#include "game.h"
|
#include "game.h"
|
||||||
#include "packet.h"
|
#include "packet.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#ifdef ENABLE_NETWORK
|
#ifdef ENABLE_NETWORK
|
||||||
|
|
||||||
/** Enum with all types of UDP packets. The order MUST not be changed **/
|
/** Enum with all types of UDP packets. The order MUST not be changed **/
|
||||||
@@ -34,7 +38,10 @@ enum PacketUDPType {
|
|||||||
PACKET_UDP_CLIENT_GET_NEWGRFS, ///< Requests the name for a list of GRFs (GRF_ID and MD5)
|
PACKET_UDP_CLIENT_GET_NEWGRFS, ///< Requests the name for a list of GRFs (GRF_ID and MD5)
|
||||||
PACKET_UDP_SERVER_NEWGRFS, ///< Sends the list of NewGRF's requested.
|
PACKET_UDP_SERVER_NEWGRFS, ///< Sends the list of NewGRF's requested.
|
||||||
PACKET_UDP_MASTER_SESSION_KEY, ///< Sends a fresh session key to the client
|
PACKET_UDP_MASTER_SESSION_KEY, ///< Sends a fresh session key to the client
|
||||||
PACKET_UDP_END, ///< Must ALWAYS be on the end of this list!! (period)
|
PACKET_UDP_END, ///< Must ALWAYS be the last non-extended item in the list!! (period)
|
||||||
|
|
||||||
|
PACKET_UDP_EX_MULTI = 128, ///< Extended/multi packet type
|
||||||
|
PACKET_UDP_EX_SERVER_RESPONSE, ///< Reply of the game server with extended game information
|
||||||
};
|
};
|
||||||
|
|
||||||
/** The types of server lists we can get */
|
/** The types of server lists we can get */
|
||||||
@@ -54,6 +61,16 @@ protected:
|
|||||||
/** The opened sockets. */
|
/** The opened sockets. */
|
||||||
SocketList sockets;
|
SocketList sockets;
|
||||||
|
|
||||||
|
uint64 fragment_token;
|
||||||
|
|
||||||
|
struct FragmentSet {
|
||||||
|
uint64 token;
|
||||||
|
NetworkAddress address;
|
||||||
|
time_t create_time;
|
||||||
|
std::vector<std::string> fragments;
|
||||||
|
};
|
||||||
|
std::vector<FragmentSet> fragments;
|
||||||
|
|
||||||
NetworkRecvStatus CloseConnection(bool error = true);
|
NetworkRecvStatus CloseConnection(bool error = true);
|
||||||
|
|
||||||
void ReceiveInvalidPacket(PacketUDPType, NetworkAddress *client_addr);
|
void ReceiveInvalidPacket(PacketUDPType, NetworkAddress *client_addr);
|
||||||
@@ -106,6 +123,8 @@ protected:
|
|||||||
*/
|
*/
|
||||||
virtual void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr);
|
virtual void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr);
|
||||||
|
|
||||||
|
virtual void Receive_EX_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Query for detailed information about companies.
|
* Query for detailed information about companies.
|
||||||
* @param p The received packet.
|
* @param p The received packet.
|
||||||
@@ -230,6 +249,8 @@ protected:
|
|||||||
* @param config the GRF to handle
|
* @param config the GRF to handle
|
||||||
*/
|
*/
|
||||||
virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) { NOT_REACHED(); }
|
virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config) { NOT_REACHED(); }
|
||||||
|
|
||||||
|
virtual void Receive_EX_MULTI(Packet *p, NetworkAddress *client_addr);
|
||||||
public:
|
public:
|
||||||
NetworkUDPSocketHandler(NetworkAddressList *bind = NULL);
|
NetworkUDPSocketHandler(NetworkAddressList *bind = NULL);
|
||||||
|
|
||||||
@@ -243,7 +264,9 @@ public:
|
|||||||
void ReceivePackets();
|
void ReceivePackets();
|
||||||
|
|
||||||
void SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info);
|
void SendNetworkGameInfo(Packet *p, const NetworkGameInfo *info);
|
||||||
|
void SendNetworkGameInfoExtended(Packet *p, const NetworkGameInfo *info, uint16 version);
|
||||||
void ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info);
|
void ReceiveNetworkGameInfo(Packet *p, NetworkGameInfo *info);
|
||||||
|
void ReceiveNetworkGameInfoExtended(Packet *p, NetworkGameInfo *info);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* ENABLE_NETWORK */
|
#endif /* ENABLE_NETWORK */
|
||||||
|
@@ -1124,9 +1124,9 @@ void NetworkShutDown()
|
|||||||
* Checks whether the given version string is compatible with our version.
|
* Checks whether the given version string is compatible with our version.
|
||||||
* @param other the version string to compare to
|
* @param other the version string to compare to
|
||||||
*/
|
*/
|
||||||
bool IsNetworkCompatibleVersion(const char *other)
|
bool IsNetworkCompatibleVersion(const char *other, bool extended)
|
||||||
{
|
{
|
||||||
return strncmp(_openttd_revision, other, NETWORK_REVISION_LENGTH - 1) == 0;
|
return strncmp(_openttd_revision, other, (extended ? NETWORK_LONG_REVISION_LENGTH : NETWORK_REVISION_LENGTH) - 1) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* ENABLE_NETWORK */
|
#endif /* ENABLE_NETWORK */
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
#include "../gfx_func.h"
|
#include "../gfx_func.h"
|
||||||
#include "../error.h"
|
#include "../error.h"
|
||||||
#include "../rev.h"
|
#include "../rev.h"
|
||||||
|
#include "../fios.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "network_base.h"
|
#include "network_base.h"
|
||||||
#include "network_client.h"
|
#include "network_client.h"
|
||||||
@@ -684,7 +685,8 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CHECK_NEWGRFS(P
|
|||||||
{
|
{
|
||||||
if (this->status != STATUS_JOIN) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
if (this->status != STATUS_JOIN) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
|
|
||||||
uint grf_count = p->Recv_uint8();
|
uint grf_count = p->Recv_uint32();
|
||||||
|
if (grf_count > MAX_NEWGRFS) return NETWORK_RECV_STATUS_MALFORMED_PACKET;
|
||||||
NetworkRecvStatus ret = NETWORK_RECV_STATUS_OKAY;
|
NetworkRecvStatus ret = NETWORK_RECV_STATUS_OKAY;
|
||||||
|
|
||||||
/* Check all GRFs */
|
/* Check all GRFs */
|
||||||
|
@@ -1179,10 +1179,6 @@ struct NetworkStartServerWindow : public Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case WID_NSS_GENERATE_GAME: // Start game
|
case WID_NSS_GENERATE_GAME: // Start game
|
||||||
if (CountSelectedGRFs(_grfconfig_newgame) > NETWORK_MAX_GRF_COUNT) {
|
|
||||||
ShowErrorMessage(STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED, INVALID_STRING_ID, WL_ERROR);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_is_network_server = true;
|
_is_network_server = true;
|
||||||
if (_ctrl_pressed) {
|
if (_ctrl_pressed) {
|
||||||
StartNewGameWithoutGUI(GENERATE_NEW_SEED);
|
StartNewGameWithoutGUI(GENERATE_NEW_SEED);
|
||||||
|
@@ -144,7 +144,7 @@ void NetworkAddServer(const char *b);
|
|||||||
void NetworkRebuildHostList();
|
void NetworkRebuildHostList();
|
||||||
void UpdateNetworkGameWindow();
|
void UpdateNetworkGameWindow();
|
||||||
|
|
||||||
bool IsNetworkCompatibleVersion(const char *version);
|
bool IsNetworkCompatibleVersion(const char *version, bool extended = false);
|
||||||
|
|
||||||
/* From network_command.cpp */
|
/* From network_command.cpp */
|
||||||
/**
|
/**
|
||||||
|
@@ -481,7 +481,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendNewGRFCheck()
|
|||||||
if (!HasBit(c->flags, GCF_STATIC)) grf_count++;
|
if (!HasBit(c->flags, GCF_STATIC)) grf_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->Send_uint8 (grf_count);
|
p->Send_uint32 (grf_count);
|
||||||
for (c = _grfconfig; c != NULL; c = c->next) {
|
for (c = _grfconfig; c != NULL; c = c->next) {
|
||||||
if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident);
|
if (!HasBit(c->flags, GCF_STATIC)) this->SendGRFIdentifier(p, &c->ident);
|
||||||
}
|
}
|
||||||
|
@@ -34,8 +34,13 @@
|
|||||||
|
|
||||||
#include "core/udp.h"
|
#include "core/udp.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
|
extern const uint8 _out_of_band_grf_md5[16] { 0x00, 0xB0, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xC0, 0xDE, 0x00, 0x00, 0x00, 0x00 };
|
||||||
|
static const uint32 FIND_SERVER_EXTENDED_TOKEN = 0x2A49582A;
|
||||||
|
|
||||||
/** Mutex for all out threaded udp resolution and such. */
|
/** Mutex for all out threaded udp resolution and such. */
|
||||||
static ThreadMutex *_network_udp_mutex = ThreadMutex::New();
|
static ThreadMutex *_network_udp_mutex = ThreadMutex::New();
|
||||||
|
|
||||||
@@ -66,6 +71,15 @@ struct NetworkUDPQueryServerInfo : NetworkAddress {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static Packet PrepareUdpClientFindServerPacket()
|
||||||
|
{
|
||||||
|
Packet p(PACKET_UDP_CLIENT_FIND_SERVER);
|
||||||
|
p.Send_uint32(FIND_SERVER_EXTENDED_TOKEN);
|
||||||
|
p.Send_uint16(0); // flags
|
||||||
|
p.Send_uint16(0); // version
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function doing the actual work for querying the server.
|
* Helper function doing the actual work for querying the server.
|
||||||
* @param address The address of the server.
|
* @param address The address of the server.
|
||||||
@@ -84,7 +98,7 @@ static void NetworkUDPQueryServer(NetworkAddress *address, bool needs_mutex, boo
|
|||||||
|
|
||||||
if (needs_mutex) _network_udp_mutex->BeginCritical();
|
if (needs_mutex) _network_udp_mutex->BeginCritical();
|
||||||
/* Init the packet */
|
/* Init the packet */
|
||||||
Packet p(PACKET_UDP_CLIENT_FIND_SERVER);
|
Packet p = PrepareUdpClientFindServerPacket();
|
||||||
if (_udp_client_socket != NULL) _udp_client_socket->SendPacket(&p, address);
|
if (_udp_client_socket != NULL) _udp_client_socket->SendPacket(&p, address);
|
||||||
if (needs_mutex) _network_udp_mutex->EndCritical();
|
if (needs_mutex) _network_udp_mutex->EndCritical();
|
||||||
}
|
}
|
||||||
@@ -153,6 +167,7 @@ protected:
|
|||||||
virtual void Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr);
|
virtual void Receive_CLIENT_FIND_SERVER(Packet *p, NetworkAddress *client_addr);
|
||||||
virtual void Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr);
|
virtual void Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr);
|
||||||
virtual void Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr);
|
virtual void Receive_CLIENT_GET_NEWGRFS(Packet *p, NetworkAddress *client_addr);
|
||||||
|
void Reply_CLIENT_FIND_SERVER_extended(Packet *p, NetworkAddress *client_addr, NetworkGameInfo *ngi);
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Create the socket.
|
* Create the socket.
|
||||||
@@ -192,6 +207,12 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, Networ
|
|||||||
strecpy(ngi.map_name, _network_game_info.map_name, lastof(ngi.map_name));
|
strecpy(ngi.map_name, _network_game_info.map_name, lastof(ngi.map_name));
|
||||||
strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name));
|
strecpy(ngi.server_name, _settings_client.network.server_name, lastof(ngi.server_name));
|
||||||
strecpy(ngi.server_revision, _openttd_revision, lastof(ngi.server_revision));
|
strecpy(ngi.server_revision, _openttd_revision, lastof(ngi.server_revision));
|
||||||
|
strecpy(ngi.short_server_revision, _openttd_revision, lastof(ngi.short_server_revision));
|
||||||
|
|
||||||
|
if (p->CanReadFromPacket(8, true) && p->Recv_uint32() == FIND_SERVER_EXTENDED_TOKEN) {
|
||||||
|
this->Reply_CLIENT_FIND_SERVER_extended(p, client_addr, &ngi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Packet packet(PACKET_UDP_SERVER_RESPONSE);
|
Packet packet(PACKET_UDP_SERVER_RESPONSE);
|
||||||
this->SendNetworkGameInfo(&packet, &ngi);
|
this->SendNetworkGameInfo(&packet, &ngi);
|
||||||
@@ -202,6 +223,19 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_FIND_SERVER(Packet *p, Networ
|
|||||||
DEBUG(net, 2, "[udp] queried from %s", client_addr->GetHostname());
|
DEBUG(net, 2, "[udp] queried from %s", client_addr->GetHostname());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ServerNetworkUDPSocketHandler::Reply_CLIENT_FIND_SERVER_extended(Packet *p, NetworkAddress *client_addr, NetworkGameInfo *ngi)
|
||||||
|
{
|
||||||
|
uint16 version = p->Recv_uint16();
|
||||||
|
|
||||||
|
Packet packet(PACKET_UDP_EX_SERVER_RESPONSE);
|
||||||
|
this->SendNetworkGameInfoExtended(&packet, ngi, version);
|
||||||
|
|
||||||
|
/* Let the client know that we are here */
|
||||||
|
this->SendPacket(&packet, client_addr);
|
||||||
|
|
||||||
|
DEBUG(net, 2, "[udp] queried (extended: %u) from %s", version, client_addr->GetHostname());
|
||||||
|
}
|
||||||
|
|
||||||
void ServerNetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr)
|
void ServerNetworkUDPSocketHandler::Receive_CLIENT_DETAIL_INFO(Packet *p, NetworkAddress *client_addr)
|
||||||
{
|
{
|
||||||
/* Just a fail-safe.. should never happen */
|
/* Just a fail-safe.. should never happen */
|
||||||
@@ -274,8 +308,12 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ
|
|||||||
uint8 num_grfs;
|
uint8 num_grfs;
|
||||||
uint i;
|
uint i;
|
||||||
|
|
||||||
const GRFConfig *in_reply[NETWORK_MAX_GRF_COUNT];
|
struct GRFInfo {
|
||||||
uint8 in_reply_count = 0;
|
GRFIdentifier ident;
|
||||||
|
const char *name = nullptr;
|
||||||
|
};
|
||||||
|
std::vector<GRFInfo> in_reply;
|
||||||
|
|
||||||
size_t packet_len = 0;
|
size_t packet_len = 0;
|
||||||
|
|
||||||
DEBUG(net, 6, "[udp] newgrf data request from %s", client_addr->GetAddressAsString());
|
DEBUG(net, 6, "[udp] newgrf data request from %s", client_addr->GetAddressAsString());
|
||||||
@@ -284,37 +322,47 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ
|
|||||||
if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
|
if (num_grfs > NETWORK_MAX_GRF_COUNT) return;
|
||||||
|
|
||||||
for (i = 0; i < num_grfs; i++) {
|
for (i = 0; i < num_grfs; i++) {
|
||||||
GRFIdentifier c;
|
GRFInfo info;
|
||||||
|
this->ReceiveGRFIdentifier(p, &info.ident);
|
||||||
|
|
||||||
|
if (memcmp(info.ident.md5sum, _out_of_band_grf_md5, 16) == 0) {
|
||||||
|
if (info.ident.grfid == 0x56D2B000) {
|
||||||
|
info.name = "=*=*= More than 62 GRFs in total =*=*=";
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
const GRFConfig *f;
|
const GRFConfig *f;
|
||||||
|
|
||||||
this->ReceiveGRFIdentifier(p, &c);
|
|
||||||
|
|
||||||
/* Find the matching GRF file */
|
/* Find the matching GRF file */
|
||||||
f = FindGRFConfig(c.grfid, FGCM_EXACT, c.md5sum);
|
f = FindGRFConfig(info.ident.grfid, FGCM_EXACT, info.ident.md5sum);
|
||||||
if (f == NULL) continue; // The GRF is unknown to this server
|
if (f == NULL) continue; // The GRF is unknown to this server
|
||||||
|
|
||||||
|
info.ident = f->ident;
|
||||||
|
info.name = f->GetName();
|
||||||
|
}
|
||||||
|
|
||||||
/* If the reply might exceed the size of the packet, only reply
|
/* If the reply might exceed the size of the packet, only reply
|
||||||
* the current list and do not send the other data.
|
* the current list and do not send the other data.
|
||||||
* The name could be an empty string, if so take the filename. */
|
* The name could be an empty string, if so take the filename. */
|
||||||
packet_len += sizeof(c.grfid) + sizeof(c.md5sum) +
|
packet_len += sizeof(info.ident.grfid) + sizeof(info.ident.md5sum) +
|
||||||
min(strlen(f->GetName()) + 1, (size_t)NETWORK_GRF_NAME_LENGTH);
|
min(strlen(info.name) + 1, (size_t)NETWORK_GRF_NAME_LENGTH);
|
||||||
if (packet_len > SEND_MTU - 4) { // 4 is 3 byte header + grf count in reply
|
if (packet_len > SEND_MTU - 4) { // 4 is 3 byte header + grf count in reply
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
in_reply[in_reply_count] = f;
|
|
||||||
in_reply_count++;
|
in_reply.push_back(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_reply_count == 0) return;
|
if (in_reply.empty()) return;
|
||||||
|
|
||||||
Packet packet(PACKET_UDP_SERVER_NEWGRFS);
|
Packet packet(PACKET_UDP_SERVER_NEWGRFS);
|
||||||
packet.Send_uint8(in_reply_count);
|
packet.Send_uint8(in_reply.size());
|
||||||
for (i = 0; i < in_reply_count; i++) {
|
for (const GRFInfo &info : in_reply) {
|
||||||
char name[NETWORK_GRF_NAME_LENGTH];
|
char name[NETWORK_GRF_NAME_LENGTH];
|
||||||
|
|
||||||
/* The name could be an empty string, if so take the filename */
|
/* The name could be an empty string, if so take the filename */
|
||||||
strecpy(name, in_reply[i]->GetName(), lastof(name));
|
strecpy(name, info.name, lastof(name));
|
||||||
this->SendGRFIdentifier(&packet, &in_reply[i]->ident);
|
this->SendGRFIdentifier(&packet, &info.ident);
|
||||||
packet.Send_string(name);
|
packet.Send_string(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,8 +373,11 @@ void ServerNetworkUDPSocketHandler::Receive_CLIENT_GET_NEWGRFS(Packet *p, Networ
|
|||||||
|
|
||||||
/** Helper class for handling all client side communication. */
|
/** Helper class for handling all client side communication. */
|
||||||
class ClientNetworkUDPSocketHandler : public NetworkUDPSocketHandler {
|
class ClientNetworkUDPSocketHandler : public NetworkUDPSocketHandler {
|
||||||
|
private:
|
||||||
|
void Receive_SERVER_RESPONSE_Common(Packet *p, NetworkAddress *client_addr, bool extended);
|
||||||
protected:
|
protected:
|
||||||
virtual void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr);
|
virtual void Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr);
|
||||||
|
virtual void Receive_EX_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr);
|
||||||
virtual void Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr);
|
virtual void Receive_MASTER_RESPONSE_LIST(Packet *p, NetworkAddress *client_addr);
|
||||||
virtual void Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr);
|
virtual void Receive_SERVER_NEWGRFS(Packet *p, NetworkAddress *client_addr);
|
||||||
virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config);
|
virtual void HandleIncomingNetworkGameInfoGRFConfig(GRFConfig *config);
|
||||||
@@ -335,19 +386,33 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr)
|
void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr)
|
||||||
|
{
|
||||||
|
this->Receive_SERVER_RESPONSE_Common(p, client_addr, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientNetworkUDPSocketHandler::Receive_EX_SERVER_RESPONSE(Packet *p, NetworkAddress *client_addr)
|
||||||
|
{
|
||||||
|
this->Receive_SERVER_RESPONSE_Common(p, client_addr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE_Common(Packet *p, NetworkAddress *client_addr, bool extended)
|
||||||
{
|
{
|
||||||
NetworkGameList *item;
|
NetworkGameList *item;
|
||||||
|
|
||||||
/* Just a fail-safe.. should never happen */
|
/* Just a fail-safe.. should never happen */
|
||||||
if (_network_udp_server) return;
|
if (_network_udp_server) return;
|
||||||
|
|
||||||
DEBUG(net, 4, "[udp] server response from %s", client_addr->GetAddressAsString());
|
DEBUG(net, 4, "[udp]%s server response from %s", extended ? " extended" : "", client_addr->GetAddressAsString());
|
||||||
|
|
||||||
/* Find next item */
|
/* Find next item */
|
||||||
item = NetworkGameListAddItem(*client_addr);
|
item = NetworkGameListAddItem(*client_addr);
|
||||||
|
|
||||||
ClearGRFConfigList(&item->info.grfconfig);
|
ClearGRFConfigList(&item->info.grfconfig);
|
||||||
|
if (extended) {
|
||||||
|
this->ReceiveNetworkGameInfoExtended(p, &item->info);
|
||||||
|
} else {
|
||||||
this->ReceiveNetworkGameInfo(p, &item->info);
|
this->ReceiveNetworkGameInfo(p, &item->info);
|
||||||
|
}
|
||||||
|
|
||||||
item->info.compatible = true;
|
item->info.compatible = true;
|
||||||
{
|
{
|
||||||
@@ -362,14 +427,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAd
|
|||||||
const GRFConfig *c;
|
const GRFConfig *c;
|
||||||
uint in_request_count = 0;
|
uint in_request_count = 0;
|
||||||
|
|
||||||
for (c = item->info.grfconfig; c != NULL; c = c->next) {
|
auto flush_request = [&]() {
|
||||||
if (c->status == GCS_NOT_FOUND) item->info.compatible = false;
|
|
||||||
if (c->status != GCS_NOT_FOUND || strcmp(c->GetName(), UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue;
|
|
||||||
in_request[in_request_count] = c;
|
|
||||||
in_request_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_request_count > 0) {
|
|
||||||
/* There are 'unknown' GRFs, now send a request for them */
|
/* There are 'unknown' GRFs, now send a request for them */
|
||||||
uint i;
|
uint i;
|
||||||
Packet packet(PACKET_UDP_CLIENT_GET_NEWGRFS);
|
Packet packet(PACKET_UDP_CLIENT_GET_NEWGRFS);
|
||||||
@@ -380,7 +438,19 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAd
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->SendPacket(&packet, &item->address);
|
this->SendPacket(&packet, &item->address);
|
||||||
|
|
||||||
|
in_request_count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (c = item->info.grfconfig; c != NULL; c = c->next) {
|
||||||
|
if (c->status == GCS_NOT_FOUND) item->info.compatible = false;
|
||||||
|
if (c->status != GCS_NOT_FOUND || strcmp(c->GetName(), UNKNOWN_GRF_NAME_PLACEHOLDER) != 0) continue;
|
||||||
|
in_request[in_request_count] = c;
|
||||||
|
in_request_count++;
|
||||||
|
if (in_request_count == NETWORK_MAX_GRF_COUNT) flush_request();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (in_request_count > 0) flush_request();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->info.hostname[0] == '\0') {
|
if (item->info.hostname[0] == '\0') {
|
||||||
@@ -392,7 +462,7 @@ void ClientNetworkUDPSocketHandler::Receive_SERVER_RESPONSE(Packet *p, NetworkAd
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we are allowed on this server based on the revision-match */
|
/* Check if we are allowed on this server based on the revision-match */
|
||||||
item->info.version_compatible = IsNetworkCompatibleVersion(item->info.server_revision);
|
item->info.version_compatible = IsNetworkCompatibleVersion(item->info.server_revision, extended);
|
||||||
item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs
|
item->info.compatible &= item->info.version_compatible; // Already contains match for GRFs
|
||||||
|
|
||||||
item->online = true;
|
item->online = true;
|
||||||
@@ -498,7 +568,7 @@ void ClientNetworkUDPSocketHandler::HandleIncomingNetworkGameInfoGRFConfig(GRFCo
|
|||||||
static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket)
|
static void NetworkUDPBroadCast(NetworkUDPSocketHandler *socket)
|
||||||
{
|
{
|
||||||
for (NetworkAddress *addr = _broadcast_list.Begin(); addr != _broadcast_list.End(); addr++) {
|
for (NetworkAddress *addr = _broadcast_list.Begin(); addr != _broadcast_list.End(); addr++) {
|
||||||
Packet p(PACKET_UDP_CLIENT_FIND_SERVER);
|
Packet p = PrepareUdpClientFindServerPacket();
|
||||||
|
|
||||||
DEBUG(net, 4, "[udp] broadcasting to %s", addr->GetHostname());
|
DEBUG(net, 4, "[udp] broadcasting to %s", addr->GetHostname());
|
||||||
|
|
||||||
|
@@ -9318,7 +9318,7 @@ void LoadNewGRF(uint load_index, uint file_index, uint num_baseset)
|
|||||||
if (stage == GLS_LABELSCAN) InitNewGRFFile(c);
|
if (stage == GLS_LABELSCAN) InitNewGRFFile(c);
|
||||||
|
|
||||||
if (!HasBit(c->flags, GCF_STATIC) && !HasBit(c->flags, GCF_SYSTEM)) {
|
if (!HasBit(c->flags, GCF_STATIC) && !HasBit(c->flags, GCF_SYSTEM)) {
|
||||||
if ((_networking && num_non_static == NETWORK_MAX_GRF_COUNT) || slot == MAX_FILE_SLOTS) {
|
if (slot == MAX_FILE_SLOTS) {
|
||||||
DEBUG(grf, 0, "'%s' is not loaded as the maximum number of non-static GRFs has been reached", c->filename);
|
DEBUG(grf, 0, "'%s' is not loaded as the maximum number of non-static GRFs has been reached", c->filename);
|
||||||
c->status = GCS_DISABLED;
|
c->status = GCS_DISABLED;
|
||||||
c->error = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED);
|
c->error = new GRFError(STR_NEWGRF_ERROR_MSG_FATAL, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED);
|
||||||
|
@@ -895,13 +895,6 @@ int openttd_main(int argc, char *argv[])
|
|||||||
DriverFactoryBase::SelectDriver(musicdriver, Driver::DT_MUSIC);
|
DriverFactoryBase::SelectDriver(musicdriver, Driver::DT_MUSIC);
|
||||||
free(musicdriver);
|
free(musicdriver);
|
||||||
|
|
||||||
// Check if not too much GRFs are loaded for network game
|
|
||||||
if (dedicated && CountSelectedGRFs(_grfconfig) > NETWORK_MAX_GRF_COUNT) {
|
|
||||||
DEBUG(net, 0, "Too many GRF loaded. Max %d are allowed.\nExiting ...", NETWORK_MAX_GRF_COUNT);
|
|
||||||
ShutdownGame();
|
|
||||||
goto exit_normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Take our initial lock on whatever we might want to do! */
|
/* Take our initial lock on whatever we might want to do! */
|
||||||
_modal_progress_paint_mutex->BeginCritical();
|
_modal_progress_paint_mutex->BeginCritical();
|
||||||
_modal_progress_work_mutex->BeginCritical();
|
_modal_progress_work_mutex->BeginCritical();
|
||||||
|
@@ -763,13 +763,6 @@ bool AfterLoadGame()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_networking && CountSelectedGRFs(_grfconfig) > NETWORK_MAX_GRF_COUNT) {
|
|
||||||
SetSaveLoadError(STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED);
|
|
||||||
/* Restore the signals */
|
|
||||||
ResetSignalHandlers();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The value of _date_fract got divided, so make sure that old games are converted correctly. */
|
/* The value of _date_fract got divided, so make sure that old games are converted correctly. */
|
||||||
if (IsSavegameVersionBefore(11, 1) || (IsSavegameVersionBefore(147) && _date_fract > DAY_TICKS)) _date_fract /= 885;
|
if (IsSavegameVersionBefore(11, 1) || (IsSavegameVersionBefore(147) && _date_fract > DAY_TICKS)) _date_fract /= 885;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user