Planeshift
netbase.h
Go to the documentation of this file.
1 /*
2  * netbase.h by Matze Braun <MatzeBraun@gmx.de>
3  *
4  * Copyright (C) 2001 Atomic Blue (info@planeshift.it, http://www.atomicblue.org)
5  *
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation (version 2 of the License)
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * This file defines some inline functions which are used in client and server
19  * network functions, the client/server interface classes should be derived from
20  * this base class
21  */
22 #ifndef __NETBASE_H__
23 #define __NETBASE_H__
24 
25 #include "net/pstypes.h"
26 #include "net/netinfos.h"
27 #include "net/netpacket.h"
28 #include "util/genrefqueue.h"
29 #include <csutil/ref.h>
30 #include <csutil/weakref.h>
31 #include <csutil/weakreferenced.h>
32 #include <csutil/refcount.h>
33 #include <csutil/strset.h>
34 #include <csutil/array.h>
35 #include "netprofile.h"
36 
41 #define NUM_BROADCAST 0xffffffff
42 #define MAXQUEUESIZE 20000
43 #define MAXCLIENTQUEUESIZE 5000
44 #define MAXPACKETHISTORY 1009 // Should be a prime to improve performance of hash
45  // This must be set carefully and ideally should be at least the size
46  // of the input queue
47 #define NETAVGCOUNT 400
48 #define RESENDAVGCOUNT 200
49 
50 const unsigned int WINDOW_MAX_SIZE = 65536; // The size of the maximum reliable window in bytes.
51 
52 // The number of times the SendTo function will retry on a EAGAIN or EWOULDBLOCK
53 #define SENDTO_MAX_RETRIES 200
54 // The whole seconds that the SendTo function will block each cycle waiting for the write state to change on the socket
55 #define SENDTO_SELECT_TIMEOUT_SEC 0
56 // The microseconds (1/10^6 s) that the SendTo function will block each cycle waiting for the write state to change on the socket
57 #define SENDTO_SELECT_TIMEOUT_USEC 10000
58 
59 /* Include platform specific socket settings */
60 #ifdef USE_WINSOCK
61 # include "net/sockwin.h"
62 #endif
63 #ifdef USE_UNISOCK
64 # include "net/sockuni.h"
65 #endif
66 
67 // Jorrit: hack for mingw.
68 #ifdef SendMessage
69 #undef SendMessage
70 #endif
71 #ifdef SetJob
72 #undef SetJob
73 #endif
74 #ifdef GetJob
75 #undef GetJob
76 #endif
77 
78 class MsgEntry;
80 class csRandomGen;
81 class csStringHashReversible;
82 struct iEngine;
85 
86 /*
87  * Microsoft sockets do not use Berkeley error codes or functions in all cases.
88  * This is the workaround.
89  * http://msdn.microsoft.com/en-us/library/ms737828(VS.85).aspx
90  * Ravna 19/3/2016: This breaks msvc2015, since various internal libraries like String use errno, and can't assign to it if it is not a value,
91  * so I changed the 3 values the macro originally replaced. Left this for reference.
92  */
93 
94 #ifndef CS_PLATFORM_WIN32
95 #define WSAEWOULDBLOCK EAGAIN
96 #endif
97 
98 
100 {
101  uint32_t client;
102  void* object;
103  float dist;
104  float min_dist;
105 
106  PublishDestination(int client, void* object, float dist, float min_dist) : client(client), object(object), dist(dist), min_dist(min_dist) {}
107 };
108 
109 //-----------------------------------------------------------------------------
110 
116 class NetBase
117 {
118 public:
119 
126  {
127  // msgstrings are loaded by CacheManager and mantained in CacheManager.msg_strings
128  // then sent from server to client at login with psMsgStringsMessage
129  // and stored in <appdata>/cache/commonstrings client side
130  csStringSet* msgstrings;
131  csStringHashReversible* msgstringshash;
132  iEngine *engine;
133 
139  const char* Request(csStringID id) const;
140 
146  csStringID Request(const char* string) const;
147  };
148 
149 
155  NetBase(int outqueuelen=100);
156  virtual ~NetBase();
157 
163  bool AddMsgQueue (MsgQueue *,objID minID=0,objID maxID=0xffffffff);
164 
166  void RemoveMsgQueue(MsgQueue *);
167 
171  virtual bool SendMessage (MsgEntry* me);
172  virtual bool SendMessage (MsgEntry* me,NetPacketQueueRefCount *queue);
173 
177  virtual void Broadcast (MsgEntry* me, int scope, int guildID) = 0;
178 
195  virtual void Multicast (MsgEntry* me, const csArray<PublishDestination>& multi, uint32_t except, float range) = 0;
196 
200  bool IsReady() { return ready; }
201 
205  bool QueueMessage(MsgEntry *me);
206 
214  void ProcessNetwork (csTicks timeout);
215 
217  bool SendOut(void);
218 
220  bool CheckIn(void);
221 
228  bool Flush(MsgQueue * queue);
229 
231  bool Bind(const char* addr, int port);
232  bool Bind(const IN_ADDR &addr, int port);
233 
239  class Connection;
240 
242  {
243  BC_EVERYONEBUTSELF = 1,
244  BC_GROUP = 2,
245  BC_GUILD = 3,
246  BC_SECTOR = 4,
247  BC_EVERYONE = 5,
248  BC_FINALPACKET = 6
249  };
250 
251  csTicks GetPing(void) { return netInfos.GetAveragePingTicks();}
252 
253  psNetMsgProfiles * GetProfs() { return profs; }
254 
256  struct timeval timeout;
257 
259  void SetMsgStrings(csStringSet* msgstrings, csStringHashReversible* msgstringshash)
260  {
261  accessPointers.msgstrings = msgstrings;
262  accessPointers.msgstringshash = msgstringshash;
263  }
264 
266  void SetEngine(iEngine* engine) { accessPointers.engine = engine; }
267 
269  iEngine* GetEngine() { return accessPointers.engine; }
270 
272  static AccessPointers* GetAccessPointers() { return &accessPointers; }
273 
280  void LogMessages(char dir, MsgEntry* me);
281 
287  csString LogMessageFilter(const char *arg);
288 
294  void AddFilterLogMessage(int type);
295 
301  void RemoveFilterLogMessage(int type);
302 
307  void LogMessageFilterClear();
308 
312  void InvertLogMessageFilter() { logmsgfiltersetting.invert = !logmsgfiltersetting.invert; }
313 
317  void ToggleReceiveMessageFilter() { logmsgfiltersetting.receive = !logmsgfiltersetting.receive; }
318 
322  void ToggleSendMessageFilter() { logmsgfiltersetting.send = !logmsgfiltersetting.send; }
323 
327  void SetLogMessageFilterHex(bool filterhex) { logmsgfiltersetting.filterhex = filterhex; }
328 
332  void LogMessageFilterDump();
333 
335  uint32_t GetRandomID();
336 
337 protected:
344  bool FilterLogMessage(int type,char dir);
345 
346  /* the following protected stuff is thought of being used in the inherited
347  * network classes
348  */
349 
354  int SendTo (LPSOCKADDR_IN addr, const void *data, unsigned int size)
355  {
356  struct timeval timeout;
357  int sentbytes;
358  int retries=0;
359  fd_set wfds;
360 
361  #ifdef DEBUG
362  if (!addr || !data)
363  Error1("wrong args");
364  #endif
365 
366  // #define ENDIAN_DEBUG
367 
368  #ifdef ENDIAN_DEBUG
369  FILE *f = fopen("hexdump.txt","a");
370  int i;
371  int len;
372  char c;
373  const char *ptr;
374  ptr = (const char *)data;
375  len = ((40<size) ? 40 : size);
376  fprintf(f,"\n------------\nSending %d bytes:\n",len);
377  for ( i = 0 ; i < len ; i++ ) /* Print the hex dump for len chars. */
378  fprintf(f,"%02x " ,(*(ptr+i)&0xff));
379  for ( i = len ; i < 16 ; i++ ) /* Pad out the dump field to the ASCII */
380  fprintf(f, " " ); /* field. */
381  fprintf(f, " " );
382  for ( i = 0 ; i < len ; i++ ) /* Now print the ASCII field. */
383  {
384  c=0x7f&(*(ptr+i)); /* mask out bit 7 */
385  if (!(isprint(c))) /* If not printable */
386  fprintf(f, "." ); /* print a dot */
387  else {
388  fprintf(f, "%c" ,c);
389  } /* else display it */
390  }
391  fprintf(f,"\n-----------------\n");
392  fclose(f);
393  #endif
394 
395  // Try and send the data, if we fail we wait for the status to change
396  sentbytes=SOCK_SENDTO(mysocket, data, size, 0, (LPSOCKADDR) addr, sizeof (SOCKADDR_IN) );
397 
398 
399  /* Call select() to wait until precisely the time of the change, but have a timeout.
400  * It's possible that the buffer will free between the sendto call and the select
401  * leaving the select hanging forever if not for the timeout value.
402  */
403 #ifdef CS_PLATFORM_WIN32
404  while (retries++ < SENDTO_MAX_RETRIES && sentbytes == -1 && (WSAGetLastError() == EAGAIN || WSAGetLastError() == WSAEWOULDBLOCK))
405 #else
406  while (retries++ < SENDTO_MAX_RETRIES && sentbytes == -1 && (errno == EAGAIN || errno == WSAEWOULDBLOCK))
407 #endif
408  {
409  printf("In while loop on EAGAIN... retry #%d.\n", retries);
410 
411  // Clear the file descriptor set
412  FD_ZERO(&wfds);
413  // Set the socket's FD in this set
414  FD_SET(mysocket,&wfds);
415 
416  // Zero out the timeout value to start
417  memset(&timeout,0,sizeof(struct timeval));
418  timeout.tv_sec=SENDTO_SELECT_TIMEOUT_SEC;
419  timeout.tv_usec=SENDTO_SELECT_TIMEOUT_USEC;
420 
421  /* Wait for the descriptor to change. Note that it's possible that the status
422  * has already cleared, so we'll try to send again after this anyway.
423  */
424  SOCK_SELECT(mysocket+1,NULL,&wfds,NULL,&timeout);
425 
426  // Try and send again.
427  sentbytes=SOCK_SENDTO(mysocket, data, size, 0, (LPSOCKADDR) addr, sizeof (SOCKADDR_IN) );
428  }
429 
430  if (sentbytes>0)
431  {
432  totaltransferout += size;
433  totalcountout++;
434  }
435  else
436  {
437 #ifdef CS_PLATFORM_WIN32
438  Error2("NetBase::SendTo() gave up trying to send a packet with errno=%d.", WSAGetLastError());
439 #else
440  Error2("NetBase::SendTo() gave up trying to send a packet with errno=%d.", errno);
441 #endif
442  }
443 
444  return sentbytes;
445  }
446 
451  int RecvFrom (LPSOCKADDR_IN addr, socklen_t *socklen, void *buf,
452  unsigned int maxsize)
453  {
454  #ifdef DEBUG
455  if (!addr || !buf)
456  Error1("wrong args");
457  #endif
458  fd_set set;
459 
460  /* Initialize the file descriptor set. */
461  FD_ZERO (&set);
462  FD_SET (mysocket, &set);
463 #ifndef CS_PLATFORM_WIN32
464  if(pipe_fd[0] > 0)
465  FD_SET (pipe_fd[0], &set);
466 #endif
467 
468  // Backup the timeval struct in case select changes it as on Linux
469  struct timeval prevTimeout = timeout;
470 
471  /* select returns 0 if timeout, 1 if input available, -1 if error. */
472  if (SOCK_SELECT(csMax(mysocket, pipe_fd[0]) + 1, &set, NULL, NULL, &timeout) < 1)
473  {
474  timeout = prevTimeout;
475  return 0;
476  }
477 
478 #ifndef CS_PLATFORM_WIN32
479  if(FD_ISSET(pipe_fd[0], &set))
480  {
481  char throwaway[32];
482  if(read(pipe_fd[0], throwaway, 32) == -1)
483  {
484  Error1("Read failed!");
485  }
486  }
487 #endif
488 
489  timeout = prevTimeout;
490 
491  if(!FD_ISSET(mysocket, &set))
492  return 0;
493 
494  int err = SOCK_RECVFROM (mysocket, buf, maxsize, 0,
495  (LPSOCKADDR) addr, socklen);
496  if (err>=0)
497  {
498  totaltransferin += err;
499  totalcountin++;
500  }
501  return err;
502  }
503 
504 
509  int GetIPByName (LPSOCKADDR_IN addr, const char *name);
510 
511  virtual Connection *GetConnByIP (LPSOCKADDR_IN addr) = 0;
512 
513  virtual Connection *GetConnByNum (uint32_t clientnum) = 0;
514 
519  virtual bool HandleUnknownClient (LPSOCKADDR_IN addr, MsgEntry *data) = 0;
520 
526  bool Init(bool autobind = true);
527 
528  void Close(bool force = true);
529 
534  bool HandleAck(psNetPacketEntry* pkt, Connection* connection, LPSOCKADDR_IN addr);
535 
541  void CheckResendPkts(void);
542 
547  bool BuildMessage(psNetPacketEntry* pkt,Connection* &connection,LPSOCKADDR_IN addr);
548 
556  void CheckFragmentTimeouts(void);
557 
562  csPtr<MsgEntry> CheckCompleteMessage(uint32_t client,uint32_t id);
563 
569  void HandleCompletedMessage(MsgEntry *me,
570  Connection* &connection,
571  LPSOCKADDR_IN addr,
572  psNetPacketEntry* pkt);
573 
577  bool CheckDoublePackets (Connection* connection, psNetPacketEntry* pkt);
578 
579 
584  bool SendMergedPackets(NetPacketQueue *q);
585 
589  bool SendSinglePacket(psNetPacketEntry* pkt);
590 
594  bool SendFinalPacket(psNetPacketEntry* pkt);
595 
599  bool SendFinalPacket(psNetPacketEntry* pkt, LPSOCKADDR_IN addr);
600 
602  csRef<NetPacketQueueRefCount> NetworkQueue;
603 
606 
608  csArray<MsgQueue*> inqueues;
609 
611  csHash<csRef<psNetPacketEntry>, PacketKey> awaitingack;
612 
614  static int socklibrefcount;
615 
617  bool ready;
618 
620  long totaltransferin, totaltransferout;
622  long totalcountin, totalcountout;
623 
625  typedef struct {
626  unsigned int senders;
627  unsigned int messages;
628  csTicks time;
630 
632  csTicks lastSendReport;
633  unsigned int avgIndex;
634 
635  size_t resends[RESENDAVGCOUNT];
636  unsigned int resendIndex;
637 
639 
640 private:
642  SOCKET mysocket;
643 
645  SOCKET pipe_fd[2];
646 
648  csHash<csRef<psNetPacketEntry> , PacketKey> packets;
649 
653  csRandomGen* randomgen;
654 
656  CS::Threading::Mutex mutex;
657 
659  psNetInfos netInfos;
660 
662  static AccessPointers accessPointers;
663 
665  csArray<int> logmessagefilter;
666 
667  typedef struct {
668  bool invert;
669  bool filterhex;
670  bool receive;
671  bool send;
672  } LogMsgFilterSetting_t;
673 
674  LogMsgFilterSetting_t logmsgfiltersetting;
675 
676  char* input_buffer;
677 };
678 
679 
680 //-----------------------------------------------------------------------------
681 
682 
685 {
686  uint32_t sequence;
687 public:
688  csHash<uint32_t> packethistoryhash;
690  void *buf;
694  csString nameAddr;
696  int pcknumin;
700  bool valid;
702  uint32_t clientnum;
708  float estRTT;
710  float devRTT;
712  csTicks RTO;
714  uint32_t sends;
716  uint32_t resends;
717 
718  // Reliable transmission window size
719  uint32_t window;
720 
722  uint32_t packethistoryid[MAXPACKETHISTORY];
723  uint32_t packethistoryoffset[MAXPACKETHISTORY];
725 
726  Connection(uint32_t num=0);
727  ~Connection();
728  bool isValid() const
729  { return valid; }
730 
731  uint32_t GetNextPacketID() {return sequence++;}
732 
734  bool IsWindowFull() {return window > WINDOW_MAX_SIZE; }
736  void AddToWindow(uint32_t bytes) {window += bytes; }
738  void RemoveFromWindow(uint32_t bytes) { if(bytes > window) abort(); window -= bytes;}
739 };
740 
741 
742 //-----------------------------------------------------------------------------
743 
744 
745 class NetPacketQueueRefCount : public NetPacketQueue, public csSyncRefCount, public CS::Utility::WeakReferenced
746 {
747 private:
748  bool pending;
749 
750 public:
752  : NetPacketQueue(qlen)
753  { pending=false; }
755  {}
756 
759  void SetPending(bool flag)
760  {
761  pending = flag;
762  }
763  bool GetPending()
764  {
765  return pending;
766  }
767 };
768 
771 #endif
772 
static AccessPointers * GetAccessPointers()
Get the access pointers.
Definition: netbase.h:272
This class holds data for a connection.
Definition: netbase.h:684
void SetLogMessageFilterHex(bool filterhex)
Set the filter hex messages flag.
Definition: netbase.h:327
virtual ~NetPacketQueueRefCount()
Definition: netbase.h:754
#define SOCK_RECVFROM(a, b, c, d, e, f)
Definition: sockuni.h:75
int heartbeat
number of attempts to keep alive connection without ack response
Definition: netbase.h:706
bool ready
is the connection ready?
Definition: netbase.h:617
csHash< csRef< psNetPacketEntry >, PacketKey > awaitingack
Packets Awaiting Ack pool.
Definition: netbase.h:611
static int socklibrefcount
System Socket lib initialized?
Definition: netbase.h:614
bool valid
Is this already a valid connection?
Definition: netbase.h:700
NetPacketQueueRefCount(int qlen)
Definition: netbase.h:751
#define IN_ADDR
Definition: sockuni.h:50
float devRTT
RTT deviance.
Definition: netbase.h:710
Gives informations about the network connection.
Definition: netinfos.h:35
uint32_t GetNextPacketID()
Definition: netbase.h:731
Struct used by MessageCracker and ToString to distribute a number of access pointers.
Definition: netbase.h:125
uint32_t objID
Definition: pstypes.h:15
unsigned int avgIndex
Definition: netbase.h:633
GenericRefQueue< MsgEntry > MsgQueue
Definition: netbase.h:82
uint32_t client
Definition: netbase.h:101
float estRTT
Estimated RTT.
Definition: netbase.h:708
csTicks RTO
timeout
Definition: netbase.h:712
uint32_t resends
Number of resends.
Definition: netbase.h:716
csTicks lastSendReport
Definition: netbase.h:632
The structure of 1 queue entry (pointer to a message)
Definition: message.h:143
#define LPSOCKADDR_IN
Definition: sockuni.h:70
#define SOCK_SELECT(max, read, write, except, timeout)
Definition: sockuni.h:78
csStringSet * msgstrings
Definition: netbase.h:130
int RecvFrom(LPSOCKADDR_IN addr, socklen_t *socklen, void *buf, unsigned int maxsize)
small inliner for receiving packets...
Definition: netbase.h:451
void SetEngine(iEngine *engine)
Set the Engine.
Definition: netbase.h:266
long totalcountout
Definition: netbase.h:622
csStringHashReversible * msgstringshash
Definition: netbase.h:131
unsigned int messages
Definition: netbase.h:627
void RemoveFromWindow(uint32_t bytes)
Remove from transmission window when an ack is received.
Definition: netbase.h:738
uint32_t clientnum
the client num
Definition: netbase.h:702
csTicks GetPing(void)
Definition: netbase.h:251
#define SENDTO_SELECT_TIMEOUT_SEC
Definition: netbase.h:55
PublishDestination(int client, void *object, float dist, float min_dist)
Definition: netbase.h:106
#define Error2(a, b)
Definition: log.h:276
int pcknumin
The Number of the last incoming packet.
Definition: netbase.h:696
void SetMsgStrings(csStringSet *msgstrings, csStringHashReversible *msgstringshash)
Set the MsgString Hash.
Definition: netbase.h:259
bool isValid() const
Definition: netbase.h:728
#define MAXPACKETHISTORY
Definition: netbase.h:44
csHash< uint32_t > packethistoryhash
Definition: netbase.h:688
const unsigned int WINDOW_MAX_SIZE
Definition: netbase.h:50
int pcknumout
The Number of the last outgoing packet.
Definition: netbase.h:698
#define SENDTO_SELECT_TIMEOUT_USEC
Definition: netbase.h:57
GenericRefQueue< psNetPacketEntry > NetPacketQueue
Definition: netbase.h:84
void ToggleSendMessageFilter()
Toggle the global send LogMessage filter.
Definition: netbase.h:322
SOCKADDR_IN addr
The INet Adress of the client.
Definition: netbase.h:692
unsigned int senders
Definition: netbase.h:626
#define SENDTO_MAX_RETRIES
Definition: netbase.h:53
csString nameAddr
The adress if provided, usually in clients, else an empty csstring.
Definition: netbase.h:694
This class acts as a base for client/server net classes.
Definition: netbase.h:116
psNetMsgProfiles * GetProfs()
Definition: netbase.h:253
void SetPending(bool flag)
This flag ensures the same object is not queued twice. Doesn&#39;t have to mutexed here because these are...
Definition: netbase.h:759
csRef< NetPacketQueueRefCount > NetworkQueue
Outgoing message queue.
Definition: netbase.h:602
void AddToWindow(uint32_t bytes)
Add to window when reliable data is in transit.
Definition: netbase.h:736
iEngine * GetEngine()
Get the Engine.
Definition: netbase.h:269
A queue of smart pointers with locking facilties for multi-threading.
Definition: genrefqueue.h:39
bool IsWindowFull()
Check if the reliable transmission window is full.
Definition: netbase.h:734
#define SOCKADDR_IN
Definition: sockuni.h:58
void InvertLogMessageFilter()
Invert the LogMessage filter.
Definition: netbase.h:312
int SendTo(LPSOCKADDR_IN addr, const void *data, unsigned int size)
Wrapper to encapsulate the sendto call and provide for retry if the buffer is full.
Definition: netbase.h:354
#define RESENDAVGCOUNT
Definition: netbase.h:48
#define LPSOCKADDR
Definition: sockuni.h:63
#define socklen_t
Definition: sockwin.h:38
long totaltransferout
Definition: netbase.h:620
uint32_t window
Definition: netbase.h:719
broadcasttype
Definition: netbase.h:241
Moving averages.
Definition: netbase.h:625
#define SOCK_SENDTO(a, b, c, d, e, f)
Definition: sockuni.h:74
bool IsReady()
Is this connection ready to use?
Definition: netbase.h:200
uint32_t sends
Number of reliable sends.
Definition: netbase.h:714
GenericRefQueue< NetPacketQueueRefCount, csWeakRef > senders
weak referenced list of outbound queues with waiting data so disconnected clients won&#39;t receive packe...
Definition: netbase.h:605
#define SOCKET
Definition: sockuni.h:43
psNetMsgProfiles * profs
Definition: netbase.h:638
#define NETAVGCOUNT
Definition: netbase.h:47
#define WSAEWOULDBLOCK
Definition: netbase.h:95
void ToggleReceiveMessageFilter()
Toggle the global receive LogMessage filter.
Definition: netbase.h:317
Statistics of receiving or sending of network messages.
Definition: netprofile.h:35
unsigned int resendIndex
Definition: netbase.h:636
void * buf
buffer for split up packets, allocated when needed
Definition: netbase.h:690
#define Error1(a)
Definition: log.h:274
csArray< MsgQueue * > inqueues
Incoming message queue vector.
Definition: netbase.h:608
csTicks lastRecvPacketTime
last time packet was received from this connection
Definition: netbase.h:704