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