EIO_Status CConnTest::DispatcherOkay(string* reason) { SConnNetInfo* net_info = ConnNetInfo_Create(0, m_DebugPrintout); ConnNetInfo_SetupStandardArgs(net_info, kTest); PreCheck(eDispatcher, 0/*main*/, "Checking whether NCBI dispatcher is okay"); int okay = 0; SAuxData* auxdata = new SAuxData(m_Canceled, &okay); CConn_HttpStream http(net_info, kEmptyStr/*user_header*/, s_SvcHeader, auxdata, s_Adjust, s_Cleanup, 0/*flags*/, m_Timeout); http.SetCanceledCallback(m_Canceled); char buf[1024]; http.read(buf, sizeof(buf)); CTempString str(buf, (size_t) http.gcount()); EIO_Status status = ConnStatus (okay != 1 || NStr::FindNoCase(str, "NCBI Dispatcher Test Page") == NPOS || NStr::FindNoCase(str, "Welcome") == NPOS, &http); string temp; if (status == eIO_Interrupt) temp = kCanceled; else if (status == eIO_Success) temp = "OK"; else { if (status != eIO_Timeout) { if (okay) { temp = "Make sure there are no stray [CONN]{HOST|PORT|PATH}" " settings in the way in your configuration\n"; } if (okay == 1) { temp += "Service response was not recognized; please contact " + HELP_EMAIL + '\n'; } } else temp += x_TimeoutMsg(); if (!(okay & 1)) { temp += "Check with your network administrator that your network" " neither filters out nor blocks non-standard HTTP headers\n"; } } PostCheck(eDispatcher, 0/*main*/, status, temp); ConnNetInfo_Destroy(net_info); if (reason) reason->swap(temp); return status; }
EIO_Status CConnTest::ServiceOkay(string* reason) { static const char kService[] = "bounce"; SConnNetInfo* net_info = ConnNetInfo_Create(kService, m_DebugPrintout); if (net_info) net_info->lb_disable = 1/*no local LB to use even if available*/; PreCheck(eStatelessService, 0/*main*/, "Checking whether NCBI services operational"); CConn_ServiceStream svc(kService, fSERV_Stateless, net_info, 0/*extra*/, m_Timeout); svc.SetCanceledCallback(m_Canceled); svc << kTest << NcbiEndl; string temp; svc >> temp; bool responded = temp.size() > 0 ? true : false; EIO_Status status = ConnStatus(NStr::Compare(temp, kTest) != 0, &svc); if (status == eIO_Interrupt) temp = kCanceled; else if (status == eIO_Success) temp = "OK"; else { char* str = net_info ? SERV_ServiceName(kService) : 0; if (str && NStr::CompareNocase(str, kService) == 0) { free(str); str = 0; } SERV_ITER iter = SERV_OpenSimple(kService); if (!iter || !SERV_GetNextInfo(iter)) { // Service not found SERV_Close(iter); iter = SERV_OpenSimple(kTest); if (!iter || !SERV_GetNextInfo(iter) || NStr::CompareNocase(SERV_MapperName(iter), "DISPD") != 0) { // Make sure there will be a mapper error printed SERV_Close(iter); temp.clear(); iter = 0; } else { // kTest service can be located but not kService temp = str ? "Substituted service" : "Service"; temp += " cannot be located"; } } else { temp = responded ? "Unrecognized" : "No"; temp += " response from "; temp += str ? "substituted service" : "service"; } if (!temp.empty()) { if (str) { temp += "; please remove ["; string upper(kService); temp += NStr::ToUpper(upper); temp += "]CONN_SERVICE_NAME=\""; temp += str; temp += "\" from your configuration\n"; } else if (status != eIO_Timeout || m_Timeout > kTimeout) temp += "; please contact " + HELP_EMAIL + '\n'; } if (status != eIO_Timeout) { const char* mapper = SERV_MapperName(iter); if (!mapper || NStr::CompareNocase(mapper, "DISPD") != 0) { temp += "Network dispatcher is not enabled as a service" " locator; please review your configuration to purge any" " occurrences of [CONN]DISPD_DISABLE off your settings\n"; } } else temp += x_TimeoutMsg(); SERV_Close(iter); if (str) free(str); } PostCheck(eStatelessService, 0/*main*/, status, temp); ConnNetInfo_Destroy(net_info); if (reason) reason->swap(temp); return status; }
EIO_Status CConnTest::ExtraCheckOnFailure(void) { static const STimeout kTimeout = { 5, 0 }; static const STimeout kTimeSlice = { 0, 100000 }; static const struct { const char* host; const char* vhost; } kTests[] = { // 0. NCBI default { "", 0 }, // NCBI // 1. External server(s) { "www.google.com", 0 }, // NB: Google's public DNS (also @8.8.8.8), responds at :80 as well { "8.8.4.4", "www.google.com" }, // 2. NCBI servers, explicitly { "www.be-md.ncbi.nlm.nih.gov", "www.ncbi.nlm.nih.gov" }, // NCBI main { "www.st-va.ncbi.nlm.nih.gov", "www.ncbi.nlm.nih.gov" }, // NCBI colo { "130.14.29.110", "www.ncbi.nlm.nih.gov" }, // NCBI main { "165.112.7.20", "www.ncbi.nlm.nih.gov" } // NCBI colo }; m_CheckPoint.clear(); PreCheck(eNone, 0/*main*/, "Failback HTTP access check"); SConnNetInfo* net_info = ConnNetInfo_Create(0, eDebugPrintout_Data); if (!net_info) { PostCheck(eNone, 0/*main*/, eIO_Unknown, "Cannot create network info structure"); return eIO_Unknown; } net_info->req_method = eReqMethod_Head; net_info->timeout = &kTimeout; net_info->max_try = 0; m_Timeout = 0; CDeadline deadline(kTimeout.sec, kTimeout.usec * 1000); time_t sec; unsigned int nanosec; deadline.GetExpirationTime(&sec, &nanosec); ::sprintf(net_info->path, "/NcbiTest%08lX%08lX", (unsigned long) sec, (unsigned long) nanosec); vector< AutoPtr<CConn_HttpStream> > http; for (size_t n = 0; n < sizeof(kTests) / sizeof(kTests[0]); ++n) { char user_header[80]; _ASSERT(::strlen(kTests[n].host) < sizeof(net_info->host) - 1); if (kTests[n].host[0]) ::strcpy(net_info->host, kTests[n].host); if (kTests[n].vhost) { _ASSERT(::strlen(kTests[n].vhost) + 6 < sizeof(user_header) - 1); ::sprintf(user_header, "Host: %s", kTests[n].vhost); } else *user_header = '\0'; SAuxData* auxdata = new SAuxData(m_Canceled, 0); http.push_back(new CConn_HttpStream(net_info, user_header, s_AnyHeader, auxdata, s_Adjust, s_Cleanup)); http.back()->SetCanceledCallback(m_Canceled); } EIO_Status status = eIO_Success; do { if (!http.size()) break; ERASE_ITERATE(vector< AutoPtr<CConn_HttpStream> >, h, http) { CONN conn = (*h)->GetCONN(); if (!conn) { VECTOR_ERASE(h, http); if (status == eIO_Success) status = eIO_Unknown; continue; } EIO_Status readst = CONN_Wait(conn, eIO_Read, &kTimeSlice); if (readst > eIO_Timeout) { if (readst == eIO_Interrupt) { status = eIO_Interrupt; break; } if (status < readst && (*h)->GetStatusCode() != 404) status = readst; VECTOR_ERASE(h, http); continue; } } } while (status != eIO_Interrupt && !deadline.IsExpired()); if (status == eIO_Success && http.size()) status = eIO_Timeout; PostCheck(eNone, 0/*main*/, status, kEmptyStr); return status; }
EIO_Status CConnTest::HttpOkay(string* reason) { SConnNetInfo* net_info = ConnNetInfo_Create(0, m_DebugPrintout); if (net_info) { if (net_info->http_proxy_host[0] && net_info->http_proxy_port) m_HttpProxy = true; // Make sure there are no extras ConnNetInfo_SetUserHeader(net_info, 0); net_info->args[0] = '\0'; } PreCheck(eHttp, 0/*main*/, "Checking whether NCBI is HTTP accessible"); string host(net_info ? net_info->host : DEF_CONN_HOST); string port(net_info && net_info->port ? ':' + NStr::UIntToString(net_info->port) : kEmptyStr); SAuxData* auxdata = new SAuxData(m_Canceled, 0); CConn_HttpStream http("/Service/index.html", net_info, kEmptyStr/*user_header*/, s_GoodHeader, auxdata, s_Adjust, s_Cleanup, 0/*flags*/, m_Timeout); http.SetCanceledCallback(m_Canceled); string temp; http >> temp; EIO_Status status = ConnStatus(temp.empty(), &http); if (status == eIO_Interrupt) temp = kCanceled; else if (status == eIO_Success) temp = "OK"; else { if (status == eIO_Timeout) temp = x_TimeoutMsg(); else temp.clear(); if (NStr::CompareNocase(host, DEF_CONN_HOST) != 0 || !port.empty()) { int n = 0; temp += "Make sure that "; if (host != DEF_CONN_HOST) { n++; temp += "[CONN]HOST=\""; temp += host; temp += port.empty() ? "\"" : "\" and "; } if (!port.empty()) { n++; temp += "[CONN]PORT=\""; temp += port.c_str() + 1; temp += '"'; } _ASSERT(n); temp += n > 1 ? " are" : " is"; temp += " redefined correctly\n"; } if (m_HttpProxy) { temp += "Make sure that the HTTP proxy server \'"; temp += net_info->http_proxy_host; temp += ':'; temp += NStr::UIntToString(net_info->http_proxy_port); temp += "' specified with [CONN]HTTP_PROXY_{HOST|PORT} is correct"; } else { if (net_info->http_proxy_host[0] || net_info->http_proxy_port) { temp += "Note that your HTTP proxy seems to have been" " specified only partially, and thus cannot be used: the "; if (net_info->http_proxy_port) { temp += "host part is missing (for port :" + NStr::UIntToString(net_info->http_proxy_port); } else { temp += "port part is missing (for host \'" + string(net_info->http_proxy_host) + '\''; } temp += ")\n"; } temp += "If your network access requires the use of an HTTP proxy" " server, please contact your network administrator and set" " [CONN]HTTP_PROXY_{HOST|PORT} (both must be set) in your" " configuration accordingly"; } temp += "; and if your proxy server requires authorization, please" " check that appropriate [CONN]HTTP_PROXY_{USER|PASS} have been" " set\n"; if (net_info && (*net_info->user || *net_info->pass)) { temp += "Make sure there are no stray [CONN]{USER|PASS} that" " appear in your configuration -- NCBI services neither" " require nor use them\n"; } } PostCheck(eHttp, 0/*main*/, status, temp); ConnNetInfo_Destroy(net_info); if (reason) reason->swap(temp); return status; }
EIO_Status CConnTest::GetFWConnections(string* reason) { SConnNetInfo* net_info = ConnNetInfo_Create(0); if (net_info) { const char* user_header; net_info->req_method = eReqMethod_Post; if (net_info->firewall) { user_header = "NCBI-RELAY: FALSE"; m_Firewall = true; } else user_header = "NCBI-RELAY: TRUE"; if (net_info->stateless) m_Stateless = true; ConnNetInfo_OverrideUserHeader(net_info, user_header); ConnNetInfo_SetupStandardArgs(net_info, 0/*w/o service*/); } string temp(m_Firewall ? "FIREWALL" : "RELAY (legacy)"); temp += " connection mode has been detected for stateful services\n"; if (m_Firewall) { temp += "This mode requires your firewall to be configured in such a" " way that it allows outbound connections to the port range [" STRINGIFY(CONN_FWD_PORT_MIN) ".." STRINGIFY(CONN_FWD_PORT_MAX) "] (inclusive) at the two fixed NCBI hosts, 130.14.29.112" " and 165.112.7.12\n" "To set that up correctly, please have your network administrator" " read the following (if they have not already done so):" " " NCBI_FW_URL "\n"; } else { temp += "This is an obsolescent mode that requires keeping a wide port" " range [4444..4544] (inclusive) open to let through connections" " to any NCBI host (130.14.2x.xxx/165.112.xx.xxx) -- this mode was" " designed for unrestricted networks when firewall port blocking" " was not an issue\n"; } if (m_Firewall) { _ASSERT(net_info); switch (net_info->firewall) { case eFWMode_Adaptive: temp += "There are also fallback connection ports such as 22 and" " 443 at 130.14.29.112. They will be used if connections to" " the ports in the range described above have failed\n"; break; case eFWMode_Firewall: temp += "Also, your configuration explicitly forbids to use any" " fallback firewall ports that may exist to improve network" " connectivity\n"; break; case eFWMode_Fallback: temp += "However, your configuration explicitly requests that only" " fallback firewall ports (if any exist) are to be used for" " connections: this also implies that no conventional ports" " from the range above will be used\n"; break; default: temp += "Internal program error, please report!\n"; _ASSERT(0); break; } } else { temp += "This mode may not be reliable if your site has a restrictive" " firewall imposing fine-grained control over which hosts and" " ports the outbound connections are allowed to use\n"; } if (m_HttpProxy) { temp += "Connections to the aforementioned ports will be made via an" " HTTP proxy at '"; temp += net_info->http_proxy_host; temp += ':'; temp += NStr::UIntToString(net_info->http_proxy_port); temp += "'"; if (net_info && net_info->http_proxy_leak) { temp += ". If that is unsuccessful, a link bypassing the proxy" " will then be attempted"; } if (m_Firewall && *net_info->proxy_host) temp += ". In addition, your"; } if (m_Firewall && *net_info->proxy_host) { if (!m_HttpProxy) temp += "Your"; temp += " configuration specifies that instead of connecting directly" " to NCBI addresses, a forwarding non-transparent proxy host '"; temp += net_info->proxy_host; temp += "' should be used for all links"; if (m_HttpProxy) temp += " (including those originating from the HTTP proxy)"; } temp += '\n'; PreCheck(eFirewallConnPoints, 0/*main*/, temp); PreCheck(eFirewallConnPoints, 1/*sub*/, "Obtaining current NCBI " + string(m_Firewall ? "firewall settings" : "service entries")); EIO_Status status = x_GetFirewallConfiguration(net_info); if (status == eIO_Interrupt) temp = kCanceled; else if (status == eIO_Success) { if (!m_Fwd.empty() || (!m_FwdFB.empty() && m_Firewall && net_info->firewall == eFWMode_Fallback)) { temp = "OK: "; if (!m_Fwd.empty()) { stable_sort(m_Fwd.begin(), m_Fwd.end()); temp += NStr::UInt8ToString(m_Fwd.size()); } if (!m_FwdFB.empty()) { stable_sort(m_FwdFB.begin(), m_FwdFB.end()); if (!m_Fwd.empty()) temp += " + "; temp += NStr::UInt8ToString(m_FwdFB.size()); } temp += m_Fwd.size() + m_FwdFB.size() == 1 ? " port" : " ports"; } else { status = eIO_Unknown; temp = "No connection ports found, please contact " + HELP_EMAIL; } } else if (status == eIO_Timeout) { temp = x_TimeoutMsg(); if (m_Timeout > kTimeout) temp += "You may want to contact " + HELP_EMAIL; } else temp = "Please contact " + HELP_EMAIL; PostCheck(eFirewallConnPoints, 1/*sub*/, status, temp); ConnNetInfo_Destroy(net_info); if (status == eIO_Success) { PreCheck(eFirewallConnPoints, 2/*sub*/, "Verifying configuration for consistency"); bool firewall = true; // Check primary ports only ITERATE(vector<CConnTest::CFWConnPoint>, cp, m_Fwd) { if (cp->port < CONN_FWD_PORT_MIN || CONN_FWD_PORT_MAX < cp->port) firewall = false; if (cp->status != eIO_Success) { status = cp->status; temp = CSocketAPI::HostPortToString(cp->host, cp->port); temp += " is not operational, please contact " + HELP_EMAIL; break; } } if (status == eIO_Success) { if (!m_Firewall && !m_FwdFB.empty()) { status = eIO_Unknown; temp = "Fallback ports found in non-firewall mode, please" " contact " + HELP_EMAIL; } else if (m_Firewall != firewall) { status = eIO_Unknown; temp = "Firewall "; temp += firewall ? "wrongly" : "not"; temp += " acknowledged, please contact " + HELP_EMAIL; } else temp.resize(2); } PostCheck(eFirewallConnPoints, 2/*sub*/, status, temp); }