@ -11,6 +11,7 @@
# include "network_gamelist.h"
# include "network_gamelist.h"
# include "network_udp.h"
# include "network_udp.h"
# include "variables.h"
# include "variables.h"
# include "newgrf_config.h"
//
//
// This file handles all the LAN-stuff
// This file handles all the LAN-stuff
@ -28,6 +29,8 @@ typedef enum {
PACKET_UDP_CLIENT_GET_LIST , // Request for serverlist from master server
PACKET_UDP_CLIENT_GET_LIST , // Request for serverlist from master server
PACKET_UDP_MASTER_RESPONSE_LIST , // Response from master server with server ip's + port's
PACKET_UDP_MASTER_RESPONSE_LIST , // Response from master server with server ip's + port's
PACKET_UDP_SERVER_UNREGISTER , // Request to be removed from the server-list
PACKET_UDP_SERVER_UNREGISTER , // Request to be removed from the server-list
PACKET_UDP_CLIENT_GET_NEWGRFS , // Requests the name for a list of GRFs (GRF_ID and MD5)
PACKET_UDP_SERVER_NEWGRFS , // Sends the list of NewGRF's requested.
PACKET_UDP_END
PACKET_UDP_END
} PacketUDPType ;
} PacketUDPType ;
@ -42,6 +45,34 @@ static void NetworkSendUDP_Packet(SOCKET udp, Packet* p, struct sockaddr_in* rec
static NetworkClientState _udp_cs ;
static NetworkClientState _udp_cs ;
/**
* Serializes the GRFIdentifier ( GRF ID and MD5 checksum ) to the packet
* @ param p the packet to write the data to
* @ param c the configuration to write the GRF ID and MD5 checksum from
*/
static void NetworkSend_GRFIdentifier ( Packet * p , const GRFConfig * c )
{
uint j ;
NetworkSend_uint32 ( p , c - > grfid ) ;
for ( j = 0 ; j < sizeof ( c - > md5sum ) ; j + + ) {
NetworkSend_uint8 ( p , c - > md5sum [ j ] ) ;
}
}
/**
* Deserializes the GRFIdentifier ( GRF ID and MD5 checksum ) from the packet
* @ param p the packet to read the data from
* @ param c the configuration to write the GRF ID and MD5 checksum to
*/
static void NetworkRecv_GRFIdentifier ( Packet * p , GRFConfig * c )
{
uint j ;
c - > grfid = NetworkRecv_uint32 ( & _udp_cs , p ) ;
for ( j = 0 ; j < sizeof ( c - > md5sum ) ; j + + ) {
c - > md5sum [ j ] = NetworkRecv_uint8 ( & _udp_cs , p ) ;
}
}
DEF_UDP_RECEIVE_COMMAND ( PACKET_UDP_CLIENT_FIND_SERVER )
DEF_UDP_RECEIVE_COMMAND ( PACKET_UDP_CLIENT_FIND_SERVER )
{
{
Packet * packet ;
Packet * packet ;
@ -59,6 +90,27 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_CLIENT_FIND_SERVER)
NetworkSend_uint8 ( packet , NETWORK_GAME_INFO_VERSION ) ;
NetworkSend_uint8 ( packet , NETWORK_GAME_INFO_VERSION ) ;
/* NETWORK_GAME_INFO_VERSION = 4 */
{
/* Only send the GRF Identification (GRF_ID and MD5 checksum) of
* the GRFs that are needed , i . e . the ones that the server has
* selected in the NewGRF GUI and not the ones that are used due
* to the fact that they are in [ newgrf - static ] in openttd . cfg */
const GRFConfig * c ;
uint i = 0 ;
/* Count number of GRFs to send information about */
for ( c = _grfconfig ; c ! = NULL ; c = c - > next ) {
if ( ! HASBIT ( c - > flags , GCF_STATIC ) ) i + + ;
}
NetworkSend_uint8 ( packet , i ) ; // Send number of GRFs
/* Send actual GRF Identifications */
for ( c = _grfconfig ; c ! = NULL ; c = c - > next ) {
if ( ! HASBIT ( c - > flags , GCF_STATIC ) ) NetworkSend_GRFIdentifier ( packet , c ) ;
}
}
/* NETWORK_GAME_INFO_VERSION = 3 */
/* NETWORK_GAME_INFO_VERSION = 3 */
NetworkSend_uint32 ( packet , _network_game_info . game_date ) ;
NetworkSend_uint32 ( packet , _network_game_info . game_date ) ;
NetworkSend_uint32 ( packet , _network_game_info . start_date ) ;
NetworkSend_uint32 ( packet , _network_game_info . start_date ) ;
@ -109,9 +161,41 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE)
// Find next item
// Find next item
item = NetworkGameListAddItem ( inet_addr ( inet_ntoa ( client_addr - > sin_addr ) ) , ntohs ( client_addr - > sin_port ) ) ;
item = NetworkGameListAddItem ( inet_addr ( inet_ntoa ( client_addr - > sin_addr ) ) , ntohs ( client_addr - > sin_port ) ) ;
item - > info . compatible = true ;
/* Please observer the order. In the order in which packets are sent
/* Please observer the order. In the order in which packets are sent
* they are to be received */
* they are to be received */
switch ( game_info_version ) {
switch ( game_info_version ) {
case 4 : {
GRFConfig * c , * * dst = & item - > info . grfconfig ;
const GRFConfig * f ;
uint i ;
uint num_grfs = NetworkRecv_uint8 ( & _udp_cs , p ) ;
for ( i = 0 ; i < num_grfs ; i + + ) {
c = calloc ( 1 , sizeof ( * c ) ) ;
NetworkRecv_GRFIdentifier ( p , c ) ;
/* Find the matching GRF file */
f = FindGRFConfig ( c - > grfid , c - > md5sum ) ;
if ( f = = NULL ) {
/* Don't know the GRF, so mark game incompatible and the (possibly)
* already resolved name for this GRF ( another server has sent the
* name of the GRF already */
item - > info . compatible = false ;
c - > name = FindUnknownGRFName ( c - > grfid , c - > md5sum , true ) ;
SETBIT ( c - > flags , GCF_NOT_FOUND ) ;
} else {
c - > filename = f - > filename ;
c - > name = f - > name ;
c - > info = f - > info ;
}
SETBIT ( c - > flags , GCF_COPY ) ;
/* Append GRFConfig to the list */
* dst = c ;
dst = & c - > next ;
}
} /* Fallthrough */
case 3 :
case 3 :
item - > info . game_date = NetworkRecv_uint32 ( & _udp_cs , p ) ;
item - > info . game_date = NetworkRecv_uint32 ( & _udp_cs , p ) ;
item - > info . start_date = NetworkRecv_uint32 ( & _udp_cs , p ) ;
item - > info . start_date = NetworkRecv_uint32 ( & _udp_cs , p ) ;
@ -146,12 +230,50 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_SERVER_RESPONSE)
snprintf ( item - > info . hostname , sizeof ( item - > info . hostname ) , " %s " , inet_ntoa ( client_addr - > sin_addr ) ) ;
snprintf ( item - > info . hostname , sizeof ( item - > info . hostname ) , " %s " , inet_ntoa ( client_addr - > sin_addr ) ) ;
/* Check if we are allowed on this server based on the revision-match */
/* Check if we are allowed on this server based on the revision-match */
item - > info . compatible =
item - > info . version_ compatible =
strcmp ( item - > info . server_revision , _openttd_revision ) = = 0 | |
strcmp ( item - > info . server_revision , _openttd_revision ) = = 0 | |
strcmp ( item - > info . server_revision , NOREV_STRING ) = = 0 ;
strcmp ( item - > info . server_revision , NOREV_STRING ) = = 0 ;
item - > info . compatible & = item - > info . version_compatible ; // Already contains match for GRFs
break ;
break ;
}
}
{
/* Checks whether there needs to be a request for names of GRFs and makes
* the request if necessary . GRFs that need to be requested are the GRFs
* that do not exist on the clients system and we do not have the name
* resolved of , i . e . the name is still UNKNOWN_GRF_NAME_PLACEHOLDER .
* The in_request array and in_request_count are used so there is no need
* to do a second loop over the GRF list , which can be relatively expensive
* due to the string comparisons . */
const GRFConfig * in_request [ NETWORK_MAX_GRF_COUNT ] ;
const GRFConfig * c ;
uint in_request_count = 0 ;
struct sockaddr_in out_addr ;
for ( c = item - > info . grfconfig ; c ! = NULL ; c = c - > next ) {
if ( ! HASBIT ( c - > flags , GCF_NOT_FOUND ) | | strcmp ( c - > name , UNKNOWN_GRF_NAME_PLACEHOLDER ) ! = 0 ) continue ;
in_request [ in_request_count ] = c ;
in_request_count + + ;
}
if ( in_request_count > 0 ) {
/* There are 'unknown' GRFs, now send a request for them */
uint i ;
Packet * packet = NetworkSend_Init ( PACKET_UDP_CLIENT_GET_NEWGRFS ) ;
NetworkSend_uint8 ( packet , in_request_count ) ;
for ( i = 0 ; i < in_request_count ; i + + ) {
NetworkSend_GRFIdentifier ( packet , in_request [ i ] ) ;
}
out_addr . sin_family = AF_INET ;
out_addr . sin_port = htons ( item - > port ) ;
out_addr . sin_addr . s_addr = item - > ip ;
NetworkSendUDP_Packet ( _udp_client_socket , packet , & out_addr ) ;
free ( packet ) ;
}
}
item - > online = true ;
item - > online = true ;
UpdateNetworkGameWindow ( false ) ;
UpdateNetworkGameWindow ( false ) ;
@ -300,6 +422,104 @@ DEF_UDP_RECEIVE_COMMAND(PACKET_UDP_MASTER_ACK_REGISTER)
}
}
}
}
/**
* A client has requested the names of some NewGRFs .
*
* Replying this can be tricky as we have a limit of SEND_MTU bytes
* in the reply packet and we can send up to 100 bytes per NewGRF
* ( GRF ID , MD5sum and NETWORK_GRF_NAME_LENGTH bytes for the name ) .
* As SEND_MTU is _much_ less than 100 * NETWORK_MAX_GRF_COUNT , it
* could be that a packet overflows . To stop this we only reply
* with the first N NewGRFs so that if the first N + 1 NewGRFs
* would be sent , the packet overflows .
* in_reply and in_reply_count are used to keep a list of GRFs to
* send in the reply .
*/
DEF_UDP_RECEIVE_COMMAND ( PACKET_UDP_CLIENT_GET_NEWGRFS )
{
uint8 num_grfs ;
uint i ;
const GRFConfig * in_reply [ NETWORK_MAX_GRF_COUNT ] ;
Packet * packet ;
uint8 in_reply_count = 0 ;
uint packet_len = 0 ;
/* Just a fail-safe.. should never happen */
if ( _udp_cs . has_quit ) return ;
DEBUG ( net , 6 ) ( " [NET][UDP] NewGRF data request from %s:%d " , inet_ntoa ( client_addr - > sin_addr ) , ntohs ( client_addr - > sin_port ) ) ;
num_grfs = NetworkRecv_uint8 ( & _udp_cs , p ) ;
if ( num_grfs > NETWORK_MAX_GRF_COUNT ) return ;
for ( i = 0 ; i < num_grfs ; i + + ) {
GRFConfig c ;
const GRFConfig * f ;
NetworkRecv_GRFIdentifier ( p , & c ) ;
/* Find the matching GRF file */
f = FindGRFConfig ( c . grfid , c . md5sum ) ;
if ( f = = NULL ) continue ; // The GRF is unknown to this server
/* If the reply might exceed the size of the packet, only reply
* the current list and do not send the other data */
packet_len + = sizeof ( c . grfid ) + sizeof ( c . md5sum ) + min ( strlen ( f - > name ) + 1 , NETWORK_GRF_NAME_LENGTH ) ;
if ( packet_len > SEND_MTU - 4 ) { // 4 is 3 byte header + grf count in reply
break ;
}
in_reply [ in_reply_count ] = f ;
in_reply_count + + ;
}
if ( in_reply_count = = 0 ) return ;
packet = NetworkSend_Init ( PACKET_UDP_SERVER_NEWGRFS ) ;
NetworkSend_uint8 ( packet , in_reply_count ) ;
for ( i = 0 ; i < in_reply_count ; i + + ) {
char name [ NETWORK_GRF_NAME_LENGTH ] ;
ttd_strlcpy ( name , in_reply [ i ] - > name , sizeof ( name ) ) ;
NetworkSend_GRFIdentifier ( packet , in_reply [ i ] ) ;
NetworkSend_string ( packet , name ) ;
}
NetworkSendUDP_Packet ( _udp_server_socket , packet , client_addr ) ;
free ( packet ) ;
}
/** The return of the client's request of the names of some NewGRFs */
DEF_UDP_RECEIVE_COMMAND ( PACKET_UDP_SERVER_NEWGRFS )
{
uint8 num_grfs ;
uint i ;
/* Just a fail-safe.. should never happen */
if ( _udp_cs . has_quit ) return ;
DEBUG ( net , 6 ) ( " [NET][UDP] NewGRF data reply from %s:%d " , inet_ntoa ( client_addr - > sin_addr ) , ntohs ( client_addr - > sin_port ) ) ;
num_grfs = NetworkRecv_uint8 ( & _udp_cs , p ) ;
if ( num_grfs > NETWORK_MAX_GRF_COUNT ) return ;
for ( i = 0 ; i < num_grfs ; i + + ) {
char * unknown_name ;
char name [ NETWORK_GRF_NAME_LENGTH ] ;
GRFConfig c ;
NetworkRecv_GRFIdentifier ( p , & c ) ;
NetworkRecv_string ( & _udp_cs , p , name , sizeof ( name ) ) ;
/* Finds the fake GRFConfig for the just read GRF ID and MD5sum tuple.
* If it exists and not resolved yet , then name of the fake GRF is
* overwritten with the name from the reply . */
unknown_name = FindUnknownGRFName ( c . grfid , c . md5sum , false ) ;
if ( unknown_name ! = NULL & & strcmp ( unknown_name , UNKNOWN_GRF_NAME_PLACEHOLDER ) = = 0 ) {
ttd_strlcpy ( unknown_name , name , NETWORK_GRF_NAME_LENGTH ) ;
}
}
}
// The layout for the receive-functions by UDP
// The layout for the receive-functions by UDP
typedef void NetworkUDPPacket ( Packet * p , struct sockaddr_in * client_addr ) ;
typedef void NetworkUDPPacket ( Packet * p , struct sockaddr_in * client_addr ) ;
@ -313,7 +533,9 @@ static NetworkUDPPacket* const _network_udp_packet[] = {
RECEIVE_COMMAND ( PACKET_UDP_MASTER_ACK_REGISTER ) ,
RECEIVE_COMMAND ( PACKET_UDP_MASTER_ACK_REGISTER ) ,
NULL ,
NULL ,
RECEIVE_COMMAND ( PACKET_UDP_MASTER_RESPONSE_LIST ) ,
RECEIVE_COMMAND ( PACKET_UDP_MASTER_RESPONSE_LIST ) ,
NULL
NULL ,
RECEIVE_COMMAND ( PACKET_UDP_CLIENT_GET_NEWGRFS ) ,
RECEIVE_COMMAND ( PACKET_UDP_SERVER_NEWGRFS ) ,
} ;
} ;