Panda3D

bioStreamBuf.cxx

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
 All Classes Functions Variables Enumerations