static int/*bool*/ s_AddServerInfo(struct SDISPD_Data* data, SSERV_Info* info) { size_t i; const char* name = SERV_NameOfInfo(info); /* First check that the new server info updates an existing one */ for (i = 0; i < data->n_cand; i++) { if (strcasecmp(name, SERV_NameOfInfo(data->cand[i].info)) == 0 && SERV_EqualInfo(info, data->cand[i].info)) { /* Replace older version */ free((void*) data->cand[i].info); data->cand[i].info = info; return 1; } } /* Next, add new service to the list */ if (data->n_cand == data->a_cand) { size_t n = data->a_cand + 10; SLB_Candidate* temp = (SLB_Candidate*) (data->cand ? realloc(data->cand, n * sizeof(*temp)) : malloc ( n * sizeof(*temp))); if (!temp) return 0; data->cand = temp; data->a_cand = n; } data->cand[data->n_cand++].info = info; return 1; }
static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info, int/*bool*/ internal) { SSERV_Info* info = 0; assert(iter && iter->op); if (iter->op->GetNextInfo) { if (!internal) { iter->time = (TNCBI_Time) time(0); s_SkipSkip(iter); } /* Obtain a fresh entry from the actual mapper */ while ((info = iter->op->GetNextInfo(iter, host_info)) != 0) { /* This should never actually be used for LBSMD dispatcher, * as all exclusion logic is already done in it internally. */ int/*bool*/ go = !info->host || iter->pref >= 0.0 || !iter->host || (iter->host == info->host && (!iter->port || iter->port == info->port)); if (go && internal) break; if (!s_AddSkipInfo(iter, SERV_NameOfInfo(info), info)) { free(info); info = 0; } if (go || !info) break; } } if (!internal) iter->last = info; return info; }
static int/*bool*/ s_AddSkipInfo(SERV_ITER iter, const char* name, SSERV_Info* info) { size_t n; assert(name); for (n = 0; n < iter->n_skip; n++) { if (strcasecmp(name, SERV_NameOfInfo(iter->skip[n])) == 0 && (SERV_EqualInfo(info, iter->skip[n]) || (iter->skip[n]->type == fSERV_Firewall && iter->skip[n]->u.firewall.type == info->u.firewall.type))) { /* Replace older version */ if (iter->last == iter->skip[n]) iter->last = info; free(iter->skip[n]); iter->skip[n] = info; return 1; } } if (iter->n_skip == iter->a_skip) { SSERV_Info** temp; n = iter->a_skip + 10; temp = (SSERV_Info**) (iter->skip ? realloc(iter->skip, n * sizeof(*temp)) : malloc ( n * sizeof(*temp))); if (!temp) return 0; iter->skip = temp; iter->a_skip = n; } iter->skip[iter->n_skip++] = info; return 1; }
const char* DBLB_GetServer(const char* lb_name, TDBLB_Flags flags, const SDBLB_Preference* preference, const char* const skip_servers[], SDBLB_ConnPoint* conn_point, char* server_name_buf, size_t server_name_buflen, EDBLB_Status* result) { static const char kPrefix[] = "DB_IP__"; size_t len, n, a_skip, n_skip; SConnNetInfo* net_info; int/*bool*/ failed; unsigned int x_host; unsigned short x_port; double x_pref; SSERV_InfoCPtr* skip; SSERV_Info* info; SDBLB_ConnPoint cp; EDBLB_Status x; const char* c; if (!result) result = &x; if (server_name_buf) { assert(server_name_buflen); server_name_buf[0] = '\0'; } if (!conn_point) conn_point = &cp; memset(conn_point, 0, sizeof(*conn_point)); if (!lb_name || !*lb_name) { *result = eDBLB_BadName; return 0/*failure*/; } *result = eDBLB_Success; if (strchr(lb_name, '.')) { cp.host = SOCK_gethostbyname(lb_name); if (cp.host == SOCK_GetLoopbackAddress()) cp.host = /*FIXME?*/SERV_LOCALHOST; } else cp.host = 0; skip = 0; n_skip = 0; a_skip = 0; net_info = 0; failed = 0/*false*/; if (skip_servers) { for (n = 0; !failed && skip_servers[n]; n++) { const char* server = skip_servers[n]; SSERV_Info* info; if (!(len = strlen(server))) { continue; } if (strncasecmp(server, kPrefix, sizeof(kPrefix)-1) == 0 && isdigit((unsigned char) server[sizeof(kPrefix)-1])) { c = strstr(server + sizeof(kPrefix)-1, "__"); if (c) { size_t i = (size_t)(c - server) - (sizeof(kPrefix)-1); char* temp = strdup(server + sizeof(kPrefix)-1); if (temp) { char* s = temp + i; *s++ = ':'; memmove(s, s + 1, strlen(s + 1) + 1); server = temp; while (++temp < s) { if (*temp == '_') *temp = '.'; } len -= sizeof(kPrefix); } } } if (SOCK_StringToHostPort(server, &x_host, &x_port) != server + len) { int/*bool*/ resolved = 0/*false*/; const SSERV_Info* temp; SERV_ITER iter; if (!net_info) net_info = ConnNetInfo_Create(lb_name); iter = SERV_Open(skip_servers[n], fSERV_Standalone | fSERV_Dns | fSERV_Promiscuous, 0, net_info); do { SSERV_Info* dns; temp = SERV_GetNextInfo(iter); if (temp) { x_host = temp->host; if (x_host && s_IsSkipHost(x_host, cp.host)) { failed = 1/*true*/; break; } x_port = temp->port; } else if (!resolved) { x_host = 0; x_port = 0; } else break; if ((dns = SERV_CreateDnsInfo(x_host)) != 0) { dns->port = x_port; s_AddSkip(&skip, &a_skip, &n_skip, x_host ? dns : SERV_CopyInfoEx(dns, skip_servers[n])); if (!x_host) free(dns); } resolved = 1/*true*/; } while (temp); SERV_Close(iter); info = 0; } else if (s_IsSkipHost(x_host, cp.host)) { failed = 1/*true*/; info = 0; } else if (server != skip_servers[n]) { info = SERV_CreateStandaloneInfo(x_host, x_port); } else if ((info = SERV_CreateDnsInfo(x_host)) != 0) info->port = x_port; if (server != skip_servers[n]) free((void*) server); if (info) s_AddSkip(&skip, &a_skip, &n_skip, info); } } if (!failed && !cp.host) { if (preference) { x_host = preference->host; x_port = preference->port; if ((x_pref = preference->pref) < 0.0) x_pref = 0.0; else if (x_pref >= 100.0) x_pref = -1.0; } else { x_host = 0; x_port = 0; x_pref = 0.0; } if (!net_info) net_info = ConnNetInfo_Create(lb_name); info = SERV_GetInfoP(lb_name, fSERV_ReverseDns | fSERV_Standalone, x_host, x_port, x_pref, net_info, skip, n_skip, 0/*not external*/, 0, 0, 0); /* NCBI_FAKE_WARNING: GCC */ if (!info && (flags & fDBLB_AllowFallbackToStandby)) { /*FIXME: eliminate second pass by fix in ordering in ncbi_lbsmd.c*/ info = SERV_GetInfoP(lb_name, fSERV_ReverseDns | fSERV_Standalone | fSERV_IncludeSuppressed, x_host, x_port, x_pref, net_info, skip, n_skip, 0/*not external*/, 0, 0, 0); /* NCBI_FAKE_WARNING: GCC */ } } else info = 0; if (!info) { if (!failed) { if (!cp.host) { if (n_skip && (x_host = SOCK_gethostbyname(lb_name)) != 0) { for (n = 0; n < n_skip; n++) { if (x_host == skip[n]->host) { failed = 1/*true*/; break; } } } if (!failed && skip_servers) { for (n = 0; (c = skip_servers[n]) != 0; n++) { if (strcasecmp(c, lb_name) == 0) { failed = 1/*true*/; break; } } } } else if (conn_point != &cp) { conn_point->host = cp.host; conn_point->time = NCBI_TIME_INFINITE; } } if (!failed && server_name_buf) strncpy0(server_name_buf, lb_name, server_name_buflen - 1); *result = eDBLB_NotFound; } else { if (info->type != fSERV_Dns) { char* s, buf[80]; strncpy0(buf, kPrefix, sizeof(buf) - 1); SOCK_HostPortToString(info->host, info->port, buf + sizeof(kPrefix) - 1, sizeof(buf) - sizeof(kPrefix)); len = strlen(buf); if ((s = strchr(buf, ':')) != 0) memmove(s + 1, s, strlen(s) + 1); for (n = 0; n < len; n++) { if (buf[n] == '.' || buf[n] == ':') buf[n] = '_'; } if (server_name_buf) strncpy0(server_name_buf, buf, server_name_buflen - 1); *result = eDBLB_NoDNSEntry; } else if (info->host) { c = SERV_NameOfInfo(info); assert(c); if (server_name_buf) strncpy0(server_name_buf, c, server_name_buflen - 1); } else { failed = 1/*true*/; *result = eDBLB_ServiceDown; } if (!failed) { conn_point->host = info->host; conn_point->port = info->port; conn_point->time = info->time; } free(info); } for (n = 0; n < n_skip; n++) free((void*) skip[n]); if (skip) free((void*) skip); if (net_info) ConnNetInfo_Destroy(net_info); return failed ? 0 : (server_name_buf ? server_name_buf : lb_name); }
static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info) { struct SLOCAL_Data* data = (struct SLOCAL_Data*) iter->data; const TSERV_Type type = iter->type & ~fSERV_Firewall; int/*bool*/ dns_info_seen = 0/*false*/; SSERV_Info* info; size_t i, n; assert(data); if (data->reset) { data->reset = 0/*false*/; if (!s_LoadServices(iter)) return 0; if (data->n_cand > 1) qsort(data->cand, data->n_cand, sizeof(*data->cand), s_Sort); } i = 0; data->i_cand = 0; while (i < data->n_cand) { /* NB all servers have been loaded in accordance with iter->external */ info = (SSERV_Info*) data->cand[i].info; if (info->rate > 0.0 || iter->ok_down) { const char* c = SERV_NameOfInfo(info); 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, c) == 0 && ((skip->type == fSERV_Dns && !skip->host) || SERV_EqualInfo(skip, info))) { break; } } else if (SERV_EqualInfo(skip, info)) break; if (iter->reverse_dns && skip->type == fSERV_Dns && skip->host == info->host && (!skip->port || skip->port == info->port)) { break; } } } else n = 0; if (!iter->ismask) { if (type == fSERV_Any) { if (iter->reverse_dns && info->type != fSERV_Dns) dns_info_seen = 1/*true*/; } else if ((type & info->type) && info->type == fSERV_Dns) dns_info_seen = 1/*true*/; } if (n < iter->n_skip) { if (i < --data->n_cand) { memmove(data->cand + i, data->cand + i + 1, (data->n_cand - i) * sizeof(*data->cand)); } free(info); } else { if (type != fSERV_Any && !(type & info->type)) break; if (type == fSERV_Any && info->type == fSERV_Dns) break; data->i_cand++; data->cand[i].status = info->rate < 0.0 ? 0.0 : info->rate; if (iter->ok_down) break; i++; } } if (data->i_cand) { n = LB_Select(iter, data, s_GetCandidate, 1.0); info = (SSERV_Info*) data->cand[n].info; if (iter->reverse_dns && info->type != fSERV_Dns) { dns_info_seen = 0/*false*/; for (i = 0; i < data->n_cand; i++) { SSERV_Info* temp = (SSERV_Info*) data->cand[i].info; if (temp->type != fSERV_Dns || temp->host != info->host || temp->port != info->port) { continue; } if (!iter->ismask) dns_info_seen = 1/*true*/; if (iter->external && temp->locl) continue; /* external mapping req'd; local server */ assert(!(temp->locl & 0xF0)); /* no private DNS */ if (temp->rate > 0.0 || iter->ok_down) { data->cand[i].status = data->cand[n].status; info = temp; n = i; break; } } if (i >= data->n_cand && dns_info_seen) info = 0; } if (info) { info->rate = data->cand[n].status; info->time += iter->time; if (n < --data->n_cand) { memmove(data->cand + n, data->cand + n + 1, (data->n_cand - n) * sizeof(*data->cand)); } } } else if (iter->last || iter->n_skip || !dns_info_seen) { info = 0; } else if ((info = SERV_CreateDnsInfo(0)) != 0) info->time = NCBI_TIME_INFINITE; if (info && host_info) *host_info = 0; return info; }
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; }
const char* SERV_CurrentName(SERV_ITER iter) { const char* name = SERV_NameOfInfo(iter->last); return name && *name ? name : iter->name; }
static SERV_ITER s_Open(const char* service, unsigned/*bool*/ ismask, TSERV_Type types, unsigned int preferred_host, unsigned short preferred_port, double preference, const SConnNetInfo* net_info, const SSERV_InfoCPtr skip[], size_t n_skip, unsigned/*bool*/ external, const char* arg, const char* val, SSERV_Info** info, HOST_INFO* host_info) { int/*bool*/ do_lbsmd = -1/*unassigned*/, do_dispd = -1/*unassigned*/; const SSERV_VTable* op; SERV_ITER iter; const char* s; if (!(s = s_ServiceName(service, ismask, 0))) return 0; if (!(iter = (SERV_ITER) calloc(1, sizeof(*iter)))) { free((void*) s); return 0; } assert(ismask || *s); iter->name = s; iter->type = types & fSERV_All; iter->host = (preferred_host == SERV_LOCALHOST ? SOCK_GetLocalHostAddress(eDefault) : preferred_host); iter->port = preferred_port; iter->pref = (preference < 0.0 ? -1.0 : 0.01 * (preference > 100.0 ? 100.0 : preference)); if (ismask) iter->ismask = 1; if (types & fSERV_IncludeDown) iter->ok_down = 1; if (types & fSERV_IncludeSuppressed) iter->ok_suppressed = 1; if (types & fSERV_ReverseDns) iter->reverse_dns = 1; if (types & fSERV_Stateless) iter->stateless = 1; iter->external = external; if (arg && *arg) { iter->arg = arg; iter->arglen = strlen(arg); if (val) { iter->val = val; iter->vallen = strlen(val); } } iter->time = (TNCBI_Time) time(0); if (n_skip) { size_t i; for (i = 0; i < n_skip; i++) { const char* name = (iter->ismask || skip[i]->type == fSERV_Dns ? SERV_NameOfInfo(skip[i]) : ""); SSERV_Info* temp = SERV_CopyInfoEx(skip[i], !iter->reverse_dns || *name ? name : s); if (temp) { temp->time = NCBI_TIME_INFINITE; if (!s_AddSkipInfo(iter, name, temp)) { free(temp); temp = 0; } } if (!temp) { SERV_Close(iter); return 0; } } } assert(n_skip == iter->n_skip); if (net_info) { if (net_info->firewall) iter->type |= fSERV_Firewall; if (net_info->stateless) iter->stateless = 1; if (net_info->lb_disable) do_lbsmd = 0/*false*/; } else do_dispd = 0/*false*/; /* Ugly optimization not to access the registry more than necessary */ if ((!s_IsMapperConfigured(service, REG_CONN_LOCAL_ENABLE) || !(op = SERV_LOCAL_Open(iter, info, host_info))) && (!do_lbsmd || !(do_lbsmd= !s_IsMapperConfigured(service, REG_CONN_LBSMD_DISABLE)) || !(op = SERV_LBSMD_Open(iter, info, host_info, !do_dispd || !(do_dispd = !s_IsMapperConfigured (service, REG_CONN_DISPD_DISABLE))))) && (!do_dispd || !(do_dispd= !s_IsMapperConfigured(service, REG_CONN_DISPD_DISABLE)) || !(op = SERV_DISPD_Open(iter, net_info, info, host_info)))) { if (!do_lbsmd && !do_dispd) { CORE_LOGF_X(1, eLOG_Error, ("[%s] No service mappers available", service)); } SERV_Close(iter); return 0; } assert(op != 0); iter->op = op; return iter; }
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; }