static void fs2netd_store_stats_results() { char str[512]; memset(str, 0, sizeof(str)); multi_display_chat_msg(XSTR("<PXO stats store process complete>", 1001), 0, 0); ml_string( XSTR("<PXO stats store process complete>", 1001) ); if (Multi_debrief_stats_accept_code != 1) { sprintf(str, XSTR("<PXO stats store failed for player %s>", 1002), Net_player->m_player->callsign); multi_display_chat_msg(str, 0, 0); ml_string(str); } }
// attempt to kick a player. return success or fail void multi_kick_player(int player_index, int ban, int reason) { // only the standalone should be able to kick the host of the game if(!(Game_mode & GM_STANDALONE_SERVER) && ((Net_players[player_index].flags & NETINFO_FLAG_GAME_HOST) || (Net_players[player_index].flags & NETINFO_FLAG_AM_MASTER))){ nprintf(("Network","Cannot kick the host or server of a game!\n")); } else { // if we're the master, then delete the guy if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ // if we're supposed to ban him, add his address to the banned list if(ban){ multi_kick_add_ban(&Net_players[player_index].p_info.addr); } // mark him as having been kicked Net_players[player_index].flags |= NETINFO_FLAG_KICKED; // set his kick timestamp and send him a leave game packet Net_players[player_index].s_info.kick_timestamp = timestamp(MULTI_KICK_RESPONSE_TIME); Net_players[player_index].s_info.kick_reason = reason; send_leave_game_packet(Net_players[player_index].player_id, reason, &Net_players[player_index]); // tell everyone else that he was kicked send_leave_game_packet(Net_players[player_index].player_id, reason); // wait until he either shuts his connection down or he times out) // add the string to the chatbox and the hud (always safe - if it is not inited, nothing bad will happen) char str[512]; memset(str, 0, 512); sprintf(str, XSTR("<kicking %s ...>", 1501), Net_players[player_index].m_player->callsign); multi_display_chat_msg(str, player_index, 0); } // otherwise, we should send the packet indicating that this guy should be kicked else { send_player_kick_packet(player_index, ban, reason); } } }
// general quit function, with optional notification, error, and winsock error codes int multi_quit_game(int prompt, int notify_code, int err_code, int wsa_error) { int ret_val,quit_already; // check for reentrancy if(Multi_quit_game){ return 0; } // if we're not connected or have not net-player if((Net_player == NULL) || !(Net_player->flags & NETINFO_FLAG_CONNECTED)){ return 1; } // reentrancy Multi_quit_game = 1; quit_already = 0; // reset my control info so that I don't continually do whacky stuff. This is ugly //player_control_reset_ci( &Player->ci ); if ( Game_mode & GM_IN_MISSION ) { memset(&Player->ci, 0, sizeof(Player->ci) ); Player->ci.afterburner_stop = 1; physics_read_flying_controls( &Player_obj->orient, &Player_obj->phys_info, &(Player->ci), flFrametime); } // CASE 1 - response to a user request // if there is no associated notification or error code, don't override the prompt argument if((err_code == -1) && (notify_code == -1)){ // if we're the server and we're already waiting for clients to leave, don't do anything if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && Multi_endgame_server_waiting){ Multi_quit_game = 0; return 0; } // if we're the client and we're already waiting to leave, don't do anythin if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER) && Multi_endgame_client_waiting){ Multi_quit_game = 0; return 0; } // see if we should be prompting the host for confirmation if((prompt==PROMPT_HOST || prompt==PROMPT_ALL) && (Net_player->flags & NETINFO_FLAG_GAME_HOST)){ int p_flags; p_flags = PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_BODY_BIG; if ( Game_mode & GM_IN_MISSION ) p_flags |= PF_RUN_STATE; ret_val = popup(p_flags,2,POPUP_CANCEL,POPUP_OK,XSTR("Warning - quitting will end the game for all players!",647)); // check for host cancel if((ret_val == 0) || (ret_val == -1)){ Multi_quit_game = 0; return 0; } // set this so that under certain circumstances, we don't call the popup below us as well quit_already = 1; } // see if we should be prompting the client for confirmation if((prompt==PROMPT_CLIENT || prompt==PROMPT_ALL) && !quit_already){ ret_val = popup(PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON | PF_BODY_BIG,2,POPUP_NO,POPUP_YES,XSTR("Are you sure you want to quit?",648)); // check for host cancel if((ret_val == 0) || (ret_val == -1)){ Multi_quit_game = 0; return 0; } quit_already = 1; } // if i'm the server of the game, tell all clients that i'm leaving, then wait if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ send_netgame_end_error_packet(MULTI_END_NOTIFY_SERVER_LEFT,MULTI_END_ERROR_NONE); // set the waiting flag and the waiting timestamp Multi_endgame_server_waiting = 1; Multi_endgame_server_wait_stamp = MULTI_ENDGAME_SERVER_WAIT; } // if i'm the client, quit now else { multi_endgame_cleanup(); } } // CASE 2 - response to an error code or packet from the server // this is the case where we're being forced to quit the game because of some error or other notification else { // if i'm the server, send a packet to the clients telling them that I'm leaving and why if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !Multi_endgame_server_waiting){ // if we're in the debrief state, mark down that the server has left the game if(((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)) && !(Game_mode & GM_STANDALONE_SERVER)){ multi_debrief_server_left(); // add a message to the chatbox multi_display_chat_msg(XSTR("<Team captains have left>",649),0,0); // set ourselves to be "not quitting" Multi_quit_game = 0; // tell the users, the game has ended send_netgame_end_error_packet(notify_code,err_code); return 0; } send_netgame_end_error_packet(notify_code,err_code); // store the globals Multi_endgame_notify_code = notify_code; Multi_endgame_error_code = err_code; Multi_endgame_wsa_error = wsa_error; // by setting this, multi_endgame_process() will know to check and see if it is ok for us to leave Multi_endgame_server_waiting = 1; Multi_endgame_server_wait_stamp = MULTI_ENDGAME_SERVER_WAIT; } // if i'm the client, set the error codes and leave the game now else if(!Multi_endgame_client_waiting){ // if we're in the debrief state, mark down that the server has left the game if((gameseq_get_state() == GS_STATE_DEBRIEF) || (gameseq_get_state() == GS_STATE_MULTI_DOGFIGHT_DEBRIEF)){ multi_debrief_server_left(); // add a message to the chatbox multi_display_chat_msg(XSTR("<The server has ended the game>",650),0,0); // shut our reliable socket to the server down psnet_rel_close_socket(&Net_player->reliable_socket); Net_player->reliable_socket = INVALID_SOCKET; // remove our do-notworking flag Net_player->flags &= ~(NETINFO_FLAG_DO_NETWORKING); Multi_quit_game = 0; return 0; } Multi_endgame_notify_code = notify_code; Multi_endgame_error_code = err_code; Multi_endgame_wsa_error = wsa_error; // by setting this, multi_endgame_process() will know to check and see if it is ok for us to leave Multi_endgame_client_waiting = 1; } } // unset the reentrancy flag Multi_quit_game = 0; 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_store_stats() { if ( !Logged_in ) { return; } ml_string("Sending stats to server"); // default to not saving the stats Multi_debrief_stats_accept_code = 0; if (Duplicate_login_detected) { Duplicate_login_detected = false; multi_display_chat_msg( XSTR("<Duplicate login detected - stats have been tossed>", 1582), 0, 0 ); ml_string( XSTR("<Duplicate login detected - stats have been tossed>", 1583) ); fs2netd_store_stats_results(); return; } if ( game_hacked_data() ) { multi_display_chat_msg( XSTR("<Hacked tables detected - stats have been tossed>", 1584), 0, 0 ); popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("You are playing with a hacked tables, your stats will not be saved", 1585) ); fs2netd_store_stats_results(); return; } if ( (multi_num_players() <= 1) && (Multi_num_players_at_start <= 1) ) { multi_display_chat_msg(XSTR("<Not enough players were present at game start or end, stats will not be saved>", 1048), 0, 0); ml_string( XSTR("<Not enough players were present at game start or end, stats will not be saved>", 1048) ); fs2netd_store_stats_results(); return; } /* // if any players have hacked info for(int idx = 0; idx < MAX_PLAYERS; idx++) { if ( MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (Net_players[idx].flags & NETINFO_FLAG_HAXOR) ) { multi_display_chat_msg( XSTR("<Connected player has hacked info - tossing invalid stats>", -1), 0, 0 ); return; } } */ if ( !fs2netd_check_mission(Netgame.mission_name) ) { multi_display_chat_msg(XSTR("<Server detected a non PXO validated mission. Stats will not be saved>", 1049), 0, 0); popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("This is not a PXO validated mission, your stats will not be saved", 1050)); fs2netd_store_stats_results(); return; } int spd_ret = fs2netd_send_player(); switch (spd_ret) { // 0 = pilot updated, 1 = invalid pilot, 2 = invalid (expired?) sid case -1: ml_string("<stats have been tossed - server error>"); break; case 0: ml_string( XSTR("<stats have been accepted>", 850) ); Multi_debrief_stats_accept_code = 1; break; case 1: ml_string("<stats have been tossed - pilot error>"); break; case 2: // we should never get here with the new code Int3(); ml_string("<stats have been tossed - invalid tracker id>"); break; default: multi_display_chat_msg( XSTR("Unknown Stats Store Request Reply", 1586), 0, 0 ); break; } fs2netd_store_stats_results(); }
void fs2netd_debrief_init() { if ( !(Game_mode & GM_MULTIPLAYER) ) { return; } if ( !Om_tracker_flag ) { return; } if ( !Is_connected ) { return; } uint CurrentMissionChsum; bool mValidStatus = false; cf_chksum_long(Netgame.mission_name, &CurrentMissionChsum); mValidStatus = FS2NetD_CheckSingleMission(Netgame.mission_name, CurrentMissionChsum); 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 != -1) { 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; } }
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); } } }