Jelajahi Sumber

added SIMULATE_NETWORK_DELAY stuff

David Rose 24 tahun lalu
induk
melakukan
891f3c3637
2 mengubah file dengan 170 tambahan dan 5 penghapusan
  1. 139 5
      panda/src/net/queuedConnectionReader.cxx
  2. 31 0
      panda/src/net/queuedConnectionReader.h

+ 139 - 5
panda/src/net/queuedConnectionReader.cxx

@@ -18,21 +18,28 @@
 
 
 #include "queuedConnectionReader.h"
 #include "queuedConnectionReader.h"
 #include "config_net.h"
 #include "config_net.h"
+#include "clockObject.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: QueuedConnectionReader::Constructor
 //     Function: QueuedConnectionReader::Constructor
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 QueuedConnectionReader::
 QueuedConnectionReader::
 QueuedConnectionReader(ConnectionManager *manager, int num_threads) :
 QueuedConnectionReader(ConnectionManager *manager, int num_threads) :
   ConnectionReader(manager, num_threads)
   ConnectionReader(manager, num_threads)
 {
 {
+#ifdef SIMULATE_NETWORK_DELAY
+  _dd_mutex = PR_NewLock();
+  _delay_active = false;
+  _min_delay = 0.0;
+  _delay_variance = 0.0;
+#endif  // SIMULATE_NETWORK_DELAY
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: QueuedConnectionReader::Destructor
 //     Function: QueuedConnectionReader::Destructor
-//       Access: Public, Virtual
+//       Access: Published, Virtual
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 QueuedConnectionReader::
 QueuedConnectionReader::
@@ -40,23 +47,30 @@ QueuedConnectionReader::
   // We call shutdown() here to guarantee that all threads are gone
   // We call shutdown() here to guarantee that all threads are gone
   // before the QueuedReturn destructs.
   // before the QueuedReturn destructs.
   shutdown();
   shutdown();
+
+#ifdef SIMULATE_NETWORK_DELAY
+  PR_DestroyLock(_dd_mutex);
+#endif  // SIMULATE_NETWORK_DELAY
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: QueuedConnectionReader::data_available
 //     Function: QueuedConnectionReader::data_available
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if a datagram is available on the queue;
 //  Description: Returns true if a datagram is available on the queue;
 //               call get_data() to extract the datagram.
 //               call get_data() to extract the datagram.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool QueuedConnectionReader::
 bool QueuedConnectionReader::
 data_available() {
 data_available() {
   poll();
   poll();
+#ifdef SIMULATE_NETWORK_DELAY
+  get_delayed();  
+#endif  // SIMULATE_NETWORK_DELAY
   return thing_available();
   return thing_available();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: QueuedConnectionReader::get_data
 //     Function: QueuedConnectionReader::get_data
-//       Access: Public
+//       Access: Published
 //  Description: If a previous call to data_available() returned
 //  Description: If a previous call to data_available() returned
 //               true, this function will return the datagram that has
 //               true, this function will return the datagram that has
 //               become available.
 //               become available.
@@ -74,7 +88,7 @@ get_data(NetDatagram &result) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: QueuedConnectionReader::get_data
 //     Function: QueuedConnectionReader::get_data
-//       Access: Public
+//       Access: Published
 //  Description: This flavor of QueuedConnectionReader::get_data(),
 //  Description: This flavor of QueuedConnectionReader::get_data(),
 //               works like the other, except that it only fills a
 //               works like the other, except that it only fills a
 //               Datagram object, not a NetDatagram object.  This
 //               Datagram object, not a NetDatagram object.  This
@@ -108,8 +122,128 @@ receive_datagram(const NetDatagram &datagram) {
       << " bytes\n";
       << " bytes\n";
   }
   }
 
 
+#ifdef SIMULATE_NETWORK_DELAY
+  delay_datagram(datagram);
+
+#else  // SIMULATE_NETWORK_DELAY
   if (!enqueue_thing(datagram)) {
   if (!enqueue_thing(datagram)) {
     net_cat.error()
     net_cat.error()
       << "QueuedConnectionReader queue full!\n";
       << "QueuedConnectionReader queue full!\n";
   }
   }
+#endif  // SIMULATE_NETWORK_DELAY
+}
+
+
+#ifdef SIMULATE_NETWORK_DELAY
+////////////////////////////////////////////////////////////////////
+//     Function: QueuedConnectionReader::start_delay
+//       Access: Published
+//  Description: Enables a simulated network latency.  All packets
+//               received from this point on will be held for a random
+//               interval of least min_delay seconds, and no more than
+//               max_delay seconds, before being visible to the
+//               data_available()/get_data() interface.  It is as if
+//               packets suddenly took much longer to arrive.
+////////////////////////////////////////////////////////////////////
+void QueuedConnectionReader::
+start_delay(double min_delay, double max_delay) {
+  PR_Lock(_dd_mutex);
+  _min_delay = min_delay;
+  _delay_variance = max(max_delay - min_delay, 0.0);
+  _delay_active = true;
+  PR_Unlock(_dd_mutex);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: QueuedConnectionReader::stop_delay
+//       Access: Published
+//  Description: Disables the simulated network latency started by a
+//               previous call to start_delay().  Packets will once
+//               again be visible as soon as they are received.
+////////////////////////////////////////////////////////////////////
+void QueuedConnectionReader::
+stop_delay() {
+  PR_Lock(_dd_mutex);
+  _delay_active = false;
+
+  // Copy the entire contents of the delay queue to the normal queue.
+  while (!_delayed.empty()) {
+    const DelayedDatagram &dd = _delayed.front();
+    if (!enqueue_thing(dd._datagram)) {
+      net_cat.error()
+        << "QueuedConnectionReader queue full!\n";
+    }
+    _delayed.pop_front();
+  }
+    
+  PR_Unlock(_dd_mutex);
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: QueuedConnectionReader::get_delayed
+//       Access: Private
+//  Description: Checks the delayed queue for any now available
+//               datagrams, and adds them to the normal queue if they
+//               are available.
+////////////////////////////////////////////////////////////////////
+void QueuedConnectionReader::
+get_delayed() {
+  if (_delay_active) {
+    PR_Lock(_dd_mutex);
+    double now = ClockObject::get_global_clock()->get_real_time();
+    while (!_delayed.empty()) {
+      const DelayedDatagram &dd = _delayed.front();
+      if (dd._reveal_time > now) {
+        // Not yet.
+        break;
+      }
+      if (!enqueue_thing(dd._datagram)) {
+        net_cat.error()
+          << "QueuedConnectionReader queue full!\n";
+      }
+      _delayed.pop_front();
+    }
+    PR_Unlock(_dd_mutex);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: QueuedConnectionReader::delay_datagram
+//       Access: Private
+//  Description: Adds the datagram to the delay queue for a random
+//               time interval.
+////////////////////////////////////////////////////////////////////
+void QueuedConnectionReader::
+delay_datagram(const NetDatagram &datagram) {
+  if (!_delay_active) {
+    if (!enqueue_thing(datagram)) {
+      net_cat.error()
+        << "QueuedConnectionReader queue full!\n";
+    }
+  } else {
+    PR_Lock(_dd_mutex);
+    // Check the delay_active flag again, now that we have grabbed the
+    // mutex.
+    if (!_delay_active) {
+      if (!enqueue_thing(datagram)) {
+        net_cat.error()
+          << "QueuedConnectionReader queue full!\n";
+      }
+
+    } else {
+      double now = ClockObject::get_global_clock()->get_real_time();
+      double reveal_time = now + _min_delay;
+      
+      if (_delay_variance > 0.0) {
+        reveal_time += _delay_variance * ((double)rand() / (double)RAND_MAX);
+      }
+      _delayed.push_back(DelayedDatagram());
+      DelayedDatagram &dd = _delayed.back();
+      dd._reveal_time = reveal_time;
+      dd._datagram = datagram;
+    }
+    PR_Unlock(_dd_mutex);
+  }
+}
+
+#endif  // SIMULATE_NETWORK_DELAY

+ 31 - 0
panda/src/net/queuedConnectionReader.h

@@ -30,6 +30,14 @@
 
 
 EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, QueuedReturn<NetDatagram>);
 EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, QueuedReturn<NetDatagram>);
 
 
+#ifndef NDEBUG
+// We define this variable if we're compiling code to implement a
+// simulated network latency, useful for debuggin networked programs.
+// Normally, since this is a debugging tool, we wouldn't compile this
+// feature in if we're building a program for public release.
+#define SIMULATE_NETWORK_DELAY
+#endif
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : QueuedConnectionReader
 //       Class : QueuedConnectionReader
 // Description : This flavor of ConnectionReader will read from its
 // Description : This flavor of ConnectionReader will read from its
@@ -51,6 +59,29 @@ PUBLISHED:
 
 
 protected:
 protected:
   virtual void receive_datagram(const NetDatagram &datagram);
   virtual void receive_datagram(const NetDatagram &datagram);
+
+#ifdef SIMULATE_NETWORK_DELAY
+PUBLISHED:
+  void start_delay(double min_delay, double max_delay);
+  void stop_delay();
+
+private:
+  void get_delayed();
+  void delay_datagram(const NetDatagram &datagram);
+
+  class DelayedDatagram {
+  public:
+    double _reveal_time;
+    NetDatagram _datagram;
+  };
+    
+  PRLock *_dd_mutex;
+  typedef pdeque<DelayedDatagram> Delayed;
+  Delayed _delayed;
+  bool _delay_active;
+  double _min_delay, _delay_variance;
+
+#endif  // SIMULATE_NETWORK_DELAY
 };
 };
 
 
 #endif
 #endif