// 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(XML_PARSER& xp) {
char buf[256];
MIOFILE& in = *(xp.f);
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) {
string platform;
while (!xp.get_tag()) {
if (xp.match_tag("/project")) return 0;
if (xp.parse_string("name", name)) continue;
if (xp.parse_string("url", url)) {
continue;
}
if (xp.parse_string("general_area", general_area)) continue;
if (xp.parse_string("specific_area", specific_area)) continue;
if (xp.parse_string("description", description)) {
continue;
}
if (xp.parse_string("home", home)) continue;
if (xp.parse_string("image", image)) continue;
if (xp.match_tag("platforms")) {
while (!xp.get_tag()) {
if (xp.match_tag("/platforms")) break;
if (xp.parse_string("name", platform)) {
platforms.push_back(platform);
}
}
}
xp.skip_unexpected(false, "");
}
return ERR_XML_PARSE;
}
void PROJECT_LIST_ENTRY::clear() {
name.clear();
url.clear();
general_area.clear();
specific_area.clear();
description.clear();
platforms.clear();
home.clear();
image.clear();
}
AM_LIST_ENTRY::AM_LIST_ENTRY() {
clear();
}
AM_LIST_ENTRY::~AM_LIST_ENTRY() {
clear();
}
int AM_LIST_ENTRY::parse(XML_PARSER& xp) {
while (!xp.get_tag()) {
if (xp.match_tag("/account_manager")) return 0;
if (xp.parse_string("name", name)) continue;
if (xp.parse_string("url", url)) continue;
if (xp.parse_string("description", description)) continue;
if (xp.parse_string("image", image)) continue;
}
return 0;
}
void AM_LIST_ENTRY::clear() {
name.clear();
url.clear();
description.clear();
image.clear();
}
ALL_PROJECTS_LIST::ALL_PROJECTS_LIST() {
}
ALL_PROJECTS_LIST::~ALL_PROJECTS_LIST() {
clear();
}
bool compare_project_list_entry(const PROJECT_LIST_ENTRY* a, const PROJECT_LIST_ENTRY* b)
{
#ifdef _WIN32
return _stricmp(a->name.c_str(), b->name.c_str()) < 0;
#else
return strcasecmp(a->name.c_str(), b->name.c_str()) < 0;
#endif
}
bool compare_am_list_entry(const AM_LIST_ENTRY* a, const AM_LIST_ENTRY* b)
{
#ifdef _WIN32
return _stricmp(a->name.c_str(), b->name.c_str()) < 0;
#else
return strcasecmp(a->name.c_str(), b->name.c_str()) < 0;
#endif
}
void ALL_PROJECTS_LIST::shuffle() {
sort(projects.begin(), projects.end(), compare_project_list_entry);
sort(account_managers.begin(), account_managers.end(), compare_am_list_entry);
}
void ALL_PROJECTS_LIST::clear() {
unsigned int i;
for (i=0; i")) return 0;
if (parse_str(buf, "", master_url, sizeof(master_url))) continue;
if (parse_double(buf, "", resource_share)) continue;
if (parse_str(buf, "", project_name)) continue;
if (parse_str(buf, "", user_name)) {
xml_unescape(user_name);
continue;
}
if (parse_str(buf, "", team_name)) {
xml_unescape(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, "", download_backoff)) continue;
if (parse_double(buf, "", upload_backoff)) continue;
if (parse_double(buf, "", sched_priority)) continue;
if (parse_double(buf, "", cpu_backoff_time)) continue;
if (parse_double(buf, "", cpu_backoff_interval)) continue;
if (parse_double(buf, "", cuda_backoff_time)) continue;
if (parse_double(buf, "", cuda_backoff_interval)) continue;
if (parse_double(buf, "", ati_backoff_time)) continue;
if (parse_double(buf, "", ati_backoff_interval)) continue;
if (parse_double(buf, "", duration_correction_factor)) continue;
if (parse_bool(buf, "anonymous_platform", anonymous_platform)) 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 (parse_bool(buf, "trickle_up_pending", trickle_up_pending)) 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(xp);
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;
if (parse_bool(buf, "no_cpu_pref", no_cpu_pref)) continue;
if (parse_bool(buf, "no_cuda_pref", no_cuda_pref)) continue;
if (parse_bool(buf, "no_ati_pref", no_ati_pref)) continue;
if (parse_str(buf, "venue", venue, sizeof(venue))) continue;
}
return ERR_XML_PARSE;
}
void PROJECT::clear() {
strcpy(master_url, "");
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;
download_backoff = 0;
upload_backoff = 0;
cpu_backoff_time = 0;
cpu_backoff_interval = 0;
cuda_backoff_time = 0;
cuda_backoff_interval = 0;
ati_backoff_time = 0;
ati_backoff_interval = 0;
duration_correction_factor = 0;
anonymous_platform = false;
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;
trickle_up_pending = false;
project_files_downloaded_time = 0;
last_rpc_time = 0;
gui_urls.clear();
statistics.clear();
no_cpu_pref = false;
no_cuda_pref = false;
no_ati_pref = false;
strcpy(venue, "");
}
APP::APP() {
clear();
}
APP::~APP() {
clear();
}
int APP::parse(XML_PARSER& xp) {
char buf[256];
MIOFILE& in = *(xp.f);
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) return 0;
if (parse_str(buf, "", name, sizeof(name))) continue;
if (parse_str(buf, "", user_friendly_name, sizeof(user_friendly_name))) continue;
}
return ERR_XML_PARSE;
}
void APP::clear() {
strcpy(name, "");
strcpy(user_friendly_name, "");
project = NULL;
}
APP_VERSION::APP_VERSION() {
clear();
}
APP_VERSION::~APP_VERSION() {
clear();
}
int APP_VERSION::parse_coproc(MIOFILE& in) {
char buf[256], type_buf[256];
double count = 0;
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) {
if (!strcmp(type_buf, "CUDA")) {
ncudas = count;
} else if (!strcmp(type_buf, GPU_TYPE_ATI)) {
natis = count;
}
return 0;
}
if (parse_str(buf, "", type_buf, sizeof(type_buf))) continue;
if (parse_double(buf, "", count)) continue;
}
return ERR_XML_PARSE;
}
int APP_VERSION::parse(XML_PARSER& xp) {
char buf[256];
MIOFILE& in = *(xp.f);
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) return 0;
if (parse_str(buf, "", app_name, sizeof(app_name))) continue;
if (parse_int(buf, "", version_num)) continue;
if (parse_str(buf, "", plan_class, sizeof(plan_class))) continue;
if (parse_str(buf, "", platform, sizeof(platform))) continue;
if (parse_double(buf, "", avg_ncpus)) continue;
if (parse_double(buf, "", gpu_ram)) continue;
if (parse_double(buf, "", flops)) continue;
if (match_tag(buf, "")) {
parse_coproc(in);
continue;
}
}
return ERR_XML_PARSE;
}
void APP_VERSION::clear() {
memset(this, 0, sizeof(*this));
}
WORKUNIT::WORKUNIT() {
clear();
}
WORKUNIT::~WORKUNIT() {
clear();
}
int WORKUNIT::parse(XML_PARSER& xp) {
char buf[256];
MIOFILE& in = *(xp.f);
while (in.fgets(buf, 256)) {
if (match_tag(buf, "")) return 0;
if (parse_str(buf, "", name, sizeof(name))) continue;
if (parse_str(buf, "", app_name, sizeof(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() {
strcpy(name, "");
strcpy(app_name, "");
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(XML_PARSER& xp) {
char buf[256];
MIOFILE& in = *(xp.f);
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, sizeof(name))) continue;
if (parse_str(buf, "", wu_name, sizeof(wu_name))) continue;
if (parse_int(buf, "", version_num)) continue;
if (parse_str(buf, "", plan_class, sizeof(plan_class))) continue;
if (parse_str(buf, "", project_url, sizeof(project_url))) continue;
if (parse_double(buf, "", report_deadline)) continue;
if (parse_double(buf, "", received_time)) 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 (parse_bool(buf, "coproc_missing", coproc_missing)) continue;
if (parse_bool(buf, "gpu_mem_wait", gpu_mem_wait)) 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 0
if (match_tag(buf, "")) {
copy_element_contents(in, "", stderr_out);
continue;
}
#endif
if (parse_int(buf, "", app_version_num)) continue;
if (parse_int(buf, "", slot)) continue;
if (parse_int(buf, "", pid)) 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, sizeof(graphics_exec_path))) continue;
if (parse_str(buf, "slot_path", slot_path, sizeof(slot_path))) continue;
if (parse_str(buf, "resources", resources, sizeof(resources))) continue;
}
return ERR_XML_PARSE;
}
void RESULT::clear() {
strcpy(name, "");
strcpy(wu_name, "");
version_num = 0;
strcpy(plan_class, "");
strcpy(project_url, "");
strcpy(graphics_exec_path, "");
strcpy(slot_path, "");
strcpy(resources, "");
report_deadline = 0;
received_time = 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;
coproc_missing = false;
gpu_mem_wait = false;
active_task = false;
active_task_state = 0;
app_version_num = 0;
slot = -1;
pid = 0;
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(XML_PARSER& xp) {
char buf[256];
MIOFILE& in = *(xp.f);
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, "sticky", sticky)) continue;
if (match_tag(buf, "")) {
pers_xfer_active = true;
continue;
}
if (match_tag(buf, "")) {
xfer_active = true;
continue;
}
if (parse_bool(buf, "is_upload", is_upload)) {
generated_locally = is_upload;
continue;
}
if (parse_bool(buf, "generated_locally", generated_locally)) {
is_upload = generated_locally;
}
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;
if (parse_double(buf, "", project_backoff)) continue;
}
return ERR_XML_PARSE;
}
void FILE_TRANSFER::clear() {
name.clear();
project_url.clear();
project_name.clear();
nbytes = 0;
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;
project_backoff = 0;
}
MESSAGE::MESSAGE() {
clear();
}
MESSAGE::~MESSAGE() {
clear();
}
int MESSAGE::parse(XML_PARSER& xp) {
char buf[256];
MIOFILE& in = *(xp.f);
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, "