int FS2NetD_CheckSingleMission(const char *m_name, uint crc32, bool do_send) { int buffer_size, buffer_offset; bool my_packet = false; char buffer[100]; if (do_send) { INIT_PACKET( PCKT_MISSION_CHECK ); PXO_ADD_STRING( m_name ); PXO_ADD_UINT( crc32 ); DONE_PACKET(); if ( FS2NetD_SendData(buffer, buffer_size) == -1 ) { return 3; } } else if ( FS2NetD_DataReady() ) { int rc; uint rc_total = 0; do { rc = FS2NetD_GetData(buffer+rc_total, sizeof(buffer)-rc_total); if (rc <= 0) { break; } rc_total += rc; Sleep(20); } while ( FS2NetD_DataReady() && (rc_total < (int)sizeof(buffer)) ); if (rc < BASE_PACKET_SIZE) { return 0; } VRFY_PACKET2( PCKT_MCHECK_REPLY ); if ( !my_packet ) { return 0; } ubyte status = 0; PXO_GET_DATA( status ); Assert( (status == 0) || (status == 1) ); // anything beyond 'true' is considered a failure of some kind if (status > 1) { status = 0; } return status+1; } return 0; }
int FS2NetD_SendPlayerData(const char *player_name, player *pl, bool do_send) { int buffer_size, buffer_offset; bool my_packet = false; char buffer[16384]; if (do_send) { int i, num_type_kills = 0; // send packet... (fs2open_pilot_update) INIT_PACKET( PCKT_PILOT_UPDATE ); PXO_ADD_INT( Multi_tracker_id ); PXO_ADD_STRING( player_name ); // name PXO_ADD_STRING( Multi_tracker_login ); // user PXO_ADD_INT( pl->stats.score ); // points PXO_ADD_UINT( pl->stats.missions_flown ); // missions PXO_ADD_UINT( pl->stats.flight_time ); // flighttime PXO_ADD_INT( pl->stats.last_flown ); // LastFlight PXO_ADD_INT( pl->stats.kill_count ); // Kills PXO_ADD_INT( pl->stats.kill_count_ok ); // NonFriendlyKills PXO_ADD_INT( pl->stats.assists ); // Assists PXO_ADD_UINT( pl->stats.p_shots_fired ); // PriShots PXO_ADD_UINT( pl->stats.p_shots_hit ); // PriHits PXO_ADD_UINT( pl->stats.p_bonehead_hits ); // PriFHits PXO_ADD_UINT( pl->stats.s_shots_fired ); // SecShots PXO_ADD_UINT( pl->stats.s_shots_hit ); // SecHits PXO_ADD_UINT( pl->stats.s_bonehead_hits ); // SecFHits PXO_ADD_INT( pl->stats.rank ); // rank for (i = 0; i < MAX_SHIP_CLASSES; i++) { if (pl->stats.kills[i] > 0) { Assert( (pl->stats.kills[i] >= 0) && (pl->stats.kills[i] < USHRT_MAX) ); num_type_kills++; } } Assert( (num_type_kills >= 0) && (num_type_kills < USHRT_MAX) ); PXO_ADD_USHORT( (ushort)num_type_kills ); for (i = 0; i < MAX_SHIP_CLASSES; i++) { if (pl->stats.kills[i] > 0) { PXO_ADD_STRING( Ship_info[i].name ); PXO_ADD_USHORT( (ushort)pl->stats.kills[i] ); } } Assert( (Num_medals >= 0) && (Num_medals < USHRT_MAX) ); PXO_ADD_USHORT( (ushort)Num_medals ); for (i = 0; i < Num_medals; i++) { PXO_ADD_INT( pl->stats.medal_counts[i] ); } DONE_PACKET(); if ( FS2NetD_SendData(buffer, buffer_size) == -1 ) { return -1; } } else if ( FS2NetD_DataReady() ) { int rc; uint rc_total = 0; do { rc = FS2NetD_GetData(buffer+rc_total, sizeof(buffer)-rc_total); if (rc <= 0) { break; } rc_total += rc; Sleep(20); } while ( FS2NetD_DataReady() && (rc_total < (int)sizeof(buffer)) ); if (rc < BASE_PACKET_SIZE) { return -1; } VRFY_PACKET2( PCKT_PILOT_UREPLY ); if ( !my_packet ) { return -1; } ubyte status; PXO_GET_DATA( status ); Assert( (status == 0) || (status == 1) || (status == 2) ); if (status > 2) { status = 2; } return (int)status; } return -1; }
int FS2NetD_ValidateTableList(bool do_send) { int buffer_size, buffer_offset; bool my_packet = false; char buffer[4096]; ushort num_tables = 0; if (do_send) { // create and send the request packet INIT_PACKET( PCKT_TABLES_RQST ); num_tables = (ushort)Table_valid_status.size(); PXO_ADD_USHORT( num_tables ); for (SCP_vector<crc_valid_status>::iterator tvs = Table_valid_status.begin(); tvs != Table_valid_status.end(); ++tvs) { PXO_ADD_STRING(tvs->name ); PXO_ADD_UINT( tvs->crc32 ); } DONE_PACKET(); if (FS2NetD_SendData(buffer, buffer_size) == -1) { return -1; } } else if ( FS2NetD_DataReady() ) { int rc; const fix end_time = timer_get_fixed_seconds() + (15 * F1_0); ubyte tbl_valid_status = 0; uint rc_total = 0; do { rc = FS2NetD_GetData(buffer+rc_total, sizeof(buffer)-rc_total); if (rc <= 0) { break; } rc_total += rc; Sleep(20); } while ( FS2NetD_DataReady() && (rc_total < (int)sizeof(buffer)) ); if (rc < BASE_PACKET_SIZE) { return -1; } VRFY_PACKET2( PCKT_TABLES_REPLY ); if ( !my_packet ) { return -1; } // make sure that we get the entire packet while ( (rc_total < (uint)buffer_size) && (rc_total < sizeof(buffer)) && (timer_get_fixed_seconds() <= end_time) ) { if ( FS2NetD_DataReady() ) { rc = FS2NetD_GetData(buffer+rc_total, sizeof(buffer) - rc_total); if (rc <= 0) { continue; } rc_total += rc; } Sleep(20); } PXO_GET_USHORT( num_tables ); if ( !num_tables ) { return -1; } if ( num_tables > (int)Table_valid_status.size() ) { ml_printf("FS2NetD WARNING: Table list contains %i tables, but we only requested %i! Invalid data!", num_tables, Table_valid_status.size()); return -1; } for (SCP_vector<crc_valid_status>::iterator tvs = Table_valid_status.begin(); tvs != Table_valid_status.end(); ++tvs) { PXO_GET_DATA( tbl_valid_status ); Assert( (tbl_valid_status == 0) || (tbl_valid_status == 1) ); tvs->valid = tbl_valid_status; } return 2; } return 0; }
int FS2NetD_Login(const char *username, const char *password, bool do_send) { int buffer_size, buffer_offset; bool my_packet = false; char buffer[150]; if (do_send) { INIT_PACKET( PCKT_LOGIN_AUTH ); PXO_ADD_STRING( username ); PXO_ADD_STRING( password ); PXO_ADD_USHORT( Multi_options_g.port ); DONE_PACKET(); if (FS2NetD_SendData(buffer, buffer_size) == -1) { return -1; } } else if ( FS2NetD_DataReady() ) { int rc; uint rc_total = 0; ubyte login_status = 0; int sid; short pilots; do { rc = FS2NetD_GetData(buffer+rc_total, sizeof(buffer)-rc_total); if (rc <= 0) { break; } rc_total += rc; Sleep(20); } while ( FS2NetD_DataReady() && (rc_total < (int)sizeof(buffer)) ); if (rc < BASE_PACKET_SIZE) { return -1; } VRFY_PACKET2( PCKT_LOGIN_REPLY ); if ( !my_packet ) { return -1; } PXO_GET_DATA( login_status ); if ( !login_status ) { return -2; } PXO_GET_INT( sid ); PXO_GET_SHORT( pilots ); return sid; } return -1; }
int FS2NetD_GetPlayerData(const char *player_name, player *pl, bool can_create, bool do_send) { int buffer_size, buffer_offset; bool my_packet = false; char buffer[16384]; if (do_send) { ubyte create = (ubyte)can_create; INIT_PACKET( PCKT_PILOT_GET ); PXO_ADD_INT( (can_create) ? Multi_tracker_id : -2 ); PXO_ADD_STRING( player_name ); PXO_ADD_DATA( create ); DONE_PACKET(); if ( FS2NetD_SendData(buffer, buffer_size) == -1 ) { return -1; } } else if ( FS2NetD_DataReady() ) { const fix end_time = timer_get_fixed_seconds() + (15 * F1_0); int rc; uint rc_total = 0; ubyte reply_type = 0; int si_index = 0; ushort bogus, num_type_kills = 0, num_medals = 0; char ship_name[NAME_LENGTH]; int idx; do { rc = FS2NetD_GetData(buffer+rc_total, sizeof(buffer)-rc_total); if (rc <= 0) { break; } rc_total += rc; Sleep(20); } while ( FS2NetD_DataReady() && (rc_total < (int)sizeof(buffer)) ); if (rc < BASE_PACKET_SIZE) { return -1; } VRFY_PACKET2( PCKT_PILOT_REPLY ); if ( !my_packet ) { return -1; } if ( buffer_size > (int)sizeof(buffer) ) { ml_printf("FS2NetD WARNING: Pilot update data is larger than receive buffer! Some data will be lost!"); } // make sure that we get the entire packet while ( (rc_total < (uint)buffer_size) && (rc_total < sizeof(buffer)) && (timer_get_fixed_seconds() <= end_time) ) { if ( FS2NetD_DataReady() ) { rc = FS2NetD_GetData(buffer+rc_total, sizeof(buffer) - rc_total); if (rc <= 0) { continue; } rc_total += rc; } Sleep(20); } PXO_GET_DATA( reply_type ); // if we weren't retrieved then bail out now if (reply_type != 0) { return (int)reply_type; } PXO_GET_INT( pl->stats.score ); // points PXO_GET_UINT( pl->stats.missions_flown ); // missions PXO_GET_UINT( pl->stats.flight_time ); // flighttime PXO_GET_INT( pl->stats.last_flown ); // LastFlight PXO_GET_INT( pl->stats.kill_count ); // Kills PXO_GET_INT( pl->stats.kill_count_ok ); // NonFriendlyKills PXO_GET_INT( pl->stats.assists ); // Assists PXO_GET_UINT( pl->stats.p_shots_fired ); // PriShots PXO_GET_UINT( pl->stats.p_shots_hit ); // PriHits PXO_GET_UINT( pl->stats.p_bonehead_hits ); // PriFHits PXO_GET_UINT( pl->stats.s_shots_fired ); // SecShots PXO_GET_UINT( pl->stats.s_shots_hit ); // SecHits PXO_GET_UINT( pl->stats.s_bonehead_hits ); // SecFHits PXO_GET_INT( pl->stats.rank ); // rank PXO_GET_USHORT( num_type_kills ); for (idx = 0; idx < (int)num_type_kills; idx++) { memset( ship_name, 0, sizeof(ship_name) ); PXO_GET_STRING( ship_name ); si_index = ship_info_lookup( ship_name ); if (si_index == -1) { PXO_GET_USHORT( bogus ); } else { PXO_GET_USHORT( pl->stats.kills[si_index] ); } } PXO_GET_USHORT( num_medals ); for (idx = 0; (idx < Num_medals) && (idx < num_medals); idx++) { PXO_GET_INT( pl->stats.medal_counts[idx] ); } return (int)reply_type; } return -1; }
static void fs2netd_handle_messages() { int buffer_size = 0, buffer_offset = 0; int bytes_read = 0; char tbuf[256]; char buffer[8192]; ubyte pid = 0; int itemp; while ( FS2NetD_DataReady() && (bytes_read < (int)sizeof(buffer)) ) { int read_size = FS2NetD_GetData(buffer+bytes_read, sizeof(buffer)-bytes_read); if (read_size <= 0) { break; } bytes_read += read_size; Sleep(20); } if ( (bytes_read == 0) || (bytes_read < BASE_PACKET_SIZE) ) { return; } Last_activity = timer_get_seconds(); buffer_offset = 0; while (buffer_offset+BASE_PACKET_SIZE <= bytes_read) { PXO_GET_DATA( pid ); PXO_GET_INT( buffer_size ); // packet has more data than our buffer received if (buffer_offset+buffer_size-BASE_PACKET_SIZE > bytes_read) { 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 PONG: %d ms", timer_get_milliseconds() - itemp); // reset timestamp, since the ping was successful Ping_timestamp = -1; break; } case PCKT_NETOWRK_WALL: { PXO_GET_STRING( tbuf ); ml_printf("FS2NetD WALL received MSG: %s", tbuf); 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(tbuf, 0, 0); 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(tbuf); break; default: // do-nothing break; } break; } case PCKT_CHAT_CHAN_COUNT_REPLY: { PXO_GET_STRING( tbuf ); PXO_GET_INT( itemp ); if ( (itemp < 0) || (itemp > USHRT_MAX) ) { itemp = 0; } multi_pxo_channel_count_update(tbuf, itemp); break; } case PCKT_VALID_SID_REPLY: { ubyte login_status = 0; PXO_GET_DATA( login_status ); if (login_status != 1) { ml_printf("FS2NetD IDENT: Got invalid login check!"); fs2netd_reset_connection(); } break; } case PCKT_DUP_LOGIN_REPLY: { ubyte dupe_status = 0; PXO_GET_DATA( dupe_status ); Duplicate_login_detected = (dupe_status != 0); break; } case PCKT_SLIST_REPLY: { int numServers = 0; int svr_flags; ushort svr_port; char svr_ip[16]; active_game ag; PXO_GET_USHORT( numServers ); if (numServers == 0) { break; } for (int i = 0; i < numServers; i++) { PXO_GET_INT( svr_flags ); PXO_GET_USHORT( svr_port ); PXO_GET_STRING( svr_ip ); if ( !psnet_is_valid_ip_string(svr_ip) ) { ml_printf("FS2NetD SLIST: Invalid ip string (%s)!", svr_ip); } else { memset( &ag, 0, sizeof(active_game) ); ag.server_addr.type = NET_TCP; ag.server_addr.port = (short) svr_port; if (ag.server_addr.port <= 0) { ag.server_addr.port = DEFAULT_GAME_PORT; } psnet_string_to_addr(&ag.server_addr, svr_ip); // query this server send_server_query(&ag.server_addr); } } break; } default: { break; } } } }
void fs2netd_do_frame() { int rc, buffer_size, buffer_offset; char buffer[300], str[256]; ubyte pid = 0; int itemp; static fix NextPing = -1, NextHeartBeat = -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(); ml_printf("FS2NetD sent PING"); } // send out server heartbeat every 2 minutes, unless forced to by an update if ( (Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Multi_create_force_heartbeat || (NextHeartBeat == -1) || (timer_get_fixed_seconds() >= NextHeartBeat)) ) { Multi_create_force_heartbeat = 0; NextHeartBeat = timer_get_fixed_seconds() + (120 * F1_0); FS2NetD_SendHeartBeat(Netgame.name, Netgame.mission_name, Netgame.title, Netgame.type_flags, Netgame.server_addr.port, multi_num_players()); ml_printf("FS2NetD sent 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_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; } default: { ml_printf("Unexpected FS2NetD Packet - PID = %x", pid); break; } } buffer_offset += (buffer_size - BASE_PACKET_SIZE); } } }