00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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>
00025 #undef X509_NAME
00026 #endif // WIN32_VC
00027
00028 #ifndef HAVE_STREAMSIZE
00029
00030 typedef int streamsize;
00031 #endif
00032
00033
00034
00035
00036
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
00053
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
00064
00065
00066
00067 BioStreamBuf::
00068 ~BioStreamBuf() {
00069 close();
00070 #ifdef PHAVE_IOSTREAM
00071 PANDA_FREE_ARRAY(_buffer);
00072 #endif
00073 }
00074
00075
00076
00077
00078
00079
00080 void BioStreamBuf::
00081 open(BioPtr *source) {
00082 _source = source;
00083 _read_open = true;
00084 _write_open = true;
00085 }
00086
00087
00088
00089
00090
00091
00092 void BioStreamBuf::
00093 close() {
00094 sync();
00095 _source.clear();
00096 _read_open = false;
00097 _write_open = false;
00098 }
00099
00100
00101
00102
00103
00104
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
00123 *pptr() = ch;
00124 pbump(1);
00125 }
00126
00127 return 0;
00128 }
00129
00130
00131
00132
00133
00134
00135
00136 int BioStreamBuf::
00137 sync() {
00138
00139
00140
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
00162
00163
00164
00165
00166 int BioStreamBuf::
00167 underflow() {
00168
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
00176
00177 int read_count = BIO_read(*_source, gptr(), buffer_size);
00178 thread_consider_yield();
00179
00180 if (read_count != (int)num_bytes) {
00181
00182 if (read_count <= 0) {
00183
00184
00185
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
00193
00194
00195
00196 _read_open = (BIO_should_retry(*_source) != 0);
00197
00198 #ifdef IS_OSX
00199
00200
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
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
00252
00253
00254
00255
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
00267
00268
00269
00270
00271
00272
00273
00274
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
00281
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
00294
00295 thread_yield();
00296 #else
00297
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
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
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