2008-08-06 18:36:30 +00:00
|
|
|
// This file is part of BOINC.
|
2005-01-20 23:22:22 +00:00
|
|
|
// http://boinc.berkeley.edu
|
2008-08-06 18:36:30 +00:00
|
|
|
// Copyright (C) 2008 University of California
|
2003-07-02 02:02:18 +00:00
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// BOINC is free software; you can redistribute it and/or modify it
|
|
|
|
// under the terms of the GNU Lesser General Public License
|
|
|
|
// as published by the Free Software Foundation,
|
|
|
|
// either version 3 of the License, or (at your option) any later version.
|
2003-07-02 02:02:18 +00:00
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// BOINC is distributed in the hope that it will be useful,
|
2005-01-20 23:22:22 +00:00
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
// See the GNU Lesser General Public License for more details.
|
2002-04-30 22:22:54 +00:00
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2003-10-16 19:03:49 +00:00
|
|
|
#include "cpp.h"
|
2002-06-06 18:42:01 +00:00
|
|
|
|
2004-03-05 04:37:53 +00:00
|
|
|
#ifdef _WIN32
|
2004-06-16 23:16:08 +00:00
|
|
|
#include "boinc_win.h"
|
2005-11-21 18:34:44 +00:00
|
|
|
#else
|
|
|
|
#include "config.h"
|
2004-03-05 04:37:53 +00:00
|
|
|
#endif
|
|
|
|
|
2012-04-30 21:00:28 +00:00
|
|
|
#include "error_numbers.h"
|
2016-02-16 05:14:52 +00:00
|
|
|
#include "str_replace.h"
|
2002-07-05 05:33:40 +00:00
|
|
|
#include "file_names.h"
|
2002-08-12 21:54:19 +00:00
|
|
|
#include "filesys.h"
|
2012-04-30 21:00:28 +00:00
|
|
|
#include "parse.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
#include "client_state.h"
|
2004-04-08 08:15:23 +00:00
|
|
|
#include "client_msgs.h"
|
2002-04-30 22:22:54 +00:00
|
|
|
#include "file_xfer.h"
|
2012-04-30 21:00:28 +00:00
|
|
|
#include "project.h"
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2004-06-30 18:17:21 +00:00
|
|
|
using std::vector;
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
FILE_XFER::FILE_XFER() {
|
|
|
|
file_xfer_done = false;
|
|
|
|
file_xfer_retval = 0;
|
2002-07-15 23:21:20 +00:00
|
|
|
fip = NULL;
|
2016-02-16 05:14:52 +00:00
|
|
|
safe_strcpy(pathname, "");
|
|
|
|
safe_strcpy(header, "");
|
2002-08-21 19:12:42 +00:00
|
|
|
file_size_query = false;
|
2015-10-20 13:31:58 +00:00
|
|
|
is_upload = false;
|
|
|
|
starting_size = 0.0;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FILE_XFER::~FILE_XFER() {
|
2003-07-23 22:24:28 +00:00
|
|
|
if (fip && fip->pers_file_xfer) {
|
|
|
|
fip->pers_file_xfer->fxp = NULL;
|
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
2002-07-05 05:33:40 +00:00
|
|
|
int FILE_XFER::init_download(FILE_INFO& file_info) {
|
2003-05-10 00:52:36 +00:00
|
|
|
is_upload = false;
|
2002-07-05 05:33:40 +00:00
|
|
|
fip = &file_info;
|
2019-09-05 22:43:15 +00:00
|
|
|
|
|
|
|
// create subdirs of project dir if needed
|
|
|
|
//
|
|
|
|
int retval = boinc_make_dirs(fip->project->project_dir(), fip->name);
|
|
|
|
if (retval) return retval;
|
|
|
|
|
2007-03-13 19:33:27 +00:00
|
|
|
get_pathname(fip, pathname, sizeof(pathname));
|
- client: add a mechanism for restartable download of compressed files.
(It turns out that the compression schemes supported by
Apache and libcurl, suprisingly, aren't restartable.)
if a <file_info> from the server contains <gzipped_url> tags,
use those instead of the <url> tags,
and flag the file as "download_gzipped".
If this is the case, download NAME.gz and save it as NAME.gzt.
When the download is complete, rename NAME.gzt to NAME.gz,
and uncompress it to NAME.
(this ensures that if NAME.gz is present, it's complete).
Also do the uncompression, if needed, in verify_file().
This ensures that the uncompression will eventually get done
even if the client quits are crashes in the middle.
- update_versions: if <gzip> is present in a <file_info>,
add a gzipped copy in the download directory
and add a <gzipped_url> elements to the app version's xml_doc.
svn path=/trunk/boinc/; revision=25112
2012-01-20 23:34:15 +00:00
|
|
|
if (fip->download_gzipped) {
|
2016-02-16 05:14:52 +00:00
|
|
|
safe_strcat(pathname, ".gzt");
|
- client: add a mechanism for restartable download of compressed files.
(It turns out that the compression schemes supported by
Apache and libcurl, suprisingly, aren't restartable.)
if a <file_info> from the server contains <gzipped_url> tags,
use those instead of the <url> tags,
and flag the file as "download_gzipped".
If this is the case, download NAME.gz and save it as NAME.gzt.
When the download is complete, rename NAME.gzt to NAME.gz,
and uncompress it to NAME.
(this ensures that if NAME.gz is present, it's complete).
Also do the uncompression, if needed, in verify_file().
This ensures that the uncompression will eventually get done
even if the client quits are crashes in the middle.
- update_versions: if <gzip> is present in a <file_info>,
add a gzipped copy in the download directory
and add a <gzipped_url> elements to the app version's xml_doc.
svn path=/trunk/boinc/; revision=25112
2012-01-20 23:34:15 +00:00
|
|
|
}
|
2007-01-17 23:52:39 +00:00
|
|
|
|
|
|
|
// if file is already as large or larger than it's supposed to be,
|
|
|
|
// something's screwy; start reading it from the beginning.
|
|
|
|
//
|
|
|
|
if (file_size(pathname, starting_size) || starting_size >= fip->nbytes) {
|
2006-01-18 21:07:04 +00:00
|
|
|
starting_size = 0;
|
2002-08-12 21:54:19 +00:00
|
|
|
}
|
2006-01-18 21:07:04 +00:00
|
|
|
bytes_xferred = starting_size;
|
2003-06-09 22:33:23 +00:00
|
|
|
|
2011-07-20 19:12:10 +00:00
|
|
|
const char* url = fip->download_urls.get_current_url(file_info);
|
2006-02-28 23:28:07 +00:00
|
|
|
if (!url) return ERR_INVALID_URL;
|
2006-01-18 21:07:04 +00:00
|
|
|
return HTTP_OP::init_get(
|
2012-11-30 04:45:00 +00:00
|
|
|
file_info.project, url, pathname, false, starting_size, file_info.nbytes
|
2006-01-18 21:07:04 +00:00
|
|
|
);
|
2002-07-05 05:33:40 +00:00
|
|
|
}
|
|
|
|
|
2002-07-07 20:39:24 +00:00
|
|
|
// for uploads, we need to build a header with xml_signature etc.
|
2007-03-05 18:34:30 +00:00
|
|
|
// (see doc/upload.php)
|
2002-07-05 05:33:40 +00:00
|
|
|
// Do this in memory.
|
|
|
|
//
|
2004-07-13 10:36:18 +00:00
|
|
|
int FILE_XFER::init_upload(FILE_INFO& file_info) {
|
2002-08-12 21:54:19 +00:00
|
|
|
// If upload_offset < 0, we need to query the upload handler
|
|
|
|
// for the offset information
|
|
|
|
//
|
2002-07-05 05:33:40 +00:00
|
|
|
fip = &file_info;
|
2007-03-13 19:33:27 +00:00
|
|
|
get_pathname(fip, pathname, sizeof(pathname));
|
2011-12-17 05:36:45 +00:00
|
|
|
if (!boinc_file_exists(pathname)) {
|
2012-02-07 07:58:08 +00:00
|
|
|
return ERR_NOT_FOUND;
|
2011-12-17 05:36:45 +00:00
|
|
|
}
|
2002-08-12 21:54:19 +00:00
|
|
|
|
2003-05-10 00:52:36 +00:00
|
|
|
is_upload = true;
|
2005-12-13 08:04:57 +00:00
|
|
|
|
2009-07-16 20:14:57 +00:00
|
|
|
// skip file size check if file is small
|
|
|
|
//
|
|
|
|
if (fip->nbytes < FILE_SIZE_CHECK_THRESHOLD) {
|
|
|
|
fip->upload_offset = 0;
|
|
|
|
}
|
|
|
|
|
2010-02-27 01:04:14 +00:00
|
|
|
if (log_flags.file_xfer_debug) {
|
|
|
|
msg_printf(file_info.project, MSG_INFO,
|
|
|
|
"[fxd] starting upload, upload_offset %.0f", file_info.upload_offset
|
|
|
|
);
|
|
|
|
}
|
2005-12-13 08:04:57 +00:00
|
|
|
if (file_info.upload_offset < 0) {
|
2003-02-27 09:21:22 +00:00
|
|
|
bytes_xferred = 0;
|
2023-05-05 18:05:20 +00:00
|
|
|
snprintf(header, sizeof(header),
|
2002-12-02 04:29:40 +00:00
|
|
|
"<data_server_request>\n"
|
|
|
|
" <core_client_major_version>%d</core_client_major_version>\n"
|
|
|
|
" <core_client_minor_version>%d</core_client_minor_version>\n"
|
2005-08-31 00:18:36 +00:00
|
|
|
" <core_client_release>%d</core_client_release>\n"
|
2002-12-02 04:29:40 +00:00
|
|
|
" <get_file_size>%s</get_file_size>\n"
|
|
|
|
"</data_server_request>\n",
|
2005-08-31 00:18:36 +00:00
|
|
|
BOINC_MAJOR_VERSION, BOINC_MINOR_VERSION, BOINC_RELEASE,
|
2002-08-12 21:54:19 +00:00
|
|
|
file_info.name
|
|
|
|
);
|
2002-08-21 19:12:42 +00:00
|
|
|
file_size_query = true;
|
2011-07-20 19:12:10 +00:00
|
|
|
const char* url = fip->upload_urls.get_current_url(file_info);
|
2006-02-28 23:28:07 +00:00
|
|
|
if (!url) return ERR_INVALID_URL;
|
2011-10-18 04:23:03 +00:00
|
|
|
return HTTP_OP::init_post2(
|
|
|
|
file_info.project, url, header, sizeof(header), NULL, 0
|
|
|
|
);
|
2002-08-12 21:54:19 +00:00
|
|
|
} else {
|
2003-02-27 09:21:22 +00:00
|
|
|
bytes_xferred = file_info.upload_offset;
|
2023-05-05 18:05:20 +00:00
|
|
|
snprintf(header, sizeof(header),
|
2002-12-02 04:29:40 +00:00
|
|
|
"<data_server_request>\n"
|
|
|
|
" <core_client_major_version>%d</core_client_major_version>\n"
|
|
|
|
" <core_client_minor_version>%d</core_client_minor_version>\n"
|
2007-03-29 18:41:41 +00:00
|
|
|
" <core_client_release>%d</core_client_release>\n"
|
2002-12-02 04:29:40 +00:00
|
|
|
"<file_upload>\n"
|
2002-08-12 21:54:19 +00:00
|
|
|
"<file_info>\n"
|
2011-08-01 23:17:12 +00:00
|
|
|
"<name>%s</name>\n"
|
2002-08-12 21:54:19 +00:00
|
|
|
"<xml_signature>\n"
|
|
|
|
"%s"
|
|
|
|
"</xml_signature>\n"
|
2011-09-13 00:51:20 +00:00
|
|
|
"<max_nbytes>%.0f</max_nbytes>\n"
|
2002-08-12 21:54:19 +00:00
|
|
|
"</file_info>\n"
|
2011-09-13 00:51:20 +00:00
|
|
|
"<nbytes>%.0f</nbytes>\n"
|
|
|
|
"<md5_cksum>%s</md5_cksum>\n"
|
2002-08-12 21:54:19 +00:00
|
|
|
"<offset>%.0f</offset>\n"
|
|
|
|
"<data>\n",
|
2007-03-29 18:41:41 +00:00
|
|
|
BOINC_MAJOR_VERSION, BOINC_MINOR_VERSION, BOINC_RELEASE,
|
2011-07-20 20:49:32 +00:00
|
|
|
file_info.name,
|
2011-09-13 00:51:20 +00:00
|
|
|
file_info.xml_signature,
|
2011-08-01 23:17:12 +00:00
|
|
|
file_info.max_nbytes,
|
2011-09-13 00:51:20 +00:00
|
|
|
file_info.nbytes,
|
2007-03-29 18:41:41 +00:00
|
|
|
file_info.md5_cksum,
|
2002-08-12 21:54:19 +00:00
|
|
|
file_info.upload_offset
|
|
|
|
);
|
2002-08-21 19:12:42 +00:00
|
|
|
file_size_query = false;
|
2011-07-20 19:12:10 +00:00
|
|
|
const char* url = fip->upload_urls.get_current_url(file_info);
|
2006-02-28 23:28:07 +00:00
|
|
|
if (!url) return ERR_INVALID_URL;
|
2002-08-26 22:57:17 +00:00
|
|
|
return HTTP_OP::init_post2(
|
2011-10-18 04:23:03 +00:00
|
|
|
file_info.project, url, header, sizeof(header),
|
|
|
|
pathname, fip->upload_offset
|
2002-12-02 04:29:40 +00:00
|
|
|
);
|
2002-08-12 21:54:19 +00:00
|
|
|
}
|
2002-07-05 05:33:40 +00:00
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2003-09-30 18:09:58 +00:00
|
|
|
// Parse the file upload handler response in req1
|
2002-08-21 19:12:42 +00:00
|
|
|
//
|
2003-09-30 18:09:58 +00:00
|
|
|
int FILE_XFER::parse_upload_response(double &nbytes) {
|
2003-05-06 21:43:26 +00:00
|
|
|
int status = ERR_UPLOAD_TRANSIENT, x;
|
2003-06-03 22:47:15 +00:00
|
|
|
char buf[256];
|
2002-12-02 04:29:40 +00:00
|
|
|
|
2003-05-06 21:43:26 +00:00
|
|
|
nbytes = -1;
|
2002-12-02 04:29:40 +00:00
|
|
|
parse_double(req1, "<file_size>", nbytes);
|
2003-05-06 21:43:26 +00:00
|
|
|
if (parse_int(req1, "<status>", x)) {
|
|
|
|
switch (x) {
|
|
|
|
case -1: status = ERR_UPLOAD_PERMANENT; break;
|
|
|
|
case 0: status = 0; break;
|
|
|
|
case 1: status = ERR_UPLOAD_TRANSIENT; break;
|
|
|
|
default: status = ERR_UPLOAD_TRANSIENT; break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
status = ERR_UPLOAD_TRANSIENT;
|
|
|
|
}
|
2003-07-02 02:02:18 +00:00
|
|
|
|
2002-12-02 04:29:40 +00:00
|
|
|
if (parse_str(req1, "<message>", buf, sizeof(buf))) {
|
2008-07-08 21:07:33 +00:00
|
|
|
msg_printf(fip->project, MSG_INTERNAL_ERROR,
|
|
|
|
"Error reported by file upload server: %s", buf
|
|
|
|
);
|
2002-12-02 04:29:40 +00:00
|
|
|
}
|
2008-05-07 23:14:26 +00:00
|
|
|
if (log_flags.file_xfer_debug) {
|
|
|
|
msg_printf(fip->project, MSG_INFO,
|
2010-04-29 20:32:51 +00:00
|
|
|
"[file_xfer] parsing upload response: %s", req1
|
2008-05-07 23:14:26 +00:00
|
|
|
);
|
|
|
|
msg_printf(fip->project, MSG_INFO,
|
2010-04-29 20:32:51 +00:00
|
|
|
"[file_xfer] parsing status: %d", status
|
2008-05-07 23:14:26 +00:00
|
|
|
);
|
|
|
|
}
|
2002-12-02 04:29:40 +00:00
|
|
|
|
2002-08-21 19:12:42 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2002-07-15 23:21:20 +00:00
|
|
|
// Create a new empty FILE_XFER_SET
|
|
|
|
//
|
2002-04-30 22:22:54 +00:00
|
|
|
FILE_XFER_SET::FILE_XFER_SET(HTTP_OP_SET* p) {
|
|
|
|
http_ops = p;
|
2005-11-25 18:17:09 +00:00
|
|
|
up_active = false;
|
|
|
|
down_active = false;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
2004-02-19 16:43:28 +00:00
|
|
|
// start a FILE_XFER going (connect to server etc.)
|
|
|
|
// If successful, add to the set
|
2002-07-15 23:21:20 +00:00
|
|
|
//
|
2002-04-30 22:22:54 +00:00
|
|
|
int FILE_XFER_SET::insert(FILE_XFER* fxp) {
|
2009-02-10 19:30:59 +00:00
|
|
|
http_ops->insert(fxp);
|
2004-02-19 16:43:28 +00:00
|
|
|
file_xfers.push_back(fxp);
|
2022-07-06 10:25:41 +00:00
|
|
|
enforce_bandwidth_limits(fxp->is_upload);
|
2002-04-30 22:22:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-07-15 23:21:20 +00:00
|
|
|
// Remove a FILE_XFER object from the set
|
|
|
|
//
|
2002-04-30 22:22:54 +00:00
|
|
|
int FILE_XFER_SET::remove(FILE_XFER* fxp) {
|
|
|
|
vector<FILE_XFER*>::iterator iter;
|
2002-08-15 22:03:41 +00:00
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
http_ops->remove(fxp);
|
|
|
|
|
|
|
|
iter = file_xfers.begin();
|
|
|
|
while (iter != file_xfers.end()) {
|
|
|
|
if (*iter == fxp) {
|
2006-10-02 17:44:27 +00:00
|
|
|
iter = file_xfers.erase(iter);
|
2022-07-06 10:25:41 +00:00
|
|
|
enforce_bandwidth_limits(fxp->is_upload);
|
2002-04-30 22:22:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2015-01-14 20:18:29 +00:00
|
|
|
++iter;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2009-02-23 04:54:04 +00:00
|
|
|
msg_printf(fxp->fip->project, MSG_INTERNAL_ERROR,
|
2006-01-17 22:48:09 +00:00
|
|
|
"File transfer for %s not found", fxp->fip->name
|
|
|
|
);
|
2004-01-30 22:19:19 +00:00
|
|
|
return ERR_NOT_FOUND;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
2002-07-15 23:21:20 +00:00
|
|
|
// Run through the FILE_XFER_SET and determine if any of the file
|
|
|
|
// transfers are complete or had an error
|
|
|
|
//
|
2005-06-07 19:22:50 +00:00
|
|
|
bool FILE_XFER_SET::poll() {
|
2002-04-30 22:22:54 +00:00
|
|
|
unsigned int i;
|
|
|
|
FILE_XFER* fxp;
|
|
|
|
bool action = false;
|
2004-10-14 22:01:05 +00:00
|
|
|
static double last_time=0;
|
2006-02-16 21:35:34 +00:00
|
|
|
char pathname[256];
|
|
|
|
double size;
|
2004-10-14 22:01:05 +00:00
|
|
|
|
2013-03-15 03:43:29 +00:00
|
|
|
if (!gstate.clock_change && gstate.now - last_time < FILE_XFER_POLL_PERIOD) return false;
|
2005-06-07 19:22:50 +00:00
|
|
|
last_time = gstate.now;
|
2002-04-30 22:22:54 +00:00
|
|
|
|
|
|
|
for (i=0; i<file_xfers.size(); i++) {
|
|
|
|
fxp = file_xfers[i];
|
2006-01-18 22:12:55 +00:00
|
|
|
if (!fxp->http_op_done()) continue;
|
2003-02-26 00:47:57 +00:00
|
|
|
|
2006-01-18 22:12:55 +00:00
|
|
|
action = true;
|
|
|
|
fxp->file_xfer_done = true;
|
2006-06-22 19:40:30 +00:00
|
|
|
if (log_flags.file_xfer_debug) {
|
2009-02-22 20:54:33 +00:00
|
|
|
msg_printf(fxp->fip->project, MSG_INFO,
|
2011-05-12 05:01:11 +00:00
|
|
|
"[file_xfer] http op done; retval %d (%s)\n",
|
|
|
|
fxp->http_op_retval, boincerror(fxp->http_op_retval)
|
2006-06-22 19:40:30 +00:00
|
|
|
);
|
|
|
|
}
|
2006-01-18 22:12:55 +00:00
|
|
|
fxp->file_xfer_retval = fxp->http_op_retval;
|
|
|
|
if (fxp->file_xfer_retval == 0) {
|
|
|
|
if (fxp->is_upload) {
|
|
|
|
fxp->file_xfer_retval = fxp->parse_upload_response(
|
|
|
|
fxp->fip->upload_offset
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this was a file size query, restart the transfer
|
|
|
|
// using the remote file size information
|
|
|
|
//
|
|
|
|
if (fxp->file_size_query) {
|
|
|
|
if (fxp->file_xfer_retval) {
|
|
|
|
fxp->fip->upload_offset = -1;
|
|
|
|
} else {
|
2002-10-15 18:09:16 +00:00
|
|
|
|
2006-01-18 22:12:55 +00:00
|
|
|
// if the server's file size is bigger than ours,
|
|
|
|
// something bad has happened
|
|
|
|
// (like a result got sent to multiple users).
|
|
|
|
// Pretend the file was successfully uploaded
|
|
|
|
//
|
|
|
|
if (fxp->fip->upload_offset >= fxp->fip->nbytes) {
|
|
|
|
fxp->file_xfer_done = true;
|
|
|
|
fxp->file_xfer_retval = 0;
|
|
|
|
} else {
|
|
|
|
// Restart the upload, using the newly obtained
|
|
|
|
// upload_offset
|
2004-01-21 07:07:16 +00:00
|
|
|
//
|
2006-01-18 22:12:55 +00:00
|
|
|
fxp->close_socket();
|
|
|
|
fxp->file_xfer_retval = fxp->init_upload(*fxp->fip);
|
2002-08-21 23:01:12 +00:00
|
|
|
|
2006-01-18 22:12:55 +00:00
|
|
|
if (!fxp->file_xfer_retval) {
|
|
|
|
remove(fxp);
|
|
|
|
i--;
|
|
|
|
fxp->file_xfer_retval = insert(fxp);
|
2003-05-06 21:43:26 +00:00
|
|
|
if (!fxp->file_xfer_retval) {
|
2006-01-18 22:12:55 +00:00
|
|
|
fxp->file_xfer_done = false;
|
|
|
|
fxp->file_xfer_retval = 0;
|
|
|
|
fxp->http_op_retval = 0;
|
2002-08-21 23:01:12 +00:00
|
|
|
}
|
|
|
|
}
|
2002-08-21 19:12:42 +00:00
|
|
|
}
|
|
|
|
}
|
2006-01-18 22:12:55 +00:00
|
|
|
}
|
|
|
|
} else if (fxp->file_xfer_retval == HTTP_STATUS_RANGE_REQUEST_ERROR) {
|
|
|
|
fxp->fip->error_msg = "Local copy is at least as large as server copy";
|
|
|
|
}
|
|
|
|
|
2006-06-27 17:31:43 +00:00
|
|
|
// deal with various error cases for downloads
|
2006-01-18 22:12:55 +00:00
|
|
|
//
|
2006-06-27 17:31:43 +00:00
|
|
|
if (!fxp->is_upload) {
|
2007-03-13 19:33:27 +00:00
|
|
|
get_pathname(fxp->fip, pathname, sizeof(pathname));
|
2006-10-23 21:00:36 +00:00
|
|
|
if (file_size(pathname, size)) continue;
|
|
|
|
double diff = size - fxp->starting_size;
|
2006-07-25 16:45:21 +00:00
|
|
|
if (fxp->http_op_retval == 0) {
|
2006-06-27 17:31:43 +00:00
|
|
|
// If no HTTP error,
|
|
|
|
// see if we read less than 5 KB and file is incomplete.
|
|
|
|
// If so truncate the amount read,
|
|
|
|
// since it may be a proxy error message
|
|
|
|
//
|
|
|
|
if (fxp->fip->nbytes) {
|
|
|
|
if (size == fxp->fip->nbytes) continue;
|
2014-04-22 17:07:06 +00:00
|
|
|
|
|
|
|
// but skip this check if it's an image file
|
|
|
|
// and user has image verification disabled
|
|
|
|
// (i.e. they're behind a proxy that shrinks images)
|
|
|
|
// The shrunk image could be < 5 KB
|
|
|
|
//
|
|
|
|
if (is_image_file(pathname) && gstate.global_prefs.dont_verify_images) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2006-06-27 17:31:43 +00:00
|
|
|
if (diff>0 && diff<MIN_DOWNLOAD_INCREMENT) {
|
|
|
|
msg_printf(fxp->fip->project, MSG_INFO,
|
|
|
|
"Incomplete read of %f < 5KB for %s - truncating",
|
|
|
|
diff, fxp->fip->name
|
|
|
|
);
|
|
|
|
boinc_truncate(pathname, fxp->starting_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2006-10-23 21:00:36 +00:00
|
|
|
// got HTTP error; truncate last 5KB of file, since some
|
2006-06-27 17:31:43 +00:00
|
|
|
// error-reporting HTML may have been appended
|
|
|
|
//
|
2009-07-31 19:46:47 +00:00
|
|
|
if (diff < MIN_DOWNLOAD_INCREMENT) {
|
|
|
|
diff = 0;
|
|
|
|
} else {
|
|
|
|
diff -= MIN_DOWNLOAD_INCREMENT;
|
|
|
|
}
|
|
|
|
boinc_truncate(pathname, fxp->starting_size + diff);
|
2005-03-10 00:43:22 +00:00
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2006-02-16 21:35:34 +00:00
|
|
|
|
|
|
|
// for downloads: if we requested a partial transfer,
|
|
|
|
// and the HTTP response is 200,
|
|
|
|
// and the file is larger than it should be,
|
|
|
|
// the server or proxy must have sent us the entire file
|
|
|
|
// (i.e. it doesn't understand Range: requests).
|
|
|
|
// In this case, trim off the initial part of the file
|
|
|
|
//
|
|
|
|
if (!fxp->is_upload && fxp->starting_size
|
|
|
|
&& fxp->response==HTTP_STATUS_OK
|
|
|
|
) {
|
2007-03-13 19:33:27 +00:00
|
|
|
get_pathname(fxp->fip, pathname, sizeof(pathname));
|
2006-02-16 21:35:34 +00:00
|
|
|
if (file_size(pathname, size)) continue;
|
|
|
|
if (size > fxp->fip->nbytes) {
|
|
|
|
FILE* f1 = boinc_fopen(pathname, "rb");
|
2008-10-07 12:45:06 +00:00
|
|
|
if (!f1) {
|
|
|
|
fxp->file_xfer_retval = ERR_FOPEN;
|
|
|
|
msg_printf(fxp->fip->project, MSG_INTERNAL_ERROR,
|
|
|
|
"File size mismatch, can't open %s", pathname
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
2006-02-16 21:35:34 +00:00
|
|
|
FILE* f2 = boinc_fopen(TEMP_FILE_NAME, "wb");
|
2008-10-07 12:45:06 +00:00
|
|
|
if (!f2) {
|
|
|
|
msg_printf(fxp->fip->project, MSG_INTERNAL_ERROR,
|
|
|
|
"File size mismatch, can't open temp %s", TEMP_FILE_NAME
|
|
|
|
);
|
|
|
|
fxp->file_xfer_retval = ERR_FOPEN;
|
2006-02-16 21:35:34 +00:00
|
|
|
fclose(f1);
|
2008-10-07 12:45:06 +00:00
|
|
|
continue;
|
2006-02-16 21:35:34 +00:00
|
|
|
}
|
2008-10-07 12:45:06 +00:00
|
|
|
fseek(f1, (long)fxp->starting_size, SEEK_SET);
|
|
|
|
copy_stream(f1, f2);
|
|
|
|
fclose(f1);
|
|
|
|
fclose(f2);
|
|
|
|
f1 = boinc_fopen(TEMP_FILE_NAME, "rb");
|
|
|
|
f2 = boinc_fopen(pathname, "wb");
|
|
|
|
copy_stream(f1, f2);
|
|
|
|
fclose(f1);
|
|
|
|
fclose(f2);
|
2006-02-16 21:35:34 +00:00
|
|
|
}
|
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
return action;
|
|
|
|
}
|
2006-10-02 16:13:08 +00:00
|
|
|
|
2005-11-25 18:17:09 +00:00
|
|
|
// return true if an upload is currently in progress
|
|
|
|
// or has been since the last call to this.
|
|
|
|
// Similar for download.
|
|
|
|
//
|
|
|
|
void FILE_XFER_SET::check_active(bool& up, bool& down) {
|
|
|
|
unsigned int i;
|
|
|
|
FILE_XFER* fxp;
|
|
|
|
|
|
|
|
up = up_active;
|
|
|
|
down = down_active;
|
|
|
|
for (i=0; i<file_xfers.size(); i++) {
|
|
|
|
fxp = file_xfers[i];
|
|
|
|
fxp->is_upload?up=true:down=true;
|
|
|
|
}
|
|
|
|
up_active = false;
|
|
|
|
down_active = false;
|
|
|
|
}
|
2004-12-08 00:40:19 +00:00
|
|
|
|
2022-07-06 10:25:41 +00:00
|
|
|
// if bandwidth limit exists, divide bandwidth equally among active xfers.
|
|
|
|
// Called on prefs change if limit exists, and on xfer start/stop
|
2006-10-02 16:13:08 +00:00
|
|
|
//
|
2022-07-06 10:25:41 +00:00
|
|
|
void FILE_XFER_SET::enforce_bandwidth_limits(bool is_upload) {
|
|
|
|
double max_bytes_sec = is_upload ? gstate.global_prefs.max_bytes_sec_up
|
|
|
|
: gstate.global_prefs.max_bytes_sec_down;
|
|
|
|
if (max_bytes_sec == 0) return;
|
|
|
|
int nxfers = 0;
|
2006-10-02 16:13:08 +00:00
|
|
|
unsigned int i;
|
|
|
|
FILE_XFER* fxp;
|
|
|
|
for (i=0; i<file_xfers.size(); i++) {
|
|
|
|
fxp = file_xfers[i];
|
2009-07-31 19:46:47 +00:00
|
|
|
if (!fxp->is_active()) continue;
|
2006-10-02 16:13:08 +00:00
|
|
|
if (is_upload) {
|
|
|
|
if (!fxp->is_upload) continue;
|
|
|
|
} else {
|
|
|
|
if (fxp->is_upload) continue;
|
|
|
|
}
|
2022-07-06 10:25:41 +00:00
|
|
|
nxfers++;
|
2006-10-02 16:13:08 +00:00
|
|
|
}
|
2022-07-06 10:25:41 +00:00
|
|
|
if (nxfers == 0) return;
|
|
|
|
max_bytes_sec /= nxfers;
|
2006-10-02 16:13:08 +00:00
|
|
|
for (i=0; i<file_xfers.size(); i++) {
|
|
|
|
fxp = file_xfers[i];
|
2009-07-31 19:46:47 +00:00
|
|
|
if (!fxp->is_active()) continue;
|
2006-10-02 16:13:08 +00:00
|
|
|
if (is_upload) {
|
|
|
|
if (!fxp->is_upload) continue;
|
|
|
|
fxp->set_speed_limit(true, max_bytes_sec);
|
|
|
|
} else {
|
|
|
|
if (fxp->is_upload) continue;
|
|
|
|
fxp->set_speed_limit(false, max_bytes_sec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-06 10:25:41 +00:00
|
|
|
// clear bandwidth limit on active xfers.
|
|
|
|
// called on prefs change if no limit
|
|
|
|
//
|
|
|
|
void FILE_XFER_SET::clear_bandwidth_limits(bool is_upload) {
|
|
|
|
unsigned int i;
|
|
|
|
FILE_XFER* fxp;
|
|
|
|
for (i=0; i<file_xfers.size(); i++) {
|
|
|
|
fxp = file_xfers[i];
|
|
|
|
if (!fxp->is_active()) continue;
|
|
|
|
if (is_upload) {
|
|
|
|
if (!fxp->is_upload) continue;
|
|
|
|
fxp->set_speed_limit(true, 0);
|
|
|
|
} else {
|
|
|
|
if (fxp->is_upload) continue;
|
|
|
|
fxp->set_speed_limit(false, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// called on prefs change
|
|
|
|
//
|
|
|
|
void FILE_XFER_SET::set_bandwidth_limits(bool is_upload) {
|
|
|
|
double max_bytes_sec = is_upload ? gstate.global_prefs.max_bytes_sec_up
|
|
|
|
: gstate.global_prefs.max_bytes_sec_down;
|
|
|
|
|
|
|
|
if (max_bytes_sec == 0) {
|
|
|
|
clear_bandwidth_limits(is_upload);
|
|
|
|
} else {
|
|
|
|
enforce_bandwidth_limits(is_upload);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|