|
@@ -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
|