]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_kick.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / network / multi_kick.cpp
1 /*
2  * $Logfile: /Freespace2/code/Network/multi_kick.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * $Log$
8  * Revision 1.2  2002/05/07 03:16:47  theoddone33
9  * The Great Newline Fix
10  *
11  * Revision 1.1.1.1  2002/05/03 03:28:10  root
12  * Initial import.
13  *  
14  * 
15  * 8     10/13/99 3:51p Jefff
16  * fixed unnumbered XSTRs
17  * 
18  * 7     3/10/99 6:50p Dave
19  * Changed the way we buffer packets for all clients. Optimized turret
20  * fired packets. Did some weapon firing optimizations.
21  * 
22  * 6     3/09/99 6:24p Dave
23  * More work on object update revamping. Identified several sources of
24  * unnecessary bandwidth.
25  * 
26  * 5     11/19/98 8:03a Dave
27  * Full support for D3-style reliable sockets. Revamped packet lag/loss
28  * system, made it receiver side and at the lowest possible level.
29  * 
30  * 4     11/17/98 11:12a Dave
31  * Removed player identification by address. Now assign explicit id #'s.
32  * 
33  * 3     11/05/98 5:55p Dave
34  * Big pass at reducing #includes
35  * 
36  * 2     10/07/98 10:53a Dave
37  * Initial checkin.
38  * 
39  * 1     10/07/98 10:50a Dave
40  * 
41  * 16    9/15/98 7:24p Dave
42  * Minor UI changes. Localized bunch of new text.
43  * 
44  * 15    9/11/98 5:53p Dave
45  * Final revisions to kick system changes.
46  * 
47  * 14    9/11/98 5:08p Dave
48  * More tweaks to kick notification system.
49  * 
50  * 13    9/11/98 4:14p Dave
51  * Fixed file checksumming of < file_size. Put in more verbose kicking and
52  * PXO stats store reporting.
53  * 
54  * 12    6/13/98 9:32p Mike
55  * Kill last character in file which caused "Find in Files" to report the
56  * file as "not a text file."
57  * 
58  * 11    6/13/98 6:01p Hoffoss
59  * Externalized all new (or forgot to be added) strings to all the code.
60  * 
61  * 10    4/23/98 6:18p Dave
62  * Store ETS values between respawns. Put kick feature in the text
63  * messaging system. Fixed text messaging system so that it doesn't
64  * process or trigger ship controls. Other UI fixes.
65  * 
66  * 9     4/04/98 4:22p Dave
67  * First rev of UDP reliable sockets is done. Seems to work well if not
68  * overly burdened.
69  * 
70  * 8     4/03/98 1:03a Dave
71  * First pass at unreliable guaranteed delivery packets.
72  * 
73  * 7     4/01/98 11:19p Dave
74  * Put in auto-loading of xferred pilot pic files. Grey out background
75  * behind pinfo popup. Put a chatbox message in when players are kicked.
76  * Moved mission title down in briefing. Other ui fixes.
77  * 
78  * 6     3/30/98 6:27p Dave
79  * Put in a more official set of multiplayer options, including a system
80  * for distributing netplayer and netgame settings.
81  * 
82  * 5     3/24/98 5:00p Dave
83  * Fixed several ui bugs. Put in pre and post voice stream playback sound
84  * fx. Put in error specific popups for clients getting dropped from games
85  * through actions other than their own.
86  * 
87  * 4     3/18/98 5:52p Dave
88  * Put in netgame password popup. Numerous ui changes. Laid groundwork for
89  * streamed multi_voice data.
90  * 
91  * 3     3/17/98 5:29p Dave
92  * Minor bug fixes in player select menu. Solidified mp joining process.
93  * Made furball mode support ingame joiners and dropped players correctly.
94  * 
95  * 2     3/15/98 4:17p Dave
96  * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
97  * of network orientation matrices.
98  * 
99  * 1     2/12/98 4:38p Dave
100  * Multiplayer kick functionality
101  * 
102  * $NoKeywords: $
103  */
104 #include "multi.h"
105 #include "multi_kick.h"
106 #include "multimsgs.h"
107 #include "multiutil.h"
108 #include "freespace.h"
109 #include "chatbox.h"
110 #include "timer.h"
111
112 // ----------------------------------------------------------------------------------
113 // KICK DEFINES/VARS
114 //
115
116 #define MULTI_KICK_RESPONSE_TIME                                                4000            // if someone who has been kicked has not responded in this time, disconnect him hard
117
118 #define MAX_BAN_SLOTS           30
119 net_addr Multi_kick_ban_slots[MAX_BAN_SLOTS];                           // banned addresses
120 int Multi_kick_num_ban_slots;                                                                           // the # of banned addresses
121                                                          
122 // ----------------------------------------------------------------------------------
123 // KICK FORWARD DECLARATIONS
124 //
125
126 // send a player kick packet
127 void send_player_kick_packet(int player_index, int ban = 1, int reason = KICK_REASON_NORM);
128
129 // process a player kick packet
130 void process_player_kick_packet(ubyte *data, header *hinfo);
131
132 // add a net address to the banned list
133 void multi_kick_add_ban(net_addr *addr);
134
135 // can the given player perform a kick
136 int multi_kick_can_kick(net_player *player);
137
138
139 // ----------------------------------------------------------------------------------
140 // KICK FUNCTIONS
141 //
142
143 // initialize all kicking details (ban lists, etc). it is safe to call this function at any time
144 void multi_kick_init()
145 {
146         // blast all the ban slots
147         memset(Multi_kick_ban_slots,0,sizeof(net_addr)*MAX_BAN_SLOTS);
148         Multi_kick_num_ban_slots = 0;
149 }
150
151 // process all kick details (disconnecting players who have been kicked but haven't closed their socket)
152 void multi_kick_process()
153 {
154         int idx;
155
156         // if i'm not the server, don't do anything
157         if(!(Net_player->flags & NETINFO_FLAG_AM_MASTER)){
158                 return;
159         }
160
161         // disconnect any kicked players who have timed out on leaving
162         for(idx=0;idx<MAX_PLAYERS;idx++){
163                 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].s_info.kick_timestamp != -1) && timestamp_elapsed(Net_players[idx].s_info.kick_timestamp) ){
164                         delete_player(idx, Net_players[idx].s_info.kick_reason);
165                 }
166         }
167 }
168
169 // attempt to kick a player. return success or fail
170 void multi_kick_player(int player_index, int ban, int reason)
171 {       
172         // only the standalone should be able to kick the host of the game
173         if(!(Game_mode & GM_STANDALONE_SERVER) && ((Net_players[player_index].flags & NETINFO_FLAG_GAME_HOST) || (Net_players[player_index].flags & NETINFO_FLAG_AM_MASTER))){
174                 nprintf(("Network","Cannot kick the host or server of a game!\n"));
175         } else {
176                 // if we're the master, then delete the guy
177                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
178                         // if we're supposed to ban him, add his address to the banned list
179                         if(ban){
180                                 multi_kick_add_ban(&Net_players[player_index].p_info.addr);
181                         }
182
183                         // mark him as having been kicked
184                         Net_players[player_index].flags |= NETINFO_FLAG_KICKED;
185
186                         // set his kick timestamp and send him a leave game packet
187                         Net_players[player_index].s_info.kick_timestamp = timestamp(MULTI_KICK_RESPONSE_TIME);
188                         Net_players[player_index].s_info.kick_reason = reason;
189                         send_leave_game_packet(Net_players[player_index].player_id, reason, &Net_players[player_index]);                                                        
190
191                         // tell everyone else that he was kicked
192                         send_leave_game_packet(Net_players[player_index].player_id, reason);
193                         
194                         // wait until he either shuts his connection down or he times out)
195                         // add the string to the chatbox and the hud (always safe - if it is not inited, nothing bad will happen)                       
196                         char str[512];
197                         memset(str, 0, 512);
198                         sprintf(str, XSTR("<kicking %s ...>", 1501), Net_players[player_index].player->callsign);
199                         multi_display_chat_msg(str, player_index, 0);                                                    
200                 }
201                 // otherwise, we should send the packet indicating that this guy should be kicked
202                 else {
203                         send_player_kick_packet(player_index, ban, reason);
204                 }
205         }
206 }
207
208 // is this net address currently kicked and banded
209 int multi_kick_is_banned(net_addr *addr)
210 {
211         int idx;
212         
213         // traverse the banned list
214         for(idx=0;idx<Multi_kick_num_ban_slots;idx++){
215                 // if we found a duplicate
216                 if(psnet_same(&Multi_kick_ban_slots[idx],addr)){
217                         return 1;
218                 }
219         }
220
221         // he's not banned
222         return 0;
223 }
224
225 // debug console function called to determine which player to kick
226 void multi_dcf_kick()
227 {
228         int player_num,idx;
229
230         // get the callsign of the player to kick
231         dc_get_arg(ARG_STRING);
232
233         if(strlen(Dc_arg) == 0){
234                 dc_printf("Invalid player callsign!\n");
235                 return ;
236         }
237
238         player_num = -1;
239         for(idx=0;idx<MAX_PLAYERS;idx++){
240                 if(MULTI_CONNECTED(Net_players[idx]) && (stricmp(Net_players[idx].player->callsign,Dc_arg)==0)){
241                         player_num = idx;
242                         break;
243                 }
244         }
245
246         // if we didn't find the player, notify of the results
247         if(player_num == -1){
248                 dc_printf("Could not find player %s to kick!",Dc_arg);
249         } 
250         // if we found the guy, then try and kick him
251         else {
252                 multi_kick_player(player_num);
253         }
254 }
255
256 // fill in the passed string with the appropriate "kicked" string
257 void multi_kick_get_text(net_player *pl, int reason, char *str)
258 {
259         // safety net
260         if((pl == NULL) || (pl->player == NULL)){
261                 strcpy(str, NOX(""));
262         }
263
264         switch(reason){
265         case KICK_REASON_BAD_XFER:
266                 sprintf(str, XSTR("<%s was kicked because of mission file xfer failure>", 1003), pl->player->callsign);
267                 break;
268         case KICK_REASON_CANT_XFER:
269                 sprintf(str, XSTR("<%s was kicked for not having builtin mission %s>", 1004), pl->player->callsign, Game_current_mission_filename);
270                 break;
271         case KICK_REASON_INGAME_ENDED:
272                 sprintf(str, XSTR("<%s was kicked for ingame joining an ended game>",1005), pl->player->callsign);
273                 break;
274         default:
275                 sprintf(str, XSTR("<%s was kicked>",687), pl->player->callsign);
276                 break;
277         }               
278 }
279
280
281 // ----------------------------------------------------------------------------------
282 // KICK FORWARD DEFINITIONS
283 //
284
285 // add a net address to the banned list
286 void multi_kick_add_ban(net_addr *addr)
287 {
288         // if we still have any slots left
289         if(Multi_kick_num_ban_slots < (MAX_BAN_SLOTS - 1)){
290                 memcpy(&Multi_kick_ban_slots[Multi_kick_num_ban_slots++],addr,sizeof(net_addr));
291         }
292 }
293
294
295 // ----------------------------------------------------------------------------------
296 // KICK PACKET HANDLERS
297 //
298
299 // send a player kick packet
300 void send_player_kick_packet(int player_index, int ban, int reason)
301 {               
302         ubyte data[MAX_PACKET_SIZE];
303         int packet_size = 0;
304
305         BUILD_HEADER(KICK_PLAYER);
306
307         // add the address of the player to be kicked
308         ADD_DATA(Net_players[player_index].player_id);
309         
310         // indicate if he should be banned
311         ADD_DATA(ban);
312         ADD_DATA(reason);
313
314         // send the request to the server       
315         multi_io_send_reliable(Net_player, data, packet_size);
316 }
317
318 // process a player kick packet
319 void process_player_kick_packet(ubyte *data, header *hinfo)
320 {
321         int player_num,from_player,ban,reason;  
322         short player_id;
323         int offset = HEADER_LENGTH;
324         
325         // get the address of the guy who is to be kicked
326         GET_DATA(player_id);
327         GET_DATA(ban);
328         GET_DATA(reason);
329         player_num = find_player_id(player_id);
330         PACKET_SET_SIZE();
331
332         // only the server should ever receive a request to kick a guy
333         Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
334         
335         // determine who sent the packet        
336         from_player = find_player_id(hinfo->id);
337
338         // check to see if this guy is allowed to make such a request
339         if((from_player == -1) || !multi_kick_can_kick(&Net_players[from_player]) ){
340                 nprintf(("Network","Received a kick request from an invalid player!!\n"));
341         } 
342         // otherwise, process the request fully
343         else {
344                 // make sure we have a valid player to kick
345                 if(player_num == -1){
346                         nprintf(("Network","Received request to kick an unknown player!\n"));
347                 } else {
348                         // will handle all the rest of the details
349                         multi_kick_player(player_num,ban,reason);
350                 }
351         }
352 }
353
354 // can the given player perform a kick
355 int multi_kick_can_kick(net_player *player)
356 {
357         // only host or server can kick
358         if((player->flags & NETINFO_FLAG_AM_MASTER) || (player->flags & NETINFO_FLAG_GAME_HOST)){
359                 return 1;
360         }
361         
362         // this guy cannot kick
363         return 0;
364 }
365