FS2_Open
Open source remastering of the Freespace 2 engine
fs2netd_client.cpp
Go to the documentation of this file.
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 the
6  * source.
7  *
8 */
9 
10 
11 
12 #include "bmpman/bmpman.h"
13 #include "cfile/cfile.h"
14 #include "cfile/cfilesystem.h"
15 #include "cmdline/cmdline.h"
16 #include "fs2netd/fs2netd_client.h"
17 #include "fs2netd/tcp_client.h"
18 #include "gamesnd/gamesnd.h"
19 #include "globalincs/alphacolors.h"
20 #include "globalincs/pstypes.h"
21 #include "graphics/2d.h"
22 #include "graphics/font.h"
23 #include "io/timer.h"
24 #include "mod_table/mod_table.h"
25 #include "network/multi.h"
26 #include "network/multi_log.h"
27 #include "network/multi_options.h"
28 #include "network/multi_pxo.h"
29 #include "network/multimsgs.h"
30 #include "network/multiui.h"
31 #include "network/multiutil.h"
32 #include "network/stand_gui.h"
33 #include "osapi/osregistry.h"
34 #include "playerman/player.h"
35 #include "popup/popup.h"
36 
37 #ifndef WIN32
38 #include <cstdio>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <cerrno>
42 #endif
43 
44 #include <string>
45 #include <limits.h>
46 
47 
48 #define FS2NETD_DEFAULT_PORT "12009"
49 #define FS2NETD_DEFAULT_SERVER "fs2netd.game-warden.com"
50 #define FS2NETD_DEFAULT_CHAT_SERVER "fs2netd.game-warden.com"
51 #define FS2NETD_DEFAULT_BANNER_URL "http://fs2netd.game-warden.com/files/banners"
52 
53 
55 extern void HUD_printf(const char *format, ...);
56 extern int game_hacked_data();
57 
58 
59 static bool PXO_options_loaded = false;
60 
61 static bool Is_connected = false;
62 static bool In_process = false;
63 static bool Logged_in = false;
64 static bool Duplicate_login_detected = false;
65 
66 static bool do_full_packet = true;
67 
68 static int Local_timeout = -1;
69 static int Next_gameserver_update = -1;
70 static int Ping_timestamp = -1;
71 static int Last_activity = -1;
72 static int Login_retry_time = -1;
73 
74 static SCP_vector<file_record> FS2NetD_file_list;
75 static SCP_vector<SCP_string> FS2NetD_ban_list;
76 
78 
79 // channel to associate when creating a server
81 
82 // channel to use when polling the tracker for games
84 
86 
87 
88 static void fs2netd_reset_state()
89 {
90  Multi_tracker_id = -1;
91  Is_connected = false;
92  In_process = false;
93  Logged_in = false;
94  do_full_packet = true;
95  Local_timeout = -1;
96  Next_gameserver_update = -1;
97  Last_activity = -1;
98  Ping_timestamp = -1;
99  Duplicate_login_detected = false;
100  Login_retry_time = -1;
101 }
102 
104 {
105  if (PXO_options_loaded) {
106  return;
107  }
108 
109  if ( !strlen(Multi_options_g.game_tracker_ip) ) {
110  ml_printf("NOTICE: Address for game tracker not specified, using default instead (%s).", FS2NETD_DEFAULT_SERVER);
112  } else if ( !strcmp("gt.pxo.net", Multi_options_g.game_tracker_ip) ) {
113  ml_printf("NOTICE: Incompatible game tracker IP detected (gt.pxo.net), using default instead (%s)!", FS2NETD_DEFAULT_SERVER);
115  }
116 
117  if ( !strlen(Multi_options_g.user_tracker_ip) ) {
118  ml_printf("NOTICE: Address for user tracker not specified, using default instead (%s).", FS2NETD_DEFAULT_SERVER);
120  } else if ( !strcmp("ut.pxo.net", Multi_options_g.user_tracker_ip) ) {
121  ml_printf("NOTICE: Incompatible user tracker IP detected (ut.pxo.net), using default instead (%s)!", FS2NETD_DEFAULT_SERVER);
123  }
124 
125  if ( !strlen(Multi_options_g.tracker_port) ) {
126  if ( FS2NetD_port >= 1024 && FS2NetD_port <= USHRT_MAX ) {
127  ml_printf("NOTICE: User override for game/user tracker port not specified, using game_settings.tbl override (%i).", FS2NetD_port);
128  int result;
130  Assertion( result > 0, "Copying port %i to tracker_port failed\n", FS2NetD_port );
131  }
132  else {
133  if ( FS2NetD_port != 0 ) {
134  ml_printf("ERROR: game_settings.tbl override for game/user tracker port '%i' must be between %i and %i.", FS2NetD_port, 1024, USHRT_MAX);
135  }
136  ml_printf("NOTICE: Port for game/user trackers not specified, using default instead (%s).", FS2NETD_DEFAULT_PORT);
138  }
139  } else {
140  long port_tmp = strtol(Multi_options_g.tracker_port, (char**)NULL, 10);
141 
142  if ( (port_tmp < 1024) || (port_tmp > USHRT_MAX) ) {
143  ml_printf("NOTICE: The port specified for game/user trackers, '%i', is outside of the required range, %i through %i!", port_tmp, 1024, USHRT_MAX);
144  ml_printf("NOTICE: Port for game/user trackers is invalid, using default instead (%s).", FS2NETD_DEFAULT_PORT);
146  }
147  }
148 
149  if ( !strlen(Multi_options_g.pxo_ip) ) {
150  ml_printf("NOTICE: Address for chat server not specified, using default instead (%s).", FS2NETD_DEFAULT_CHAT_SERVER);
152  } else if ( !strcmp("chat.pxo.net", Multi_options_g.pxo_ip) ) {
153  ml_printf("NOTICE: Incompatible chat server IP detected (chat.pxo.net), using default instead (%s)!", FS2NETD_DEFAULT_CHAT_SERVER);
155  }
156 
157  if ( !strlen(Multi_options_g.pxo_banner_url) ) {
158  ml_printf("NOTICE: URL for banners not specified, using default instead (%s).", FS2NETD_DEFAULT_BANNER_URL);
160  } else if ( !strcmp("http://www.pxo.net/files/banners", Multi_options_g.pxo_banner_url) ) {
161  ml_printf("NOTICE: Incompatible banner URL detected (chat.pxo.net), using default instead (%s)!", FS2NETD_DEFAULT_BANNER_URL);
163  }
164 
165  PXO_options_loaded = true;
166 }
167 
169 {
170  return (Is_connected && Logged_in);
171 }
172 
174 {
175  bool reset_gameserver = false;
176 
179  reset_gameserver = true;
180  }
181 
183 
184  fs2netd_reset_state();
185 
186  // wait a little to allow for the port to clear
187  Sleep(500);
188 
189  // try to reinit the server connection
190  fs2netd_login();
191 
192  Sleep(250);
193 
194  if ( reset_gameserver && fs2netd_is_online() ) {
196  }
197 }
198 
200 {
201  if ( !Is_connected ) {
202  return;
203  }
204 
207  }
208 
210 
211  fs2netd_reset_state();
212 
213  Sleep(500);
214 }
215 
216 static int fs2netd_connect_do()
217 {
219 
220  Sleep(5);
221 
222  switch (retval) {
223  // connection failed
224  case -1:
225  Is_connected = false;
226  return 2;
227 
228  // still trying to connect
229  case 0:
230  return 0;
231 
232  // connected!
233  case 1:
234  Is_connected = true;
235  return 1;
236  }
237 
238  return 0;
239 }
240 
242 {
243  int rc = 0;
244 
245  // don't bother with this if we aren't on FS2NetD
246  if ( !Om_tracker_flag ) {
247  return;
248  }
249 
250  if ( !(Game_mode & GM_MULTIPLAYER) ) {
251  return;
252  }
253 
254  if (Is_connected) {
255  return;
256  }
257 
260 
261  In_process = true;
262 
263  if (Is_standalone) {
264  do { rc = fs2netd_connect_do(); } while (!rc);
265  } else {
266  popup_till_condition(fs2netd_connect_do, XSTR("&Cancel", 779), XSTR("Connecting into FS2NetD", 1575));
267  }
268 
269  In_process = false;
270  Local_timeout = -1;
271 }
272 
274 {
275  if (Multi_tracker_id < 0) {
276  if ( Is_standalone && std_gen_is_active() ) {
277  std_gen_set_text("Verifying username and password", 1);
278  } else {
279  popup_change_text( XSTR("Verifying username and password", 1576) );
280  }
281 
283 
284  if (Local_timeout == -1) {
285  Local_timeout = timer_get_seconds() + 15;
286  }
287 
288  // if timeout passes then bail on SID failure
289  if ( timer_get_seconds() > Local_timeout ) {
290  ml_string("FS2NetD MSG: Login failure due to timeout!");
291  Local_timeout = -1;
292  return 2;
293  }
294 
295  const char *user = Multi_tracker_login;
296  const char *passwd = Multi_tracker_passwd;
297 
298  if (Is_standalone) {
299  if ( strlen(Multi_options_g.std_pxo_login) ) {
301  }
302 
303  if ( strlen(Multi_options_g.std_pxo_password) ) {
305  }
306  }
307 
308  Multi_tracker_id = FS2NetD_Login(user, passwd, do_full_packet);
309 
310  // if we have already been through once then only deal with the recieve packet next time
311  do_full_packet = false;
312 
313  // invalid login
314  if (Multi_tracker_id == -2) {
315  Multi_tracker_id = -1;
316  Local_timeout = -1;
317  return 1;
318  }
319 
320  if (Multi_tracker_id >= 0) {
321  ml_printf("FS2NetD MSG: Login '%s' is valid, session ID is %d!", user, Multi_tracker_id);
322  do_full_packet = true;
323  Local_timeout = -1;
324  }
325  } else {
326  if ( Is_standalone && std_gen_is_active() ) {
327  std_gen_set_text("Getting pilot stats", 1);
328  } else {
329  popup_change_text( XSTR("Getting pilot stats", 1577) );
330  }
331 
332  if (Local_timeout == -1) {
333  Local_timeout = timer_get_seconds() + 30;
334  }
335 
336  // if timeout passes then bail on stats failure
337  if ( timer_get_seconds() > Local_timeout ) {
338 
339  Local_timeout = -1;
340  return 2;
341  }
342 
343  if (do_full_packet) {
344  ml_printf("FS2NetD MSG: Requesting login pilot stats for '%s' ...", Players[Player_num].callsign);
345  }
346 
347  int rescode = FS2NetD_GetPlayerData(Players[Player_num].callsign, &Players[Player_num], true, do_full_packet);
348 
349  do_full_packet = false;
350 
351  if ( rescode != -1 ) {
352  Local_timeout = -1;
353  return (rescode + 3);
354  }
355  }
356 
357  return 0;
358 }
359 
361 {
362  bool retval = true;
363  int rc;
364 
365  // don't bother with this if we aren't on FS2NetD
366  if ( !Om_tracker_flag ) {
367  return false;
368  }
369 
370  if ( !(Game_mode & GM_MULTIPLAYER) ) {
371  return false;
372  }
373 
374  if ( Logged_in && (Multi_tracker_id >= 0) ) {
375  return true;
376  }
377 
378  Logged_in = false;
379 
380  Multi_tracker_id = -1;
381  memset( Multi_tracker_id_string, 0, sizeof(Multi_tracker_id_string) );
382 
383  // verify that our connection settings are sane
385 
386  // if we're a standalone, show a dialog saying "validating tables"
387  if (Is_standalone) {
388  std_create_gen_dialog("Logging into FS2NetD");
389  std_gen_set_text("Connecting...", 1);
390  }
391 
392  fs2netd_connect();
393 
394  if ( !Is_connected ) {
395  if ( !Is_standalone ) {
396  popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Failed to connect to FS2NetD server!", 1578));
397  } else {
398  std_gen_set_text("Connect FAILED!", 1);
399  Sleep(2000);
401  }
402 
403  return false;
404  }
405 
406  char error_str[256];
407  char std_error_str[64];
408 
409  do_full_packet = true;
410 
411  In_process = true;
412 
413  if (Is_standalone) {
414  do { rc = fs2netd_login_do(); } while (!rc);
415  } else {
416  rc = popup_till_condition(fs2netd_login_do, XSTR("&Cancel", 779), XSTR("Logging into FS2NetD", 1579));
417  }
418 
419  In_process = false;
420  Local_timeout = -1;
421 
422  memset( error_str, 0, sizeof(error_str) );
423  memset( std_error_str, 0, sizeof(std_error_str) );
424 
425  switch (rc) {
426  // the action was cancelled
427  case 0:
428  ml_string("FS2NetD MSG: Login process canceled by user.");
429  retval = false;
430  break;
431 
432  // didn't get a session id
433  case 1: {
434  const char *user = Multi_tracker_login;
435  const char *passwd = Multi_tracker_passwd;
436 
437  if (Is_standalone) {
438  if ( strlen(Multi_options_g.std_pxo_login) ) {
440  }
441 
442  if ( strlen(Multi_options_g.std_pxo_password) ) {
444  }
445  }
446 
447  ml_printf("FS2NetD ERROR: Login %s/%s is invalid!", user, passwd);
448 
449  if (strlen(user) == 0) {
450  strcpy_s(error_str, "Login failed! No username supplied. Go to options -> multi options and add one");
451  strcpy_s(std_error_str, "Login failed! No username!");
452  }
453  else if (strlen(passwd) == 0) {
454  strcpy_s(error_str, "Login failed! No password supplied. Go to options -> multi options and add one");
455  strcpy_s(std_error_str, "Login failed! No password!");
456  }
457  else {
458  strcpy_s(error_str, "Login failed!");
459  strcpy_s(std_error_str, "Login failed!");
460  }
461  retval = false;
462  break;
463  }
464 
465  // unknown failure fetching pilot data
466  case 2:
467  ml_string("FS2NetD ERROR: UNKNOWN ERROR when fetching pilot data");
468  strcpy_s(error_str, "An Unknown Error (probably a timeout) occured when trying to retrieve your pilot data.");
469  strcpy_s(std_error_str, "Unknown Error (timeout?)");
470  retval = false;
471  break;
472 
473  // success!!
474  case 3:
475  ml_string("FS2NetD MSG: Got Pilot data");
476  retval = true;
477  break;
478 
479  // success!! pilot was created
480  case 4:
481  ml_string("FS2NetD MSG: Created New Pilot");
482  strcpy_s(error_str, "New Pilot has been created.");
483  strcpy_s(std_error_str, "New Pilot has been created.");
484  retval = true;
485  break;
486 
487  // invalid pilot name
488  case 5:
489  ml_string("FS2NetD ERROR: Invalid Pilot!");
490  strcpy_s(error_str, "Invalid pilot name - A serious error has occured, Contact the FS2NetD Administrator!");
491  strcpy_s(std_error_str, "Invalid pilot name!");
492  retval = false;
493  break;
494 
495  // the session id was invalid
496  case 6:
497  ml_string("FS2NetD ERROR: Invalid SID!");
498  strcpy_s(error_str, "Invalid SID - A serious error has occured, Contact the FS2NetD Administrator!");
499  strcpy_s(std_error_str, "Invalid SID");
500  retval = false;
501  break;
502 
503  default:
504  ml_string("FS2NetD ERROR: Unknown return case for GetPlayerData()");
505  strcpy_s(error_str, "Unknown return case from GetPlayerData(). Contact the FS2NetD Administrator!");
506  retval = false;
507  break;
508  }
509 
510  if ( !Is_standalone && strlen(error_str) ) {
511  popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, error_str);
512  } else if ( Is_standalone && std_gen_is_active() && strlen(std_error_str) ) {
513  std_gen_set_text(std_error_str, 1);
514  Sleep(2000);
515  }
516 
517  if (retval) {
518  Logged_in = true;
520  } else {
521  // clear and reset connection, for the next time we try...
523  }
524 
525  if (Is_standalone) {
527  }
528 
529  return retval;
530 }
531 
532 static void fs2netd_handle_ping()
533 {
534  static int CONN_check = -1;
535 
536  // if we didn't get a pong within 30 seconds of a ping then assume that the
537  // server connection must of have dropped or is otherwise unresponsive
538  if ( (Ping_timestamp != -1) && ((timer_get_seconds() - Ping_timestamp) > 30) ) {
539  Ping_timestamp = -1;
540 
541  ml_string("FS2NetD WARNING: Lost connection to server!");
543 
544  // make sure that we are good to go
545  if ( !Is_connected ) {
546  if (!Is_standalone) {
548  popup(PF_USE_AFFIRMATIVE_ICON | PF_TITLE_BIG | PF_TITLE_RED, 1, POPUP_OK, "ERROR:\nLost connection to the FS2NetD server!");
549  }
550 
551  ml_string("FS2NetD ERROR: Lost connection to the FS2NetD server!");
552 
554 
555  ml_string("FS2NetD MSG: Will attempt an automatic reconnect to server in 5 minutes...");
556  Login_retry_time = timer_get_seconds() + 300;
557 
558  return;
559  } else {
560  ml_string("FS2NetD NOTICE: Connection to server has been reestablished!");
561  }
562  }
563 
564  // send out a ping after 5 minutes of no other activity to make sure the server
565  // is still responding (probably not though)
566  if ( (Ping_timestamp == -1) && (timer_get_seconds() >= (Last_activity + 300)) ) {
567  Ping_timestamp = timer_get_seconds();
568  FS2NetD_Ping();
569  ml_string("FS2NetD sent PING");
570 
571  if (Last_activity < 0) {
572  Last_activity = timer_get_seconds();
573  }
574  }
575 
576  // check for a valid connection (SID, duplicate login, etc.)
577  if ( (CONN_check == -1) || (timer_get_seconds() >= CONN_check) ) {
578  // every 3 minutes
579  CONN_check = timer_get_seconds() + 180;
580 
581  // session ID check
582  if ( FS2NetD_CheckValidID() < 0 ) {
583  ml_string("FS2NetD WARNING: Unable to validate login!");
585 
586  // make sure that we are good to go
587  if ( !Is_connected ) {
588  if (!Is_standalone) {
590  popup(PF_USE_AFFIRMATIVE_ICON | PF_TITLE_BIG | PF_TITLE_RED, 1, POPUP_OK, "ERROR:\nLost connection to the FS2NetD server!");
591  }
592 
593  ml_string("FS2NetD ERROR: Lost connection to the FS2NetD server!");
594 
596 
597  ml_string("FS2NetD MSG: Will attempt an automatic reconnect to server in 5 minutes...");
598  Login_retry_time = timer_get_seconds() + 300;
599 
600  return;
601  } else {
602  ml_string("FS2NetD NOTICE: Connection to server has been reestablished!");
603  }
604  }
605 
606  // verify that we are only logged in once (for stats saving purposes)
609  }
610 
611  ml_string("FS2NetD sent IDENT check");
612  }
613 }
614 
615 static void fs2netd_handle_messages()
616 {
617  int buffer_size = 0, buffer_offset = 0;
618  int bytes_read = 0;
619  char tbuf[256];
620  char buffer[8192];
621  ubyte pid = 0;
622  int itemp;
623 
624  while ( FS2NetD_DataReady() && (bytes_read < (int)sizeof(buffer)) ) {
625  int read_size = FS2NetD_GetData(buffer+bytes_read, sizeof(buffer)-bytes_read);
626 
627  if (read_size <= 0) {
628  break;
629  }
630 
631  bytes_read += read_size;
632 
633  Sleep(20);
634  }
635 
636  if ( (bytes_read == 0) || (bytes_read < BASE_PACKET_SIZE) ) {
637  return;
638  }
639 
640  Last_activity = timer_get_seconds();
641 
642  buffer_offset = 0;
643 
644  while (buffer_offset+BASE_PACKET_SIZE <= bytes_read) {
645  PXO_GET_DATA( pid );
646  PXO_GET_INT( buffer_size );
647 
648  // packet has more data than our buffer received
649  if (buffer_offset+buffer_size-BASE_PACKET_SIZE > bytes_read) {
650  break;
651  }
652 
653  // processing time!
654  switch (pid) {
655  case PCKT_PING: {
656  PXO_GET_INT( itemp );
657 
658  // ml_printf("FS2NetD received PING");
659 
660  FS2NetD_Pong(itemp);
661 
662  break;
663  }
664 
665  case PCKT_PONG: {
666  PXO_GET_INT( itemp );
667 
668  ml_printf("FS2NetD PONG: %d ms", timer_get_milliseconds() - itemp);
669 
670  // reset timestamp, since the ping was successful
671  Ping_timestamp = -1;
672 
673  break;
674  }
675 
676  case PCKT_NETOWRK_WALL: {
677  PXO_GET_STRING( tbuf );
678  ml_printf("FS2NetD WALL received MSG: %s", tbuf);
679 
680  switch (Netgame.game_state) {
685  multi_display_chat_msg(tbuf, 0, 0);
686  break;
687 
688  case NETGAME_STATE_IN_MISSION: // gotta make it paused
689  //multi_pause_request(1);
690  //send_game_chat_packet(Net_player, str, MULTI_MSG_ALL, NULL);
691  HUD_printf(tbuf);
692  break;
693 
694  default:
695  // do-nothing
696  break;
697  }
698 
699  break;
700  }
701 
703  PXO_GET_STRING( tbuf );
704  PXO_GET_INT( itemp );
705 
706  if ( (itemp < 0) || (itemp > USHRT_MAX) ) {
707  itemp = 0;
708  }
709 
710  multi_pxo_channel_count_update(tbuf, itemp);
711 
712  break;
713  }
714 
715  case PCKT_VALID_SID_REPLY: {
716  ubyte login_status = 0;
717 
718  PXO_GET_DATA( login_status );
719 
720  if (login_status != 1) {
721  ml_printf("FS2NetD IDENT: Got invalid login check!");
723  }
724 
725  break;
726  }
727 
728  case PCKT_DUP_LOGIN_REPLY: {
729  ubyte dupe_status = 0;
730 
731  PXO_GET_DATA( dupe_status );
732 
733  Duplicate_login_detected = (dupe_status != 0);
734 
735  break;
736  }
737 
738  case PCKT_SLIST_REPLY: {
739  int numServers = 0;
740  int svr_flags __UNUSED; // gcc [-Wunused-but-set-variable] doesn't like MACROs
741  ushort svr_port;
742  char svr_ip[16];
743  active_game ag;
744 
745  PXO_GET_USHORT( numServers );
746 
747  if (numServers == 0) {
748  break;
749  }
750 
751  for (int i = 0; i < numServers; i++) {
752  PXO_GET_INT( svr_flags );
753  PXO_GET_USHORT( svr_port );
754  PXO_GET_STRING( svr_ip );
755 
756  if ( !psnet_is_valid_ip_string(svr_ip) ) {
757  ml_printf("FS2NetD SLIST: Invalid ip string (%s)!", svr_ip);
758  } else {
759  memset( &ag, 0, sizeof(active_game) );
760 
761  ag.server_addr.type = NET_TCP;
762  ag.server_addr.port = (short) svr_port;
763 
764  if (ag.server_addr.port <= 0) {
766  }
767 
768  psnet_string_to_addr(&ag.server_addr, svr_ip);
769 
770  // query this server
772  }
773  }
774 
775  break;
776  }
777 
778  default: {
779  break;
780  }
781  }
782  }
783 }
784 
786 {
787  // in a previous processing loop, so don't do a frame until that has completed
788  if ( In_process ) {
789  return;
790  }
791 
792  if ( !Logged_in ) {
793  // maybe try and reconnect, if we were bumped due to a comm error ...
794  if ( (Login_retry_time != -1) && (timer_get_seconds() >= Login_retry_time) ) {
795  fs2netd_login();
796 
797  if ( !Logged_in ) {
798  // bah! try again in another 5 minutes
799  Login_retry_time = timer_get_seconds() + 300;
800  } else {
801  Login_retry_time = -1;
802  }
803  }
804 
805  return;
806  }
807 
808  // do ping/pong and ident
809  fs2netd_handle_ping();
810 
811  // handle gameserver updates
813 
814  // check for server messages, ping replies, etc.
815  fs2netd_handle_messages();
816 
817  // WTF?! (TODO: figure out how this happens)
818  if (Is_connected && !Logged_in) {
819  fs2netd_login();
820  }
821 }
822 
824 {
825  if ( !Logged_in ) {
826  return;
827  }
828 
829  // already been here
831  return;
832  }
833 
834  memset(&Multi_tracker_game_data, 0, sizeof(tracker_game_data));
835 
836  strcpy_s(Multi_tracker_game_data.name, Netgame.name);
837  strcpy_s(Multi_tracker_game_data.mission_name, Netgame.mission_name);
838  strcpy_s(Multi_tracker_game_data.title, Netgame.title);
839  strcpy_s(Multi_tracker_game_data.campaign_name, Netgame.campaign_name);
840 
841  if ( strlen(Multi_fs_tracker_channel) ) {
842  strcpy_s(Multi_tracker_game_data.chat_channel, Multi_fs_tracker_channel);
843  }
844 
845  Multi_tracker_game_data.campaign_mode = (ubyte)Netgame.campaign_mode;
846  Multi_tracker_game_data.flags = Netgame.flags;
847  Multi_tracker_game_data.type_flags = Netgame.type_flags;
848  Multi_tracker_game_data.players = (short)multi_num_players();
849  Multi_tracker_game_data.max_players = (short)Netgame.max_players;
850  Multi_tracker_game_data.mode = (ubyte)Netgame.mode;
851  Multi_tracker_game_data.rank_base = (ubyte)Netgame.rank_base;
852  Multi_tracker_game_data.game_state = (ubyte)Netgame.game_state;
853  Multi_tracker_game_data.speed = (ubyte)multi_get_connection_speed();
854 
856 
858 
859  // initial update should be about 2 seconds from now
860  Next_gameserver_update = timer_get_seconds() + 2;
861 
862  ml_string("FS2NetD sent game server start");
863 }
864 
866 {
867  if ( !Logged_in ) {
868  return;
869  }
870 
871  // server hasn't started yet?
873  return;
874  }
875 
876  // is it actually time for an update
877  if ( !force && (timer_get_seconds() < Next_gameserver_update) ) {
878  return;
879  }
880 
881  strcpy_s(Multi_tracker_game_data.mission_name, Netgame.mission_name);
882  strcpy_s(Multi_tracker_game_data.title, Netgame.title);
883  strcpy_s(Multi_tracker_game_data.campaign_name, Netgame.campaign_name);
884 
885  Multi_tracker_game_data.campaign_mode = (ubyte)Netgame.campaign_mode;
886  Multi_tracker_game_data.players = (short)multi_num_players();
887  Multi_tracker_game_data.game_state = (ubyte)Netgame.game_state;
888 
890 
891  // set timeout for every 2 minutes
892  Next_gameserver_update = timer_get_seconds() + 120;
893 
894  ml_string("FS2NetD sent game server update");
895 }
896 
898 {
899  if ( !Logged_in ) {
900  return;
901  }
902 
903  // server hasn't started yet?
905  return;
906  }
907 
909 
911 
912  ml_string("FS2NetD sent game server disconnect");
913 }
914 
916 {
917  if ( !Logged_in ) {
918  return;
919  }
920 
922 }
923 
924 static char Chk_mission_name[NAME_LENGTH+1];
925 static uint Chk_mission_crc = 0;
926 
928 {
929  if (Local_timeout == -1) {
930  Local_timeout = timer_get_seconds() + 15;
931  }
932 
933  // if timeout passes then bail on stats failure
934  if ( timer_get_seconds() > Local_timeout ) {
935  Local_timeout = -1;
936  return 4;
937  }
938 
939  int rescode = FS2NetD_CheckSingleMission(Chk_mission_name, Chk_mission_crc, do_full_packet);
940 
941  do_full_packet = false;
942 
943  if (rescode) {
944  Local_timeout = -1;
945  return rescode;
946  }
947 
948  return 0;
949 }
950 
951 bool fs2netd_check_mission(char *mission_name)
952 {
953  int rc = 0;
954  char popup_string[256];
955 
956  if ( !Logged_in ) {
957  return 0;
958  }
959 
960  strcpy_s(Chk_mission_name, mission_name);
961  cf_chksum_long(Chk_mission_name, &Chk_mission_crc);
962 
963  do_full_packet = true;
964 
965  In_process = true;
966 
967  memset(popup_string, 0, sizeof(popup_string));
968  sprintf(popup_string, XSTR("Validating mission %s", 1074), mission_name);
969 
970  if (Is_standalone) {
971  do { rc = fs2netd_check_mission_do(); } while (!rc);
972  } else {
973  rc = popup_till_condition(fs2netd_check_mission_do, XSTR("&Cancel", 779), popup_string);
974  }
975 
976  In_process = false;
977  Local_timeout = -1;
978 
979  switch (rc) {
980  // operation canceled, or invalid
981  case 0:
982  return false;
983 
984  // successful, but invalid
985  case 1:
986  return false;
987 
988  // successful and valid
989  case 2:
990  return true;
991 
992  // failed to send request packet
993  case 3:
994  if ( !Is_standalone ) {
995  popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Server request failed!",1580));
996  }
997 
998  return false;
999 
1000  // it timed out
1001  case 4:
1002  if ( !Is_standalone ) {
1003  popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Server request timed out!", 1581));
1004  }
1005 
1006  return false;
1007  }
1008 
1009  return false;
1010 }
1011 
1012 static int fs2netd_send_player_do()
1013 {
1014  if (Local_timeout == -1) {
1015  Local_timeout = timer_get_seconds() + 15;
1016  }
1017 
1018  // if timeout passes then bail on stats failure
1019  if ( timer_get_seconds() > Local_timeout ) {
1020  Local_timeout = -1;
1021  return 2;
1022  }
1023 
1024  int rescode = FS2NetD_SendPlayerData(Players[Player_num].callsign, &Players[Player_num], do_full_packet);
1025 
1026  do_full_packet = false;
1027 
1028  if (rescode != -1) {
1029  Local_timeout = -1;
1030  return rescode+3;
1031  }
1032 
1033  return 0;
1034 }
1035 
1036 static int fs2netd_send_player()
1037 {
1038  int rc;
1039 
1040  do_full_packet = true;
1041 
1042  In_process = true;
1043 
1044  if (Is_standalone) {
1045  do { rc = fs2netd_send_player_do(); } while (!rc);
1046  } else {
1047  rc = popup_till_condition(fs2netd_send_player_do, XSTR("&Cancel", 779), XSTR("Sending player stats requests ...", 676));
1048  }
1049 
1050  In_process = false;
1051  Local_timeout = -1;
1052 
1053  rc = rc - 3;
1054 
1055  if (rc < -1) {
1056  rc = -1;
1057  }
1058 
1059  return rc;
1060 }
1061 
1062 static void fs2netd_store_stats_results()
1063 {
1064  char str[512];
1065 
1066  memset(str, 0, sizeof(str));
1067 
1068  multi_display_chat_msg(XSTR("<PXO stats store process complete>", 1001), 0, 0);
1069  ml_string( XSTR("<PXO stats store process complete>", 1001) );
1070 
1072  sprintf(str, XSTR("<PXO stats store failed for player %s>", 1002), Net_player->m_player->callsign);
1073  multi_display_chat_msg(str, 0, 0);
1074  ml_string(str);
1075  }
1076 }
1077 
1079 {
1080  if ( !Logged_in ) {
1081  return;
1082  }
1083 
1084  ml_string("Sending stats to server");
1085 
1086  // default to not saving the stats
1088 
1089  if (Duplicate_login_detected) {
1090  Duplicate_login_detected = false;
1091  multi_display_chat_msg( XSTR("<Duplicate login detected - stats have been tossed>", 1582), 0, 0 );
1092  ml_string( XSTR("<Duplicate login detected - stats have been tossed>", 1583) );
1093  fs2netd_store_stats_results();
1094  return;
1095  }
1096 
1097  if ( game_hacked_data() ) {
1098  multi_display_chat_msg( XSTR("<Hacked tables detected - stats have been tossed>", 1584), 0, 0 );
1099  popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("You are playing with a hacked tables, your stats will not be saved", 1585) );
1100  fs2netd_store_stats_results();
1101  return;
1102  }
1103 
1104  if ( (multi_num_players() <= 1) && (Multi_num_players_at_start <= 1) ) {
1105  multi_display_chat_msg(XSTR("<Not enough players were present at game start or end, stats will not be saved>", 1048), 0, 0);
1106  ml_string( XSTR("<Not enough players were present at game start or end, stats will not be saved>", 1048) );
1107  fs2netd_store_stats_results();
1108  return;
1109  }
1110 
1111 /*
1112  // if any players have hacked info
1113  for(int idx = 0; idx < MAX_PLAYERS; idx++) {
1114  if ( MULTI_CONNECTED(Net_players[idx]) && !MULTI_STANDALONE(Net_players[idx]) && (Net_players[idx].flags & NETINFO_FLAG_HAXOR) ) {
1115  multi_display_chat_msg( XSTR("<Connected player has hacked info - tossing invalid stats>", -1), 0, 0 );
1116  return;
1117  }
1118  }
1119 */
1121  multi_display_chat_msg(XSTR("<Server detected a non PXO validated mission. Stats will not be saved>", 1049), 0, 0);
1122  popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("This is not a PXO validated mission, your stats will not be saved", 1050));
1123  fs2netd_store_stats_results();
1124  return;
1125  }
1126 
1127  int spd_ret = fs2netd_send_player();
1128 
1129  switch (spd_ret) { // 0 = pilot updated, 1 = invalid pilot, 2 = invalid (expired?) sid
1130  case -1:
1131  ml_string("<stats have been tossed - server error>");
1132  break;
1133 
1134  case 0:
1135  ml_string( XSTR("<stats have been accepted>", 850) );
1137  break;
1138 
1139  case 1:
1140  ml_string("<stats have been tossed - pilot error>");
1141  break;
1142 
1143  case 2:
1144  // we should never get here with the new code
1145  Int3();
1146  ml_string("<stats have been tossed - invalid tracker id>");
1147  break;
1148 
1149  default:
1150  multi_display_chat_msg( XSTR("Unknown Stats Store Request Reply", 1586), 0, 0 );
1151  break;
1152  }
1153 
1154  fs2netd_store_stats_results();
1155 }
1156 
1158 {
1159  if (Local_timeout == -1) {
1160  Local_timeout = timer_get_seconds() + 30;
1161  }
1162 
1163  // if timeout passes then bail on stats failure
1164  if ( timer_get_seconds() > Local_timeout ) {
1165  Local_timeout = -1;
1166  return 2;
1167  }
1168 
1169  int rc = FS2NetD_GetBanList(FS2NetD_ban_list, do_full_packet);
1170 
1171  do_full_packet = false;
1172 
1173  if (rc) {
1174  Local_timeout = -1;
1175  return 1;
1176  }
1177 
1178  return 0;
1179 }
1180 
1182 {
1183  int rc = 0;
1184 
1185  if ( !Logged_in ) {
1186  return;
1187  }
1188 
1189  // destroy the file prior to updating
1190  cf_delete( "banlist.cfg", CF_TYPE_DATA );
1191 
1192  do_full_packet = true;
1193 
1194  In_process = true;
1195 
1196  if (Is_standalone) {
1197  do { rc = fs2netd_update_ban_list_do(); } while (!rc);
1198  } else {
1199  rc = popup_till_condition(fs2netd_update_ban_list_do, XSTR("&Cancel", 779), XSTR("Requesting IP ban list", 1587));
1200  }
1201 
1202  In_process = false;
1203  Local_timeout = -1;
1204 
1205  if ( !FS2NetD_ban_list.empty() ) {
1206  CFILE *banlist_cfg = cfopen("banlist.cfg", "wt", CFILE_NORMAL, CF_TYPE_DATA);
1207 
1208  if (banlist_cfg != NULL) {
1209  for (SCP_vector<SCP_string>::iterator bl = FS2NetD_ban_list.begin(); bl != FS2NetD_ban_list.end(); ++bl) {
1210  cfputs( bl->c_str(), banlist_cfg );
1211  }
1212 
1213  cfclose(banlist_cfg);
1214  }
1215  }
1216 
1217  FS2NetD_ban_list.clear();
1218 }
1219 
1221 {
1222  if ( !Logged_in ) {
1223  return false;
1224  }
1225 
1226  char line[32]; // no line should be larger than 16, but let's be safe
1227  char ip_str[32];
1228  memset(ip_str, 0, 32);
1229  memset(line, 0, 32);
1230 
1231  bool retval = false;
1232  CFILE *banlist_cfg = cfopen("banlist.cfg", "rt", CFILE_NORMAL, CF_TYPE_DATA);
1233 
1234  if (banlist_cfg == NULL) {
1235  return false;
1236  }
1237 
1238  psnet_addr_to_string( ip_str, addr );
1239 
1240  while ( !cfeof(banlist_cfg) && !retval ) {
1241  cfgets(line, 32, banlist_cfg);
1242 
1243  if ( !strnicmp(ip_str, line, strlen(line)) ) {
1244  retval = true; // BANNINATED!!!
1245  }
1246  }
1247 
1248  cfclose(banlist_cfg);
1249 
1250  return retval;
1251 }
1252 
1254 {
1255  if (Local_timeout == -1) {
1256  Local_timeout = timer_get_seconds() + 30;
1257  }
1258 
1259  // get the available CRCs from the server if we need to
1260  if ( FS2NetD_file_list.empty() ) {
1261  int rc = FS2NetD_GetMissionsList(FS2NetD_file_list, do_full_packet);
1262 
1263  do_full_packet = false;
1264 
1265  // communications error
1266  if (rc < 0) {
1267  Local_timeout = -1;
1268  return 4;
1269  }
1270 
1271  // no missions
1272  if ( rc && FS2NetD_file_list.empty() ) {
1273  Local_timeout = -1;
1274  return 2;
1275  }
1276 
1277  // if timeout passes then bail on crc failure
1278  if ( timer_get_seconds() > Local_timeout ) {
1279  Local_timeout = -1;
1280  return 1;
1281  }
1282  }
1283  // we should have the CRCs, or there were no missions, so process them
1284  else {
1285  static char **file_names = NULL;
1286  static int idx = 0, count = 0;
1287 
1288  bool found = false;
1289  int file_index = 0;
1290  char valid_status = MVALID_STATUS_UNKNOWN;
1291  char full_name[MAX_FILENAME_LEN], wild_card[10];
1292  char val_text[MAX_FILENAME_LEN+15];
1293  uint checksum = 0;
1294 
1295  if (file_names == NULL) {
1296  // allocate filename space
1297  file_names = (char**) vm_malloc_q( sizeof(char*) * 1024 ); // 1024 files should be safe!
1298 
1299  if (file_names == NULL) {
1300  Local_timeout = -1;
1301  return 3;
1302  }
1303 
1304  memset( wild_card, 0, sizeof(wild_card) );
1305  strcpy_s( wild_card, NOX("*") );
1306  strcat_s( wild_card, FS_MISSION_FILE_EXT );
1307 
1308  idx = count = cf_get_file_list(1024, file_names, CF_TYPE_MISSIONS, wild_card);
1309  }
1310 
1311  // drop idx first thing
1312  idx--;
1313 
1314  // we should be done validating, or just not have nothing to validate
1315  if (idx < 0) {
1316  for (idx = 0; idx < count; idx++) {
1317  if (file_names[idx] != NULL) {
1318  vm_free(file_names[idx]);
1319  file_names[idx] = NULL;
1320  }
1321  }
1322 
1323  vm_free(file_names);
1324  file_names = NULL;
1325 
1326  idx = count = 0;
1327 
1328  Local_timeout = -1;
1329  return 4;
1330  }
1331 
1332 
1333  // verify all filenames that we know about with their CRCs
1334  // NOTE: that this is done for one file per frame, since this is inside of a popup
1335  memset( full_name, 0, MAX_FILENAME_LEN );
1336  strncpy( full_name, cf_add_ext(file_names[idx], FS_MISSION_FILE_EXT), sizeof(full_name) - 1 );
1337 
1338  memset( val_text, 0, sizeof(val_text) );
1339  snprintf( val_text, sizeof(val_text) - 1, "Validating: %s", full_name );
1340 
1341  if (Is_standalone) {
1342  if ( std_gen_is_active() ) {
1343  std_gen_set_text(val_text, 1);
1344  }
1345  } else {
1346  popup_change_text(val_text);
1347  }
1348 
1349  cf_chksum_long(full_name, &checksum);
1350 
1351  // try and find the file
1352  file_index = multi_create_lookup_mission(full_name);
1353 
1354  found = false;
1355 
1356  if (file_index >= 0) {
1357  for (SCP_vector<file_record>::iterator fr = FS2NetD_file_list.begin(); fr != FS2NetD_file_list.end() && !found; ++fr) {
1358  if ( !stricmp(full_name, fr->name) ) {
1359  if (fr->crc32 == checksum) {
1360  found = true;
1361  valid_status = MVALID_STATUS_VALID;
1362  } else {
1363  valid_status = MVALID_STATUS_INVALID;
1364  }
1365 
1366  Multi_create_mission_list[file_index].valid_status = valid_status;
1367  }
1368  }
1369 
1370  if (found) {
1371  ml_printf("FS2NetD Mission Validation: %s => Valid!", full_name);
1372  } else {
1373  ml_printf("FS2NetD Mission Validation: %s => INVALID! -- 0x%08x", full_name, checksum);
1374  }
1375  }
1376  }
1377 
1378  return 0;
1379 }
1380 
1382 {
1383  int rc = 0;
1384 
1385  if ( !Logged_in ) {
1386  return false;
1387  }
1388 
1389  FS2NetD_file_list.clear();
1390 
1391  do_full_packet = true;
1392 
1393  In_process = true;
1394 
1395  if (Is_standalone) {
1396  do { rc = fs2netd_get_valid_missions_do(); } while (!rc);
1397  } else {
1398  rc = popup_till_condition(fs2netd_get_valid_missions_do, XSTR("&Cancel", 779), XSTR("Starting mission validation", 1588));
1399  }
1400 
1401  In_process = false;
1402  Local_timeout = -1;
1403 
1404  FS2NetD_file_list.clear(); //-V586
1405 
1406  switch (rc) {
1407  // canceled by popup
1408  case 0:
1409  return false;
1410 
1411  // timed out
1412  case 1:
1413  if ( !Is_standalone ) {
1414  popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Mission validation timed out!", 1589));
1415  }
1416 
1417  return false;
1418 
1419  // no missions
1420  case 2:
1421  if ( !Is_standalone ) {
1422  popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("No missions are available from the server for validation!", 1590));
1423  }
1424 
1425  return false;
1426 
1427  // out of memory
1428  case 3:
1429  if ( !Is_standalone ) {
1430  popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Memory error during mission validation!", 1591));
1431  }
1432 
1433  return false;
1434  }
1435 
1436  return true;
1437 }
1438 
1440 {
1441  if (Local_timeout == -1) {
1442  Local_timeout = timer_get_seconds() + 30;
1443  }
1444 
1445  int rc = FS2NetD_ValidateTableList(do_full_packet);
1446 
1447  do_full_packet = false;
1448 
1449  // if timeout passes then bail on crc failure
1450  if ( timer_get_seconds() > Local_timeout ) {
1451  Local_timeout = -1;
1452  return 1;
1453  }
1454 
1455  if ( rc == 0 ) {
1456  return 0;
1457  }
1458 
1459  switch (rc) {
1460  // some error occured, assume that there are no valid table crcs
1461  case -1:
1462  Local_timeout = -1;
1463  return 2;
1464 
1465  // timeout
1466  case 1:
1467  Local_timeout = -1;
1468  return 1;
1469 
1470  // done!
1471  case 2:
1472  Local_timeout = -1;
1473  return 3;
1474  }
1475 
1476  return 0;
1477 }
1478 
1480 {
1481  int rc;
1482  int hacked = 0;
1483 
1484  if ( !Logged_in ) {
1485  return -1;
1486  }
1487 
1488  // if there are no tables to check with then bail
1489  if ( Table_valid_status.empty() ) {
1490  return -1;
1491  }
1492 
1493  // if we're a standalone, show a dialog saying "validating tables"
1495  std_create_gen_dialog("Validating tables");
1496  std_gen_set_text("Querying FS2NetD:", 1);
1497  }
1498 
1499  do_full_packet = true;
1500 
1501  In_process = true;
1502 
1503  if (Is_standalone) {
1504  do { rc = fs2netd_update_valid_tables_do(); } while (!rc);
1505  } else {
1506  rc = popup_till_condition(fs2netd_update_valid_tables_do, XSTR("&Cancel", 779), XSTR("Starting table validation", 1592));
1507  }
1508 
1509  In_process = false;
1510  Local_timeout = -1;
1511 
1512  switch (rc) {
1513  // canceled by popup
1514  case 0:
1515  return -1;
1516 
1517  // timed out
1518  case 1: {
1519  if ( !Is_standalone ) {
1520  popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("Table validation timed out!", 1593));
1521  }
1522 
1523  return -1;
1524  }
1525 
1526  // no tables
1527  case 2: {
1528  if ( !Is_standalone ) {
1529  popup(PF_USE_AFFIRMATIVE_ICON, 1, POPUP_OK, XSTR("No tables are available from the server for validation!", 1594));
1530  }
1531 
1532  return -1;
1533  }
1534  }
1535 
1536  // output the status of table validity to multi.log
1537  for (SCP_vector<crc_valid_status>::iterator tvs = Table_valid_status.begin(); tvs != Table_valid_status.end(); ++tvs) {
1538  if (tvs->valid) {
1539  ml_printf("FS2NetD Table Check: '%s' -- Valid!", tvs->name);
1540  } else {
1541  ml_printf("FS2NetD Table Check: '%s' -- INVALID (0x%x)!", tvs->name, tvs->crc32);
1542  hacked = 1;
1543  }
1544  }
1545 
1546  // if we're a standalone, kill the validate dialog
1547  if (Game_mode & GM_STANDALONE_SERVER) {
1549  }
1550 
1551  return hacked;
1552 }
1553 
1554 void fs2netd_add_table_validation(const char *tblname)
1555 {
1556  uint chksum = 0;
1557 
1558  // if the tbl name isn't valid then just assume that the tbl is too
1559  if ( (tblname == NULL) || !strlen(tblname) ) {
1560  return;
1561  }
1562 
1563  CFILE *tbl = cfopen(tblname, "rt", CFILE_NORMAL, CF_TYPE_TABLES);
1564 
1565  if (tbl == NULL) {
1566  return;
1567  }
1568 
1569  cf_chksum_long(tbl, &chksum);
1570 
1571  cfclose(tbl);
1572 
1573  crc_valid_status tbl_crc;
1574 
1575  strcpy_s(tbl_crc.name, tblname);
1576  tbl_crc.crc32 = chksum;
1577  tbl_crc.valid = 0;
1578 
1579  Table_valid_status.push_back( tbl_crc );
1580 }
1581 
1582 int fs2netd_get_pilot_info(const char *callsign, player *out_plr, bool first_call)
1583 {
1584  if ( !Logged_in ) {
1585  return -2;
1586  }
1587 
1588  if ( (out_plr == NULL) || (callsign == NULL) || !(strlen(callsign)) ) {
1589  return -2;
1590  }
1591 
1592  static player new_plr;
1593 
1594  if (first_call) {
1595  new_plr.reset();
1596  strncpy( new_plr.callsign, callsign, CALLSIGN_LEN );
1597 
1598  out_plr->reset();
1599 
1600  Local_timeout = timer_get_seconds() + 30;
1601 
1602  In_process = true;
1603 
1604  ml_printf("FS2NetD MSG: Requesting pilot stats for '%s' ...", callsign);
1605  }
1606 
1607  int rc = FS2NetD_GetPlayerData(callsign, &new_plr, false, first_call);
1608 
1609  // some sort of failure
1610  if (rc > 0) {
1611  In_process = false;
1612  Local_timeout = -1;
1613  return -2;
1614  }
1615 
1616  // if timeout passes then bail on failure
1617  if ( timer_get_seconds() > Local_timeout ) {
1618  In_process = false;
1619  Local_timeout = -1;
1620  return -2;
1621  }
1622 
1623  if (rc == 0) {
1624  out_plr->assign(&new_plr);
1625  In_process = false;
1626  Local_timeout = -1;
1627  }
1628 
1629  // we should only be returning -1 (processing) or 0 (got data successfully)
1630  return rc;
1631 }
1632 
1634 {
1635  // make sure that a hosted games is de-listed
1637 
1639 
1640  fs2netd_reset_state();
1641  PXO_options_loaded = false;
1642 
1643  Table_valid_status.clear();
1644 
1645  FS2NetD_file_list.clear();
1646  FS2NetD_ban_list.clear();
1647 }
1648 
1649 void fs2netd_update_game_count(const char *chan_name)
1650 {
1651  if ( !Logged_in ) {
1652  return;
1653  }
1654 
1655  if ( (chan_name == NULL) || !strlen(chan_name) ) {
1656  return;
1657  }
1658 
1659  FS2NetD_GameCountUpdate(chan_name);
1660 }
1661 
1662 void fs2netd_spew_table_checksums(char *outfile)
1663 {
1664  char full_name[MAX_PATH_LEN];
1665  FILE *out = NULL;
1666  char description[512] = { 0 };
1667  char filename[65] = { 0 };
1668  size_t offset = 0;
1669  char *p = NULL;
1670 
1671  if ( Table_valid_status.empty() ) {
1672  return;
1673  }
1674 
1675  cf_create_default_path_string(full_name, sizeof(full_name) - 1, CF_TYPE_ROOT, outfile);
1676 
1677  // open the outfile
1678  out = fopen(full_name, "wt");
1679 
1680  if (out == NULL) {
1681  return;
1682  }
1683 
1685 
1686  while (*p && (offset < sizeof(description))) {
1687  if (*p == '"' && offset < sizeof(description)-1) {
1688  description[offset++] = '"';
1689  description[offset++] = '"';
1690  } else {
1691  description[offset++] = *p;
1692  }
1693 
1694  p++;
1695  }
1696 
1697  // header
1698  fprintf(out, "filename,CRC32,description\r\n");
1699 
1700  // do all the checksums
1701  for (SCP_vector<crc_valid_status>::iterator tvs = Table_valid_status.begin(); tvs != Table_valid_status.end(); ++tvs) {
1702  offset = 0;
1703  p = tvs->name;
1704 
1705  while (*p && (offset < sizeof(filename))) {
1706  if (*p == '"' && offset < sizeof(filename)-1) {
1707  filename[offset++] = '"';
1708  filename[offset++] = '"';
1709  } else {
1710  filename[offset++] = *p;
1711  }
1712 
1713  p++;
1714  }
1715 
1716  if (offset < sizeof(filename)) {
1717  filename[offset] = '\0';
1718  } else {
1719  filename[sizeof(filename)-1] = '\0';
1720  }
1721 
1722  fprintf(out, "\"%s\",%u,\"%s\"\r\n", filename, tvs->crc32, description);
1723  }
1724 
1725  fflush(out);
1726  fclose(out);
1727 }
int fs2netd_update_valid_tables()
#define __UNUSED
Definition: clang.h:23
GLenum GLsizei GLenum format
Definition: Gl.h:1509
GLuint64EXT * result
Definition: Glext.h:10775
void FS2NetD_Pong(int tstamp)
Definition: tcp_client.cpp:652
int FS2NetD_port
Definition: mod_table.cpp:32
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
char pxo_banner_url[MULTI_OPTIONS_STRING_LEN]
Definition: multi_options.h:45
int std_gen_is_active()
#define vm_malloc_q(size)
Definition: pstypes.h:554
#define FS_MISSION_FILE_EXT
Definition: missionparse.h:25
#define CFILE_NORMAL
Definition: cfile.h:89
#define NET_TCP
Definition: psnet2.h:29
#define NETGAME_STATE_DEBRIEF
Definition: multi.h:669
int i
Definition: multi_pxo.cpp:466
#define vm_free(ptr)
Definition: pstypes.h:548
void fs2netd_gameserver_start()
char Multi_fs_tracker_channel[MAX_PATH]
void send_server_query(net_addr *addr)
Definition: multimsgs.cpp:2266
int cf_delete(const char *filename, int path_type)
Delete the specified file.
Definition: cfile.cpp:483
int FS2NetD_CheckSingleMission(const char *m_name, uint crc32, bool do_send)
Definition: tcp_client.cpp:36
#define PXO_GET_STRING(s)
Definition: tcp_client.h:71
int Game_mode
Definition: systemvars.cpp:24
#define NETINFO_FLAG_MT_CONNECTED
Definition: multi.h:600
net_addr server_addr
Definition: multi.h:552
int fs2netd_check_mission_do()
void fs2netd_add_table_validation(const char *tblname)
int FS2NetD_GetBanList(SCP_vector< SCP_string > &mask_list, bool do_send)
Definition: tcp_client.cpp:317
char tracker_port[STD_NAME_LEN]
Definition: multi_options.h:39
void fs2netd_close()
net_player * Net_player
Definition: multi.cpp:94
#define PCKT_VALID_SID_REPLY
Definition: protocol.h:49
void FS2NetD_Disconnect()
Definition: tcp_socket.cpp:50
#define MAX_PATH
player * m_player
Definition: multi.h:459
void fs2netd_connect()
int mode
Definition: multi.h:494
#define PCKT_PING
Definition: protocol.h:40
#define NETGAME_STATE_BRIEFING
Definition: multi.h:665
#define MVALID_STATUS_INVALID
Definition: multi.h:114
int FS2NetD_ConnectToServer(const char *host, const char *port)
Definition: tcp_socket.cpp:62
void std_destroy_gen_dialog()
Assert(pm!=NULL)
general failure sound for any event
Definition: gamesnd.h:297
bool FS2NetD_DataReady()
Definition: tcp_socket.cpp:245
void ml_string(const char *string, int add_time)
Definition: multi_log.cpp:131
Definition: cfile.h:28
#define FS2NETD_DEFAULT_BANNER_URL
#define PCKT_DUP_LOGIN_REPLY
Definition: protocol.h:56
int multi_get_connection_speed()
Definition: multiutil.cpp:2999
#define Assertion(expr, msg,...)
Definition: clang.h:41
#define PCKT_CHAT_CHAN_COUNT_REPLY
Definition: protocol.h:52
int FS2NetD_CheckValidID()
Definition: tcp_client.cpp:666
void fs2netd_gameserver_disconnect()
int fs2netd_get_pilot_info(const char *callsign, player *out_plr, bool first_call)
char title[NAME_LENGTH+1]
char chat_channel[MAX_PATH+1]
int flags
Definition: multi.h:463
void reset()
int cf_create_default_path_string(char *path, uint path_max, int pathtype, const char *filename, bool localize)
#define Int3()
Definition: pstypes.h:292
void FS2NetD_GameCountUpdate(const char *chan_name)
Definition: tcp_client.cpp:777
void FS2NetD_SendServerDisconnect()
Definition: tcp_client.cpp:599
int fs2netd_login_do()
int FS2NetD_GetPlayerData(const char *player_name, player *pl, bool can_create, bool do_send)
Definition: tcp_client.cpp:195
int Multi_debrief_stats_accept_code
Definition: multiui.cpp:8615
char std_pxo_password[MULTI_OPTIONS_STRING_LEN]
Definition: multi_options.h:54
char callsign[CALLSIGN_LEN+1]
Definition: player.h:91
void fs2netd_disconnect()
int game_state
Definition: multi.h:498
void assign(const player *pl)
#define PXO_GET_DATA(d)
Definition: tcp_client.h:66
void fs2netd_update_game_count(const char *chan_name)
player Players[MAX_PLAYERS]
#define CF_TYPE_ROOT
Definition: cfile.h:45
int timer_get_seconds()
Definition: timer.cpp:140
int multi_num_players()
Definition: multiutil.cpp:1799
void multi_display_chat_msg(const char *msg, int player_index, int add_id)
Definition: multiutil.cpp:2895
#define PCKT_SLIST_REPLY
Definition: protocol.h:28
GLintptr offset
Definition: Glext.h:5497
Definition: player.h:85
bool fs2netd_login()
int type_flags
Definition: multi.h:493
int fs2netd_get_valid_missions_do()
char Multi_tracker_passwd[MULTI_TRACKER_STRING_LEN+1]
Definition: multi.cpp:144
char campaign_name[NAME_LENGTH+1]
int multi_create_lookup_mission(char *fname)
Definition: multiui.cpp:5385
int FS2NetD_GetData(char *buffer, int blen)
Definition: tcp_socket.cpp:224
unsigned int uint
Definition: pstypes.h:64
void ml_printf(const char *format,...)
Definition: multi_log.cpp:112
#define cfopen(...)
Definition: cfile.h:134
int psnet_is_valid_ip_string(char *ip_string, int allow_port)
Definition: psnet2.cpp:938
#define FS2NETD_DEFAULT_CHAT_SERVER
#define GM_MULTIPLAYER
Definition: systemvars.h:18
char name[MAX_GAMENAME_LEN+1]
Definition: multi.h:487
char * cfgets(char *buf, int n, CFILE *cfile)
Definition: cfile.cpp:1571
void fs2netd_reset_connection()
#define DEFAULT_GAME_PORT
Definition: psnet2.h:36
char * filename
#define strnicmp(s1, s2, n)
Definition: config.h:272
netgame_info Netgame
Definition: multi.cpp:97
char mission_name[MAX_GAMENAME_LEN+1]
char game_tracker_ip[MULTI_OPTIONS_STRING_LEN]
Definition: multi_options.h:38
#define CF_TYPE_TABLES
Definition: cfile.h:50
sprintf(buf,"(%f,%f,%f)", v3->xyz.x, v3->xyz.y, v3->xyz.z)
void std_gen_set_text(char *str, int field_num)
int Multi_num_players_at_start
Definition: multi.cpp:114
void FS2NetD_CheckDuplicateLogin()
Definition: tcp_client.cpp:791
#define BASE_PACKET_SIZE
Definition: tcp_client.h:57
int game_hacked_data()
Definition: fredstubs.cpp:208
GLuint buffer
Definition: Glext.h:5492
char Multi_tracker_id_string[255]
Definition: multi.cpp:147
#define NETGAME_STATE_MISSION_SYNC
Definition: multi.h:670
#define FS2NETD_DEFAULT_SERVER
void fs2netd_store_stats()
char mission_name[NAME_LENGTH+1]
Definition: multi.h:488
bool fs2netd_player_banned(net_addr *addr)
void fs2netd_options_config_init()
void FS2NetD_SendServerStart()
Definition: tcp_client.cpp:533
int idx
Definition: multiui.cpp:761
SCP_vector< crc_valid_status > Table_valid_status
#define MULTI_OPTIONS_STRING_LEN
Definition: multi_options.h:29
char campaign_name[NAME_LENGTH+1]
Definition: multi.h:490
unsigned char ubyte
Definition: pstypes.h:62
char title[NAME_LENGTH+1]
Definition: multi.h:489
const char * XSTR(const char *str, int index)
Definition: localize.cpp:851
int rank_base
Definition: multi.h:496
int Multi_tracker_id
Definition: multi.cpp:146
int cfeof(CFILE *cfile)
#define NOX(s)
Definition: pstypes.h:473
#define GM_STANDALONE_SERVER
Definition: systemvars.h:27
int cf_chksum_long(const char *filename, uint *chksum, int max_size, int cf_type)
Definition: cfile.cpp:1841
#define MVALID_STATUS_VALID
Definition: multi.h:113
#define NETGAME_STATE_IN_MISSION
Definition: multi.h:666
#define STD_NAME_LEN
Definition: multi_options.h:28
#define MAX_PATH_LEN
Definition: pstypes.h:325
char * cf_add_ext(const char *filename, const char *ext)
Definition: cfile.cpp:458
#define CF_TYPE_DATA
Definition: cfile.h:46
SCP_vector< multi_create_info > Multi_create_mission_list
Definition: multiui.cpp:3326
void multi_pxo_channel_count_update(char *name, int count)
Definition: multi_pxo.cpp:2170
#define CALLSIGN_LEN
Definition: globals.h:31
int campaign_mode
Definition: multi.h:509
int cfputs(const char *str, CFILE *cfile)
Definition: cfile.cpp:1504
#define strcat_s(...)
Definition: safe_strings.h:68
#define NAME_LENGTH
Definition: globals.h:15
uint type
Definition: psnet2.h:39
bool fs2netd_is_online()
bool fs2netd_get_valid_missions()
unsigned short ushort
Definition: pstypes.h:63
char name[MAX_GAMENAME_LEN+1]
char user_tracker_ip[MULTI_OPTIONS_STRING_LEN]
Definition: multi_options.h:37
char Multi_fs_tracker_filter[MAX_PATH]
#define CF_TYPE_MISSIONS
Definition: cfile.h:74
void FS2NetD_Ping()
Definition: tcp_client.cpp:637
GLfloat GLfloat p
Definition: Glext.h:8373
void Sleep(int mili)
void FS2NetD_RequestServerList()
Definition: tcp_client.cpp:611
void fs2netd_send_game_request()
int fs2netd_update_valid_tables_do()
int FS2NetD_GetMissionsList(SCP_vector< file_record > &m_list, bool do_send)
Definition: tcp_client.cpp:392
char * Cmdline_spew_table_crcs
Definition: cmdline.cpp:411
void FS2NetD_SendServerUpdate()
Definition: tcp_client.cpp:574
int FS2NetD_SendPlayerData(const char *player_name, player *pl, bool do_send)
Definition: tcp_client.cpp:94
#define MVALID_STATUS_UNKNOWN
Definition: multi.h:112
void std_create_gen_dialog(char *title)
GLint GLsizei count
Definition: Gl.h:1491
int fs2netd_update_ban_list_do()
void fs2netd_gameserver_update(bool force)
char pxo_ip[MULTI_OPTIONS_STRING_LEN]
Definition: multi_options.h:41
void HUD_printf(const char *format,...)
Definition: hudmessage.cpp:527
#define PCKT_PONG
Definition: protocol.h:41
bool fs2netd_check_mission(char *mission_name)
#define FS2NETD_DEFAULT_PORT
void psnet_string_to_addr(net_addr *address, char *text)
Definition: psnet2.cpp:732
tracker_game_data Multi_tracker_game_data
#define PXO_GET_USHORT(d)
Definition: tcp_client.h:68
void fs2netd_spew_table_checksums(char *outfile)
#define PCKT_NETOWRK_WALL
Definition: protocol.h:47
#define PXO_GET_INT(d)
Definition: tcp_client.h:69
void gamesnd_play_iface(int n)
Definition: gamesnd.cpp:260
char * psnet_addr_to_string(char *text, net_addr *address)
Definition: psnet2.cpp:705
int Om_tracker_flag
int cfclose(CFILE *cfile)
Definition: cfile.cpp:895
char std_pxo_login[MULTI_OPTIONS_STRING_LEN]
Definition: multi_options.h:53
GLenum const GLvoid * addr
Definition: Glext.h:9092
#define NETGAME_STATE_FORMING
Definition: multi.h:664
int FS2NetD_ValidateTableList(bool do_send)
Definition: tcp_client.cpp:685
int cf_get_file_list(SCP_vector< SCP_string > &list, int pathtype, const char *filter, int sort=CF_SORT_NONE, SCP_vector< file_list_info > *info=NULL)
char name[NAME_LENGTH]
Definition: protocol.h:71
short port
Definition: psnet2.h:42
int max_players
Definition: multi.h:497
int timer_get_milliseconds()
Definition: timer.cpp:150
#define stricmp(s1, s2)
Definition: config.h:271
char Multi_tracker_login[MULTI_TRACKER_STRING_LEN+1]
Definition: multi.cpp:143
multi_global_options Multi_options_g
int flags
Definition: multi.h:495
void fs2netd_do_frame()
int FS2NetD_Login(const char *username, const char *password, bool do_send)
Definition: tcp_client.cpp:470
int Player_num
#define strcpy_s(...)
Definition: safe_strings.h:67
int Is_standalone
Definition: systemvars.cpp:59
void fs2netd_update_ban_list()