diff --git a/checkin_notes b/checkin_notes index b4a1e7b42b..20a746447a 100644 --- a/checkin_notes +++ b/checkin_notes @@ -6241,3 +6241,23 @@ Rom 19 Sept 2011 / configure.ac version.h + +David 19 Sept 2011 + - client: in handling the acct_mgr GUI RPC, + don't start the RPC directly; + that might fail if CLIENT_STATE::gui_http is busy. + Instead, set a timer field. + - client: structure ACCT_MGR_OP the same as other GUI_HTTP_OP variants + - client: clarify the comments on GUI_HTTP and GUI_HTTP_OP + + Note: GUI_HTTP and GUI_HTTP_OP are misnomers; they refer to + any HTTP op other than scheduler requests and file transfers. + Should change the name, maybe to CLIENT_HTTP* + + client/ + client_state.cpp + gui_rpc_server.cpp + gui_rpc_server_ops.cpp + gui_http.cpp,h + acct_mgr.cpp,h + cs_trickle.h diff --git a/client/acct_mgr.cpp b/client/acct_mgr.cpp index 4a685d1602..2fdb6a412e 100644 --- a/client/acct_mgr.cpp +++ b/client/acct_mgr.cpp @@ -40,10 +40,6 @@ static const char *run_mode_name[] = {"", "always", "auto", "never"}; -ACCT_MGR_OP::ACCT_MGR_OP() { - global_prefs_xml = 0; -} - // do an account manager RPC; // if URL is null, detach from current account manager // @@ -199,7 +195,7 @@ int ACCT_MGR_OP::do_rpc( fprintf(f, "\n"); fclose(f); sprintf(buf, "%srpc.php", url); - retval = gstate.gui_http.do_rpc_post( + retval = gui_http->do_rpc_post( this, buf, ACCT_MGR_REQUEST_FILENAME, ACCT_MGR_REPLY_FILENAME, true ); if (retval) { @@ -812,7 +808,7 @@ int ACCT_MGR_INFO::init() { bool ACCT_MGR_INFO::poll() { if (!using_am()) return false; - if (gstate.gui_http.is_busy()) return false; + if (gstate.acct_mgr_op.gui_http->is_busy()) return false; if (gstate.now > next_rpc_time) { diff --git a/client/acct_mgr.h b/client/acct_mgr.h index c0043271b6..eb25270af7 100644 --- a/client/acct_mgr.h +++ b/client/acct_mgr.h @@ -131,7 +131,11 @@ struct ACCT_MGR_OP: public GUI_HTTP_OP { int parse(FILE*); virtual void handle_reply(int http_op_retval); - ACCT_MGR_OP(); + ACCT_MGR_OP(GUI_HTTP* p) { + gui_http = p; + global_prefs_xml = 0; + error_num = BOINC_SUCCESS; + } virtual ~ACCT_MGR_OP(){} }; diff --git a/client/client_state.cpp b/client/client_state.cpp index db285a5da1..74c5ccce14 100644 --- a/client/client_state.cpp +++ b/client/client_state.cpp @@ -67,7 +67,8 @@ COPROCS coprocs; CLIENT_STATE::CLIENT_STATE() : lookup_website_op(&gui_http), get_current_version_op(&gui_http), - get_project_list_op(&gui_http) + get_project_list_op(&gui_http), + acct_mgr_op(&gui_http) { http_ops = new HTTP_OP_SET(); file_xfers = new FILE_XFER_SET(http_ops); @@ -242,7 +243,7 @@ static void check_too_large_jobs() { } } -// Sometime has failed N times. +// Something has failed N times. // Calculate an exponential backoff between MIN and MAX // double calculate_exponential_backoff(int n, double MIN, double MAX) { @@ -1720,6 +1721,8 @@ int CLIENT_STATE::reset_project(PROJECT* project, bool detaching) { msg_printf(project, MSG_INFO, "Resetting project"); active_tasks.abort_project(project); + // stop and remove file transfers + // for (i=0; ipers_file_xfers.size(); i++) { pxp = pers_file_xfers->pers_file_xfers[i]; if (pxp->fip->project == project) { @@ -1737,6 +1740,10 @@ int CLIENT_STATE::reset_project(PROJECT* project, bool detaching) { // scheduler_op->abort(project); + // abort other HTTP operations + // + //http_ops.abort_project_ops(project); + // mark results as server-acked. // This will cause garbage_collect to delete them, // and in turn their WUs will be deleted diff --git a/client/cs_trickle.h b/client/cs_trickle.h new file mode 100644 index 0000000000..a7b36962b3 --- /dev/null +++ b/client/cs_trickle.h @@ -0,0 +1,31 @@ +// This file is part of BOINC. +// http://boinc.berkeley.edu +// Copyright (C) 2011 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 . + +// support for replicated trickles + +struct TRICKLE_UP_OP: public GUI_HTTP_OP { + std::string reply; + int error_num; + + TRICKLE_UP_OP(GUI_HTTP* p) { + error_num = BOINC_SUCCESS; + gui_http = p; + } + virtual ~TRICKLE_UP_OP(){} + int do_rpc(std::string url); + virtual void handle_reply(int http_op_retval); +}; diff --git a/client/gui_http.cpp b/client/gui_http.cpp index 538ac52b0c..5b2e74f9ec 100644 --- a/client/gui_http.cpp +++ b/client/gui_http.cpp @@ -87,4 +87,3 @@ bool GUI_HTTP::poll() { } return true; } - diff --git a/client/gui_http.h b/client/gui_http.h index ec55789554..0e1e9fd1a0 100644 --- a/client/gui_http.h +++ b/client/gui_http.h @@ -20,9 +20,31 @@ // A high-level interface for client-initiated HTTP requests. -// GUI_HTTP represents a "channel" for doing HTTP ops. -// There's one of these for each GUI RPC connection, -// and one for the client itself (so the name is a misnomer). +// GUI_HTTP represents a "channel" for doing a sequence of HTTP ops, +// possibly to different servers. +// There's no queuing: +// if you call do_rpc() while an op is in progress, you get an error. +// You must call poll() periodically to make things work. +// +// GUI_HTTP_OP is base class for various types of ops. +// Each instance is tied to a particular GUI_HTTP. +// When the op is completed or failed, its handle_reply() is called +// +// The set of GUI_HTTPs: +// - one for each GUI RPC connection +// GUI_HTTP_OPs that use this channel: +// GUI_RPC_CONN::get_project_config_op +// GUI_RPC_CONN::lookup_account_op +// GUI_RPC_CONN::create_account_op +// +// - one for the client itself +// GUI_HTTP_OPs that use this channel: +// CLIENT_STATE::lookup_website_op +// CLIENT_STATE::get_current_version +// CLIENT_STATE::get_project_list +// CLIENT_STATE::acct_mgr_op +// These are all "best effort": if an op is requested while +// another is in progress, it's OK; it will be retried later. #include "http_curl.h" diff --git a/client/gui_rpc_server.cpp b/client/gui_rpc_server.cpp index b1dec7bed9..844f2d0a88 100644 --- a/client/gui_rpc_server.cpp +++ b/client/gui_rpc_server.cpp @@ -54,12 +54,13 @@ #endif #endif -#include "str_util.h" -#include "util.h" #include "error_numbers.h" -#include "network.h" #include "filesys.h" #include "md5_file.h" +#include "network.h" +#include "str_util.h" +#include "thread.h" +#include "util.h" #include "file_names.h" #include "client_msgs.h" @@ -508,3 +509,11 @@ bool GUI_RPC_CONN_SET::quits_sent() { return true; } +void* gui_rpc_handler(void* p) { + THREAD& thread = *((THREAD*)p); + GUI_RPC_CONN& grc = *((GUI_RPC_CONN*)thread.arg); + while (1) { + int retval = grc.handle_rpc(); + } + return NULL; +} diff --git a/client/gui_rpc_server_ops.cpp b/client/gui_rpc_server_ops.cpp index 0694f452eb..761183a9c4 100644 --- a/client/gui_rpc_server_ops.cpp +++ b/client/gui_rpc_server_ops.cpp @@ -899,7 +899,7 @@ static void handle_acct_mgr_rpc(GUI_RPC_CONN& grc) { if (bad_arg) { grc.mfout.printf("bad arg\n"); } else { - gstate.acct_mgr_op.do_rpc(url, name, password_hash, true); + gstate.acct_mgr_info.next_rpc_time = gstate.now; grc.mfout.printf("\n"); } } @@ -1214,6 +1214,8 @@ GUI_RPC gui_rpcs[] = { GUI_RPC("retry_file_transfer", handle_retry_file_transfer, true, true, false), }; +// return nonzero only if we need to close the connection +// static int handle_rpc_aux(GUI_RPC_CONN& grc) { int retval = 0; grc.mfin.init_buf_read(grc.request_msg); @@ -1242,6 +1244,8 @@ static int handle_rpc_aux(GUI_RPC_CONN& grc) { return 0; } +// return nonzero only if we need to close the connection +// int GUI_RPC_CONN::handle_rpc() { int n, retval=0; char* p; @@ -1366,4 +1370,3 @@ int GUI_RPC_CONN::handle_rpc() { } return retval; } -