static SSERV_Info* s_GetInfo(const char* service, 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, int /*bool*/ external, const char* arg, const char* val, HOST_INFO* host_info) { SSERV_Info* info = 0; SERV_ITER iter = s_Open(service, 0/*not mask*/, types, preferred_host, preferred_port, preference, net_info, skip, n_skip, external, arg, val, &info, host_info); if (iter && iter->op && !info) { /* All LOCAL/DISPD searches end up here, but none LBSMD ones */ info = s_GetNextInfo(iter, host_info, 1/*internal*/); } SERV_Close(iter); return info; }
const SSERV_VTable* SERV_LBSMD_Open(SERV_ITER iter, SSERV_Info** info, HOST_INFO* host_info, int/*bool*/ no_dispd_follows) { static int s_Init = 0; SSERV_Info* tmp; /* Daemon is running if LBSM_LBSMD returns 1: mutex exists but read operation failed with errno == EAGAIN (the mutex is busy) */ if (LBSM_LBSMD(0) <= 0 || errno != EAGAIN) return 0; if (!s_Init) { CORE_LOCK_WRITE; if (!s_Init && atexit(s_Fini) == 0) s_Init = 1; CORE_UNLOCK; } if (g_NCBI_ConnectRandomSeed == 0) { g_NCBI_ConnectRandomSeed = iter->time ^ NCBI_CONNECT_SRAND_ADDEND; srand(g_NCBI_ConnectRandomSeed); } if (!no_dispd_follows) iter->data = iter; tmp = s_GetNextInfo(iter, host_info); if (iter->data == iter) iter->data = 0; if (!tmp) { s_Close(iter); return 0; } if (info) *info = tmp; else if (tmp) free(tmp); return &s_op; }
const SSERV_Info* SERV_GetNextInfo(SERV_ITER iter) { return iter && iter->op ? s_GetNextInfo(iter, 0, 0) : 0; }
const SSERV_Info* SERV_GetNextInfoEx(SERV_ITER iter, HOST_INFO* host_info) { return iter && iter->op ? s_GetNextInfo(iter, host_info, 0) : 0; }
static EIO_Status s_VT_Open(CONNECTOR connector, const STimeout* timeout) { SServiceConnector* uuu = (SServiceConnector*) connector->handle; SMetaConnector* meta = connector->meta; EIO_Status status; for (;;) { const SSERV_Info* info; SConnNetInfo* net_info; CONNECTOR conn; int stateless; assert(!uuu->meta.list && !uuu->name && !uuu->descr); if (!uuu->iter && !s_OpenDispatcher(uuu)) { status = eIO_Closed; break; } if (uuu->net_info->firewall && strcasecmp(uuu->iter->name, "local")) info = 0; else if (!(info = s_GetNextInfo(uuu))) { status = eIO_Closed; break; } if (!(net_info = ConnNetInfo_Clone(uuu->net_info))) { status = eIO_Unknown; break; } net_info->scheme = eURL_Unspec; conn = s_Open(uuu, timeout, info, net_info, 0/*!second_try*/); if (conn) uuu->descr = ConnNetInfo_URL(net_info); stateless = net_info->stateless; ConnNetInfo_Destroy(net_info); if (!conn) { if (!info) { status = eIO_Closed; break; } continue; } /* Setup the new connector on a temporary meta-connector... */ memset(&uuu->meta, 0, sizeof(uuu->meta)); METACONN_Add(&uuu->meta, conn); /* ...then link it in using current connection's meta */ conn->meta = meta; conn->next = meta->list; meta->list = conn; if (!uuu->descr && uuu->meta.descr) CONN_SET_METHOD(meta, descr, uuu->meta.descr, uuu->meta.c_descr); CONN_SET_METHOD (meta, wait, uuu->meta.wait, uuu->meta.c_wait); CONN_SET_METHOD (meta, write, uuu->meta.write, uuu->meta.c_write); CONN_SET_METHOD (meta, flush, uuu->meta.flush, uuu->meta.c_flush); CONN_SET_METHOD (meta, read, uuu->meta.read, uuu->meta.c_read); CONN_SET_METHOD (meta, status,uuu->meta.status,uuu->meta.c_status); if (uuu->meta.get_type) { const char* type; if ((type = uuu->meta.get_type(uuu->meta.c_get_type)) != 0) { size_t slen = strlen(uuu->service); size_t tlen = strlen(type); char* name = (char*) malloc(slen + tlen + 2); if (name) { memcpy(name, uuu->service, slen); name[slen++] = '/'; memcpy(name + slen, type, tlen); tlen += slen; name[tlen] = '\0'; uuu->name = name; } } } status = uuu->meta.open ? uuu->meta.open(uuu->meta.c_open, timeout) : eIO_Success; if (status == eIO_Success) break; if (!stateless && (!info || info->type == fSERV_Firewall)) { static const char kFWLink[] = { "http://www.ncbi.nlm.nih.gov" "/IEB/ToolBox/NETWORK" "/dispatcher.html#Firewalling"}; CORE_LOGF_X(6, eLOG_Error, ("[%s] %s connection failed (%s) indicating possible " "firewall configuration problem; please consult <%s>", uuu->service, !info ? "Firewall" : "Stateful relay", IO_StatusStr(status), kFWLink)); } s_Close(connector, timeout, 0/*don't close dispatcher just as yet*/); } uuu->status = status; return status; }
/* This callback is only for services called via direct HTTP */ static int/*bool*/ s_AdjustNetInfo(SConnNetInfo* net_info, void* data, unsigned int n) { SServiceConnector* uuu = (SServiceConnector*) data; const char* user_header; const SSERV_Info* info; assert(n != 0); /* paranoid assertion :-) */ if (uuu->net_info->firewall && !uuu->net_info->stateless) return 0; /*cannot adjust firewall stateful client*/ for (;;) { if (!(info = s_GetNextInfo(uuu))) return 0/*false - not adjusted*/; /* Skip any 'stateful_capable' or unconnectable entries here, * which might have left behind by either a failed stateful * dispatching with a fallback to stateless HTTP mode or * a too relaxed server type selection */ if (!info->sful && info->type != fSERV_Dns) break; } {{ char* iter_header = SERV_Print(uuu->iter, 0, 0); switch (info->type) { case fSERV_Ncbid: user_header = "Connection-Mode: STATELESS\r\n"; /*default*/ user_header = s_AdjustNetParams(uuu->service, net_info, eReqMethod_Post, NCBID_WEBPATH, SERV_NCBID_ARGS(&info->u.ncbid), uuu->net_info->args, user_header, info->mime_t, info->mime_s, info->mime_e, iter_header); break; case fSERV_Http: case fSERV_HttpGet: case fSERV_HttpPost: user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/ user_header = s_AdjustNetParams(uuu->service, net_info, info->type == fSERV_HttpGet ? eReqMethod_Get : (info->type == fSERV_HttpPost ? eReqMethod_Post : eReqMethod_Any), SERV_HTTP_PATH(&info->u.http), SERV_HTTP_ARGS(&info->u.http), uuu->net_info->args, user_header, info->mime_t, info->mime_s, info->mime_e, iter_header); break; case fSERV_Standalone: case fSERV_Firewall: user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/ user_header = s_AdjustNetParams(uuu->service, net_info, eReqMethod_Post, uuu->net_info->path, 0, uuu->net_info->args, user_header, info->mime_t, info->mime_s, info->mime_e, iter_header); break; default: if (iter_header) free(iter_header); user_header = 0; break; } }} if (!user_header) return 0/*false - not adjusted*/; if (uuu->user_header) { assert(*uuu->user_header); ConnNetInfo_DeleteUserHeader(net_info, uuu->user_header); free((void*) uuu->user_header); } if (*user_header) { uuu->user_header = user_header; if (!ConnNetInfo_OverrideUserHeader(net_info, user_header)) return 0/*false - not adjusted*/; } else uuu->user_header = 0; if (info->type == fSERV_Ncbid || (info->type & fSERV_Http)) { SOCK_ntoa(info->host, net_info->host, sizeof(net_info->host)); net_info->port = info->port; } else { strcpy(net_info->host, uuu->net_info->host); net_info->port = uuu->net_info->port; } return 1/*true - adjusted*/; }