string CSocketAPI::HostPortToString(unsigned int host, unsigned short port) { char buf[80]; size_t len = SOCK_HostPortToString(host, port, buf, sizeof(buf)); return string(buf, len); }
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); }
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; }
char* SERV_WriteInfo(const SSERV_Info* info) { char c_t[MAX_CONTENT_TYPE_LEN]; const SSERV_Attr* attr; size_t reserve; char* str; if (!(attr = s_GetAttrByType(info->type))) return 0; if (info->type != fSERV_Dns && MIME_ComposeContentTypeEx(info->mime_t, info->mime_s, info->mime_e, c_t, sizeof(c_t))) { char* p; assert(c_t[strlen(c_t) - 2] == '\r' && c_t[strlen(c_t) - 1] == '\n'); c_t[strlen(c_t) - 2] = 0; p = strchr(c_t, ' '); assert(p); p++; memmove(c_t, p, strlen(p) + 1); } else *c_t = 0; reserve = attr->tag_len+1 + MAX_IP_ADDR_LEN + 1+5/*port*/ + 1+10/*flag*/ + 1+9/*coef*/ + 3+strlen(c_t)/*cont.type*/ + 1+5/*locl*/ + 1+5/*priv*/ + 1+7/*quorum*/ + 1+14/*rate*/ + 1+5/*sful*/ + 1+12/*time*/ + 1/*EOL*/; /* write server-specific info */ if ((str = attr->vtable.Write(reserve, &info->u)) != 0) { char* s = str; size_t n; memcpy(s, attr->tag, attr->tag_len); s += attr->tag_len; *s++ = ' '; s += SOCK_HostPortToString(info->host, info->port, s, reserve); if ((n = strlen(str + reserve)) != 0) { *s++ = ' '; memmove(s, str + reserve, n + 1); s = str + strlen(str); } assert(info->flag < (int)(sizeof(k_FlagTag)/sizeof(k_FlagTag[0]))); if (k_FlagTag[info->flag] && *k_FlagTag[info->flag]) s += sprintf(s, " %s", k_FlagTag[info->flag]); s += sprintf(s, " B=%.2f", info->coef); if (*c_t) s += sprintf(s, " C=%s", c_t); s += sprintf(s, " L=%s", info->locl & 0x0F ? "yes" : "no"); if (info->type != fSERV_Dns && (info->locl & 0xF0)) s += sprintf(s, " P=yes"); if (info->host && info->quorum) { if (info->quorum == (unsigned short)(-1)) s += sprintf(s, " Q=yes"); else s += sprintf(s, " Q=%hu", info->quorum); } s += sprintf(s," R=%.*f", fabs(info->rate) < 0.01 ? 3 : 2, info->rate); if (!(info->type & fSERV_Http) && info->type != fSERV_Dns) s += sprintf(s, " S=%s", info->sful ? "yes" : "no"); s += sprintf(s, " T=%lu", (unsigned long)info->time); } return str; }