char* SERV_Print(SERV_ITER iter, SConnNetInfo* net_info, int/*bool*/ but_last) { static const char kClientRevision[] = "Client-Revision: %hu.%hu\r\n"; static const char kAcceptedServerTypes[] = "Accepted-Server-Types:"; static const char kUsedServerInfo[] = "Used-Server-Info: "; static const char kNcbiFWPorts[] = "NCBI-Firewall-Ports: "; static const char kServerCount[] = "Server-Count: "; static const char kPreference[] = "Preference: "; static const char kSkipInfo[] = "Skip-Info-%u: "; static const char kAffinity[] = "Affinity: "; char buffer[128], *str; size_t buflen, i; TSERV_Type t; BUF buf = 0; /* Put client version number */ buflen = sprintf(buffer, kClientRevision, SERV_CLIENT_REVISION_MAJOR, SERV_CLIENT_REVISION_MINOR); assert(buflen < sizeof(buffer)); if (!BUF_Write(&buf, buffer, buflen)) { BUF_Destroy(buf); return 0; } if (iter) { if (net_info && !net_info->http_referer && iter->op && iter->op->name) s_SetDefaultReferer(iter, net_info); /* Accepted server types */ buflen = sizeof(kAcceptedServerTypes) - 1; memcpy(buffer, kAcceptedServerTypes, buflen); for (t = 1; t; t <<= 1) { if (iter->type & t) { const char* name = SERV_TypeStr((ESERV_Type) t); size_t namelen = strlen(name); if (!namelen || buflen + 1 + namelen + 2 >= sizeof(buffer)) break; buffer[buflen++] = ' '; memcpy(buffer + buflen, name, namelen); buflen += namelen; } } if (buffer[buflen - 1] != ':') { strcpy(&buffer[buflen], "\r\n"); assert(strlen(buffer) == buflen+2 && buflen+2 < sizeof(buffer)); if (!BUF_Write(&buf, buffer, buflen + 2)) { BUF_Destroy(buf); return 0; } } if (iter->ismask || (iter->pref && (iter->host | iter->port))) { /* FIXME: To obsolete? */ /* How many server-infos for the dispatcher to send to us */ if (!BUF_Write(&buf, kServerCount, sizeof(kServerCount) - 1) || !BUF_Write(&buf, iter->ismask ? "10\r\n" : "ALL\r\n", iter->ismask ? 4 : 5)) { BUF_Destroy(buf); return 0; } } if (iter->type & fSERV_Firewall) { /* Firewall */ s_PrintFirewallPorts(buffer, sizeof(buffer), net_info); if (*buffer && (!BUF_Write(&buf, kNcbiFWPorts, sizeof(kNcbiFWPorts)-1) || !BUF_Write(&buf, buffer, strlen(buffer)) || !BUF_Write(&buf, "\r\n", 2))) { BUF_Destroy(buf); return 0; } } if (iter->pref && (iter->host | iter->port)) { /* Preference */ buflen = SOCK_HostPortToString(iter->host, iter->port, buffer, sizeof(buffer)); buflen += sprintf(buffer + buflen, " %.2lf%%\r\n", iter->pref*1e2); if (!BUF_Write(&buf, kPreference, sizeof(kPreference) - 1) || !BUF_Write(&buf, buffer, buflen)) { BUF_Destroy(buf); return 0; } } if (iter->arglen) { /* Affinity */ if (!BUF_Write(&buf, kAffinity, sizeof(kAffinity) - 1) || !BUF_Write(&buf, iter->arg, iter->arglen) || (iter->val && (!BUF_Write(&buf, "=", 1) || !BUF_Write(&buf, iter->val, iter->vallen))) || !BUF_Write(&buf, "\r\n", 2)) { BUF_Destroy(buf); return 0; } } /* Drop any outdated skip entries */ iter->time = (TNCBI_Time) time(0); s_SkipSkip(iter); /* Put all the rest into rejection list */ for (i = 0; i < iter->n_skip; i++) { /* NB: all skip infos are now kept with names (perhaps, empty) */ const char* name = SERV_NameOfInfo(iter->skip[i]); size_t namelen = name && *name ? strlen(name) : 0; if (!(str = SERV_WriteInfo(iter->skip[i]))) break; if (but_last && iter->last == iter->skip[i]) { buflen = sizeof(kUsedServerInfo) - 1; memcpy(buffer, kUsedServerInfo, buflen); } else buflen = sprintf(buffer, kSkipInfo, (unsigned) i + 1); assert(buflen < sizeof(buffer) - 1); if (!BUF_Write(&buf, buffer, buflen) || (namelen && !BUF_Write(&buf, name, namelen)) || (namelen && !BUF_Write(&buf, " ", 1)) || !BUF_Write(&buf, str, strlen(str)) || !BUF_Write(&buf, "\r\n", 2)) { free(str); break; } free(str); } if (i < iter->n_skip) { BUF_Destroy(buf); return 0; } } /* Ok then, we have filled the entire header, <CR><LF> terminated */ if ((buflen = BUF_Size(buf)) != 0) { if ((str = (char*) malloc(buflen + 1)) != 0) { if (BUF_Read(buf, str, buflen) != buflen) { free(str); str = 0; } else str[buflen] = '\0'; } } else str = 0; BUF_Destroy(buf); return str; }
/* One can define env.var. 'service'_CONN_HOST to reroute dispatching * information to particular dispatching host (instead of default). */ int main(int argc, const char* argv[]) { static const char kParameter[] = "test_parameter"; const char* service = argc > 1 ? argv[1] : "bounce"; SConnNetInfo* net_info; const SSERV_Info* info; const char* value; int n_found = 0; SERV_ITER iter; CORE_SetLOGFormatFlags(fLOG_None | fLOG_Level | fLOG_OmitNoteLevel | fLOG_DateTime); CORE_SetLOGFILE(stderr, 0/*false*/); if (argc > 2) { if (strcasecmp(argv[2],"heap") == 0 || strcasecmp(argv[2],"all") == 0){ HEAP_Options(eOff, eDefault); CORE_LOG(eLOG_Note, "Using slow heap access (w/checks)"); } if (strcasecmp(argv[2],"lbsm") == 0 || strcasecmp(argv[2],"all") == 0){ #ifdef NCBI_OS_MSWIN if (strcasecmp(argv[2],"lbsm") == 0) { CORE_LOG(eLOG_Warning, "Option \"lbsm\" has no useful effect on MS-Windows"); } #else LBSMD_FastHeapAccess(eOn); CORE_LOG(eLOG_Note, "Using live (faster) LBSM heap access"); #endif /*NCBI_OS_MSWIN*/ } if (strcasecmp(argv[2],"lbsm") != 0 && strcasecmp(argv[2],"heap") != 0 && strcasecmp(argv[2],"all") != 0) CORE_LOGF(eLOG_Fatal, ("Unknown option `%s'", argv[2])); } value = LBSMD_GetHostParameter(SERV_LOCALHOST, kParameter); CORE_LOGF(eLOG_Note, ("Querying host parameter `%s': %s%s%s", kParameter, "`" + !value, value ? value : "Not found", "'" + !value)); if (value) free((void*) value); CORE_LOGF(eLOG_Note, ("Looking for service `%s'", service)); net_info = ConnNetInfo_Create(service); CORE_LOG(eLOG_Trace, "Opening service mapper"); iter = SERV_OpenP(service, (fSERV_All & ~fSERV_Firewall) | (strpbrk(service, "?*") ? fSERV_Promiscuous : 0), SERV_LOCALHOST, 0/*port*/, 0.0/*preference*/, net_info, 0/*skip*/, 0/*n_skip*/, 0/*external*/, 0/*arg*/, 0/*val*/); ConnNetInfo_Destroy(net_info); if (iter) { HOST_INFO hinfo; CORE_LOGF(eLOG_Trace,("%s service mapper has been successfully opened", SERV_MapperName(iter))); while ((info = SERV_GetNextInfoEx(iter, &hinfo)) != 0) { char* info_str = SERV_WriteInfo(info); CORE_LOGF(eLOG_Note, ("Server #%d `%s' = %s", ++n_found, SERV_CurrentName(iter), info_str)); if (hinfo) { static const char kTimeFormat[] = "%m/%d/%y %H:%M:%S"; time_t t; char buf[80]; double array[5]; SHINFO_Params params; const char* e = HINFO_Environment(hinfo); const char* a = HINFO_AffinityArgument(hinfo); const char* v = HINFO_AffinityArgvalue(hinfo); CORE_LOG(eLOG_Note, " Host info available:"); CORE_LOGF(eLOG_Note, (" Number of CPUs: %d", HINFO_CpuCount(hinfo))); CORE_LOGF(eLOG_Note, (" Number of CPU units: %d @ %.0fMHz", HINFO_CpuUnits(hinfo), HINFO_CpuClock(hinfo))); CORE_LOGF(eLOG_Note, (" Number of tasks: %d", HINFO_TaskCount(hinfo))); if (HINFO_MachineParams(hinfo, ¶ms)) { CORE_LOGF(eLOG_Note, (" Arch: %d", params.arch)); CORE_LOGF(eLOG_Note, (" OSType: %d", params.ostype)); t = (time_t) params.bootup; strftime(buf, sizeof(buf), kTimeFormat, localtime(&t)); CORE_LOGF(eLOG_Note, (" Kernel: %hu.%hu.%hu @ %s", params.kernel.major, params.kernel.minor, params.kernel.patch, buf)); CORE_LOGF(eLOG_Note, (" Bits: %hu", params.bits)); CORE_LOGF(eLOG_Note, (" Page size: %lu", (unsigned long) params.pgsize)); t = (time_t) params.start; strftime(buf, sizeof(buf), kTimeFormat, localtime(&t)); CORE_LOGF(eLOG_Note, (" LBSMD: %hu.%hu.%hu @ %s", params.daemon.major, params.daemon.minor, params.daemon.patch, buf)); } else CORE_LOG (eLOG_Note, " Machine params: unavailable"); if (HINFO_Memusage(hinfo, array)) { CORE_LOGF(eLOG_Note, (" Total RAM: %.2fMB", array[0])); CORE_LOGF(eLOG_Note, (" Cache RAM: %.2fMB", array[1])); CORE_LOGF(eLOG_Note, (" Free RAM: %.2fMB", array[2])); CORE_LOGF(eLOG_Note, (" Total Swap: %.2fMB", array[3])); CORE_LOGF(eLOG_Note, (" Free Swap: %.2fMB", array[4])); } else CORE_LOG (eLOG_Note, " Memory usage: unavailable"); if (HINFO_LoadAverage(hinfo, array)) { CORE_LOGF(eLOG_Note, (" Load averages: %f, %f (BLAST)", array[0], array[1])); } else CORE_LOG (eLOG_Note, " Load averages: unavailable"); if (a) { assert(*a); CORE_LOGF(eLOG_Note, (" Affinity argument: %s", a)); } if (a && v) CORE_LOGF(eLOG_Note, (" Affinity value: %s%s%s", *v ? "" : "\"", v, *v ? "" : "\"")); CORE_LOGF(eLOG_Note, (" Host environment: %s%s%s", e? "\"": "", e? e: "NULL", e? "\"": "")); free(hinfo); } free(info_str); } CORE_LOG(eLOG_Trace, "Resetting service mapper"); SERV_Reset(iter); CORE_LOG(eLOG_Trace, "Service mapper has been reset"); if (n_found && !(info = SERV_GetNextInfo(iter))) CORE_LOG(eLOG_Fatal, "Service not found after reset"); CORE_LOG(eLOG_Trace, "Closing service mapper"); SERV_Close(iter); } if (n_found != 0) CORE_LOGF(eLOG_Note, ("%d server(s) found", n_found)); else CORE_LOG(eLOG_Fatal, "Requested service not found"); #if 0 {{ SConnNetInfo* net_info; net_info = ConnNetInfo_Create(service); iter = SERV_Open(service, fSERV_Http, SERV_LOCALHOST, net_info); ConnNetInfo_Destroy(net_info); }} if (iter != 0) { while ((info = SERV_GetNextInfo(iter)) != 0) { char* info_str = SERV_WriteInfo(info); CORE_LOGF(eLOG_Note, ("Service `%s' = %s", service, info_str)); free(info_str); n_found++; } SERV_Close(iter); } #endif CORE_LOG(eLOG_Note, "TEST completed successfully"); CORE_SetLOG(0); return 0; }
static int run_a_test(size_t test_idx, int live, const char *svc, const char *hdr, int check_for_match, int exp_err, const char *mock_body_in, int repop, int reset) { const SSERV_Info *info = NULL; SConnNetInfo *net_info; SERV_ITER iter; const char *mock_body = NULL; char *mock_body_adj = NULL; int n_matches_perfect = 0, n_matches_near = 0; int success = 0, errors = 0; int retval = -1; s_n_hits_got = 0; /* Adjust mock data for current time, if necessary. */ adjust_mock_times(mock_body_in, &mock_body_adj); mock_body = mock_body_adj ? mock_body_adj : mock_body_in; /* Select the HTTP data source (live or mock). */ s_results[test_idx].live = live; if ( ! s_results[test_idx].live && ( ! mock_body || ! *mock_body)) { CORE_TRACE("Mock HTTP data source unavailable."); s_results[test_idx].live = 1; } if (s_results[test_idx].live) { CORE_TRACE("Using a live HTTP data source."); SERV_NAMERD_SetConnectorSource(NULL); /* use live HTTP */ } else { CORE_TRACE("Using a mock HTTP data source."); if ( ! SERV_NAMERD_SetConnectorSource(mock_body)) { CORE_LOG(eLOG_Error, "Unable to create mock HTTP data source."); retval = 1; goto out; } } /* Set up the server iterator. */ net_info = ConnNetInfo_Create(svc); if (*hdr) ConnNetInfo_SetUserHeader(net_info, hdr); iter = SERV_OpenP(svc, fSERV_All | (strpbrk(svc, "?*") ? fSERV_Promiscuous : 0), SERV_LOCALHOST, 0/*port*/, 0.0/*preference*/, net_info, 0/*skip*/, 0/*n_skip*/, 0/*external*/, 0/*arg*/, 0/*val*/); ConnNetInfo_Destroy(net_info); /* Fetch the server hits from namerd. */ if (iter) { for (; s_n_hits_got < MAX_HITS && (info = SERV_GetNextInfo(iter)); ++s_n_hits_got) { if (info->type & fSERV_Http) { CORE_LOGF(eLOG_Note, (" HTTP extra (path): %s", SERV_HTTP_PATH(&info->u.http))); } strcpy(s_hits_got[s_n_hits_got].type, SERV_TypeStr(info->type)); strcpy(s_hits_got[s_n_hits_got].xtra, (info->type & fSERV_Http) ? SERV_HTTP_PATH(&info->u.http) : ""); strcpy(s_hits_got[s_n_hits_got].loc , (info->site & fSERV_Local ) ? "yes" : "no"); strcpy(s_hits_got[s_n_hits_got].priv, (info->site & fSERV_Private ) ? "yes" : "no"); strcpy(s_hits_got[s_n_hits_got].stfl, (info->mode & fSERV_Stateful) ? "yes" : "no"); SOCK_ntoa(info->host, s_hits_got[s_n_hits_got].host, LEN_HOST); s_hits_got[s_n_hits_got].port = info->port; s_hits_got[s_n_hits_got].match = 0; char *info_str; info_str = SERV_WriteInfo(info); CORE_LOGF(eLOG_Note, (" Found server %d: %s", s_n_hits_got, info_str ? info_str : "?")); if (info_str) free(info_str); } /* Make sure endpoint data can be repopulated and reset. */ if (repop && s_n_hits_got) { /* repopulate */ CORE_LOG(eLOG_Trace, "Repopulating the service mapper."); if ( ! info && ! SERV_GetNextInfo(iter)) { CORE_LOG(eLOG_Error, "Unable to repopulate endpoint data."); errors = 1; } } if (reset && s_n_hits_got) { /* reset */ CORE_LOG(eLOG_Trace, "Resetting the service mapper."); SERV_Reset(iter); if ( ! SERV_GetNextInfo(iter)) { CORE_LOG(eLOG_Error, "No services found after reset."); errors = 1; } } SERV_Close(iter); } else { errors = 1; } /* Search for matches unless this is a standalone run. */ if (check_for_match) { /* Search for perfect matches first (order is unknown). */ int it_exp, it_got; for (it_got=0; it_got < s_n_hits_got; ++it_got) { for (it_exp=0; it_exp < s_n_hits_exp; ++it_exp) { if (s_hits_exp[it_exp].match) continue; /*if (check_match(fMatch_Default, it_exp, it_got)) {*/ if (check_match(fMatch_All, it_exp, it_got)) { CORE_LOGF(eLOG_Note, ( " Found server %d perfectly matched expected server " "%d.", it_got, it_exp)); s_hits_exp[it_exp].match = 1; s_hits_got[it_got].match = 1; ++n_matches_perfect; break; } } } /* If not all found, search again but exclude host:port from match. */ for (it_got=0; it_got < s_n_hits_got; ++it_got) { if (s_hits_got[it_got].match) continue; for (it_exp=0; it_exp < s_n_hits_exp; ++it_exp) { if (s_hits_exp[it_exp].match) continue; if (check_match(fMatch_NoHostPort, it_exp, it_got)) { CORE_LOGF(eLOG_Note, ( " Found server %d nearly matched expected server %d.", it_got, it_exp)); s_hits_exp[it_exp].match = 1; s_hits_got[it_got].match = 1; ++n_matches_near; log_match_diffs(it_exp, it_got); break; } } } /* List any non-matching servers. */ for (it_exp=0; it_exp < s_n_hits_exp; ++it_exp) { if ( ! s_hits_exp[it_exp].match) CORE_LOGF(eLOG_Note, ( " Expected server %d didn't match any found servers.", it_exp)); } for (it_got=0; it_got < s_n_hits_got; ++it_got) { if ( ! s_hits_got[it_got].match) CORE_LOGF(eLOG_Note, ( " Found server %d didn't match any expected servers.", it_got)); } CORE_LOGF(n_matches_perfect + n_matches_near == s_n_hits_got ? eLOG_Note : eLOG_Error, ("Expected %d servers; found %d (%d perfect matches, %d near " "matches, and %d non-matches).", s_n_hits_exp, s_n_hits_got, n_matches_perfect, n_matches_near, s_n_hits_got - n_matches_perfect - n_matches_near)); if (!errors && s_n_hits_got == s_n_hits_exp && s_n_hits_got == n_matches_perfect + n_matches_near) { success = 1; } retval = (success != exp_err ? 1 : 0); CORE_LOGF(eLOG_Note, ("Test result: %s.", retval ? (success ? "PASS" : "PASS (with expected error)") : (success ? "FAIL (success when error expected)" : "FAIL"))); } out: if (mock_body_adj) free(mock_body_adj); return retval == -1 ? (success != exp_err ? 1 : 0) : retval; }
static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info) { const TSERV_Type types = iter->types & ~fSERV_Firewall; size_t i, n, idx[eHost_NoMatch], n_cand, a_cand; EHost_Match best_match, match; struct SLBSM_Candidate* cand; const SLBSM_Service* svc; TNCBI_Time dns_info_time; const SLBSM_Host* host; const char* env, *a; SSERV_Info* info; const char* name; double status; int standby; HEAP heap; char* v; heap = (HEAP)(iter->data != iter ? iter->data : 0); if (heap) { #ifdef LBSM_DEBUG CORE_LOGF(eLOG_Trace, ("LBSM heap[%p, %p, %d] for \"%s\" detected", heap, HEAP_Base(heap), HEAP_Serial(heap), iter->name)); #endif /*LBSM_DEBUG*/ /*noop*/; } else if (!(heap = s_GetHeapCopy(iter->time))) { return iter->external || iter->data == iter || !(types & fSERV_Dns) ? 0 : s_FakeDnsReturn(iter, host_info, 0, NCBI_TIME_INFINITE); } best_match = eHost_InitMatch; memset(idx, 0, sizeof(idx)); standby = -1/*unassigned*/; dns_info_time = 0/*none*/; n = n_cand = a_cand = 0; a = v = 0; cand = 0; svc = 0; name = *iter->name ? iter->name : 0; assert(name || iter->ismask); /*NB: ismask ignored for NULL*/ while ((svc = LBSM_LookupService(heap, name, iter->ismask, svc))) { if (svc->entry.good < iter->time) continue; /* out-of-date entry */ if (!svc->info.time) continue; /* off */ if (types != fSERV_Any && !(types & svc->info.type)) continue; /* type doesn't match */ if (iter->external && svc->info.locl) continue; /* external mapping requested; local/private server */ if (svc->info.locl & 0xF0) { /* private server */ if (svc->info.host && svc->info.host != s_GetLocalHostAddress(heap)) { continue; } } if (svc->info.type == fSERV_Dns) { if (types == fSERV_Any) continue; /* DNS entries have to be requested explicitly */ if (!iter->ismask) { if (dns_info_time < svc->info.time) dns_info_time = svc->info.time; } } else { if (iter->stateless && svc->info.sful) { /* Skip stateful-only non-CGI (NCBID and standalone) svc */ if (!(svc->info.type & fSERV_Http)) continue; } if (!iter->ismask && iter->reverse_dns) { if (dns_info_time < svc->info.time) dns_info_time = svc->info.time; } } if (svc->info.rate > 0.0 || host_info) { if (!(host = s_LookupHost(heap, iter, svc)) && svc->info.rate > 0.0) { continue; /* no host information for non-static server */ } } else host = 0; for (n = 0; n < iter->n_skip; n++) { const SSERV_Info* skip = iter->skip[n]; const char* s = SERV_NameOfInfo(skip); if (*s) { assert(iter->ismask || iter->reverse_dns); if (strcasecmp(s, (const char*) svc + svc->name) == 0 && ((skip->type == fSERV_Dns && !skip->host) || SERV_EqualInfo(skip, &svc->info))) { break; } } else if (SERV_EqualInfo(skip, &svc->info)) break; if (skip->type == fSERV_Firewall && skip->u.firewall.type == svc->info.type) { break; } if (iter->reverse_dns && skip->type == fSERV_Dns && skip->host == svc->info.host && (!skip->port || skip->port == svc->info.port)) { break; } } /*FIXME*//*CORE_LOG(eLOG_Note, (char*) svc + svc->name);*/ if (n >= iter->n_skip) { status = LBSM_CalculateStatus(svc->info.rate, svc->fine, svc->info.flag, &host->sys.load); if (status <= 0.0) { if (!svc->info.rate) { if (!iter->ok_down) continue; /* not operational */ status = 0.0; } else status = copysign(svc->info.rate, -1.0); } } else status = 0.0; /* dummy assignment to keep no-init warning off */ if (v) { free(v); v = 0; } a = env = 0; if (iter->pref < 0.0 && iter->host && (iter->host != svc->info.host || (iter->port && iter->port != svc->info.port))) { /* not a suitable fixed latching */ match = eHost_BadMatch; } else if (iter->arglen) { assert(iter->arg); if (!host) host = s_LookupHost(heap, iter, svc); if ( host && host->env) env = (const char*) host + host->env; match = s_Match(env, iter->arg, iter->arglen, iter->val, iter->vallen, &a, &v); assert(!a || a == iter->arg); } else match = eHost_GoodMatch; if (best_match > match) best_match = match; if (match > eHost_NoMatch) { assert(!v); continue; } if (svc->info.rate) { /* NB: server is _not_ down, but it may have been suppressed */ if (fabs(svc->info.rate) < 0.01) { if (!standby) { if (!iter->ok_suppressed) continue; /* this has to be given out as a suppressed one */ status = copysign(svc->info.rate, -1.0); } else if (standby < 0) standby = 1; } else if (standby) { standby = 0/*cancel*/; if (!iter->ok_suppressed) { memset(idx, 0, sizeof(idx)); for (i = 0; i < n_cand; i++) { if (cand[i].val) free((void*) cand[i].val); } n_cand = 0; } else for (i = 0; i < n_cand; i++) cand[i].cand.status = copysign(cand[i].svc->info.rate,-1.); } } if (n < iter->n_skip) continue; /* excluded/seen; NB: dummy assignment goes off here */ if (!iter->ok_suppressed && status < 0.0) continue; #ifdef NCBI_LB_DEBUG if (iter->arglen) { char* s = SERV_WriteInfo(&svc->info); const char* m; assert(s); switch (match) { case eHost_BestMatch: m = "Best match"; break; case eHost_GoodMatch: m = "Good match"; break; case eHost_FairMatch: m = "Fair match"; break; case eHost_PoorMatch: m = "Poor match"; break; case eHost_NoMatch: m = "No match"; break; default: assert(0); m = "?"; break; } assert(!a || *a); assert(!v || a); CORE_LOGF(eLOG_Note, ("%s%s%s%s: %s%s%s%s%s%s", s, env ? " <" : "", env ? env : "", env ? ">" : "", m, a ? ", arg=" : "", a ? a : "", v ? ", val=" : "", v ? (*v ? v : "\"\"") : "", standby > 0 ? ", standby" : "")); free(s); } #endif /*NCBI_LB_DEBUG*/ /* This server should be taken into consideration */ if (n_cand == a_cand) { struct SLBSM_Candidate* temp; n = a_cand + 10; temp = (struct SLBSM_Candidate*) (cand ? realloc(cand, n * sizeof(*temp)) : malloc ( n * sizeof(*temp))); if (!temp) break; cand = temp; a_cand = n; } if (match < eHost_NoMatch) { assert((size_t) match < sizeof(idx)/sizeof(idx[0])); n = idx[match]; if (n < n_cand) memmove(&cand[n + 1], &cand[n], sizeof(cand[0])*(n_cand - n)); for (i = match; i < sizeof(idx)/sizeof(idx[0]); i++) idx[i]++; } else n = n_cand; cand[n].cand.info = &svc->info; cand[n].cand.status = status; cand[n].host = host; cand[n].svc = svc; cand[n].arg = a; cand[n].val = v; a = v = 0; n_cand++; } if (v) free(v); if (best_match < eHost_NoMatch) { assert(!best_match || !idx[best_match - 1]); for (n = idx[best_match]; n < n_cand; n++) { if (cand[n].val) free((void*) cand[n].val); } n_cand = idx[best_match]; } if (n_cand) { assert(cand); do { if (standby <= 0) { struct SLBSM_Data data; data.cand = cand; data.n_cand = n_cand; n = LB_Select(iter, &data, s_GetCandidate, LBSMD_LOCAL_BONUS); } else { qsort(cand, n_cand, sizeof(*cand), s_SortStandbys); status = cand[0].cand.status; for (n = 1; n < n_cand; n++) { if (status != cand[n].cand.status) break; } n = rand() % n; } svc = cand[n].svc; if (iter->reverse_dns && svc->info.type != fSERV_Dns) { svc = 0; dns_info_time = 0/*none*/; while ((svc = LBSM_LookupService(heap, 0/*all*/, 0, svc)) !=0){ if (svc->info.type != fSERV_Dns || !svc->info.time || svc->info.host != cand[n].svc->info.host || svc->info.port != cand[n].svc->info.port) { continue; } if (!iter->ismask) { if (dns_info_time < svc->info.time) dns_info_time = svc->info.time; } if (iter->external && svc->info.locl) continue;/* external mapping requested; local server */ assert(!(svc->info.locl & 0xF0)); /* no private DNS */ status = LBSM_CalculateStatus(!svc->info.rate ? 0.0 : -LBSM_DEFAULT_RATE, svc->fine, fSERV_Regular, NULL); if (status > 0.0) break; if ((!svc->info.rate && iter->ok_down) || ( svc->info.rate && iter->ok_suppressed)) { cand[n].cand.status = !svc->info.rate ? 0.0 : copysign(svc->info.rate, -1.0); break; } } if (!svc && !dns_info_time) svc = cand[n].svc; } if (svc) break; if (cand[n].val) free((void*) cand[n].val); if (n < --n_cand) memmove(cand + n, cand + n + 1, (n_cand - n) * sizeof(*cand)); } while (n_cand); } else svc = 0; if (svc) { const char* name = (iter->ismask || iter->reverse_dns ? (const char*) svc + svc->name : ""); if ((info = SERV_CopyInfoEx(&svc->info, name)) != 0) { info->rate = cand[n].cand.status; if (info->time != NCBI_TIME_INFINITE) info->time = cand[n].svc->entry.good; if (host_info) { if ((host = cand[n].host) != 0) { *host_info = HINFO_Create(host->addr, &host->sys, sizeof(host->sys), host->env ? (const char*) host + host->env : 0, cand[n].arg, cand[n].val); } else *host_info = 0; } } } else { info = !n_cand && dns_info_time ? s_FakeDnsReturn(iter, host_info, best_match == eHost_InitMatch ? 0/*down*/ : best_match != eHost_BadMatch ? -1/*busy*/ : 1, dns_info_time) : 0; } for (n = 0; n < n_cand; n++) { if (cand[n].val) free((void*) cand[n].val); } if (cand) free(cand); if (!s_FastHeapAccess) { #ifdef LBSM_DEBUG CORE_LOGF(eLOG_Trace, ("LBSM heap[%p, %p, %d] for \"%s\" released", heap, HEAP_Base(heap), HEAP_Serial(heap), iter->name)); #endif /*LBSM_DEBUG*/ CORE_LOCK_WRITE; HEAP_Detach(heap); CORE_UNLOCK; heap = 0; } #ifdef LBSM_DEBUG else { CORE_LOGF(eLOG_Trace, ("LBSM heap[%p, %p, %d] for \"%s\" retained", heap, HEAP_Base(heap), HEAP_Serial(heap), iter->name)); } #endif /*LBSM_DEBUG*/ iter->data = heap; return info; }