2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/Network/multi_kick.cpp $
16 * Revision 1.6 2005/10/02 09:30:10 taylor
17 * sync up rest of big-endian network changes. it should at least be as good as what's in FS2_Open now, only better :)
19 * Revision 1.5 2004/06/11 01:18:40 tigital
20 * byte-swapping changes for bigendian systems
22 * Revision 1.4 2002/06/09 04:41:23 relnev
23 * added copyright header
25 * Revision 1.3 2002/05/27 00:40:47 theoddone33
26 * Fix net_addr vs net_addr_t
28 * Revision 1.2 2002/05/07 03:16:47 theoddone33
29 * The Great Newline Fix
31 * Revision 1.1.1.1 2002/05/03 03:28:10 root
35 * 8 10/13/99 3:51p Jefff
36 * fixed unnumbered XSTRs
38 * 7 3/10/99 6:50p Dave
39 * Changed the way we buffer packets for all clients. Optimized turret
40 * fired packets. Did some weapon firing optimizations.
42 * 6 3/09/99 6:24p Dave
43 * More work on object update revamping. Identified several sources of
44 * unnecessary bandwidth.
46 * 5 11/19/98 8:03a Dave
47 * Full support for D3-style reliable sockets. Revamped packet lag/loss
48 * system, made it receiver side and at the lowest possible level.
50 * 4 11/17/98 11:12a Dave
51 * Removed player identification by address. Now assign explicit id #'s.
53 * 3 11/05/98 5:55p Dave
54 * Big pass at reducing #includes
56 * 2 10/07/98 10:53a Dave
59 * 1 10/07/98 10:50a Dave
61 * 16 9/15/98 7:24p Dave
62 * Minor UI changes. Localized bunch of new text.
64 * 15 9/11/98 5:53p Dave
65 * Final revisions to kick system changes.
67 * 14 9/11/98 5:08p Dave
68 * More tweaks to kick notification system.
70 * 13 9/11/98 4:14p Dave
71 * Fixed file checksumming of < file_size. Put in more verbose kicking and
72 * PXO stats store reporting.
74 * 12 6/13/98 9:32p Mike
75 * Kill last character in file which caused "Find in Files" to report the
76 * file as "not a text file."
78 * 11 6/13/98 6:01p Hoffoss
79 * Externalized all new (or forgot to be added) strings to all the code.
81 * 10 4/23/98 6:18p Dave
82 * Store ETS values between respawns. Put kick feature in the text
83 * messaging system. Fixed text messaging system so that it doesn't
84 * process or trigger ship controls. Other UI fixes.
86 * 9 4/04/98 4:22p Dave
87 * First rev of UDP reliable sockets is done. Seems to work well if not
90 * 8 4/03/98 1:03a Dave
91 * First pass at unreliable guaranteed delivery packets.
93 * 7 4/01/98 11:19p Dave
94 * Put in auto-loading of xferred pilot pic files. Grey out background
95 * behind pinfo popup. Put a chatbox message in when players are kicked.
96 * Moved mission title down in briefing. Other ui fixes.
98 * 6 3/30/98 6:27p Dave
99 * Put in a more official set of multiplayer options, including a system
100 * for distributing netplayer and netgame settings.
102 * 5 3/24/98 5:00p Dave
103 * Fixed several ui bugs. Put in pre and post voice stream playback sound
104 * fx. Put in error specific popups for clients getting dropped from games
105 * through actions other than their own.
107 * 4 3/18/98 5:52p Dave
108 * Put in netgame password popup. Numerous ui changes. Laid groundwork for
109 * streamed multi_voice data.
111 * 3 3/17/98 5:29p Dave
112 * Minor bug fixes in player select menu. Solidified mp joining process.
113 * Made furball mode support ingame joiners and dropped players correctly.
115 * 2 3/15/98 4:17p Dave
116 * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
117 * of network orientation matrices.
119 * 1 2/12/98 4:38p Dave
120 * Multiplayer kick functionality
125 #include "multi_kick.h"
126 #include "multimsgs.h"
127 #include "multiutil.h"
128 #include "freespace.h"
132 // ----------------------------------------------------------------------------------
136 #define MULTI_KICK_RESPONSE_TIME 4000 // if someone who has been kicked has not responded in this time, disconnect him hard
138 #define MAX_BAN_SLOTS 30
139 net_addr_t Multi_kick_ban_slots[MAX_BAN_SLOTS]; // banned addresses
140 int Multi_kick_num_ban_slots; // the # of banned addresses
142 // ----------------------------------------------------------------------------------
143 // KICK FORWARD DECLARATIONS
146 // send a player kick packet
147 void send_player_kick_packet(int player_index, int ban = 1, int reason = KICK_REASON_NORM);
149 // process a player kick packet
150 void process_player_kick_packet(ubyte *data, header *hinfo);
152 // add a net address to the banned list
153 void multi_kick_add_ban(net_addr_t *addr);
155 // can the given player perform a kick
156 int multi_kick_can_kick(net_player *player);
159 // ----------------------------------------------------------------------------------
163 // initialize all kicking details (ban lists, etc). it is safe to call this function at any time
164 void multi_kick_init()
166 // blast all the ban slots
167 memset(Multi_kick_ban_slots,0,sizeof(net_addr_t)*MAX_BAN_SLOTS);
168 Multi_kick_num_ban_slots = 0;
171 // process all kick details (disconnecting players who have been kicked but haven't closed their socket)
172 void multi_kick_process()
176 // if i'm not the server, don't do anything
177 if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
181 // disconnect any kicked players who have timed out on leaving
182 for(idx=0;idx<MAX_PLAYERS;idx++){
183 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].s_info.kick_timestamp != -1) && timestamp_elapsed(Net_players[idx].s_info.kick_timestamp) ){
184 delete_player(idx, Net_players[idx].s_info.kick_reason);
189 // attempt to kick a player. return success or fail
190 void multi_kick_player(int player_index, int ban, int reason)
192 // only the standalone should be able to kick the host of the game
193 if(!(Game_mode & GM_STANDALONE_SERVER) && ((Net_players[player_index].flags & NETINFO_FLAG_GAME_HOST) || (Net_players[player_index].flags & NETINFO_FLAG_AM_MASTER))){
194 nprintf(("Network","Cannot kick the host or server of a game!\n"));
196 // if we're the master, then delete the guy
197 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
198 // if we're supposed to ban him, add his address to the banned list
200 multi_kick_add_ban(&Net_players[player_index].p_info.addr);
203 // mark him as having been kicked
204 Net_players[player_index].flags |= NETINFO_FLAG_KICKED;
206 // set his kick timestamp and send him a leave game packet
207 Net_players[player_index].s_info.kick_timestamp = timestamp(MULTI_KICK_RESPONSE_TIME);
208 Net_players[player_index].s_info.kick_reason = reason;
209 send_leave_game_packet(Net_players[player_index].player_id, reason, &Net_players[player_index]);
211 // tell everyone else that he was kicked
212 send_leave_game_packet(Net_players[player_index].player_id, reason);
214 // wait until he either shuts his connection down or he times out)
215 // add the string to the chatbox and the hud (always safe - if it is not inited, nothing bad will happen)
217 SDL_snprintf(str, SDL_arraysize(str), XSTR("<kicking %s ...>", 1501), Net_players[player_index].player->callsign);
218 multi_display_chat_msg(str, player_index, 0);
220 // otherwise, we should send the packet indicating that this guy should be kicked
222 send_player_kick_packet(player_index, ban, reason);
227 // is this net address currently kicked and banded
228 int multi_kick_is_banned(net_addr_t *addr)
232 // traverse the banned list
233 for(idx=0;idx<Multi_kick_num_ban_slots;idx++){
234 // if we found a duplicate
235 if(psnet_same(&Multi_kick_ban_slots[idx],addr)){
244 // debug console function called to determine which player to kick
245 void multi_dcf_kick()
249 // get the callsign of the player to kick
250 dc_get_arg(ARG_STRING);
252 if(strlen(Dc_arg) == 0){
253 dc_printf("Invalid player callsign!\n");
258 for(idx=0;idx<MAX_PLAYERS;idx++){
259 if(MULTI_CONNECTED(Net_players[idx]) && (SDL_strcasecmp(Net_players[idx].player->callsign,Dc_arg)==0)){
265 // if we didn't find the player, notify of the results
266 if(player_num == -1){
267 dc_printf("Could not find player %s to kick!",Dc_arg);
269 // if we found the guy, then try and kick him
271 multi_kick_player(player_num);
275 // fill in the passed string with the appropriate "kicked" string
276 void multi_kick_get_text(net_player *pl, int reason, char *str, const int max_strlen)
279 if((pl == NULL) || (pl->player == NULL)){
280 SDL_strlcpy(str, NOX(""), max_strlen);
285 case KICK_REASON_BAD_XFER:
286 SDL_snprintf(str, max_strlen, XSTR("<%s was kicked because of mission file xfer failure>", 1003), pl->player->callsign);
288 case KICK_REASON_CANT_XFER:
289 SDL_snprintf(str, max_strlen, XSTR("<%s was kicked for not having builtin mission %s>", 1004), pl->player->callsign, Game_current_mission_filename);
291 case KICK_REASON_INGAME_ENDED:
292 SDL_snprintf(str, max_strlen, XSTR("<%s was kicked for ingame joining an ended game>",1005), pl->player->callsign);
295 SDL_snprintf(str, max_strlen, XSTR("<%s was kicked>",687), pl->player->callsign);
301 // ----------------------------------------------------------------------------------
302 // KICK FORWARD DEFINITIONS
305 // add a net address to the banned list
306 void multi_kick_add_ban(net_addr_t *addr)
308 // if we still have any slots left
309 if(Multi_kick_num_ban_slots < (MAX_BAN_SLOTS - 1)){
310 memcpy(&Multi_kick_ban_slots[Multi_kick_num_ban_slots++],addr,sizeof(net_addr_t));
315 // ----------------------------------------------------------------------------------
316 // KICK PACKET HANDLERS
319 // send a player kick packet
320 void send_player_kick_packet(int player_index, int ban, int reason)
322 ubyte data[MAX_PACKET_SIZE];
325 BUILD_HEADER(KICK_PLAYER);
327 // add the address of the player to be kicked
328 ADD_SHORT(Net_players[player_index].player_id);
330 // indicate if he should be banned
334 // send the request to the server
335 multi_io_send_reliable(Net_player, data, packet_size);
338 // process a player kick packet
339 void process_player_kick_packet(ubyte *data, header *hinfo)
341 int player_num,from_player,ban,reason;
343 int offset = HEADER_LENGTH;
345 // get the address of the guy who is to be kicked
346 GET_SHORT(player_id);
349 player_num = find_player_id(player_id);
352 // only the server should ever receive a request to kick a guy
353 SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
355 // determine who sent the packet
356 from_player = find_player_id(hinfo->id);
358 // check to see if this guy is allowed to make such a request
359 if((from_player == -1) || !multi_kick_can_kick(&Net_players[from_player]) ){
360 nprintf(("Network","Received a kick request from an invalid player!!\n"));
362 // otherwise, process the request fully
364 // make sure we have a valid player to kick
365 if(player_num == -1){
366 nprintf(("Network","Received request to kick an unknown player!\n"));
368 // will handle all the rest of the details
369 multi_kick_player(player_num,ban,reason);
374 // can the given player perform a kick
375 int multi_kick_can_kick(net_player *player)
377 // only host or server can kick
378 if((player->flags & NETINFO_FLAG_AM_MASTER) || (player->flags & NETINFO_FLAG_GAME_HOST)){
382 // this guy cannot kick