diff --git a/checkin_notes b/checkin_notes index 6a078ee68e..9ef1405d36 100755 --- a/checkin_notes +++ b/checkin_notes @@ -1487,3 +1487,20 @@ Rom 6 Feb 2006 client/ client_state.h main.C + +David 6 Feb 2005 + - Core client: when we switched to Curl, we lost the code + that sets gstate.want_network_flag when name resolution fails. + I restored this to the Curl code. + + - The above is a kludge for detecting lack of physical connection. + But name resolution can fail for reasons other than lack of + physical connection; e.g. hostname might be bad. + So if get name resolution failure, + try to contact a reference web site, + and only if that also fails set want_network_flag. + + client/ + acct_setup.C + client_state.C,h + net_xfer_curl.C diff --git a/client/acct_setup.C b/client/acct_setup.C index 7606fea32b..6b1c2a1a72 100644 --- a/client/acct_setup.C +++ b/client/acct_setup.C @@ -188,6 +188,15 @@ int LOOKUP_WEBSITE_OP::do_rpc(string& url) { void LOOKUP_WEBSITE_OP::handle_reply(int http_op_retval) { error_num = http_op_retval; + + // if we couldn't contact a reference web site, + // we can assume there's a problem that requires user attention + // (usually no physical network connection). + // Set a flag that will signal the Manager to that effect + // + if (error_num) { + gstate.want_network_flag = true; + } } int GET_CURRENT_VERSION_OP::do_rpc() { diff --git a/client/client_state.C b/client/client_state.C index 0a4d6ecd0c..f301a5d297 100644 --- a/client/client_state.C +++ b/client/client_state.C @@ -1393,15 +1393,15 @@ int CLIENT_STATE::detach_project(PROJECT* project) { return 0; } -// Return true if the core client wants a network connection. -// Don't return false if we've actually been using the network -// in the last 10 seconds (so that polling mechanisms -// have a change to trigger) +// Return true if the core client wants a network connection, +// or if we've been using the network in the last 10 seconds +// (so that polling mechanisms have a change to trigger) // bool CLIENT_STATE::want_network() { static double last_true_return=0; if (http_ops->nops()) goto return_true; + // if we're using network, return true if (network_suspended) goto return_false; if (want_network_flag) goto return_true; if (active_tasks.want_network()) goto return_true; diff --git a/client/client_state.h b/client/client_state.h index 9d7d69c81d..31c95b0556 100644 --- a/client/client_state.h +++ b/client/client_state.h @@ -241,7 +241,19 @@ public: int report_result_error(RESULT&, const char *format, ...); int reset_project(PROJECT*); bool want_network_flag; + // client wants to do network comm and no physical connection exists. + // Initially false; set whenever a Curl operation + // returns CURLE_COULDNT_RESOLVE_HOST; + // cleared whenever a Curl operation returns anything else + // TODO: is this the best way to do this? + // won't it set this flag when user enters URL with + // non-existent URL, e.g.? + // bool have_sporadic_connection; + // we have a network connection, but it's likely to go away soon, + // so do as much network comm as possible + // (e.g. report completed results) + // bool want_network(); void network_available(); bool no_gui_rpc; diff --git a/client/net_xfer_curl.C b/client/net_xfer_curl.C index 26ab56c317..dcd27796c0 100644 --- a/client/net_xfer_curl.C +++ b/client/net_xfer_curl.C @@ -66,12 +66,14 @@ using std::vector; // #define NET_XFER_TIMEOUT 600 -CURLM* g_curlMulti = NULL; // global curl for this module, can handle http & https +CURLM* g_curlMulti = NULL; // the file descriptor sets need to be global so libcurl has access always +// fd_set read_fds, write_fds, error_fds; -// call these once at the start of the program and once at the end (init & cleanup of course) +// call these once at the start of the program and once at the end +// int curl_init() { curl_global_init(CURL_GLOBAL_ALL); g_curlMulti = curl_multi_init(); @@ -95,11 +97,11 @@ void NET_XFER::reset() { is_connected = false; want_download = false; want_upload = false; - do_file_io = true; // CMC Note: should I default to true, i.e. this does all i/o? + do_file_io = true; io_done = false; fileIn = NULL; fileOut = NULL; - io_ready = true; // don't allow higher levels to do i/o? + io_ready = true; error = 0; file_read_buf_offset = 0; file_read_buf_len = 0; @@ -125,7 +127,8 @@ NET_XFER::~NET_XFER() { } void NET_XFER::close_socket() { - // CMC: this just cleans up the curlEasy, and "spoofs" the old close_socket + // this cleans up the curlEasy, and "spoofs" the old close_socket + // if (pcurlList) { curl_slist_free_all(pcurlList); pcurlList = NULL; @@ -195,9 +198,6 @@ NET_XFER_SET::NET_XFER_SET() { bytes_down = 0; } -// Connect to a server, -// and if successful insert the NET_XFER object into the set -// int NET_XFER_SET::insert(NET_XFER* nxp) { net_xfers.push_back(nxp); return 0; @@ -223,7 +223,9 @@ int NET_XFER_SET::remove(NET_XFER* nxp) { void NET_XFER_SET::get_fdset(FDSET_GROUP& fg) { CURLMcode curlMErr; - curlMErr = curl_multi_fdset(g_curlMulti, &fg.read_fds, &fg.write_fds, &fg.exc_fds, &fg.max_fd); + curlMErr = curl_multi_fdset( + g_curlMulti, &fg.read_fds, &fg.write_fds, &fg.exc_fds, &fg.max_fd + ); //printf("curl msfd %d %d\n", curlMErr, fg.max_fd); } @@ -265,6 +267,7 @@ void NET_XFER_SET::got_select(FDSET_GROUP&, double timeout) { } // read messages from curl that may have come in from the above loop + // while ((pcurlMsg = curl_multi_info_read(g_curlMulti, &iNumMsg))) { // if we have a msg, then somebody finished // can check also with pcurlMsg->msg == CURLMSG_DONE @@ -304,9 +307,12 @@ void NET_XFER_SET::got_select(FDSET_GROUP&, double timeout) { } // the op is done if curl_multi_msg_read gave us a msg for this http_op + // nxf->http_op_state = HTTP_STATE_DONE; - // added a more useful error string (just pass the curl string up for now) + // added a more useful error string + // (just pass the curl string up for now) + // nxf->CurlResult = pcurlMsg->data.result; safe_strcpy(nxf->strCurlResult, curl_easy_strerror(nxf->CurlResult)); @@ -334,6 +340,16 @@ void NET_XFER_SET::got_select(FDSET_GROUP&, double timeout) { nxf->http_op_retval = nxf->response; } } else { + // If we couldn't resolve hostname, + // it could be because there's no physical network connection. + // Find out for sure by trying to contact google + // + if (nxf->CurlResult == CURLE_COULDNT_RESOLVE_HOST) { + std::string url = "http://www.google.com"; + gstate.lookup_website_op.do_rpc(url); + } else { + gstate.want_network_flag = false; + } msg_printf(0, MSG_ERROR, "HTTP error: %s", nxf->strCurlResult); nxf->http_op_retval = ERR_HTTP_ERROR; } @@ -347,11 +363,12 @@ void NET_XFER_SET::got_select(FDSET_GROUP&, double timeout) { file_size(nxf->outfile, dSize); nxf->fileOut = boinc_fopen(nxf->outfile, "rb"); if (!nxf->fileOut) { // ack, can't open back up! - nxf->response = 1; // flag as a bad response for a possible retry later + nxf->response = 1; + // flag as a bad response for a possible retry later } else { fseek(nxf->fileOut, 0, SEEK_SET); // CMC Note: req1 is a pointer to "header" which is 4096 - memset(nxf->req1, 0x00, 4096); + memset(nxf->req1, 0, 4096); fread(nxf->req1, 1, (size_t) dSize, nxf->fileOut); } }