]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_kick.cpp
log standalone out of tracker only on close
[taylor/freespace2.git] / src / network / multi_kick.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Network/multi_kick.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * $Log$
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 :)
18  *
19  * Revision 1.5  2004/06/11 01:18:40  tigital
20  * byte-swapping changes for bigendian systems
21  *
22  * Revision 1.4  2002/06/09 04:41:23  relnev
23  * added copyright header
24  *
25  * Revision 1.3  2002/05/27 00:40:47  theoddone33
26  * Fix net_addr vs net_addr_t
27  *
28  * Revision 1.2  2002/05/07 03:16:47  theoddone33
29  * The Great Newline Fix
30  *
31  * Revision 1.1.1.1  2002/05/03 03:28:10  root
32  * Initial import.
33  *  
34  * 
35  * 8     10/13/99 3:51p Jefff
36  * fixed unnumbered XSTRs
37  * 
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.
41  * 
42  * 6     3/09/99 6:24p Dave
43  * More work on object update revamping. Identified several sources of
44  * unnecessary bandwidth.
45  * 
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.
49  * 
50  * 4     11/17/98 11:12a Dave
51  * Removed player identification by address. Now assign explicit id #'s.
52  * 
53  * 3     11/05/98 5:55p Dave
54  * Big pass at reducing #includes
55  * 
56  * 2     10/07/98 10:53a Dave
57  * Initial checkin.
58  * 
59  * 1     10/07/98 10:50a Dave
60  * 
61  * 16    9/15/98 7:24p Dave
62  * Minor UI changes. Localized bunch of new text.
63  * 
64  * 15    9/11/98 5:53p Dave
65  * Final revisions to kick system changes.
66  * 
67  * 14    9/11/98 5:08p Dave
68  * More tweaks to kick notification system.
69  * 
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.
73  * 
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."
77  * 
78  * 11    6/13/98 6:01p Hoffoss
79  * Externalized all new (or forgot to be added) strings to all the code.
80  * 
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.
85  * 
86  * 9     4/04/98 4:22p Dave
87  * First rev of UDP reliable sockets is done. Seems to work well if not
88  * overly burdened.
89  * 
90  * 8     4/03/98 1:03a Dave
91  * First pass at unreliable guaranteed delivery packets.
92  * 
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.
97  * 
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.
101  * 
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.
106  * 
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.
110  * 
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.
114  * 
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.
118  * 
119  * 1     2/12/98 4:38p Dave
120  * Multiplayer kick functionality
121  * 
122  * $NoKeywords: $
123  */
124 #include "multi.h"
125 #include "multi_kick.h"
126 #include "multimsgs.h"
127 #include "multiutil.h"
128 #include "freespace.h"
129 #include "chatbox.h"
130 #include "timer.h"
131
132 // ----------------------------------------------------------------------------------
133 // KICK DEFINES/VARS
134 //
135
136 #define MULTI_KICK_RESPONSE_TIME                                                4000            // if someone who has been kicked has not responded in this time, disconnect him hard
137
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
141                                                          
142 // ----------------------------------------------------------------------------------
143 // KICK FORWARD DECLARATIONS
144 //
145
146 // send a player kick packet
147 void send_player_kick_packet(int player_index, int ban = 1, int reason = KICK_REASON_NORM);
148
149 // process a player kick packet
150 void process_player_kick_packet(ubyte *data, header *hinfo);
151
152 // add a net address to the banned list
153 void multi_kick_add_ban(net_addr_t *addr);
154
155 // can the given player perform a kick
156 int multi_kick_can_kick(net_player *player);
157
158
159 // ----------------------------------------------------------------------------------
160 // KICK FUNCTIONS
161 //
162
163 // initialize all kicking details (ban lists, etc). it is safe to call this function at any time
164 void multi_kick_init()
165 {
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;
169 }
170
171 // process all kick details (disconnecting players who have been kicked but haven't closed their socket)
172 void multi_kick_process()
173 {
174         int idx;
175
176         // if i'm not the server, don't do anything
177         if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
178                 return;
179         }
180
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);
185                 }
186         }
187 }
188
189 // attempt to kick a player. return success or fail
190 void multi_kick_player(int player_index, int ban, int reason)
191 {       
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"));
195         } else {
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
199                         if(ban){
200                                 multi_kick_add_ban(&Net_players[player_index].p_info.addr);
201                         }
202
203                         // mark him as having been kicked
204                         Net_players[player_index].flags |= NETINFO_FLAG_KICKED;
205
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]);                                                        
210
211                         // tell everyone else that he was kicked
212                         send_leave_game_packet(Net_players[player_index].player_id, reason);
213                         
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)                       
216                         char str[512];
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);                                                    
219                 }
220                 // otherwise, we should send the packet indicating that this guy should be kicked
221                 else {
222                         send_player_kick_packet(player_index, ban, reason);
223                 }
224         }
225 }
226
227 // is this net address currently kicked and banded
228 int multi_kick_is_banned(net_addr_t *addr)
229 {
230         int idx;
231         
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)){
236                         return 1;
237                 }
238         }
239
240         // he's not banned
241         return 0;
242 }
243
244 // debug console function called to determine which player to kick
245 void multi_dcf_kick()
246 {
247         int player_num,idx;
248
249         // get the callsign of the player to kick
250         dc_get_arg(ARG_STRING);
251
252         if(strlen(Dc_arg) == 0){
253                 dc_printf("Invalid player callsign!\n");
254                 return ;
255         }
256
257         player_num = -1;
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)){
260                         player_num = idx;
261                         break;
262                 }
263         }
264
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);
268         } 
269         // if we found the guy, then try and kick him
270         else {
271                 multi_kick_player(player_num);
272         }
273 }
274
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)
277 {
278         // safety net
279         if((pl == NULL) || (pl->player == NULL)){
280                 SDL_strlcpy(str, NOX(""), max_strlen);
281                 return;
282         }
283
284         switch(reason){
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);
287                 break;
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);
290                 break;
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);
293                 break;
294         default:
295                 SDL_snprintf(str, max_strlen, XSTR("<%s was kicked>",687), pl->player->callsign);
296                 break;
297         }               
298 }
299
300
301 // ----------------------------------------------------------------------------------
302 // KICK FORWARD DEFINITIONS
303 //
304
305 // add a net address to the banned list
306 void multi_kick_add_ban(net_addr_t *addr)
307 {
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));
311         }
312 }
313
314
315 // ----------------------------------------------------------------------------------
316 // KICK PACKET HANDLERS
317 //
318
319 // send a player kick packet
320 void send_player_kick_packet(int player_index, int ban, int reason)
321 {               
322         ubyte data[MAX_PACKET_SIZE];
323         int packet_size = 0;
324
325         BUILD_HEADER(KICK_PLAYER);
326
327         // add the address of the player to be kicked
328         ADD_SHORT(Net_players[player_index].player_id);
329         
330         // indicate if he should be banned
331         ADD_INT(ban);
332         ADD_INT(reason);
333
334         // send the request to the server       
335         multi_io_send_reliable(Net_player, data, packet_size);
336 }
337
338 // process a player kick packet
339 void process_player_kick_packet(ubyte *data, header *hinfo)
340 {
341         int player_num,from_player,ban,reason;  
342         short player_id;
343         int offset = HEADER_LENGTH;
344         
345         // get the address of the guy who is to be kicked
346         GET_SHORT(player_id);
347         GET_INT(ban);
348         GET_INT(reason);
349         player_num = find_player_id(player_id);
350         PACKET_SET_SIZE();
351
352         // only the server should ever receive a request to kick a guy
353         SDL_assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
354         
355         // determine who sent the packet        
356         from_player = find_player_id(hinfo->id);
357
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"));
361         } 
362         // otherwise, process the request fully
363         else {
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"));
367                 } else {
368                         // will handle all the rest of the details
369                         multi_kick_player(player_num,ban,reason);
370                 }
371         }
372 }
373
374 // can the given player perform a kick
375 int multi_kick_can_kick(net_player *player)
376 {
377         // only host or server can kick
378         if((player->flags & NETINFO_FLAG_AM_MASTER) || (player->flags & NETINFO_FLAG_GAME_HOST)){
379                 return 1;
380         }
381         
382         // this guy cannot kick
383         return 0;
384 }
385