// 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 #include #include using namespace std; #include "parse.h" #include "error_numbers.h" #include "util.h" #include "main.h" #include "sched_util.h" #include "sched_msgs.h" #include "server_types.h" #ifdef _USING_FCGI_ #include "fcgi_stdio.h" #endif int CLIENT_APP_VERSION::parse(FILE* f) { char buf[256]; while (fgets(buf, 256, f)) { if (match_tag(buf, "")) return 0; if (parse_str(buf, "", app_name, 256)) continue; if (parse_int(buf, "", version_num)) continue; } return ERR_XML_PARSE; } int FILE_INFO::parse(FILE* f) { char buf[256]; memset(this, 0, sizeof(FILE_INFO)); while (fgets(buf, 256, f)) { if (match_tag(buf, "")) { if (!strlen(name)) return ERR_XML_PARSE; return 0; } if (parse_str(buf, "", name, 256)) continue; } return ERR_XML_PARSE; } SCHEDULER_REQUEST::SCHEDULER_REQUEST() { } SCHEDULER_REQUEST::~SCHEDULER_REQUEST() { } int SCHEDULER_REQUEST::parse(FILE* fin) { char buf[256]; RESULT result; int retval; strcpy(authenticator, ""); strcpy(platform_name, ""); strcpy(cross_project_id, ""); hostid = 0; core_client_major_version = 0; core_client_minor_version = 0; rpc_seqno = 0; work_req_seconds = 0; resource_share_fraction = 1.0; estimated_delay = 0; strcpy(global_prefs_xml, ""); strcpy(code_sign_key, ""); anonymous_platform = false; memset(&global_prefs, 0, sizeof(global_prefs)); memset(&host, 0, sizeof(host)); fgets(buf, 256, fin); if (!match_tag(buf, "")) return ERR_XML_PARSE; while (fgets(buf, 256, fin)) { if (match_tag(buf, "")) return 0; else if (parse_str(buf, "", authenticator, sizeof(authenticator))) continue; else if (parse_str(buf, "", cross_project_id, sizeof(cross_project_id))) continue; else if (parse_int(buf, "", hostid)) continue; else if (parse_int(buf, "", rpc_seqno)) continue; else if (parse_str(buf, "", platform_name, sizeof(platform_name))) continue; else if (match_tag(buf, "")) { while (fgets(buf, 256, fin)) { if (match_tag(buf, "")) break; if (match_tag(buf, "")) { CLIENT_APP_VERSION cav; cav.parse(fin); client_app_versions.push_back(cav); } } continue; } else if (parse_int(buf, "", core_client_major_version)) continue; else if (parse_int(buf, "", core_client_minor_version)) continue; else if (parse_double(buf, "", work_req_seconds)) continue; else if (parse_double(buf, "", resource_share_fraction)) continue; else if (parse_double(buf, "", estimated_delay)) continue; // ROMW: Added these back in since we have 3.x clients who still want // want to send us the older style for determining disk usage. // TODO: Remove the two lines below when the 4.x way of doing things // is completely implemented. else if (parse_double(buf, "", project_disk_usage)) continue; else if (parse_double(buf, "", total_disk_usage)) continue; #if 0 else if (parse_double(buf, "", project_disk_free)) continue; else if (parse_double(buf, "", potentially_free_offender)) continue; else if (parse_double(buf, "", potentially_free_self)) continue; #endif else if (match_tag(buf, "")) { strcpy(global_prefs_xml, "\n"); while (fgets(buf, 256, fin)) { if (strstr(buf, "")) break; safe_strcat(global_prefs_xml, buf); } safe_strcat(global_prefs_xml, "\n"); } else if (parse_str(buf, "", global_prefs_source_email_hash, sizeof(global_prefs_source_email_hash))) continue; else if (match_tag(buf, "")) { host.parse(fin); continue; } else if (match_tag(buf, "")) { host.parse_time_stats(fin); continue; } else if (match_tag(buf, "")) { host.parse_net_stats(fin); continue; } else if (match_tag(buf, "")) { result.parse_from_client(fin); results.push_back(result); continue; } else if (match_tag(buf, "")) { copy_element_contents(fin, "", code_sign_key, sizeof(code_sign_key)); } else if (match_tag(buf, "")) { MSG_FROM_HOST_DESC md; retval = md.parse(fin); if (!retval) { msgs_from_host.push_back(md); } } else if (match_tag(buf, "")) { FILE_INFO fi; retval = fi.parse(fin); if (!retval) { file_infos.push_back(fi); } } else if (match_tag(buf, "")) { // do NOTHING here } else { log_messages.printf(SCHED_MSG_LOG::NORMAL, "SCHEDULER_REQUEST::parse(): unrecognized: %s\n", buf); } } return ERR_XML_PARSE; } int SCHEDULER_REQUEST::write(FILE* fout) { unsigned int i; fprintf(fout, "\n" " %s\n" " %s\n" " %s\n" " %d\n" " %d\n" " %d\n" " %d\n" " %.15f\n" " %.15f\n" " %.15f\n" " %s\n" " %.15f\n" " %.15f\n" " %s\n", authenticator, platform_name, cross_project_id, hostid, core_client_major_version, core_client_minor_version, rpc_seqno, work_req_seconds, resource_share_fraction, estimated_delay, code_sign_key, total_disk_usage, project_disk_usage, anonymous_platform?"true":"false" ); for (i=0; i\n" " %s\n" " %d\n" " \n", client_app_versions[i].app_name, client_app_versions[i].version_num ); } fprintf(fout, " \n" " %s" " \n", global_prefs_xml ); fprintf(fout, " %s\n", global_prefs_source_email_hash ); fprintf(fout, " \n" " %d\n" " %d\n" " %d\n" " %.15f\n" " %.15f\n" " %.15f\n" " %.15f\n" " %.15f\n", host.id, host.rpc_time, host.timezone, host.d_total, host.d_free, host.d_boinc_used_total, host.d_boinc_used_project, host.d_boinc_max ); for (i=0; i\n" " %s\n" " %d\n" " %.15f\n" " %d\n" " %d\n" " \n", results[i].name, results[i].client_state, results[i].cpu_time, results[i].exit_status, results[i].app_version_num ); } for (i=0; i\n" " %s\n" " %s\n" " \n", msgs_from_host[i].variety, msgs_from_host[i].msg_text.c_str() ); } for (i=0; i\n" " %s\n" " \n", file_infos[i].name ); fprintf(fout, "\n"); } return 0; } int MSG_FROM_HOST_DESC::parse(FILE* fin) { char buf[256]; msg_text = ""; while (fgets(buf, 256, fin)) { if (match_tag(buf, "")) return 0; if (parse_str(buf, "", variety, sizeof(variety))) continue; msg_text += buf; } return ERR_XML_PARSE; } SCHEDULER_REPLY::SCHEDULER_REPLY() { memset(&wreq, 0, sizeof(wreq)); memset(&disk_limits, 0, sizeof(disk_limits)); request_delay = 0; hostid = 0; send_global_prefs = false; strcpy(code_sign_key, ""); strcpy(code_sign_key_signature, ""); memset(&user, 0, sizeof(user)); memset(&host, 0, sizeof(host)); memset(&team, 0, sizeof(team)); nucleus_only = false; probable_user_browser = false; send_msg_ack = false; strcpy(email_hash, ""); } SCHEDULER_REPLY::~SCHEDULER_REPLY() { } int SCHEDULER_REPLY::write(FILE* fout) { unsigned int i, j; string u1, u2, t1, t2; char buf[LARGE_BLOB_SIZE]; fprintf(fout, "\n" "%d\n", BOINC_MAJOR_VERSION*100+BOINC_MINOR_VERSION ); if (request_delay) { fprintf(fout, "%f\n", request_delay); log_messages.printf(SCHED_MSG_LOG::NORMAL, "sending delay request %f\n", request_delay); } if (wreq.core_client_version <= 419) { std::string msg; std::string pri = "low"; for (i=0; i0) { // any newlines will break message printing under 4.19 and under! // replace them with spaces. // while (1) { string::size_type pos = msg.find("\n", 0); if (pos == string::npos) break; msg.replace(pos, 1, " "); } fprintf(fout, "%s\n", pri.c_str(), msg.c_str() ); } } else { for (i=0; i%s\n", um.priority.c_str(), um.message.c_str() ); } } if (nucleus_only) goto end; fprintf(fout, "%s\n", config.long_name ); if (user.id) { u1 = user.name; xml_escape(u1, u2); fprintf(fout, "%s\n" "%f\n" "%f\n" "%d\n", u2.c_str(), user.total_credit, user.expavg_credit, user.create_time ); // be paranoid about the following to avoid sending null // if (strlen(email_hash)) { fprintf(fout, "%s\n", email_hash ); } if (strlen(user.cross_project_id)) { fprintf(fout, "%s\n", user.cross_project_id ); } if (send_global_prefs) { fputs(user.global_prefs, fout); } // always send project prefs // fputs(user.project_prefs, fout); } if (hostid) { fprintf(fout, "%d\n", hostid ); } fprintf(fout, "%f\n" "%f\n" "%s\n" "%d\n", host.total_credit, host.expavg_credit, host.venue, host.create_time ); // might want to send team credit too. // if (team.id) { t1 = team.name; xml_escape(t1, t2); fprintf(fout, "%s\n", t2.c_str() ); } #if 0 if (deletion_policy_priority) fprintf(fout, "\n"); if (deletion_policy_expire) fprintf(fout, "\n"); #endif // acknowledge results // for (i=0; i\n" " %s\n" "\n", result_acks[i].name ); } for (i=0; i\n", fout); fputs(code_sign_key, fout); fputs("\n", fout); } if (strlen(code_sign_key_signature)) { fputs("\n", fout); fputs(code_sign_key_signature, fout); fputs("\n", fout); } if (send_msg_ack) { fputs("\n", fout); } // changed implimentation so that messages have no flags // that say they are messages unless specified in the xml // portion in the MSG_TO_HOST object. for (i=0; i\n"); } for (i=0; i%s\n", file_deletes[i].name ); } gui_urls.get_gui_urls(user, host, team, buf); fputs(buf, fout); end: fprintf(fout, "\n" ); if (probable_user_browser) { // User is probably trying to look at cgi output with a browser. // Redirect them to the project home page. fprintf(fout, "\n\n" "You seem to be viewing this page in a WWW browser. Visit the main page.\n\n" "\n", "../", "../" ); } return 0; } // set delay to the MAX of the existing value or the requested value // never send a delay request longer than two days. // void SCHEDULER_REPLY::set_delay(double delay) { if (request_delay < delay) { request_delay = delay; } if (request_delay > 2*24*3600) { request_delay = 2*24*3600; } return; } void SCHEDULER_REPLY::insert_app_unique(APP& app) { unsigned int i; for (i=0; i\n" " %s\n" "\n", name ); return 0; } int APP_VERSION::write(FILE* fout) { fputs(xml_doc, fout); return 0; } int RESULT::parse_from_client(FILE* fin) { char buf[256]; // should be non-zero if exit_status is not found exit_status = ERR_NO_EXIT_STATUS; memset(this, 0, sizeof(RESULT)); while (fgets(buf, 256, fin)) { if (match_tag(buf, "")) return 0; else if (parse_str(buf, "", name, sizeof(name))) continue; else if (parse_int(buf, "", client_state)) continue; else if (parse_double(buf, "", cpu_time)) continue; else if (parse_int(buf, "", exit_status)) continue; else if (parse_int(buf, "", app_version_num)) continue; else if (match_tag(buf, "")) { safe_strcat(xml_doc_out, buf); while (fgets(buf, 256, fin)) { safe_strcat(xml_doc_out, buf); if (match_tag(buf, "")) break; } continue; } else if (match_tag(buf, "" )) { while (fgets(buf, 256, fin)) { if (match_tag(buf, "")) break; safe_strcat(stderr_out, buf); } continue; } else { log_messages.printf( SCHED_MSG_LOG::NORMAL, "RESULT::parse_from_client(): unrecognized: %s\n", buf ); } } return ERR_XML_PARSE; } // TODO: put the benchmark errors into the DB // int HOST::parse(FILE* fin) { char buf[256]; p_ncpus = 1; while (fgets(buf, 256, fin)) { int trash_int; double trash_double; if (match_tag(buf, "")) return 0; else if (parse_int(buf, "", timezone)) continue; else if (parse_str(buf, "", domain_name, sizeof(domain_name))) continue; else if (parse_str(buf, "", serialnum, sizeof(serialnum))) continue; else if (parse_str(buf, "", last_ip_addr, sizeof(last_ip_addr))) continue; else if (parse_str(buf, "", host_cpid, sizeof(host_cpid))) continue; else if (parse_int(buf, "", p_ncpus)) continue; else if (parse_str(buf, "", p_vendor, sizeof(p_vendor))) continue; else if (parse_str(buf, "", p_model, sizeof(p_model))) continue; else if (parse_double(buf, "", p_fpops)) continue; else if (parse_double(buf, "", p_iops)) continue; else if (parse_double(buf, "", p_membw)) continue; else if (parse_str(buf, "", os_name, sizeof(os_name))) continue; else if (parse_str(buf, "", os_version, sizeof(os_version))) continue; else if (parse_double(buf, "", m_nbytes)) continue; else if (parse_double(buf, "", m_cache)) continue; else if (parse_double(buf, "", m_swap)) continue; else if (parse_double(buf, "", d_total)) continue; else if (parse_double(buf, "", d_free)) continue; else if (parse_double(buf, "", n_bwup)) continue; else if (parse_double(buf, "", n_bwdown)) continue; // following four lines can be eliminated with a later version of // the core client. else if (parse_int(buf, "", trash_int)) continue; else if (parse_int(buf, "", trash_int)) continue; else if (parse_int(buf, "", trash_int)) continue; else if (parse_double(buf, "", trash_double)) continue; else { log_messages.printf(SCHED_MSG_LOG::NORMAL, "HOST::parse(): unrecognized: %s\n", buf ); } } return ERR_XML_PARSE; } int HOST::parse_time_stats(FILE* fin) { char buf[256]; while (fgets(buf, 256, fin)) { if (match_tag(buf, "")) return 0; else if (parse_double(buf, "", on_frac)) continue; else if (parse_double(buf, "", connected_frac)) continue; else if (parse_double(buf, "", active_frac)) continue; else { log_messages.printf( SCHED_MSG_LOG::NORMAL, "HOST::parse_time_stats(): unrecognized: %s\n", buf ); } } return ERR_XML_PARSE; } int HOST::parse_net_stats(FILE* fin) { char buf[256]; while (fgets(buf, 256, fin)) { if (match_tag(buf, "")) return 0; else if (parse_double(buf, "", n_bwup)) continue; else if (parse_double(buf, "", n_bwdown)) continue; else { log_messages.printf( SCHED_MSG_LOG::NORMAL, "HOST::parse_net_stats(): unrecognized: %s\n", buf ); } } return ERR_XML_PARSE; } void GLOBAL_PREFS::parse(char* buf, char* venue) { char buf2[LARGE_BLOB_SIZE]; disk_max_used_gb = 0; disk_max_used_pct = 0; disk_min_free_gb = 0; work_buf_min_days = 0; extract_venue(buf, venue, buf2); parse_double(buf2, "", disk_max_used_gb); parse_double(buf2, "", disk_max_used_pct); parse_double(buf2, "", disk_min_free_gb); parse_double(buf2, "", work_buf_min_days); } void GUI_URLS::init() { text = 0; read_file_malloc("../gui_urls.xml", text); } void GUI_URLS::get_gui_urls(USER& user, HOST& host, TEAM& team, char* buf) { bool found; char userid[256], teamid[256], hostid[256]; strcpy(buf, ""); if (!text) return; strcpy(buf, text); sprintf(userid, "%d", user.id); sprintf(hostid, "%d", host.id); if (user.teamid) { sprintf(teamid, "%d", team.id); } else { strcpy(teamid, "0"); while (remove_element(buf, "", "")) { continue; } } while (1) { found = false; found |= str_replace(buf, "", userid); found |= str_replace(buf, "", user.name); found |= str_replace(buf, "", hostid); found |= str_replace(buf, "", teamid); found |= str_replace(buf, "", team.name); found |= str_replace(buf, "", user.authenticator); if (!found) break; } } const char *BOINC_RCSID_ea659117b3 = "$Id$";