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-08-15 22:39:56 +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-08-15 22:39:56 +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/>.
|
2008-05-06 19:53:49 +00:00
|
|
|
|
2005-11-21 18:34:44 +00:00
|
|
|
#include "config.h"
|
2009-02-26 00:23:23 +00:00
|
|
|
#include <cstdlib>
|
2004-08-03 21:51:30 +00:00
|
|
|
#include <cassert>
|
2002-09-26 23:12:13 +00:00
|
|
|
#include <vector>
|
|
|
|
#include <string>
|
2008-02-27 23:26:38 +00:00
|
|
|
#include <cstring>
|
2002-09-26 23:12:13 +00:00
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
#include "parse.h"
|
2004-01-08 00:27:59 +00:00
|
|
|
#include "error_numbers.h"
|
2007-02-21 16:26:51 +00:00
|
|
|
#include "str_util.h"
|
2007-06-22 23:48:37 +00:00
|
|
|
#include "util.h"
|
2002-08-25 07:54:33 +00:00
|
|
|
#include "main.h"
|
2003-06-11 23:36:40 +00:00
|
|
|
#include "sched_util.h"
|
2004-04-08 08:15:23 +00:00
|
|
|
#include "sched_msgs.h"
|
2008-01-13 00:12:14 +00:00
|
|
|
#include "time_stats_log.h"
|
2004-04-08 08:15:23 +00:00
|
|
|
#include "server_types.h"
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2004-04-30 19:33:05 +00:00
|
|
|
#ifdef _USING_FCGI_
|
2008-09-09 19:10:42 +00:00
|
|
|
#include "boinc_fcgi.h"
|
2004-04-30 19:33:05 +00:00
|
|
|
#endif
|
|
|
|
|
2008-12-15 21:14:32 +00:00
|
|
|
SCHEDULER_REQUEST* g_request;
|
|
|
|
SCHEDULER_REPLY* g_reply;
|
2008-12-16 16:29:54 +00:00
|
|
|
WORK_REQ* g_wreq;
|
2008-12-15 21:14:32 +00:00
|
|
|
|
2005-10-26 06:29:35 +00:00
|
|
|
// remove (by truncating) any quotes from the given string.
|
|
|
|
// This is for things (e.g. authenticator) that will be used in
|
|
|
|
// a SQL query, to prevent SQL injection attacks
|
|
|
|
//
|
|
|
|
void remove_quotes(char* p) {
|
|
|
|
int i, n=strlen(p);
|
|
|
|
for (i=0; i<n; i++) {
|
|
|
|
if (p[i]=='\'' || p[i]=='"') {
|
|
|
|
p[i] = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-01-26 19:29:39 +00:00
|
|
|
int CLIENT_APP_VERSION::parse(FILE* f) {
|
|
|
|
char buf[256];
|
|
|
|
|
- scheduler: add support for anonymous-platform coproc apps.
Old: although the request message contained all info
about the app version (flops, coproc usage etc.)
the server ignored this info,
and assumed that all anonymous platform apps where CPU.
With 6.6 client, this could produce infinite work fetch:
- client uses anon platform, has coproc app
- client has idle CPU, requests CPU work
- scheduler sends it jobs, thinking they will be done by CPU app
- client asks for more work etc.
New: scheduler parses full info on anon platform app versions:
plan class, FLOPS, coprocs.
It uses this info to make scheduling decisions;
in particular, if the request is for CUDA work,
if will only send jobs that use a CUDA app version.
The <result> records it returns contain info
(plan_class) that tells the client which app_version to use.
This will work correctly even if the client has multiple app versions
for the same app (e.g., a CPU version and a GPU version)
svn path=/trunk/boinc/; revision=17506
2009-03-05 17:30:10 +00:00
|
|
|
memset(this, 0, sizeof(CLIENT_APP_VERSION));
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), f)) {
|
2004-01-26 19:29:39 +00:00
|
|
|
if (match_tag(buf, "</app_version>")) return 0;
|
|
|
|
if (parse_str(buf, "<app_name>", app_name, 256)) continue;
|
2009-03-05 17:54:39 +00:00
|
|
|
if (parse_str(buf, "<platform>", platform, 256)) continue;
|
- scheduler: add support for anonymous-platform coproc apps.
Old: although the request message contained all info
about the app version (flops, coproc usage etc.)
the server ignored this info,
and assumed that all anonymous platform apps where CPU.
With 6.6 client, this could produce infinite work fetch:
- client uses anon platform, has coproc app
- client has idle CPU, requests CPU work
- scheduler sends it jobs, thinking they will be done by CPU app
- client asks for more work etc.
New: scheduler parses full info on anon platform app versions:
plan class, FLOPS, coprocs.
It uses this info to make scheduling decisions;
in particular, if the request is for CUDA work,
if will only send jobs that use a CUDA app version.
The <result> records it returns contain info
(plan_class) that tells the client which app_version to use.
This will work correctly even if the client has multiple app versions
for the same app (e.g., a CPU version and a GPU version)
svn path=/trunk/boinc/; revision=17506
2009-03-05 17:30:10 +00:00
|
|
|
if (parse_str(buf, "<plan_class>", plan_class, 256)) continue;
|
2004-01-26 19:29:39 +00:00
|
|
|
if (parse_int(buf, "<version_num>", version_num)) continue;
|
- scheduler: add support for anonymous-platform coproc apps.
Old: although the request message contained all info
about the app version (flops, coproc usage etc.)
the server ignored this info,
and assumed that all anonymous platform apps where CPU.
With 6.6 client, this could produce infinite work fetch:
- client uses anon platform, has coproc app
- client has idle CPU, requests CPU work
- scheduler sends it jobs, thinking they will be done by CPU app
- client asks for more work etc.
New: scheduler parses full info on anon platform app versions:
plan class, FLOPS, coprocs.
It uses this info to make scheduling decisions;
in particular, if the request is for CUDA work,
if will only send jobs that use a CUDA app version.
The <result> records it returns contain info
(plan_class) that tells the client which app_version to use.
This will work correctly even if the client has multiple app versions
for the same app (e.g., a CPU version and a GPU version)
svn path=/trunk/boinc/; revision=17506
2009-03-05 17:30:10 +00:00
|
|
|
if (parse_double(buf, "<flops>", host_usage.flops)) continue;
|
2009-03-06 22:21:47 +00:00
|
|
|
if (match_tag(buf, "<coproc>")) {
|
|
|
|
COPROC coproc;
|
|
|
|
MIOFILE mf;
|
|
|
|
mf.init_file(f);
|
|
|
|
int retval = coproc.parse(mf);
|
|
|
|
if (!retval && !strcmp(coproc.type, "CUDA")) {
|
|
|
|
host_usage.ncudas = coproc.count;
|
- scheduler: add support for anonymous-platform coproc apps.
Old: although the request message contained all info
about the app version (flops, coproc usage etc.)
the server ignored this info,
and assumed that all anonymous platform apps where CPU.
With 6.6 client, this could produce infinite work fetch:
- client uses anon platform, has coproc app
- client has idle CPU, requests CPU work
- scheduler sends it jobs, thinking they will be done by CPU app
- client asks for more work etc.
New: scheduler parses full info on anon platform app versions:
plan class, FLOPS, coprocs.
It uses this info to make scheduling decisions;
in particular, if the request is for CUDA work,
if will only send jobs that use a CUDA app version.
The <result> records it returns contain info
(plan_class) that tells the client which app_version to use.
This will work correctly even if the client has multiple app versions
for the same app (e.g., a CPU version and a GPU version)
svn path=/trunk/boinc/; revision=17506
2009-03-05 17:30:10 +00:00
|
|
|
}
|
|
|
|
}
|
2004-01-26 19:29:39 +00:00
|
|
|
}
|
|
|
|
return ERR_XML_PARSE;
|
|
|
|
}
|
|
|
|
|
2004-09-10 21:02:11 +00:00
|
|
|
int FILE_INFO::parse(FILE* f) {
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
memset(this, 0, sizeof(FILE_INFO));
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), f)) {
|
2004-09-10 21:02:11 +00:00
|
|
|
if (match_tag(buf, "</file_info>")) {
|
|
|
|
if (!strlen(name)) return ERR_XML_PARSE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (parse_str(buf, "<name>", name, 256)) continue;
|
|
|
|
}
|
|
|
|
return ERR_XML_PARSE;
|
|
|
|
}
|
|
|
|
|
2005-07-28 09:00:19 +00:00
|
|
|
int OTHER_RESULT::parse(FILE* f) {
|
|
|
|
char buf[256];
|
|
|
|
|
2009-06-01 22:15:14 +00:00
|
|
|
strcpy(name, "");
|
|
|
|
have_plan_class = false;
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), f)) {
|
2005-07-28 09:00:19 +00:00
|
|
|
if (match_tag(buf, "</other_result>")) {
|
|
|
|
if (name=="") return ERR_XML_PARSE;
|
|
|
|
return 0;
|
|
|
|
}
|
2009-06-01 22:15:14 +00:00
|
|
|
if (parse_str(buf, "<name>", name, sizeof(name))) continue;
|
|
|
|
if (parse_str(buf, "<plan_class>", plan_class, sizeof(plan_class))) {
|
|
|
|
have_plan_class = true;
|
|
|
|
continue;
|
|
|
|
}
|
2005-07-28 09:00:19 +00:00
|
|
|
}
|
|
|
|
return ERR_XML_PARSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int IP_RESULT::parse(FILE* f) {
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
report_deadline = 0;
|
|
|
|
cpu_time_remaining = 0;
|
- scheduler: add <workload_sim> config option.
If set, the scheduler will use EDF simulation,
together with the in-progress workload reported by the client,
to avoid sending results that
1) will miss their deadline, or
2) will cause an in-progress result to miss its deadline, or
3) will make an in-progress result miss its deadline
by more than is already predicted.
If this option is not set, or if the client request doesn't
include a workload description (i.e. the client is old)
use the existing approach, which assumes there's no workload.
NOTE: this is experimental. Production projects should not use it.
- EDF sim: write debug stuff to stderr instead of stdout
- Account manager:
- if an account is detach_when_done, set dont_request_more_work
- check done_request_more_work even for first-time projects
- update_uotd: generate a file for use by Google gadget
- user_links(): use full URLs (so can use in Google gadget)
client/
acct_mgr.C
work_fetch.C
html/
inc/
uotd.inc
util.inc
user/
uotd_gadget.php (new)
sched/
Makefile.am
edf_sim.C
sched_config.C,h
sched_resend.C
sched_send.C,h
server_types.C,h
svn path=/trunk/boinc/; revision=12639
2007-05-10 21:50:52 +00:00
|
|
|
strcpy(name, "");
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), f)) {
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "</ip_result>")) return 0;
|
- scheduler: add <workload_sim> config option.
If set, the scheduler will use EDF simulation,
together with the in-progress workload reported by the client,
to avoid sending results that
1) will miss their deadline, or
2) will cause an in-progress result to miss its deadline, or
3) will make an in-progress result miss its deadline
by more than is already predicted.
If this option is not set, or if the client request doesn't
include a workload description (i.e. the client is old)
use the existing approach, which assumes there's no workload.
NOTE: this is experimental. Production projects should not use it.
- EDF sim: write debug stuff to stderr instead of stdout
- Account manager:
- if an account is detach_when_done, set dont_request_more_work
- check done_request_more_work even for first-time projects
- update_uotd: generate a file for use by Google gadget
- user_links(): use full URLs (so can use in Google gadget)
client/
acct_mgr.C
work_fetch.C
html/
inc/
uotd.inc
util.inc
user/
uotd_gadget.php (new)
sched/
Makefile.am
edf_sim.C
sched_config.C,h
sched_resend.C
sched_send.C,h
server_types.C,h
svn path=/trunk/boinc/; revision=12639
2007-05-10 21:50:52 +00:00
|
|
|
if (parse_str(buf, "<name>", name, sizeof(name))) continue;
|
2005-07-28 09:00:19 +00:00
|
|
|
if (parse_double(buf, "<report_deadline>", report_deadline)) continue;
|
|
|
|
if (parse_double(buf, "<cpu_time_remaining>", cpu_time_remaining)) continue;
|
|
|
|
}
|
|
|
|
return ERR_XML_PARSE;
|
|
|
|
}
|
|
|
|
|
2007-04-19 22:45:57 +00:00
|
|
|
int CLIENT_PLATFORM::parse(FILE* fin) {
|
|
|
|
char buf[256];
|
|
|
|
strcpy(name, "");
|
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "</alt_platform>")) return 0;
|
|
|
|
if (parse_str(buf, "<name>", name, sizeof(name))) continue;
|
2007-04-19 22:45:57 +00:00
|
|
|
}
|
|
|
|
return ERR_XML_PARSE;
|
|
|
|
}
|
|
|
|
|
2008-03-07 21:13:01 +00:00
|
|
|
|
2009-02-26 03:03:35 +00:00
|
|
|
void WORK_REQ::insert_no_work_message(const USER_MESSAGE& um) {
|
- server code: at some point I made a global var "SCHED_CONFIG config",
mostly so that the parse function could assume
that everything was initially zero.
However, various back-end functions pass around SCHED_CONFIG&
as an argument (also named "config").
This creates a shadow, which is always bad.
Worse is the possibility that some projects have back-end programs
that have a SCHED_CONFIG variable that's automatic,
and therefore isn't zero initially,
and therefore isn't parsing correctly.
To fix this, I changed the 2 vectors in SCHED_CONFIG into pointers,
and have the parse routine zero the structure.
I was tempted to remove the SCHED_CONFIG& args to back-end functions,
but this would have broken some projects' code.
I did, however, change the name from config to config_loc
to avoid shadowing.
Also fixed various other compiler warnings.
svn path=/trunk/boinc/; revision=15541
2008-07-02 17:24:53 +00:00
|
|
|
for (unsigned int i=0; i<no_work_messages.size(); i++) {
|
2008-03-07 21:13:01 +00:00
|
|
|
if (!strcmp(um.message.c_str(), no_work_messages.at(i).message.c_str())){
|
2008-11-26 21:49:36 +00:00
|
|
|
return;
|
2008-03-07 21:13:01 +00:00
|
|
|
}
|
|
|
|
}
|
2008-11-26 21:49:36 +00:00
|
|
|
no_work_messages.push_back(um);
|
2008-03-07 21:13:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
SCHEDULER_REQUEST::SCHEDULER_REQUEST() {
|
|
|
|
}
|
|
|
|
|
|
|
|
SCHEDULER_REQUEST::~SCHEDULER_REQUEST() {
|
|
|
|
}
|
|
|
|
|
2008-10-01 22:07:35 +00:00
|
|
|
// return an error message or NULL
|
|
|
|
//
|
2008-07-01 16:34:51 +00:00
|
|
|
const char* SCHEDULER_REQUEST::parse(FILE* fin) {
|
2003-07-01 00:20:22 +00:00
|
|
|
char buf[256];
|
2002-04-30 22:22:54 +00:00
|
|
|
RESULT result;
|
2004-01-08 00:27:59 +00:00
|
|
|
int retval;
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
strcpy(authenticator, "");
|
2007-04-19 22:45:57 +00:00
|
|
|
strcpy(platform.name, "");
|
2005-05-12 00:32:03 +00:00
|
|
|
strcpy(cross_project_id, "");
|
2002-04-30 22:22:54 +00:00
|
|
|
hostid = 0;
|
2005-05-12 00:32:03 +00:00
|
|
|
core_client_major_version = 0;
|
|
|
|
core_client_minor_version = 0;
|
2005-08-31 00:18:36 +00:00
|
|
|
core_client_release = 0;
|
2005-05-12 00:32:03 +00:00
|
|
|
rpc_seqno = 0;
|
2002-04-30 22:22:54 +00:00
|
|
|
work_req_seconds = 0;
|
2009-01-10 00:43:33 +00:00
|
|
|
cpu_req_secs = 0;
|
|
|
|
cpu_req_instances = 0;
|
2004-07-06 21:51:49 +00:00
|
|
|
resource_share_fraction = 1.0;
|
2005-10-04 21:44:58 +00:00
|
|
|
rrs_fraction = 1.0;
|
|
|
|
prrs_fraction = 1.0;
|
2009-01-30 21:25:24 +00:00
|
|
|
cpu_estimated_delay = 0;
|
2003-04-03 18:35:40 +00:00
|
|
|
strcpy(global_prefs_xml, "");
|
2006-10-06 18:52:50 +00:00
|
|
|
strcpy(working_global_prefs_xml, "");
|
2003-04-03 18:35:40 +00:00
|
|
|
strcpy(code_sign_key, "");
|
2005-05-12 00:32:03 +00:00
|
|
|
anonymous_platform = false;
|
|
|
|
memset(&global_prefs, 0, sizeof(global_prefs));
|
|
|
|
memset(&host, 0, sizeof(host));
|
2005-07-28 10:13:30 +00:00
|
|
|
have_other_results_list = false;
|
|
|
|
have_ip_results_list = false;
|
2008-01-13 00:12:14 +00:00
|
|
|
have_time_stats_log = false;
|
2008-04-02 19:05:08 +00:00
|
|
|
client_cap_plan_class = false;
|
2008-10-01 19:48:52 +00:00
|
|
|
sandbox = -1;
|
2009-01-26 05:00:49 +00:00
|
|
|
coproc_cuda = 0;
|
2002-04-30 22:22:54 +00:00
|
|
|
|
- server code: at some point I made a global var "SCHED_CONFIG config",
mostly so that the parse function could assume
that everything was initially zero.
However, various back-end functions pass around SCHED_CONFIG&
as an argument (also named "config").
This creates a shadow, which is always bad.
Worse is the possibility that some projects have back-end programs
that have a SCHED_CONFIG variable that's automatic,
and therefore isn't zero initially,
and therefore isn't parsing correctly.
To fix this, I changed the 2 vectors in SCHED_CONFIG into pointers,
and have the parse routine zero the structure.
I was tempted to remove the SCHED_CONFIG& args to back-end functions,
but this would have broken some projects' code.
I did, however, change the name from config to config_loc
to avoid shadowing.
Also fixed various other compiler warnings.
svn path=/trunk/boinc/; revision=15541
2008-07-02 17:24:53 +00:00
|
|
|
fgets(buf, sizeof(buf), fin);
|
2008-07-01 16:34:51 +00:00
|
|
|
if (!match_tag(buf, "<scheduler_request>")) return "no start tag";
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2008-07-02 23:19:44 +00:00
|
|
|
// If a line is too long, ignore it.
|
|
|
|
// This can happen e.g. if the client has bad global_prefs.xml
|
|
|
|
// This won't be necessary if we rewrite this using XML_PARSER
|
|
|
|
//
|
|
|
|
if (!strchr(buf, '\n')) {
|
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
|
|
|
if (strchr(buf, '\n')) break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2008-10-01 22:07:35 +00:00
|
|
|
if (match_tag(buf, "</scheduler_request>")) {
|
|
|
|
core_client_version = 100*core_client_major_version + core_client_minor_version;
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_str(buf, "<authenticator>", authenticator, sizeof(authenticator))) {
|
2005-10-26 06:29:35 +00:00
|
|
|
remove_quotes(authenticator);
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_str(buf, "<cross_project_id>", cross_project_id, sizeof(cross_project_id))) continue;
|
|
|
|
if (parse_int(buf, "<hostid>", hostid)) continue;
|
|
|
|
if (parse_int(buf, "<rpc_seqno>", rpc_seqno)) continue;
|
|
|
|
if (parse_str(buf, "<platform_name>", platform.name, sizeof(platform.name))) continue;
|
|
|
|
if (match_tag(buf, "<alt_platform>")) {
|
2007-04-19 22:45:57 +00:00
|
|
|
CLIENT_PLATFORM cp;
|
|
|
|
retval = cp.parse(fin);
|
|
|
|
if (!retval) {
|
|
|
|
alt_platforms.push_back(cp);
|
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
continue;
|
2007-04-19 22:45:57 +00:00
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<app_versions>")) {
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2004-01-26 19:29:39 +00:00
|
|
|
if (match_tag(buf, "</app_versions>")) break;
|
|
|
|
if (match_tag(buf, "<app_version>")) {
|
|
|
|
CLIENT_APP_VERSION cav;
|
|
|
|
cav.parse(fin);
|
|
|
|
client_app_versions.push_back(cav);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_int(buf, "<core_client_major_version>", core_client_major_version)) continue;
|
|
|
|
if (parse_int(buf, "<core_client_minor_version>", core_client_minor_version)) continue;
|
|
|
|
if (parse_int(buf, "<core_client_release>", core_client_release)) continue;
|
|
|
|
if (parse_double(buf, "<work_req_seconds>", work_req_seconds)) continue;
|
2009-01-10 00:43:33 +00:00
|
|
|
if (parse_double(buf, "<cpu_req_secs>", cpu_req_secs)) continue;
|
|
|
|
if (parse_double(buf, "<cpu_req_instances>", cpu_req_instances)) continue;
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_double(buf, "<resource_share_fraction>", resource_share_fraction)) continue;
|
|
|
|
if (parse_double(buf, "<rrs_fraction>", rrs_fraction)) continue;
|
|
|
|
if (parse_double(buf, "<prrs_fraction>", prrs_fraction)) continue;
|
2009-01-30 21:25:24 +00:00
|
|
|
if (parse_double(buf, "<estimated_delay>", cpu_estimated_delay)) continue;
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_double(buf, "<duration_correction_factor>", host.duration_correction_factor)) continue;
|
|
|
|
if (match_tag(buf, "<global_preferences>")) {
|
2003-04-03 18:35:40 +00:00
|
|
|
strcpy(global_prefs_xml, "<global_preferences>\n");
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2002-09-29 00:32:11 +00:00
|
|
|
if (strstr(buf, "</global_preferences>")) break;
|
2003-04-03 18:35:40 +00:00
|
|
|
safe_strcat(global_prefs_xml, buf);
|
2002-06-01 20:26:21 +00:00
|
|
|
}
|
2003-04-03 18:35:40 +00:00
|
|
|
safe_strcat(global_prefs_xml, "</global_preferences>\n");
|
2007-06-14 23:08:43 +00:00
|
|
|
continue;
|
2002-06-01 20:26:21 +00:00
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<working_global_preferences>")) {
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2006-10-06 18:52:50 +00:00
|
|
|
if (strstr(buf, "</working_global_preferences>")) break;
|
|
|
|
safe_strcat(working_global_prefs_xml, buf);
|
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
continue;
|
2006-10-06 18:52:50 +00:00
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_str(buf, "<global_prefs_source_email_hash>", global_prefs_source_email_hash, sizeof(global_prefs_source_email_hash))) continue;
|
|
|
|
if (match_tag(buf, "<host_info>")) {
|
2002-04-30 22:22:54 +00:00
|
|
|
host.parse(fin);
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<time_stats>")) {
|
2002-04-30 22:22:54 +00:00
|
|
|
host.parse_time_stats(fin);
|
|
|
|
continue;
|
|
|
|
}
|
2008-01-13 00:12:14 +00:00
|
|
|
if (match_tag(buf, "<time_stats_log>")) {
|
|
|
|
handle_time_stats_log(fin);
|
|
|
|
have_time_stats_log = true;
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<net_stats>")) {
|
2002-04-30 22:22:54 +00:00
|
|
|
host.parse_net_stats(fin);
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<disk_usage>")) {
|
2005-10-04 21:44:58 +00:00
|
|
|
host.parse_disk_usage(fin);
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<result>")) {
|
2002-04-30 22:22:54 +00:00
|
|
|
result.parse_from_client(fin);
|
|
|
|
results.push_back(result);
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<code_sign_key>")) {
|
2003-04-03 18:35:40 +00:00
|
|
|
copy_element_contents(fin, "</code_sign_key>", code_sign_key, sizeof(code_sign_key));
|
2007-06-14 23:08:43 +00:00
|
|
|
continue;
|
2002-07-07 20:39:24 +00:00
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<msg_from_host>")) {
|
2004-06-24 21:00:13 +00:00
|
|
|
MSG_FROM_HOST_DESC md;
|
|
|
|
retval = md.parse(fin);
|
2004-01-08 00:27:59 +00:00
|
|
|
if (!retval) {
|
2004-06-24 21:00:13 +00:00
|
|
|
msgs_from_host.push_back(md);
|
2004-01-08 00:27:59 +00:00
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
continue;
|
2004-09-10 21:02:11 +00:00
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<file_info>")) {
|
2004-09-10 21:02:11 +00:00
|
|
|
FILE_INFO fi;
|
|
|
|
retval = fi.parse(fin);
|
|
|
|
if (!retval) {
|
|
|
|
file_infos.push_back(fi);
|
|
|
|
}
|
2005-06-25 17:48:17 +00:00
|
|
|
continue;
|
2007-06-14 23:08:43 +00:00
|
|
|
}
|
|
|
|
if (match_tag(buf, "<host_venue>")) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (match_tag(buf, "<other_results>")) {
|
2005-07-28 10:13:30 +00:00
|
|
|
have_other_results_list = true;
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2005-07-28 09:00:19 +00:00
|
|
|
if (match_tag(buf, "</other_results>")) break;
|
|
|
|
if (match_tag(buf, "<other_result>")) {
|
|
|
|
OTHER_RESULT o_r;
|
|
|
|
retval = o_r.parse(fin);
|
|
|
|
if (!retval) {
|
|
|
|
other_results.push_back(o_r);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-06-25 17:48:17 +00:00
|
|
|
continue;
|
2007-06-14 23:08:43 +00:00
|
|
|
}
|
|
|
|
if (match_tag(buf, "<in_progress_results>")) {
|
2005-07-28 10:13:30 +00:00
|
|
|
have_ip_results_list = true;
|
- scheduler: add <workload_sim> config option.
If set, the scheduler will use EDF simulation,
together with the in-progress workload reported by the client,
to avoid sending results that
1) will miss their deadline, or
2) will cause an in-progress result to miss its deadline, or
3) will make an in-progress result miss its deadline
by more than is already predicted.
If this option is not set, or if the client request doesn't
include a workload description (i.e. the client is old)
use the existing approach, which assumes there's no workload.
NOTE: this is experimental. Production projects should not use it.
- EDF sim: write debug stuff to stderr instead of stdout
- Account manager:
- if an account is detach_when_done, set dont_request_more_work
- check done_request_more_work even for first-time projects
- update_uotd: generate a file for use by Google gadget
- user_links(): use full URLs (so can use in Google gadget)
client/
acct_mgr.C
work_fetch.C
html/
inc/
uotd.inc
util.inc
user/
uotd_gadget.php (new)
sched/
Makefile.am
edf_sim.C
sched_config.C,h
sched_resend.C
sched_send.C,h
server_types.C,h
svn path=/trunk/boinc/; revision=12639
2007-05-10 21:50:52 +00:00
|
|
|
int i = 0;
|
|
|
|
double now = time(0);
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2005-07-28 09:00:19 +00:00
|
|
|
if (match_tag(buf, "</in_progress_results>")) break;
|
|
|
|
if (match_tag(buf, "<ip_result>")) {
|
|
|
|
IP_RESULT ir;
|
|
|
|
retval = ir.parse(fin);
|
|
|
|
if (!retval) {
|
- scheduler: add <workload_sim> config option.
If set, the scheduler will use EDF simulation,
together with the in-progress workload reported by the client,
to avoid sending results that
1) will miss their deadline, or
2) will cause an in-progress result to miss its deadline, or
3) will make an in-progress result miss its deadline
by more than is already predicted.
If this option is not set, or if the client request doesn't
include a workload description (i.e. the client is old)
use the existing approach, which assumes there's no workload.
NOTE: this is experimental. Production projects should not use it.
- EDF sim: write debug stuff to stderr instead of stdout
- Account manager:
- if an account is detach_when_done, set dont_request_more_work
- check done_request_more_work even for first-time projects
- update_uotd: generate a file for use by Google gadget
- user_links(): use full URLs (so can use in Google gadget)
client/
acct_mgr.C
work_fetch.C
html/
inc/
uotd.inc
util.inc
user/
uotd_gadget.php (new)
sched/
Makefile.am
edf_sim.C
sched_config.C,h
sched_resend.C
sched_send.C,h
server_types.C,h
svn path=/trunk/boinc/; revision=12639
2007-05-10 21:50:52 +00:00
|
|
|
if (!strlen(ir.name)) {
|
|
|
|
sprintf(ir.name, "ip%d", i++);
|
|
|
|
}
|
|
|
|
ir.report_deadline -= now;
|
2005-07-28 09:00:19 +00:00
|
|
|
ip_results.push_back(ir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2005-06-25 17:48:17 +00:00
|
|
|
continue;
|
2003-01-07 01:02:08 +00:00
|
|
|
}
|
2008-03-10 21:59:27 +00:00
|
|
|
if (match_tag(buf, "coprocs")) {
|
|
|
|
coprocs.parse(fin);
|
2009-01-26 05:00:49 +00:00
|
|
|
coproc_cuda = (COPROC_CUDA*)coprocs.lookup("CUDA");
|
2008-03-10 21:59:27 +00:00
|
|
|
continue;
|
|
|
|
}
|
2008-04-02 19:05:08 +00:00
|
|
|
if (parse_bool(buf, "client_cap_plan_class", client_cap_plan_class)) continue;
|
2008-10-01 19:48:52 +00:00
|
|
|
if (parse_int(buf, "<sandbox>", sandbox)) continue;
|
2007-09-23 21:38:47 +00:00
|
|
|
|
|
|
|
if (match_tag(buf, "<active_task_set>")) continue;
|
|
|
|
if (match_tag(buf, "<app>")) continue;
|
|
|
|
if (match_tag(buf, "<app_version>")) continue;
|
|
|
|
if (match_tag(buf, "<duration_variability>")) continue;
|
|
|
|
if (match_tag(buf, "<new_version_check_time>")) continue;
|
|
|
|
if (match_tag(buf, "<newer_version>")) continue;
|
|
|
|
if (match_tag(buf, "<project>")) continue;
|
|
|
|
if (match_tag(buf, "<project_files>")) continue;
|
|
|
|
if (match_tag(buf, "<proxy_info>")) continue;
|
|
|
|
if (match_tag(buf, "<user_network_request>")) continue;
|
|
|
|
if (match_tag(buf, "<user_run_request>")) continue;
|
2007-09-24 06:54:01 +00:00
|
|
|
if (match_tag(buf, "<master_url>")) continue;
|
|
|
|
if (match_tag(buf, "<project_name>")) continue;
|
|
|
|
if (match_tag(buf, "<user_name>")) continue;
|
|
|
|
if (match_tag(buf, "<team_name>")) continue;
|
|
|
|
if (match_tag(buf, "<email_hash>")) continue;
|
|
|
|
if (match_tag(buf, "<user_total_credit>")) continue;
|
|
|
|
if (match_tag(buf, "<user_expavg_credit>")) continue;
|
|
|
|
if (match_tag(buf, "<user_create_time>")) continue;
|
|
|
|
if (match_tag(buf, "<host_total_credit>")) continue;
|
|
|
|
if (match_tag(buf, "<host_expavg_credit>")) continue;
|
|
|
|
if (match_tag(buf, "<host_create_time>")) continue;
|
|
|
|
if (match_tag(buf, "<nrpc_failures>")) continue;
|
|
|
|
if (match_tag(buf, "<master_fetch_failures>")) continue;
|
|
|
|
if (match_tag(buf, "<min_rpc_time>")) continue;
|
|
|
|
if (match_tag(buf, "<short_term_debt>")) continue;
|
|
|
|
if (match_tag(buf, "<long_term_debt>")) continue;
|
|
|
|
if (match_tag(buf, "<resource_share>")) continue;
|
|
|
|
if (match_tag(buf, "<scheduler_url>")) continue;
|
|
|
|
if (match_tag(buf, "</project>")) continue;
|
2008-07-02 23:19:44 +00:00
|
|
|
if (match_tag(buf, "<?xml")) continue;
|
|
|
|
strip_whitespace(buf);
|
|
|
|
if (!strlen(buf)) continue;
|
2007-09-23 21:38:47 +00:00
|
|
|
|
2008-02-21 21:00:58 +00:00
|
|
|
log_messages.printf(MSG_NORMAL,
|
2007-06-14 23:08:43 +00:00
|
|
|
"SCHEDULER_REQUEST::parse(): unrecognized: %s\n", buf
|
|
|
|
);
|
|
|
|
MIOFILE mf;
|
|
|
|
mf.init_file(fin);
|
|
|
|
retval = skip_unrecognized(buf, mf);
|
2008-07-01 16:34:51 +00:00
|
|
|
if (retval) return "unterminated unrecognized XML";
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2008-07-01 16:34:51 +00:00
|
|
|
return "no end tag";
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
2005-01-31 16:10:49 +00:00
|
|
|
int SCHEDULER_REQUEST::write(FILE* fout) {
|
2005-04-18 17:54:03 +00:00
|
|
|
unsigned int i;
|
2005-01-31 16:10:49 +00:00
|
|
|
|
2005-04-18 17:54:03 +00:00
|
|
|
fprintf(fout,
|
|
|
|
"<scheduler_request>\n"
|
|
|
|
" <authenticator>%s</authentiicator>\n"
|
|
|
|
" <platform_name>%s</platform_name>\n"
|
|
|
|
" <cross_project_id>%s</cross_project_id>\n"
|
|
|
|
" <hostid>%d</hostid>\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"
|
2005-04-18 17:54:03 +00:00
|
|
|
" <rpc_seqno>%d</rpc_seqno>\n"
|
|
|
|
" <work_req_seconds>%.15f</work_req_seconds>\n"
|
|
|
|
" <resource_share_fraction>%.15f</resource_share_fraction>\n"
|
2005-10-04 21:44:58 +00:00
|
|
|
" <rrs_fraction>%.15f</rrs_fraction>\n"
|
|
|
|
" <prrs_fraction>%.15f</prrs_fraction>\n"
|
2005-04-18 17:54:03 +00:00
|
|
|
" <estimated_delay>%.15f</estimated_delay>\n"
|
|
|
|
" <code_sign_key>%s</code_sign_key>\n"
|
|
|
|
" <anonymous_platform>%s</anonymous_platform>\n",
|
|
|
|
authenticator,
|
2007-04-19 22:45:57 +00:00
|
|
|
platform.name,
|
2005-04-18 17:54:03 +00:00
|
|
|
cross_project_id,
|
|
|
|
hostid,
|
|
|
|
core_client_major_version,
|
|
|
|
core_client_minor_version,
|
2005-08-31 00:18:36 +00:00
|
|
|
core_client_release,
|
2005-04-18 17:54:03 +00:00
|
|
|
rpc_seqno,
|
|
|
|
work_req_seconds,
|
|
|
|
resource_share_fraction,
|
2005-10-04 21:44:58 +00:00
|
|
|
rrs_fraction,
|
|
|
|
prrs_fraction,
|
2009-01-30 21:25:24 +00:00
|
|
|
cpu_estimated_delay,
|
2005-04-18 17:54:03 +00:00
|
|
|
code_sign_key,
|
2007-04-19 22:45:57 +00:00
|
|
|
anonymous_platform?"true":"false"
|
2005-04-18 17:54:03 +00:00
|
|
|
);
|
2005-01-31 16:10:49 +00:00
|
|
|
|
2005-04-18 17:54:03 +00:00
|
|
|
for (i=0; i<client_app_versions.size(); i++) {
|
|
|
|
fprintf(fout,
|
2005-01-31 16:10:49 +00:00
|
|
|
" <app_version>\n"
|
|
|
|
" <app_name>%s</app_name>\n"
|
|
|
|
" <version_num>%d</version_num>\n"
|
|
|
|
" </app_version>\n",
|
|
|
|
client_app_versions[i].app_name,
|
|
|
|
client_app_versions[i].version_num
|
2005-04-18 17:54:03 +00:00
|
|
|
);
|
|
|
|
}
|
2005-01-31 16:10:49 +00:00
|
|
|
|
2005-04-18 17:54:03 +00:00
|
|
|
fprintf(fout,
|
|
|
|
" <global_prefs_xml>\n"
|
|
|
|
" %s"
|
|
|
|
" </globals_prefs_xml>\n",
|
|
|
|
global_prefs_xml
|
|
|
|
);
|
2005-01-31 16:10:49 +00:00
|
|
|
|
2005-04-18 17:54:03 +00:00
|
|
|
fprintf(fout,
|
|
|
|
" <global_prefs_source_email_hash>%s</global_prefs_source_email_hash>\n",
|
|
|
|
global_prefs_source_email_hash
|
|
|
|
);
|
2005-01-31 16:10:49 +00:00
|
|
|
|
|
|
|
fprintf(fout,
|
2005-04-18 17:54:03 +00:00
|
|
|
" <host>\n"
|
|
|
|
" <id>%d</id>\n"
|
|
|
|
" <rpc_time>%d</rpc_time>\n"
|
|
|
|
" <timezone>%d</timezone>\n"
|
|
|
|
" <d_total>%.15f</d_total>\n"
|
|
|
|
" <d_free>%.15f</d_free>\n"
|
|
|
|
" <d_boinc_used_total>%.15f</d_boinc_used_total>\n"
|
|
|
|
" <d_boinc_used_project>%.15f</d_boinc_used_project>\n"
|
|
|
|
" <d_boinc_max>%.15f</d_boinc_max>\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<results.size(); i++) {
|
|
|
|
fprintf(fout,
|
2005-01-31 16:10:49 +00:00
|
|
|
" <result>\n"
|
|
|
|
" <name>%s</name>\n"
|
|
|
|
" <client_state>%d</client_state>\n"
|
|
|
|
" <cpu_time>%.15f</cpu_time>\n"
|
|
|
|
" <exit_status>%d</exit_status>\n"
|
|
|
|
" <app_version_num>%d</app_version_num>\n"
|
|
|
|
" </result>\n",
|
|
|
|
results[i].name,
|
|
|
|
results[i].client_state,
|
|
|
|
results[i].cpu_time,
|
|
|
|
results[i].exit_status,
|
|
|
|
results[i].app_version_num
|
2005-04-18 17:54:03 +00:00
|
|
|
);
|
|
|
|
}
|
2005-01-31 16:10:49 +00:00
|
|
|
|
2005-04-18 17:54:03 +00:00
|
|
|
for (i=0; i<msgs_from_host.size(); i++) {
|
|
|
|
fprintf(fout,
|
|
|
|
" <msg_from_host>\n"
|
|
|
|
" <variety>%s</variety>\n"
|
|
|
|
" <msg_text>%s</msg_text>\n"
|
|
|
|
" </msg_from_host>\n",
|
|
|
|
msgs_from_host[i].variety,
|
|
|
|
msgs_from_host[i].msg_text.c_str()
|
|
|
|
);
|
|
|
|
}
|
2005-01-31 16:10:49 +00:00
|
|
|
|
2005-04-18 17:54:03 +00:00
|
|
|
for (i=0; i<file_infos.size(); i++) {
|
|
|
|
fprintf(fout,
|
|
|
|
" <file_info>\n"
|
|
|
|
" <name>%s</name>\n"
|
|
|
|
" </file_info>\n",
|
|
|
|
file_infos[i].name
|
|
|
|
);
|
|
|
|
fprintf(fout, "</scheduler_request>\n");
|
|
|
|
}
|
|
|
|
return 0;
|
2005-01-31 16:10:49 +00:00
|
|
|
}
|
|
|
|
|
2004-06-24 21:00:13 +00:00
|
|
|
int MSG_FROM_HOST_DESC::parse(FILE* fin) {
|
2004-01-08 00:27:59 +00:00
|
|
|
char buf[256];
|
|
|
|
|
2004-06-24 21:00:13 +00:00
|
|
|
msg_text = "";
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2004-06-24 21:00:13 +00:00
|
|
|
if (match_tag(buf, "</msg_from_host>")) return 0;
|
2004-07-06 04:10:51 +00:00
|
|
|
if (parse_str(buf, "<variety>", variety, sizeof(variety))) continue;
|
|
|
|
msg_text += buf;
|
2004-01-08 00:27:59 +00:00
|
|
|
}
|
|
|
|
return ERR_XML_PARSE;
|
|
|
|
}
|
2002-04-30 22:22:54 +00:00
|
|
|
|
|
|
|
SCHEDULER_REPLY::SCHEDULER_REPLY() {
|
2005-01-31 23:20:49 +00:00
|
|
|
memset(&wreq, 0, sizeof(wreq));
|
2005-04-18 17:54:03 +00:00
|
|
|
memset(&disk_limits, 0, sizeof(disk_limits));
|
2002-04-30 22:22:54 +00:00
|
|
|
request_delay = 0;
|
|
|
|
hostid = 0;
|
2002-09-27 20:36:03 +00:00
|
|
|
send_global_prefs = false;
|
2003-04-03 18:35:40 +00:00
|
|
|
strcpy(code_sign_key, "");
|
|
|
|
strcpy(code_sign_key_signature, "");
|
2002-09-22 23:27:14 +00:00
|
|
|
memset(&user, 0, sizeof(user));
|
|
|
|
memset(&host, 0, sizeof(host));
|
2003-02-24 21:31:36 +00:00
|
|
|
memset(&team, 0, sizeof(team));
|
2002-12-02 04:29:40 +00:00
|
|
|
nucleus_only = false;
|
2008-03-13 23:35:13 +00:00
|
|
|
project_is_down = false;
|
2004-06-24 21:00:13 +00:00
|
|
|
send_msg_ack = false;
|
2004-05-03 02:18:35 +00:00
|
|
|
strcpy(email_hash, "");
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
SCHEDULER_REPLY::~SCHEDULER_REPLY() {
|
|
|
|
}
|
|
|
|
|
2008-10-01 22:07:35 +00:00
|
|
|
int SCHEDULER_REPLY::write(FILE* fout, SCHEDULER_REQUEST& sreq) {
|
2007-06-20 22:34:06 +00:00
|
|
|
unsigned int i;
|
2008-03-31 16:19:45 +00:00
|
|
|
char buf[BLOB_SIZE];
|
2002-12-02 04:29:40 +00:00
|
|
|
|
2007-02-23 17:29:19 +00:00
|
|
|
// Note: at one point we had
|
|
|
|
// "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n"
|
|
|
|
// after the Content-type (to make it legit XML),
|
|
|
|
// but this broke 4.19 clients
|
|
|
|
//
|
2002-04-30 22:22:54 +00:00
|
|
|
fprintf(fout,
|
2006-12-04 19:00:37 +00:00
|
|
|
"Content-type: text/xml\n\n"
|
2002-04-30 22:22:54 +00:00
|
|
|
"<scheduler_reply>\n"
|
2005-01-28 18:27:00 +00:00
|
|
|
"<scheduler_version>%d</scheduler_version>\n",
|
2005-01-27 23:09:19 +00:00
|
|
|
BOINC_MAJOR_VERSION*100+BOINC_MINOR_VERSION
|
2002-12-02 04:29:40 +00:00
|
|
|
);
|
2006-03-07 21:46:49 +00:00
|
|
|
if (strlen(config.master_url)) {
|
|
|
|
fprintf(fout,
|
|
|
|
"<master_url>%s</master_url>\n",
|
|
|
|
config.master_url
|
|
|
|
);
|
|
|
|
}
|
2007-05-24 16:07:21 +00:00
|
|
|
if (config.ended) {
|
|
|
|
fprintf(fout, " <ended>1</ended>\n");
|
|
|
|
}
|
2002-12-02 04:29:40 +00:00
|
|
|
|
2005-09-13 13:25:01 +00:00
|
|
|
// if the scheduler has requested a delay OR the sysadmin has configured
|
|
|
|
// the scheduler with a minimum time between RPCs, send a delay request.
|
|
|
|
// Make it 1% larger than the min required to take care of time skew.
|
2005-09-13 13:36:11 +00:00
|
|
|
// If this is less than one second bigger, bump up by one sec.
|
2005-09-13 13:25:01 +00:00
|
|
|
//
|
|
|
|
if (request_delay || config.min_sendwork_interval) {
|
2005-10-12 18:40:53 +00:00
|
|
|
double min_delay_needed = 1.01*config.min_sendwork_interval;
|
|
|
|
if (min_delay_needed < config.min_sendwork_interval+1) {
|
|
|
|
min_delay_needed = config.min_sendwork_interval+1;
|
|
|
|
}
|
|
|
|
if (request_delay<min_delay_needed) {
|
2009-06-01 22:15:14 +00:00
|
|
|
request_delay = min_delay_needed;
|
2005-10-12 18:40:53 +00:00
|
|
|
}
|
2005-02-16 23:17:43 +00:00
|
|
|
fprintf(fout, "<request_delay>%f</request_delay>\n", request_delay);
|
2002-12-02 04:29:40 +00:00
|
|
|
}
|
2008-05-02 17:48:29 +00:00
|
|
|
log_messages.printf(MSG_NORMAL,
|
- scheduler: add support for anonymous-platform coproc apps.
Old: although the request message contained all info
about the app version (flops, coproc usage etc.)
the server ignored this info,
and assumed that all anonymous platform apps where CPU.
With 6.6 client, this could produce infinite work fetch:
- client uses anon platform, has coproc app
- client has idle CPU, requests CPU work
- scheduler sends it jobs, thinking they will be done by CPU app
- client asks for more work etc.
New: scheduler parses full info on anon platform app versions:
plan class, FLOPS, coprocs.
It uses this info to make scheduling decisions;
in particular, if the request is for CUDA work,
if will only send jobs that use a CUDA app version.
The <result> records it returns contain info
(plan_class) that tells the client which app_version to use.
This will work correctly even if the client has multiple app versions
for the same app (e.g., a CPU version and a GPU version)
svn path=/trunk/boinc/; revision=17506
2009-03-05 17:30:10 +00:00
|
|
|
"Sending reply to [HOST#%d]: %d results, delay req %.2f\n",
|
2009-06-01 22:15:14 +00:00
|
|
|
host.id, wreq.njobs_sent, request_delay
|
2008-05-02 17:48:29 +00:00
|
|
|
);
|
|
|
|
|
2008-10-01 22:07:35 +00:00
|
|
|
if (sreq.core_client_version <= 419) {
|
2005-02-01 20:30:33 +00:00
|
|
|
std::string msg;
|
|
|
|
std::string pri = "low";
|
|
|
|
for (i=0; i<messages.size(); i++) {
|
|
|
|
USER_MESSAGE& um = messages[i];
|
|
|
|
msg += um.message + std::string(" ");
|
|
|
|
if (um.priority == "high") {
|
|
|
|
pri = "high";
|
|
|
|
}
|
|
|
|
}
|
2005-02-02 15:16:59 +00:00
|
|
|
if (messages.size()>0) {
|
2005-02-28 21:58:27 +00:00
|
|
|
// any newlines will break message printing under 4.19 and under!
|
|
|
|
// replace them with spaces.
|
2005-03-10 22:05:42 +00:00
|
|
|
//
|
|
|
|
while (1) {
|
2009-02-26 00:23:23 +00:00
|
|
|
std::string::size_type pos = msg.find("\n", 0);
|
|
|
|
if (pos == std::string::npos) break;
|
2005-03-10 22:05:42 +00:00
|
|
|
msg.replace(pos, 1, " ");
|
2005-02-28 21:58:27 +00:00
|
|
|
}
|
2005-02-02 15:16:59 +00:00
|
|
|
fprintf(fout,
|
|
|
|
"<message priority=\"%s\">%s</message>\n",
|
|
|
|
pri.c_str(), msg.c_str()
|
|
|
|
);
|
|
|
|
}
|
2005-02-01 20:30:33 +00:00
|
|
|
} else {
|
|
|
|
for (i=0; i<messages.size(); i++) {
|
|
|
|
USER_MESSAGE& um = messages[i];
|
|
|
|
fprintf(fout,
|
|
|
|
"<message priority=\"%s\">%s</message>\n",
|
|
|
|
um.priority.c_str(),
|
|
|
|
um.message.c_str()
|
|
|
|
);
|
|
|
|
}
|
2002-12-02 04:29:40 +00:00
|
|
|
}
|
|
|
|
fprintf(fout,
|
2003-02-14 22:35:35 +00:00
|
|
|
"<project_name>%s</project_name>\n",
|
2004-05-02 15:55:17 +00:00
|
|
|
config.long_name
|
2002-04-30 22:22:54 +00:00
|
|
|
);
|
|
|
|
|
2008-01-13 00:12:14 +00:00
|
|
|
if (config.request_time_stats_log) {
|
2008-12-19 18:14:02 +00:00
|
|
|
if (!have_time_stats_log()) {
|
2008-01-13 00:12:14 +00:00
|
|
|
fprintf(fout, "<send_time_stats_log>1</send_time_stats_log>\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-05-16 00:14:48 +00:00
|
|
|
if (project_is_down) {
|
|
|
|
fprintf(fout,"<project_is_down/>\n");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nucleus_only) goto end;
|
|
|
|
|
2006-05-22 09:54:31 +00:00
|
|
|
if (strlen(config.symstore)) {
|
|
|
|
fprintf(fout, "<symstore>%s</symstore>\n", config.symstore);
|
|
|
|
}
|
2006-05-25 18:51:57 +00:00
|
|
|
if (config.next_rpc_delay) {
|
|
|
|
fprintf(fout, "<next_rpc_delay>%f</next_rpc_delay>\n", config.next_rpc_delay);
|
|
|
|
}
|
2004-08-12 13:36:05 +00:00
|
|
|
if (user.id) {
|
2008-08-13 17:27:13 +00:00
|
|
|
xml_escape(user.name, buf, sizeof(buf));
|
2004-05-13 04:48:19 +00:00
|
|
|
fprintf(fout,
|
2004-08-12 13:36:05 +00:00
|
|
|
"<user_name>%s</user_name>\n"
|
|
|
|
"<user_total_credit>%f</user_total_credit>\n"
|
|
|
|
"<user_expavg_credit>%f</user_expavg_credit>\n"
|
|
|
|
"<user_create_time>%d</user_create_time>\n",
|
2006-04-17 22:41:29 +00:00
|
|
|
buf,
|
2004-08-12 13:36:05 +00:00
|
|
|
user.total_credit,
|
|
|
|
user.expavg_credit,
|
|
|
|
user.create_time
|
2004-05-13 04:48:19 +00:00
|
|
|
);
|
2004-08-12 13:36:05 +00:00
|
|
|
// be paranoid about the following to avoid sending null
|
|
|
|
//
|
|
|
|
if (strlen(email_hash)) {
|
|
|
|
fprintf(fout,
|
|
|
|
"<email_hash>%s</email_hash>\n",
|
|
|
|
email_hash
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (strlen(user.cross_project_id)) {
|
|
|
|
fprintf(fout,
|
|
|
|
"<cross_project_id>%s</cross_project_id>\n",
|
|
|
|
user.cross_project_id
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (send_global_prefs) {
|
|
|
|
fputs(user.global_prefs, fout);
|
2006-04-19 18:49:54 +00:00
|
|
|
fputs("\n", fout);
|
2004-08-12 13:36:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// always send project prefs
|
|
|
|
//
|
|
|
|
fputs(user.project_prefs, fout);
|
2006-04-19 18:49:54 +00:00
|
|
|
fputs("\n", fout);
|
2004-08-12 13:36:05 +00:00
|
|
|
|
2004-05-13 04:48:19 +00:00
|
|
|
}
|
2004-08-12 13:36:05 +00:00
|
|
|
if (hostid) {
|
2004-05-13 04:48:19 +00:00
|
|
|
fprintf(fout,
|
2004-10-01 07:49:01 +00:00
|
|
|
"<hostid>%d</hostid>\n",
|
|
|
|
hostid
|
2004-05-13 04:48:19 +00:00
|
|
|
);
|
2004-08-13 11:21:12 +00:00
|
|
|
}
|
2004-10-01 07:49:01 +00:00
|
|
|
fprintf(fout,
|
|
|
|
"<host_total_credit>%f</host_total_credit>\n"
|
|
|
|
"<host_expavg_credit>%f</host_expavg_credit>\n"
|
|
|
|
"<host_venue>%s</host_venue>\n"
|
|
|
|
"<host_create_time>%d</host_create_time>\n",
|
|
|
|
host.total_credit,
|
|
|
|
host.expavg_credit,
|
|
|
|
host.venue,
|
|
|
|
host.create_time
|
|
|
|
);
|
2004-05-13 04:48:19 +00:00
|
|
|
|
2003-02-24 21:31:36 +00:00
|
|
|
// might want to send team credit too.
|
|
|
|
//
|
|
|
|
if (team.id) {
|
2008-08-13 17:27:13 +00:00
|
|
|
xml_escape(team.name, buf, sizeof(buf));
|
2003-02-24 21:31:36 +00:00
|
|
|
fprintf(fout,
|
|
|
|
"<team_name>%s</team_name>\n",
|
2006-04-17 22:41:29 +00:00
|
|
|
buf
|
2003-02-24 21:31:36 +00:00
|
|
|
);
|
2005-10-09 05:53:35 +00:00
|
|
|
} else {
|
|
|
|
fprintf(fout,
|
|
|
|
"<team_name></team_name>\n"
|
|
|
|
);
|
2003-02-24 21:31:36 +00:00
|
|
|
}
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
// acknowledge results
|
|
|
|
//
|
|
|
|
for (i=0; i<result_acks.size(); i++) {
|
|
|
|
fprintf(fout,
|
|
|
|
"<result_ack>\n"
|
|
|
|
" <name>%s</name>\n"
|
|
|
|
"</result_ack>\n",
|
2005-06-22 06:02:59 +00:00
|
|
|
result_acks[i].c_str()
|
2002-04-30 22:22:54 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2007-04-05 17:02:01 +00:00
|
|
|
// abort results
|
|
|
|
//
|
|
|
|
for (i=0; i<result_aborts.size(); i++) {
|
|
|
|
fprintf(fout,
|
|
|
|
"<result_abort>\n"
|
|
|
|
" <name>%s</name>\n"
|
|
|
|
"</result_abort>\n",
|
|
|
|
result_aborts[i].c_str()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// abort results not started
|
|
|
|
//
|
|
|
|
for (i=0; i<result_abort_if_not_starteds.size(); i++) {
|
|
|
|
fprintf(fout,
|
|
|
|
"<result_abort_if_not_started>\n"
|
|
|
|
" <name>%s</name>\n"
|
|
|
|
"</result_abort_if_not_started>\n",
|
|
|
|
result_abort_if_not_starteds[i].c_str()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
for (i=0; i<apps.size(); i++) {
|
|
|
|
apps[i].write(fout);
|
|
|
|
}
|
2003-05-20 00:03:39 +00:00
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
for (i=0; i<app_versions.size(); i++) {
|
2007-05-02 23:14:00 +00:00
|
|
|
app_versions[i].write(fout);
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2003-05-20 00:03:39 +00:00
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
for (i=0; i<wus.size(); i++) {
|
|
|
|
fputs(wus[i].xml_doc, fout);
|
|
|
|
}
|
2003-05-20 00:03:39 +00:00
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
for (i=0; i<results.size(); i++) {
|
2007-05-02 23:14:00 +00:00
|
|
|
results[i].write_to_client(fout);
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2003-05-20 00:03:39 +00:00
|
|
|
|
2003-04-03 18:35:40 +00:00
|
|
|
if (strlen(code_sign_key)) {
|
2002-07-07 20:39:24 +00:00
|
|
|
fputs("<code_sign_key>\n", fout);
|
|
|
|
fputs(code_sign_key, fout);
|
|
|
|
fputs("</code_sign_key>\n", fout);
|
|
|
|
}
|
2003-05-20 00:03:39 +00:00
|
|
|
|
2003-04-03 18:35:40 +00:00
|
|
|
if (strlen(code_sign_key_signature)) {
|
2002-07-07 20:39:24 +00:00
|
|
|
fputs("<code_sign_key_signature>\n", fout);
|
|
|
|
fputs(code_sign_key_signature, fout);
|
|
|
|
fputs("</code_sign_key_signature>\n", fout);
|
|
|
|
}
|
2006-06-20 17:36:28 +00:00
|
|
|
|
2004-06-24 21:00:13 +00:00
|
|
|
if (send_msg_ack) {
|
|
|
|
fputs("<message_ack/>\n", fout);
|
2004-03-17 01:26:44 +00:00
|
|
|
}
|
2004-07-10 00:11:20 +00:00
|
|
|
|
2004-06-22 22:56:50 +00:00
|
|
|
for (i=0; i<msgs_to_host.size(); i++) {
|
2004-06-24 21:00:13 +00:00
|
|
|
MSG_TO_HOST& md = msgs_to_host[i];
|
|
|
|
fprintf(fout, "%s\n", md.xml);
|
2004-01-08 00:27:59 +00:00
|
|
|
}
|
2004-07-13 13:54:09 +00:00
|
|
|
|
2004-04-14 23:32:17 +00:00
|
|
|
if (config.non_cpu_intensive) {
|
|
|
|
fprintf(fout, "<non_cpu_intensive/>\n");
|
|
|
|
}
|
2004-09-10 21:02:11 +00:00
|
|
|
|
2006-06-20 17:36:28 +00:00
|
|
|
if (config.verify_files_on_app_start) {
|
|
|
|
fprintf(fout, "<verify_files_on_app_start/>\n");
|
|
|
|
}
|
|
|
|
|
2004-09-10 21:02:11 +00:00
|
|
|
for (i=0; i<file_deletes.size(); i++) {
|
|
|
|
fprintf(fout,
|
|
|
|
"<delete_file_info>%s</delete_file_info>\n",
|
|
|
|
file_deletes[i].name
|
|
|
|
);
|
|
|
|
}
|
2004-09-13 18:05:54 +00:00
|
|
|
|
2004-09-27 19:44:40 +00:00
|
|
|
gui_urls.get_gui_urls(user, host, team, buf);
|
2004-09-13 18:05:54 +00:00
|
|
|
fputs(buf, fout);
|
2006-06-26 22:58:24 +00:00
|
|
|
if (project_files.text) {
|
|
|
|
fputs(project_files.text, fout);
|
2008-10-02 19:16:09 +00:00
|
|
|
fprintf(fout, "\n");
|
2006-06-26 22:58:24 +00:00
|
|
|
}
|
2004-09-13 18:05:54 +00:00
|
|
|
|
2002-12-02 04:29:40 +00:00
|
|
|
end:
|
2002-04-30 22:22:54 +00:00
|
|
|
fprintf(fout,
|
|
|
|
"</scheduler_reply>\n"
|
2004-01-08 00:27:59 +00:00
|
|
|
);
|
2002-04-30 22:22:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-02-16 23:17:43 +00:00
|
|
|
// 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) {
|
2005-02-16 01:26:43 +00:00
|
|
|
if (request_delay < delay) {
|
2005-02-16 01:14:12 +00:00
|
|
|
request_delay = delay;
|
2005-02-16 01:26:43 +00:00
|
|
|
}
|
2008-02-28 21:22:50 +00:00
|
|
|
if (request_delay > DELAY_MAX) {
|
|
|
|
request_delay = DELAY_MAX;
|
2005-02-16 01:26:43 +00:00
|
|
|
}
|
2005-02-16 01:14:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
void SCHEDULER_REPLY::insert_app_unique(APP& app) {
|
|
|
|
unsigned int i;
|
|
|
|
for (i=0; i<apps.size(); i++) {
|
|
|
|
if (app.id == apps[i].id) return;
|
|
|
|
}
|
|
|
|
apps.push_back(app);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SCHEDULER_REPLY::insert_app_version_unique(APP_VERSION& av) {
|
|
|
|
unsigned int i;
|
|
|
|
for (i=0; i<app_versions.size(); i++) {
|
|
|
|
if (av.id == app_versions[i].id) return;
|
|
|
|
}
|
|
|
|
app_versions.push_back(av);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SCHEDULER_REPLY::insert_workunit_unique(WORKUNIT& wu) {
|
|
|
|
unsigned int i;
|
|
|
|
for (i=0; i<wus.size(); i++) {
|
|
|
|
if (wu.id == wus[i].id) return;
|
|
|
|
}
|
|
|
|
wus.push_back(wu);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SCHEDULER_REPLY::insert_result(RESULT& result) {
|
|
|
|
results.push_back(result);
|
|
|
|
}
|
|
|
|
|
2009-02-26 03:03:35 +00:00
|
|
|
void SCHEDULER_REPLY::insert_message(const USER_MESSAGE& um) {
|
2005-01-31 22:19:03 +00:00
|
|
|
messages.push_back(um);
|
|
|
|
}
|
|
|
|
|
2005-02-16 23:17:43 +00:00
|
|
|
USER_MESSAGE::USER_MESSAGE(const char* m, const char* p) {
|
2005-01-31 22:19:03 +00:00
|
|
|
message = m;
|
|
|
|
priority = p;
|
|
|
|
}
|
|
|
|
|
2002-04-30 22:22:54 +00:00
|
|
|
int APP::write(FILE* fout) {
|
|
|
|
fprintf(fout,
|
|
|
|
"<app>\n"
|
|
|
|
" <name>%s</name>\n"
|
2006-06-26 19:08:00 +00:00
|
|
|
" <user_friendly_name>%s</user_friendly_name>\n"
|
2002-04-30 22:22:54 +00:00
|
|
|
"</app>\n",
|
2006-06-26 19:08:00 +00:00
|
|
|
name, user_friendly_name
|
2002-04-30 22:22:54 +00:00
|
|
|
);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-02-16 23:17:43 +00:00
|
|
|
int APP_VERSION::write(FILE* fout) {
|
2008-04-02 19:57:41 +00:00
|
|
|
char buf[APP_VERSION_XML_BLOB_SIZE];
|
2008-03-28 18:00:27 +00:00
|
|
|
unsigned int i;
|
|
|
|
|
2007-05-02 23:14:00 +00:00
|
|
|
strcpy(buf, xml_doc);
|
|
|
|
char* p = strstr(buf, "</app_version>");
|
|
|
|
if (!p) {
|
|
|
|
fprintf(stderr, "ERROR: app version %d XML has no end tag!\n", id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
fputs(buf, fout);
|
|
|
|
PLATFORM* pp = ssp->lookup_platform_id(platformid);
|
2008-03-27 18:25:29 +00:00
|
|
|
fprintf(fout, " <platform>%s</platform>\n", pp->name);
|
|
|
|
if (strlen(plan_class)) {
|
|
|
|
fprintf(fout, " <plan_class>%s</plan_class>\n", plan_class);
|
|
|
|
}
|
2008-03-28 18:00:27 +00:00
|
|
|
fprintf(fout,
|
|
|
|
" <avg_ncpus>%f</avg_ncpus>\n"
|
|
|
|
" <max_ncpus>%f</max_ncpus>\n"
|
|
|
|
" <flops>%f</flops>\n",
|
|
|
|
bavp->host_usage.avg_ncpus,
|
|
|
|
bavp->host_usage.max_ncpus,
|
|
|
|
bavp->host_usage.flops
|
|
|
|
);
|
|
|
|
if (strlen(bavp->host_usage.cmdline)) {
|
|
|
|
fprintf(fout,
|
|
|
|
" <cmdline>%s</cmdline>\n",
|
|
|
|
bavp->host_usage.cmdline
|
|
|
|
);
|
|
|
|
}
|
2009-03-05 00:10:16 +00:00
|
|
|
if (bavp->host_usage.ncudas) {
|
2008-03-28 18:00:27 +00:00
|
|
|
fprintf(fout,
|
|
|
|
" <coproc>\n"
|
2009-03-05 00:10:16 +00:00
|
|
|
" <type>CUDA</type>\n"
|
2008-03-28 18:00:27 +00:00
|
|
|
" <count>%d</count>\n"
|
|
|
|
" </coproc>\n",
|
2009-03-05 00:10:16 +00:00
|
|
|
bavp->host_usage.ncudas
|
2008-03-28 18:00:27 +00:00
|
|
|
);
|
|
|
|
}
|
2007-05-02 23:14:00 +00:00
|
|
|
fputs("</app_version>\n", fout);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int RESULT::write_to_client(FILE* fout) {
|
2008-03-31 16:19:45 +00:00
|
|
|
char buf[BLOB_SIZE];
|
2008-03-27 18:25:29 +00:00
|
|
|
|
2007-05-02 23:14:00 +00:00
|
|
|
strcpy(buf, xml_doc_in);
|
|
|
|
char* p = strstr(buf, "</result>");
|
|
|
|
if (!p) {
|
|
|
|
fprintf(stderr, "ERROR: result %d XML has no end tag!\n", id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
*p = 0;
|
|
|
|
fputs(buf, fout);
|
2007-05-21 14:49:00 +00:00
|
|
|
|
2008-03-27 18:25:29 +00:00
|
|
|
APP_VERSION* avp = bavp->avp;
|
- scheduler: add support for anonymous-platform coproc apps.
Old: although the request message contained all info
about the app version (flops, coproc usage etc.)
the server ignored this info,
and assumed that all anonymous platform apps where CPU.
With 6.6 client, this could produce infinite work fetch:
- client uses anon platform, has coproc app
- client has idle CPU, requests CPU work
- scheduler sends it jobs, thinking they will be done by CPU app
- client asks for more work etc.
New: scheduler parses full info on anon platform app versions:
plan class, FLOPS, coprocs.
It uses this info to make scheduling decisions;
in particular, if the request is for CUDA work,
if will only send jobs that use a CUDA app version.
The <result> records it returns contain info
(plan_class) that tells the client which app_version to use.
This will work correctly even if the client has multiple app versions
for the same app (e.g., a CPU version and a GPU version)
svn path=/trunk/boinc/; revision=17506
2009-03-05 17:30:10 +00:00
|
|
|
CLIENT_APP_VERSION* cavp = bavp->cavp;
|
2008-03-27 18:25:29 +00:00
|
|
|
if (avp) {
|
|
|
|
PLATFORM* pp = ssp->lookup_platform_id(avp->platformid);
|
|
|
|
fprintf(fout,
|
2007-05-21 14:49:00 +00:00
|
|
|
" <platform>%s</platform>\n"
|
2008-03-28 18:00:27 +00:00
|
|
|
" <version_num>%d</version_num>\n"
|
|
|
|
" <plan_class>%s</plan_class>\n",
|
|
|
|
pp->name, avp->version_num, avp->plan_class
|
2007-05-21 14:49:00 +00:00
|
|
|
);
|
- scheduler: add support for anonymous-platform coproc apps.
Old: although the request message contained all info
about the app version (flops, coproc usage etc.)
the server ignored this info,
and assumed that all anonymous platform apps where CPU.
With 6.6 client, this could produce infinite work fetch:
- client uses anon platform, has coproc app
- client has idle CPU, requests CPU work
- scheduler sends it jobs, thinking they will be done by CPU app
- client asks for more work etc.
New: scheduler parses full info on anon platform app versions:
plan class, FLOPS, coprocs.
It uses this info to make scheduling decisions;
in particular, if the request is for CUDA work,
if will only send jobs that use a CUDA app version.
The <result> records it returns contain info
(plan_class) that tells the client which app_version to use.
This will work correctly even if the client has multiple app versions
for the same app (e.g., a CPU version and a GPU version)
svn path=/trunk/boinc/; revision=17506
2009-03-05 17:30:10 +00:00
|
|
|
} else if (cavp) {
|
|
|
|
fprintf(fout,
|
2009-03-05 17:54:39 +00:00
|
|
|
" <platform>%s</platform>\n"
|
- scheduler: add support for anonymous-platform coproc apps.
Old: although the request message contained all info
about the app version (flops, coproc usage etc.)
the server ignored this info,
and assumed that all anonymous platform apps where CPU.
With 6.6 client, this could produce infinite work fetch:
- client uses anon platform, has coproc app
- client has idle CPU, requests CPU work
- scheduler sends it jobs, thinking they will be done by CPU app
- client asks for more work etc.
New: scheduler parses full info on anon platform app versions:
plan class, FLOPS, coprocs.
It uses this info to make scheduling decisions;
in particular, if the request is for CUDA work,
if will only send jobs that use a CUDA app version.
The <result> records it returns contain info
(plan_class) that tells the client which app_version to use.
This will work correctly even if the client has multiple app versions
for the same app (e.g., a CPU version and a GPU version)
svn path=/trunk/boinc/; revision=17506
2009-03-05 17:30:10 +00:00
|
|
|
" <version_num>%d</version_num>\n"
|
|
|
|
" <plan_class>%s</plan_class>\n",
|
2009-03-05 17:54:39 +00:00
|
|
|
cavp->platform, cavp->version_num, cavp->plan_class
|
- scheduler: add support for anonymous-platform coproc apps.
Old: although the request message contained all info
about the app version (flops, coproc usage etc.)
the server ignored this info,
and assumed that all anonymous platform apps where CPU.
With 6.6 client, this could produce infinite work fetch:
- client uses anon platform, has coproc app
- client has idle CPU, requests CPU work
- scheduler sends it jobs, thinking they will be done by CPU app
- client asks for more work etc.
New: scheduler parses full info on anon platform app versions:
plan class, FLOPS, coprocs.
It uses this info to make scheduling decisions;
in particular, if the request is for CUDA work,
if will only send jobs that use a CUDA app version.
The <result> records it returns contain info
(plan_class) that tells the client which app_version to use.
This will work correctly even if the client has multiple app versions
for the same app (e.g., a CPU version and a GPU version)
svn path=/trunk/boinc/; revision=17506
2009-03-05 17:30:10 +00:00
|
|
|
);
|
2007-05-21 14:49:00 +00:00
|
|
|
}
|
- scheduler: add support for anonymous-platform coproc apps.
Old: although the request message contained all info
about the app version (flops, coproc usage etc.)
the server ignored this info,
and assumed that all anonymous platform apps where CPU.
With 6.6 client, this could produce infinite work fetch:
- client uses anon platform, has coproc app
- client has idle CPU, requests CPU work
- scheduler sends it jobs, thinking they will be done by CPU app
- client asks for more work etc.
New: scheduler parses full info on anon platform app versions:
plan class, FLOPS, coprocs.
It uses this info to make scheduling decisions;
in particular, if the request is for CUDA work,
if will only send jobs that use a CUDA app version.
The <result> records it returns contain info
(plan_class) that tells the client which app_version to use.
This will work correctly even if the client has multiple app versions
for the same app (e.g., a CPU version and a GPU version)
svn path=/trunk/boinc/; revision=17506
2009-03-05 17:30:10 +00:00
|
|
|
|
2007-05-02 23:14:00 +00:00
|
|
|
fputs("</result>\n", fout);
|
2002-04-30 22:22:54 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int RESULT::parse_from_client(FILE* fin) {
|
2003-07-01 00:20:22 +00:00
|
|
|
char buf[256];
|
2009-03-18 21:14:44 +00:00
|
|
|
double final_cpu_time = 0, final_elapsed_time = 0;
|
2003-01-07 01:02:08 +00:00
|
|
|
|
2004-03-20 07:57:22 +00:00
|
|
|
// should be non-zero if exit_status is not found
|
2004-06-24 21:00:13 +00:00
|
|
|
exit_status = ERR_NO_EXIT_STATUS;
|
2002-04-30 22:22:54 +00:00
|
|
|
memset(this, 0, sizeof(RESULT));
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2009-03-18 21:14:44 +00:00
|
|
|
if (match_tag(buf, "</result>")) {
|
|
|
|
// newer clients (>6.6.15) report final elapsed time;
|
|
|
|
// use it if possible
|
|
|
|
//
|
|
|
|
// actually, let's hold off on this
|
|
|
|
|
|
|
|
//if (final_elapsed_time) {
|
|
|
|
// cpu_time = final_elapsed_time;
|
|
|
|
//} else {
|
|
|
|
cpu_time = final_cpu_time;
|
|
|
|
//}
|
|
|
|
return 0;
|
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_str(buf, "<name>", name, sizeof(name))) continue;
|
|
|
|
if (parse_int(buf, "<state>", client_state)) continue;
|
2009-03-18 21:14:44 +00:00
|
|
|
if (parse_double(buf, "<final_cpu_time>", final_cpu_time)) continue;
|
|
|
|
if (parse_double(buf, "<final_elapsed_time>", final_elapsed_time)) continue;
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_int(buf, "<exit_status>", exit_status)) continue;
|
|
|
|
if (parse_int(buf, "<app_version_num>", app_version_num)) continue;
|
|
|
|
if (parse_double(buf, "<fpops_per_cpu_sec>", fpops_per_cpu_sec)) continue;
|
|
|
|
if (parse_double(buf, "<fpops_cumulative>", fpops_cumulative)) continue;
|
|
|
|
if (parse_double(buf, "<intops_per_cpu_sec>", intops_per_cpu_sec)) continue;
|
|
|
|
if (parse_double(buf, "<intops_cumulative>", intops_cumulative)) continue;
|
|
|
|
if (match_tag(buf, "<file_info>")) {
|
2003-04-03 18:35:40 +00:00
|
|
|
safe_strcat(xml_doc_out, buf);
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2003-04-03 18:35:40 +00:00
|
|
|
safe_strcat(xml_doc_out, buf);
|
2002-04-30 22:22:54 +00:00
|
|
|
if (match_tag(buf, "</file_info>")) break;
|
|
|
|
}
|
|
|
|
continue;
|
2007-06-14 23:08:43 +00:00
|
|
|
}
|
|
|
|
if (match_tag(buf, "<stderr_out>" )) {
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2002-04-30 22:22:54 +00:00
|
|
|
if (match_tag(buf, "</stderr_out>")) break;
|
2003-04-03 18:35:40 +00:00
|
|
|
safe_strcat(stderr_out, buf);
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
continue;
|
2003-01-07 01:02:08 +00:00
|
|
|
}
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<platform>")) continue;
|
|
|
|
if (match_tag(buf, "<version_num>")) continue;
|
2008-05-02 17:48:29 +00:00
|
|
|
if (match_tag(buf, "<plan_class>")) continue;
|
2007-09-23 21:38:47 +00:00
|
|
|
if (match_tag(buf, "<completed_time>")) continue;
|
|
|
|
if (match_tag(buf, "<file_name>")) continue;
|
|
|
|
if (match_tag(buf, "<file_ref>")) continue;
|
2007-09-24 06:54:01 +00:00
|
|
|
if (match_tag(buf, "</file_ref>")) continue;
|
2007-09-23 21:38:47 +00:00
|
|
|
if (match_tag(buf, "<open_name>")) continue;
|
|
|
|
if (match_tag(buf, "<ready_to_report>")) continue;
|
2007-09-24 06:54:01 +00:00
|
|
|
if (match_tag(buf, "<ready_to_report/>")) continue;
|
2007-09-23 21:38:47 +00:00
|
|
|
if (match_tag(buf, "<report_deadline>")) continue;
|
|
|
|
if (match_tag(buf, "<wu_name>")) continue;
|
|
|
|
|
2008-02-21 21:00:58 +00:00
|
|
|
log_messages.printf(MSG_NORMAL,
|
2007-06-14 23:08:43 +00:00
|
|
|
"RESULT::parse_from_client(): unrecognized: %s\n",
|
|
|
|
buf
|
|
|
|
);
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2004-01-08 00:27:59 +00:00
|
|
|
return ERR_XML_PARSE;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int HOST::parse(FILE* fin) {
|
2007-03-11 01:16:37 +00:00
|
|
|
char buf[1024];
|
2003-01-07 01:02:08 +00:00
|
|
|
|
2005-02-14 04:39:07 +00:00
|
|
|
p_ncpus = 1;
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2002-04-30 22:22:54 +00:00
|
|
|
if (match_tag(buf, "</host_info>")) return 0;
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_int(buf, "<timezone>", timezone)) continue;
|
|
|
|
if (parse_str(buf, "<domain_name>", domain_name, sizeof(domain_name))) continue;
|
|
|
|
if (parse_str(buf, "<ip_addr>", last_ip_addr, sizeof(last_ip_addr))) continue;
|
|
|
|
if (parse_str(buf, "<host_cpid>", host_cpid, sizeof(host_cpid))) continue;
|
|
|
|
if (parse_int(buf, "<p_ncpus>", p_ncpus)) continue;
|
|
|
|
if (parse_str(buf, "<p_vendor>", p_vendor, sizeof(p_vendor))) continue;
|
|
|
|
if (parse_str(buf, "<p_model>", p_model, sizeof(p_model))) continue;
|
|
|
|
if (parse_double(buf, "<p_fpops>", p_fpops)) continue;
|
|
|
|
if (parse_double(buf, "<p_iops>", p_iops)) continue;
|
|
|
|
if (parse_double(buf, "<p_membw>", p_membw)) continue;
|
|
|
|
if (parse_str(buf, "<os_name>", os_name, sizeof(os_name))) continue;
|
|
|
|
if (parse_str(buf, "<os_version>", os_version, sizeof(os_version))) continue;
|
|
|
|
if (parse_double(buf, "<m_nbytes>", m_nbytes)) continue;
|
|
|
|
if (parse_double(buf, "<m_cache>", m_cache)) continue;
|
|
|
|
if (parse_double(buf, "<m_swap>", m_swap)) continue;
|
|
|
|
if (parse_double(buf, "<d_total>", d_total)) continue;
|
|
|
|
if (parse_double(buf, "<d_free>", d_free)) continue;
|
|
|
|
if (parse_double(buf, "<n_bwup>", n_bwup)) continue;
|
|
|
|
if (parse_double(buf, "<n_bwdown>", n_bwdown)) continue;
|
2009-02-19 15:43:37 +00:00
|
|
|
if (parse_str(buf, "<p_features>", p_features, sizeof(p_features))) continue;
|
2005-10-04 21:44:58 +00:00
|
|
|
|
|
|
|
// parse deprecated fields to avoid error messages
|
2005-10-23 07:19:03 +00:00
|
|
|
//
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<p_calculated>")) continue;
|
|
|
|
if (match_tag(buf, "<p_fpop_err>")) continue;
|
|
|
|
if (match_tag(buf, "<p_iop_err>")) continue;
|
|
|
|
if (match_tag(buf, "<p_membw_err>")) continue;
|
2005-10-04 21:44:58 +00:00
|
|
|
|
2006-06-22 19:40:30 +00:00
|
|
|
// fields reported by 5.5+ clients, not currently used
|
2006-05-24 09:40:35 +00:00
|
|
|
//
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<p_capabilities>")) continue;
|
|
|
|
if (match_tag(buf, "<accelerators>")) continue;
|
2006-05-24 09:40:35 +00:00
|
|
|
|
2007-09-23 21:38:47 +00:00
|
|
|
#if 1
|
2008-12-19 20:55:49 +00:00
|
|
|
// not sure where these fields belong in the above categories
|
2007-09-23 21:38:47 +00:00
|
|
|
//
|
|
|
|
if (match_tag(buf, "<cpu_caps>")) continue;
|
|
|
|
if (match_tag(buf, "<cache_l1>")) continue;
|
|
|
|
if (match_tag(buf, "<cache_l2>")) continue;
|
|
|
|
if (match_tag(buf, "<cache_l3>")) continue;
|
|
|
|
#endif
|
|
|
|
|
2008-02-21 21:00:58 +00:00
|
|
|
log_messages.printf(MSG_NORMAL,
|
2007-06-14 23:08:43 +00:00
|
|
|
"HOST::parse(): unrecognized: %s\n", buf
|
|
|
|
);
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2004-01-08 00:27:59 +00:00
|
|
|
return ERR_XML_PARSE;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int HOST::parse_time_stats(FILE* fin) {
|
2003-07-01 00:20:22 +00:00
|
|
|
char buf[256];
|
2003-01-07 01:02:08 +00:00
|
|
|
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2002-04-30 22:22:54 +00:00
|
|
|
if (match_tag(buf, "</time_stats>")) return 0;
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_double(buf, "<on_frac>", on_frac)) continue;
|
|
|
|
if (parse_double(buf, "<connected_frac>", connected_frac)) continue;
|
|
|
|
if (parse_double(buf, "<active_frac>", active_frac)) continue;
|
2008-12-17 20:53:46 +00:00
|
|
|
#if 0
|
2007-06-14 23:08:43 +00:00
|
|
|
if (match_tag(buf, "<outages>")) continue;
|
|
|
|
if (match_tag(buf, "<outage>")) continue;
|
2007-09-23 21:38:47 +00:00
|
|
|
if (match_tag(buf, "<start>")) continue;
|
|
|
|
if (match_tag(buf, "<end>")) continue;
|
2008-02-21 21:00:58 +00:00
|
|
|
log_messages.printf(MSG_NORMAL,
|
2007-06-14 23:08:43 +00:00
|
|
|
"HOST::parse_time_stats(): unrecognized: %s\n",
|
|
|
|
buf
|
|
|
|
);
|
2008-12-17 20:53:46 +00:00
|
|
|
#endif
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2004-01-08 00:27:59 +00:00
|
|
|
return ERR_XML_PARSE;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int HOST::parse_net_stats(FILE* fin) {
|
2003-07-01 00:20:22 +00:00
|
|
|
char buf[256];
|
2002-04-30 22:22:54 +00:00
|
|
|
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2002-04-30 22:22:54 +00:00
|
|
|
if (match_tag(buf, "</net_stats>")) return 0;
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_double(buf, "<bwup>", n_bwup)) continue;
|
|
|
|
if (parse_double(buf, "<bwdown>", n_bwdown)) continue;
|
2007-09-21 18:10:54 +00:00
|
|
|
|
|
|
|
// items reported by 5.10+ clients, not currently used
|
|
|
|
//
|
|
|
|
if (match_tag(buf, "<avg_time_up>")) continue;
|
|
|
|
if (match_tag(buf, "<avg_up>")) continue;
|
|
|
|
if (match_tag(buf, "<avg_time_down>")) continue;
|
|
|
|
if (match_tag(buf, "<avg_down>")) continue;
|
2007-09-23 21:38:47 +00:00
|
|
|
|
2008-02-21 21:00:58 +00:00
|
|
|
log_messages.printf(MSG_NORMAL,
|
2007-06-14 23:08:43 +00:00
|
|
|
"HOST::parse_net_stats(): unrecognized: %s\n",
|
|
|
|
buf
|
|
|
|
);
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2004-01-08 00:27:59 +00:00
|
|
|
return ERR_XML_PARSE;
|
2002-04-30 22:22:54 +00:00
|
|
|
}
|
2003-11-04 22:22:06 +00:00
|
|
|
|
2005-10-04 21:44:58 +00:00
|
|
|
int HOST::parse_disk_usage(FILE* fin) {
|
|
|
|
char buf[256];
|
|
|
|
|
2007-03-27 21:39:40 +00:00
|
|
|
while (fgets(buf, sizeof(buf), fin)) {
|
2005-10-04 21:44:58 +00:00
|
|
|
if (match_tag(buf, "</disk_usage>")) return 0;
|
2007-06-14 23:08:43 +00:00
|
|
|
if (parse_double(buf, "<d_boinc_used_total>", d_boinc_used_total)) continue;
|
|
|
|
if (parse_double(buf, "<d_boinc_used_project>", d_boinc_used_project)) continue;
|
2008-02-21 21:00:58 +00:00
|
|
|
log_messages.printf(MSG_NORMAL,
|
2007-06-14 23:08:43 +00:00
|
|
|
"HOST::parse_disk_usage(): unrecognized: %s\n",
|
|
|
|
buf
|
|
|
|
);
|
2005-10-04 21:44:58 +00:00
|
|
|
}
|
|
|
|
return ERR_XML_PARSE;
|
|
|
|
}
|
|
|
|
|
2006-11-07 17:40:55 +00:00
|
|
|
void GLOBAL_PREFS::parse(const char* buf, const char* venue) {
|
2008-03-31 16:19:45 +00:00
|
|
|
char buf2[BLOB_SIZE];
|
2006-10-04 17:01:36 +00:00
|
|
|
double dtemp;
|
2005-04-18 18:42:29 +00:00
|
|
|
|
2006-10-31 17:14:03 +00:00
|
|
|
defaults();
|
2003-11-04 22:22:06 +00:00
|
|
|
|
2008-02-03 21:46:30 +00:00
|
|
|
if (parse_double(buf, "<mod_time>", mod_time)) {
|
|
|
|
// mod_time is outside of venue
|
|
|
|
if (mod_time > dtime()) mod_time = dtime();
|
|
|
|
}
|
2004-03-31 06:07:17 +00:00
|
|
|
extract_venue(buf, venue, buf2);
|
|
|
|
parse_double(buf2, "<disk_max_used_gb>", disk_max_used_gb);
|
|
|
|
parse_double(buf2, "<disk_max_used_pct>", disk_max_used_pct);
|
|
|
|
parse_double(buf2, "<disk_min_free_gb>", disk_min_free_gb);
|
2005-04-18 18:42:29 +00:00
|
|
|
parse_double(buf2, "<work_buf_min_days>", work_buf_min_days);
|
2006-10-04 17:01:36 +00:00
|
|
|
if (parse_double(buf2, "<ram_max_used_busy_pct>", dtemp)) {
|
|
|
|
ram_max_used_busy_frac = dtemp/100.;
|
|
|
|
}
|
|
|
|
if (parse_double(buf2, "<ram_max_used_idle_pct>", dtemp)) {
|
|
|
|
ram_max_used_idle_frac = dtemp/100.;
|
|
|
|
}
|
2008-03-27 18:25:29 +00:00
|
|
|
parse_double(buf2, "<max_ncpus_pct>", max_ncpus_pct);
|
2006-10-06 18:52:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GLOBAL_PREFS::defaults() {
|
|
|
|
memset(this, 0, sizeof(GLOBAL_PREFS));
|
2003-11-04 22:22:06 +00:00
|
|
|
}
|
2004-09-13 18:05:54 +00:00
|
|
|
|
|
|
|
void GUI_URLS::init() {
|
|
|
|
text = 0;
|
2009-05-07 13:54:51 +00:00
|
|
|
read_file_malloc(config.project_path("gui_urls.xml"), text);
|
2004-09-13 18:05:54 +00:00
|
|
|
}
|
|
|
|
|
2004-09-27 19:44:40 +00:00
|
|
|
void GUI_URLS::get_gui_urls(USER& user, HOST& host, TEAM& team, char* buf) {
|
2004-09-13 18:05:54 +00:00
|
|
|
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);
|
2004-09-27 19:44:40 +00:00
|
|
|
if (user.teamid) {
|
|
|
|
sprintf(teamid, "%d", team.id);
|
|
|
|
} else {
|
|
|
|
strcpy(teamid, "0");
|
2004-09-27 20:09:49 +00:00
|
|
|
while (remove_element(buf, "<ifteam>", "</ifteam>")) {
|
2004-09-27 19:44:40 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2004-09-13 18:05:54 +00:00
|
|
|
while (1) {
|
|
|
|
found = false;
|
|
|
|
found |= str_replace(buf, "<userid/>", userid);
|
2004-09-27 19:44:40 +00:00
|
|
|
found |= str_replace(buf, "<user_name/>", user.name);
|
2004-09-13 18:05:54 +00:00
|
|
|
found |= str_replace(buf, "<hostid/>", hostid);
|
|
|
|
found |= str_replace(buf, "<teamid/>", teamid);
|
2004-09-27 19:44:40 +00:00
|
|
|
found |= str_replace(buf, "<team_name/>", team.name);
|
2004-09-13 18:05:54 +00:00
|
|
|
found |= str_replace(buf, "<authenticator/>", user.authenticator);
|
|
|
|
if (!found) break;
|
|
|
|
}
|
|
|
|
}
|
2004-12-08 00:40:19 +00:00
|
|
|
|
2006-06-26 22:58:24 +00:00
|
|
|
void PROJECT_FILES::init() {
|
|
|
|
text = 0;
|
2009-05-07 13:54:51 +00:00
|
|
|
read_file_malloc(config.project_path("project_files.xml"), text);
|
2006-06-26 22:58:24 +00:00
|
|
|
}
|
|
|
|
|
2005-01-02 18:29:53 +00:00
|
|
|
const char *BOINC_RCSID_ea659117b3 = "$Id$";
|