Panda3D
 All Classes Functions Variables Enumerations
queuedConnectionReader.cxx
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
 All Classes Functions Variables Enumerations