// Berkeley Open Infrastructure for Network Computing // http://boinc.berkeley.edu // Copyright (C) 2005 University of California // // This 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 2.1 of the License, or (at your option) any later version. // // This software is distributed in the hope that it will be useful, // 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. // // To view the GNU Lesser General Public License visit // http://www.gnu.org/copyleft/lesser.html // or write to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "cpp.h" #ifdef _WIN32 #include "boinc_win.h" #endif #ifndef _WIN32 #include #include #endif #include "error_numbers.h" #include "file_names.h" #include "filesys.h" #include "client_msgs.h" #include "log_flags.h" #include "parse.h" #include "util.h" #include "client_state.h" #include "pers_file_xfer.h" #include "client_types.h" using std::string; using std::vector; PROJECT::PROJECT() { init(); } void PROJECT::init() { strcpy(master_url, ""); strcpy(authenticator, ""); #if 0 share_size = 0; size = 0; #endif project_specific_prefs = ""; gui_urls = ""; resource_share = 100; strcpy(project_name, ""); strcpy(user_name, ""); strcpy(team_name, ""); strcpy(email_hash, ""); strcpy(cross_project_id, ""); user_total_credit = 0; user_expavg_credit = 0; user_create_time = 0; rpc_seqno = 0; hostid = 0; host_total_credit = 0; host_expavg_credit = 0; host_create_time = 0; exp_avg_cpu = 0; exp_avg_mod_time = 0; strcpy(code_sign_key, ""); nrpc_failures = 0; min_rpc_time = 0; min_report_min_rpc_time = 0; master_fetch_failures = 0; master_url_fetch_pending = false; sched_rpc_pending = false; tentative = false; anonymous_platform = false; debt = 0; anticipated_debt = 0; work_done_this_period = 0; next_runnable_result = NULL; work_request = 0; send_file_list = false; non_cpu_intensive = false; suspended_via_gui = false; dont_request_more_work = false; #if 0 deletion_policy_priority = false; deletion_policy_expire = false; #endif } PROJECT::~PROJECT() { } // parse project fields from client_state.xml // int PROJECT::parse_state(MIOFILE& in) { char buf[256]; STRING256 sched_url; string str1, str2; int retval; double x; SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_STATE); strcpy(project_name, ""); strcpy(user_name, ""); strcpy(team_name, ""); strcpy(email_hash, ""); strcpy(cross_project_id, ""); resource_share = 100; exp_avg_cpu = 0; exp_avg_mod_time = 0; min_rpc_time = 0; min_report_min_rpc_time = 0; nrpc_failures = 0; master_url_fetch_pending = false; sched_rpc_pending = false; send_file_list = false; non_cpu_intensive = false; suspended_via_gui = false; scheduler_urls.clear(); while (in.fgets(buf, 256)) { if (match_tag(buf, "")) return 0; else if (parse_str(buf, "", sched_url.text, sizeof(sched_url.text))) { scheduler_urls.push_back(sched_url); continue; } else if (parse_str(buf, "", master_url, sizeof(master_url))) continue; else if (parse_str(buf, "", project_name, sizeof(project_name))) continue; #if 0 else if (parse_double(buf, "", share_size)) continue; else if (parse_double(buf, "", size)) continue; #endif else if (parse_str(buf, "", user_name, sizeof(user_name))) continue; else if (parse_str(buf, "", team_name, sizeof(team_name))) continue; else if (parse_str(buf, "", host_venue, sizeof(host_venue))) continue; else if (parse_str(buf, "", email_hash, sizeof(email_hash))) continue; else if (parse_str(buf, "", cross_project_id, sizeof(cross_project_id))) continue; else if (parse_double(buf, "", user_total_credit)) continue; else if (parse_double(buf, "", user_expavg_credit)) continue; else if (parse_double(buf, "", user_create_time)) { validate_time(user_create_time); continue; } else if (parse_int(buf, "", rpc_seqno)) continue; else if (parse_int(buf, "", hostid)) continue; else if (parse_double(buf, "", host_total_credit)) continue; else if (parse_double(buf, "", host_expavg_credit)) continue; else if (parse_double(buf, "", host_create_time)) { validate_time(user_create_time); continue; } else if (parse_double(buf, "", exp_avg_cpu)) continue; else if (parse_double(buf, "", exp_avg_mod_time)) { validate_time(exp_avg_mod_time); continue; } else if (match_tag(buf, "")) { retval = copy_element_contents( in, "", code_sign_key, sizeof(code_sign_key) ); if (retval) return retval; } else if (parse_int(buf, "", nrpc_failures)) continue; else if (parse_int(buf, "", master_fetch_failures)) continue; else if (parse_double(buf, "", min_rpc_time)) { validate_time(min_rpc_time); continue; } else if (match_tag(buf, "")) master_url_fetch_pending = true; else if (match_tag(buf, "")) sched_rpc_pending = true; else if (match_tag(buf, "")) send_file_list = true; else if (match_tag(buf, "")) non_cpu_intensive = true; else if (match_tag(buf, "")) suspended_via_gui = true; else if (match_tag(buf, "")) dont_request_more_work = true; #if 0 else if (match_tag(buf, "")) deletion_policy_priority = true; else if (match_tag(buf, "")) deletion_policy_expire = true; #endif else if (parse_double(buf, "", debt)) continue; else if (parse_double(buf, "", x)) continue; // not authoritative else scope_messages.printf("PROJECT::parse_state(): unrecognized: %s\n", buf); } return ERR_XML_PARSE; } // Write project information to client state file // int PROJECT::write_state(MIOFILE& out, bool gui_rpc) { unsigned int i; string u1, u2, t1, t2; out.printf( "\n" ); u1 = user_name; xml_escape(u1, u2); t1 = team_name; xml_escape(t1, t2); out.printf( " %s\n" " %s\n" #if 0 " %f\n" " %f\n" #endif " %s\n" " %s\n" " %s\n" " %s\n" " %f\n" " %f\n" " %f\n" " %d\n" " %d\n" " %f\n" " %f\n" " %f\n" " %f\n" " %f\n" " %d\n" " %d\n" " %f\n" " %f\n" " %f\n" "%s%s%s%s%s%s", master_url, project_name, #if 0 share_size, size, #endif u2.c_str(), t2.c_str(), email_hash, cross_project_id, user_total_credit, user_expavg_credit, user_create_time, rpc_seqno, hostid, host_total_credit, host_expavg_credit, host_create_time, exp_avg_cpu, exp_avg_mod_time, nrpc_failures, master_fetch_failures, min_rpc_time, debt, resource_share, master_url_fetch_pending?" \n":"", sched_rpc_pending?" \n":"", send_file_list?" \n":"", non_cpu_intensive?" \n":"", suspended_via_gui?" \n":"", dont_request_more_work?" \n":"" ); #if 0 out.printf( "%s%s", deletion_policy_priority?" \n":"", deletion_policy_expire?" \n":"" ); #endif if (gui_rpc) { out.printf("%s", gui_urls.c_str()); } else { for (i=0; i%s\n", scheduler_urls[i].text ); } if (strlen(code_sign_key)) { out.printf( " \n%s\n", code_sign_key ); } } out.printf( "\n" ); return 0; } // copy fields from "p" into "this" that are stored in client_state.xml // void PROJECT::copy_state_fields(PROJECT& p) { scheduler_urls = p.scheduler_urls; safe_strcpy(project_name, p.project_name); #if 0 share_size = p.share_size; size = p.size; #endif safe_strcpy(user_name, p.user_name); safe_strcpy(team_name, p.team_name); safe_strcpy(email_hash, p.email_hash); safe_strcpy(cross_project_id, p.cross_project_id); user_total_credit = p.user_total_credit; user_expavg_credit = p.user_expavg_credit; user_create_time = p.user_create_time; rpc_seqno = p.rpc_seqno; hostid = p.hostid; host_total_credit = p.host_total_credit; host_expavg_credit = p.host_expavg_credit; host_create_time = p.host_create_time; exp_avg_cpu = p.exp_avg_cpu; exp_avg_mod_time = p.exp_avg_mod_time; nrpc_failures = p.nrpc_failures; master_fetch_failures = p.master_fetch_failures; min_rpc_time = p.min_rpc_time; master_url_fetch_pending = p.master_url_fetch_pending; sched_rpc_pending = p.sched_rpc_pending; safe_strcpy(code_sign_key, p.code_sign_key); debt = p.debt; send_file_list = p.send_file_list; non_cpu_intensive = p.non_cpu_intensive; suspended_via_gui = p.suspended_via_gui; dont_request_more_work = p.dont_request_more_work; #if 0 deletion_policy_priority = p.deletion_policy_priority; deletion_policy_expire = p.deletion_policy_expire; #endif } char* PROJECT::get_project_name() { if (strlen(project_name)) { return project_name; } else { return master_url; } } #if 0 // comment? what does this do? // Does it do a lot of disk access to do it?? // bool PROJECT::associate_file(FILE_INFO* fip) { return 0; double space_made = 0; if (gstate.get_more_disk_space(this, fip->nbytes)) { size += fip->nbytes; return true; } gstate.calc_proj_size(this); gstate.anything_free(space_made); space_made += gstate.select_delete(this, fip->nbytes - space_made, P_HIGH); if (space_made > fip->nbytes) { size += fip->nbytes; return true; } else { return false; } } #endif int APP::parse(MIOFILE& in) { char buf[256]; SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_STATE); strcpy(name, ""); project = NULL; while (in.fgets(buf, 256)) { if (match_tag(buf, "")) return 0; else if (parse_str(buf, "", name, sizeof(name))) continue; else scope_messages.printf("APP::parse(): unrecognized: %s\n", buf); } return ERR_XML_PARSE; } int APP::write(MIOFILE& out) { out.printf( "\n" " %s\n" "\n", name ); return 0; } FILE_INFO::FILE_INFO() { strcpy(name, ""); strcpy(md5_cksum, ""); max_nbytes = 0; nbytes = 0; upload_offset = -1; generated_locally = false; status = FILE_NOT_PRESENT; executable = false; uploaded = false; upload_when_present = false; sticky = false; report_on_rpc = false; signature_required = false; is_user_file = false; pers_file_xfer = NULL; result = NULL; project = NULL; urls.clear(); start_url = -1; current_url = -1; strcpy(signed_xml, ""); strcpy(xml_signature, ""); strcpy(file_signature, ""); #if 0 priority = P_LOW; time_last_used = dtime(); exp_date = dtime() + 60*SECONDS_PER_DAY; #endif } FILE_INFO::~FILE_INFO() { if (pers_file_xfer) { msg_printf(NULL, MSG_ERROR, "%s: delete FILE_INFO when a pers_file_xfer still points to it\n", name); pers_file_xfer->fip = NULL; } } void FILE_INFO::reset() { status = FILE_NOT_PRESENT; delete_file(); error_msg = ""; } // Set the appropriate permissions depending on whether // it's an executable file // This doesn't seem to exist in Windows // int FILE_INFO::set_permissions() { #ifdef _WIN32 return 0; #else int retval; char pathname[256]; get_pathname(this, pathname); if (executable) { retval = chmod(pathname, S_IEXEC|S_IREAD|S_IWRITE); } else { retval = chmod(pathname, S_IREAD|S_IWRITE); } return retval; #endif } // see if a file markes as present actually IS present // and have the right size. // If not, mark it as not present // bool FILE_INFO::verify_existing_file() { int retval; double size; char path[256]; get_pathname(this, path); retval = file_size(path, size); if (retval) { status = FILE_NOT_PRESENT; return false; } if (!log_flags.dont_check_file_sizes && size!=nbytes) { status = FILE_NOT_PRESENT; return false; } return true; } // If from server, make an exact copy of everything // except the start/end tags and the element. // int FILE_INFO::parse(MIOFILE& in, bool from_server) { char buf[256], buf2[1024]; STRING256 url; PERS_FILE_XFER *pfxp; int retval; SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_STATE); while (in.fgets(buf, 256)) { if (match_tag(buf, "")) return 0; else if (match_tag(buf, "")) { retval = copy_element_contents( in, "", xml_signature, sizeof(xml_signature) ); if (retval) return retval; continue; } else if (match_tag(buf, "")) { retval = copy_element_contents( in, "", file_signature, sizeof(file_signature) ); if (retval) return retval; if (from_server) { strcat(signed_xml, "\n"); strcat(signed_xml, file_signature); strcat(signed_xml, "\n"); } continue; } strcat(signed_xml, buf); if (parse_str(buf, "", name, sizeof(name))) continue; else if (parse_str(buf, "", url.text, sizeof(url.text))) { urls.push_back(url); continue; } else if (parse_str(buf, "", md5_cksum, sizeof(md5_cksum))) continue; else if (parse_double(buf, "", nbytes)) continue; else if (parse_double(buf, "", max_nbytes)) continue; else if (match_tag(buf, "")) generated_locally = true; else if (parse_int(buf, "", status)) continue; else if (match_tag(buf, "")) executable = true; else if (match_tag(buf, "")) uploaded = true; else if (match_tag(buf, "")) upload_when_present = true; else if (match_tag(buf, "")) sticky = true; else if (match_tag(buf, "")) report_on_rpc = true; else if (match_tag(buf, "")) signature_required = true; #if 0 else if (parse_int(buf, "", (int&)time_last_used)) continue; else if (parse_int(buf, "", priority)) continue; else if (parse_double(buf, "", exp_date)) continue; else if (parse_double(buf, "", exp_days)) { exp_date = dtime() + exp_days*SECONDS_PER_DAY; } #endif else if (match_tag(buf, "")) { pfxp = new PERS_FILE_XFER; retval = pfxp->parse(in); if (!retval) { pers_file_xfer = pfxp; } else { delete pfxp; } } else if (!from_server && match_tag(buf, "")) { retval = copy_element_contents( in, "", signed_xml, sizeof(signed_xml) ); if (retval) return retval; continue; } else if (match_tag(buf, "")) { while (in.fgets(buf, 256)) { if (match_tag(buf, "")) break; } continue; } else if (match_tag(buf, "")) { retval = copy_element_contents( in, "", buf2, sizeof(buf2) ); if (retval) return retval; error_msg = buf2; } else scope_messages.printf("FILE_INFO::parse(): unrecognized: %s\n", buf); } return ERR_XML_PARSE; } int FILE_INFO::write(MIOFILE& out, bool to_server) { unsigned int i; int retval; out.printf( "\n" " %s\n" " %f\n" " %f\n", name, nbytes, max_nbytes ); if (strlen(md5_cksum)) { out.printf( " %s\n", md5_cksum ); } if (!to_server) { if (generated_locally) out.printf(" \n"); out.printf(" %d\n", status); if (executable) out.printf(" \n"); if (uploaded) out.printf(" \n"); if (upload_when_present) out.printf(" \n"); if (sticky) out.printf(" \n"); if (report_on_rpc) out.printf(" \n"); if (signature_required) out.printf(" \n"); if (strlen(file_signature)) out.printf(" \n%s\n", file_signature); #if 0 if (time_last_used) out.printf(" %d\n", time_last_used); if (priority) out.printf(" %d\n", priority); if (exp_date) out.printf(" %ld\n", exp_date); #endif } for (i=0; i%s\n", urls[i].text); } if (!to_server && pers_file_xfer) { retval = pers_file_xfer->write(out); if (retval) return retval; } if (!to_server) { if (strlen(signed_xml) && strlen(xml_signature)) { out.printf( " \n%s \n" " \n%s \n", signed_xml, xml_signature ); } } if (!error_msg.empty()) { out.printf(" \n%s\n", error_msg.c_str()); } out.printf("\n"); #if 0 if (to_server) update_time(); // huh?? #endif return 0; } int FILE_INFO::write_gui(MIOFILE& out) { out.printf( "\n" " %s\n" " %s\n" " %s\n" " %f\n" " %f\n" " %d\n", project->master_url, project->project_name, name, nbytes, max_nbytes, status ); if (generated_locally) out.printf(" \n"); if (uploaded) out.printf(" \n"); if (upload_when_present) out.printf(" \n"); if (sticky) out.printf(" \n"); if (pers_file_xfer) { pers_file_xfer->write(out); } out.printf("\n"); return 0; } // delete physical underlying file associated with FILE_INFO // int FILE_INFO::delete_file() { char path[256]; get_pathname(this, path); int retval = boinc_delete_file(path); if (retval && status != FILE_NOT_PRESENT) { msg_printf(project, MSG_ERROR, "Couldn't delete file %s\n", path); } status = FILE_NOT_PRESENT; return retval; } // If a file has multiple replicas, we want to choose // a random one to try first, and then cycle through others // if transfers fail. // Call this to get the initial url, // // Files may have URLs for both upload and download. // The is_upload arg says which kind you want. // NULL return means there is no URL of the requested type // char* FILE_INFO::get_init_url(bool is_upload) { double temp; temp = rand(); temp *= urls.size(); temp /= RAND_MAX; current_url = (int)temp; start_url = current_url; while(1) { if (!is_correct_url_type(is_upload, urls[current_url])) { current_url = (current_url + 1)%urls.size(); if (current_url == start_url) { msg_printf(project, MSG_ERROR, "Couldn't find suitable URL for %s\n", name); return NULL; } } else { start_url = current_url; return urls[current_url].text; } } } // Call this to get the next URL of the indicated type. // NULL return means you've tried them all. // char* FILE_INFO::get_next_url(bool is_upload) { while(1) { current_url = (current_url + 1)%urls.size(); if (current_url == start_url) { return NULL; } if (is_correct_url_type(is_upload, urls[current_url])) { return urls[current_url].text; } } } char* FILE_INFO::get_current_url(bool is_upload) { if (current_url < 0) { return get_init_url(is_upload); } return urls[current_url].text; } // Checks if the url includes the phrase "file_upload_handler" // The inclusion of this phrase indicates the url is an upload url // bool FILE_INFO::is_correct_url_type(bool is_upload, STRING256 url) { char* has_str = strstr(url.text, "file_upload_handler"); if ((is_upload && !has_str) || (!is_upload && has_str)) { return false; } else { return true; } } // merges information from a new FILE_INFO that has the same name as a // FILE_INFO that is already present in the client state // Potentially changes upload_when_present, max_nbytes, and signed_xml // int FILE_INFO::merge_info(FILE_INFO& new_info) { char buf[256]; bool has_url; unsigned int i, j; upload_when_present = new_info.upload_when_present; // This could be a file that was previously marked for deletion. // Undo this. // sticky = new_info.sticky; #if 0 if (new_info.priority > priority) { priority = new_info.priority; } if (new_info.exp_date > exp_date) { exp_date = new_info.exp_date; } #endif if (max_nbytes <= 0 && new_info.max_nbytes) { max_nbytes = new_info.max_nbytes; sprintf(buf, " %.0f\n", new_info.max_nbytes); strcat(signed_xml, buf); } for (i=0; i\n" " %s\n" " %d\n" " %s\n" "\n", name, status, error_msg.c_str() ); } return true; } return false; } #if 0 // Sets the time_last_used to be equal to the current time int FILE_INFO::update_time() { time_last_used = dtime(); return 0; } #endif // Parse XML based app_version information, usually from client_state.xml // int APP_VERSION::parse(MIOFILE& in) { char buf[256]; FILE_REF file_ref; SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_STATE); strcpy(app_name, ""); version_num = 0; app = NULL; project = NULL; while (in.fgets(buf, 256)) { if (match_tag(buf, "")) return 0; else if (parse_str(buf, "", app_name, sizeof(app_name))) continue; else if (match_tag(buf, "")) { file_ref.parse(in); app_files.push_back(file_ref); continue; } else if (parse_int(buf, "", version_num)) continue; else scope_messages.printf("APP_VERSION::parse(): unrecognized: %s\n", buf); } return ERR_XML_PARSE; } int APP_VERSION::write(MIOFILE& out) { unsigned int i; int retval; out.printf( "\n" " %s\n" " %d\n", app_name, version_num ); for (i=0; i\n" ); return 0; } bool APP_VERSION::had_download_failure(int& failnum) { unsigned int i; for (i=0; ihad_failure(failnum)) { return true; } } return false; } void APP_VERSION::get_file_errors(string& str) { int errnum; unsigned int i; FILE_INFO* fip; char buf[1024]; str = "couldn't get input files:\n"; for (i=0; ihad_failure(errnum, buf)) { str = str + buf; } } } void APP_VERSION::clear_errors() { int x; unsigned int i; for (i=0; ihad_failure(x)) { fip->reset(); } } } int FILE_REF::parse(MIOFILE& in) { char buf[256]; SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_STATE); strcpy(file_name, ""); strcpy(open_name, ""); fd = -1; main_program = false; copy_file = false; while (in.fgets(buf, 256)) { if (match_tag(buf, "")) return 0; else if (parse_str(buf, "", file_name, sizeof(file_name))) continue; else if (parse_str(buf, "", open_name, sizeof(open_name))) continue; else if (parse_int(buf, "", fd)) continue; else if (match_tag(buf, "")) main_program = true; else if (match_tag(buf, "")) copy_file = true; else scope_messages.printf("FILE_REF::parse(): unrecognized: %s\n", buf); } return ERR_XML_PARSE; } int FILE_REF::write(MIOFILE& out) { out.printf( " \n" " %s\n", file_name ); if (strlen(open_name)) { out.printf(" %s\n", open_name); } if (fd >= 0) { out.printf(" %d\n", fd); } if (main_program) { out.printf(" \n"); } if (copy_file) { out.printf(" \n"); } out.printf(" \n"); return 0; } int WORKUNIT::parse(MIOFILE& in) { char buf[4096]; FILE_REF file_ref; SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_STATE); strcpy(name, ""); strcpy(app_name, ""); version_num = 0; command_line = ""; //strcpy(env_vars, ""); app = NULL; project = NULL; // Default these to very large values (1 week on a 1 cobblestone machine) // so we don't keep asking the server for more work rsc_fpops_est = 1e9*SECONDS_PER_DAY*7; rsc_fpops_bound = 4e9*SECONDS_PER_DAY*7; rsc_memory_bound = 1e8; rsc_disk_bound = 1e9; while (in.fgets(buf, sizeof(buf))) { if (match_tag(buf, "")) return 0; else if (parse_str(buf, "", name, sizeof(name))) continue; else if (parse_str(buf, "", app_name, sizeof(app_name))) continue; else if (parse_int(buf, "", version_num)) continue; else if (match_tag(buf, "")) { if (strstr(buf, "")) { parse_str(buf, "", command_line); } else { bool found=false; while (in.fgets(buf, sizeof(buf))) { if (strstr(buf, " element", name ); return ERR_XML_PARSE; } } strip_whitespace(command_line); continue; } //else if (parse_str(buf, "", env_vars, sizeof(env_vars))) continue; else if (parse_double(buf, "", rsc_fpops_est)) continue; else if (parse_double(buf, "", rsc_fpops_bound)) continue; else if (parse_double(buf, "", rsc_memory_bound)) continue; else if (parse_double(buf, "", rsc_disk_bound)) continue; else if (match_tag(buf, "")) { file_ref.parse(in); input_files.push_back(file_ref); continue; } else scope_messages.printf("WORKUNIT::parse(): unrecognized: %s\n", buf); } return ERR_XML_PARSE; } int WORKUNIT::write(MIOFILE& out) { unsigned int i; out.printf( "\n" " %s\n" " %s\n" " %d\n" //" %s\n" " %f\n" " %f\n" " %f\n" " %f\n", name, app_name, version_num, //env_vars, rsc_fpops_est, rsc_fpops_bound, rsc_memory_bound, rsc_disk_bound ); if (command_line.size()) { out.printf( " \n" "%s\n" " \n", command_line.c_str() ); } for (i=0; i\n"); return 0; } bool WORKUNIT::had_download_failure(int& failnum) { unsigned int i; for (i=0;ihad_failure(failnum)) { return true; } } return false; } void WORKUNIT::get_file_errors(string& str) { int x; unsigned int i; FILE_INFO* fip; char buf[1024]; str = "couldn't get input files:\n"; for (i=0;ihad_failure(x, buf)) { str = str + buf; } } } // if any input files had download error from previous WU, // reset them to try download again // void WORKUNIT::clear_errors() { int x; unsigned int i; for (i=0; ihad_failure(x)) { fip->reset(); } } } int RESULT::parse_ack(FILE* in) { char buf[256]; SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_STATE); strcpy(name, ""); while (fgets(buf, 256, in)) { if (match_tag(buf, "")) return 0; else if (parse_str(buf, "", name, sizeof(name))) continue; else scope_messages.printf("RESULT::parse(): unrecognized: %s\n", buf); } return ERR_XML_PARSE; } void RESULT::clear() { strcpy(name, ""); strcpy(wu_name, ""); report_deadline = 0; output_files.clear(); state = RESULT_NEW; ready_to_report = false; got_server_ack = false; final_cpu_time = 0; exit_status = 0; stderr_out = ""; suspended_via_gui = false; aborted_via_gui = false; app = NULL; wup = NULL; project = NULL; } // parse a element from scheduling server. // int RESULT::parse_server(MIOFILE& in) { char buf[256]; FILE_REF file_ref; SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_STATE); clear(); while (in.fgets(buf, 256)) { if (match_tag(buf, "")) return 0; if (parse_str(buf, "", name, sizeof(name))) continue; if (parse_str(buf, "", wu_name, sizeof(wu_name))) continue; if (parse_double(buf, "", report_deadline)) { validate_time(report_deadline); continue; } if (match_tag(buf, "")) { file_ref.parse(in); output_files.push_back(file_ref); continue; } else scope_messages.printf("RESULT::parse(): unrecognized: %s\n", buf); } return ERR_XML_PARSE; } // parse a element from state file // int RESULT::parse_state(MIOFILE& in) { char buf[256]; FILE_REF file_ref; SCOPE_MSG_LOG scope_messages(log_messages, CLIENT_MSG_LOG::DEBUG_STATE); clear(); while (in.fgets(buf, 256)) { if (match_tag(buf, "")) { // restore some invariants in case of bad state file // if (got_server_ack || ready_to_report) { state = RESULT_FILES_UPLOADED; } return 0; } if (parse_str(buf, "", name, sizeof(name))) continue; if (parse_str(buf, "", wu_name, sizeof(wu_name))) continue; if (parse_double(buf, "", report_deadline)) { validate_time(report_deadline); continue; } if (match_tag(buf, "")) { file_ref.parse(in); output_files.push_back(file_ref); continue; } else if (parse_double(buf, "", final_cpu_time)) continue; else if (parse_int(buf, "", exit_status)) continue; else if (match_tag(buf, "")) got_server_ack = true; else if (match_tag(buf, "")) ready_to_report = true; else if (match_tag(buf, "")) suspended_via_gui = true; else if (match_tag(buf, "")) aborted_via_gui = true; else if (parse_int(buf, "", state)) continue; else if (match_tag(buf, "")) { while (in.fgets(buf, 256)) { if (match_tag(buf, "")) break; stderr_out.append(buf); } continue; } else scope_messages.printf("RESULT::parse(): unrecognized: %s\n", buf); } return ERR_XML_PARSE; } int RESULT::write(MIOFILE& out, bool to_server) { unsigned int i; FILE_INFO* fip; int n, retval; out.printf( "\n" " %s\n" " %f\n" " %d\n" " %d\n", name, final_cpu_time, exit_status, state ); if (to_server) { out.printf( " %d\n", wup->version_num ); } n = stderr_out.length(); if (n) { out.printf("\n"); if (to_server) { out.printf( "%d.%.2d\n", gstate.core_client_major_version, gstate.core_client_minor_version ); } out.printf(stderr_out.c_str()); if (stderr_out[n-1] != '\n') { out.printf("\n"); } out.printf("\n"); } if (to_server) { for (i=0; iuploaded) { retval = fip->write(out, true); if (retval) return retval; } } } else { if (got_server_ack) out.printf(" \n"); if (ready_to_report) out.printf(" \n"); if (suspended_via_gui) out.printf(" \n"); if (aborted_via_gui) out.printf(" \n"); out.printf( " %s\n" " %f\n", wu_name, report_deadline ); for (i=0; i\n"); return 0; } int RESULT::write_gui(MIOFILE& out) { out.printf( "\n" " %s\n" " %s\n" " %s\n" " %f\n" " %d\n" " %d\n" " %f\n" " %f\n", name, wu_name, project->master_url, final_cpu_time, exit_status, state, report_deadline, estimated_cpu_time_remaining() ); if (got_server_ack) out.printf(" \n"); if (ready_to_report) out.printf(" \n"); if (suspended_via_gui) out.printf(" \n"); if (aborted_via_gui) out.printf(" \n"); ACTIVE_TASK* atp = gstate.active_tasks.lookup_result(this); if (atp) { atp->write(out); } out.printf("\n"); return 0; } // Returns true if the result's output files are all either // successfully uploaded or have unrecoverable errors // bool RESULT::is_upload_done() { unsigned int i; FILE_INFO* fip; int retval; for (i=0; iupload_when_present) { if (fip->had_failure(retval)) continue; if (!fip->uploaded) { return false; } } } return true; } void RESULT::get_app_version_string(string& str) { char buf[256]; sprintf(buf, " %.2f", wup->version_num/100.); str = app->name + string(buf); } // resets all FILE_INFO's in result to uploaded = false // if upload_when_present is true. // Also updates the last time the input files were used void RESULT::reset_files() { unsigned int i; FILE_INFO* fip; for (i=0; iupload_when_present) { fip->uploaded = false; } #if 0 fip->update_time(); #endif } for (i=0; i < wup->input_files.size(); i++) { fip = wup->input_files[i].file_info; #if 0 fip->update_time(); #endif } } // estimate how long a result will take on this host // double RESULT::estimated_cpu_time() { return wup->rsc_fpops_est/gstate.host_info.p_fpops; } double RESULT::estimated_cpu_time_remaining() { double x=-1; if (state >= RESULT_COMPUTE_ERROR) return -1; ACTIVE_TASK* atp = gstate.lookup_active_task_by_result(this); if (atp) { x = atp->est_cpu_time_to_completion(); if (x >= 0) return x; } return estimated_cpu_time(); } const char *BOINC_RCSID_b81ff9a584 = "$Id$";