Panda3D
 All Classes Functions Variables Enumerations
socketStream.cxx
1 // Filename: socketStream.cxx
2 // Created by: drose (19Oct02)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "socketStream.h"
16 #include "datagram.h"
17 #include "datagramIterator.h"
18 #include "httpChannel.h"
19 #include "config_downloader.h"
20 
21 #ifdef HAVE_OPENSSL
22 
23 ////////////////////////////////////////////////////////////////////
24 // Function: SSReader::Constructor
25 // Access: Public
26 // Description:
27 ////////////////////////////////////////////////////////////////////
28 SSReader::
29 SSReader(istream *stream) : _istream(stream) {
30  _data_expected = 0;
31  _tcp_header_size = tcp_header_size;
32 
33 #ifdef SIMULATE_NETWORK_DELAY
34  _delay_active = false;
35  _min_delay = 0.0;
36  _delay_variance = 0.0;
37 #endif // SIMULATE_NETWORK_DELAY
38 }
39 
40 ////////////////////////////////////////////////////////////////////
41 // Function: SSReader::Destructor
42 // Access: Public, Virtual
43 // Description:
44 ////////////////////////////////////////////////////////////////////
45 SSReader::
46 ~SSReader() {
47 }
48 
49 ////////////////////////////////////////////////////////////////////
50 // Function: SSReader::do_receive_datagram
51 // Access: Private
52 // Description: Receives a datagram over the socket by expecting a
53 // little-endian 16-bit byte count as a prefix. If the
54 // socket stream is non-blocking, may return false if
55 // the data is not available; otherwise, returns false
56 // only if the socket closes.
57 ////////////////////////////////////////////////////////////////////
58 bool SSReader::
59 do_receive_datagram(Datagram &dg) {
60  if (_tcp_header_size == 0) {
61  _data_expected = _data_so_far.length();
62  }
63  if (_data_expected == 0) {
64  // Read the first two bytes: the datagram length.
65  while ((int)_data_so_far.length() < _tcp_header_size) {
66  int ch = _istream->get();
67  if (_istream->eof() || _istream->fail()) {
68  _istream->clear();
69  return false;
70  }
71  _data_so_far += (char)ch;
72  }
73 
74  Datagram header(_data_so_far);
75  DatagramIterator di(header);
76  if (_tcp_header_size == 2) {
77  _data_expected = di.get_uint16();
78  } else if (_tcp_header_size == 4) {
79  _data_expected = di.get_uint32();
80  }
81  _data_so_far = _data_so_far.substr(_tcp_header_size);
82 
83  if (_data_expected == 0) {
84  // Empty datagram.
85  dg.clear();
86  return true;
87  }
88  }
89 
90  // Read the next n bytes until the datagram is filled.
91 
92  static const size_t buffer_size = 1024;
93  char buffer[buffer_size];
94 
95  size_t read_count = min(_data_expected - _data_so_far.length(),
96  buffer_size);
97  _istream->read(buffer, read_count);
98  size_t count = _istream->gcount();
99  while (count != 0) {
100  _data_so_far.append(buffer, count);
101 
102  read_count = min(_data_expected - _data_so_far.length(),
103  buffer_size);
104  _istream->read(buffer, read_count);
105  count = _istream->gcount();
106  }
107 
108  if (_data_so_far.length() < _data_expected) {
109  // Not yet here. Clear the istream error flag and return false to
110  // indicate more coming.
111  _istream->clear();
112  return false;
113  }
114 
115  dg.clear();
116  dg.append_data(_data_so_far);
117 
118  _data_expected = 0;
119  _data_so_far = string();
120 
121  return true;
122 }
123 
124 #ifdef SIMULATE_NETWORK_DELAY
125 ////////////////////////////////////////////////////////////////////
126 // Function: SSReader::start_delay
127 // Access: Published
128 // Description: Enables a simulated network latency. All datagrams
129 // received from this point on will be held for a random
130 // interval of least min_delay seconds, and no more than
131 // max_delay seconds, before being visible. It is as if
132 // datagrams suddenly took much longer to arrive.
133 //
134 // This should *only* be called if the underlying socket
135 // is non-blocking. If you call this on a blocking
136 // socket, it will force all datagrams to be held up
137 // until the socket closes.
138 ////////////////////////////////////////////////////////////////////
139 void SSReader::
140 start_delay(double min_delay, double max_delay) {
141  _min_delay = min_delay;
142  _delay_variance = max(max_delay - min_delay, 0.0);
143  _delay_active = true;
144 }
145 #endif // SIMULATE_NETWORK_DELAY
146 
147 #ifdef SIMULATE_NETWORK_DELAY
148 ////////////////////////////////////////////////////////////////////
149 // Function: SSReader::stop_delay
150 // Access: Published
151 // Description: Disables the simulated network latency started by a
152 // previous call to start_delay(). Datagrams will once
153 // again be visible as soon as they are received.
154 ////////////////////////////////////////////////////////////////////
155 void SSReader::
156 stop_delay() {
157  _delay_active = false;
158 }
159 #endif // SIMULATE_NETWORK_DELAY
160 
161 #ifdef SIMULATE_NETWORK_DELAY
162 ////////////////////////////////////////////////////////////////////
163 // Function: SSReader::delay_datagram
164 // Access: Private
165 // Description: Adds the datagram to the delay queue for a random
166 // time interval.
167 ////////////////////////////////////////////////////////////////////
168 void SSReader::
169 delay_datagram(const Datagram &datagram) {
170  nassertv(_delay_active);
171 
172  double now = TrueClock::get_global_ptr()->get_short_time();
173  double reveal_time = now + _min_delay;
174 
175  if (_delay_variance > 0.0) {
176  reveal_time += _delay_variance * ((double)rand() / (double)RAND_MAX);
177  }
178  _delayed.push_back(DelayedDatagram());
179  DelayedDatagram &dd = _delayed.back();
180  dd._reveal_time = reveal_time;
181  dd._datagram = datagram;
182 }
183 #endif // SIMULATE_NETWORK_DELAY
184 
185 #ifdef SIMULATE_NETWORK_DELAY
186 ////////////////////////////////////////////////////////////////////
187 // Function: SSReader::get_delayed
188 // Access: Private
189 // Description: Checks the delayed queue for any now available
190 // datagrams. If any are available, returns true and
191 // fills datagram with its value.
192 ////////////////////////////////////////////////////////////////////
193 bool SSReader::
194 get_delayed(Datagram &datagram) {
195  if (_delayed.empty()) {
196  return false;
197  }
198  const DelayedDatagram &dd = _delayed.front();
199  if (_delay_active) {
200  double now = TrueClock::get_global_ptr()->get_short_time();
201  if (dd._reveal_time > now) {
202  // Not yet.
203  return false;
204  }
205  }
206 
207  datagram = dd._datagram;
208  _delayed.pop_front();
209 
210  return true;
211 }
212 #endif // SIMULATE_NETWORK_DELAY
213 
214 ////////////////////////////////////////////////////////////////////
215 // Function: SSWriter::Constructor
216 // Access: Public
217 // Description:
218 ////////////////////////////////////////////////////////////////////
219 SSWriter::
220 SSWriter(ostream *stream) : _ostream(stream) {
221  _collect_tcp = collect_tcp;
222  _collect_tcp_interval = collect_tcp_interval;
223  _queued_data_start = 0.0;
224  _tcp_header_size = tcp_header_size;
225 }
226 
227 ////////////////////////////////////////////////////////////////////
228 // Function: SSWriter::Destructor
229 // Access: Public, Virtual
230 // Description:
231 ////////////////////////////////////////////////////////////////////
232 SSWriter::
233 ~SSWriter() {
234 }
235 
236 ////////////////////////////////////////////////////////////////////
237 // Function: SSWriter::send_datagram
238 // Access: Public
239 // Description: Transmits the indicated datagram over the socket by
240 // prepending it with a little-endian 16-bit byte count.
241 // Does not return until the data is sent or the
242 // connection is closed, even if the socket stream is
243 // non-blocking.
244 ////////////////////////////////////////////////////////////////////
245 bool SSWriter::
246 send_datagram(const Datagram &dg) {
247  Datagram header;
248  if (_tcp_header_size == 2) {
249  if (dg.get_length() >= 0x10000) {
250  downloader_cat.error()
251  << "Attempt to send TCP datagram of " << dg.get_length()
252  << " bytes--too long!\n";
253  nassert_raise("Datagram too long");
254  return false;
255  }
256 
257  header.add_uint16(dg.get_length());
258  } else if (_tcp_header_size == 4) {
259  header.add_uint32(dg.get_length());
260  }
261 
262  // These two writes don't generate two socket calls, because the
263  // socket stream is always buffered.
264  _ostream->write((const char *)header.get_data(), header.get_length());
265  _ostream->write((const char *)dg.get_data(), dg.get_length());
266 
267  // Now flush the buffer immediately, forcing the data to be sent
268  // (unless collect-tcp mode is in effect).
269  flush();
270 
271  return !is_closed();
272 }
273 
274 ////////////////////////////////////////////////////////////////////
275 // Function: ISocketStream::Destructor
276 // Access: Published, Virtual
277 // Description:
278 ////////////////////////////////////////////////////////////////////
279 ISocketStream::
280 ~ISocketStream() {
281  // This should already have been cleared by the subclass destructor.
282  nassertv(_channel == NULL);
283 }
284 
285 #endif // HAVE_OPENSSL
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
Definition: trueClock.I:81
void append_data(const void *data, size_t size)
Appends some more raw data to the end of the datagram.
Definition: datagram.cxx:144
virtual void clear()
Resets the datagram to empty, in preparation for building up a new datagram.
Definition: datagram.cxx:41
size_t get_length() const
Returns the number of bytes in the datagram.
Definition: datagram.I:457
void add_uint16(PN_uint16 value)
Adds an unsigned 16-bit integer to the datagram.
Definition: datagram.I:181
void add_uint32(PN_uint32 value)
Adds an unsigned 32-bit integer to the datagram.
Definition: datagram.I:192
const void * get_data() const
Returns a pointer to the beginning of the datagram&#39;s data.
Definition: datagram.I:447
A class to retrieve the individual data elements previously stored in a Datagram. ...
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43