00001 // Filename: queuedConnectionReader.cxx 00002 // Created by: drose (08Feb00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "queuedConnectionReader.h" 00016 #include "config_net.h" 00017 #include "trueClock.h" 00018 #include "lightMutexHolder.h" 00019 00020 //////////////////////////////////////////////////////////////////// 00021 // Function: QueuedConnectionReader::Constructor 00022 // Access: Published 00023 // Description: 00024 //////////////////////////////////////////////////////////////////// 00025 QueuedConnectionReader:: 00026 QueuedConnectionReader(ConnectionManager *manager, int num_threads) : 00027 ConnectionReader(manager, num_threads) 00028 { 00029 #ifdef SIMULATE_NETWORK_DELAY 00030 _delay_active = false; 00031 _min_delay = 0.0; 00032 _delay_variance = 0.0; 00033 #endif // SIMULATE_NETWORK_DELAY 00034 } 00035 00036 //////////////////////////////////////////////////////////////////// 00037 // Function: QueuedConnectionReader::Destructor 00038 // Access: Published, Virtual 00039 // Description: 00040 //////////////////////////////////////////////////////////////////// 00041 QueuedConnectionReader:: 00042 ~QueuedConnectionReader() { 00043 // We call shutdown() here to guarantee that all threads are gone 00044 // before the QueuedReturn destructs. 00045 shutdown(); 00046 } 00047 00048 //////////////////////////////////////////////////////////////////// 00049 // Function: QueuedConnectionReader::data_available 00050 // Access: Published 00051 // Description: Returns true if a datagram is available on the queue; 00052 // call get_data() to extract the datagram. 00053 //////////////////////////////////////////////////////////////////// 00054 bool QueuedConnectionReader:: 00055 data_available() { 00056 poll(); 00057 #ifdef SIMULATE_NETWORK_DELAY 00058 get_delayed(); 00059 #endif // SIMULATE_NETWORK_DELAY 00060 return thing_available(); 00061 } 00062 00063 //////////////////////////////////////////////////////////////////// 00064 // Function: QueuedConnectionReader::get_data 00065 // Access: Published 00066 // Description: If a previous call to data_available() returned 00067 // true, this function will return the datagram that has 00068 // become available. 00069 // 00070 // The return value is true if a datagram was 00071 // successfully returned, or false if there was, in 00072 // fact, no datagram available. (This may happen if 00073 // there are multiple threads accessing the 00074 // QueuedConnectionReader). 00075 //////////////////////////////////////////////////////////////////// 00076 bool QueuedConnectionReader:: 00077 get_data(NetDatagram &result) { 00078 return get_thing(result); 00079 } 00080 00081 //////////////////////////////////////////////////////////////////// 00082 // Function: QueuedConnectionReader::get_data 00083 // Access: Published 00084 // Description: This flavor of QueuedConnectionReader::get_data(), 00085 // works like the other, except that it only fills a 00086 // Datagram object, not a NetDatagram object. This 00087 // means that the Datagram cannot be queried for its 00088 // source Connection and/or NetAddress, but it is useful 00089 // in all other respects. 00090 //////////////////////////////////////////////////////////////////// 00091 bool QueuedConnectionReader:: 00092 get_data(Datagram &result) { 00093 NetDatagram nd; 00094 if (!get_thing(nd)) { 00095 return false; 00096 } 00097 result = nd; 00098 return true; 00099 } 00100 00101 //////////////////////////////////////////////////////////////////// 00102 // Function: QueuedConnectionReader::receive_datagram 00103 // Access: Protected, Virtual 00104 // Description: An internal function called by ConnectionReader() 00105 // when a new datagram has become available. The 00106 // QueuedConnectionReader simply queues it up for later 00107 // retrieval by get_data(). 00108 //////////////////////////////////////////////////////////////////// 00109 void QueuedConnectionReader:: 00110 receive_datagram(const NetDatagram &datagram) { 00111 /* 00112 if (net_cat.is_spam()) { 00113 net_cat.spam() 00114 << "Received datagram of " << datagram.get_length() 00115 << " bytes\n"; 00116 } 00117 */ 00118 00119 #ifdef SIMULATE_NETWORK_DELAY 00120 delay_datagram(datagram); 00121 00122 #else // SIMULATE_NETWORK_DELAY 00123 if (!enqueue_thing(datagram)) { 00124 net_cat.error() 00125 << "QueuedConnectionReader queue full!\n"; 00126 } 00127 #endif // SIMULATE_NETWORK_DELAY 00128 } 00129 00130 00131 #ifdef SIMULATE_NETWORK_DELAY 00132 //////////////////////////////////////////////////////////////////// 00133 // Function: QueuedConnectionReader::start_delay 00134 // Access: Published 00135 // Description: Enables a simulated network latency. All packets 00136 // received from this point on will be held for a random 00137 // interval of least min_delay seconds, and no more than 00138 // max_delay seconds, before being visible to the 00139 // data_available()/get_data() interface. It is as if 00140 // packets suddenly took much longer to arrive. 00141 //////////////////////////////////////////////////////////////////// 00142 void QueuedConnectionReader:: 00143 start_delay(double min_delay, double max_delay) { 00144 LightMutexHolder holder(_dd_mutex); 00145 _min_delay = min_delay; 00146 _delay_variance = max(max_delay - min_delay, 0.0); 00147 _delay_active = true; 00148 } 00149 00150 //////////////////////////////////////////////////////////////////// 00151 // Function: QueuedConnectionReader::stop_delay 00152 // Access: Published 00153 // Description: Disables the simulated network latency started by a 00154 // previous call to start_delay(). Packets will once 00155 // again be visible as soon as they are received. 00156 //////////////////////////////////////////////////////////////////// 00157 void QueuedConnectionReader:: 00158 stop_delay() { 00159 LightMutexHolder holder(_dd_mutex); 00160 _delay_active = false; 00161 00162 // Copy the entire contents of the delay queue to the normal queue. 00163 while (!_delayed.empty()) { 00164 const DelayedDatagram &dd = _delayed.front(); 00165 if (!enqueue_thing(dd._datagram)) { 00166 net_cat.error() 00167 << "QueuedConnectionReader queue full!\n"; 00168 } 00169 _delayed.pop_front(); 00170 } 00171 } 00172 00173 //////////////////////////////////////////////////////////////////// 00174 // Function: QueuedConnectionReader::get_delayed 00175 // Access: Private 00176 // Description: Checks the delayed queue for any now available 00177 // datagrams, and adds them to the normal queue if they 00178 // are available. 00179 //////////////////////////////////////////////////////////////////// 00180 void QueuedConnectionReader:: 00181 get_delayed() { 00182 if (_delay_active) { 00183 LightMutexHolder holder(_dd_mutex); 00184 double now = TrueClock::get_global_ptr()->get_short_time(); 00185 while (!_delayed.empty()) { 00186 const DelayedDatagram &dd = _delayed.front(); 00187 if (dd._reveal_time > now) { 00188 // Not yet. 00189 break; 00190 } 00191 if (!enqueue_thing(dd._datagram)) { 00192 net_cat.error() 00193 << "QueuedConnectionReader queue full!\n"; 00194 } 00195 _delayed.pop_front(); 00196 } 00197 } 00198 } 00199 00200 //////////////////////////////////////////////////////////////////// 00201 // Function: QueuedConnectionReader::delay_datagram 00202 // Access: Private 00203 // Description: Adds the datagram to the delay queue for a random 00204 // time interval. 00205 //////////////////////////////////////////////////////////////////// 00206 void QueuedConnectionReader:: 00207 delay_datagram(const NetDatagram &datagram) { 00208 if (!_delay_active) { 00209 if (!enqueue_thing(datagram)) { 00210 net_cat.error() 00211 << "QueuedConnectionReader queue full!\n"; 00212 } 00213 } else { 00214 LightMutexHolder holder(_dd_mutex); 00215 // Check the delay_active flag again, now that we have grabbed the 00216 // mutex. 00217 if (!_delay_active) { 00218 if (!enqueue_thing(datagram)) { 00219 net_cat.error() 00220 << "QueuedConnectionReader queue full!\n"; 00221 } 00222 00223 } else { 00224 double now = TrueClock::get_global_ptr()->get_short_time(); 00225 double reveal_time = now + _min_delay; 00226 00227 if (_delay_variance > 0.0) { 00228 reveal_time += _delay_variance * ((double)rand() / (double)RAND_MAX); 00229 } 00230 _delayed.push_back(DelayedDatagram()); 00231 DelayedDatagram &dd = _delayed.back(); 00232 dd._reveal_time = reveal_time; 00233 dd._datagram = datagram; 00234 } 00235 } 00236 } 00237 00238 #endif // SIMULATE_NETWORK_DELAY