fgms 0.11.8
The
FlightGear MultiPlayer Server
project
fg_tracker.cxx
Go to the documentation of this file.
1 /**
2  * @file fg_tracker.cxx
3  * @author (c) 2006 Julien Pierru
4  * @author (c) 2012 Rob Dosogne ( FreeBSD friendly )
5  *
6  * @todo Pete To make a links here to the config and explain a bit
7  *
8  */
9 
10 //////////////////////////////////////////////////////////////////////
11 //
12 // server tracker for FlightGear
13 // (c) 2006 Julien Pierru
14 // (c) 2012 Rob Dosogne ( FreeBSD friendly )
15 //
16 // Licenced under GPL
17 //
18 //////////////////////////////////////////////////////////////////////
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #include <iostream>
24 #include <fstream>
25 #include <list>
26 #include <string>
27 #include <string.h>
28 #include <sstream>
29 #ifdef _MSC_VER
30 #include <sys/timeb.h>
31 #else
32 #include <errno.h>
33 #include <time.h>
34 #include <stdint.h>
35 #include <unistd.h>
36 #include <sys/ipc.h>
37 #include <sys/msg.h>
38 #include <sys/types.h>
39 #include <signal.h>
40 #endif
41 #include <unistd.h>
42 #include <stdio.h>
43 #include "fg_common.hxx"
44 #include "fg_tracker.hxx"
45 #include "fg_util.hxx"
47 #include "daemon.hxx"
48 #include <libcli/debug.hxx>
49 
50 #ifndef DEF_CONN_SECS
51 #define DEF_CONN_SECS 30
52 #endif
53 
55 
56 #if defined(_MSC_VER) || defined(__MINGW32__)
57 /* windows work around for gettimeofday() */
58 int gettimeofday(struct timeval* tp, void* tzp)
59 {
60  struct __timeb64 tm;
61  _ftime64_s(&tm); // Time since Epoch, midnight (00:00:00), January 1, 1970, UTC.
62  tp->tv_sec = tm.time;
63  tp->tv_usec = 1000000 * tm.millitm; // milliseconds to nanoseconds
64  return 0;
65 }
66 #endif /* #if defined(_MSC_VER) || defined(__MINGW32__) */
67 
68 //////////////////////////////////////////////////////////////////////
69 /**
70  * @brief Initialize to standard values
71  * @param port
72  * @param server ip or domain
73  * @param id what is id? -- todo --
74  */
75 FG_TRACKER::FG_TRACKER ( int port, string server, int id )
76 {
78  m_TrackerServer = server;
79  m_TrackerSocket = 0;
80  SG_LOG ( SG_FGTRACKER, SG_DEBUG, "# FG_TRACKER::FG_TRACKER:"
81  << m_TrackerServer << ", Port: " << m_TrackerPort
82  );
83  LastSeen = 0;
84  LastSent = 0;
85  BytesSent = 0;
86  BytesRcvd = 0;
87  PktsSent = 0;
88  PktsRcvd = 0;
89  LostConnections = 0;
90  LastConnected = 0;
91  WantExit = false;
92  m_connected = false;
93 } // FG_TRACKER()
94 
95 //////////////////////////////////////////////////////////////////////
96 /**
97  * @brief xTerminate the tracker
98  */
100 {
101  pthread_mutex_unlock ( &msg_mutex ); // give up the lock
102  WriteQueue ();
103  msg_queue.clear ();
104  if ( m_TrackerSocket )
105  {
107  delete m_TrackerSocket;
108  m_TrackerSocket = 0;
109  }
110 } // ~FG_TRACKER()
111 //////////////////////////////////////////////////////////////////////
112 
113 //////////////////////////////////////////////////////////////////////
114 pthread_t
116 ()
117 {
118  return MyThreadID;
119 }
120 //////////////////////////////////////////////////////////////////////
121 
122 //////////////////////////////////////////////////////////////////////
123 void
125 {
126  VI CurrentMessage;
127  ofstream queue_file;
128  pthread_mutex_lock ( &msg_mutex ); // set the lock
129  if ( msg_queue.size() == 0 )
130  {
131  pthread_mutex_unlock ( &msg_mutex ); // give up the lock
132  return;
133  }
134  queue_file.open ( "queue_file", ios::out|ios::app );
135  if ( ! queue_file )
136  {
137  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::WriteQueue: "
138  << "could not open queuefile!" );
139  pthread_mutex_unlock ( &msg_mutex ); // give up the lock
140  return;
141  }
142  CurrentMessage = msg_queue.begin(); // get first message
143  while ( CurrentMessage != msg_queue.end() )
144  {
145  queue_file << ( *CurrentMessage ) << endl;
146  CurrentMessage++;
147  }
148  pthread_mutex_unlock ( &msg_mutex ); // set the lock
149  queue_file.close ();
150 }
151 //////////////////////////////////////////////////////////////////////
152 
153 //////////////////////////////////////////////////////////////////////
154 void
156 (
157  const string& message
158 )
159 {
160  pthread_mutex_lock ( &msg_mutex ); // acquire the lock
161 #if 0
162  if ( msg_queue.size () > 512 )
163  {
164  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER queue full, writeing backlog..." );
165  pthread_mutex_unlock ( &msg_mutex ); // give up the lock
166  WriteQueue ();
167  msg_queue.clear();
168  }
169 #endif
170  msg_queue.push_back ( message.c_str() ); // queue the message
171  pthread_cond_signal ( &condition_var ); // wake up the worker
172  pthread_mutex_unlock ( &msg_mutex ); // give up the lock
173 } // FG_TRACKER::AddMessage()
174 //////////////////////////////////////////////////////////////////////
175 
176 //////////////////////////////////////////////////////////////////////
177 int
178 FG_TRACKER::TrackerWrite ( const string& str )
179 {
180  size_t l = str.size() + 1;
181  LastSent = time ( 0 );
182  errno = 0;
183  int s = -1;
184  while ( s < 0 )
185  {
186  s = m_TrackerSocket->send ( str.c_str(), l, MSG_NOSIGNAL );
187  if ( s < 0 )
188  {
189  if ( ( errno == EAGAIN ) || ( errno == EWOULDBLOCK ) )
190  {
191  continue;
192  }
193  m_connected = false;
194  LostConnections++;
195  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::TrackerWrite: "
196  << "lost connection to server"
197  );
198  return -1;
199  }
200  }
201  BytesSent += s;
202  PktsSent++;
203  return s;
204 }
205 //////////////////////////////////////////////////////////////////////
206 
207 //////////////////////////////////////////////////////////////////////
208 void
209 FG_TRACKER::ReplyToServer ( const string& str )
210 {
211  string reply;
212  if ( str == "OK" )
213  {
214  // set timeout time to 0
215  return;
216  }
217  else if ( str == "PING" )
218  {
219  reply = "PONG STATUS OK";
220  if ( TrackerWrite ( reply ) < 0 )
221  {
222  return;
223  }
224  SG_LOG ( SG_FGTRACKER, SG_DEBUG, "# FG_TRACKER::ReplyToServer: "
225  << "PING from server received"
226  );
227  return;
228  }
229  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::ReplyToServer: "
230  << "Responce not recognized. Msg: '" << str
231  );
232 }
233 //////////////////////////////////////////////////////////////////////
234 
235 //////////////////////////////////////////////////////////////////////
236 void
238 {
239 //////////////////////////////////////////////////
240 // FIXME: this needs a better mechanism.
241 // This is fire and forget, and forgets
242 // messages if the server is not reachable
243 //////////////////////////////////////////////////
244  ifstream queue_file;
245  queue_file.open ( "queue_file" );
246  if ( ! queue_file )
247  {
248  return;
249  }
250  string line;
251  int line_number = 0;
252  while ( getline ( queue_file, line, '\n' ) )
253  {
254  line_number++;
255  pthread_mutex_lock ( &msg_mutex ); // set the lock
256  msg_queue.push_back ( line ); // queue the message
257  pthread_mutex_unlock ( &msg_mutex ); // give up the lock
258 #if 0
259  if ( TrackerWrite ( line ) < 0 )
260  {
261  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::FG_TRACKER: "
262  << "lost connection while sending queue after " << line_number
263  << " entries"
264  );
265  m_connected = false;
266  queue_file.close();
267  return;
268  }
269  TrackerRead ();
270 #endif
271  }
272  queue_file.close();
273  remove ( "queue_file" );
274 }
275 //////////////////////////////////////////////////////////////////////
276 
277 //////////////////////////////////////////////////////////////////////
278 void
280 {
281  char res[MSGMAXLINE]; /*Msg from/to server*/
282  errno = 0;
283  int i = m_TrackerSocket->recv ( res, MSGMAXLINE, MSG_NOSIGNAL );
284  if ( i <= 0 )
285  {
286  // error
287  if ( ( errno != EAGAIN ) && ( errno != EWOULDBLOCK ) && ( errno != EINTR ) )
288  {
289  m_connected = false;
290  LostConnections++;
291  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::TrackerRead: "
292  << "lost connection to server"
293  );
294  }
295  }
296  else
297  {
298  // something received from tracker server
299  res[i]='\0';
300  LastSeen = time ( 0 );
301  PktsRcvd++;
302  BytesRcvd += i;
303  ReplyToServer ( res );
304  }
305 }
306 //////////////////////////////////////////////////////////////////////
307 
308 //////////////////////////////////////////////////////////////////////
309 /**
310 * @brief Send the messages to the tracker server
311 */
312 int
314 {
315  VI CurrentMessage;
316  size_t length;
317  string Msg;
318  int MsgCounter;
319  pthread_mutex_init ( &msg_mutex, 0 );
320  pthread_cond_init ( &condition_var, 0 );
321  length = 0;
322  MsgCounter = 0;
323  MyThreadID = pthread_self();
324 #ifdef WIN32
325  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::Loop: "
326  << "started, thread ID " << MyThreadID.p
327  );
328 #else
329  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::Loop: "
330  << "started, thread ID " << MyThreadID
331  );
332 #endif
333  /*Infinite loop*/
334  while ( ! WantExit )
335  {
336  if (! m_connected)
337  {
338  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::Loop: "
339  << "trying to connect"
340  );
341  m_connected = Connect();
342  if ( ! m_connected )
343  {
344  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::Loop: "
345  << "not connected, will sleep for " << tracker_conn_secs << " seconds"
346  );
347  struct timeval now;
348  struct timespec timeout;
349  gettimeofday(&now, 0);
350  timeout.tv_sec = now.tv_sec + tracker_conn_secs;
351  timeout.tv_nsec = now.tv_usec * 1000;
352  pthread_mutex_lock ( &msg_mutex );
353  pthread_cond_timedwait ( &condition_var, &msg_mutex, &timeout );
354  pthread_mutex_unlock ( &msg_mutex );
355  continue;
356  }
357  ReadQueue (); // read backlog, if any
358  }
359  pthread_mutex_lock ( &msg_mutex );
360  length = msg_queue.size ();
361  pthread_mutex_unlock ( &msg_mutex );
362  if (length == 0)
363  {
364  // wait for data
365  pthread_mutex_lock ( &msg_mutex );
366  pthread_cond_wait ( &condition_var, &msg_mutex );
367  length = msg_queue.size ();
368  pthread_mutex_unlock ( &msg_mutex );
369  }
370  while ( length && m_connected )
371  {
372  pthread_mutex_lock ( &msg_mutex );
373  CurrentMessage = msg_queue.begin(); // get first message
374  Msg = ( *CurrentMessage ).c_str();
375  CurrentMessage = msg_queue.erase ( CurrentMessage );
376  length = msg_queue.size ();
377  pthread_mutex_unlock ( &msg_mutex );
378 #ifdef ADD_TRACKER_LOG
379  write_msg_log ( Msg.c_str(), Msg.size(), ( char* ) "OUT: " );
380 #endif // #ifdef ADD_TRACKER_LOG
381  SG_LOG ( SG_FGTRACKER, SG_DEBUG, "# FG_TRACKER::Loop: "
382  << "sending msg " << Msg.size() << " bytes: " << Msg
383  );
384  if ( TrackerWrite ( Msg ) < 0 )
385  {
386  AddMessage ( Msg ); // requeue message
387  length = 0;
388  break;
389  }
390  MsgCounter++;
391  if ( MsgCounter == 25 )
392  {
393  sleep ( 1 ); // give tracker server some time to write data
394  MsgCounter = 0;
395  }
396  Msg = "";
397  TrackerRead ();
398  }
399  }
400  return ( 0 );
401 } // Loop ()
402 //////////////////////////////////////////////////////////////////////
403 
404 //////////////////////////////////////////////////////////////////////
405 //
406 // (Re)connect the tracker to its server
407 // RETURN: true = success, false = failed
408 //
409 //////////////////////////////////////////////////////////////////////
410 bool
412 {
413  if ( m_TrackerSocket )
414  {
416  delete m_TrackerSocket;
417  m_TrackerSocket = 0;
418  }
419  m_TrackerSocket = new netSocket();
420  SG_LOG ( SG_FGTRACKER, SG_DEBUG, "# FG_TRACKER::Connect: "
421  << "Server: " << m_TrackerServer << ", Port: " << m_TrackerPort );
422  if ( m_TrackerSocket->open ( true ) == false )
423  {
424  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::Connect: "
425  << "Can't get socket..."
426  );
427  delete m_TrackerSocket;
428  m_TrackerSocket = 0;
429  return false;
430  }
431  if ( m_TrackerSocket->connect ( m_TrackerServer.c_str(), m_TrackerPort ) < 0 )
432  {
433  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::Connect: "
434  << "Connect failed!"
435  );
436  delete m_TrackerSocket;
437  m_TrackerSocket = 0;
438  return false;
439  }
440  m_TrackerSocket->setBlocking ( false );
441  SG_LOG ( SG_FGTRACKER, SG_ALERT, "# FG_TRACKER::Connect: "
442  << "success"
443  );
444  LastConnected = time ( 0 );
445  m_TrackerSocket->write_char ( '\0' );
446  sleep ( 2 );
447  TrackerWrite ( "NOWAIT" );
448  SG_LOG ( SG_FGTRACKER, SG_DEBUG, "# FG_TRACKER::Connect: "
449  << "Written 'NOWAIT'"
450  );
451  sleep ( 1 );
452  return true;
453 } // Connect ()
454 
455 //////////////////////////////////////////////////////////////////////
456 /**
457  * @brief Signal handling
458  * @param s int with the signal
459  */
460 void
461 signal_handler ( int s )
462 {
463 #ifndef _MSC_VER
464  switch ( s )
465  {
466  case 1:
467  printf ( "SIGHUP received, exiting...\n" );
468  exit ( 0 );
469  break;
470  case 2:
471  printf ( "SIGINT received, exiting...\n" );
472  exit ( 0 );
473  break;
474  case 3:
475  printf ( "SIGQUIT received, exiting...\n" );
476  break;
477  case 4:
478  printf ( "SIGILL received\n" );
479  break;
480  case 5:
481  printf ( "SIGTRAP received\n" );
482  break;
483  case 6:
484  printf ( "SIGABRT received\n" );
485  break;
486  case 7:
487  printf ( "SIGBUS received\n" );
488  break;
489  case 8:
490  printf ( "SIGFPE received\n" );
491  break;
492  case 9:
493  printf ( "SIGKILL received\n" );
494  exit ( 0 );
495  break;
496  case 10:
497  printf ( "SIGUSR1 received\n" );
498  break;
499  case 11:
500  printf ( "SIGSEGV received. Exiting...\n" );
501  exit ( 1 );
502  break;
503  case 12:
504  printf ( "SIGUSR2 received\n" );
505  break;
506  case 13:
507  printf ( "SIGPIPE received. Connection Error.\n" );
508  break;
509  case 14:
510  printf ( "SIGALRM received\n" );
511  break;
512  case 15:
513  printf ( "SIGTERM received\n" );
514  exit ( 0 );
515  break;
516  case 16:
517  printf ( "SIGSTKFLT received\n" );
518  break;
519  case 17:
520  printf ( "SIGCHLD received\n" );
521  break;
522  case 18:
523  printf ( "SIGCONT received\n" );
524  break;
525  case 19:
526  printf ( "SIGSTOP received\n" );
527  break;
528  case 20:
529  printf ( "SIGTSTP received\n" );
530  break;
531  case 21:
532  printf ( "SIGTTIN received\n" );
533  break;
534  case 22:
535  printf ( "SIGTTOU received\n" );
536  break;
537  case 23:
538  printf ( "SIGURG received\n" );
539  break;
540  case 24:
541  printf ( "SIGXCPU received\n" );
542  break;
543  case 25:
544  printf ( "SIGXFSZ received\n" );
545  break;
546  case 26:
547  printf ( "SIGVTALRM received\n" );
548  break;
549  case 27:
550  printf ( "SIGPROF received\n" );
551  break;
552  case 28:
553  printf ( "SIGWINCH received\n" );
554  break;
555  case 29:
556  printf ( "SIGIO received\n" );
557  break;
558  case 30:
559  printf ( "SIGPWR received\n" );
560  break;
561  default:
562  printf ( "signal %d received\n",s );
563  }
564 #endif
565 }
566 
567 // eof - fg_tracker.cxx
568 //////////////////////////////////////////////////////////////////////
#define DEF_CONN_SECS
Definition: fg_tracker.cxx:51
pthread_cond_t condition_var
Definition: fg_tracker.hxx:103
uint64_t PktsRcvd
Definition: fg_tracker.hxx:115
size_t LostConnections
Definition: fg_tracker.hxx:116
netSocket * m_TrackerSocket
Definition: fg_tracker.hxx:98
Socket type.
Definition: netSocket.h:125
int TrackerWrite(const string &str)
Definition: fg_tracker.cxx:178
~FG_TRACKER()
xTerminate the tracker
Definition: fg_tracker.cxx:99
pthread_t GetThreadID()
Definition: fg_tracker.cxx:116
#define MSGMAXLINE
Definition: fg_common.hxx:180
void close(void)
Definition: netSocket.cxx:419
vMSG msg_queue
Definition: fg_tracker.hxx:104
void AddMessage(const string &message)
Definition: fg_tracker.cxx:156
uint64_t PktsSent
Definition: fg_tracker.hxx:114
#define MSG_NOSIGNAL
Definition: netSocket.cxx:62
bool m_connected
Definition: fg_tracker.hxx:97
time_t LastSent
Definition: fg_tracker.hxx:111
int Loop()
Send the messages to the tracker server.
Definition: fg_tracker.cxx:313
void WriteQueue()
Definition: fg_tracker.cxx:124
void ReplyToServer(const string &str)
Definition: fg_tracker.cxx:209
time_t LastSeen
Definition: fg_tracker.hxx:110
Stream based logging mechanism.
bool open(bool stream=true)
Definition: netSocket.cxx:224
#define SG_LOG(C, P, M)
Definition: logstream.hxx:412
int send(const void *buffer, int size, int flags=0)
Definition: netSocket.cxx:371
void signal_handler(int s)
Signal handling.
Definition: fg_tracker.cxx:461
int m_TrackerPort
Definition: fg_tracker.hxx:95
pthread_mutex_t msg_mutex
Definition: fg_tracker.hxx:102
int tracker_conn_secs
Definition: fg_tracker.cxx:54
int recv(void *buffer, int size, int flags=0)
Definition: netSocket.cxx:403
FG_TRACKER(int port, string server, int id)
Initialize to standard values.
Definition: fg_tracker.cxx:75
void ReadQueue()
Definition: fg_tracker.cxx:237
string m_TrackerServer
Definition: fg_tracker.hxx:96
int connect(const char *host, int port)
Definition: netSocket.cxx:329
uint64_t BytesRcvd
Definition: fg_tracker.hxx:113
static char * port
Definition: server.c:69
Very possible impending problem.
Definition: debug_types.h:38
time_t LastConnected
Definition: fg_tracker.hxx:109
void setBlocking(bool blocking)
Definition: netSocket.cxx:233
Less frequent debug type messages.
Definition: debug_types.h:29
int write_char(const char &c)
Definition: netSocket.cxx:366
pthread_t MyThreadID
Definition: fg_tracker.hxx:117
void write_msg_log(const char *msg, int len, char *src=0)
t_Point3D length(const Point3D &P)
Return the length of P.
bool Connect()
Definition: fg_tracker.cxx:411
uint64_t BytesSent
Definition: fg_tracker.hxx:112
vMSG::iterator VI
Definition: fg_tracker.hxx:101
void TrackerRead()
Definition: fg_tracker.cxx:279