fgms 0.11.8
The
FlightGear MultiPlayer Server
project
fg_list.hxx
Go to the documentation of this file.
1 /**
2  * @file fg_list.hxx
3  * @author Oliver Schroeder
4  */
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License as
8 // published by the Free Software Foundation; either version 2 of the
9 // License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, U$
19 //
20 // Copyright (C) 2005-2013 Oliver Schroeder
21 //
22 
23 /**
24  * @file fg_list.hxx
25  * @author Oliver Schroeder
26  *
27  * Implementation of a thread-safe list.
28  */
29 
30 #if !defined FG_LIST_HXX
31 #define FG_LIST_HXX
32 
33 #include <string>
34 #include <vector>
35 #include <plib/netSocket.h>
36 #include <pthread.h>
37 #include <fg_geometry.hxx>
38 #include <fg_common.hxx>
39 
40 
41 //////////////////////////////////////////////////////////////////////
42 /**
43  * @class FG_ListElement
44  * @brief Represent a generic list element
45  *
46  */
48 {
49 public:
50  /** every element has a a name */
51  FG_ListElement ( const string& Name );
52  FG_ListElement ( const FG_ListElement& P );
53  ~FG_ListElement ();
54  /** mark a nonexisting element */
55  static const size_t NONE_EXISTANT;
56  /** @brief The ID of this entry */
57  size_t ID;
58  /** @brief The Timeout of this entry */
59  time_t Timeout;
60  /** @brief The callsign (or name) */
61  string Name;
62  /** @brief The network address of this element */
64  /** @brief The time this entry was added to the list */
65  time_t JoinTime;
66  /** @brief timestamp of last seen packet from this element */
67  time_t LastSeen;
68  /** @brief timestamp of last sent packet to this element */
69  time_t LastSent;
70  /** @brief Count of packets recieved from client */
71  uint64_t PktsRcvd;
72  /** @brief Count of packets sent to client */
73  uint64_t PktsSent;
74  /** @brief Count of bytes recieved from client */
75  uint64_t BytesRcvd;
76  /** @brief Count of bytes sent to client */
77  uint64_t BytesSent;
78  void operator = ( const FG_ListElement& P );
79  virtual bool operator == ( const FG_ListElement& P );
80  void UpdateSent ( size_t bytes );
81  void UpdateRcvd ( size_t bytes );
82 protected:
83  FG_ListElement ();
84  void assign ( const FG_ListElement& P );
85 }; // FG_ListElement
86 
87 //////////////////////////////////////////////////////////////////////
88 /**
89  * @class FG_Player
90  * @brief Represent a Player
91  *
92  * Player objects are stored in the FG_SERVER::m_PlayerList
93  * They are created and added in FG_SERVER::AddClient
94  * They are dropped with FG_SERVER::DropClient after expiry time
95  * Clients are added even if they have bad data, see FG_SERVER::AddBadClient
96  */
97 class FG_Player : public FG_ListElement
98 {
99 public:
100  string Origin;
101  /** @brief The password
102  * @warning This is not currently used
103  */
104  string Passwd;
105  /** @brief The model name */
106  string ModelName;
107  /** @brief The last recorded position */
109  /** @brief The last recorded orientation */
111  /** @brief \b true is this client is directly connected to this \ref fgms instance */
112  bool IsLocal;
113  /** @brief in case of errors the reason is stored here
114  * @see FG_SERVER::AddBadClient
115  */
116  string Error; // in case of errors
117  /** @brief \b true if this client has errors
118  * @see FG_SERVER::AddBadClient
119  */
120  bool HasErrors;
121  /** when did we sent updates of this player to inactive relays */
123  /** \b true if we need to send updates to inactive relays */
124  bool DoUpdate;
125  FG_Player ();
126  FG_Player ( const string& Name );
127  FG_Player ( const FG_Player& P);
128  ~FG_Player ();
129  void operator = ( const FG_Player& P );
130  virtual bool operator == ( const FG_Player& P );
131 private:
132  void assign ( const FG_Player& P );
133 }; // FG_Player
134 
135 /**
136  * @class mT_FG_List
137  * @brief a generic list implementation for fgms
138  *
139  */
140 template <class T>
142 {
143 public:
144  typedef vector<T> ListElements;
145  typedef typename vector<T>::iterator ListIterator;
146  /** constructor, must supply a Name */
147  mT_FG_List ( const string& Name );
148  ~mT_FG_List ();
149  /** return the number of elements in this list */
150  size_t Size ();
151  /** delete all elements of this list */
152  void Clear ();
153  /** add an element to this list */
154  size_t Add ( T& Element, time_t TTL );
155  /** Check entries for expired TTL */
156  void CheckTTL ();
157  /** delete an element of this list */
158  ListIterator Delete ( const ListIterator& Element );
159  /** find an element by its IP address */
160  ListIterator Find ( const netAddress& Address, const string& Name = "" );
161  /** find an element by its Name */
162  ListIterator FindByName ( const string& Name = "" );
163  /** find an element by its ID */
164  ListIterator FindByID ( size_t ID );
165  /** return an iterator of the first element */
166  ListIterator Begin ();
167  /** iterator of the end of the list */
168  ListIterator End ();
169  /** update sent counter of an element and of the list */
170  void UpdateSent ( ListIterator& Element, size_t bytes );
171  /** update receive counter of an element and of the list */
172  void UpdateRcvd ( ListIterator& Element, size_t bytes );
173  /** update sent counter of the list */
174  void UpdateSent ( size_t bytes );
175  /** update receive counter of the list */
176  void UpdateRcvd ( size_t bytes );
177  /** thread lock the list */
178  void Lock();
179  /** thread unlock the list */
180  void Unlock();
181  /** return a copy of an element at position x (thread safe) */
182  T operator []( const size_t& Index );
183  /** @brief maximum entries this list ever had */
184  size_t MaxID;
185  /** @brief Count of packets recieved from client */
186  uint64_t PktsRcvd;
187  /** @brief Count of packets sent to client */
188  uint64_t PktsSent;
189  /** @brief Count of bytes recieved from client */
190  uint64_t BytesRcvd;
191  /** @brief Count of bytes sent to client */
192  uint64_t BytesSent;
193  /** the name (or description) of this element */
194  string Name;
195 private:
196  /** @brief mutex for thread safty */
197  pthread_mutex_t m_ListMutex;
198  /** @brief timestamp of last cleanup */
199  time_t LastRun;
200  /** do not allow standard constructor */
201  mT_FG_List ();
202  /** the actual storage of elements */
203  ListElements Elements;
204 };
205 
208 typedef vector<FG_ListElement>::iterator ItList;
209 typedef vector<FG_Player>::iterator PlayerIt;
210 
211 //////////////////////////////////////////////////////////////////////
212 /**
213  *
214  * construct an element and initialise counters
215  */
216 template <class T>
218 (
219  const string& Name
220 )
221 {
222  pthread_mutex_init ( &m_ListMutex, 0 );
223  this->Name = Name;
224  PktsSent = 0;
225  BytesSent = 0;
226  PktsRcvd = 0;
227  BytesRcvd = 0;
228 }
229 //////////////////////////////////////////////////////////////////////
230 
231 //////////////////////////////////////////////////////////////////////
232 template <class T>
234 ()
235 {
236  Clear ();
237 }
238 //////////////////////////////////////////////////////////////////////
239 
240 //////////////////////////////////////////////////////////////////////
241 /** NOT thread safe
242  *
243  * Return the number of elements of this list.
244  * If working with threads make sure to * use Lock() and Unlock()
245  * @see Lock()
246  * @see Unlock()
247  */
248 template <class T>
249 size_t
251 ()
252 {
253  return Elements.size ();
254 }
255 //////////////////////////////////////////////////////////////////////
256 
257 //////////////////////////////////////////////////////////////////////
258 /** thread safe
259  *
260  * Add an element to the list
261  * @param Element the FG_ListElement to add
262  * @param TTL automatic expiry of the element (time-to-live)
263  * @see Find()
264  */
265 template <class T>
266 size_t
268 (
269  T& Element,
270  time_t TTL
271 )
272 {
273  this->MaxID++;
274  Element.ID = this->MaxID;
275  Element.Timeout = TTL;
276 // pthread_mutex_lock ( & m_ListMutex );
277  Elements.push_back ( Element );
278 // pthread_mutex_unlock ( & m_ListMutex );
279  return this->MaxID;
280 }
281 //////////////////////////////////////////////////////////////////////
282 
283 //////////////////////////////////////////////////////////////////////
284 /** thread safe
285  *
286  * Delete an entry from the list
287  * @param Element iterator pointing to the element to delete
288  */
289 template <class T>
290 typename vector<T>::iterator
292 (
293  const ListIterator& Element
294 )
295 {
296  ListIterator E;
297  pthread_mutex_lock ( & m_ListMutex );
298  E = Elements.erase ( Element );
299  pthread_mutex_unlock ( & m_ListMutex );
300  return (E);
301 }
302 //////////////////////////////////////////////////////////////////////
303 
304 //////////////////////////////////////////////////////////////////////
305 /** NOT thread safe
306  *
307  * Find an element by IP-address (and optionally Name). Automatically
308  * removes entries which TTL is expired, with the exception of the 'users'
309  * list which entries are deleted in FG_SERVER::HandlePacket()
310  * @param Address IP address of the element
311  * @param Name The name (or description) of the element
312  * @return iterator pointing to the found element, or End() if element
313  * could not be found
314  */
315 template <class T>
316 typename vector<T>::iterator
318 (
319  const netAddress& Address,
320  const string& Name
321 )
322 {
323  ListIterator Element;
324  ListIterator RetElem;
325 
326  this->LastRun = time (0);
327  RetElem = Elements.end();
328  Element = Elements.begin();
329  while (Element != Elements.end())
330  {
331  if (Element->Address == Address)
332  {
333  if (Name != "")
334  { // additionally look for matching name
335  if (Element->Name == Name)
336  {
337  Element->LastSeen = this->LastRun;
338  RetElem = Element;
339  }
340  }
341  else
342  {
343  Element->LastSeen = this->LastRun;
344  RetElem = Element;
345  }
346  }
347  else
348  {
349  if ((Element->Timeout == 0) || (this->Name == "Users"))
350  { // never times out
351  Element++;
352  continue;
353  }
354  if ( (this->LastRun - Element->LastSeen) > Element->Timeout )
355  {
357  this->Name << ": TTL exceeded for "
358  << Element->Name << " "
359  << Element->Address.getHost() << " "
360  << "after " << diff_to_days (Element->LastSeen - Element->JoinTime)
361  );
362  Element = Elements.erase (Element);
363  continue;
364  }
365  }
366  Element++;
367  }
368  return RetElem;
369 }
370 //////////////////////////////////////////////////////////////////////
371 
372 //////////////////////////////////////////////////////////////////////
373 /** NOT thread safe
374  *
375  * Find an element by Name.
376  * @param Name The name (or description) of the element
377  * @return iterator pointing to the found element, or End() if element
378  * could not be found
379  */
380 template <class T>
381 typename vector<T>::iterator
383 (
384  const string& Name
385 )
386 {
387  ListIterator Element;
388  ListIterator RetElem;
389 
390  this->LastRun = time (0);
391  RetElem = Elements.end();
392  Element = Elements.begin();
393  while (Element != Elements.end())
394  {
395  if (Element->Name == Name)
396  {
397  Element->LastSeen = this->LastRun;
398  return Element;
399  }
400  Element++;
401  }
402  return RetElem;
403 }
404 //////////////////////////////////////////////////////////////////////
405 
406 //////////////////////////////////////////////////////////////////////
407 /** NOT thread safe
408  *
409  * Find an element by ID.
410  * @param ID The ID of the element
411  * @return iterator pointing to the found element, or End() if element
412  * could not be found
413  */
414 template <class T>
415 typename vector<T>::iterator
417 (
418  size_t ID
419 )
420 {
421  ListIterator Element;
422  ListIterator RetElem;
423  this->LastRun = time (0);
424  RetElem = Elements.end();
425  Element = Elements.begin();
426  while (Element != Elements.end())
427  {
428  if (Element->ID == ID)
429  {
430  RetElem = Element;
431  break;
432  }
433  Element++;
434  }
435  return RetElem;
436 }
437 //////////////////////////////////////////////////////////////////////
438 
439 //////////////////////////////////////////////////////////////////////
440 /** NOT thread safe
441  *
442  * In general iterators are not thread safe. If you use them you have
443  * to ensure propper locking youself!
444  *
445  * @return the first element of the list. If the list is empty this
446  * equals End()
447  */
448 template <class T>
449 typename vector<T>::iterator
451 ()
452 {
453  return Elements.begin ();
454 }
455 //////////////////////////////////////////////////////////////////////
456 
457 //////////////////////////////////////////////////////////////////////
458 /**
459  *
460  * @return the end of the list (which is not a valid entry!)
461  */
462 template <class T>
463 typename vector<T>::iterator
465 ()
466 {
467  return Elements.end ();
468 }
469 //////////////////////////////////////////////////////////////////////
470 
471 //////////////////////////////////////////////////////////////////////
472 /**
473  *
474  * Set a mutex lock on the list, so concurrent operations are blocked
475  * until the lock is released.
476  * @see Unlock()
477  */
478 template <class T>
479 void
481 ()
482 {
483  pthread_mutex_lock ( & m_ListMutex );
484 }
485 //////////////////////////////////////////////////////////////////////
486 
487 //////////////////////////////////////////////////////////////////////
488 /**
489  *
490  * Release a mutex lock
491  */
492 template <class T>
493 void
495 ()
496 {
497  pthread_mutex_unlock ( & m_ListMutex );
498 }
499 //////////////////////////////////////////////////////////////////////
500 
501 //////////////////////////////////////////////////////////////////////
502 /** thread safe
503  * Check entries for expired TTL. All expired entries are removed
504  * from the list.
505  */
506 template <class T>
507 void
509 ()
510 {
511  pthread_mutex_lock ( & m_ListMutex );
512  ListIterator Element;
513  this->LastRun = time (0);
514  Element = Elements.begin();
515  while (Element != Elements.end())
516  {
517  if (Element->Timeout == 0)
518  { // never timeouts
519  Element++;
520  continue;
521  }
522  if ( (this->LastRun - Element->LastSeen) > Element->Timeout )
523  {
525  this->Name << ": TTL exceeded for "
526  << Element->Name << " "
527  << Element->Address.getHost() << " "
528  << "after " << diff_to_days (Element->LastSeen - Element->JoinTime)
529  );
530  Element = Elements.erase (Element);
531  continue;
532  }
533  Element++;
534  }
535  pthread_mutex_unlock ( & m_ListMutex );
536 }
537 //////////////////////////////////////////////////////////////////////
538 
539 //////////////////////////////////////////////////////////////////////
540 /** thread safe
541  * Use this for element access whenever possible. However, if you
542  * need to modify the element you have to use iterators which are not
543  * thread safe and make sure to use Lock() and Unlock() yourself.
544  * @param Index index of the element
545  * @return a copy the the element at index Index
546  */
547 template <class T>
548 T
550 (
551  const size_t& Index
552 )
553 {
554  T RetElem("");
555 // pthread_mutex_lock ( & m_ListMutex );
556  if (Index < Elements.size ())
557  RetElem = Elements[Index];
558 // pthread_mutex_unlock ( & m_ListMutex );
559  return RetElem;
560 }
561 //////////////////////////////////////////////////////////////////////
562 
563 //////////////////////////////////////////////////////////////////////
564 /**
565  *
566  * Update sent-counters of the list and of an element. Every call of
567  * this method means we sent a single packet (and the packet counter
568  * is increased by 1).
569  * @param Element The element to which data was sent
570  * @param bytes The number of bytes sent
571  */
572 template <class T>
573 void
575 (
576  ListIterator& Element,
577  size_t bytes
578 )
579 {
580  PktsSent++;
581  BytesSent += bytes;
582  Element->UpdateSent (bytes);
583 }
584 //////////////////////////////////////////////////////////////////////
585 
586 //////////////////////////////////////////////////////////////////////
587 /**
588  *
589  * Update receive-counters of the list and of an element. Every call of
590  * this method means we received a single packet (and the packet counter
591  * is increased by 1).
592  * @param Element The element from which data was received
593  * @param bytes The number of bytes received
594  */
595 template <class T>
596 void
598 (
599  ListIterator& Element,
600  size_t bytes
601 )
602 {
603  PktsRcvd++;
604  BytesRcvd += bytes;
605  Element->UpdateRcvd (bytes);
606 }
607 //////////////////////////////////////////////////////////////////////
608 
609 //////////////////////////////////////////////////////////////////////
610 /**
611  *
612  * Update sent-counters of the list. Every call of
613  * this method means we sent a single packet (and the packet counter
614  * is increased by 1).
615  * @param bytes The number of bytes sent
616  */
617 template <class T>
618 void
620 (
621  size_t bytes
622 )
623 {
624  PktsSent++;
625  BytesSent += bytes;
626 }
627 //////////////////////////////////////////////////////////////////////
628 
629 //////////////////////////////////////////////////////////////////////
630 /**
631  *
632  * Update received-counters of the list. Every call of
633  * this method means we received a single packet (and the packet counter
634  * is increased by 1).
635  * @param bytes The number of bytes received.
636  */
637 template <class T>
638 void
640 (
641  size_t bytes
642 )
643 {
644  PktsRcvd++;
645  BytesRcvd += bytes;
646 }
647 //////////////////////////////////////////////////////////////////////
648 
649 //////////////////////////////////////////////////////////////////////
650 /**
651  *
652  * Delete all entries of the list.
653  */
654 template <class T>
655 void
657 ()
658 {
659  Lock ();
660  Elements.clear ();
661  Unlock ();
662 }
663 //////////////////////////////////////////////////////////////////////
664 
665 #endif
~FG_Player()
Definition: fg_list.cxx:205
time_t LastRun
timestamp of last cleanup
Definition: fg_list.hxx:199
size_t ID
The ID of this entry.
Definition: fg_list.hxx:57
uint64_t BytesRcvd
Count of bytes recieved from client.
Definition: fg_list.hxx:190
string Name
The callsign (or name)
Definition: fg_list.hxx:61
uint64_t PktsRcvd
Count of packets recieved from client.
Definition: fg_list.hxx:186
string diff_to_days(time_t Date)
convert a time duration expressed in seconds to a string representation of the form "3 days 2 hours" ...
Definition: fg_util.cxx:52
uint64_t BytesSent
Count of bytes sent to client.
Definition: fg_list.hxx:77
void Lock()
Definition: fg_list.hxx:481
T operator[](const size_t &Index)
Definition: fg_list.hxx:550
ListIterator FindByID(size_t ID)
Definition: fg_list.hxx:417
time_t JoinTime
The time this entry was added to the list.
Definition: fg_list.hxx:65
void UpdateSent(ListIterator &Element, size_t bytes)
Definition: fg_list.hxx:575
time_t LastRelayedToInactive
Definition: fg_list.hxx:122
bool DoUpdate
Definition: fg_list.hxx:124
void CheckTTL()
Definition: fg_list.hxx:509
ListIterator Find(const netAddress &Address, const string &Name="")
Definition: fg_list.hxx:318
string Origin
Definition: fg_list.hxx:100
uint64_t BytesSent
Count of bytes sent to client.
Definition: fg_list.hxx:192
uint64_t PktsSent
Count of packets sent to client.
Definition: fg_list.hxx:188
virtual bool operator==(const FG_ListElement &P)
Definition: fg_list.cxx:99
virtual bool operator==(const FG_Player &P)
Definition: fg_list.cxx:224
ListIterator End()
Definition: fg_list.hxx:465
Represent a Player.
Definition: fg_list.hxx:97
vector< T >::iterator ListIterator
Definition: fg_list.hxx:145
time_t Timeout
The Timeout of this entry.
Definition: fg_list.hxx:59
static char E[48]
Definition: crypt-win.c:146
pthread_mutex_t m_ListMutex
mutex for thread safty
Definition: fg_list.hxx:197
#define SG_LOG(C, P, M)
Definition: logstream.hxx:412
uint64_t PktsSent
Count of packets sent to client.
Definition: fg_list.hxx:73
bool HasErrors
true if this client has errors
Definition: fg_list.hxx:120
string Error
in case of errors the reason is stored here
Definition: fg_list.hxx:116
static char P[]
Definition: crypt-win.c:209
size_t Size()
Definition: fg_list.hxx:251
mT_FG_List< FG_ListElement > FG_List
Definition: fg_list.hxx:206
void UpdateRcvd(size_t bytes)
Definition: fg_list.cxx:147
size_t MaxID
maximum entries this list ever had
Definition: fg_list.hxx:184
ListIterator Delete(const ListIterator &Element)
Definition: fg_list.hxx:292
void UpdateSent(size_t bytes)
Definition: fg_list.cxx:134
vector< FG_Player >::iterator PlayerIt
Definition: fg_list.hxx:209
void assign(const FG_ListElement &P)
Definition: fg_list.cxx:113
void operator=(const FG_ListElement &P)
Definition: fg_list.cxx:88
a generic list implementation for fgms
Definition: fg_list.hxx:141
string Passwd
The password.
Definition: fg_list.hxx:104
void Unlock()
Definition: fg_list.hxx:495
Point3D LastOrientation
The last recorded orientation.
Definition: fg_list.hxx:110
ListIterator Begin()
Definition: fg_list.hxx:451
void Clear()
Definition: fg_list.hxx:657
Informatory messages.
Definition: debug_types.h:32
uint64_t BytesRcvd
Count of bytes recieved from client.
Definition: fg_list.hxx:75
Represent a generic list element.
Definition: fg_list.hxx:47
Socket address, internet style.
Definition: netSocket.h:87
mT_FG_List< FG_Player > PlayerList
Definition: fg_list.hxx:207
vector< FG_ListElement >::iterator ItList
Definition: fg_list.hxx:208
void UpdateRcvd(ListIterator &Element, size_t bytes)
Definition: fg_list.hxx:598
time_t LastSeen
timestamp of last seen packet from this element
Definition: fg_list.hxx:67
netSocket is a thin C++ wrapper over bsd sockets to facilitate porting to other platforms. Part of PLIB - A Suite of Portable Game Libraries
string ModelName
The model name.
Definition: fg_list.hxx:106
void operator=(const FG_Player &P)
Definition: fg_list.cxx:213
bool IsLocal
true is this client is directly connected to this fgms instance
Definition: fg_list.hxx:112
uint64_t PktsRcvd
Count of packets recieved from client.
Definition: fg_list.hxx:71
static const size_t NONE_EXISTANT
Definition: fg_list.hxx:55
netAddress Address
The network address of this element.
Definition: fg_list.hxx:63
time_t LastSent
timestamp of last sent packet to this element
Definition: fg_list.hxx:69
Point3D LastPos
The last recorded position.
Definition: fg_list.hxx:108
vector< T > ListElements
Definition: fg_list.hxx:144
ListElements Elements
Definition: fg_list.hxx:203
size_t Add(T &Element, time_t TTL)
Definition: fg_list.hxx:268
void assign(const FG_Player &P)
Definition: fg_list.cxx:237
ListIterator FindByName(const string &Name="")
Definition: fg_list.hxx:383
string Name
Definition: fg_list.hxx:194