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  */
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
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
Definition: trueClock.I:68
A specific kind of Datagram, especially for sending across or receiving from a network.
Definition: netDatagram.h:40
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The primary interface to the low-level networking layer in this package.
void shutdown()
Terminates all threads cleanly.
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.
bool data_available()
Returns true if a datagram is available on the queue; call get_data() to extract the datagram.
Similar to MutexHolder, but for a light mutex.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool get_data(NetDatagram &result)
If a previous call to data_available() returned true, this function will return the datagram that has...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.