Panda3D
queuedConnectionReader.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file queuedConnectionReader.cxx
10  * @author drose
11  * @date 2000-02-08
12  */
13 
14 #include "queuedConnectionReader.h"
15 #include "config_net.h"
16 #include "trueClock.h"
17 #include "lightMutexHolder.h"
18 
19 template class QueuedReturn<NetDatagram>;
20 
21 /**
22  *
23  */
24 QueuedConnectionReader::
25 QueuedConnectionReader(ConnectionManager *manager, int num_threads) :
26  ConnectionReader(manager, num_threads)
27 {
28 #ifdef SIMULATE_NETWORK_DELAY
29  _delay_active = false;
30  _min_delay = 0.0;
31  _delay_variance = 0.0;
32 #endif // SIMULATE_NETWORK_DELAY
33 }
34 
35 /**
36  *
37  */
38 QueuedConnectionReader::
39 ~QueuedConnectionReader() {
40  // We call shutdown() here to guarantee that all threads are gone before the
41  // QueuedReturn destructs.
42  shutdown();
43 }
44 
45 /**
46  * Returns true if a datagram is available on the queue; call get_data() to
47  * extract the datagram.
48  */
51  poll();
52 #ifdef SIMULATE_NETWORK_DELAY
53  get_delayed();
54 #endif // SIMULATE_NETWORK_DELAY
55  return thing_available();
56 }
57 
58 /**
59  * If a previous call to data_available() returned true, this function will
60  * return the datagram that has become available.
61  *
62  * The return value is true if a datagram was successfully returned, or false
63  * if there was, in fact, no datagram available. (This may happen if there
64  * are multiple threads accessing the QueuedConnectionReader).
65  */
67 get_data(NetDatagram &result) {
68  return get_thing(result);
69 }
70 
71 /**
72  * This flavor of QueuedConnectionReader::get_data(), works like the other,
73  * except that it only fills a Datagram object, not a NetDatagram object.
74  * This means that the Datagram cannot be queried for its source Connection
75  * and/or NetAddress, but it is useful in all other respects.
76  */
78 get_data(Datagram &result) {
79  NetDatagram nd;
80  if (!get_thing(nd)) {
81  return false;
82  }
83  result = nd;
84  return true;
85 }
86 
87 /**
88  * An internal function called by ConnectionReader() when a new datagram has
89  * become available. The QueuedConnectionReader simply queues it up for later
90  * retrieval by get_data().
91  */
92 void QueuedConnectionReader::
93 receive_datagram(const NetDatagram &datagram) {
94  /*
95  if (net_cat.is_spam()) {
96  net_cat.spam()
97  << "Received datagram of " << datagram.get_length()
98  << " bytes\n";
99  }
100  */
101 
102 #ifdef SIMULATE_NETWORK_DELAY
103  delay_datagram(datagram);
104 
105 #else // SIMULATE_NETWORK_DELAY
106  if (!enqueue_thing(datagram)) {
107  net_cat.error()
108  << "QueuedConnectionReader queue full!\n";
109  }
110 #endif // SIMULATE_NETWORK_DELAY
111 }
112 
113 
114 #ifdef SIMULATE_NETWORK_DELAY
115 /**
116  * Enables a simulated network latency. All packets received from this point
117  * on will be held for a random interval of least min_delay seconds, and no
118  * more than max_delay seconds, before being visible to the
119  * data_available()/get_data() interface. It is as if packets suddenly took
120  * much longer to arrive.
121  */
122 void QueuedConnectionReader::
123 start_delay(double min_delay, double max_delay) {
124  LightMutexHolder holder(_dd_mutex);
125  _min_delay = min_delay;
126  _delay_variance = std::max(max_delay - min_delay, 0.0);
127  _delay_active = true;
128 }
129 
130 /**
131  * Disables the simulated network latency started by a previous call to
132  * start_delay(). Packets will once again be visible as soon as they are
133  * received.
134  */
135 void QueuedConnectionReader::
136 stop_delay() {
137  LightMutexHolder holder(_dd_mutex);
138  _delay_active = false;
139 
140  // Copy the entire contents of the delay queue to the normal queue.
141  while (!_delayed.empty()) {
142  const DelayedDatagram &dd = _delayed.front();
143  if (!enqueue_thing(dd._datagram)) {
144  net_cat.error()
145  << "QueuedConnectionReader queue full!\n";
146  }
147  _delayed.pop_front();
148  }
149 }
150 
151 /**
152  * Checks the delayed queue for any now available datagrams, and adds them to
153  * the normal queue if they are available.
154  */
155 void QueuedConnectionReader::
156 get_delayed() {
157  if (_delay_active) {
158  LightMutexHolder holder(_dd_mutex);
159  double now = TrueClock::get_global_ptr()->get_short_time();
160  while (!_delayed.empty()) {
161  const DelayedDatagram &dd = _delayed.front();
162  if (dd._reveal_time > now) {
163  // Not yet.
164  break;
165  }
166  if (!enqueue_thing(dd._datagram)) {
167  net_cat.error()
168  << "QueuedConnectionReader queue full!\n";
169  }
170  _delayed.pop_front();
171  }
172  }
173 }
174 
175 /**
176  * Adds the datagram to the delay queue for a random time interval.
177  */
178 void QueuedConnectionReader::
179 delay_datagram(const NetDatagram &datagram) {
180  if (!_delay_active) {
181  if (!enqueue_thing(datagram)) {
182  net_cat.error()
183  << "QueuedConnectionReader queue full!\n";
184  }
185  } else {
186  LightMutexHolder holder(_dd_mutex);
187  // Check the delay_active flag again, now that we have grabbed the mutex.
188  if (!_delay_active) {
189  if (!enqueue_thing(datagram)) {
190  net_cat.error()
191  << "QueuedConnectionReader queue full!\n";
192  }
193 
194  } else {
195  double now = TrueClock::get_global_ptr()->get_short_time();
196  double reveal_time = now + _min_delay;
197 
198  if (_delay_variance > 0.0) {
199  reveal_time += _delay_variance * ((double)rand() / (double)RAND_MAX);
200  }
201  _delayed.push_back(DelayedDatagram());
202  DelayedDatagram &dd = _delayed.back();
203  dd._reveal_time = reveal_time;
204  dd._datagram = datagram;
205  }
206  }
207 }
208 
209 #endif // SIMULATE_NETWORK_DELAY
The primary interface to the low-level networking layer in this package.
This is an abstract base class for a family of classes that listen for activity on a socket and respo...
void poll()
Explicitly polls the available sockets to see if any of them have any noise.
void shutdown()
Terminates all threads cleanly.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Similar to MutexHolder, but for a light mutex.
A specific kind of Datagram, especially for sending across or receiving from a network.
Definition: netDatagram.h:40
bool get_data(NetDatagram &result)
If a previous call to data_available() returned true, this function will return the datagram that has...
bool data_available()
Returns true if a datagram is available on the queue; call get_data() to extract the datagram.
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
Definition: trueClock.I:68
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.