Panda3D
|
00001 // Filename: bioStreamBuf.cxx 00002 // Created by: drose (25Sep02) 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 "bioStreamBuf.h" 00016 #include "config_downloader.h" 00017 #include "openSSLWrapper.h" 00018 #include <errno.h> 00019 00020 #ifdef HAVE_OPENSSL 00021 00022 #if defined(WIN32_VC) || defined(WIN64_VC) 00023 #include <WinSock2.h> 00024 #include <windows.h> // for WSAGetLastError() 00025 #undef X509_NAME 00026 #endif // WIN32_VC 00027 00028 #ifndef HAVE_STREAMSIZE 00029 // Some compilers (notably SGI) don't define this for us 00030 typedef int streamsize; 00031 #endif /* HAVE_STREAMSIZE */ 00032 00033 //////////////////////////////////////////////////////////////////// 00034 // Function: BioStreamBuf::Constructor 00035 // Access: Public 00036 // Description: 00037 //////////////////////////////////////////////////////////////////// 00038 BioStreamBuf:: 00039 BioStreamBuf() { 00040 _read_open = false; 00041 _write_open = false; 00042 00043 #ifdef PHAVE_IOSTREAM 00044 _buffer = (char *)PANDA_MALLOC_ARRAY(8192); 00045 char *ebuf = _buffer + 8192; 00046 char *mbuf = _buffer + 4096; 00047 setg(_buffer, mbuf, mbuf); 00048 setp(mbuf, ebuf); 00049 00050 #else 00051 allocate(); 00052 // Chop the buffer in half. The bottom half goes to the get buffer; 00053 // the top half goes to the put buffer. 00054 char *b = base(); 00055 char *t = ebuf(); 00056 char *m = b + (t - b) / 2; 00057 setg(b, m, m); 00058 setp(b, m); 00059 #endif 00060 } 00061 00062 //////////////////////////////////////////////////////////////////// 00063 // Function: BioStreamBuf::Destructor 00064 // Access: Public, Virtual 00065 // Description: 00066 //////////////////////////////////////////////////////////////////// 00067 BioStreamBuf:: 00068 ~BioStreamBuf() { 00069 close(); 00070 #ifdef PHAVE_IOSTREAM 00071 PANDA_FREE_ARRAY(_buffer); 00072 #endif 00073 } 00074 00075 //////////////////////////////////////////////////////////////////// 00076 // Function: BioStreamBuf::open 00077 // Access: Public 00078 // Description: 00079 //////////////////////////////////////////////////////////////////// 00080 void BioStreamBuf:: 00081 open(BioPtr *source) { 00082 _source = source; 00083 _read_open = true; 00084 _write_open = true; 00085 } 00086 00087 //////////////////////////////////////////////////////////////////// 00088 // Function: BioStreamBuf::close 00089 // Access: Public 00090 // Description: 00091 //////////////////////////////////////////////////////////////////// 00092 void BioStreamBuf:: 00093 close() { 00094 sync(); 00095 _source.clear(); 00096 _read_open = false; 00097 _write_open = false; 00098 } 00099 00100 //////////////////////////////////////////////////////////////////// 00101 // Function: BioStreamBuf::overflow 00102 // Access: Protected, Virtual 00103 // Description: Called by the system ostream implementation when its 00104 // internal buffer is filled, plus one character. 00105 //////////////////////////////////////////////////////////////////// 00106 int BioStreamBuf:: 00107 overflow(int ch) { 00108 size_t n = pptr() - pbase(); 00109 if (downloader_cat.is_spam()) { 00110 downloader_cat.spam() 00111 << "BioStreamBuf::overflow, " << n << " bytes\n"; 00112 } 00113 if (n != 0) { 00114 size_t num_wrote = write_chars(pbase(), n); 00115 pbump(-(int)n); 00116 if (num_wrote != n) { 00117 return EOF; 00118 } 00119 } 00120 00121 if (ch != EOF) { 00122 // Store the next character back in the buffer. 00123 *pptr() = ch; 00124 pbump(1); 00125 } 00126 00127 return 0; 00128 } 00129 00130 //////////////////////////////////////////////////////////////////// 00131 // Function: BioStreamBuf::sync 00132 // Access: Protected, Virtual 00133 // Description: Called by the system iostream implementation to 00134 // implement a flush operation. 00135 //////////////////////////////////////////////////////////////////// 00136 int BioStreamBuf:: 00137 sync() { 00138 /* 00139 size_t n = egptr() - gptr(); 00140 gbump(n); 00141 */ 00142 00143 size_t n = pptr() - pbase(); 00144 00145 if (downloader_cat.is_spam() && n != 0) { 00146 downloader_cat.spam() 00147 << "BioStreamBuf::sync, " << n << " bytes\n"; 00148 } 00149 00150 size_t num_wrote = write_chars(pbase(), n); 00151 pbump(-(int)n); 00152 00153 if (num_wrote != n) { 00154 return EOF; 00155 } 00156 00157 return 0; 00158 } 00159 00160 //////////////////////////////////////////////////////////////////// 00161 // Function: BioStreamBuf::underflow 00162 // Access: Protected, Virtual 00163 // Description: Called by the system istream implementation when its 00164 // internal buffer needs more characters. 00165 //////////////////////////////////////////////////////////////////// 00166 int BioStreamBuf:: 00167 underflow() { 00168 // Sometimes underflow() is called even if the buffer is not empty. 00169 if (gptr() >= egptr()) { 00170 size_t buffer_size = egptr() - eback(); 00171 gbump(-(int)buffer_size); 00172 00173 size_t num_bytes = buffer_size; 00174 00175 // BIO_read might return -1 or -2 on eof or error, so we have to 00176 // allow for negative numbers. 00177 int read_count = BIO_read(*_source, gptr(), buffer_size); 00178 thread_consider_yield(); 00179 00180 if (read_count != (int)num_bytes) { 00181 // Oops, we didn't read what we thought we would. 00182 if (read_count <= 0) { 00183 // Immediately save the os error in case we screw up and do 00184 // something that will change its value before we can output 00185 // it. 00186 #if defined(WIN32_VC) || defined(WIN64_VC) 00187 int os_error = WSAGetLastError(); 00188 #else 00189 int os_error = errno; 00190 #endif // WIN32_VC 00191 00192 // Though BIO_eof() is tempting, it appears there are cases in 00193 // which that never returns true, if the socket is closed by 00194 // the server. But BIO_should_retry() *appears* to be 00195 // reliable. 00196 _read_open = (BIO_should_retry(*_source) != 0); 00197 00198 #ifdef IS_OSX 00199 // occassionally we get -1 on read_open on the mac 00200 // the os_error is 35 which means "Resource temporarily unavailable". 00201 if ( (_read_open == -1) && (os_error == 35)) { 00202 downloader_cat.warning() << "forcing retry to true again and _read_open to true\n"; 00203 BIO_set_retry_read(*_source); 00204 _read_open = true; 00205 } 00206 #endif 00207 if (!_read_open) { 00208 downloader_cat.info() 00209 << "Lost connection to " 00210 << _source->get_server_name() << ":" 00211 << _source->get_port() << " (" << read_count << ").\n"; 00212 OpenSSLWrapper::get_global_ptr()->notify_ssl_errors(); 00213 00214 SSL *ssl = NULL; 00215 BIO_get_ssl(*_source, &ssl); 00216 if (ssl != (SSL *)NULL) { 00217 downloader_cat.warning() 00218 << "OpenSSL error code: " << SSL_get_error(ssl, read_count) 00219 << "\n"; 00220 } 00221 00222 #if defined(WIN32_VC) || defined(WIN64_VC) 00223 downloader_cat.warning() 00224 << "Windows error code: " << os_error << "\n"; 00225 #else 00226 downloader_cat.warning() 00227 << "Unix error code: " << os_error << "\n"; 00228 #endif // WIN32_VC 00229 } 00230 gbump(num_bytes); 00231 return EOF; 00232 } 00233 00234 // Slide what we did read to the top of the buffer. 00235 nassertr(read_count < (int)num_bytes, EOF); 00236 size_t delta = (int)num_bytes - read_count; 00237 memmove(gptr() + delta, gptr(), read_count); 00238 gbump(delta); 00239 } 00240 00241 if (downloader_cat.is_spam()) { 00242 downloader_cat.spam() 00243 << "read " << read_count << " bytes from " << _source << "\n"; 00244 } 00245 } 00246 00247 return (unsigned char)*gptr(); 00248 } 00249 00250 //////////////////////////////////////////////////////////////////// 00251 // Function: BioStreamBuf::write_chars 00252 // Access: Private 00253 // Description: Sends some characters to the dest stream. Does not 00254 // return until all characters are sent or the socket is 00255 // closed, even if the underlying BIO is non-blocking. 00256 //////////////////////////////////////////////////////////////////// 00257 size_t BioStreamBuf:: 00258 write_chars(const char *start, size_t length) { 00259 if (length != 0) { 00260 size_t wrote_so_far = 0; 00261 00262 int write_count = BIO_write(*_source, start, length); 00263 thread_consider_yield(); 00264 while (write_count != (int)(length - wrote_so_far)) { 00265 if (write_count <= 0) { 00266 // http://www.openssl.org/docs/crypto/BIO_s_bio.html 00267 // "Calls to BIO_write() will place data in the buffer or 00268 // request a retry if the buffer is full." 00269 // 00270 // when the server is terminated, this seems to be the best 00271 // way of detecting that case on the client: a BIO write error 00272 // without a retry request 00273 //_write_open = BIO_should_retry(*_source); 00274 //_write_open = !BIO_eof(*_source); 00275 _write_open = (BIO_should_write(*_source) != 0 || BIO_should_retry(*_source) != 0); 00276 if (!_write_open) { 00277 return wrote_so_far; 00278 } 00279 00280 // Block on the underlying socket before we try to write some 00281 // more. 00282 int fd = -1; 00283 BIO_get_fd(*_source, &fd); 00284 if (fd < 0) { 00285 downloader_cat.warning() 00286 << "socket BIO has no file descriptor.\n"; 00287 } else { 00288 if (downloader_cat.is_spam()) { 00289 downloader_cat.spam() 00290 << "waiting to write to BIO.\n"; 00291 } 00292 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS) 00293 // In SIMPLE_THREADS mode, instead of blocking, simply yield 00294 // the thread. 00295 thread_yield(); 00296 #else 00297 // In any other threading mode, we actually want to block. 00298 fd_set wset; 00299 FD_ZERO(&wset); 00300 FD_SET(fd, &wset); 00301 select(fd + 1, NULL, &wset, NULL, NULL); 00302 #endif // SIMPLE_THREADS 00303 } 00304 00305 } else { 00306 // wrote some characters. 00307 wrote_so_far += write_count; 00308 if (downloader_cat.is_spam()) { 00309 downloader_cat.spam() 00310 << "wrote " << write_count << " bytes to " << _source << "\n"; 00311 } 00312 } 00313 00314 // Try to write some more. 00315 write_count = BIO_write(*_source, start + wrote_so_far, length - wrote_so_far); 00316 if (downloader_cat.is_spam()) { 00317 downloader_cat.spam() 00318 << "continued, wrote " << write_count << " bytes.\n"; 00319 } 00320 thread_consider_yield(); 00321 } 00322 if (downloader_cat.is_spam()) { 00323 downloader_cat.spam() 00324 << "wrote " << write_count << " bytes to " << _source << "\n"; 00325 } 00326 } 00327 00328 return length; 00329 } 00330 00331 #endif // HAVE_OPENSSL