From f5adb8ca21f18d2b37cb21223f4aa209f6c85709 Mon Sep 17 00:00:00 2001 From: Mike Goslin Date: Sat, 9 Dec 2000 22:08:03 +0000 Subject: [PATCH] *** empty log message *** --- panda/src/downloader/downloader.cxx | 280 ++++++++++++++-------------- panda/src/downloader/downloader.h | 5 +- 2 files changed, 148 insertions(+), 137 deletions(-) diff --git a/panda/src/downloader/downloader.cxx b/panda/src/downloader/downloader.cxx index d5bc782d4c..a24c7221c2 100644 --- a/panda/src/downloader/downloader.cxx +++ b/panda/src/downloader/downloader.cxx @@ -412,14 +412,14 @@ safe_send(int socket, const char *data, int length, long timeout) { // Description: //////////////////////////////////////////////////////////////////// int Downloader:: -safe_receive(int socket, char *data, int length, long timeout, int &bytes) { - char *data_ptr = data; +safe_receive(int socket, DownloadStatus &status, int length, + long timeout, int &bytes) { + bytes = 0; if (length == 0) { downloader_cat.error() << "Downloader::safe_receive() - requested 0 length receive!" << endl; return RS_error; } - bytes = 0; struct timeval tv; tv.tv_sec = timeout; tv.tv_usec = 0; @@ -438,14 +438,15 @@ safe_receive(int socket, char *data, int length, long timeout, int &bytes) { << "Downloader::safe_receive() - error: " << strerror(errno) << endl; return RS_error; } - int ret = recv(socket, data_ptr, length - bytes, 0); + int ret = recv(socket, status._next_in, length - bytes, 0); if (ret > 0) { if (downloader_cat.is_debug()) downloader_cat.debug() << "Downloader::safe_receive() - recv() got: " << ret << " bytes" << endl; bytes += ret; - data_ptr += ret; + status._next_in += ret; + status._bytes_in_buffer += ret; } else if (ret == 0) { if (downloader_cat.is_debug()) downloader_cat.debug() @@ -457,9 +458,61 @@ safe_receive(int socket, char *data, int length, long timeout, int &bytes) { return RS_error; } } + nassertr(bytes == length, RS_error); return RS_success; } +//////////////////////////////////////////////////////////////////// +// Function: Downloader::attempt_read +// Access: Private +// Description: +//////////////////////////////////////////////////////////////////// +int Downloader:: +attempt_read(int length, DownloadStatus &status, int &bytes_read) { + + bytes_read = 0; + for (int i = 0; i < downloader_timeout_retries; i++) { + + // Ensure we have enough room in the buffer to download length bytes + // If we don't have enough room, write the buffer to disk + if (status._bytes_in_buffer + length > _buffer_size) { + if (downloader_cat.is_debug()) + downloader_cat.debug() + << "Downloader::attempt_read() - Flushing buffer" << endl; + + if (write_to_disk(status) == false) + return RS_error; + } + + // Make the request for length bytes + int bytes; + int ans = safe_receive(_socket, status, length, + (long)downloader_timeout, bytes); + bytes_read += bytes; + + switch (ans) { + case RS_error: + case RS_eof: + return ans; + case RS_timeout: + // Try again + break; + case RS_success: + nassertr(bytes_read == length, RS_error); + return RS_success; + default: + downloader_cat.error() + << "Downloader::attempt_read() - unknown return condition " + << "from safe_receive() : " << ans << endl; + return RS_error; + } + } + + // We timed out on retries consecutive attempts - this is considered + // a true timeout + return RS_timeout; +} + //////////////////////////////////////////////////////////////////// // Function: Downloader::download // Access: Private @@ -470,6 +523,13 @@ download(const string &file_name, Filename file_dest, const string &event_name, int first_byte, int last_byte, int total_bytes, bool partial_content, uint id) { + if (_download_enabled == false) { + if (downloader_cat.is_debug()) + downloader_cat.debug() + << "Downloader::download() - downloading is disabled" << endl; + return false; + } + // Make sure we are still connected to the server if (connect_to_server() == false) return false; @@ -512,6 +572,7 @@ download(const string &file_name, Filename file_dest, int send_ret = safe_send(_socket, request.c_str(), outlen, (long)downloader_timeout); + // Handle timeouts on the send if (send_ret == SS_timeout) { for (int sr = 0; sr < downloader_timeout_retries; sr++) { send_ret = safe_send(_socket, request.c_str(), outlen, @@ -536,167 +597,116 @@ download(const string &file_name, Filename file_dest, if (send_ret == SS_error) return false; - // Loop at the requested frequency until the download completes + // Create a download status to maintain download progress information DownloadStatus status(_buffer->_buffer, event_name, first_byte, last_byte, total_bytes, partial_content, id); bool got_any_data = false; - bool timeout_updated_bytes_in_buffer = false; + // Loop at the requested frequency until the download completes for (;;) { - if (_download_enabled) { - // Ensure that these don't change while we're computing read_size + // Ensure that these don't change while we're computing read_size #ifdef HAVE_IPC - _bandwidth_frequency_lock.lock(); + _bandwidth_frequency_lock.lock(); #endif - int read_size = (int)_bandwidth; - if (_frequency > 0) - read_size = (int)(_bandwidth * _frequency); + // read_size is the length of the buffer requested via safe_receive() + int read_size = (int)_bandwidth; + if (_frequency > 0) + read_size = (int)(_bandwidth * _frequency); #ifdef HAVE_IPC - _bandwidth_frequency_lock.unlock(); + _bandwidth_frequency_lock.unlock(); #endif - // Ensure we have enough room in the buffer to download read_size - // If we don't have enough room, write the buffer to disk - if (status._bytes_in_buffer + read_size > _buffer_size) { - if (downloader_cat.is_debug()) - downloader_cat.debug() - << "Downloader::download() - Flushing buffer" << endl; + // Attempt to read + int bytes_read; + int ret = attempt_read(read_size, status, bytes_read); + if (bytes_read > 0) + got_any_data = true; - if (write_to_disk(status) == false) - return false; - } + switch (ret) { + case RS_error: - // Grab the next chunk - int bytes = 0; - int ans = safe_receive(_socket, status._next_in, read_size, - (long)downloader_timeout, bytes); + downloader_cat.error() + << "Downloader::download() - Error reading from socket: " + << strerror(errno) << endl; + return false; - // Handle receive timeouts by trying again - if (ans == RS_timeout) { - int extra_bytes = 0; + case RS_timeout: - if (bytes > 0) { - status._bytes_in_buffer += bytes; - status._next_in += bytes; - got_any_data = true; - timeout_updated_bytes_in_buffer = true; - } - - // Ensure we have enough room in the buffer to download read_size - // If we don't have enough room, write the buffer to disk - if (status._bytes_in_buffer + read_size > _buffer_size) { - if (downloader_cat.is_debug()) - downloader_cat.debug() - << "Downloader::download() - Flushing buffer" << endl; - if (write_to_disk(status) == false) - return false; - } - - for (int r = 0; r < downloader_timeout_retries; r++) { - extra_bytes = 0; - - // Ensure we have enough room in the buffer to download read_size - // If we don't have enough room, write the buffer to disk - if (status._bytes_in_buffer + read_size > _buffer_size) { - if (downloader_cat.is_debug()) - downloader_cat.debug() - << "Downloader::download() - Flushing buffer" << endl; - if (write_to_disk(status) == false) - return false; - } - - ans = safe_receive(_socket, status._next_in, read_size, - (long)downloader_timeout, extra_bytes); - - if (extra_bytes > 0) { - bytes += extra_bytes; - status._bytes_in_buffer += bytes; - status._next_in += bytes; - got_any_data = true; - timeout_updated_bytes_in_buffer = true; - } - - if (ans != RS_timeout) - break; - } - - if (ans == RS_timeout) { - // We've really timed out - throw an event + { + // We've really timed out - throw an event downloader_cat.error() << "Downloader::download() - receive timed out after: " << downloader_timeout_retries << " retries" << endl; - if (bytes > 0) { - status._bytes_in_buffer += bytes; - status._next_in += bytes; + if (bytes_read > 0) { if (write_to_disk(status) == false) { downloader_cat.error() - << "Downloader::download() - write to disk failed after " - << "timeout!" << endl; + << "Downloader::download() - write to disk failed after " + << "timeout!" << endl; + return false; } } + + // Throw a timeout event PT_Event timeout_event = new Event(status._event_name); timeout_event->add_parameter(EventParameter((int)status._id)); - timeout_event->add_parameter( - EventParameter(status._total_bytes_written)); + timeout_event->add_parameter(EventParameter(0)); timeout_event->add_parameter(EventParameter(-1)); throw_event(timeout_event); return false; - } - } + } - // Handle receive errors - if (ans == RS_error) { - downloader_cat.error() - << "Downloader::download() - Error reading from socket: " - << strerror(errno) << endl; - return false; - } + case RS_success: - if (ans == RS_eof) { - - if (bytes > 0 || got_any_data == true) { - if (downloader_cat.is_debug()) - downloader_cat.debug() - << "Download for: " << file_name << " completed" << endl; - if (bytes > 0) { - status._bytes_in_buffer += bytes; - status._next_in += bytes; - } - bool ret = write_to_disk(status); - _dest_stream.close(); - - // The "Connection: close" line tells server to close connection - // when the download is complete - _connected = false; - return ret; - } else { - if (downloader_cat.is_debug()) - downloader_cat.debug() - << "Downloader::download() - Received 0 bytes" << endl; - nap(); - } - - } else { // ans == RS_success if (downloader_cat.is_debug()) downloader_cat.debug() - << "Downloader::download() - Got: " << bytes << " bytes" << endl; + << "Downloader::download() - Got: " << bytes_read << " bytes" + << endl; + break; - // If the timeout read data and already updated these variables - // we do not want to update them again - if (timeout_updated_bytes_in_buffer == true) { - // reset this variable and do not update the byte count - timeout_updated_bytes_in_buffer = false; - } else { - status._bytes_in_buffer += bytes; - status._next_in += bytes; - got_any_data = true; - } - - // Sleep for the requested frequency - nap(); - } - } - } + case RS_eof: + + { + // We occasionally will get 0 bytes on the first attempt - we + // don't want to treat this as end of file in any case + if (got_any_data == true) { + if (downloader_cat.is_debug()) + downloader_cat.debug() + << "Download for: " << file_name << " completed" << endl; + bool ret = true; + if (bytes_read > 0) + ret = write_to_disk(status); + _dest_stream.close(); + + // The "Connection: close" line tells server to close connection + // when the download is complete + _connected = false; + return ret; + } else { + if (downloader_cat.is_debug()) + downloader_cat.debug() + << "Downloader::download() - Received 0 bytes" << endl; + } + } + break; + + default: + + downloader_cat.error() + << "Downloader::download() - Unknown return value from " + << "attempt_read() : " << ret << endl; + return false; + + } // switch(ret) + + // Sleep for the requested frequency + nap(); + + } // for (;;) + + downloader_cat.error() + << "Downloader::download() - Dropped out of for loop without returning!" + << endl; + return false; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/downloader/downloader.h b/panda/src/downloader/downloader.h index 95a4cbc7ff..f61c8a4222 100644 --- a/panda/src/downloader/downloader.h +++ b/panda/src/downloader/downloader.h @@ -89,9 +89,10 @@ private: bool write_to_disk(DownloadStatus &status); bool connect_to_server(void); int safe_send(int socket, const char *data, int length, long timeout); - int safe_receive(int socket, char *data, int length, long timeout, - int &bytes); + int safe_receive(int socket, DownloadStatus &status, int length, + long timeout, int &bytes); bool parse_http_response(const string &resp); + int attempt_read(int length, DownloadStatus &status, int &bytes_read); typedef TokenBoard DownloaderTokenBoard; DownloaderTokenBoard *_token_board;