Panda3D
 All Classes Functions Variables Enumerations
socketStream.cxx
00001 // Filename: socketStream.cxx
00002 // Created by:  drose (19Oct02)
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 "socketStream.h"
00016 #include "datagram.h"
00017 #include "datagramIterator.h"
00018 #include "httpChannel.h"
00019 #include "config_downloader.h"
00020 
00021 #ifdef HAVE_OPENSSL
00022 
00023 ////////////////////////////////////////////////////////////////////
00024 //     Function: SSReader::Constructor
00025 //       Access: Public
00026 //  Description:
00027 ////////////////////////////////////////////////////////////////////
00028 SSReader::
00029 SSReader(istream *stream) : _istream(stream) {
00030   _data_expected = 0;
00031   _tcp_header_size = tcp_header_size;
00032 
00033 #ifdef SIMULATE_NETWORK_DELAY
00034   _delay_active = false;
00035   _min_delay = 0.0;
00036   _delay_variance = 0.0;
00037 #endif  // SIMULATE_NETWORK_DELAY
00038 }
00039 
00040 ////////////////////////////////////////////////////////////////////
00041 //     Function: SSReader::Destructor
00042 //       Access: Public, Virtual
00043 //  Description: 
00044 ////////////////////////////////////////////////////////////////////
00045 SSReader::
00046 ~SSReader() {
00047 }
00048 
00049 ////////////////////////////////////////////////////////////////////
00050 //     Function: SSReader::do_receive_datagram
00051 //       Access: Private
00052 //  Description: Receives a datagram over the socket by expecting a
00053 //               little-endian 16-bit byte count as a prefix.  If the
00054 //               socket stream is non-blocking, may return false if
00055 //               the data is not available; otherwise, returns false
00056 //               only if the socket closes.
00057 ////////////////////////////////////////////////////////////////////
00058 bool SSReader::
00059 do_receive_datagram(Datagram &dg) {
00060   if (_tcp_header_size == 0) {
00061     _data_expected = _data_so_far.length();
00062   }
00063   if (_data_expected == 0) {
00064     // Read the first two bytes: the datagram length.
00065     while ((int)_data_so_far.length() < _tcp_header_size) {
00066       int ch = _istream->get();
00067       if (_istream->eof() || _istream->fail()) {
00068         _istream->clear();
00069         return false;
00070       }
00071       _data_so_far += (char)ch;
00072     }
00073 
00074     Datagram header(_data_so_far);
00075     DatagramIterator di(header);
00076     if (_tcp_header_size == 2) {
00077       _data_expected = di.get_uint16();
00078     } else if (_tcp_header_size == 4) {
00079       _data_expected = di.get_uint32();
00080     }
00081     _data_so_far = _data_so_far.substr(_tcp_header_size);
00082 
00083     if (_data_expected == 0) {
00084       // Empty datagram.
00085       dg.clear();
00086       return true;
00087     }
00088   }
00089 
00090   // Read the next n bytes until the datagram is filled.
00091 
00092   static const size_t buffer_size = 1024;
00093   char buffer[buffer_size];
00094 
00095   size_t read_count = min(_data_expected - _data_so_far.length(),
00096                           buffer_size);
00097   _istream->read(buffer, read_count);
00098   size_t count = _istream->gcount();
00099   while (count != 0) {
00100     _data_so_far.append(buffer, count);
00101     
00102     read_count = min(_data_expected - _data_so_far.length(),
00103                      buffer_size);
00104     _istream->read(buffer, read_count);
00105     count = _istream->gcount();
00106   }
00107 
00108   if (_data_so_far.length() < _data_expected) {
00109     // Not yet here.  Clear the istream error flag and return false to
00110     // indicate more coming.
00111     _istream->clear();
00112     return false;
00113   }
00114 
00115   dg.clear();
00116   dg.append_data(_data_so_far);
00117 
00118   _data_expected = 0;
00119   _data_so_far = string();
00120 
00121   return true;
00122 }
00123 
00124 #ifdef SIMULATE_NETWORK_DELAY
00125 ////////////////////////////////////////////////////////////////////
00126 //     Function: SSReader::start_delay
00127 //       Access: Published
00128 //  Description: Enables a simulated network latency.  All datagrams
00129 //               received from this point on will be held for a random
00130 //               interval of least min_delay seconds, and no more than
00131 //               max_delay seconds, before being visible.  It is as if
00132 //               datagrams suddenly took much longer to arrive.
00133 //
00134 //               This should *only* be called if the underlying socket
00135 //               is non-blocking.  If you call this on a blocking
00136 //               socket, it will force all datagrams to be held up
00137 //               until the socket closes.
00138 ////////////////////////////////////////////////////////////////////
00139 void SSReader::
00140 start_delay(double min_delay, double max_delay) {
00141   _min_delay = min_delay;
00142   _delay_variance = max(max_delay - min_delay, 0.0);
00143   _delay_active = true;
00144 }
00145 #endif  // SIMULATE_NETWORK_DELAY
00146 
00147 #ifdef SIMULATE_NETWORK_DELAY
00148 ////////////////////////////////////////////////////////////////////
00149 //     Function: SSReader::stop_delay
00150 //       Access: Published
00151 //  Description: Disables the simulated network latency started by a
00152 //               previous call to start_delay().  Datagrams will once
00153 //               again be visible as soon as they are received.
00154 ////////////////////////////////////////////////////////////////////
00155 void SSReader::
00156 stop_delay() {
00157   _delay_active = false;
00158 }
00159 #endif  // SIMULATE_NETWORK_DELAY
00160 
00161 #ifdef SIMULATE_NETWORK_DELAY
00162 ////////////////////////////////////////////////////////////////////
00163 //     Function: SSReader::delay_datagram
00164 //       Access: Private
00165 //  Description: Adds the datagram to the delay queue for a random
00166 //               time interval.
00167 ////////////////////////////////////////////////////////////////////
00168 void SSReader::
00169 delay_datagram(const Datagram &datagram) {
00170   nassertv(_delay_active);
00171 
00172   double now = TrueClock::get_global_ptr()->get_short_time();
00173   double reveal_time = now + _min_delay;
00174   
00175   if (_delay_variance > 0.0) {
00176     reveal_time += _delay_variance * ((double)rand() / (double)RAND_MAX);
00177   }
00178   _delayed.push_back(DelayedDatagram());
00179   DelayedDatagram &dd = _delayed.back();
00180   dd._reveal_time = reveal_time;
00181   dd._datagram = datagram;
00182 }
00183 #endif  // SIMULATE_NETWORK_DELAY
00184 
00185 #ifdef SIMULATE_NETWORK_DELAY
00186 ////////////////////////////////////////////////////////////////////
00187 //     Function: SSReader::get_delayed
00188 //       Access: Private
00189 //  Description: Checks the delayed queue for any now available
00190 //               datagrams.  If any are available, returns true and
00191 //               fills datagram with its value.
00192 ////////////////////////////////////////////////////////////////////
00193 bool SSReader::
00194 get_delayed(Datagram &datagram) {
00195   if (_delayed.empty()) {
00196     return false;
00197   }
00198   const DelayedDatagram &dd = _delayed.front();
00199   if (_delay_active) {
00200     double now = TrueClock::get_global_ptr()->get_short_time();
00201     if (dd._reveal_time > now) {
00202       // Not yet.
00203       return false;
00204     }
00205   }
00206 
00207   datagram = dd._datagram;
00208   _delayed.pop_front();
00209 
00210   return true;
00211 }
00212 #endif  // SIMULATE_NETWORK_DELAY
00213 
00214 ////////////////////////////////////////////////////////////////////
00215 //     Function: SSWriter::Constructor
00216 //       Access: Public
00217 //  Description:
00218 ////////////////////////////////////////////////////////////////////
00219 SSWriter::
00220 SSWriter(ostream *stream) : _ostream(stream) {
00221   _collect_tcp = collect_tcp;
00222   _collect_tcp_interval = collect_tcp_interval;
00223   _queued_data_start = 0.0;
00224   _tcp_header_size = tcp_header_size;
00225 }
00226 
00227 ////////////////////////////////////////////////////////////////////
00228 //     Function: SSWriter::Destructor
00229 //       Access: Public, Virtual
00230 //  Description: 
00231 ////////////////////////////////////////////////////////////////////
00232 SSWriter::
00233 ~SSWriter() {
00234 }
00235 
00236 ////////////////////////////////////////////////////////////////////
00237 //     Function: SSWriter::send_datagram
00238 //       Access: Public
00239 //  Description: Transmits the indicated datagram over the socket by
00240 //               prepending it with a little-endian 16-bit byte count.
00241 //               Does not return until the data is sent or the
00242 //               connection is closed, even if the socket stream is
00243 //               non-blocking.
00244 ////////////////////////////////////////////////////////////////////
00245 bool SSWriter::
00246 send_datagram(const Datagram &dg) {
00247   Datagram header;
00248   if (_tcp_header_size == 2) {
00249     if (dg.get_length() >= 0x10000) {
00250       downloader_cat.error()
00251         << "Attempt to send TCP datagram of " << dg.get_length()
00252         << " bytes--too long!\n";
00253       nassert_raise("Datagram too long");
00254       return false;
00255     }
00256     
00257     header.add_uint16(dg.get_length());
00258   } else if (_tcp_header_size == 4) {
00259     header.add_uint32(dg.get_length());
00260   }
00261 
00262   // These two writes don't generate two socket calls, because the
00263   // socket stream is always buffered.
00264   _ostream->write((const char *)header.get_data(), header.get_length());
00265   _ostream->write((const char *)dg.get_data(), dg.get_length());
00266 
00267   // Now flush the buffer immediately, forcing the data to be sent
00268   // (unless collect-tcp mode is in effect).
00269   flush();
00270 
00271   return !is_closed();
00272 }
00273 
00274 ////////////////////////////////////////////////////////////////////
00275 //     Function: ISocketStream::Destructor
00276 //       Access: Published, Virtual
00277 //  Description: 
00278 ////////////////////////////////////////////////////////////////////
00279 ISocketStream::
00280 ~ISocketStream() {
00281   // This should already have been cleared by the subclass destructor.
00282   nassertv(_channel == NULL);
00283 }
00284 
00285 #endif  // HAVE_OPENSSL
 All Classes Functions Variables Enumerations