mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-11 04:31:35 -10:00
make the chat channel count update more than once, since that didn't appear to work very well fix compile error with GCC 4.3
1549 lines
34 KiB
C++
1549 lines
34 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. 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.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* $Logfile: /freespace2/code/fs2netd/fs2netd_client.cpp $
|
|
* $Revision: 1.1.2.3 $
|
|
* $Date: 2007-11-22 05:04:07 $
|
|
* $Author: taylor $
|
|
*
|
|
* FS2NetD client handler
|
|
*
|
|
* $Log: not supported by cvs2svn $
|
|
* Revision 1.1.2.2 2007/10/15 08:18:33 taylor
|
|
* Oops, forgot that the v.2 daemon is still on the secondary IP :)
|
|
*
|
|
* Revision 1.1.2.1 2007/10/15 06:43:09 taylor
|
|
* FS2NetD v.2 (still a work in progress, but is ~98% complete)
|
|
*
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include "globalincs/pstypes.h"
|
|
#include "fs2netd/fs2netd_client.h"
|
|
#include "fs2netd/tcp_client.h"
|
|
#include "cfile/cfile.h"
|
|
#include "network/multi_log.h"
|
|
#include "osapi/osregistry.h"
|
|
#include "popup/popup.h"
|
|
#include "gamesnd/gamesnd.h"
|
|
#include "network/multi.h"
|
|
#include "playerman/player.h"
|
|
#include "io/timer.h"
|
|
#include "network/multiutil.h"
|
|
#include "network/multiui.h"
|
|
#include "network/stand_gui.h"
|
|
#include "network/multi_pxo.h"
|
|
#include "bmpman/bmpman.h"
|
|
#include "graphics/2d.h"
|
|
#include "graphics/font.h"
|
|
#include "globalincs/alphacolors.h"
|
|
#include "network/multi_options.h"
|
|
#include "cmdline/cmdline.h"
|
|
#include "cfile/cfilesystem.h"
|
|
|
|
#ifdef WIN32
|
|
//#include <windows.h>
|
|
//#include <process.h>
|
|
#else
|
|
#include <cstdio>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <cerrno>
|
|
#endif
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <limits.h>
|
|
|
|
|
|
#define FS2NETD_DEFAULT_PORT "12009"
|
|
#define FS2NETD_DEFAULT_SERVER "fs2netd.game-warden.com"
|
|
#define FS2NETD_DEFAULT_CHAT_SERVER "fs2netd.game-warden.com"
|
|
#define FS2NETD_DEFAULT_BANNER_URL "http://fs2netd.game-warden.com/files/banners"
|
|
|
|
|
|
extern int Om_tracker_flag; // needed to know whether or not to use FS2OpenPXO
|
|
extern int Multi_debrief_stats_accept_code;
|
|
extern void HUD_printf(char *format, ...);
|
|
extern int game_hacked_data();
|
|
void multi_update_valid_tables(); // from multiutil
|
|
extern int Multi_create_force_heartbeat; // to force a master heardbeat packet be sent (rather than waiting for timeout)
|
|
extern void send_udp_hole_punch(char *ip, short port, short state);
|
|
|
|
static int PXO_SID = -1; // FS2 Open PXO Session ID
|
|
static char PXO_Server[64] = { 0 };
|
|
static ushort PXO_port = 0;
|
|
static bool Is_connected = false;
|
|
static bool In_process = false;
|
|
static bool Logged_in = false;
|
|
static int do_full_packet = 1;
|
|
static fix timeout = -1;
|
|
static fix NextHeartBeat = -1;
|
|
static ushort GameServerPort = 0;
|
|
|
|
static int FS2NetD_file_list_count = -1;
|
|
static file_record *FS2NetD_file_list = NULL;
|
|
|
|
static int FS2NetD_ban_list_count = -1;
|
|
static fs2open_banmask *FS2NetD_ban_list = NULL;
|
|
|
|
std::vector<crc_valid_status> Table_valid_status;
|
|
|
|
// channel to associate when creating a server
|
|
char Multi_fs_tracker_channel[MAX_PATH] = "";
|
|
|
|
// channel to use when polling the tracker for games
|
|
char Multi_fs_tracker_filter[MAX_PATH] = "";
|
|
|
|
|
|
void fs2netd_options_config_init()
|
|
{
|
|
if ( !strlen(Multi_options_g.game_tracker_ip) ) {
|
|
ml_printf("FS2NetD MSG: Address for game tracker not specified, using default instead (%s).", FS2NETD_DEFAULT_SERVER);
|
|
strncpy( Multi_options_g.game_tracker_ip, FS2NETD_DEFAULT_SERVER, MULTI_OPTIONS_STRING_LEN );
|
|
}
|
|
|
|
if ( !strlen(Multi_options_g.user_tracker_ip) ) {
|
|
ml_printf("FS2NetD MSG: Address for user tracker not specified, using default instead (%s).", FS2NETD_DEFAULT_SERVER);
|
|
strncpy( Multi_options_g.user_tracker_ip, FS2NETD_DEFAULT_SERVER, MULTI_OPTIONS_STRING_LEN );
|
|
}
|
|
|
|
if ( !strlen(Multi_options_g.tracker_port) ) {
|
|
ml_printf("FS2NetD MSG: Port for game/user trackers not specified, using default instead (%u).", FS2NETD_DEFAULT_PORT);
|
|
strncpy( Multi_options_g.tracker_port, FS2NETD_DEFAULT_PORT, STD_NAME_LEN );
|
|
}
|
|
|
|
if ( !strlen(Multi_options_g.pxo_ip) ) {
|
|
ml_printf("FS2NetD MSG: Address for chat server not specified, using default instead (%s).", FS2NETD_DEFAULT_CHAT_SERVER);
|
|
strncpy( Multi_options_g.pxo_ip, FS2NETD_DEFAULT_CHAT_SERVER, MULTI_OPTIONS_STRING_LEN );
|
|
}
|
|
|
|
if ( !strlen(Multi_options_g.pxo_banner_url) ) {
|
|
ml_printf("FS2NetD MSG: URL for banners not specified, using default instead (%s).", FS2NETD_DEFAULT_BANNER_URL);
|
|
strncpy( Multi_options_g.pxo_banner_url, FS2NETD_DEFAULT_BANNER_URL, MULTI_OPTIONS_STRING_LEN );
|
|
}
|
|
}
|
|
|
|
static int fs2netd_connect_do()
|
|
{
|
|
int retval = FS2NetD_ConnectToServer(PXO_Server, PXO_port);
|
|
|
|
Sleep(5);
|
|
|
|
switch (retval) {
|
|
// connection failed
|
|
case -1:
|
|
Is_connected = false;
|
|
return 2;
|
|
|
|
// still trying to connect
|
|
case 0:
|
|
return 0;
|
|
|
|
// connected!
|
|
case 1:
|
|
Is_connected = true;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void fs2netd_connect()
|
|
{
|
|
int rc = 0;
|
|
|
|
// don't bother with this if we aren't on FS2NetD
|
|
if ( !Om_tracker_flag ) {
|
|
return;
|
|
}
|
|
|
|
if ( !(Game_mode & GM_MULTIPLAYER) ) {
|
|
return;
|
|
}
|
|
|
|
if (Is_connected) {
|
|
return;
|
|
}
|
|
|
|
|
|
if ( !PXO_port ) {
|
|
Assert( strlen(Multi_options_g.game_tracker_ip) );
|
|
Assert( strlen(Multi_options_g.tracker_port) );
|
|
|
|
if ( strlen(Multi_options_g.game_tracker_ip) ) {
|
|
strncpy( PXO_Server, Multi_options_g.game_tracker_ip, sizeof(PXO_Server) - 1 );
|
|
} else {
|
|
ml_printf("FS2NetD ERROR: No server specified in multi.cfg! Using default instead (%s)!", FS2NETD_DEFAULT_SERVER);
|
|
strncpy( PXO_Server, FS2NETD_DEFAULT_SERVER, sizeof(PXO_Server) - 1 );
|
|
}
|
|
|
|
if ( strlen(Multi_options_g.tracker_port) ) {
|
|
long tmp = strtol(Multi_options_g.tracker_port, (char**)NULL, 10);
|
|
|
|
if ( (tmp < 1024) || (tmp > USHRT_MAX) ) {
|
|
ml_printf("FS2NetD ERROR: The port specified in multi.cfg, '%i', is outside of the required range, %i through %i!", tmp, 1024, USHRT_MAX);
|
|
ml_printf("Fs2NetD ERROR: Setting port to default value (%s) ...", FS2NETD_DEFAULT_PORT);
|
|
PXO_port = (ushort) strtol(FS2NETD_DEFAULT_PORT, (char**)NULL, 10);
|
|
} else {
|
|
PXO_port = (ushort)tmp;
|
|
}
|
|
} else {
|
|
PXO_port = (ushort) strtol(FS2NETD_DEFAULT_PORT, (char**)NULL, 10);
|
|
}
|
|
}
|
|
|
|
In_process = true;
|
|
|
|
if (Is_standalone) {
|
|
do { rc = fs2netd_connect_do(); } while (!rc);
|
|
} else {
|
|
popup_till_condition(fs2netd_connect_do, XSTR("&Cancel", 779), XSTR("Connecting into FS2NetD", -1));
|
|
}
|
|
|
|
In_process = false;
|
|
}
|
|
|
|
int fs2netd_login_do()
|
|
{
|
|
if (PXO_SID < 0) {
|
|
if ( Is_standalone && std_gen_is_active() ) {
|
|
std_gen_set_text("Verifying username and password", 1);
|
|
} else {
|
|
popup_change_text( XSTR("Verifying username and password", -1) );
|
|
}
|
|
|
|
if (timeout == -1) {
|
|
timeout = timer_get_fixed_seconds() + (15 * F1_0);
|
|
}
|
|
|
|
// if timeout passes then bail on SID failure
|
|
if ( timer_get_fixed_seconds() > timeout ) {
|
|
timeout = -1;
|
|
return 2;
|
|
}
|
|
|
|
PXO_SID = FS2NetD_Login(Multi_tracker_login, Multi_tracker_passwd, do_full_packet);
|
|
|
|
// if we have already been through once then only deal with the recieve packet next time
|
|
do_full_packet = 0;
|
|
|
|
// invalid login
|
|
if (PXO_SID == -2) {
|
|
timeout = -1;
|
|
return 1;
|
|
}
|
|
|
|
if (PXO_SID >= 0) {
|
|
ml_printf("FS2NetD MSG: Login '%s' is valid, session ID is %i!", Multi_tracker_login, PXO_SID);
|
|
do_full_packet = 1;
|
|
timeout = -1;
|
|
}
|
|
} else {
|
|
if ( Is_standalone && std_gen_is_active() ) {
|
|
std_gen_set_text("Getting pilot stats", 1);
|
|
} else {
|
|
popup_change_text( XSTR("Getting pilot stats", -1) );
|
|
}
|
|
|
|
if (timeout == -1) {
|
|
timeout = timer_get_fixed_seconds() + (30 * F1_0);
|
|
}
|
|
|
|
// if timeout passes then bail on stats failure
|
|
if ( timer_get_fixed_seconds() > timeout ) {
|
|
timeout = -1;
|
|
return 2;
|
|
}
|
|
|
|
int rescode = FS2NetD_GetPlayerData(PXO_SID, Players[Player_num].callsign, &Players[Player_num], true, do_full_packet);
|
|
|
|
do_full_packet = 0;
|
|
|
|
if ( rescode != -1 ) {
|
|
timeout = -1;
|
|
return (rescode + 3);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool fs2netd_login()
|
|
{
|
|
bool retval = true;
|
|
int rc;
|
|
|
|
// don't bother with this if we aren't on FS2NetD
|
|
if ( !Om_tracker_flag ) {
|
|
return false;
|
|
}
|
|
|
|
if ( !(Game_mode & GM_MULTIPLAYER) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( Logged_in && (PXO_SID >= 0) ) {
|
|
return true;
|
|
}
|
|
|
|
Logged_in = false;
|
|
|
|
fs2netd_connect();
|
|
|
|
if ( !Is_connected ) {
|
|
if ( !Is_standalone ) {
|
|
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Failed to connect to FS2NetD server!", -1));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
char error_str[256];
|
|
|
|
do_full_packet = 1;
|
|
|
|
In_process = true;
|
|
|
|
if (Is_standalone) {
|
|
do { rc = fs2netd_login_do(); } while (!rc);
|
|
} else {
|
|
rc = popup_till_condition(fs2netd_login_do, XSTR("&Cancel", 779), XSTR("Logging into FS2NetD", -1));
|
|
}
|
|
|
|
In_process = false;
|
|
|
|
memset( error_str, 0, sizeof(error_str) );
|
|
|
|
switch (rc) {
|
|
// the action was cancelled
|
|
case 0:
|
|
retval = false;
|
|
break;
|
|
|
|
// didn't get a session id
|
|
case 1:
|
|
ml_printf("FS2NetD ERROR: Login %s/%s is invalid!", Multi_tracker_login, Multi_tracker_passwd);
|
|
strcpy(error_str, "Login failed!");
|
|
retval = false;
|
|
break;
|
|
|
|
// unknown failure fetching pilot data
|
|
case 2:
|
|
ml_printf("FS2NetD ERROR: UNKNOWN ERROR when fetching pilot data");
|
|
strcpy(error_str, "An Unknown Error (probably a timeout) occured when trying to retrieve your pilot data.");
|
|
retval = false;
|
|
break;
|
|
|
|
// success!!
|
|
case 3:
|
|
ml_printf("FS2NetD MSG: Got Pilot data");
|
|
retval = true;
|
|
break;
|
|
|
|
// success!! pilot was created
|
|
case 4:
|
|
ml_printf("FS2NetD MSG: Created New Pilot");
|
|
strcpy(error_str, "New Pilot has been created.");
|
|
retval = true;
|
|
break;
|
|
|
|
// invalid pilot name
|
|
case 5:
|
|
ml_printf("FS2NetD ERROR: Invalid Pilot!");
|
|
strcpy(error_str, "Invalid Pilot name - A serious error has occured, Contact the FS2NetD Administrator!");
|
|
retval = false;
|
|
break;
|
|
|
|
// the session id was invalid
|
|
case 6:
|
|
ml_printf("FS2NetD ERROR: Invalid SID!");
|
|
strcpy(error_str, "Invalid SID - A serious error has occured, Contact the FS2NetD Administrator!");
|
|
retval = false;
|
|
break;
|
|
|
|
default:
|
|
ml_printf("FS2NetD ERROR: Unknown return case for GetPlayerData()");
|
|
strcpy(error_str, "Unkown return case from GetPlayerData(). Contact the FS2NetD Administrator!");
|
|
retval = false;
|
|
break;
|
|
}
|
|
|
|
if ( !Is_standalone && strlen(error_str) ) {
|
|
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, error_str);
|
|
}
|
|
|
|
if (retval) {
|
|
Logged_in = true;
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
void fs2netd_do_frame()
|
|
{
|
|
int rc, buffer_size, buffer_offset;
|
|
char buffer[300], str[256];
|
|
ubyte pid = 0;
|
|
int itemp;
|
|
static fix NextPing = -1;
|
|
static fix GotPong = -1;
|
|
bool reset = false;
|
|
|
|
// don't bother with this if we aren't on FS2NetD
|
|
if ( !Om_tracker_flag ) {
|
|
return;
|
|
}
|
|
|
|
if ( !(Game_mode & GM_MULTIPLAYER) ) {
|
|
return;
|
|
}
|
|
|
|
// not connected to server
|
|
if ( !Is_connected ) {
|
|
return;
|
|
}
|
|
|
|
// in a previous processing loop, so don't do a frame until that has completed
|
|
if ( In_process ) {
|
|
return;
|
|
}
|
|
|
|
|
|
// if we didn't get a PONG within 4 minutes the server connection must have dropped
|
|
if ( (GotPong != -1) && ((NextPing - GotPong) > (240 * F1_0)) ) {
|
|
ml_printf("FS2NetD WARNING: Lost connection to server!");
|
|
FS2NetD_Disconnect();
|
|
|
|
Is_connected = false;
|
|
Logged_in = false;
|
|
PXO_SID = -1;
|
|
|
|
NextHeartBeat = -1;
|
|
NextPing = -1;
|
|
GotPong = -1;
|
|
|
|
// try to reinit the server connection
|
|
fs2netd_login();
|
|
|
|
// make sure that we are good to go
|
|
if ( !Is_connected ) {
|
|
if (!Is_standalone) {
|
|
gamesnd_play_iface(SND_GENERAL_FAIL);
|
|
popup(PF_USE_AFFIRMATIVE_ICON | PF_TITLE_BIG | PF_TITLE_RED, 1, POPUP_OK, "ERROR:\nLost connection to the FS2NetD server!");
|
|
}
|
|
|
|
return;
|
|
} else {
|
|
ml_printf("FS2NetD NOTICE: Connection to server has been reestablished!");
|
|
}
|
|
}
|
|
|
|
// send out ping every 60 seconds
|
|
if ( (NextPing == -1) || (timer_get_fixed_seconds() >= NextPing) ) {
|
|
// if we have seen a long period of time between pings then reset the pong time too
|
|
if ( (timer_get_fixed_seconds() - NextPing) > (120 * F1_0) ) {
|
|
reset = true;
|
|
}
|
|
|
|
NextPing = timer_get_fixed_seconds() + (60 * F1_0);
|
|
|
|
// we go ahead and set the initial GotPong here, even though we haven't gotten a pong yet
|
|
if ( (GotPong == -1) || reset ) {
|
|
GotPong = NextPing;
|
|
reset = false;
|
|
}
|
|
|
|
FS2NetD_Ping();
|
|
|
|
// also send out a SID check to keep our login verified
|
|
if ( FS2NetD_CheckValidSID(PXO_SID) < 0 ) {
|
|
ml_printf("FS2NetD WARNING: Unable to validate login!");
|
|
FS2NetD_Disconnect();
|
|
|
|
Logged_in = false;
|
|
PXO_SID = -1;
|
|
|
|
NextHeartBeat = -1;
|
|
NextPing = -1;
|
|
GotPong = -1;
|
|
|
|
// try to log in again
|
|
fs2netd_login();
|
|
|
|
// make sure that we are good to go
|
|
if ( !Is_connected ) {
|
|
if (!Is_standalone) {
|
|
gamesnd_play_iface(SND_GENERAL_FAIL);
|
|
popup(PF_USE_AFFIRMATIVE_ICON | PF_TITLE_BIG | PF_TITLE_RED, 1, POPUP_OK, "ERROR:\nLost connection to the FS2NetD server!");
|
|
}
|
|
|
|
return;
|
|
} else {
|
|
ml_printf("FS2NetD NOTICE: Connection to server has been reestablished!");
|
|
}
|
|
}
|
|
|
|
ml_printf("FS2NetD sent PING/IDENT");
|
|
}
|
|
|
|
// handle server heart beats
|
|
fs2netd_server_send_heartbeat();
|
|
|
|
// Check for GWall messages - ping replies, etc
|
|
if ( (rc = FS2NetD_GetData(buffer, sizeof(buffer))) != -1 ) {
|
|
int rc_total = rc;
|
|
buffer_offset = 0;
|
|
|
|
while (rc_total > buffer_offset) {
|
|
// make sure we have enough data to try and process
|
|
if (rc_total < BASE_PACKET_SIZE) {
|
|
break;
|
|
}
|
|
|
|
PXO_GET_DATA( pid );
|
|
PXO_GET_INT( buffer_size );
|
|
|
|
while ( (rc_total < buffer_size) && ((sizeof(buffer) - rc_total) > 0) ) {
|
|
if ( (rc = FS2NetD_GetData(buffer+rc_total, sizeof(buffer) - rc_total)) != -1 ) {
|
|
rc_total += rc;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (buffer_size <= 0) {
|
|
break;
|
|
}
|
|
|
|
// we don't have the full packet, so bail
|
|
if ( rc_total < (buffer_offset+buffer_size-BASE_PACKET_SIZE) ) {
|
|
break;
|
|
}
|
|
|
|
// processing time!
|
|
switch (pid) {
|
|
case PCKT_PING: {
|
|
PXO_GET_INT( itemp );
|
|
|
|
ml_printf("FS2NetD received PING");
|
|
|
|
FS2NetD_Pong(itemp);
|
|
break;
|
|
}
|
|
|
|
case PCKT_PONG: {
|
|
PXO_GET_INT( itemp );
|
|
|
|
ml_printf("FS2NetD received PONG: %d ms", timer_get_milliseconds() - itemp);
|
|
|
|
GotPong = timer_get_fixed_seconds();
|
|
break;
|
|
}
|
|
|
|
case PCKT_NETOWRK_WALL: {
|
|
PXO_GET_STRING( str );
|
|
ml_printf("FS2NetD WALL received MSG: %s", str);
|
|
|
|
switch (Netgame.game_state) {
|
|
case NETGAME_STATE_FORMING:
|
|
case NETGAME_STATE_BRIEFING:
|
|
case NETGAME_STATE_MISSION_SYNC:
|
|
case NETGAME_STATE_DEBRIEF:
|
|
multi_display_chat_msg(str, 0, 0);
|
|
break;
|
|
|
|
/* -- Won't Happen - multi_do_frame() is not called during paused state
|
|
so the game will not even receive the data during it
|
|
case NETGAME_STATE_PAUSED: // EASY!
|
|
send_game_chat_packet(Net_player, str, MULTI_MSG_ALL, NULL);
|
|
break;
|
|
*/
|
|
|
|
case NETGAME_STATE_IN_MISSION: // gotta make it paused
|
|
//multi_pause_request(1);
|
|
//send_game_chat_packet(Net_player, str, MULTI_MSG_ALL, NULL);
|
|
HUD_printf(str);
|
|
break;
|
|
|
|
default:
|
|
// do-nothing
|
|
break;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case PCKT_CHAT_CHAN_COUNT_REPLY: {
|
|
PXO_GET_STRING( str );
|
|
PXO_GET_INT( itemp );
|
|
|
|
if ( (itemp < 0) || (itemp > USHRT_MAX) ) {
|
|
itemp = 0;
|
|
}
|
|
|
|
multi_pxo_channel_count_update(str, itemp);
|
|
|
|
break;
|
|
}
|
|
|
|
case PCKT_VALID_SID_REPLY: {
|
|
ubyte login_status = 0;
|
|
|
|
PXO_GET_DATA( login_status );
|
|
|
|
ml_printf("FS2NetD IDENT: Got %s login check", (login_status == 1) ? NOX("valid") : NOX("invalid"));
|
|
|
|
if (login_status != 1) {
|
|
Logged_in = false;
|
|
PXO_SID = -1;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default: {
|
|
ml_printf("Unexpected FS2NetD Packet - PID = %x", pid);
|
|
break;
|
|
}
|
|
}
|
|
|
|
buffer_offset += buffer_size;
|
|
}
|
|
}
|
|
}
|
|
|
|
void fs2netd_server_send_heartbeat(bool force)
|
|
{
|
|
if ( !Om_tracker_flag ) {
|
|
return;
|
|
}
|
|
|
|
// if we aren't hosting this game then bail
|
|
if ( !(Net_player->flags & NETINFO_FLAG_GAME_HOST) ) {
|
|
return;
|
|
}
|
|
|
|
// is it actually time for a new hb?
|
|
if ( !force && (timer_get_fixed_seconds() < NextHeartBeat) ) {
|
|
return;
|
|
}
|
|
|
|
// don't bother if there is nothing to actually send yet
|
|
if ( !strlen(Netgame.mission_name) ) {
|
|
return;
|
|
}
|
|
|
|
FS2NetD_SendHeartBeat();
|
|
|
|
GameServerPort = Netgame.server_addr.port;
|
|
|
|
// we only need to send the chat channel update once per game server that is created
|
|
// only send the chat channel update every other HB
|
|
static bool send_chat_update = true;
|
|
|
|
if (send_chat_update) {
|
|
fs2netd_update_chat_channel();
|
|
}
|
|
|
|
send_chat_update = !send_chat_update;
|
|
|
|
// set timeout for every 2 minutes
|
|
NextHeartBeat = timer_get_fixed_seconds() + (120 * F1_0);
|
|
Multi_create_force_heartbeat = 0;
|
|
|
|
ml_printf("FS2NetD sent HeartBeat");
|
|
}
|
|
|
|
void fs2netd_server_disconnect()
|
|
{
|
|
if ( !Om_tracker_flag ) {
|
|
return;
|
|
}
|
|
|
|
// if we aren't hosting this game then bail
|
|
if ( !(Net_player->flags & NETINFO_FLAG_GAME_HOST) ) {
|
|
return;
|
|
}
|
|
|
|
if (GameServerPort == 0) {
|
|
return;
|
|
}
|
|
|
|
FS2NetD_SendServerDisconnect(GameServerPort);
|
|
|
|
GameServerPort = 0;
|
|
|
|
// set the next HB for about 2 seconds from now, to prevent a HB from being
|
|
// sent *after* we have actually closed the host game
|
|
NextHeartBeat = timer_get_fixed_seconds() + (2 * F1_0);
|
|
|
|
ml_printf("FS2NetD sent game_server disconnect");
|
|
}
|
|
|
|
int fs2netd_load_servers_do()
|
|
{
|
|
if (timeout == -1) {
|
|
timeout = timer_get_fixed_seconds() + (30 * F1_0);
|
|
}
|
|
|
|
// if timeout passes then bail on stats failure
|
|
if ( timer_get_fixed_seconds() > timeout ) {
|
|
timeout = -1;
|
|
return 3;
|
|
}
|
|
|
|
int rescode = FS2NetD_GetServerList(do_full_packet);
|
|
|
|
do_full_packet = 0;
|
|
|
|
if (rescode) {
|
|
timeout = -1;
|
|
return rescode;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fs2netd_load_servers()
|
|
{
|
|
int rc = 0;
|
|
|
|
// don't bother with this if we aren't on FS2NetD
|
|
if ( !Om_tracker_flag ) {
|
|
return 0;
|
|
}
|
|
|
|
if ( !(Game_mode & GM_MULTIPLAYER) ) {
|
|
return 0;
|
|
}
|
|
|
|
if ( !Is_connected ) {
|
|
return 0;
|
|
}
|
|
|
|
|
|
// free up any existing server list
|
|
multi_free_server_list();
|
|
|
|
do_full_packet = 1;
|
|
|
|
In_process = true;
|
|
|
|
if (Is_standalone) {
|
|
do { rc = fs2netd_load_servers_do(); } while (!rc);
|
|
} else {
|
|
rc = popup_till_condition(fs2netd_load_servers_do, XSTR("&Cancel", 779), XSTR("Requesting list of servers", -1));
|
|
}
|
|
|
|
In_process = false;
|
|
|
|
switch (rc) {
|
|
// operation canceled
|
|
case 0:
|
|
return 0;
|
|
|
|
// successful
|
|
case 1:
|
|
return 1;
|
|
|
|
// failed to send request packet
|
|
case 2:
|
|
if ( !Is_standalone ) {
|
|
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Server request failed!", -1));
|
|
}
|
|
|
|
return -1;
|
|
|
|
// it timed out
|
|
case 3:
|
|
if ( !Is_standalone ) {
|
|
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Server request timed out!", -1));
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static char Chk_mission_name[NAME_LENGTH+1];
|
|
static uint Chk_mission_crc = 0;
|
|
|
|
int fs2netd_check_mission_do()
|
|
{
|
|
if (timeout == -1) {
|
|
timeout = timer_get_fixed_seconds() + (15 * F1_0);
|
|
}
|
|
|
|
// if timeout passes then bail on stats failure
|
|
if ( timer_get_fixed_seconds() > timeout ) {
|
|
timeout = -1;
|
|
return 4;
|
|
}
|
|
|
|
int rescode = FS2NetD_CheckSingleMission(Chk_mission_name, Chk_mission_crc, do_full_packet);
|
|
|
|
do_full_packet = 0;
|
|
|
|
if (rescode) {
|
|
timeout = -1;
|
|
return rescode;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool fs2netd_check_mission(char *mission_name)
|
|
{
|
|
int rc = 0;
|
|
|
|
// don't bother with this if we aren't on FS2NetD
|
|
if ( !Om_tracker_flag ) {
|
|
return 0;
|
|
}
|
|
|
|
if ( !(Game_mode & GM_MULTIPLAYER) ) {
|
|
return 0;
|
|
}
|
|
|
|
if ( !Is_connected ) {
|
|
return 0;
|
|
}
|
|
|
|
strcpy(Chk_mission_name, mission_name);
|
|
cf_chksum_long(Chk_mission_name, &Chk_mission_crc);
|
|
|
|
do_full_packet = 1;
|
|
|
|
In_process = true;
|
|
|
|
if (Is_standalone) {
|
|
do { rc = fs2netd_check_mission_do(); } while (!rc);
|
|
} else {
|
|
rc = popup_till_condition(fs2netd_check_mission_do, XSTR("&Cancel", 779), XSTR("Sending stats...", -1));
|
|
}
|
|
|
|
In_process = false;
|
|
|
|
switch (rc) {
|
|
// operation canceled, or invalid
|
|
case 0:
|
|
return false;
|
|
|
|
// successful, but invalid
|
|
case 1:
|
|
return false;
|
|
|
|
// successful and valid
|
|
case 2:
|
|
return true;
|
|
|
|
// failed to send request packet
|
|
case 3:
|
|
if ( !Is_standalone ) {
|
|
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Server request failed!", -1));
|
|
}
|
|
|
|
return false;
|
|
|
|
// it timed out
|
|
case 4:
|
|
if ( !Is_standalone ) {
|
|
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Server request timed out!", -1));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void fs2netd_debrief_init()
|
|
{
|
|
if ( !(Game_mode & GM_MULTIPLAYER) ) {
|
|
return;
|
|
}
|
|
|
|
if ( !Om_tracker_flag ) {
|
|
return;
|
|
}
|
|
|
|
if ( !Is_connected ) {
|
|
return;
|
|
}
|
|
|
|
|
|
bool mValidStatus = fs2netd_check_mission(Netgame.mission_name);
|
|
|
|
if ( ((multi_num_players() > 1) || (Multi_num_players_at_start > 1)) && !game_hacked_data() && mValidStatus ) {
|
|
// verify that we are logged in before doing anything else
|
|
fs2netd_login();
|
|
|
|
int spd_ret = FS2NetD_SendPlayerData(PXO_SID, Players[Player_num].callsign, Multi_tracker_login, &Players[Player_num]);
|
|
|
|
switch (spd_ret) { // 0 = pilot updated, 1 = invalid pilot, 2 = invalid (expired?) sid
|
|
case -1:
|
|
multi_display_chat_msg( XSTR("<Did not receive response from server within timeout period>", -1), 0, 0 );
|
|
multi_display_chat_msg( XSTR("<Your stats may not have been stored>", -1), 0, 0 );
|
|
multi_display_chat_msg( XSTR("<This is not a critical error>", -1), 0, 0 );
|
|
Multi_debrief_stats_accept_code = 1;
|
|
break;
|
|
|
|
case 0:
|
|
multi_display_chat_msg( XSTR("<stats have been accepted>", 850), 0, 0 );
|
|
Multi_debrief_stats_accept_code = 1;
|
|
break;
|
|
|
|
case 1:
|
|
multi_display_chat_msg( XSTR("<stats have been tossed>", 850), 0, 0 );
|
|
multi_display_chat_msg( XSTR("WARNING: Your pilot was invalid, this is a serious error, possible data corruption", -1), 0, 0 );
|
|
Multi_debrief_stats_accept_code = 0;
|
|
break;
|
|
|
|
case 2:
|
|
// we really shouldn't be here with the new code, but handle it just in case
|
|
Int3();
|
|
|
|
fs2netd_login();
|
|
|
|
if (PXO_SID >= 0) {
|
|
if ( !FS2NetD_SendPlayerData(PXO_SID, Players[Player_num].callsign, Multi_tracker_login, &Players[Player_num]) ) {
|
|
multi_display_chat_msg( XSTR("<stats have been accepted>", 850), 0, 0 );
|
|
Multi_debrief_stats_accept_code = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
multi_display_chat_msg( XSTR("<stats have been tossed>", 851), 0, 0 );
|
|
Multi_debrief_stats_accept_code = 0;
|
|
break;
|
|
|
|
default:
|
|
multi_display_chat_msg( XSTR("Unknown Stats Store Request Reply", -1), 0, 0 );
|
|
break;
|
|
}
|
|
} else {
|
|
multi_display_chat_msg( XSTR("<stats have been tossed>", 851), 0, 0 );
|
|
Multi_debrief_stats_accept_code = 0;
|
|
}
|
|
}
|
|
|
|
int fs2netd_update_ban_list_do()
|
|
{
|
|
if (timeout == -1) {
|
|
timeout = timer_get_fixed_seconds() + (30 * F1_0);
|
|
}
|
|
|
|
// if timeout passes then bail on stats failure
|
|
if ( timer_get_fixed_seconds() > timeout ) {
|
|
timeout = -1;
|
|
return 2;
|
|
}
|
|
|
|
FS2NetD_ban_list = FS2NetD_GetBanList(&FS2NetD_ban_list_count, do_full_packet);
|
|
|
|
do_full_packet = 0;
|
|
|
|
if ( (FS2NetD_ban_list != NULL) || (FS2NetD_ban_list_count >= 0) ) {
|
|
timeout = -1;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void fs2netd_update_ban_list()
|
|
{
|
|
int rc = 0;
|
|
|
|
// don't bother with this if we aren't on FS2NetD
|
|
if ( !Om_tracker_flag ) {
|
|
return;
|
|
}
|
|
|
|
if ( !(Game_mode & GM_MULTIPLAYER) ) {
|
|
return;
|
|
}
|
|
|
|
if (!Is_connected) {
|
|
return;
|
|
}
|
|
|
|
|
|
// destroy the file prior to updating
|
|
cf_delete( "banlist.cfg", CF_TYPE_DATA );
|
|
|
|
do_full_packet = 1;
|
|
|
|
In_process = true;
|
|
|
|
if (Is_standalone) {
|
|
do { rc = fs2netd_update_ban_list_do(); } while (!rc);
|
|
} else {
|
|
rc = popup_till_condition(fs2netd_update_ban_list_do, XSTR("&Cancel", 779), XSTR("Requesting IP ban list", -1));
|
|
}
|
|
|
|
In_process = false;
|
|
|
|
|
|
if (FS2NetD_ban_list) {
|
|
CFILE *banlist_cfg = cfopen("banlist.cfg", "wt", CFILE_NORMAL, CF_TYPE_DATA);
|
|
|
|
if (banlist_cfg != NULL) {
|
|
for (int i = 0; i < FS2NetD_ban_list_count; i++) {
|
|
cfputs( FS2NetD_ban_list[i].ip_mask, banlist_cfg );
|
|
}
|
|
|
|
cfclose(banlist_cfg);
|
|
}
|
|
|
|
delete[] FS2NetD_ban_list;
|
|
}
|
|
|
|
FS2NetD_ban_list = NULL;
|
|
FS2NetD_ban_list_count = -1;
|
|
}
|
|
|
|
bool fs2netd_player_banned(net_addr *addr)
|
|
{
|
|
// don't bother with this if we aren't on FS2NetD
|
|
if ( !Om_tracker_flag ) {
|
|
return false;
|
|
}
|
|
|
|
if ( !(Game_mode & GM_MULTIPLAYER) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( !Is_connected ) {
|
|
return false;
|
|
}
|
|
|
|
char line[32]; // no line should be larger than 16, but let's be safe
|
|
char ip_str[32];
|
|
memset(ip_str, 0, 32);
|
|
memset(line, 0, 32);
|
|
|
|
bool retval = false;
|
|
CFILE *banlist_cfg = cfopen("banlist.cfg", "rt", CFILE_NORMAL, CF_TYPE_DATA);
|
|
|
|
if (banlist_cfg == NULL) {
|
|
return false;
|
|
}
|
|
|
|
psnet_addr_to_string( ip_str, addr );
|
|
|
|
while ( !cfeof(banlist_cfg) && !retval ) {
|
|
cfgets(line, 32, banlist_cfg);
|
|
|
|
if ( !strnicmp(ip_str, line, strlen(line)) ) {
|
|
retval = true; // BANNINATED!!!
|
|
}
|
|
}
|
|
|
|
cfclose(banlist_cfg);
|
|
|
|
return retval;
|
|
}
|
|
|
|
int fs2netd_get_valid_missions_do()
|
|
{
|
|
if (timeout == -1) {
|
|
timeout = timer_get_fixed_seconds() + (30 * F1_0);
|
|
}
|
|
|
|
// get the available CRCs from the server if we need to
|
|
if ( !FS2NetD_file_list && (FS2NetD_file_list_count < 0) ) {
|
|
FS2NetD_file_list = FS2NetD_GetMissionsList(&FS2NetD_file_list_count, do_full_packet);
|
|
|
|
do_full_packet = 0;
|
|
|
|
// if timeout passes then bail on crc failure
|
|
if ( timer_get_fixed_seconds() > timeout ) {
|
|
timeout = -1;
|
|
return 1;
|
|
}
|
|
}
|
|
// we should have the CRCs, or there were no missions, so process them
|
|
else {
|
|
static char **file_names = NULL;
|
|
static int idx = 0, count = 0;
|
|
|
|
bool found = false;
|
|
int file_index = 0;
|
|
char valid_status = MVALID_STATUS_UNKNOWN;
|
|
char full_name[MAX_FILENAME_LEN], wild_card[10];
|
|
char val_text[MAX_FILENAME_LEN+15];
|
|
int i;
|
|
uint checksum = 0;
|
|
|
|
// oops, something went wrong here...
|
|
if (FS2NetD_file_list_count <= 0) {
|
|
return 2;
|
|
}
|
|
|
|
if (file_names == NULL) {
|
|
// allocate filename space
|
|
file_names = (char**) vm_malloc_q( sizeof(char*) * 1024 ); // 1024 files should be safe!
|
|
|
|
if (file_names == NULL) {
|
|
return 3;
|
|
}
|
|
|
|
memset( wild_card, 0, sizeof(wild_card) );
|
|
strcpy( wild_card, NOX("*") );
|
|
strcat( wild_card, FS_MISSION_FILE_EXT );
|
|
|
|
idx = count = cf_get_file_list(1024, file_names, CF_TYPE_MISSIONS, wild_card);
|
|
}
|
|
|
|
// drop idx first thing
|
|
idx--;
|
|
|
|
// we should be done validating, or not just have nothing locally to validate
|
|
if (idx < 0) {
|
|
for (idx = 0; idx < count; idx++) {
|
|
if (file_names[idx] != NULL) {
|
|
vm_free(file_names[idx]);
|
|
file_names[idx] = NULL;
|
|
}
|
|
}
|
|
|
|
vm_free(file_names);
|
|
file_names = NULL;
|
|
|
|
idx = count = 0;
|
|
|
|
return 4;
|
|
}
|
|
|
|
|
|
// verify all filenames that we know about with their CRCs
|
|
// NOTE: that this is done for one file per frame, since this is inside of a popup
|
|
memset( full_name, 0, MAX_FILENAME_LEN );
|
|
strncpy( full_name, cf_add_ext(file_names[idx], FS_MISSION_FILE_EXT), sizeof(full_name) - 1 );
|
|
|
|
memset( val_text, 0, sizeof(val_text) );
|
|
snprintf( val_text, sizeof(val_text) - 1, "Validating: %s", full_name );
|
|
|
|
if (Is_standalone ) {
|
|
if ( std_gen_is_active() ) {
|
|
std_gen_set_text(val_text, 1);
|
|
}
|
|
} else {
|
|
popup_change_text(val_text);
|
|
}
|
|
|
|
cf_chksum_long(full_name, &checksum);
|
|
|
|
// try and find the file
|
|
file_index = multi_create_lookup_mission(full_name);
|
|
|
|
found = false;
|
|
|
|
if (file_index >= 0) {
|
|
for (i = 0; (i < FS2NetD_file_list_count) && (!found); i++) {
|
|
if ( !stricmp(full_name, FS2NetD_file_list[i].name) ) {
|
|
if (FS2NetD_file_list[i].crc32 == checksum) {
|
|
found = true;
|
|
valid_status = MVALID_STATUS_VALID;
|
|
} else {
|
|
valid_status = MVALID_STATUS_INVALID;
|
|
}
|
|
|
|
|
|
Multi_create_mission_list[file_index].valid_status = valid_status;
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
ml_printf("FS2NetD Mission Validation: %s => Valid!", full_name);
|
|
} else {
|
|
ml_printf("FS2NetD Mission Validation: %s => INVALID! -- 0x%08x", full_name, checksum);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool fs2netd_get_valid_missions()
|
|
{
|
|
int rc = 0;
|
|
|
|
// don't bother with this if we aren't on FS2NetD
|
|
if ( !Om_tracker_flag ) {
|
|
return false;
|
|
}
|
|
|
|
if ( !(Game_mode & GM_MULTIPLAYER) ) {
|
|
return false;
|
|
}
|
|
|
|
// maybe try to init first
|
|
fs2netd_login();
|
|
|
|
// if we didn't connect to FS2NetD then bail out now
|
|
if ( !Is_connected ) {
|
|
return false;
|
|
}
|
|
|
|
|
|
do_full_packet = 1;
|
|
|
|
In_process = true;
|
|
|
|
if (Is_standalone) {
|
|
do { rc = fs2netd_get_valid_missions_do(); } while (!rc);
|
|
} else {
|
|
rc = popup_till_condition(fs2netd_get_valid_missions_do, XSTR("&Cancel", 779), XSTR("Starting mission validation", -1));
|
|
}
|
|
|
|
In_process = false;
|
|
|
|
if (FS2NetD_file_list != NULL) {
|
|
delete[] FS2NetD_file_list;
|
|
FS2NetD_file_list = NULL;
|
|
}
|
|
|
|
FS2NetD_file_list_count = -1;
|
|
|
|
switch (rc) {
|
|
// canceled by popup
|
|
case 0:
|
|
return false;
|
|
|
|
// timed out
|
|
case 1:
|
|
if ( !Is_standalone ) {
|
|
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Mission validation timed out!", -1));
|
|
}
|
|
|
|
return false;
|
|
|
|
// no missions
|
|
case 2:
|
|
if ( !Is_standalone ) {
|
|
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("No missions are available from the server for validation!", -1));
|
|
}
|
|
|
|
return false;
|
|
|
|
// out of memory
|
|
case 3:
|
|
if ( !Is_standalone ) {
|
|
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Memory error during mission validation!", -1));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
int fs2netd_update_valid_tables_do()
|
|
{
|
|
if (timeout == -1) {
|
|
timeout = timer_get_fixed_seconds() + (30 * F1_0);
|
|
}
|
|
|
|
int rc = FS2NetD_ValidateTableList(do_full_packet);
|
|
|
|
// if timeout passes then bail on crc failure
|
|
if ( timer_get_fixed_seconds() > timeout ) {
|
|
timeout = -1;
|
|
return 1;
|
|
}
|
|
|
|
do_full_packet = 0;
|
|
|
|
if ( rc == 0 ) {
|
|
return 0;
|
|
}
|
|
|
|
switch (rc) {
|
|
// some error occured, assume that there are no valid table crcs
|
|
case -1:
|
|
timeout = -1;
|
|
return 2;
|
|
|
|
// timeout
|
|
case 1:
|
|
timeout = -1;
|
|
return 1;
|
|
|
|
// done!
|
|
case 2:
|
|
timeout = -1;
|
|
return 3;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fs2netd_update_valid_tables()
|
|
{
|
|
int rc;
|
|
int hacked = 0;
|
|
|
|
// if there are no tables to check with then bail
|
|
if ( Table_valid_status.empty() ) {
|
|
return -1;
|
|
}
|
|
|
|
// if we're not on FS2NetD then don't bother with this function
|
|
if ( !Om_tracker_flag && (Game_mode & GM_MULTIPLAYER) ) {
|
|
return -1;
|
|
}
|
|
|
|
// maybe try to init first
|
|
fs2netd_login();
|
|
|
|
// if we didn't connect to FS2NetD then bail out now
|
|
if ( !Is_connected ) {
|
|
return -1;
|
|
}
|
|
|
|
// if we're a standalone, show a dialog saying "validating tables"
|
|
if (Game_mode & GM_STANDALONE_SERVER) {
|
|
std_create_gen_dialog("Validating tables");
|
|
std_gen_set_text("Querying FS2NetD:", 1);
|
|
}
|
|
|
|
do_full_packet = 1;
|
|
|
|
In_process = true;
|
|
|
|
if (Is_standalone) {
|
|
do { rc = fs2netd_update_valid_tables_do(); } while (!rc);
|
|
} else {
|
|
rc = popup_till_condition(fs2netd_update_valid_tables_do, XSTR("&Cancel", 779), XSTR("Starting table validation", -1));
|
|
}
|
|
|
|
In_process = false;
|
|
|
|
switch (rc) {
|
|
// canceled by popup
|
|
case 0:
|
|
return -1;
|
|
|
|
// timed out
|
|
case 1: {
|
|
if ( !Is_standalone ) {
|
|
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Table validation timed out!", -1));
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// no tables
|
|
case 2: {
|
|
if ( !Is_standalone ) {
|
|
popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("No tables are available from the server for validation!", -1));
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
// output the status of table validity to multi.log
|
|
for (uint i = 0; i < Table_valid_status.size(); i++) {
|
|
if (Table_valid_status[i].valid) {
|
|
ml_printf("FS2NetD Table Check: '%s' -- Valid!", Table_valid_status[i].name);
|
|
} else {
|
|
ml_printf("FS2NetD Table Check: '%s' -- INVALID (0x%x)!", Table_valid_status[i].name, Table_valid_status[i].crc32);
|
|
hacked = 1;
|
|
}
|
|
}
|
|
|
|
// if we're a standalone, kill the validate dialog
|
|
if (Game_mode & GM_STANDALONE_SERVER) {
|
|
std_destroy_gen_dialog();
|
|
}
|
|
|
|
return hacked;
|
|
}
|
|
|
|
void fs2netd_add_table_validation(char *tblname)
|
|
{
|
|
uint chksum = 0;
|
|
|
|
// if the tbl name isn't valid then just assume that the tbl is too
|
|
if ( (tblname == NULL) || !strlen(tblname) ) {
|
|
return;
|
|
}
|
|
|
|
CFILE *tbl = cfopen(tblname, "rt", CFILE_NORMAL, CF_TYPE_TABLES);
|
|
|
|
if (tbl == NULL) {
|
|
return;
|
|
}
|
|
|
|
cf_chksum_long(tbl, &chksum);
|
|
|
|
cfclose(tbl);
|
|
|
|
crc_valid_status tbl_crc;
|
|
|
|
strncpy(tbl_crc.name, tblname, NAME_LENGTH);
|
|
tbl_crc.crc32 = chksum;
|
|
tbl_crc.valid = 0;
|
|
|
|
Table_valid_status.push_back( tbl_crc );
|
|
}
|
|
|
|
int fs2netd_get_pilot_info(const char *callsign, player *out_plr, bool first_call)
|
|
{
|
|
// don't bother with this if we aren't on FS2NetD
|
|
if ( !Om_tracker_flag ) {
|
|
return -2;
|
|
}
|
|
|
|
if ( !(Game_mode & GM_MULTIPLAYER) ) {
|
|
return -2;
|
|
}
|
|
|
|
if ( (out_plr == NULL) || (callsign == NULL) || !(strlen(callsign)) ) {
|
|
return -2;
|
|
}
|
|
|
|
player new_plr;
|
|
|
|
if (first_call) {
|
|
memset( &new_plr, 0, sizeof(player) );
|
|
strncpy( new_plr.callsign, callsign, CALLSIGN_LEN );
|
|
|
|
memset( out_plr, 0, sizeof(player) );
|
|
|
|
timeout = timer_get_fixed_seconds() + (30 * F1_0);
|
|
}
|
|
|
|
int rc = FS2NetD_GetPlayerData(-2, callsign, &new_plr, false, (int)first_call );
|
|
|
|
// some sort of failure
|
|
if (rc > 0) {
|
|
timeout = -1;
|
|
return -2;
|
|
}
|
|
|
|
if (rc == 0) {
|
|
memcpy( out_plr, &new_plr, sizeof(player) );
|
|
}
|
|
|
|
// if timeout passes then bail on failure
|
|
if ( timer_get_fixed_seconds() > timeout ) {
|
|
timeout = -1;
|
|
return -2;
|
|
}
|
|
|
|
// we should only be returning -1 (processing) or 0 (got data successfully)
|
|
return rc;
|
|
}
|
|
|
|
void fs2netd_close()
|
|
{
|
|
Table_valid_status.clear();
|
|
|
|
if (FS2NetD_file_list != NULL) {
|
|
delete[] FS2NetD_file_list;
|
|
FS2NetD_file_list = NULL;
|
|
}
|
|
|
|
if (FS2NetD_ban_list != NULL) {
|
|
delete[] FS2NetD_ban_list;
|
|
FS2NetD_ban_list = NULL;
|
|
}
|
|
}
|
|
|
|
void fs2netd_update_chat_channel()
|
|
{
|
|
if ( !Om_tracker_flag ) {
|
|
return;
|
|
}
|
|
|
|
if ( !Is_connected ) {
|
|
return;
|
|
}
|
|
|
|
if ( !strlen(Multi_fs_tracker_channel) ) {
|
|
return;
|
|
}
|
|
|
|
FS2NetD_ChatChannelUpdate(Multi_fs_tracker_channel);
|
|
}
|
|
|
|
void fs2netd_update_game_count(char *chan_name)
|
|
{
|
|
if ( !Om_tracker_flag ) {
|
|
return;
|
|
}
|
|
|
|
if ( !Is_connected ) {
|
|
return;
|
|
}
|
|
|
|
if ( (chan_name == NULL) || !strlen(chan_name) ) {
|
|
return;
|
|
}
|
|
|
|
FS2NetD_GameCountUpdate(chan_name);
|
|
}
|
|
|
|
void fs2netd_spew_table_checksums(char *outfile)
|
|
{
|
|
char full_name[MAX_PATH_LEN];
|
|
int count, idx;
|
|
FILE *out = NULL;
|
|
char modname[128];
|
|
time_t my_time = 0;
|
|
|
|
if ( Table_valid_status.empty() ) {
|
|
return;
|
|
}
|
|
|
|
cf_create_default_path_string(full_name, sizeof(full_name) - 1, CF_TYPE_ROOT, outfile);
|
|
|
|
// open the outfile
|
|
out = fopen(full_name, "wt");
|
|
|
|
if (out == NULL) {
|
|
return;
|
|
}
|
|
|
|
memset( modname, 0, sizeof(modname) );
|
|
strcpy( modname, Cmdline_spew_table_crcs );
|
|
|
|
my_time = time(NULL);
|
|
|
|
fprintf(out, "-- Table CRCs generated on %s \n", ctime(&my_time));
|
|
|
|
fprintf(out, "LOCK TABLES `fstables` WRITE;\n");
|
|
fprintf(out, "INSERT INTO `fstables` VALUES ");
|
|
|
|
count = (int)Table_valid_status.size();
|
|
|
|
// do all the checksums
|
|
for (idx = 0; idx < count; idx++) {
|
|
if (idx == 0) {
|
|
fprintf(out, "('%s',%u,'%s')", Table_valid_status[idx].name, Table_valid_status[idx].crc32, modname);
|
|
} else {
|
|
fprintf(out, ",('%s',%u,'%s')", Table_valid_status[idx].name, Table_valid_status[idx].crc32, modname);
|
|
}
|
|
}
|
|
|
|
fprintf(out, ";\n");
|
|
fprintf(out, "UNLOCK TABLES;\n");
|
|
|
|
fclose(out);
|
|
}
|