Files
Taylor Richards 0e059459d8 improve PXO data validation code (#3817)
* add batch validation for tables
* add batch validation for missions
* handle server connection errors in a more useful way
2021-12-23 09:06:26 -05:00

325 lines
13 KiB
C

/*
* Copyright (C) Volition, Inc. 2005. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
#ifndef _pilot_track_header
#define _pilot_track_header
#include "stats/scoring.h" // for medals count
//Pilot tracker client header
#define REGPORT 9243
#define MAX_NET_RETRIES 30
#define NET_ACK_TIMEOUT 2500
#define MAX_PXO_FILENAME_LEN 32
//This is for type
#define UNT_CONTROL 0
#define UNT_NEW_ID_REQUEST 1
#define UNT_VALIDAT_ID_REQUEST 2
#define UNT_LOOKUP_ID_REQUEST 3
#define UNT_UPDATE_ID_REQUEST 4
#define UNT_MOTD_REQUEST 5
#define UNT_MOTD_RESPONSE 6
#define UNT_PILOT_DATA_READ 7 // Request from the game for pilot info
#define UNT_PILOT_DATA_RESPONSE 8 // Mastertracker's response to a read request (has pilot data in this packet)
#define UNT_PILOT_DATA_WRITE 9 // Request from the server to write a user record
#define UNT_PILOT_WRITE_FAILED 10 // Server didn't update the pilots record for some reason
#define UNT_PILOT_WRITE_SUCCESS 11 // Server updated the pilots record
#define UNT_PILOT_READ_FAILED 12 // Couldn't find the record
#define UNT_LOGIN_AUTH_REQUEST 13 // Request login authentication by login/password only (returns tracker id)
#define UNT_LOGIN_NO_AUTH 14 // Couldn't login this user (code has reason)
#define UNT_LOGIN_AUTHENTICATED 15 // User was authenticated (data has sz string with tracker id)
#define UNT_VALID_FS_MSN_REQ 18 // Client asking if this is a valid mission
#define UNT_VALID_FS_MSN_RSP 19 // Server Response (code has the answer)
#define UNT_PILOT_DATA_READ_NEW 20 // New packet for requesting reads (tracker will get new security field when receiving this)
#define UNT_PILOT_DATA_WRITE_NEW 21 // New packet for requesting writes (tracker will compare security fields if this packet is used)
// 22 through 45 are D3 specific codes
#define UNT_VALID_FS2_MSN_REQ 46 // validated mission request to PXO for FS2
#define UNT_VALID_FS2_MSN_RSP 47 // validated mission response from PXO for FS2
// validate a squad war mission
#define UNT_VALID_SW_MSN_REQ 48 // send info about a squad war mission, wait for tracker response
#define UNT_VALID_SW_MSN_RSP 49 // response from the tracker
#define UNT_SW_RESULT_WRITE 50 // report on a finished squad war mission to the tracker
#define UNT_SW_RESULT_RESPONSE 51 // response on a squad war mission write request
#define UNT_CONTROL_VALIDATION 70 // UNT_CONTROL for validation packets
#define UNT_VALID_MSN_REQ 71 // Client asking if this is a valid mission
#define UNT_VALID_MSN_RSP 72 // Server response (code has the answer)
#define UNT_VALID_TBL_REQ 73 // Client asking if this is a valid table
#define UNT_VALID_TBL_RSP 74 // Server response (code has the answer)
#define UNT_VALID_DATA_REQ 75 // client asking for data validity check
#define UNT_VALID_DATA_RSP 76 // server response
//This is for code
#define CMD_NEW_USER_ACK 1
#define CMD_NEW_USER_NAK 2
#define CMD_VALIDATED_USER_ACK 3
#define CMD_UPDATED_USER_ACK 4
#define CMD_CLIENT_RECEIVED 5
#define CMD_FIND_USER_NAK 6
#define CMD_FIND_USER_ACK 7
#define CMD_UPDATED_USER_NAK 8
#define CMD_VALIDATED_USER_NAK 9
//Game designators for UNT_PILOT_DATA_REQUEST and UNT_PILOT_DATA_RESPONSE
#define CMD_GAME_FREESPACE 10
#define CMD_GAME_DESCENT3 11
#define CMD_GAME_FREESPACE2 12
#define CMD_GAME_FS2OPEN 13
//This is for xcode
#define REG_NAK_EMAIL 0 // failed to register the guy because of an invalid email address
#define REG_NAK_LOGIN 1 // failed to register the guy because an existing login exists
#define REG_NAK_ERROR 2 // failed to register because of an error on the tracker
#define REG_NAK_STRINGS 3 // failed to validate because of invalid password/login match
#define REG_NAK_UNKNOWN 4 // failed to validate because the player is unknown
#define REG_NAK_UPDATE_PL 5 // update info failed because login/passwd were not correct
#define REG_NAK_UPDATE_GEN 6 // update info failed in general (tracker problem)
#define REG_NAK_UPDATE_LOG 7 // update failed because login not found
#define REG_ACK_NEW_ID 8 // New id created, just used for return code, not net packets.
#define MAX_UDP_DATA_LENGH 500
#define PACKED_HEADER_ONLY_SIZE (sizeof(udp_packet_header)-MAX_UDP_DATA_LENGH)
//sizeof(update_id_request) //The largest packet
#define LOGIN_LEN 33
#define REAL_NAME_LEN 66
#define PASSWORD_LEN 17
#define EMAIL_LEN 100
#define TRACKER_ID_LEN 10
#define PILOT_NAME_LEN 20
#define MATCH_CODE_LEN 34
#define MAX_SQUAD_PLAYERS 4
#define MAX_SQUAD_RESPONSE_LEN 255
// data could be one of the following:
// type == UNT_NEW_ID_REQUEST
// Respond with ACK
typedef struct {
char first_name[REAL_NAME_LEN]; // Real Name
char last_name[REAL_NAME_LEN]; // Real Name
char login[LOGIN_LEN]; // Login id
char password[PASSWORD_LEN]; // password
char email[EMAIL_LEN]; // Email Address
unsigned char showemail; // 0==don't show 1 == show
unsigned char showname; // 0==don't show 1 == show
} new_id_request;
// type == UNT_VALIDAT_ID_REQUEST or UNT_LOOKUP_ID_REQUEST
typedef struct {
char login[LOGIN_LEN]; // Login id
char password[PASSWORD_LEN]; // password
char tracker_id[TRACKER_ID_LEN]; // Tracker ID
} validate_id_request;
// type == UNT_UPDATE_ID_REQUEST
typedef struct {
char old_login[LOGIN_LEN]; // Login before it's changed.
char old_password[PASSWORD_LEN]; // Password before it's changed
char tracker_id[TRACKER_ID_LEN]; // Tracker ID (not sure if we need it for updating, but maybe)
char first_name[REAL_NAME_LEN]; // Real Name
char last_name[REAL_NAME_LEN]; // Real Name
char login[LOGIN_LEN]; // Login id (new)
char password[PASSWORD_LEN]; // password (new)
char email[EMAIL_LEN]; // Email Address (new)
unsigned char showemail; // 0==don't show 1 == show
unsigned char showname; // 0==don't show 1 == show
} update_id_request;
typedef struct {
char pilot_name[PILOT_NAME_LEN]; // Login id
char tracker_id[TRACKER_ID_LEN]; // Tracker ID
char pad[2]; // 2-bytes padding
} pilot_request;
// type == UNT_VALID_SW_MSN_REQ
typedef struct squad_war_request {
int squad_plr1[MAX_SQUAD_PLAYERS]; // id #'s for all squad members in the match
int squad_plr2[MAX_SQUAD_PLAYERS]; // id #'s for all squad memebrs in the match
ubyte squad_count1; // # of players present in squad 1
ubyte squad_count2; // # of players present in squad 2
char match_code[MATCH_CODE_LEN]; // code for the match
char mission_filename[MAX_PXO_FILENAME_LEN]; // filename of mission
int mission_checksum; // mission checksum
} squad_war_request;
// type == UNT_SW_RESULT_WRITE
typedef struct squad_war_result {
char match_code[MATCH_CODE_LEN]; // code for the match
ubyte result; // result of the match, 0 == tie, 1 == one team won
ubyte squad_count1; // # of players in winning squad
ubyte squad_count2; // # of players in the losing squad
char pad[3]; // 3-bytes padding
int squad_winners[MAX_SQUAD_PLAYERS]; // list of players on the winning team
int squad_losers[MAX_SQUAD_PLAYERS]; // list of players on the losing team
} squad_war_result;
// type == UNT_VALID_SW_MSN_RSP and UNT_SW_RESULT_RESPONSE
typedef struct squad_war_response {
char reason[MAX_SQUAD_RESPONSE_LEN];
unsigned char accepted;
} squad_war_response;
// type == UNT_VALID_DATA_REQ and UNT_VAID_DATA_RSP
enum {
VDR_TYPE_TABLE = 0,
VDR_TYPE_MISSION = 1,
VDR_TYPE_SCRIPT = 2
};
enum {
VDR_FLAG_IDENT = 1<<0, // include mod ident in response
VDR_FLAG_STATUS = 1<<1 // include individual file valid status in response
};
struct valid_data_item {
uint32_t crc;
SCP_string name;
};
// NOTE: This is packed manually and should not be associated/copied/cast to the data block!!
struct vmt_valid_data_req_struct {
uint8_t type;
uint8_t flags;
uint8_t num_files;
SCP_vector<valid_data_item> files;
};
// NOTE: This is not used directly but listed here to document the packet
/*
struct vmt_valid_data_rsp_struct {
uint8_t flags;
// if VDR_FLAG_IDENT is set
short game_id;
SCP_string game_tag;
SCP_string game_name;
// if VDR_FLAG_STATUS is set
uint8_t status_count;
SCP_vector<uint32_t> status;
};
*/
#pragma pack(push, 1)
typedef struct {
unsigned char type; // type
unsigned short len; // Length of total packet, including this header
unsigned int code; // For control messages
unsigned short xcode; // For control/NAK messages and for sigs.
unsigned int sig; // To identify unique return ACKs
unsigned int security; // Just a random value, we store the last value used in the user record
// So we don't process the same request twice.
unsigned char data[MAX_UDP_DATA_LENGH];
} udp_packet_header;
#pragma pack(pop)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// GAME SPECIFIC structures
// -----------------------------------------------------------------------------
// FS2 Open
// NOTE: struct is packed when serialized, padding bytes ignored
const unsigned short MAX_FS2OPEN_COUNTS = 192;
struct vmt_fs2open_struct {
int tracker_id;
char pilot_name[PILOT_NAME_LEN];
int score;
int rank;
int assists;
int kill_count; // total alltime kills
int kill_count_ok; // total valid alltime kills (no friendlies)
unsigned int p_shots_fired; // primary weapon
unsigned int s_shots_fired; // secondary weapon
unsigned int p_shots_hit; // primary
unsigned int s_shots_hit; // secondary
unsigned int p_bonehead_hits; // hits/kills on the players own team
unsigned int s_bonehead_hits;
int bonehead_kills;
unsigned int missions_flown; // # of missions flown to completion
unsigned int flight_time; // total hours of flight time
unsigned int last_flown; // data/time of last mission flown
int security;
unsigned int checksum; // This value needs to be equal to whatever the checksum is once the packet is decoded
unsigned char virgin_pilot; // This pilot was just created if TRUE
char pad; // IGNORED!! 1-byte padding (alignment)
unsigned char num_medals;
unsigned char num_ships;
unsigned short counts[MAX_FS2OPEN_COUNTS]; // <-- This *must* be last entry!!!!
};
const unsigned short FS2OPEN_BLOCK_SIZE = sizeof(vmt_fs2open_struct) - 1; // ignore pad byte in size
#define vmt_stats_struct vmt_fs2open_struct
#define STATS_BLOCK_SIZE FS2OPEN_BLOCK_SIZE
//Function prototypes
int InitPilotTrackerClient();
void AckServer(unsigned int sig);
int SendFSPilotData(vmt_stats_struct *fs_pilot);
int GetFSPilotData(vmt_stats_struct *fs_pilot, const char *pilot_name, const char *tracker_id, int update_security);
int SendSWData(squad_war_result *sw_res, squad_war_response *sw_resp);
void PollPTrackNet();
//Definitions
#define STATE_IDLE 0
#define STATE_SENDING_PILOT 1
#define STATE_READING_PILOT 2
#define STATE_RECEIVED_PILOT 3
#define STATE_WROTE_PILOT 4
#define STATE_TIMED_OUT 5
#define STATE_PILOT_NOT_FOUND 6
#define STATE_WRITE_PILOT_FAILED 7
#define PILOT_REQ_TIMEOUT 30000
#define PILOT_REQ_RESEND_TIME 3500
#define PXO_ADD_DATA(d) do { memcpy(data+packet_size, &d, sizeof(d) ); packet_size += sizeof(d); } while (false)
#define PXO_ADD_SHORT(d) do { short swap = INTEL_SHORT(d); memcpy(data+packet_size, &swap, sizeof(d) ); packet_size += sizeof(d); } while (false)
#define PXO_ADD_USHORT(d) do { ushort swap = INTEL_SHORT(d); memcpy(data+packet_size, &swap, sizeof(d) ); packet_size += sizeof(d); } while (false)
#define PXO_ADD_INT(d) do { int swap = INTEL_INT(d); memcpy(data+packet_size, &swap, sizeof(d) ); packet_size += sizeof(d); } while (false)
#define PXO_ADD_UINT(d) do { uint swap = INTEL_INT(d); memcpy(data+packet_size, &swap, sizeof(d) ); packet_size += sizeof(d); } while (false)
#define PXO_ADD_STRING(d, l) do { size_t len = SDL_strlcpy(reinterpret_cast<char *>(data+packet_size), reinterpret_cast<const char *>(d), l-packet_size); packet_size += static_cast<unsigned short>(SDL_min(len+1, static_cast<size_t>(l-packet_size))); } while (0)
#define PXO_GET_DATA(d) do { memcpy(&d, data+offset, sizeof(d) ); offset += sizeof(d); } while(false)
#define PXO_GET_SHORT(d) do { short swap; memcpy(&swap, data+offset, sizeof(d) ); d = INTEL_SHORT(swap); offset += sizeof(d); } while(false)
#define PXO_GET_USHORT(d) do { ushort swap; memcpy(&swap, data+offset, sizeof(d) ); d = INTEL_SHORT(swap); offset += sizeof(d); } while(false)
#define PXO_GET_INT(d) do { int swap; memcpy(&swap, data+offset, sizeof(d) ); d = INTEL_INT(swap); offset += sizeof(d); } while(false)
#define PXO_GET_UINT(d) do { uint swap; memcpy(&swap, data+offset, sizeof(d) ); d = INTEL_INT(swap); offset += sizeof(d); } while(false)
#define PXO_GET_STRING(d) do { size_t len = SDL_strlcpy(d, reinterpret_cast<const char *>(data+offset), SDL_arraysize(d)); offset += static_cast<unsigned short>(SDL_min(len+1, SDL_arraysize(d))); } while(0)
#endif