// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2008 University of California
//
// 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.
//
// BOINC 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.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see .
// This file contains:
// 1) functions to clear and parse the various structs
// 2) actual GUI RPCs
// The core client expects all data to be formatted in the "C" locale,
// so each GUI RPC should get the current locale, then switch to the
// "C" locale before formatting messages or parsing results.
// After all work is completed, revert back to the original locale.
//
// Template:
//
// int RPC_CLIENT::template_function( args ) {
// int retval;
// SET_LOCALE sl;
// char buf[256];
// RPC rpc(this);
//
//
//
// return retval;
// }
//
// NOTE: Failing to revert back to the original locale will cause
// formatting failures for any software that has been localized or
// displays localized data.
#if defined(_WIN32) && !defined(__STDWX_H__) && !defined(_BOINC_WIN_) && !defined(_AFX_STDAFX_H_)
#include "boinc_win.h"
#endif
#ifdef _WIN32
#include "../version.h"
#else
#include "config.h"
#include
#include
#include
#include
#include
#include
#include
#include
#endif
#include "diagnostics.h"
#include "parse.h"
#include "str_util.h"
#include "util.h"
#include "error_numbers.h"
#include "miofile.h"
#include "md5_file.h"
#include "network.h"
#include "common_defs.h"
#include "gui_rpc_client.h"
using std::string;
using std::vector;
using std::sort;
DISPLAY_INFO::DISPLAY_INFO() {
memset(this, 0, sizeof(DISPLAY_INFO));
}
int GUI_URL::parse(MIOFILE& in) {
char buf[256];
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) return 0;
if (match_tag(buf, "")) break;
if (parse_str(buf, "", name)) continue;
if (parse_str(buf, "", description)) continue;
if (parse_str(buf, "", url)) continue;
}
return ERR_XML_PARSE;
}
PROJECT_LIST_ENTRY::PROJECT_LIST_ENTRY() {
clear();
}
PROJECT_LIST_ENTRY::~PROJECT_LIST_ENTRY() {
clear();
}
int PROJECT_LIST_ENTRY::parse(XML_PARSER& xp) {
char tag[256];
bool is_tag;
string platform;
while (!xp.get(tag, sizeof(tag), is_tag)) {
if (!strcmp(tag, "/project")) return 0;
if (xp.parse_string(tag, "name", name)) continue;
if (xp.parse_string(tag, "url", url)) continue;
if (xp.parse_string(tag, "general_area", general_area)) continue;
if (xp.parse_string(tag, "specific_area", specific_area)) continue;
if (xp.parse_string(tag, "description", description)) continue;
if (xp.parse_string(tag, "home", home)) continue;
if (xp.parse_string(tag, "image", image)) continue;
if (!strcmp(tag, "platforms")) {
while (!xp.get(tag, sizeof(tag), is_tag)) {
if (!strcmp(tag, "/platforms")) break;
if (xp.parse_string(tag, "name", platform)) {
platforms.push_back(platform);
}
}
}
xp.skip_unexpected(tag, false, "");
}
return ERR_XML_PARSE;
}
int AM_LIST_ENTRY::parse(XML_PARSER& xp) {
char tag[256];
bool is_tag;
while (!xp.get(tag, sizeof(tag), is_tag)) {
if (!strcmp(tag, "/account_manager")) return 0;
if (xp.parse_string(tag, "name", name)) continue;
if (xp.parse_string(tag, "url", url)) continue;
if (xp.parse_string(tag, "description", description)) continue;
if (xp.parse_string(tag, "image", image)) continue;
}
return 0;
}
void PROJECT_LIST_ENTRY::clear() {
name.clear();
url.clear();
general_area.clear();
specific_area.clear();
description.clear();
platforms.clear();
home.clear();
image.clear();
rand = 0;
}
bool PROJECT_LIST_ENTRY::operator<(const PROJECT_LIST_ENTRY& compare) {
return rand < compare.rand;
}
bool AM_LIST_ENTRY::operator<(const AM_LIST_ENTRY& compare) {
return rand < compare.rand;
}
PROJECT::PROJECT() {
clear();
}
PROJECT::~PROJECT() {
clear();
}
void PROJECT::get_name(std::string& s) {
if (project_name.length() == 0) {
s = master_url;
} else {
s = project_name;
}
}
int PROJECT::parse(MIOFILE& in) {
char buf[256];
int retval;
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) return 0;
if (parse_str(buf, "", master_url)) continue;
if (parse_double(buf, "", resource_share)) continue;
if (parse_str(buf, "", project_name)) continue;
if (parse_str(buf, "", user_name)) continue;
if (parse_str(buf, "", team_name)) continue;
if (parse_int(buf, "", hostid)) continue;
if (parse_double(buf, "", user_total_credit)) continue;
if (parse_double(buf, "", user_expavg_credit)) continue;
if (parse_double(buf, "", host_total_credit)) continue;
if (parse_double(buf, "", host_expavg_credit)) continue;
if (parse_double(buf, "", disk_usage)) continue;
if (parse_int(buf, "", nrpc_failures)) continue;
if (parse_int(buf, "", master_fetch_failures)) continue;
if (parse_double(buf, "", min_rpc_time)) continue;
if (parse_double(buf, "", short_term_debt)) continue;
if (parse_double(buf, "", cpu_long_term_debt)) continue;
if (parse_double(buf, "", cpu_backoff_time)) continue;
if (parse_double(buf, "", cpu_backoff_interval)) continue;
if (parse_double(buf, "", cuda_debt)) continue;
if (parse_double(buf, "", cuda_backoff_time)) continue;
if (parse_double(buf, "", cuda_backoff_interval)) continue;
if (parse_double(buf, "", duration_correction_factor)) continue;
if (parse_bool(buf, "master_url_fetch_pending", master_url_fetch_pending)) continue;
if (parse_int(buf, "", sched_rpc_pending)) continue;
if (parse_bool(buf, "non_cpu_intensive", non_cpu_intensive)) continue;
if (parse_bool(buf, "suspended_via_gui", suspended_via_gui)) continue;
if (parse_bool(buf, "dont_request_more_work", dont_request_more_work)) continue;
if (parse_bool(buf, "ended", ended)) continue;
if (parse_bool(buf, "scheduler_rpc_in_progress", scheduler_rpc_in_progress)) continue;
if (parse_bool(buf, "attached_via_acct_mgr", attached_via_acct_mgr)) continue;
if (parse_bool(buf, "detach_when_done", detach_when_done)) continue;
if (match_tag(buf, "")) {
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) break;
if (match_tag(buf, "")) {
GUI_URL gu;
retval = gu.parse(in);
if (retval) break;
gui_urls.push_back(gu);
continue;
}
}
continue;
}
if (parse_double(buf, "", project_files_downloaded_time)) continue;
if (parse_double(buf, "", last_rpc_time)) continue;
}
return ERR_XML_PARSE;
}
void PROJECT::clear() {
master_url.clear();
resource_share = 0;
project_name.clear();
user_name.clear();
team_name.clear();
user_total_credit = 0;
user_expavg_credit = 0;
host_total_credit = 0;
host_expavg_credit = 0;
disk_usage = 0;
nrpc_failures = 0;
master_fetch_failures = 0;
min_rpc_time = 0;
short_term_debt = 0;
cpu_long_term_debt = 0;
cpu_backoff_time = 0;
cpu_backoff_interval = 0;
cuda_debt = 0;
cuda_backoff_time = 0;
cuda_backoff_interval = 0;
duration_correction_factor = 0;
master_url_fetch_pending = false;
sched_rpc_pending = 0;
ended = false;
non_cpu_intensive = false;
suspended_via_gui = false;
dont_request_more_work = false;
scheduler_rpc_in_progress = false;
attached_via_acct_mgr = false;
detach_when_done = false;
project_files_downloaded_time = 0;
last_rpc_time = 0;
gui_urls.clear();
statistics.clear();
}
APP::APP() {
clear();
}
APP::~APP() {
clear();
}
int APP::parse(MIOFILE& in) {
char buf[256];
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) return 0;
if (parse_str(buf, "", name)) continue;
if (parse_str(buf, "", user_friendly_name)) continue;
}
return ERR_XML_PARSE;
}
void APP::clear() {
name.clear();
project = NULL;
}
APP_VERSION::APP_VERSION() {
clear();
}
APP_VERSION::~APP_VERSION() {
clear();
}
int APP_VERSION::parse(MIOFILE& in) {
char buf[256];
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) return 0;
if (parse_str(buf, "", app_name)) continue;
if (parse_str(buf, "", plan_class)) continue;
if (parse_int(buf, "", version_num)) continue;
}
return ERR_XML_PARSE;
}
void APP_VERSION::clear() {
app_name.clear();
version_num = 0;
app = NULL;
project = NULL;
}
WORKUNIT::WORKUNIT() {
clear();
}
WORKUNIT::~WORKUNIT() {
clear();
}
int WORKUNIT::parse(MIOFILE& in) {
char buf[256];
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) return 0;
if (parse_str(buf, "", name)) continue;
if (parse_str(buf, "", app_name)) continue;
if (parse_int(buf, "", version_num)) continue;
if (parse_double(buf, "", rsc_fpops_est)) continue;
if (parse_double(buf, "", rsc_fpops_bound)) continue;
if (parse_double(buf, "", rsc_memory_bound)) continue;
if (parse_double(buf, "", rsc_disk_bound)) continue;
}
return ERR_XML_PARSE;
}
void WORKUNIT::clear() {
name.clear();
app_name.clear();
version_num = 0;
rsc_fpops_est = 0;
rsc_fpops_bound = 0;
rsc_memory_bound = 0;
rsc_disk_bound = 0;
project = NULL;
app = NULL;
}
RESULT::RESULT() {
clear();
}
RESULT::~RESULT() {
clear();
}
int RESULT::parse(MIOFILE& in) {
char buf[256];
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) {
// if CPU time is nonzero but elapsed time is zero,
// we must be talking to an old client.
// Set elapsed = CPU
// (easier to deal with this here than in the manager)
//
if (current_cpu_time && !elapsed_time) {
elapsed_time = current_cpu_time;
}
if (final_cpu_time && !final_elapsed_time) {
final_elapsed_time = final_cpu_time;
}
return 0;
}
if (parse_str(buf, "", name)) continue;
if (parse_str(buf, "", wu_name)) continue;
if (parse_int(buf, "", version_num)) continue;
if (parse_str(buf, "", plan_class)) continue;
if (parse_str(buf, "", project_url)) continue;
if (parse_int(buf, "", report_deadline)) continue;
if (parse_bool(buf, "ready_to_report", ready_to_report)) continue;
if (parse_bool(buf, "got_server_ack", got_server_ack)) continue;
if (parse_bool(buf, "suspended_via_gui", suspended_via_gui)) continue;
if (parse_bool(buf, "project_suspended_via_gui", project_suspended_via_gui)) continue;
if (match_tag(buf, "")) {
active_task = true;
continue;
}
if (parse_bool(buf, "supports_graphics", supports_graphics)) continue;
if (parse_int(buf, "", graphics_mode_acked)) continue;
if (parse_double(buf, "", final_cpu_time)) continue;
if (parse_double(buf, "", final_elapsed_time)) continue;
if (parse_int(buf, "", state)) continue;
if (parse_int(buf, "", scheduler_state)) continue;
if (parse_int(buf, "", exit_status)) continue;
if (parse_int(buf, "", signal)) continue;
if (parse_int(buf, "", active_task_state)) continue;
if (match_tag(buf, "")) {
copy_element_contents(in, "", stderr_out);
continue;
}
if (parse_int(buf, "", app_version_num)) continue;
if (parse_int(buf, "", slot)) continue;
if (parse_double(buf, "", checkpoint_cpu_time)) continue;
if (parse_double(buf, "", current_cpu_time)) continue;
if (parse_double(buf, "", elapsed_time)) continue;
if (parse_double(buf, "", swap_size)) continue;
if (parse_double(buf, "", working_set_size_smoothed)) continue;
if (parse_double(buf, "", fraction_done)) continue;
if (parse_double(buf, "", estimated_cpu_time_remaining)) continue;
if (parse_bool(buf, "too_large", too_large)) continue;
if (parse_bool(buf, "needs_shmem", needs_shmem)) continue;
if (parse_bool(buf, "edf_scheduled", edf_scheduled)) continue;
if (parse_str(buf, "graphics_exec_path", graphics_exec_path)) continue;
if (parse_str(buf, "slot_path", slot_path)) continue;
if (parse_str(buf, "resources", resources)) continue;
}
return ERR_XML_PARSE;
}
void RESULT::clear() {
name.clear();
wu_name.clear();
version_num = 0;
plan_class.clear();
project_url.clear();
graphics_exec_path.clear();
slot_path.clear();
report_deadline = 0;
ready_to_report = false;
got_server_ack = false;
final_cpu_time = 0;
final_elapsed_time = 0;
state = 0;
scheduler_state = 0;
exit_status = 0;
signal = 0;
stderr_out.clear();
suspended_via_gui = false;
project_suspended_via_gui = false;
active_task = false;
active_task_state = 0;
app_version_num = 0;
slot = -1;
checkpoint_cpu_time = 0;
current_cpu_time = 0;
fraction_done = 0;
elapsed_time = 0;
swap_size = 0;
working_set_size_smoothed = 0;
estimated_cpu_time_remaining = 0;
supports_graphics = false;
graphics_mode_acked = 0;
too_large = false;
needs_shmem = false;
edf_scheduled = false;
app = NULL;
wup = NULL;
project = NULL;
avp = NULL;
}
FILE_TRANSFER::FILE_TRANSFER() {
clear();
}
FILE_TRANSFER::~FILE_TRANSFER() {
clear();
}
int FILE_TRANSFER::parse(MIOFILE& in) {
char buf[256];
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) return 0;
if (parse_str(buf, "", name)) continue;
if (parse_str(buf, "", project_url)) continue;
if (parse_str(buf, "", project_name)) continue;
if (parse_double(buf, "", nbytes)) continue;
if (parse_bool(buf, "generated_locally", generated_locally)) continue;
if (parse_bool(buf, "uploaded", uploaded)) continue;
if (parse_bool(buf, "upload_when_present", upload_when_present)) continue;
if (parse_bool(buf, "sticky", sticky)) continue;
if (match_tag(buf, "")) {
pers_xfer_active = true;
continue;
}
if (match_tag(buf, "")) {
xfer_active = true;
continue;
}
if (parse_int(buf, "", num_retries)) continue;
if (parse_int(buf, "", first_request_time)) continue;
if (parse_int(buf, "", next_request_time)) continue;
if (parse_int(buf, "", status)) continue;
if (parse_double(buf, "", time_so_far)) continue;
if (parse_double(buf, "", bytes_xferred)) continue;
if (parse_double(buf, "", file_offset)) continue;
if (parse_double(buf, "", xfer_speed)) continue;
if (parse_str(buf, "", hostname)) continue;
}
return ERR_XML_PARSE;
}
void FILE_TRANSFER::clear() {
name.clear();
project_url.clear();
project_name.clear();
nbytes = 0;
generated_locally = false;
uploaded = false;
upload_when_present = false;
sticky = false;
pers_xfer_active = false;
xfer_active = false;
num_retries = 0;
first_request_time = 0;
next_request_time = 0;
status = 0;
time_so_far = 0;
bytes_xferred = 0;
file_offset = 0;
xfer_speed = 0;
hostname.clear();
project = NULL;
}
MESSAGE::MESSAGE() {
clear();
}
MESSAGE::~MESSAGE() {
clear();
}
int MESSAGE::parse(MIOFILE& in) {
char buf[256];
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) return 0;
if (parse_str(buf, "", project)) continue;
if (match_tag(buf, "" )) {
copy_element_contents(in, "", body);
continue;
}
if (parse_int(buf, "", priority)) continue;
if (parse_int(buf, "