]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_data.cpp
return 404 for favicon.ico to avoid sending html twice
[taylor/freespace2.git] / src / network / multi_data.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_data.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * $Log$
16  * Revision 1.4  2002/06/09 04:41:23  relnev
17  * added copyright header
18  *
19  * Revision 1.3  2002/05/26 20:22:48  theoddone33
20  * Most of network/ works
21  *
22  * Revision 1.2  2002/05/07 03:16:47  theoddone33
23  * The Great Newline Fix
24  *
25  * Revision 1.1.1.1  2002/05/03 03:28:10  root
26  * Initial import.
27  * 
28  * 
29  * 8     6/16/99 4:06p Dave
30  * New pilot info popup. Added new draw-bitmap-as-poly function.
31  * 
32  * 7     1/21/99 2:06p Dave
33  * Final checkin for multiplayer testing.
34  * 
35  * 6     1/14/99 6:06p Dave
36  * 100% full squad logo support for single player and multiplayer.
37  * 
38  * 5     12/18/98 12:31p Johnson
39  * Fixed a bug where the server would not properly redistribute a data
40  * file that he already had to other players.
41  * 
42  * 4     12/14/98 4:01p Dave
43  * Got multi_data stuff working well with new xfer stuff. 
44  * 
45  * 3     12/14/98 12:13p Dave
46  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
47  * Need to test now.
48  * 
49  * 2     10/07/98 10:53a Dave
50  * Initial checkin.
51  * 
52  * 1     10/07/98 10:50a Dave
53  * 
54  * 19    6/13/98 3:18p Hoffoss
55  * NOX()ed out a bunch of strings that shouldn't be translated.
56  * 
57  * 18    5/21/98 3:45a Sandeep
58  * Make sure file xfer sender side uses correct directory type.
59  * 
60  * 17    5/17/98 6:32p Dave
61  * Make sure clients/servers aren't kicked out of the debriefing when team
62  * captains leave a game. Fixed chatbox off-by-one error. Fixed image
63  * xfer/pilot info popup stuff.
64  * 
65  * 16    5/13/98 6:54p Dave
66  * More sophistication to PXO interface. Changed respawn checking so
67  * there's no window for desynchronization between the server and the
68  * clients.
69  * 
70  * 15    4/30/98 4:53p John
71  * Restructured and cleaned up cfile code.  Added capability to read off
72  * of CD-ROM drive and out of multiple pack files.
73  * 
74  * 14    4/21/98 4:44p Dave
75  * Implement Vasudan ships in multiplayer. Added a debug function to bash
76  * player rank. Fixed a few rtvoice buffer overrun problems. Fixed ui
77  * problem in options screen. 
78  * 
79  * 13    4/16/98 1:55p Dave
80  * Removed unneeded SDL_assert when processing chat packets. Fixed standalone
81  * sequencing bugs. Laid groundwork for join screen server status
82  * icons/text.
83  * 
84  * 12    4/14/98 12:19p Dave
85  * Revised the pause system yet again. Seperated into its own module.
86  * 
87  * 11    4/08/98 2:51p Dave
88  * Fixed pilot image xfer once again. Solidify team selection process in
89  * pre-briefing multiplayer.
90  * 
91  * 10    4/04/98 4:22p Dave
92  * First rev of UDP reliable sockets is done. Seems to work well if not
93  * overly burdened.
94  * 
95  * 9     3/30/98 6:27p Dave
96  * Put in a more official set of multiplayer options, including a system
97  * for distributing netplayer and netgame settings.
98  * 
99  * 8     3/26/98 6:01p Dave
100  * Put in file checksumming routine in cfile. Made pilot pic xferring more
101  * robust. Cut header size of voice data packets in half. Put in
102  * restricted game host query system.
103  * 
104  * 7     3/23/98 5:42p Dave
105  * Put in automatic xfer of pilot pic files. Changed multi_xfer system so
106  * that it can support multiplayer sends/received between client and
107  * server simultaneously.
108  * 
109  * 6     3/21/98 7:14p Dave
110  * Fixed up standalone player slot switching. Made training missions not
111  * count towards player stats.
112  * 
113  * 5     3/15/98 4:17p Dave
114  * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
115  * of network orientation matrices.
116  * 
117  * 4     3/11/98 2:04p Dave
118  * Removed optimized build warnings.
119  * 
120  * 3     2/20/98 4:43p Dave
121  * Finished support for multiplayer player data files. Split off
122  * multiplayer campaign functionality.
123  * 
124  * 2     2/19/98 6:44p Dave
125  * Finished server getting data from players. Now need to rebroadcast the
126  * data.
127  * 
128  * 1     2/19/98 6:21p Dave
129  * Player data file xfer module.
130  * 
131  * $NoKeywords: $
132  */
133
134 #include <ctype.h>
135 #include "bmpman.h"
136 #include "psnet.h"
137 #include "multi_data.h"
138 #include "freespace.h"
139 #include "multi_xfer.h"
140 #include "multi.h"
141 #include "multimsgs.h"
142 #include "multiutil.h"
143 #include "player.h"
144
145 // -------------------------------------------------------------------------
146 // MULTI DATA DEFINES/VARS
147 //
148
149 #define MAX_MULTI_DATA                                  40
150
151 // player data struct
152 typedef struct np_data {
153         char filename[MAX_FILENAME_LEN+1];                      // filename
154         ubyte status[MAX_PLAYERS];                                              // status for all players (0 == don't have it, 1 == have or sending, 2 == i sent it originally)
155         ushort player_id;                                                                       // id of the player who sent the file
156         ubyte used;                                                                                     // in use or not
157 } np_data;
158
159 np_data Multi_data[MAX_MULTI_DATA];
160
161 time_t Multi_data_time = 0;
162
163
164 // -------------------------------------------------------------------------
165 // MULTI DATA FORWARD DECLARATIONS
166 //
167
168 // is the given filename for a "multi data" file (pcx, wav, etc)
169 int multi_data_is_data(char *filename);
170
171 // get a free np_data slot
172 int multi_data_get_free();
173
174 // server side - add a new file
175 int multi_data_add_new(char *filename, int player_index);
176
177 // maybe try and reload player squad logo bitmaps
178 void multi_data_maybe_reload();
179
180
181 // -------------------------------------------------------------------------
182 // MULTI DATA FUNCTIONS
183 //
184
185 // reset the data xfer system
186 void multi_data_reset()
187 {               
188         int idx;
189
190         // clear out all used bits
191         for(idx=0; idx<MAX_MULTI_DATA; idx++){
192                 Multi_data[idx].used = 0;
193         }
194 }
195
196 // handle a player join (clear out lists of files, etc)
197 void multi_data_handle_join(int player_index)
198 {
199         int idx;
200         
201         // clear out his status for all files           
202         for(idx=0;idx<MAX_MULTI_DATA;idx++){
203                 Multi_data[idx].status[player_index] = 0;
204         }
205 }
206
207 // handle a player drop (essentially the same as multi_data_handle_join)
208 void multi_data_handle_drop(int player_index)
209 {
210         int idx;
211                 
212         // mark all files he sent as being unused
213         for(idx=0;idx<MAX_MULTI_DATA;idx++){
214                 if(Multi_data[idx].player_id == Net_players[player_index].player_id){
215                         Multi_data[idx].used = 0;
216                 }
217         }
218 }
219
220 // do all sync related data stuff (server-side only)
221 void multi_data_do()
222 {               
223         int idx, p_idx;
224
225         // only do this once a second
226         if((time(NULL) - Multi_data_time) < 1){         
227                 return;
228         }
229
230         // maybe try and reload player squad logo bitmaps
231         multi_data_maybe_reload();
232
233         // reset the time
234         Multi_data_time = time(NULL);
235
236         // if I'm the server
237         if(Net_player && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
238                 // for all valid files
239                 for(idx=0; idx<MAX_MULTI_DATA; idx++){
240                         // a valid file that isn't currently xferring (ie, anything we've got completely on our hard drive)
241                         if(Multi_data[idx].used && (multi_xfer_lookup(Multi_data[idx].filename) < 0)){
242                                 // send it to all players who need it
243                                 for(p_idx=0; p_idx<MAX_PLAYERS; p_idx++){
244                                         // if he doesn't have it
245                                         if((Net_player != &Net_players[p_idx]) && MULTI_CONNECTED(Net_players[p_idx]) && (Net_players[p_idx].reliable_socket != INVALID_SOCKET) && (Multi_data[idx].status[p_idx] == 0)){                                               
246                                                 // queue up the file to send to him, or at least try to
247                                                 if(multi_xfer_send_file(Net_players[p_idx].reliable_socket, Multi_data[idx].filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE) < 0){
248                                                         nprintf(("Network", "Failed to send data file! Trying again later...\n"));
249                                                 } else {
250                                                         // mark his status
251                                                         Multi_data[idx].status[p_idx] = 1;
252                                                 }
253                                         }
254                                 }
255                         }
256                 }
257         }
258 }
259
260 // handle an incoming xfer request from the xfer system
261 void multi_data_handle_incoming(int handle)
262 {       
263         int player_index = -1;
264         PSNET_SOCKET_RELIABLE sock = INVALID_SOCKET;    
265         char *fname;            
266
267         // get the player who is sending us this file   
268         sock = multi_xfer_get_sock(handle);
269         player_index = find_player_socket(sock);
270
271         // get the filename of the file
272         fname = multi_xfer_get_filename(handle);
273         if(fname == NULL){
274                 nprintf(("Network", "Could not get file xfer filename! wacky...!\n"));
275
276                 // kill the stream
277                 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
278                 return;
279         }
280
281         // if this is not a valid data file
282         if(!multi_data_is_data(fname)){
283                 nprintf(("Network", "Not accepting xfer request because its not a valid data file!\n"));
284                 
285                 // kill the stream              
286                 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);   
287                 return;
288         }       
289
290         // if we already have a copy of this file, abort the xfer               
291         // Does file exist in \multidata?
292         if( cf_exist(fname, CF_TYPE_MULTI_CACHE) ){                     
293                 nprintf(("Network", "Not accepting file xfer because a duplicate exists!\n"));                  
294         
295                 // kill the stream              
296                 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);   
297
298                 // if we're the server, we still need to add it to the list though
299                 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (player_index >= 0)){
300                         multi_data_add_new(fname, player_index);
301                 }
302                 return;
303         }       
304         
305         // if I'm the server of the game, do stuff a little differently
306         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
307                 if(player_index == -1){
308                         nprintf(("Network", "Could not find player for incoming player data stream!\n"));
309
310                         // kill the stream
311                         multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
312                         return;
313                 }       
314
315                 // attempt to add the file
316                 if(!multi_data_add_new(fname, player_index)){
317                         // kill the stream
318                         multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);
319                         return;
320                 } else {
321                         // force the file to go into the multi cache directory
322                         multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
323                         
324                         // mark it as autodestroy                       
325                         multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
326                 }
327         }
328         // if i'm a client, this is an incoming file from the server
329         else {
330                 // if i'm not accepting pilot pics, abort
331                 if(!(Net_player->p_info.options.flags & MLO_FLAG_ACCEPT_PIX)){
332                         nprintf(("Network", "Client not accepting files because we don't want 'em!\n"));
333
334                         // kill the stream              
335                         multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_REJECT);   
336                         return;
337                 }
338
339                 // set the xfer handle to autodestroy itself since we don't really want to have to manage all incoming pics
340                 multi_xfer_xor_flags(handle, MULTI_XFER_FLAG_AUTODESTROY);
341                 
342                 // force the file to go into the multi cache directory
343                 multi_xfer_handle_force_dir(handle, CF_TYPE_MULTI_CACHE);
344
345                 // begin receiving the file
346                 nprintf(("Network", "Client receiving xfer handle %d\n",handle));
347         }               
348 }
349
350 // send all my files as necessary
351 void multi_data_send_my_junk()
352 {               
353         char *with_ext; 
354         int bmap, w, h;
355         int ok_to_send = 1;
356
357         // pilot pic --------------------------------------------------------------
358
359         // verify that my pilot pic is valid
360         if(strlen(Net_player->player->image_filename)){
361                 bmap = bm_load(Net_player->player->image_filename);
362                 if(bmap == -1){                 
363                         ok_to_send = 0;
364                 }
365
366                 // verify image dimensions
367                 if(ok_to_send){
368                         w = -1;
369                         h = -1;
370                         bm_get_info(bmap,&w,&h);
371
372                         // release the bitmap
373                         bm_release(bmap);
374
375                         // if the dimensions are invalid, kill the filename
376                         if((w != PLAYER_PILOT_PIC_W) || (h != PLAYER_PILOT_PIC_H)){
377                                 ok_to_send = 0;
378                         }
379                 }
380         } else {                
381                 ok_to_send = 0;
382         }
383
384         if(ok_to_send){
385                 with_ext = cf_add_ext(Net_player->player->image_filename, NOX(".pcx"));
386                 if(with_ext != NULL){
387                         SDL_strlcpy(Net_player->player->image_filename, with_ext, MAX_FILENAME_LEN);
388                 }
389
390                 // host should put his own pic file in the list now
391                 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (strlen(Net_player->player->image_filename) > 0)){
392                         multi_data_add_new(Net_player->player->image_filename, MY_NET_PLAYER_NUM);
393                 }
394                 // otherwise clients should just queue up a send
395                 else {
396                         // add a file extension if necessary                    
397                         multi_xfer_send_file(Net_player->reliable_socket, Net_player->player->image_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
398                 }               
399         }
400
401
402         // squad logo --------------------------------------------------------------
403
404         // verify that my pilot pic is valid
405         ok_to_send = 1;
406         if(strlen(Net_player->player->squad_filename)){
407                 bmap = bm_load(Net_player->player->squad_filename);
408                 if(bmap == -1){                 
409                         ok_to_send = 0;
410                 }
411
412                 if(ok_to_send){
413                         // verify image dimensions
414                         w = -1;
415                         h = -1;
416                         bm_get_info(bmap,&w,&h);
417
418                         // release the bitmap
419                         bm_release(bmap);
420
421                         // if the dimensions are invalid, kill the filename
422                         if((w != PLAYER_SQUAD_PIC_W) || (h != PLAYER_SQUAD_PIC_H)){
423                                 ok_to_send = 0;
424                         }
425                 }
426         } else {                
427                 ok_to_send = 0;
428         }
429
430         if(ok_to_send){
431                 with_ext = cf_add_ext(Net_player->player->squad_filename, NOX(".pcx"));
432                 if(with_ext != NULL){
433                         SDL_strlcpy(Net_player->player->squad_filename, with_ext, MAX_FILENAME_LEN);
434                 }
435
436                 // host should put his own pic file in the list now
437                 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && !(Game_mode & GM_STANDALONE_SERVER) && (strlen(Net_player->player->squad_filename) > 0)){
438                         multi_data_add_new(Net_player->player->squad_filename, MY_NET_PLAYER_NUM);
439                 }
440                 // otherwise clients should just queue up a send
441                 else {
442                         // add a file extension if necessary                    
443                         multi_xfer_send_file(Net_player->reliable_socket, Net_player->player->squad_filename, CF_TYPE_ANY, MULTI_XFER_FLAG_AUTODESTROY | MULTI_XFER_FLAG_QUEUE);
444                 }               
445         }
446 }
447
448
449 // -------------------------------------------------------------------------
450 // MULTI DATA FORWARD DECLARATIONS
451 //
452
453 // is the give file xfer handle for a "multi data" file (pcx, wav, etc)
454 int multi_data_is_data(char *filename)
455 {               
456         int len,idx;
457
458         SDL_assert(filename != NULL);
459
460         // some kind of error
461         if(filename == NULL){
462                 return 0;
463         }
464
465         // convert to lowercase
466         len = strlen(filename);
467         for(idx=0;idx<len;idx++){
468                 filename[idx] = (char)tolower(filename[idx]);
469         }
470
471         // check to see if the extension is .pcx
472         if(strstr(filename, NOX(".pcx"))){
473                 return 1;
474         }
475
476         // not a data file
477         return 0;
478 }
479
480 // get a free np_data slot
481 int multi_data_get_free()
482 {
483         int idx;
484
485         // find a free slot
486         for(idx=0; idx<MAX_MULTI_DATA; idx++){
487                 if(!Multi_data[idx].used){
488                         return idx;
489                 }
490         }
491
492         // couldn't find one
493         return -1;
494 }
495
496 // server side - add a new file. return 1 on success
497 int multi_data_add_new(char *filename, int player_index)
498 {       
499         int slot;
500                 
501         // try and get a free slot
502         slot = multi_data_get_free();
503         if(slot < 0){
504                 nprintf(("Network", "Could not get free np_data slot! yikes!\n"));              
505                 return 0;
506         }
507
508         // if the netgame isn't flagged as accepting data files
509         if(!(Netgame.options.flags & MSO_FLAG_ACCEPT_PIX)){
510                 nprintf(("Network", "Server not accepting pilot pic because we don't want 'em!\n"));    
511                 return 0;
512         }                       
513
514         // assign the data
515         memset(&Multi_data[slot], 0, sizeof(np_data));                                                          // clear the slot out
516         SDL_strlcpy(Multi_data[slot].filename, filename, MAX_FILENAME_LEN);                                                                     // copy the filename
517         Multi_data[slot].used = 1;                                                                                                                      // set it as being in use
518         Multi_data[slot].player_id = Net_players[player_index].player_id;               // player id of who's sending the file
519         Multi_data[slot].status[player_index] = 2;                                                                      // mark his status appropriately
520
521         // success
522         return 1;
523 }
524
525 // maybe try and reload player squad logo bitmaps
526 void multi_data_maybe_reload()
527 {
528         int idx;
529
530         // go through all connected and try to reload their images if necessary
531         for(idx=0; idx<MAX_PLAYERS; idx++){
532                 if(MULTI_CONNECTED(Net_players[idx]) && strlen(Net_players[idx].player->squad_filename) && (Net_players[idx].player->insignia_texture == -1)){
533                         Net_players[idx].player->insignia_texture = bm_load_duplicate(Net_players[idx].player->squad_filename);
534
535                         // if the bitmap loaded properly, lock it as a transparent texture
536                         if(Net_players[idx].player->insignia_texture != -1){
537                                 bm_lock(Net_players[idx].player->insignia_texture, 16, BMP_TEX_XPARENT);
538                                 bm_unlock(Net_players[idx].player->insignia_texture);
539                         }
540                 }
541         }       
542 }