fgms 0.11.8
The
FlightGear MultiPlayer Server
project
fg_server.cxx
Go to the documentation of this file.
1 /**
2  * @file fg_server.cxx
3  */
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U$
18 //
19 
20 #define FGMS_USE_THREADS
21 
22 //////////////////////////////////////////////////////////////////////
23 //
24 // Server for FlightGear
25 // (c) 2005-2012 Oliver Schroeder
26 // and contributors (see AUTHORS)
27 //
28 //////////////////////////////////////////////////////////////////////
29 #ifdef HAVE_CONFIG_H
30  #include "config.h"
31 #endif
32 
33 #include <sys/types.h>
34 #include <unistd.h>
35 #include <time.h>
36 #include <string.h>
37 #ifndef _MSC_VER
38  #ifndef __FreeBSD__
39  #include <endian.h>
40  #endif
41  #include <sys/ipc.h>
42  #include <sys/msg.h>
43  #include <netinet/in.h>
44 #endif
45 #include <string>
46 
47 #include "fg_cli.hxx"
48 #include "fg_server.hxx" /* includes pthread.h */
49 #include "fg_common.hxx"
50 #include "fg_util.hxx"
51 
52 #ifdef _MSC_VER
53  #include <conio.h> // for _kbhit(), _getch
54  typedef int pid_t;
55 #else
57 #endif
58 
59 bool RunAsDaemon = false;
60 bool AddCLI = true;
61 
62 #ifndef DEF_SERVER_LOG
63  #define DEF_SERVER_LOG "fg_server.log"
64 #endif
65 
66 #ifndef DEF_UPDATE_SECS
67  #define DEF_UPDATE_SECS 10
68 #endif
69 
70 extern void SigHUPHandler ( int SigType );
71 #ifndef DEF_EXIT_FILE
72  #define DEF_EXIT_FILE "fgms_exit"
73 #endif
74 #ifndef DEF_RESET_FILE
75  #define DEF_RESET_FILE "fgms_reset"
76 #endif
77 #ifndef DEF_STAT_FILE
78  #define DEF_STAT_FILE "fgms_stat"
79 #endif
80 
81 #ifdef ADD_TRACKER_LOG
82  #ifndef DEF_MESSAGE_LOG
83  #define DEF_MESSAGE_LOG "fg_message.log"
84  #endif
85  static char* msg_log = ( char* ) DEF_MESSAGE_LOG;
86  static FILE* msg_file = NULL;
87 #endif // #ifdef ADD_TRACKER_LOG
88 
89 #if _MSC_VER
90  static char* exit_file = ( char* ) DEF_EXIT_FILE; // "fgms_exit"
91  static char* reset_file = ( char* ) DEF_RESET_FILE; // "fgms_reset"
92  static char* stat_file = ( char* ) DEF_STAT_FILE; // "fgms_stat"
93 #else // !_MSC_VER
94  static char* exit_file = ( char* ) "/tmp/" DEF_EXIT_FILE;
95  static char* reset_file = ( char* ) "/tmp/" DEF_RESET_FILE;
96  static char* stat_file = ( char* ) "/tmp/" DEF_STAT_FILE;
97 #endif // _MSC_VER y/n
98 
99 #ifdef ADD_TRACKER_LOG
100 
101 // FIXME: use SG_LOG !
102 
103 static void write_time_string ( FILE* file )
104 {
105  time_t Timestamp = time ( 0 );
106  char TimeStr[100];
107  tm* tm;
108  // Creates the UTC time string
109  tm = gmtime ( & Timestamp );
110  int len = sprintf (
111  TimeStr,
112  "%04d-%02d-%02d %02d:%02d:%02d: ",
113  tm->tm_year+1900,
114  tm->tm_mon+1,
115  tm->tm_mday,
116  tm->tm_hour,
117  tm->tm_min,
118  tm->tm_sec );
119  fwrite ( TimeStr,1,len,file );
120 }
121 
122 void write_msg_log ( const char* msg, int len, char* src )
123 {
124  if ( msg_file == NULL )
125  {
126  msg_file = fopen ( msg_log, "ab" );
127  if ( !msg_file )
128  {
129  printf ( "ERROR: Failed to OPEN/append %s log file!\n", msg_log );
130  msg_file = ( FILE* )-1;
131  }
132  }
133  if ( len && msg_file && ( msg_file != ( FILE* )-1 ) )
134  {
135  write_time_string ( msg_file );
136  if ( src && strlen ( src ) )
137  {
138  fwrite ( src,1,strlen ( src ),msg_file );
139  }
140  int wtn = ( int ) fwrite ( msg,1,len,msg_file );
141  if ( wtn != len )
142  {
143  fclose ( msg_file );
144  msg_file = ( FILE* )-1;
145  printf ( "ERROR: Failed to WRITE %d != %d to %s log file!\n", wtn, len, msg_log );
146  }
147  else
148  {
149  if ( msg[len-1] != '\n' )
150  {
151  fwrite ( ( char* ) "\n",1,1,msg_file );
152  }
153  fflush ( msg_file ); // push to disk now
154  }
155  }
156 }
157 #endif // #ifdef ADD_TRACKER_LOG
158 
159 //////////////////////////////////////////////////////////////////////
160 /**
161  * @class FG_SERVER
162  */
163 /** @brief Constructor */
165 () : m_CrossfeedList("Crossfeed"),
166  m_BlackList("Blacklist"),
167  m_RelayList("Relays"),
168  m_PlayerList("Users")
169 {
170  typedef union
171  {
172  uint32_t complete;
173  int16_t High;
174  int16_t Low;
175  } converter;
176  converter* tmp;
177  m_Initialized = false;// Init() will do it
178  m_ReinitData = true; // init the data port
179  m_ReinitTelnet = true; // init the telnet port
180  m_ReinitAdmin = true; // init the telnet port
181  m_ListenPort = 5000; // port for client connections
182  m_PlayerExpires = 10; // standard expiration period
183  m_Listening = false;
184  m_DataSocket = 0;
185  m_TelnetPort = m_ListenPort+1;
186  m_AdminPort = m_ListenPort+2;
187  m_NumMaxClients = 0;
188  m_PlayerIsOutOfReach = 100; // standard 100 nm
189  m_IsParent = false;
190  m_ServerName = "* Server *";
191  m_BindAddress = "";
192  tmp = ( converter* ) ( & PROTO_VER );
193  m_ProtoMinorVersion = tmp->High;
194  m_ProtoMajorVersion = tmp->Low;
195  m_LogFileName = DEF_SERVER_LOG; // "fg_server.log";
196  m_RelayMap = map<uint32_t, string>();
197  m_IsTracked = false; // off until config file read
198  m_Tracker = 0; // no tracker yet
199  m_UpdateTrackerFreq = DEF_UPDATE_SECS;
200  // clear stats - should show what type of packet was received
201  m_PacketsReceived = 0;
202  m_TelnetReceived = 0;
203  m_AdminReceived = 0;
204  m_BlackRejected = 0; // in black list
205  m_PacketsInvalid = 0; // invalid packet
206  m_UnknownRelay = 0; // unknown relay
207  m_RelayMagic = 0; // relay magic packet
208  m_PositionData = 0; // position data packet
209  m_NotPosData = 0;
210  // clear totals
211  mT_PacketsReceived = 0;
212  mT_BlackRejected = 0;
213  mT_PacketsInvalid = 0;
214  mT_UnknownRelay = 0;
215  mT_PositionData = 0;
216  mT_TelnetReceived = 0;
217  mT_RelayMagic = 0;
218  mT_NotPosData = 0;
219  m_CrossFeedFailed = 0;
220  m_CrossFeedSent = 0;
221  mT_CrossFeedFailed = 0;
222  mT_CrossFeedSent = 0;
223  m_TrackerConnect = 0;
224  m_TrackerDisconnect = 0;
225  m_TrackerPosition = 0; // Tracker messages queued
226  m_LocalClients = 0;
227  m_RemoteClients = 0;
228  m_Uptime = time(0);
229  m_WantExit = false;
230  ConfigFile = "";
231  SetLog (SG_FGMS|SG_FGTRACKER, SG_INFO);
232  // SetLog (SG_ALL, SG_DISABLED);
233 } // FG_SERVER::FG_SERVER()
234 
235 //////////////////////////////////////////////////////////////////////
236 /**
237  * @brief Standard destructor
238  */
240 ()
241 {
242  Done();
243 } // FG_SERVER::~FG_SERVER()
244 
245 static void*
247 (
248  void* context
249 )
250 {
251  pthread_detach ( pthread_self() );
252  st_telnet* t = reinterpret_cast<st_telnet*> ( context );
253  FG_SERVER* tmp_server = t->Instance;
254  tmp_server->HandleTelnet ( t->Fd );
255  delete t;
256  return 0;
257 }
258 
259 void*
261 (
262  void* context
263 )
264 {
265  st_telnet* t = reinterpret_cast<st_telnet*> ( context );
266  FG_SERVER* tmp_server = t->Instance;
267  pthread_detach ( pthread_self() );
268  tmp_server->HandleAdmin ( t->Fd );
269  delete t;
270  return 0;
271 }
272 
273 void* detach_tracker ( void* vp )
274 {
275  FG_TRACKER* pt = reinterpret_cast<FG_TRACKER*> (vp);
276  pt->Loop();
277  delete pt;
278  return ( ( void* ) 0xdead );
279 }
280 
281 //////////////////////////////////////////////////////////////////////
282 /**
283  * @brief Basic initialization
284  *
285  * If we are already initialized, close
286  * all connections and re-init all variables
287  */
288 int
290 ()
291 {
292  //////////////////////////////////////////////////
293  // if we are already initialized, close
294  // all connections and re-init all
295  // variables
296  //////////////////////////////////////////////////
297  if ( !m_LogFile.is_open() )
298  {
299  m_LogFile.open ( m_LogFileName.c_str(), ios::out|ios::app );
301  sglog().enable_with_date ( true );
302  if (m_LogFile.is_open())
303  {
304  sglog().set_output ( m_LogFile );
305  }
306  else
307  {
308  SG_CONSOLE ( SG_FGMS, SG_ALERT, "FG_SERVER::Init() - "
309  << "Failed to open log file "
310  << m_LogFileName );
311  }
312  }
313  if ( m_Initialized == false )
314  {
315  if ( m_Listening )
316  {
317  Done();
318  }
319  m_Initialized = true;
320  m_Listening = false;
321  m_DataSocket = 0;
322  m_NumMaxClients = 0;
323  netInit (); // WinSocket initialisation
324  }
325  if ( m_ReinitData )
326  {
327  if ( m_DataSocket )
328  {
329  delete m_DataSocket;
330  m_DataSocket = 0;
331  }
332  m_DataSocket = new netSocket();
333  if ( m_DataSocket->open ( false ) == 0 ) // UDP-Socket
334  {
335  SG_CONSOLE ( SG_FGMS, SG_ALERT, "FG_SERVER::Init() - "
336  << "failed to create listener socket" );
337  return ( ERROR_CREATE_SOCKET );
338  }
339  m_DataSocket->setBlocking ( false );
340  m_DataSocket->setSockOpt ( SO_REUSEADDR, true );
341  if ( m_DataSocket->bind ( m_BindAddress.c_str(), m_ListenPort ) != 0 )
342  {
343  SG_CONSOLE ( SG_FGMS, SG_ALERT, "FG_SERVER::Init() - "
344  << "failed to bind to port " << m_ListenPort );
345  SG_CONSOLE ( SG_FGMS, SG_ALERT, "already in use?" );
346  return ( ERROR_COULDNT_BIND );
347  }
348  m_ReinitData = false;
349  }
350  if ( m_ReinitTelnet )
351  {
352  if ( m_TelnetSocket )
353  {
354  delete m_TelnetSocket;
355  m_TelnetSocket = 0;
356  }
357  m_TelnetSocket = 0;
358  if ( m_TelnetPort != 0 )
359  {
360  m_TelnetSocket = new netSocket;
361  if ( m_TelnetSocket->open ( true ) == 0 ) // TCP-Socket
362  {
363  SG_CONSOLE ( SG_FGMS, SG_ALERT, "FG_SERVER::Init() - "
364  << "failed to create telnet socket" );
365  return ( ERROR_CREATE_SOCKET );
366  }
367  m_TelnetSocket->setBlocking ( false );
368  m_TelnetSocket->setSockOpt ( SO_REUSEADDR, true );
369  if ( m_TelnetSocket->bind ( m_BindAddress.c_str(), m_TelnetPort ) != 0 )
370  {
371  SG_CONSOLE ( SG_FGMS, SG_ALERT, "FG_SERVER::Init() - "
372  << "failed to bind telnet socket " << m_TelnetPort );
373  SG_CONSOLE ( SG_FGMS, SG_ALERT, "already in use?" );
374  return ( ERROR_COULDNT_BIND );
375  }
376  if ( m_TelnetSocket->listen ( MAX_TELNETS ) != 0 )
377  {
378  SG_CONSOLE ( SG_FGMS, SG_ALERT, "FG_SERVER::Init() - "
379  << "failed to listen to telnet port" );
380  return ( ERROR_COULDNT_LISTEN );
381  }
382  }
383  m_ReinitTelnet = false;
384  }
385  if ( m_ReinitAdmin )
386  {
387  if ( m_AdminSocket )
388  {
389  delete m_AdminSocket;
390  }
391  m_AdminSocket = 0;
392  if ( m_AdminPort != 0 )
393  {
394  m_AdminSocket = new netSocket;
395  if ( m_AdminSocket->open ( true ) == 0 ) // TCP-Socket
396  {
397  SG_CONSOLE ( SG_FGMS, SG_ALERT, "FG_SERVER::Init() - "
398  << "failed to create admin socket" );
399  return ( ERROR_CREATE_SOCKET );
400  }
401  m_AdminSocket->setBlocking ( false );
402  m_AdminSocket->setSockOpt ( SO_REUSEADDR, true );
403  if ( m_AdminSocket->bind ( m_BindAddress.c_str(), m_AdminPort ) != 0 )
404  {
405  SG_CONSOLE ( SG_FGMS, SG_ALERT, "FG_SERVER::Init() - "
406  << "failed to bind admin socket " << m_AdminPort );
407  SG_CONSOLE ( SG_FGMS, SG_ALERT, "already in use?" );
408  return ( ERROR_COULDNT_BIND );
409  }
410  if ( m_AdminSocket->listen ( MAX_TELNETS ) != 0 )
411  {
412  SG_CONSOLE ( SG_FGMS, SG_ALERT, "FG_SERVER::Init() - "
413  << "failed to listen to admin port" );
414  return ( ERROR_COULDNT_LISTEN );
415  }
416  }
417  m_ReinitAdmin = false;
418  }
419  SG_CONSOLE (SG_FGMS, SG_ALERT, "# This is " << m_ServerName );
420  SG_CONSOLE ( SG_FGMS, SG_ALERT, "# FlightGear Multiplayer Server v"
421  << VERSION << " started" );
422  SG_CONSOLE ( SG_FGMS, SG_ALERT, "# using protocol version v"
423  << m_ProtoMajorVersion << "." << m_ProtoMinorVersion
424  << " (LazyRelay enabled)" );
425  SG_CONSOLE ( SG_FGMS, SG_ALERT,"# listening to port " << m_ListenPort );
426  if ( m_TelnetSocket )
427  {
428  SG_CONSOLE ( SG_FGMS, SG_ALERT,"# telnet port " << m_TelnetPort );
429  }
430  else
431  {
432  SG_CONSOLE ( SG_FGMS, SG_ALERT,"# telnet port DISABLED");
433  }
434  if ( m_AdminSocket )
435  {
436  SG_CONSOLE ( SG_FGMS, SG_ALERT,"# admin port " << m_AdminPort );
437  }
438  else
439  {
440  SG_CONSOLE ( SG_FGMS, SG_ALERT,"# admin port DISABLED" );
441  }
442  SG_CONSOLE ( SG_FGMS, SG_ALERT,"# using logfile " << m_LogFileName );
443  if ( m_BindAddress != "" )
444  {
445  SG_CONSOLE ( SG_FGMS, SG_ALERT,"# listening on " << m_BindAddress );
446  }
447  if ( m_IamHUB )
448  {
449  SG_CONSOLE ( SG_FGMS, SG_ALERT, "# I am a HUB Server" );
450  }
451  if (( m_IsTracked ) && (m_Tracker != 0))
452  {
453  pthread_t th;
454  pthread_create ( &th, NULL, &detach_tracker, m_Tracker );
455  SG_CONSOLE ( SG_FGMS, SG_ALERT, "# tracked to "
456  << m_Tracker->GetTrackerServer ()
457  << ":" << m_Tracker->GetTrackerPort ()
458  << ", using a thread."
459  );
460  }
461  else
462  {
463  SG_CONSOLE ( SG_FGMS, SG_ALERT, "# tracking is disabled." );
464  }
465  size_t Count;
466  FG_ListElement Entry("");
467  //////////////////////////////////////////////////
468  // print list of all relays
469  //////////////////////////////////////////////////
470  Count = m_RelayList.Size();
471  SG_CONSOLE ( SG_FGMS, SG_ALERT, "# I have " << Count << " relays" );
472  for (size_t i = 0; i < Count; i++)
473  {
474  Entry = m_RelayList[i];
475  if (Entry.ID == FG_ListElement::NONE_EXISTANT)
476  continue;
477  SG_CONSOLE ( SG_FGMS, SG_ALERT, "# relay " << Entry.Name
478  << ":" << Entry.Address.getPort()
479  << " (" << Entry.Address.getHost() << ")");
480  }
481  //////////////////////////////////////////////////
482  // print list of all crossfeeds
483  //////////////////////////////////////////////////
484  Count = m_CrossfeedList.Size();
485  SG_CONSOLE ( SG_FGMS, SG_ALERT, "# I have " << Count << " crossfeeds" );
486  for (size_t i = 0; i < Count; i++)
487  {
488  Entry = m_CrossfeedList[i];
489  if (Entry.ID == FG_ListElement::NONE_EXISTANT)
490  continue;
491  SG_CONSOLE ( SG_FGMS, SG_ALERT, "# crossfeed " << Entry.Name
492  << ":" << Entry.Address.getPort() );
493  }
494  SG_CONSOLE ( SG_FGMS, SG_ALERT, "# I have " << m_BlackList.Size() << " blacklisted IPs" );
495  SG_CONSOLE ( SG_FGMS, SG_ALERT, "# Files: exit=[" << exit_file << "] stat=[" << stat_file << "]" );
496  m_Listening = true;
497  return ( SUCCESS );
498 } // FG_SERVER::Init()
499 
500 //////////////////////////////////////////////////////////////////////
501 /**
502  * @brief Do anything necessary to (re-) init the server used to handle kill -HUP
503  */
504 void
506 ()
507 {
508  if ( ! m_IsParent )
509  return;
510  SG_LOG ( SG_FGMS, SG_ALERT, "# caught SIGHUP, doing reinit!" );
511  // release all locks
512  m_PlayerList.Unlock ();
513  m_RelayList.Unlock ();
514  m_CrossfeedList.Unlock ();
515  m_BlackList.Unlock ();
516  // and clear all but the player list
517  m_RelayList.Clear ();
518  m_BlackList.Clear ();
519  m_CrossfeedList.Clear ();
520  m_RelayMap.clear (); // clear(): is a std::map (NOT a FG_List)
521  CloseTracker ();
522 } // FG_SERVER::PrepareInit ()
523 //////////////////////////////////////////////////////////////////////
524 
525 //////////////////////////////////////////////////////////////////////
526 /**
527  * @brief Handle an admin session.
528  *
529  * If a telnet connection to the admin port is established, a new FG_CLI
530  * instance is created.
531  * @param Fd -- docs todo --
532  */
533 void*
535 (
536  int Fd
537 )
538 {
539  FG_CLI* MyCLI;
540  errno = 0;
541  MyCLI = new FG_CLI ( this, Fd );
542  MyCLI->loop ();
543  if (Fd == 0)
544  { // reading from stdin
545  WantExit();
546  }
547  delete MyCLI;
548  return ( 0 );
549 }
550 
551 //////////////////////////////////////////////////////////////////////
552 /**
553  * @brief Handle a telnet session. if a telnet connection is opened, this
554  * method outputs a list of all known clients.
555  * @param Fd -- docs todo --
556  */
557 void*
559 (
560  int Fd
561 )
562 {
563  errno = 0;
564  string Message;
565  /** @brief Geodetic Coordinates */
566  Point3D PlayerPosGeod;
567  FG_Player CurrentPlayer;
568  netSocket NewTelnet;
569  unsigned int it;
570  NewTelnet.setHandle ( Fd );
571  errno = 0;
572  //////////////////////////////////////////////////
573  //
574  // create the output message
575  // header
576  //
577  //////////////////////////////////////////////////
578  Message = "# This is " + m_ServerName;
579  Message += "\n";
580  Message += "# FlightGear Multiplayer Server v" + string ( VERSION );
581  Message += "\n";
582  Message += "# using protocol version v";
583  Message += NumToStr ( m_ProtoMajorVersion, 0 );
584  Message += "." + NumToStr ( m_ProtoMinorVersion, 0 );
585  Message += " (LazyRelay enabled)";
586  Message += "\n";
587  if ( m_IsTracked )
588  {
589  Message += "# This server is tracked: ";
590  Message += m_Tracker->GetTrackerServer();
591  Message += "\n";
592  }
593  if ( NewTelnet.write_str ( Message ) < 0 )
594  {
595  if ( ( errno != EAGAIN ) && ( errno != EPIPE ) )
596  {
597  SG_LOG ( SG_FGMS, SG_ALERT, "FG_SERVER::HandleTelnet() - " << strerror ( errno ) );
598  }
599  return ( 0 );
600  }
601  Message = "# "+ NumToStr ( m_PlayerList.Size(), 0 );
602  Message += " pilot(s) online\n";
603  if ( NewTelnet.write_str ( Message ) < 0 )
604  {
605  if ( ( errno != EAGAIN ) && ( errno != EPIPE ) )
606  {
607  SG_LOG ( SG_FGMS, SG_ALERT, "FG_SERVER::HandleTelnet() - " << strerror ( errno ) );
608  }
609  return ( 0 );
610  }
611  //////////////////////////////////////////////////
612  //
613  // create list of players
614  //
615  //////////////////////////////////////////////////
616  it = 0;
617  for ( ;; )
618  {
619  if ( it < m_PlayerList.Size() )
620  {
621  CurrentPlayer = m_PlayerList[it];
622  it++;
623  }
624  else
625  {
626  break;
627  }
628  if (CurrentPlayer.Name.compare (0, 3, "obs", 3) == 0)
629  {
630  continue;
631  }
632  sgCartToGeod ( CurrentPlayer.LastPos, PlayerPosGeod );
633  Message = CurrentPlayer.Name + "@";
634  if ( CurrentPlayer.IsLocal )
635  {
636  Message += "LOCAL: ";
637  }
638  else
639  {
640  mT_RelayMapIt Relay = m_RelayMap.find ( CurrentPlayer.Address.getIP() );
641  if ( Relay != m_RelayMap.end() )
642  {
643  Message += Relay->second + ": ";
644  }
645  else
646  {
647  Message += CurrentPlayer.Origin + ": ";
648  }
649  }
650  if ( CurrentPlayer.Error != "" )
651  {
652  Message += CurrentPlayer.Error + " ";
653  }
654  Message += NumToStr ( CurrentPlayer.LastPos[X], 6 ) +" ";
655  Message += NumToStr ( CurrentPlayer.LastPos[Y], 6 ) +" ";
656  Message += NumToStr ( CurrentPlayer.LastPos[Z], 6 ) +" ";
657  Message += NumToStr ( PlayerPosGeod[Lat], 6 ) +" ";
658  Message += NumToStr ( PlayerPosGeod[Lon], 6 ) +" ";
659  Message += NumToStr ( PlayerPosGeod[Alt], 6 ) +" ";
660  Message += NumToStr ( CurrentPlayer.LastOrientation[X], 6 ) +" ";
661  Message += NumToStr ( CurrentPlayer.LastOrientation[Y], 6 ) +" ";
662  Message += NumToStr ( CurrentPlayer.LastOrientation[Z], 6 ) +" ";
663  Message += CurrentPlayer.ModelName;
664  Message += "\n";
665  if ( NewTelnet.write_str ( Message ) < 0 )
666  {
667  if ( ( errno != EAGAIN ) && ( errno != EPIPE ) )
668  {
669  SG_LOG ( SG_FGMS, SG_ALERT, "FG_SERVER::HandleTelnet() - " << strerror ( errno ) );
670  }
671  return ( 0 );
672  }
673  }
674  NewTelnet.close ();
675  return ( 0 );
676 } // FG_SERVER::HandleTelnet ()
677 
678 //////////////////////////////////////////////////////////////////////
679 /**
680  * @brief If we receive bad data from a client, we add the client to
681  * the internal list anyway, but mark them as bad. But first
682  * we look if it isn't already there.
683  * Send an error message to the bad client.
684  * @param Sender
685  * @param ErrorMsg
686  * @param IsLocal
687  */
688 void
690 (
691  const netAddress& Sender,
692  string& ErrorMsg,
693  bool IsLocal,
694  int Bytes
695 )
696 {
697  string Message;
698  FG_Player NewPlayer;
699  PlayerIt CurrentPlayer;
700  //////////////////////////////////////////////////
701  // see, if we already know the client
702  //////////////////////////////////////////////////
703  m_PlayerList.Lock ();
704  CurrentPlayer = m_PlayerList.Find (Sender);
705  if ( CurrentPlayer != m_PlayerList.End () )
706  {
707  CurrentPlayer->UpdateRcvd (Bytes);
708  m_PlayerList.UpdateRcvd (Bytes);
709  m_PlayerList.Unlock();
710  return;
711  }
712  //////////////////////////////////////////////////
713  // new client, add to the list
714  //////////////////////////////////////////////////
715  if (IsLocal)
716  m_LocalClients++;
717  else
718  m_RemoteClients++;
719  NewPlayer.Name = "* Bad Client *";
720  NewPlayer.ModelName = "* unknown *";
721  NewPlayer.Origin = Sender.getHost ();
722  NewPlayer.Address = Sender;
723  NewPlayer.IsLocal = IsLocal;
724  NewPlayer.HasErrors = true;
725  NewPlayer.Error = ErrorMsg;
726  NewPlayer.UpdateRcvd (Bytes);
727  SG_LOG ( SG_FGMS, SG_WARN, "FG_SERVER::AddBadClient() - " << ErrorMsg );
728  m_PlayerList.Add (NewPlayer, m_PlayerExpires);
729  m_PlayerList.UpdateRcvd (Bytes);
730  m_PlayerList.Unlock();
731 } // FG_SERVER::AddBadClient ()
732 
733 //////////////////////////////////////////////////////////////////////
734 /**
735  * @brief Insert a new client to internal list
736  * @param Sender
737  * @param Msg
738  */
739 void
741 (
742  const netAddress& Sender,
743  char* Msg
744 )
745 {
746  uint32_t MsgMagic;
747  string Message;
748  string Origin;
749  T_MsgHdr* MsgHdr;
750  T_PositionMsg* PosMsg;
751  FG_Player NewPlayer;
752  bool IsLocal;
753  MsgHdr = ( T_MsgHdr* ) Msg;
754  PosMsg = ( T_PositionMsg* ) ( Msg + sizeof ( T_MsgHdr ) );
755  MsgMagic = XDR_decode<uint32_t> ( MsgHdr->Magic );
756  IsLocal = true;
757  if ( MsgMagic == RELAY_MAGIC ) // not a local client
758  {
759  IsLocal = false;
760  }
761  NewPlayer.Name = MsgHdr->Name;
762  NewPlayer.Passwd = "test"; //MsgHdr->Passwd;
763  NewPlayer.ModelName = "* unknown *";
764  NewPlayer.Origin = Sender.getHost ();
765  NewPlayer.Address = Sender;
766  NewPlayer.IsLocal = IsLocal;
767  NewPlayer.LastPos.Set (
768  XDR_decode64<double> ( PosMsg->position[X] ),
769  XDR_decode64<double> ( PosMsg->position[Y] ),
770  XDR_decode64<double> ( PosMsg->position[Z] )
771  );
772  NewPlayer.LastOrientation.Set (
773  XDR_decode<float> ( PosMsg->orientation[X] ),
774  XDR_decode<float> ( PosMsg->orientation[Y] ),
775  XDR_decode<float> ( PosMsg->orientation[Z] )
776  );
777  NewPlayer.ModelName = PosMsg->Model;
778  m_PlayerList.Add ( NewPlayer, m_PlayerExpires );
779  size_t NumClients = m_PlayerList.Size ();
780  if ( NumClients > m_NumMaxClients )
781  {
782  m_NumMaxClients = NumClients;
783  }
784  if ( IsLocal )
785  {
786  m_LocalClients++;
787  UpdateTracker ( NewPlayer.Name, NewPlayer.Passwd,
788  NewPlayer.ModelName, NewPlayer.LastSeen, CONNECT );
789  }
790  else
791  {
792  m_RemoteClients++;
793  }
794  Origin = NewPlayer.Origin;
795  if ( IsLocal )
796  {
797  Message = "New LOCAL Client: ";
798  }
799  else
800  {
801  Message = "New REMOTE Client: ";
802  mT_RelayMapIt Relay = m_RelayMap.find ( NewPlayer.Address.getIP() );
803  if ( Relay != m_RelayMap.end() )
804  {
805  Origin = Relay->second;
806  }
807  }
808  SG_LOG ( SG_FGMS, SG_INFO, Message
809  << NewPlayer.Name << "@"
810  << Origin << ":" << Sender.getPort()
811  << " (" << NewPlayer.ModelName << ")"
812  << " current clients: "
813  << NumClients << " max: " << m_NumMaxClients
814  );
815 } // FG_SERVER::AddClient()
816 
817 //////////////////////////////////////////////////////////////////////
818 /**
819  * @brief Insert a new relay server into internal list
820  * @param Server
821  * @param Port
822  */
823 void
825 (
826  const string& Relay,
827  int Port
828 )
829 {
830  FG_ListElement B (Relay);
831 
832  B.Address.set ( ( char* ) Relay.c_str(), Port );
833  if (B.Address.getIP() == 0)
834  {
836  "could not resolve '" << Relay << "'");
837  return;
838  }
839  if ((B.Address.getIP() >= 0x7F000001) && (B.Address.getIP() <= 0x7FFFFFFF))
840  {
842  "relay points back to me '" << Relay << "'");
843  return;
844  }
845  m_RelayList.Lock ();
846  ItList CurrentEntry = m_RelayList.Find ( B.Address, "" );
847  m_RelayList.Unlock ();
848  if ( CurrentEntry == m_RelayList.End() )
849  {
850  m_RelayList.Add (B, 0);
851  string S;
852  if (B.Address.getHost() == Relay)
853  {
854  S = Relay;
855  }
856  else
857  {
858  unsigned I;
859  I = Relay.find ( "." );
860  if ( I != string::npos )
861  {
862  S = Relay.substr ( 0, I );
863  }
864  else
865  {
866  S = Relay;
867  }
868  }
869  m_RelayMap[B.Address.getIP()] = S;
870  }
871 } // FG_SERVER::AddRelay()
872 
873 //////////////////////////////////////////////////////////////////////
874 /**
875  * @brief Insert a new crossfeed server into internal list
876  * @param Server char with server
877  * @param Port int with port number
878  */
879 void
881 (
882  const string& Server,
883  int Port
884 )
885 {
886  string s = Server;
887 #ifdef _MSC_VER
888  if ( s == "localhost" )
889  {
890  s = "127.0.0.1";
891  }
892 #endif // _MSC_VER
893  FG_ListElement B (s);
894  B.Address.set ( ( char* ) s.c_str(), Port );
895  m_CrossfeedList.Lock ();
896  ItList CurrentEntry = m_CrossfeedList.Find ( B.Address, "" );
897  m_CrossfeedList.Unlock ();
898  if ( CurrentEntry == m_CrossfeedList.End() )
899  {
900  m_CrossfeedList.Add (B, 0);
901  }
902 } // FG_SERVER::AddCrossfeed()
903 
904 //////////////////////////////////////////////////////////////////////
905 /**
906  * @brief Add a tracking server
907  * @param Server String with server
908  * @param Port The port number
909  * @param IsTracked Is Stracked
910  * @retval int -1 for fail or SUCCESS
911  */
912 int
914 (
915  const string& Server,
916  int Port,
917  bool IsTracked
918 )
919 {
920  CloseTracker();
921  m_IsTracked = IsTracked;
922  m_Tracker = new FG_TRACKER ( Port, Server, 0 );
923  return ( SUCCESS );
924 } // FG_SERVER::AddTracker()
925 
926 //////////////////////////////////////////////////////////////////////
927 /**
928  * @brief Add an IP to the blacklist
929  * @param FourDottedIP IP to add to blacklist
930  */
931 void
933 (
934  const string& DottedIP,
935  const string& Reason,
936  time_t Timeout
937 )
938 {
939 
940  FG_ListElement B (Reason);
941  B.Address.set (DottedIP.c_str(), 0);
942  m_BlackList.Lock ();
943  ItList CurrentEntry = m_BlackList.Find ( B.Address, "" );
944  m_BlackList.Unlock ();
945  if ( CurrentEntry == m_BlackList.End() )
946  { // FIXME: every list has its own standard TTL
947  m_BlackList.Add (B, Timeout);
948  }
949 } // FG_SERVER::AddBlacklist()
950 
951 //////////////////////////////////////////////////////////////////////
952 /**
953  * @brief Check if the sender is a known relay
954  * @param SenderAddress
955  * @retval bool true if known relay
956  */
957 bool
959 (
960  const netAddress& SenderAddress,
961  size_t Bytes
962 )
963 {
964  ItList CurrentEntry;
965  m_RelayList.Lock ();
966  CurrentEntry = m_RelayList.Find ( SenderAddress, "" );
967  if ( CurrentEntry != m_RelayList.End() )
968  {
969  m_RelayList.UpdateRcvd (CurrentEntry, Bytes);
970  m_RelayList.Unlock ();
971  return true;
972  }
973  m_RelayList.Unlock ();
974  string ErrorMsg;
975  ErrorMsg = SenderAddress.getHost();
976  ErrorMsg += " is not a valid relay!";
977  AddBlacklist ( SenderAddress.getHost(), "not a valid relay", 0);
978  SG_LOG ( SG_FGMS, SG_ALERT, "UNKNOWN RELAY: " << ErrorMsg );
979  return ( false );
980 } // FG_SERVER::IsKnownRelay ()
981 //////////////////////////////////////////////////////////////////////
982 
983 //////////////////////////////////////////////////////////////////////
984 //
985 // check if the packet is valid
986 //
987 //////////////////////////////////////////////////////////////////////
988 /**
989  * @brief
990  */
991 bool
993 (
994  int Bytes,
995  T_MsgHdr* MsgHdr,
996  const netAddress& SenderAddress
997 )
998 {
999  uint32_t MsgMagic;
1000  uint32_t MsgLen;
1001  uint32_t MsgId;
1002  string ErrorMsg;
1003  string Origin;
1004  typedef union
1005  {
1006  uint32_t complete;
1007  int16_t High;
1008  int16_t Low;
1009  } converter;
1010 
1011  Origin = SenderAddress.getHost();
1012  MsgMagic = XDR_decode<uint32_t> ( MsgHdr->Magic );
1013  MsgId = XDR_decode<uint32_t> ( MsgHdr->MsgId );
1014  MsgLen = XDR_decode<uint32_t> ( MsgHdr->MsgLen );
1015  if ( Bytes < ( int ) sizeof ( MsgHdr ) )
1016  {
1017  ErrorMsg = SenderAddress.getHost();
1018  ErrorMsg += " packet size is too small!";
1019  AddBadClient ( SenderAddress, ErrorMsg, true, Bytes );
1020  return ( false );
1021  }
1022  if ( ( MsgMagic != MSG_MAGIC ) && ( MsgMagic != RELAY_MAGIC ) )
1023  {
1024  char m[5];
1025  memcpy ( m, ( char* ) &MsgMagic, 4 );
1026  m[4] = 0;
1027  ErrorMsg = Origin;
1028  ErrorMsg += " BAD magic number: ";
1029  ErrorMsg += m;
1030  AddBadClient ( SenderAddress, ErrorMsg, true, Bytes );
1031  return ( false );
1032  }
1033  if ( XDR_decode<uint32_t> ( MsgHdr->Version ) != PROTO_VER )
1034  {
1035  MsgHdr->Version = XDR_decode<uint32_t> ( MsgHdr->Version );
1036  ErrorMsg = Origin;
1037  ErrorMsg += " BAD protocol version! Should be ";
1038  converter* tmp;
1039  tmp = ( converter* ) ( & PROTO_VER );
1040  ErrorMsg += NumToStr ( tmp->High, 0 );
1041  ErrorMsg += "." + NumToStr ( tmp->Low, 0 );
1042  ErrorMsg += " but is ";
1043  tmp = ( converter* ) ( & MsgHdr->Version );
1044  ErrorMsg += NumToStr ( tmp->Low, 0 );
1045  ErrorMsg += "." + NumToStr ( tmp->High, 0 );
1046  AddBadClient ( SenderAddress, ErrorMsg, true, Bytes );
1047  return ( false );
1048  }
1049  if ( MsgId == POS_DATA_ID )
1050  {
1051  if ( MsgLen < sizeof ( T_MsgHdr ) + sizeof ( T_PositionMsg ) )
1052  {
1053  ErrorMsg = Origin;
1054  ErrorMsg += " Client sends insufficient position data, ";
1055  ErrorMsg += "should be ";
1056  ErrorMsg += NumToStr ( sizeof ( T_MsgHdr ) +sizeof ( T_PositionMsg ) );
1057  ErrorMsg += " is: " + NumToStr ( MsgHdr->MsgLen );
1058  AddBadClient ( SenderAddress, ErrorMsg, true, Bytes );
1059  return ( false );
1060  }
1061  }
1062  return ( true );
1063 } // FG_SERVER::PacketIsValid ()
1064 //////////////////////////////////////////////////////////////////////
1065 
1066 //////////////////////////////////////////////////////////////////////
1067 /**
1068  * @brief Send message to all crossfeed servers.
1069  * Crossfeed servers receive all traffic without condition,
1070  * mainly used for testing and debugging
1071  */
1072 void
1075  char* Msg,
1076  int Bytes,
1077  const netAddress& SenderAddress
1078 )
1079 {
1080  T_MsgHdr* MsgHdr;
1081  uint32_t MsgMagic;
1082  int sent;
1083  ItList Entry;
1084  MsgHdr = ( T_MsgHdr* ) Msg;
1085  MsgMagic = MsgHdr->Magic;
1086  MsgHdr->Magic = XDR_encode<uint32_t> ( RELAY_MAGIC );
1087  // pass on senders address and port to crossfeed server
1088  MsgHdr->ReplyAddress = XDR_encode<uint32_t> ( SenderAddress.getIP() );
1089  MsgHdr->ReplyPort = XDR_encode<uint32_t> ( SenderAddress.getPort() );
1090  m_CrossfeedList.Lock();
1091  for (Entry = m_CrossfeedList.Begin(); Entry != m_CrossfeedList.End(); Entry++)
1092  {
1093  sent = m_DataSocket->sendto ( Msg, Bytes, 0, &Entry->Address );
1094  m_CrossfeedList.UpdateSent (Entry, sent);
1095  }
1096  m_CrossfeedList.Unlock();
1097  MsgHdr->Magic = MsgMagic; // restore the magic value
1098 } // FG_SERVER::SendToCrossfeed ()
1099 //////////////////////////////////////////////////////////////////////
1100 
1101 //////////////////////////////////////////////////////////////////////
1102 /**
1103  * @brief Send message to all relay servers
1104  */
1105 void
1108  char* Msg,
1109  int Bytes,
1110  FG_Player& SendingPlayer
1111 )
1112 {
1113  T_MsgHdr* MsgHdr;
1114  uint32_t MsgMagic;
1115  unsigned int PktsForwarded = 0;
1116  ItList CurrentRelay;
1117 
1118  if ( (! SendingPlayer.IsLocal ) && ( ! m_IamHUB ) )
1119  {
1120  return;
1121  }
1122  MsgHdr = ( T_MsgHdr* ) Msg;
1123  MsgMagic = XDR_decode<uint32_t> ( MsgHdr->Magic );
1124  MsgHdr->Magic = XDR_encode<uint32_t> ( RELAY_MAGIC );
1125  m_RelayList.Lock ();
1126  CurrentRelay = m_RelayList.Begin();
1127  while ( CurrentRelay != m_RelayList.End() )
1128  {
1129 
1130  if ( CurrentRelay->Address.getIP() != SendingPlayer.Address.getIP() )
1131  {
1132  if ( SendingPlayer.DoUpdate || IsInRange ( *CurrentRelay, SendingPlayer ) )
1133  {
1134  m_DataSocket->sendto ( Msg, Bytes, 0, &CurrentRelay->Address );
1135  m_RelayList.UpdateSent (CurrentRelay, Bytes);
1136  PktsForwarded++;
1137  }
1138  }
1139  CurrentRelay++;
1140  }
1141  m_RelayList.Unlock ();
1142  MsgHdr->Magic = XDR_encode<uint32_t> ( MsgMagic ); // restore the magic value
1143 } // FG_SERVER::SendToRelays ()
1144 //////////////////////////////////////////////////////////////////////
1145 
1146 //////////////////////////////////////////////////////////////////////
1147 // Remove Player from list
1148 void
1151  PlayerIt& CurrentPlayer
1152 )
1153 {
1154  string Origin;
1155  if ((CurrentPlayer->IsLocal) && (CurrentPlayer->HasErrors == false))
1156  {
1157  UpdateTracker (CurrentPlayer->Name,
1158  CurrentPlayer->Passwd,
1159  CurrentPlayer->ModelName,
1160  CurrentPlayer->LastSeen,
1161  DISCONNECT
1162  );
1163  }
1164  if (CurrentPlayer->IsLocal)
1165  m_LocalClients--;
1166  else
1167  m_RemoteClients--;
1168  mT_RelayMapIt Relay = m_RelayMap.find ( CurrentPlayer->Address.getIP() );
1169  if ( Relay != m_RelayMap.end() )
1170  {
1171  Origin = Relay->second;
1172  }
1173  else
1174  {
1175  Origin = "LOCAL";
1176  }
1177  SG_LOG (SG_FGMS, SG_INFO, "TTL exceeded, dropping pilot "
1178  << CurrentPlayer->Name << "@" << Origin
1179  << " after " << time(0)-CurrentPlayer->JoinTime << " seconds. "
1180  << "Current clients: "
1181  << m_PlayerList.Size()-1 << " max: " << m_NumMaxClients
1182  );
1183  CurrentPlayer = m_PlayerList.Delete (CurrentPlayer);
1184 } // FG_SERVER::DropClient()
1185 //////////////////////////////////////////////////////////////////////
1186 
1187 //////////////////////////////////////////////////////////////////////
1188 /**
1189  * @brief Handle client connections
1190  * @param Msg
1191  * @param Bytes
1192  * @param SenderAddress
1193  */
1194 void
1197  char* Msg,
1198  int Bytes,
1199  const netAddress& SenderAddress
1200 )
1201 {
1202  T_MsgHdr* MsgHdr;
1203  T_PositionMsg* PosMsg;
1204  uint32_t MsgId;
1205  uint32_t MsgMagic;
1206  Point3D SenderPosition;
1207  Point3D SenderOrientation;
1208  Point3D PlayerPosGeod;
1209  PlayerIt CurrentPlayer;
1210  FG_Player SendingPlayer;
1211  ItList CurrentEntry;
1212  time_t Now;
1213  unsigned int PktsForwarded = 0;
1214  MsgHdr = ( T_MsgHdr* ) Msg;
1215  MsgMagic = XDR_decode<uint32_t> ( MsgHdr->Magic );
1216  MsgId = XDR_decode<uint32_t> ( MsgHdr->MsgId );
1217  Now = time ( 0 );
1218  //////////////////////////////////////////////////
1219  //
1220  // First of all, send packet to all
1221  // crossfeed servers.
1222  //
1223  //////////////////////////////////////////////////
1224  SendToCrossfeed ( Msg, Bytes, SenderAddress );
1225  //////////////////////////////////////////////////
1226  //
1227  // Now do the local processing
1228  //
1229  //////////////////////////////////////////////////
1230  m_BlackList.Lock ();
1231  CurrentEntry = m_BlackList.Find ( SenderAddress, "" );
1232  if ( CurrentEntry != m_BlackList.End() )
1233  {
1234  m_BlackList.UpdateRcvd (CurrentEntry, Bytes);
1235  m_BlackRejected++;
1236  m_BlackList.Unlock ();
1237  return;
1238  }
1239  m_BlackList.Unlock ();
1240  if ( ! PacketIsValid ( Bytes, MsgHdr, SenderAddress ) )
1241  {
1242  m_PacketsInvalid++;
1243  return;
1244  }
1245  if ( MsgMagic == RELAY_MAGIC ) // not a local client
1246  {
1247  if ( ! IsKnownRelay ( SenderAddress, Bytes ) )
1248  {
1249  m_UnknownRelay++;
1250  return;
1251  }
1252  else
1253  {
1254  m_RelayMagic++; // bump relay magic packet
1255  }
1256  }
1257  //////////////////////////////////////////////////
1258  //
1259  // Store senders position
1260  //
1261  //////////////////////////////////////////////////
1262  if ( MsgId == POS_DATA_ID )
1263  {
1264  m_PositionData++;
1265  PosMsg = ( T_PositionMsg* ) ( Msg + sizeof ( T_MsgHdr ) );
1266  double x = XDR_decode64<double> ( PosMsg->position[X] );
1267  double y = XDR_decode64<double> ( PosMsg->position[Y] );
1268  double z = XDR_decode64<double> ( PosMsg->position[Z] );
1269  if ( ( x == 0.0 ) || ( y == 0.0 ) || ( z == 0.0 ) )
1270  {
1271  // ignore while position is not settled
1272  return;
1273  }
1274  SenderPosition.Set ( x, y, z );
1275  SenderOrientation.Set (
1276  XDR_decode<float> ( PosMsg->orientation[X] ),
1277  XDR_decode<float> ( PosMsg->orientation[Y] ),
1278  XDR_decode<float> ( PosMsg->orientation[Z] )
1279  );
1280  }
1281  else
1282  {
1283  m_NotPosData++;
1284  }
1285  //////////////////////////////////////////////////
1286  //
1287  // Add Client to list if its not known
1288  //
1289  //////////////////////////////////////////////////
1290  m_PlayerList.Lock();
1291  CurrentPlayer = m_PlayerList.FindByName ( MsgHdr->Name );
1292  if (CurrentPlayer == m_PlayerList.End () )
1293  {
1294  // unknown, add to the list
1295  if ( MsgId != POS_DATA_ID )
1296  {
1297  // ignore clients until we have a valid position
1298  m_PlayerList.Unlock();
1299  return;
1300  }
1301  AddClient ( SenderAddress, Msg );
1302  }
1303  else
1304  {
1305  if ( CurrentPlayer->Address != SenderAddress )
1306  {
1307  m_PlayerList.Unlock();
1308  return;
1309  }
1310  }
1311  m_PlayerList.Unlock();
1312  //////////////////////////////////////////
1313  //
1314  // send the packet to all clients.
1315  // since we are walking through the list,
1316  // we look for the sending client, too. if it
1317  // is not already there, add it to the list
1318  //
1319  //////////////////////////////////////////////////
1320  MsgHdr->Magic = XDR_encode<uint32_t> ( MSG_MAGIC );
1321  CurrentPlayer = m_PlayerList.Begin();
1322  while ( CurrentPlayer != m_PlayerList.End() )
1323  {
1324  //////////////////////////////////////////////////
1325  //
1326  // ignore clients with errors
1327  //
1328  //////////////////////////////////////////////////
1329  if ( CurrentPlayer->HasErrors )
1330  {
1331  if ((Now - CurrentPlayer->LastSeen) > CurrentPlayer->Timeout )
1332  {
1333  DropClient (CurrentPlayer);
1334  }
1335  else
1336  {
1337  CurrentPlayer++;
1338  }
1339  continue;
1340  }
1341  //////////////////////////////////////////////////
1342  // Sender == CurrentPlayer?
1343  //////////////////////////////////////////////////
1344  // FIXME: if Sender is a Relay,
1345  // CurrentPlayer->Address will be
1346  // address of Relay and not the client's!
1347  // so use a clientID instead
1348  if ( CurrentPlayer->Name == MsgHdr->Name )
1349  {
1350  if ( MsgId == POS_DATA_ID )
1351  {
1352  CurrentPlayer->LastPos = SenderPosition;
1353  CurrentPlayer->LastOrientation = SenderOrientation;
1354  }
1355  else
1356  {
1357  SenderPosition = CurrentPlayer->LastPos;
1358  SenderOrientation = CurrentPlayer->LastOrientation;
1359  }
1360  if ( CurrentPlayer->IsLocal )
1361  {
1362  m_PlayerList.UpdateRcvd (CurrentPlayer, Bytes);
1363  }
1364  //////////////////////////////////////////////////
1365  // send update to inactive relays?
1366  //////////////////////////////////////////////////
1367  CurrentPlayer->DoUpdate = ( (Now - CurrentPlayer->LastRelayedToInactive) > UPDATE_INACTIVE_PERIOD );
1368  if ( CurrentPlayer->DoUpdate )
1369  {
1370  CurrentPlayer->LastRelayedToInactive = Now;
1371  }
1372  SendingPlayer = *CurrentPlayer;
1373  CurrentPlayer++;
1374  continue; // don't send packet back to sender
1375  }
1376  //////////////////////////////////////////////////
1377  // Drop Users if they did'nt send data
1378  // within TTL
1379  //////////////////////////////////////////////////
1380  if (((Now - CurrentPlayer->LastSeen) > CurrentPlayer->Timeout )
1381  && ((Now - CurrentPlayer->JoinTime) > 30)) // give 30 seconds gracetime on startup
1382  {
1383  DropClient (CurrentPlayer); // ###
1384  continue;
1385  }
1386  //////////////////////////////////////////////////
1387  // do not send packets to clients if the
1388  // origin is an observer, but do send
1389  // chat messages anyway
1390  // FIXME: MAGIC = SFGF!
1391  //////////////////////////////////////////////////
1392  if ( strncasecmp ( MsgHdr->Name, "obs", 3 ) == 0 )
1393  {
1394  return;
1395  }
1396  //////////////////////////////////////////////////
1397  //
1398  // do not send packet to clients which
1399  // are out of reach.
1400  // FIX20140603 - compare fix by Markus Pargmann
1401  //////////////////////////////////////////////////
1402  if ( ( Distance ( SenderPosition, CurrentPlayer->LastPos ) > m_PlayerIsOutOfReach )
1403  && (CurrentPlayer->Name.compare (0, 3, "obs", 3) != 0 ) )
1404  {
1405  CurrentPlayer++;
1406  continue;
1407  }
1408  //////////////////////////////////////////////////
1409  //
1410  // only send packet to local clients
1411  //
1412  //////////////////////////////////////////////////
1413  if ( CurrentPlayer->IsLocal )
1414  {
1415  m_DataSocket->sendto ( Msg, Bytes, 0, &CurrentPlayer->Address );
1416  m_PlayerList.UpdateSent (CurrentPlayer, Bytes);
1417  PktsForwarded++;
1418  }
1419  CurrentPlayer++;
1420  }
1421  if ( SendingPlayer.ID == FG_ListElement::NONE_EXISTANT )
1422  {
1423  // player not yet in our list
1424  // should not happen, but test just in case
1425  SG_LOG ( SG_FGMS, SG_ALERT, "## BAD => "
1426  << MsgHdr->Name << ":" << SenderAddress.getHost()
1427  );
1428  return;
1429  }
1430  SendToRelays ( Msg, Bytes, SendingPlayer );
1431 } // FG_SERVER::HandlePacket ();
1432 //////////////////////////////////////////////////////////////////////
1433 
1434 /**
1435  * @brief Show Stats
1436  */
1438 {
1439  int pilot_cnt, local_cnt;
1440  // update totals since start
1451  // output to LOG and cerr channels
1452  pilot_cnt = local_cnt = 0;
1453  FG_Player CurrentPlayer; // get LOCAL pilot count
1454  pilot_cnt = m_PlayerList.Size ();
1455  for (int i = 0; i < pilot_cnt; i++)
1456  {
1457  CurrentPlayer = m_PlayerList[i];
1458  if (CurrentPlayer.ID == FG_ListElement::NONE_EXISTANT)
1459  continue;
1460  if ( CurrentPlayer.IsLocal )
1461  {
1462  local_cnt++;
1463  }
1464  }
1465  SG_LOG ( SG_FGMS, SG_ALERT, "## Pilots: total " << pilot_cnt << ", local " << local_cnt );
1466  SG_LOG ( SG_FGMS, SG_ALERT, "## Since: Packets " <<
1467  m_PacketsReceived << " BL=" <<
1468  m_BlackRejected << " INV=" <<
1469  m_PacketsInvalid << " UR=" <<
1470  m_UnknownRelay << " RD=" <<
1471  m_RelayMagic << " PD=" <<
1472  m_PositionData << " NP=" <<
1473  m_NotPosData << " CF=" <<
1474  m_CrossFeedSent << "/" << m_CrossFeedFailed << " TN=" <<
1476  );
1477  SG_LOG ( SG_FGMS, SG_ALERT, "## Total: Packets " <<
1478  mT_PacketsReceived << " BL=" <<
1479  mT_BlackRejected << " INV=" <<
1480  mT_PacketsInvalid << " UR=" <<
1481  mT_UnknownRelay << " RD=" <<
1482  mT_RelayMagic << " PD=" <<
1483  mT_PositionData << " NP=" <<
1484  mT_NotPosData << " CF=" <<
1485  mT_CrossFeedSent << "/" << mT_CrossFeedFailed << " TN=" <<
1486  mT_TelnetReceived << " TC/D/P=" <<
1488  );
1489  // restart 'since' last stat counter
1492  m_RelayMagic = m_NotPosData = 0; // reset
1494 }
1495 
1496 /**
1497  * @brief Check stats file etc
1498  */
1499 int
1501 ()
1502 {
1503  struct stat buf;
1504  if ( stat ( exit_file,&buf ) == 0 )
1505  {
1506  SG_LOG ( SG_FGMS, SG_ALERT, "## Got EXIT file : " << exit_file );
1507  unlink ( exit_file );
1508  if ( stat ( exit_file,&buf ) == 0 )
1509  {
1510  SG_LOG ( SG_FGMS, SG_ALERT, "ERROR: Unable to delete exit file! Doing hard exit..." );
1511  exit ( 1 );
1512  }
1513  return 1;
1514  }
1515  else if ( stat ( reset_file,&buf ) == 0 )
1516  {
1517  SG_LOG ( SG_FGMS, SG_ALERT, "## Got RESET file " << reset_file );
1518  unlink ( reset_file );
1519  if ( stat ( reset_file,&buf ) == 0 )
1520  {
1521  SG_LOG ( SG_FGMS, SG_ALERT, "ERROR: Unable to delete reset file! Doing hard exit..." );
1522  exit ( 1 );
1523  }
1524  m_ReinitData = true; // init the data port
1525  m_ReinitTelnet = true; // init the telnet port
1526  m_ReinitAdmin = true; // init the admin port
1527  SigHUPHandler ( 0 );
1528  }
1529  else if ( stat ( stat_file,&buf ) == 0 )
1530  {
1531  SG_LOG ( SG_FGMS, SG_ALERT, "## Got STAT file " << stat_file );
1532  unlink ( stat_file );
1533  if ( stat ( stat_file,&buf ) == 0 )
1534  {
1535  SG_LOG ( SG_FGMS, SG_ALERT, "ERROR: Unable to delete stat file! Doing hard exit..." );
1536  exit ( 1 );
1537  }
1538  Show_Stats();
1539  }
1540 #ifdef _MSC_VER
1541  if (!AddCLI && _kbhit())
1542  {
1543  int ch = _getch ();
1544  if ( ch == 0x1b )
1545  {
1546  printf("Got ESC key to exit...\n");
1547  return 1;
1548  }
1549  else
1550  {
1551  printf("Got UNKNOWN keyboard! %#X - Only ESC, to exit\n", ch);
1552  }
1553  }
1554 #endif // _MSC_VER
1555  return 0;
1556 }
1557 
1558 //////////////////////////////////////////////////////////////////////
1559 /**
1560  * @brief allow the Admin CLI to shut down fgms
1561  */
1562 void
1564 ()
1565 {
1566  m_WantExit = true;
1567 }
1568 //////////////////////////////////////////////////////////////////////
1569 
1570 //////////////////////////////////////////////////////////////////////
1571 /**
1572  * @brief Main loop of the server
1573  */
1574 int
1576 ()
1577 {
1578  int Bytes;
1579  char Msg[MAX_PACKET_SIZE];
1580  netAddress SenderAddress;
1581  netSocket* ListenSockets[3 + MAX_TELNETS];
1582  time_t LastTrackerUpdate;
1583  time_t CurrentTime;
1584  LastTrackerUpdate = time ( 0 );
1585  m_IsParent = true;
1586  if ( m_Listening == false )
1587  {
1588  SG_LOG ( SG_FGMS, SG_ALERT, "FG_SERVER::Loop() - "
1589  << "not listening on any socket!" );
1590  return ( ERROR_NOT_LISTENING );
1591  }
1592 #ifdef _MSC_VER
1593  SG_LOG ( SG_FGMS, SG_ALERT, "ESC key to EXIT (after select " << m_PlayerExpires << " sec timeout)." );
1594 #endif
1595  if ( (m_AdminUser == "" ) || (m_AdminPass == "") )
1596  {
1597  if (m_AdminSocket)
1598  {
1599  m_AdminSocket->close();
1600  delete m_AdminSocket;
1601  m_AdminSocket = 0;
1602  SG_CONSOLE (SG_FGMS, SG_ALERT, "# Admin port disabled, please set user and password");
1603  }
1604  }
1605  if (! RunAsDaemon && AddCLI )
1606  { // Run admin CLI in foreground reading from stdin
1607  st_telnet* t = new st_telnet;
1608  t->Instance = this;
1609  t->Fd = 0;
1610  pthread_t th;
1611  pthread_create ( &th, NULL, &admin_helper, t );
1612  }
1613  //////////////////////////////////////////////////
1614  //
1615  // infinite listening loop
1616  //
1617  //////////////////////////////////////////////////
1618  while ( m_WantExit == false )
1619  {
1620  if (! m_Listening )
1621  {
1622  cout << "bummer 1!" << endl;
1623  return 1;
1624  }
1625  if (m_DataSocket == 0)
1626  {
1627  cout << "bummer 2!" << endl;
1628  return 2;
1629  }
1630  CurrentTime = time ( 0 );
1631  // Update some things every (default) 10 secondes
1632  if ( ( CurrentTime - LastTrackerUpdate ) >= m_UpdateTrackerFreq )
1633  {
1634  LastTrackerUpdate = time ( 0 );
1635  if ( m_PlayerList.Size() >0 )
1636  {
1637  // updates the position of the users
1638  // regularly (tracker)
1639  UpdateTracker ("" , "", "", LastTrackerUpdate, UPDATE );
1640  }
1641  if ( check_files() )
1642  {
1643  break;
1644  }
1645  } // position (tracker)
1646  errno = 0;
1647  ListenSockets[0] = m_DataSocket;
1648  ListenSockets[1] = m_TelnetSocket;
1649  ListenSockets[2] = m_AdminSocket;
1650  ListenSockets[3] = 0;
1651  Bytes = m_DataSocket->select ( ListenSockets, 0, m_PlayerExpires );
1652  if ( Bytes < 0 )
1653  { // error
1654  continue;
1655  }
1656  else if (Bytes == 0)
1657  { // timeout
1658  m_PlayerList.CheckTTL ();
1659  m_BlackList.CheckTTL ();
1660  continue;
1661  }
1662  if ( ListenSockets[0] > 0 )
1663  {
1664  // something on the wire (clients)
1665  Bytes = m_DataSocket->recvfrom ( Msg,MAX_PACKET_SIZE, 0, &SenderAddress );
1666  if ( Bytes <= 0 )
1667  {
1668  continue;
1669  }
1670  m_PacketsReceived++;
1671  HandlePacket ( ( char* ) &Msg, Bytes, SenderAddress );
1672  } // DataSocket
1673  else if ( ListenSockets[1] > 0 )
1674  {
1675  // something on the wire (telnet)
1676  netAddress TelnetAddress;
1677  m_TelnetReceived++;
1678  int Fd = m_TelnetSocket->accept ( &TelnetAddress );
1679  if ( Fd < 0 )
1680  {
1681  if ( ( errno != EAGAIN ) && ( errno != EPIPE ) )
1682  {
1683  SG_LOG ( SG_FGMS, SG_ALERT, "FG_SERVER::Loop() - " << strerror ( errno ) );
1684  }
1685  continue;
1686  }
1687  st_telnet* t = new st_telnet;
1688  t->Instance = this;
1689  t->Fd = Fd;
1690  pthread_t th;
1691  pthread_create ( &th, NULL, &telnet_helper, t );
1692  } // TelnetSocket
1693  else if ( ListenSockets[2] > 0 )
1694  {
1695  // something on the wire (admin port)
1696  netAddress AdminAddress;
1697  m_AdminReceived++;
1698  int Fd = m_AdminSocket->accept ( &AdminAddress );
1699  if ( Fd < 0 )
1700  {
1701  if ( ( errno != EAGAIN ) && ( errno != EPIPE ) )
1702  {
1703  SG_LOG ( SG_FGMS, SG_ALERT, "FG_SERVER::Loop() - " << strerror ( errno ) );
1704  }
1705  continue;
1706  }
1707  SG_LOG ( SG_FGMS, SG_ALERT, "FG_SERVER::Loop() - new Admin connection from "
1708  << AdminAddress.getHost());
1709  st_telnet* t = new st_telnet;
1710  t->Instance = this;
1711  t->Fd = Fd;
1712  pthread_t th;
1713  pthread_create ( &th, NULL, &admin_helper, t );
1714  } // TelnetSocket
1715  }
1716  return ( 0 );
1717 } // FG_SERVER::Loop()
1718 
1719 //////////////////////////////////////////////////////////////////////
1720 /**
1721  * @brief Set listening port for incoming clients
1722  */
1723 void
1726  int Port
1727 )
1728 {
1729  if ( Port != m_ListenPort )
1730  {
1731  m_ListenPort = Port; m_ReinitData = true;
1732  m_TelnetPort = m_ListenPort+1; m_ReinitTelnet = true;
1733  m_AdminPort = m_ListenPort+2; m_ReinitAdmin = true;
1734  }
1735 } // FG_SERVER::SetPort ( unsigned int iPort )
1736 
1737 //////////////////////////////////////////////////////////////////////
1738 /**
1739  * @brief Set listening port for telnets
1740  */
1741 void
1744  int Port
1745 )
1746 {
1747  if ( m_TelnetPort != Port )
1748  {
1749  m_TelnetPort = Port;
1750  m_ReinitTelnet = true;
1751  }
1752 } // FG_SERVER::SetTelnetPort ( unsigned int iPort )
1753 
1754 //////////////////////////////////////////////////////////////////////
1755 /**
1756  * @brief Set listening port for admin connections
1757  */
1758 void
1761  int Port
1762 )
1763 {
1764  if ( m_AdminPort != Port )
1765  {
1766  m_AdminPort = Port;
1767  m_ReinitAdmin = true;
1768  }
1769 } // FG_SERVER::SetAdminPort ( unsigned int iPort )
1770 
1771 //////////////////////////////////////////////////////////////////////
1772 /**
1773  * @brief Set User for admin connections
1774  */
1775 void
1778  string User
1779 )
1780 {
1781  m_AdminUser = User;
1782 } // FG_SERVER::SetAdminUser ( unsigned int iPort )
1783 
1784 //////////////////////////////////////////////////////////////////////
1785 /**
1786  * @brief Set Password for admin connections
1787  */
1788 void
1791  string Pass
1792 )
1793 {
1794  m_AdminPass = Pass;
1795 } // FG_SERVER::SetAdminPass ( unsigned int iPort )
1796 
1797 //////////////////////////////////////////////////////////////////////
1798 /**
1799  * @brief Set enable password for admin connections
1800  */
1801 void
1804  string Enable
1805 )
1806 {
1807  m_AdminEnable = Enable;
1808 } // FG_SERVER::SetAdminPass ( unsigned int iPort )
1809 
1810 //////////////////////////////////////////////////////////////////////
1811 /**
1812  * @brief Set time in seconds. if no packet arrives from a client
1813  * within this time, the connection is dropped.
1814  */
1815 void
1818  int Seconds
1819 )
1820 {
1821  m_PlayerExpires = Seconds;
1822 } // FG_SERVER::SetPlayerExpires ( int iSeconds )
1823 //////////////////////////////////////////////////////////////////////
1824 
1825 //////////////////////////////////////////////////////////////////////
1826 /**
1827  * @brief Set nautical miles two players must be apart to be out of reach
1828  */
1829 void
1832  int OutOfReach
1833 )
1834 {
1835  m_PlayerIsOutOfReach = OutOfReach;
1836 } // FG_SERVER::SetOutOfReach ( int iOutOfReach )
1837 //////////////////////////////////////////////////////////////////////
1838 
1839 //////////////////////////////////////////////////////////////////////
1840 /**
1841  * @brief Set the default loglevel
1842  */
1843 void
1846  int Facility,
1847  int Priority
1848 )
1849 {
1850  sglog().setLogLevels ( (sgDebugClass) Facility, (sgDebugPriority) Priority );
1851 } // FG_SERVER::SetLoglevel ()
1852 //////////////////////////////////////////////////////////////////////
1853 
1854 //////////////////////////////////////////////////////////////////////
1855 /**
1856  * @brief Set the logfile
1857  */
1858 void
1861  const std::string& LogfileName
1862 )
1863 {
1864  m_LogFileName = LogfileName;
1865  SG_LOG ( SG_FGMS, SG_ALERT,"# using logfile " << m_LogFileName );
1866  if ( m_LogFile.is_open() )
1867  {
1868  m_LogFile.close ();
1869  }
1870  m_LogFile.open ( m_LogFileName.c_str(), ios::out|ios::app );
1871  sglog().enable_with_date ( true );
1872  sglog().set_output ( m_LogFile );
1873 } // FG_SERVER::SetLogfile ( const std::string &LogfileName )
1874 //////////////////////////////////////////////////////////////////////
1875 
1876 //////////////////////////////////////////////////////////////////////
1877 /**
1878  * @brief Set if we are running as a Hubserver
1879  */
1880 void
1883  bool IamHUB
1884 )
1885 {
1886  m_IamHUB = IamHUB;
1887 } // FG_SERVER::SetHub ( int iLoglevel )
1888 //////////////////////////////////////////////////////////////////////
1889 
1890 //////////////////////////////////////////////////////////////////////
1891 /**
1892  * @brief Set the server name
1893  */
1894 void
1897  const std::string& ServerName
1898 )
1899 {
1900  m_ServerName = ServerName;
1901 } // FG_SERVER::SetServerName ( const std::string &ServerName )
1902 //////////////////////////////////////////////////////////////////////
1903 
1904 //////////////////////////////////////////////////////////////////////
1905 /**
1906  * @brief Set the address this server listens on
1907  */
1908 void
1911  const std::string& BindAddress
1912 )
1913 {
1914  m_BindAddress = BindAddress;
1915 } // FG_SERVER::SetBindAddress ( const std::string &BindAddress )
1916 //////////////////////////////////////////////////////////////////////
1917 
1918 //////////////////////////////////////////////////////////////////////
1919 /**
1920  * @brief Close sockets, logfile etc.
1921  */
1922 void
1924 ()
1925 {
1926  if ( ! m_IsParent )
1927  {
1928  return;
1929  }
1930  SG_LOG ( SG_FGMS, SG_ALERT, "FG_SERVER::Done() - exiting" );
1931  m_LogFile.close();
1932  if ( m_Listening == false )
1933  {
1934  return;
1935  }
1936  if ( m_TelnetSocket )
1937  {
1938  m_TelnetSocket->close();
1939  delete m_TelnetSocket;
1940  m_TelnetSocket = 0;
1941  }
1942  if ( m_AdminSocket )
1943  {
1944  m_AdminSocket->close();
1945  delete m_AdminSocket;
1946  m_AdminSocket = 0;
1947  }
1948  if ( m_DataSocket )
1949  {
1950  m_DataSocket->close();
1951  delete m_DataSocket;
1952  m_DataSocket = 0;
1953  }
1954  CloseTracker ();
1955  m_PlayerList.Unlock (); m_PlayerList.Clear ();
1956  m_RelayList.Unlock (); m_RelayList.Clear ();
1957  m_CrossfeedList.Unlock (); m_CrossfeedList.Clear ();
1958  m_BlackList.Unlock (); m_BlackList.Clear ();
1959  m_RelayMap.clear (); // clear(): is a std::map (NOT a FG_List)
1960  m_Listening = false;
1961 } // FG_SERVER::Done()
1962 //////////////////////////////////////////////////////////////////////
1963 
1964 //////////////////////////////////////////////////////////////////////
1965 /**
1966  * @brief Updates the remote tracker web server
1967  */
1968 int
1971  const string& Name,
1972  const string& Passwd,
1973  const string& Modelname,
1974  const time_t Timestamp,
1975  const int type
1976 )
1977 {
1978  char TimeStr[100];
1979  FG_Player CurrentPlayer;
1980  Point3D PlayerPosGeod;
1981  string Aircraft;
1982  string Message;
1983  tm* tm;
1984  if ( ! m_IsTracked || ( Name == "mpdummy" ) )
1985  {
1986  return ( 1 );
1987  }
1988  // Creates the UTC time string
1989  tm = gmtime ( & Timestamp );
1990  sprintf (
1991  TimeStr,
1992  "%04d-%02d-%02d %02d:%02d:%02d",
1993  tm->tm_year+1900,
1994  tm->tm_mon+1,
1995  tm->tm_mday,
1996  tm->tm_hour,
1997  tm->tm_min,
1998  tm->tm_sec
1999  );
2000  // Edits the aircraft name string
2001  size_t Index = Modelname.rfind ( "/" );
2002  if ( Index != string::npos )
2003  {
2004  Aircraft = Modelname.substr ( Index + 1 );
2005  }
2006  else
2007  {
2008  Aircraft = Modelname;
2009  }
2010  Index = Aircraft.find ( ".xml" );
2011  if ( Index != string::npos )
2012  {
2013  Aircraft.erase ( Index );
2014  }
2015  // Creates the message
2016  if ( type == CONNECT )
2017  {
2018  Message = "CONNECT ";
2019  Message += Name;
2020  Message += " ";
2021  Message += Passwd;
2022  Message += " ";
2023  Message += Aircraft;
2024  Message += " ";
2025  Message += TimeStr;
2026  // queue the message
2027  m_Tracker->AddMessage (Message);
2028 #ifdef ADD_TRACKER_LOG
2029  write_msg_log ( Message.c_str(), Message.size(), ( char* ) "IN: " ); // write message log
2030 #endif // #ifdef ADD_TRACKER_LOG
2031  m_TrackerConnect++; // count a CONNECT message queued
2032  return ( 0 );
2033  }
2034  else if ( type == DISCONNECT )
2035  {
2036  Message = "DISCONNECT ";
2037  Message += Name;
2038  Message += " ";
2039  Message += Passwd;
2040  Message += " ";
2041  Message += Aircraft;
2042  Message += " ";
2043  Message += TimeStr;
2044  // queue the message
2045  m_Tracker->AddMessage (Message);
2046 #ifdef ADD_TRACKER_LOG
2047  write_msg_log ( Message.c_str(), Message.size(), ( char* ) "IN: " ); // write message log
2048 #endif // #ifdef ADD_TRACKER_LOG
2049  m_TrackerDisconnect++; // count a DISCONNECT message queued
2050  return ( 0 );
2051  }
2052  // we only arrive here if type!=CONNECT and !=DISCONNECT
2053  size_t pilot_cnt = m_PlayerList.Size ();
2054  for (size_t i = 0; i < pilot_cnt; i++)
2055  {
2056  CurrentPlayer = m_PlayerList[i];
2057  if (CurrentPlayer.ID == FG_ListElement::NONE_EXISTANT)
2058  continue;
2059  if ((CurrentPlayer.IsLocal) && (CurrentPlayer.HasErrors == false))
2060  {
2061  sgCartToGeod ( CurrentPlayer.LastPos, PlayerPosGeod );
2062  Message = "POSITION ";
2063  Message += CurrentPlayer.Name;
2064  Message += " ";
2065  Message += CurrentPlayer.Passwd;
2066  Message += " ";
2067  Message += NumToStr ( PlayerPosGeod[Lat], 6 ) +" "; //lat
2068  Message += NumToStr ( PlayerPosGeod[Lon], 6 ) +" "; //lon
2069  Message += NumToStr ( PlayerPosGeod[Alt], 6 ) +" "; //alt
2070  Message += TimeStr;
2071  // queue the message
2072  m_Tracker->AddMessage (Message);
2073  m_TrackerPosition++; // count a POSITION messge queued
2074  }
2075  Message.erase ( 0 );
2076  } // while
2077  return ( 0 );
2078 } // UpdateTracker (...)
2079 //////////////////////////////////////////////////////////////////////
2080 
2081 //////////////////////////////////////////////////////////////////////
2082 /**
2083  * @brief Cleanly closes the tracker
2084  */
2085 void
2087 ()
2088 {
2089  if ( m_IsTracked )
2090  {
2091  if ( m_Tracker )
2092  {
2093  m_Tracker->WantExit = true;
2094  pthread_cond_signal ( &m_Tracker->condition_var ); // wake up the worker
2095  pthread_join (m_Tracker->GetThreadID(), 0);
2096  }
2097  m_Tracker = 0;
2098  m_IsTracked = false;
2099  }
2100 } // CloseTracker ( )
2101 //////////////////////////////////////////////////////////////////////
2102 
2103 //////////////////////////////////////////////////////////////////////
2104 /**
2105  * @brief Decide whether the relay is interested in full rate updates.
2106  * @see \ref server_out_of_reach config.
2107  * @param Relay
2108  * @param SendingPlayer
2109  * @retval true is within range
2110  */
2111 bool
2114  FG_ListElement& Relay,
2115  FG_Player& SendingPlayer
2116 )
2117 {
2118  FG_Player CurrentPlayer;
2119  size_t Cnt;
2120  Cnt = m_PlayerList.Size ();
2121  for (size_t i = 0; i < Cnt; i++)
2122  {
2123  CurrentPlayer = m_PlayerList[i];
2124  if (CurrentPlayer.ID == FG_ListElement::NONE_EXISTANT)
2125  continue;
2126  if ( ( CurrentPlayer.Address == Relay.Address )
2127  && ( Distance ( SendingPlayer.LastPos, CurrentPlayer.LastPos ) <= m_PlayerIsOutOfReach ) )
2128  {
2129  return true;
2130  }
2131  }
2132  return false;
2133 } // FG_SERVER::IsInRange()
2134 //////////////////////////////////////////////////////////////////////
2135 
unsigned int getPort() const
Return the port no as int.
Definition: netSocket.cxx:140
std::map< uint32_t, string >::iterator mT_RelayMapIt
Definition: fg_server.hxx:135
void setLogLevels(sgDebugClass c, sgDebugPriority p)
Set the global log class and priority level.
Definition: logstream.cxx:123
size_t mT_PositionData
Definition: fg_server.hxx:191
#define DEF_STAT_FILE
Definition: fg_server.cxx:78
The header sent as the first part of all mp message packets.
Definition: mpmessages.hxx:80
void set(const char *host, int port)
Definition: netSocket.cxx:73
size_t ID
The ID of this entry.
Definition: fg_list.hxx:57
Socket type.
Definition: netSocket.h:125
unsigned int getIP() const
Definition: netSocket.cxx:134
void SetAdminPort(int Port)
Set listening port for admin connections.
Definition: fg_server.cxx:1760
char Name[MAX_CALLSIGN_LEN]
Callsign used by the player.
Definition: mpmessages.hxx:101
#define DEF_EXIT_FILE
Definition: fg_server.cxx:72
bool AddCLI
Definition: fg_server.cxx:60
string Name
The callsign (or name)
Definition: fg_list.hxx:61
#define DEF_RESET_FILE
Definition: fg_server.cxx:75
bool IsKnownRelay(const netAddress &SenderAddress, size_t Bytes)
Check if the sender is a known relay.
Definition: fg_server.cxx:959
void close(void)
Definition: netSocket.cxx:419
size_t m_TrackerDisconnect
Definition: fg_server.hxx:195
void setHandle(int handle)
Definition: netSocket.cxx:217
The tracker class.
Definition: fg_tracker.hxx:47
size_t mT_BlackRejected
Definition: fg_server.hxx:190
void SigHUPHandler(int SigType)
If we receive a SIGHUP, reinit application.
Definition: main.cxx:603
size_t m_CrossFeedSent
Definition: fg_server.hxx:193
size_t m_TelnetReceived
Definition: fg_server.hxx:188
void CloseTracker()
Cleanly closes the tracker.
Definition: fg_server.cxx:2087
#define DISCONNECT
Definition: fg_tracker.hxx:37
size_t mT_PacketsInvalid
Definition: fg_server.hxx:190
FG_SERVER()
Constructor.
Definition: fg_server.cxx:165
void SetLogfile(const std::string &LogfileName)
Set the logfile.
Definition: fg_server.cxx:1860
size_t m_CrossFeedFailed
Definition: fg_server.hxx:193
int AddTracker(const string &Server, int Port, bool IsTracked)
Add a tracking server.
Definition: fg_server.cxx:914
void sgCartToGeod(const Point3D &CartPoint, Point3D &GeodPoint)
Convert a cartexian XYZ coordinate to a geodetic lat/lon/alt. This function is a copy of what's in Si...
void SetLog(int Facility, int Priority)
Set the default loglevel.
Definition: fg_server.cxx:1845
void Done()
Close sockets, logfile etc.
Definition: fg_server.cxx:1924
int Loop()
Send the messages to the tracker server.
Definition: fg_tracker.cxx:313
void AddRelay(const string &Server, int Port)
Insert a new relay server into internal list.
Definition: fg_server.cxx:825
bool DoUpdate
Definition: fg_list.hxx:124
string Origin
Definition: fg_list.hxx:100
const uint32_t MSG_MAGIC
The Magic value for message (currently FGFS). The magic is at the start of every packet and is used f...
Definition: mpmessages.hxx:49
const uint32_t PROTO_VER
The MP protocol version that is send with each packet (currently 1.1).
Definition: mpmessages.hxx:54
sgDebugPriority
Define the possible logging priorities (and their order).
Definition: debug_types.h:24
size_t mT_UnknownRelay
Definition: fg_server.hxx:191
#define DEF_SERVER_LOG
Definition: fg_server.cxx:63
xdr_data2_t position[3]
Position wrt the earth centered frame.
Definition: mpmessages.hxx:117
FG_SERVER * Instance
Definition: fg_server.hxx:222
bool RunAsDaemon
Flag whether instance is a Daemon.
Definition: fg_server.cxx:59
Represent a Player.
Definition: fg_list.hxx:97
void AddClient(const netAddress &Sender, char *Msg)
Insert a new client to internal list.
Definition: fg_server.cxx:741
void set_output(ostream &out)
Set the output stream.
Definition: logstream.hxx:302
#define SG_LOG(C, P, M)
Definition: logstream.hxx:412
size_t mT_TelnetReceived
Definition: fg_server.hxx:191
size_t m_PositionData
Definition: fg_server.hxx:186
void * HandleAdmin(int Fd)
Handle an admin session.
Definition: fg_server.cxx:535
xdr_data_t MsgLen
Absolute length of message.
Definition: mpmessages.hxx:89
string NumToStr(T n_Number, int n_Precision=2, int n_Base=10)
Convert a number to string.
Definition: fg_util.hxx:193
size_t m_PacketsReceived
Definition: fg_server.hxx:181
bool HasErrors
true if this client has errors
Definition: fg_list.hxx:120
~FG_SERVER()
Standard destructor.
Definition: fg_server.cxx:240
xdr_data_t ReplyPort
Player's receiver port.
Definition: mpmessages.hxx:99
string Error
in case of errors the reason is stored here
Definition: fg_list.hxx:116
bool PacketIsValid(int Bytes, T_MsgHdr *MsgHdr, const netAddress &SenderAddress)
Definition: fg_server.cxx:993
void SetTelnetPort(int Port)
Set listening port for telnets.
Definition: fg_server.cxx:1743
size_t Size()
Definition: fg_list.hxx:251
void * admin_helper(void *context)
Definition: fg_server.cxx:261
int loop()
Definition: libcli.cxx:1896
void UpdateRcvd(size_t bytes)
Definition: fg_list.cxx:147
xdr_data_t ReplyAddress
Player's receiver address.
Definition: mpmessages.hxx:94
void SetAdminUser(string User)
Set User for admin connections.
Definition: fg_server.cxx:1777
logstream & sglog()
Return the one and only logstream instance.
Definition: logstream.hxx:375
size_t m_TrackerConnect
Definition: fg_server.hxx:195
int UpdateTracker(const string &callsign, const string &passwd, const string &modelname, const time_t time, const int type)
Updates the remote tracker web server.
Definition: fg_server.cxx:1970
int Loop()
Main loop of the server.
Definition: fg_server.cxx:1576
size_t mT_RelayMagic
Definition: fg_server.hxx:192
vector< FG_Player >::iterator PlayerIt
Definition: fg_list.hxx:209
void SendToCrossfeed(char *Msg, int Bytes, const netAddress &SenderAddress)
Send message to all crossfeed servers. Crossfeed servers receive all traffic without condition...
Definition: fg_server.cxx:1074
xdr_data_t Version
Protocol version.
Definition: mpmessages.hxx:85
static int select(netSocket **reads, netSocket **writes, int timeout)
Definition: netSocket.cxx:489
int write_str(const char *str, int len)
Definition: netSocket.cxx:339
static char * stat_file
Definition: fg_server.cxx:96
xdr_data_t orientation[3]
Orientation wrt the earth centered frame, stored in the angle axis representation where the angle is ...
Definition: mpmessages.hxx:122
cisco like command line interface
Definition: fg_cli.hxx:44
void SetOutOfReach(int OutOfReach)
Set nautical miles two players must be apart to be out of reach.
Definition: fg_server.cxx:1831
size_t m_RelayMagic
Definition: fg_server.hxx:185
#define DEF_UPDATE_SECS
Definition: fg_server.cxx:67
Very possible impending problem.
Definition: debug_types.h:38
string Passwd
The password.
Definition: fg_list.hxx:104
Point3D LastOrientation
The last recorded orientation.
Definition: fg_list.hxx:110
sgDebugClass
Define the possible classes/categories of logging messages.
Definition: debug_types.h:8
#define POS_DATA_ID
ID of a "position" message, and the most trafficked.
Definition: mpmessages.hxx:57
struct st_telnet st_telnet
#define UPDATE
Definition: fg_tracker.hxx:38
void enable_with_date(bool enable)
Enable output of date.
Definition: logstream.hxx:348
void * HandleTelnet(int Fd)
Handle a telnet session. if a telnet connection is opened, this method outputs a list of all known cl...
Definition: fg_server.cxx:559
static char * exit_file
Definition: fg_server.cxx:94
void SetAdminEnable(string Enable)
Set enable password for admin connections.
Definition: fg_server.cxx:1803
void AddBlacklist(const string &DottedIP, const string &Reason, time_t Timeout=10)
Add an IP to the blacklist.
Definition: fg_server.cxx:933
static void * telnet_helper(void *context)
Definition: fg_server.cxx:247
void HandlePacket(char *sMsg, int Bytes, const netAddress &SenderAdress)
Handle client connections.
Definition: fg_server.cxx:1196
Implement everything necessary to become a daemon.
Definition: daemon.hxx:43
int netInit()
Definition: netSocket.cxx:585
void SetServerName(const std::string &ServerName)
Set the server name.
Definition: fg_server.cxx:1896
#define CONNECT
Definition: fg_tracker.hxx:36
Informatory messages.
Definition: debug_types.h:32
void SendToRelays(char *Msg, int Bytes, FG_Player &SendingPlayer)
Send message to all relay servers.
Definition: fg_server.cxx:1107
void AddBadClient(const netAddress &Sender, string &ErrorMsg, bool IsLocal, int Bytes)
If we receive bad data from a client, we add the client to the internal list anyway, but mark them as bad. But first we look if it isn't already there. Send an error message to the bad client.
Definition: fg_server.cxx:690
void SetHub(bool IamHUB)
Set if we are running as a Hubserver.
Definition: fg_server.cxx:1882
Represent a generic list element.
Definition: fg_list.hxx:47
void PrepareInit()
Do anything necessary to (re-) init the server used to handle kill -HUP.
Definition: fg_server.cxx:506
A Position Message.
Definition: mpmessages.hxx:108
int Init()
Basic initialization.
Definition: fg_server.cxx:290
size_t mT_CrossFeedFailed
Definition: fg_server.hxx:194
void AddCrossfeed(const string &Server, int Port)
Insert a new crossfeed server into internal list.
Definition: fg_server.cxx:881
static char * reset_file
Definition: fg_server.cxx:95
size_t m_TrackerPosition
Definition: fg_server.hxx:195
void DropClient(PlayerIt &CurrentPlayer)
Definition: fg_server.cxx:1150
xdr_data_t MsgId
Message identifier.
Definition: mpmessages.hxx:87
const std::string getHost() const
Create a string object representing an IP address. This is always a string of the form 'dd...
Definition: netSocket.cxx:123
Socket address, internet style.
Definition: netSocket.h:87
vector< FG_ListElement >::iterator ItList
Definition: fg_list.hxx:208
The Main fgms Class.
Definition: fg_server.hxx:55
bool IsInRange(FG_ListElement &Relay, FG_Player &SendingPlayer)
Decide whether the relay is interested in full rate updates.
Definition: fg_server.cxx:2113
size_t m_BlackRejected
Definition: fg_server.hxx:182
void write_msg_log(const char *msg, int len, char *src=0)
time_t LastSeen
timestamp of last seen packet from this element
Definition: fg_list.hxx:67
size_t mT_PacketsReceived
Definition: fg_server.hxx:190
cDaemon Myself
An instance of cDaemon.
Definition: fg_server.cxx:56
xdr_data_t Magic
Magic Value.
Definition: mpmessages.hxx:83
void SetAdminPass(string Pass)
Set Password for admin connections.
Definition: fg_server.cxx:1790
string ModelName
The model name.
Definition: fg_list.hxx:106
static char S[8][64]
Definition: crypt-win.c:163
void Show_Stats(void)
Show Stats.
Definition: fg_server.cxx:1437
void WantExit()
allow the Admin CLI to shut down fgms
Definition: fg_server.cxx:1564
size_t mT_CrossFeedSent
Definition: fg_server.hxx:194
size_t m_UnknownRelay
Definition: fg_server.hxx:184
bool IsLocal
true is this client is directly connected to this fgms instance
Definition: fg_list.hxx:112
void Set(const t_Point3D &X, const t_Point3D &Y, const t_Point3D &Z)
Definition: fg_geometry.cxx:74
static const size_t NONE_EXISTANT
Definition: fg_list.hxx:55
size_t m_NotPosData
Definition: fg_server.hxx:187
void SetBindAddress(const std::string &BindAddress)
Set the address this server listens on.
Definition: fg_server.cxx:1910
Possible impending problem.
Definition: debug_types.h:35
void * detach_tracker(void *vp)
Definition: fg_server.cxx:273
char Model[MAX_MODEL_NAME_LEN]
Name of the aircraft model.
Definition: mpmessages.hxx:111
netAddress Address
The network address of this element.
Definition: fg_list.hxx:63
size_t m_PacketsInvalid
Definition: fg_server.hxx:183
size_t mT_NotPosData
Definition: fg_server.hxx:192
PlayerList m_PlayerList
Definition: fg_server.hxx:169
Point3D LastPos
The last recorded position.
Definition: fg_list.hxx:108
float Distance(const Point3D &P1, const Point3D &P2)
Calculate distance of clients.
void SetPlayerExpires(int Seconds)
Set time in seconds. if no packet arrives from a client within this time, the connection is dropped...
Definition: fg_server.cxx:1817
int check_files()
Check stats file etc.
Definition: fg_server.cxx:1501
void SetDataPort(int Port)
Set listening port for incoming clients.
Definition: fg_server.cxx:1725