Short-circuit network version mismatch tests

Once one component is known not to match, there is no reason to read the
other components from memory.
This commit is contained in:
Kp 2022-07-09 13:39:29 +00:00
parent 9af7159592
commit c354f9a606

View file

@ -433,6 +433,21 @@ constexpr sockaddr_in6 GMcast_v6 = { // same for IPv6-only
};
#endif
enum class game_info_request_result : uint8_t
{
// Valid request
accept,
/* Game type header does not match. The request is for D1 while this
* program is D2, or vice versa, or the request is not a Rebirth request at
* all.
*/
id_mismatch,
/* Game version mismatch. The peer is running an older or newer
* multiplayer protocol than this program.
*/
version_mismatch,
};
class RAIIsocket
{
#ifndef _WIN32
@ -772,6 +787,27 @@ ssize_t dxx_recvfrom(const int sockfd, const socket_data_buffer msg, const int f
return rv;
}
static game_info_request_result net_udp_check_game_info_request(const uint8_t *const data)
{
if (const auto sender_major_version = GET_INTEL_SHORT(&(data[5])); sender_major_version != DXX_VERSION_MAJORi)
return game_info_request_result::version_mismatch;
if (const auto sender_minor_version = GET_INTEL_SHORT(&(data[7])); sender_minor_version != DXX_VERSION_MINORi)
return game_info_request_result::version_mismatch;
if (const auto sender_micro_version = GET_INTEL_SHORT(&(data[9])); sender_micro_version != DXX_VERSION_MICROi)
return game_info_request_result::version_mismatch;
return game_info_request_result::accept;
}
static game_info_request_result net_udp_check_game_info_request(const uint8_t *const data, int lite)
{
if (!lite)
{
if (const auto sender_proto_version = GET_INTEL_SHORT(&data[11]); sender_proto_version != MULTI_PROTO_VERSION)
return game_info_request_result::version_mismatch;
}
return net_udp_check_game_info_request(data);
}
}
}
@ -2434,6 +2470,14 @@ void net_udp_send_rejoin_sync(const unsigned player_num)
return;
}
static game_info_request_result net_udp_check_game_info_request(const uint8_t *const data, int lite)
{
if (memcmp(&data[1], UDP_REQ_ID, 4))
return game_info_request_result::id_mismatch;
return ::dcx::net_udp_check_game_info_request(data, lite);
}
}
}
@ -2682,28 +2726,6 @@ static void net_udp_process_version_deny(const uint8_t *const data, const _socka
Netgame.protocol.udp.valid = -1;
}
// Check request for game info. Return 1 if sucessful; -1 if version mismatch; 0 if wrong game or some other error - do not process
static int net_udp_check_game_info_request(const uint8_t *const data, int lite)
{
short sender_iver[4] = { 0, 0, 0, 0 };
char sender_id[4] = "";
memcpy(&sender_id, &(data[1]), 4);
sender_iver[0] = GET_INTEL_SHORT(&(data[5]));
sender_iver[1] = GET_INTEL_SHORT(&(data[7]));
sender_iver[2] = GET_INTEL_SHORT(&(data[9]));
if (!lite)
sender_iver[3] = GET_INTEL_SHORT(&(data[11]));
if (memcmp(&sender_id, UDP_REQ_ID, 4))
return 0;
if ((sender_iver[0] != DXX_VERSION_MAJORi) || (sender_iver[1] != DXX_VERSION_MINORi) || (sender_iver[2] != DXX_VERSION_MICROi) || (!lite && sender_iver[3] != MULTI_PROTO_VERSION))
return -1;
return 1;
}
struct game_info_light
{
std::array<uint8_t, UPID_GAME_INFO_LITE_SIZE_MAX> buf;
@ -3141,6 +3163,11 @@ static void net_udp_process_request(const UDP_sequence_request_packet &their, co
}
}
}
namespace dsx {
namespace {
static void net_udp_process_packet(const d_level_shared_robot_info_state &LevelSharedRobotInfoState, uint8_t *const data, const _sockaddr &sender_addr, int length)
{
switch (data[0])
@ -3152,18 +3179,26 @@ static void net_udp_process_packet(const d_level_shared_robot_info_state &LevelS
break;
case UPID_GAME_INFO_REQ:
{
int result = 0;
static fix64 last_full_req_time = 0;
if (!multi_i_am_master() || length != UPID_GAME_INFO_REQ_SIZE)
break;
if (timer_query() < last_full_req_time+(F1_0/2)) // answer 2 times per second max
break;
last_full_req_time = timer_query();
result = net_udp_check_game_info_request(data, 0);
if (result == -1)
net_udp_send_version_deny(sender_addr);
else if (result == 1)
net_udp_send_game_info(sender_addr, &sender_addr, UPID_GAME_INFO);
switch (net_udp_check_game_info_request(data, 0))
{
case game_info_request_result::accept:
net_udp_send_game_info(sender_addr, &sender_addr, UPID_GAME_INFO);
break;
case game_info_request_result::id_mismatch:
/* No response - peer is not the same type of Descent, and
* may not be Descent at all.
*/
break;
case game_info_request_result::version_mismatch:
net_udp_send_version_deny(sender_addr);
break;
}
break;
}
case UPID_GAME_INFO:
@ -3179,8 +3214,22 @@ static void net_udp_process_packet(const d_level_shared_robot_info_state &LevelS
if (timer_query() < last_lite_req_time+(F1_0/8))// answer 8 times per second max
break;
last_lite_req_time = timer_query();
if (net_udp_check_game_info_request(data, 1) == 1)
net_udp_send_game_info(sender_addr, &sender_addr, UPID_GAME_INFO_LITE);
switch (net_udp_check_game_info_request(data, 1))
{
case game_info_request_result::accept:
net_udp_send_game_info(sender_addr, &sender_addr, UPID_GAME_INFO_LITE);
break;
case game_info_request_result::id_mismatch:
/* No response - peer is not the same type of Descent, and
* may not be Descent at all.
*/
case game_info_request_result::version_mismatch:
/* No response - peer was speculatively searching for games
* of the same version, and does not want to receive
* responses from version-incompatible programs.
*/
break;
}
break;
}
case UPID_GAME_INFO_LITE:
@ -3291,6 +3340,11 @@ static void net_udp_process_packet(const d_level_shared_robot_info_state &LevelS
}
}
}
}
namespace {
// Packet for end of level syncing
void net_udp_read_endlevel_packet(const uint8_t *data, const _sockaddr &sender_addr)
{