00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include "ncbi_ansi_ext.h"
00034 #include "ncbi_comm.h"
00035 #include "ncbi_priv.h"
00036 #include "ncbi_servicep.h"
00037 #include <connect/ncbi_service_connector.h>
00038 #include <connect/ncbi_socket_connector.h>
00039 #include <ctype.h>
00040 #include <stdlib.h>
00041
00042 #define NCBI_USE_ERRCODE_X Connect_Service
00043
00044
00045 static const char kFWDaemon[] = "fwdaemon.ncbi.nlm.nih.gov";
00046
00047
00048 typedef struct SServiceConnectorTag {
00049 const char* name;
00050 TSERV_Type types;
00051 SConnNetInfo* net_info;
00052 const char* user_header;
00053 SERV_ITER iter;
00054 SMetaConnector meta;
00055 EIO_Status status;
00056 unsigned int host;
00057 unsigned short port;
00058 ticket_t ticket;
00059 SSERVICE_Extra params;
00060 char service[1];
00061 } SServiceConnector;
00062
00063
00064
00065
00066
00067
00068 #ifdef __cplusplus
00069 extern "C" {
00070 #endif
00071 static const char* s_VT_GetType (CONNECTOR connector);
00072 static EIO_Status s_VT_Open (CONNECTOR connector,
00073 const STimeout* timeout);
00074 static EIO_Status s_VT_Status (CONNECTOR connector,
00075 EIO_Event dir);
00076 static EIO_Status s_VT_Close (CONNECTOR connector,
00077 const STimeout* timeout);
00078 static void s_Setup (SMetaConnector* meta,
00079 CONNECTOR connector);
00080 static void s_Destroy (CONNECTOR connector);
00081 #ifdef __cplusplus
00082 }
00083 #endif
00084
00085
00086 static int s_OpenDispatcher(SServiceConnector* uuu)
00087 {
00088 if (!(uuu->iter = SERV_OpenEx(uuu->service, uuu->types,
00089 SERV_LOCALHOST, uuu->net_info, 0, 0))) {
00090 CORE_LOGF_X(5, eLOG_Error,
00091 ("[%s] Error locating server", uuu->service));
00092 return 0;
00093 }
00094 return 1;
00095 }
00096
00097
00098 static void s_CloseDispatcher(SServiceConnector* uuu)
00099 {
00100 SERV_Close(uuu->iter);
00101 uuu->iter = 0;
00102 }
00103
00104
00105
00106
00107
00108 static void s_Reset(SMetaConnector *meta)
00109 {
00110 CONN_SET_METHOD(meta, descr, 0, 0);
00111 CONN_SET_METHOD(meta, wait, 0, 0);
00112 CONN_SET_METHOD(meta, write, 0, 0);
00113 CONN_SET_METHOD(meta, flush, 0, 0);
00114 CONN_SET_METHOD(meta, read, 0, 0);
00115 CONN_SET_METHOD(meta, status, s_VT_Status, 0);
00116 #ifdef IMPLEMENTED__CONN_WaitAsync
00117 CONN_SET_METHOD(meta, wait_async, 0, 0);
00118 #endif
00119 }
00120
00121
00122 #ifdef __cplusplus
00123 extern "C" {
00124 static int s_ParseHeader(const char*, void*, int);
00125 }
00126 #endif
00127
00128 static int s_ParseHeader(const char* header,
00129 void* data,
00130 int server_error)
00131 {
00132 static const char kStateless[] = "TRY_STATELESS";
00133 static const size_t klen = sizeof(kStateless) - 1;
00134 SServiceConnector* uuu = (SServiceConnector*) data;
00135
00136 SERV_Update(uuu->iter, header, server_error);
00137 if (server_error)
00138 return 1;
00139
00140 while (header && *header) {
00141 if (strncasecmp(header, HTTP_CONNECTION_INFO,
00142 sizeof(HTTP_CONNECTION_INFO) - 1) == 0) {
00143 unsigned int i1, i2, i3, i4, ticket;
00144 unsigned char o1, o2, o3, o4;
00145 char ipaddr[40];
00146
00147 if (uuu->host)
00148 break;
00149 header += sizeof(HTTP_CONNECTION_INFO) - 1;
00150 while (*header && isspace((unsigned char)(*header)))
00151 header++;
00152 if (strncasecmp(header, kStateless, klen) == 0 &&
00153 (!header[klen] || isspace((unsigned char) header[klen]))) {
00154
00155 uuu->host = (unsigned int)(-1);
00156 #if defined(_DEBUG) && !defined(NDEBUG)
00157 if (uuu->net_info->debug_printout) {
00158 CORE_LOGF_X(2, eLOG_Note,
00159 ("[%s] Fallback to stateless", uuu->service));
00160 }
00161 #endif
00162 } else {
00163 int n;
00164 if (sscanf(header, "%u.%u.%u.%u %hu %x%n",
00165 &i1, &i2, &i3, &i4, &uuu->port, &ticket, &n) < 6 ||
00166 (header[n] && !isspace((unsigned char) header[n]))) {
00167 break;
00168 }
00169 o1 = i1; o2 = i2; o3 = i3; o4 = i4;
00170 sprintf(ipaddr, "%u.%u.%u.%u", o1, o2, o3, o4);
00171 if (!(uuu->host = SOCK_gethostbyname(ipaddr)) || !uuu->port)
00172 break;
00173 uuu->ticket = SOCK_HostToNetLong(ticket);
00174 }
00175 }
00176 if ((header = strchr(header, '\n')) != 0)
00177 header++;
00178 }
00179 if (!header || !*header)
00180 return 1;
00181
00182 uuu->host = 0;
00183 return 0;
00184 }
00185
00186
00187
00188 static int s_IsContentTypeDefined(const char* service,
00189 const SConnNetInfo* net_info,
00190 EMIME_Type mime_t,
00191 EMIME_SubType mime_s,
00192 EMIME_Encoding mime_e)
00193 {
00194 const char* s;
00195
00196 assert(net_info);
00197 for (s = net_info->http_user_header; s; s = strchr(s, '\n')) {
00198 if (s != net_info->http_user_header)
00199 s++;
00200 if (!*s)
00201 break;
00202 if (strncasecmp(s, "content-type: ", 14) == 0) {
00203 #if defined(_DEBUG) && !defined(NDEBUG)
00204 EMIME_Type m_t;
00205 EMIME_SubType m_s;
00206 EMIME_Encoding m_e;
00207 char c_t[MAX_CONTENT_TYPE_LEN];
00208 if (net_info->debug_printout &&
00209 mime_t != eMIME_T_Undefined &&
00210 mime_t != eMIME_T_Unknown &&
00211 (!MIME_ParseContentTypeEx(s, &m_t, &m_s, &m_e)
00212 || mime_t != m_t
00213 || (mime_s != eMIME_Undefined &&
00214 mime_s != eMIME_Unknown &&
00215 m_s != eMIME_Unknown && mime_s != m_s)
00216 || (mime_e != eENCOD_None &&
00217 m_e != eENCOD_None && mime_e != m_e))) {
00218 const char* c;
00219 size_t len;
00220 char* t;
00221 for (s += 15; *s; s++) {
00222 if (!isspace((unsigned char)(*s)))
00223 break;
00224 }
00225 if (!(c = strchr(s, '\n')))
00226 c = s + strlen(s);
00227 if (c > s && c[-1] == '\r')
00228 c--;
00229 len = (size_t)(c - s);
00230 if ((t = (char*) malloc(len + 1)) != 0) {
00231 memcpy(t, s, len);
00232 t[len] = '\0';
00233 }
00234 if (!MIME_ComposeContentTypeEx(mime_t, mime_s, mime_e,
00235 c_t, sizeof(c_t))) {
00236 *c_t = '\0';
00237 }
00238 CORE_LOGF_X(3, eLOG_Warning,
00239 ("[%s] Content-Type mismatch: "
00240 "%s%s%s%s%s%s%s", service,
00241 t && *t ? "specified=<" : "",
00242 t && *t ? t : "",
00243 t && *t ? ">" : "",
00244 t && *t && *c_t ? ", " : "",
00245 *c_t ? "configured=<" : "",
00246 *c_t ? c_t : "",
00247 *c_t ? ">" : ""));
00248 if (t)
00249 free(t);
00250 }
00251 #endif
00252 return 1;
00253 }
00254 }
00255 return 0;
00256 }
00257
00258
00259 static const char* s_AdjustNetParams(const char* service,
00260 SConnNetInfo* net_info,
00261 EReqMethod req_method,
00262 const char* cgi_path,
00263 const char* cgi_args,
00264 const char* args,
00265 const char* static_header,
00266 EMIME_Type mime_t,
00267 EMIME_SubType mime_s,
00268 EMIME_Encoding mime_e,
00269 char* dynamic_header)
00270 {
00271 const char *retval = 0;
00272
00273 net_info->req_method = req_method;
00274
00275 if (cgi_path)
00276 strncpy0(net_info->path, cgi_path, sizeof(net_info->path) - 1);
00277
00278 if (args)
00279 strncpy0(net_info->args, args, sizeof(net_info->args) - 1);
00280 ConnNetInfo_DeleteAllArgs(net_info, cgi_args);
00281
00282 if (ConnNetInfo_PrependArg(net_info, cgi_args, 0)) {
00283 size_t sh_len = static_header ? strlen(static_header) : 0;
00284 size_t dh_len = dynamic_header ? strlen(dynamic_header) : 0;
00285 char c_t[MAX_CONTENT_TYPE_LEN];
00286 size_t ct_len, len;
00287
00288 if (s_IsContentTypeDefined(service, net_info, mime_t, mime_s, mime_e)
00289 || !MIME_ComposeContentTypeEx(mime_t, mime_s, mime_e,
00290 c_t, sizeof(c_t))) {
00291 c_t[0] = '\0';
00292 ct_len = 0;
00293 } else
00294 ct_len = strlen(c_t);
00295 if ((len = sh_len + dh_len + ct_len) != 0) {
00296 char* temp = (char*) malloc(len + 1);
00297 if (temp) {
00298 strcpy(temp, static_header ? static_header : "");
00299 strcpy(temp + sh_len, dynamic_header ? dynamic_header : "");
00300 strcpy(temp + sh_len + dh_len, c_t);
00301 retval = temp;
00302 }
00303 } else
00304 retval = "";
00305 }
00306
00307 if (dynamic_header)
00308 free(dynamic_header);
00309 return retval;
00310 }
00311
00312
00313 static const SSERV_Info* s_GetNextInfo(SServiceConnector* uuu)
00314 {
00315 if (uuu->params.get_next_info)
00316 return uuu->params.get_next_info(uuu->iter, uuu->params.data);
00317 else
00318 return SERV_GetNextInfo(uuu->iter);
00319 }
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 #ifdef __cplusplus
00331 extern "C" {
00332 static int s_AdjustNetInfo(SConnNetInfo*, void*, unsigned int);
00333 }
00334 #endif
00335
00336
00337
00338 static int s_AdjustNetInfo(SConnNetInfo* net_info,
00339 void* data,
00340 unsigned int n)
00341 {
00342 SServiceConnector* uuu = (SServiceConnector*) data;
00343 const char* user_header;
00344 const SSERV_Info* info;
00345
00346 assert(n != 0);
00347 if (uuu->net_info->firewall && !uuu->net_info->stateless)
00348 return 0;
00349
00350 for (;;) {
00351 if (!(info = s_GetNextInfo(uuu)))
00352 return 0;
00353
00354
00355
00356
00357 if (!info->sful && info->type != fSERV_Dns)
00358 break;
00359 }
00360
00361 {{
00362 char* iter_header = SERV_Print(uuu->iter, 0, 0);
00363 switch (info->type) {
00364 case fSERV_Ncbid:
00365 user_header = "Connection-Mode: STATELESS\r\n";
00366 user_header = s_AdjustNetParams(uuu->service, net_info,
00367 eReqMethod_Post,
00368 NCBID_WEBPATH,
00369 SERV_NCBID_ARGS(&info->u.ncbid),
00370 uuu->net_info->args,
00371 user_header, info->mime_t,
00372 info->mime_s, info->mime_e,
00373 iter_header);
00374 break;
00375 case fSERV_Http:
00376 case fSERV_HttpGet:
00377 case fSERV_HttpPost:
00378 user_header = "Client-Mode: STATELESS_ONLY\r\n";
00379 user_header = s_AdjustNetParams(uuu->service, net_info,
00380 info->type == fSERV_HttpGet
00381 ? eReqMethod_Get
00382 : (info->type == fSERV_HttpPost
00383 ? eReqMethod_Post
00384 : eReqMethod_Any),
00385 SERV_HTTP_PATH(&info->u.http),
00386 SERV_HTTP_ARGS(&info->u.http),
00387 uuu->net_info->args,
00388 user_header, info->mime_t,
00389 info->mime_s, info->mime_e,
00390 iter_header);
00391 break;
00392 case fSERV_Standalone:
00393 case fSERV_Firewall:
00394 user_header = "Client-Mode: STATELESS_ONLY\r\n";
00395 user_header = s_AdjustNetParams(uuu->service, net_info,
00396 eReqMethod_Post,
00397 uuu->net_info->path, 0,
00398 uuu->net_info->args,
00399 user_header, info->mime_t,
00400 info->mime_s, info->mime_e,
00401 iter_header);
00402 break;
00403 default:
00404 if (iter_header)
00405 free(iter_header);
00406 user_header = 0;
00407 break;
00408 }
00409 }}
00410 if (!user_header)
00411 return 0;
00412
00413 if (uuu->user_header) {
00414 ConnNetInfo_DeleteUserHeader(net_info, uuu->user_header);
00415 free((void*) uuu->user_header);
00416 }
00417 uuu->user_header = *user_header ? user_header : 0;
00418 if (!ConnNetInfo_OverrideUserHeader(net_info, user_header))
00419 return 0;
00420
00421 if (info->type == fSERV_Ncbid || (info->type & fSERV_Http)) {
00422 SOCK_ntoa(info->host, net_info->host, sizeof(net_info->host));
00423 net_info->port = info->port;
00424 } else {
00425 strcpy(net_info->host, uuu->net_info->host);
00426 net_info->port = uuu->net_info->port;
00427 }
00428
00429 if (net_info->http_proxy_adjusted)
00430 net_info->http_proxy_adjusted = 0;
00431
00432 return 1;
00433 }
00434
00435
00436 static CONNECTOR s_Open(SServiceConnector* uuu,
00437 const STimeout* timeout,
00438 const SSERV_Info* info,
00439 SConnNetInfo* net_info,
00440 int second_try)
00441 {
00442 int but_last = 0;
00443 const char* user_header;
00444 char* iter_header;
00445 EReqMethod req_method;
00446
00447 if (info && info->type != fSERV_Firewall) {
00448
00449 assert(!second_try);
00450
00451 if (info->type != fSERV_Standalone || !net_info->stateless) {
00452 SOCK_ntoa(info->host, net_info->host, sizeof(net_info->host));
00453 net_info->port = info->port;
00454 }
00455
00456 switch (info->type) {
00457 case fSERV_Ncbid:
00458
00459 if (net_info->stateless) {
00460
00461 user_header = "Connection-Mode: STATELESS\r\n";
00462 req_method = eReqMethod_Post;
00463 } else {
00464
00465 user_header = "Connection-Mode: STATEFUL\r\n";
00466 req_method = eReqMethod_Get;
00467 }
00468 user_header = s_AdjustNetParams(uuu->service, net_info, req_method,
00469 NCBID_WEBPATH,
00470 SERV_NCBID_ARGS(&info->u.ncbid),
00471 0, user_header, info->mime_t,
00472 info->mime_s, info->mime_e, 0);
00473 break;
00474 case fSERV_Http:
00475 case fSERV_HttpGet:
00476 case fSERV_HttpPost:
00477
00478 req_method = info->type == fSERV_HttpGet
00479 ? eReqMethod_Get : (info->type == fSERV_HttpPost
00480 ? eReqMethod_Post : eReqMethod_Any);
00481 user_header = "Client-Mode: STATELESS_ONLY\r\n";
00482 user_header = s_AdjustNetParams(uuu->service, net_info, req_method,
00483 SERV_HTTP_PATH(&info->u.http),
00484 SERV_HTTP_ARGS(&info->u.http),
00485 0, user_header, info->mime_t,
00486 info->mime_s, info->mime_e, 0);
00487 break;
00488 case fSERV_Standalone:
00489 if (!net_info->stateless) {
00490
00491 return SOCK_CreateConnectorEx(net_info->host,
00492 net_info->port,
00493 1,
00494 0,
00495 0,
00496 net_info->debug_printout ==
00497 eDebugPrintout_Data ?
00498 fSOCK_LogOn : fSOCK_LogDefault);
00499 }
00500
00501 user_header = "Client-Mode: STATELESS_ONLY\r\n";
00502 user_header = s_AdjustNetParams(uuu->service, net_info,
00503 eReqMethod_Post, 0, 0,
00504 0, user_header, info->mime_t,
00505 info->mime_s, info->mime_e, 0);
00506 but_last = 1;
00507 break;
00508 default:
00509 user_header = 0;
00510 break;
00511 }
00512 } else {
00513 EMIME_Type mime_t;
00514 EMIME_SubType mime_s;
00515 EMIME_Encoding mime_e;
00516 if (net_info->stateless ||
00517 (info && (info->u.firewall.type & fSERV_Http))) {
00518 if (info) {
00519 req_method = info->u.firewall.type == fSERV_HttpGet
00520 ? eReqMethod_Get : (info->u.firewall.type == fSERV_HttpPost
00521 ? eReqMethod_Post : eReqMethod_Any);
00522 net_info->stateless = 1;
00523 } else
00524 req_method = eReqMethod_Any;
00525 } else
00526 req_method = eReqMethod_Get;
00527 if (info) {
00528 mime_t = info->mime_t;
00529 mime_s = info->mime_s;
00530 mime_e = info->mime_e;
00531 } else {
00532 mime_t = eMIME_T_Undefined;
00533 mime_s = eMIME_Undefined;
00534 mime_e = eENCOD_None;
00535 }
00536
00537 user_header = net_info->stateless
00538 ? "Client-Mode: STATELESS_ONLY\r\n"
00539 : "Client-Mode: STATEFUL_CAPABLE\r\n";
00540 user_header = s_AdjustNetParams(uuu->service, net_info, req_method,
00541 0, 0, 0, user_header,
00542 mime_t, mime_s, mime_e, 0);
00543 }
00544 if (!user_header)
00545 return 0;
00546
00547 if ((iter_header = SERV_Print(uuu->iter, net_info, but_last)) != 0) {
00548 size_t uh_len;
00549 if ((uh_len = strlen(user_header)) > 0) {
00550 char* ih;
00551 size_t ih_len = strlen(iter_header);
00552 if ((ih = (char*) realloc(iter_header, ih_len + uh_len + 1)) != 0){
00553 strcpy(ih + ih_len, user_header);
00554 iter_header = ih;
00555 }
00556 free((char*) user_header);
00557 }
00558 user_header = iter_header;
00559 } else if (!*user_header)
00560 user_header = 0;
00561
00562 if (uuu->user_header) {
00563 ConnNetInfo_DeleteUserHeader(net_info, uuu->user_header);
00564 free((void*) uuu->user_header);
00565 }
00566 uuu->user_header = user_header;
00567 if (!ConnNetInfo_OverrideUserHeader(net_info, user_header))
00568 return 0;
00569
00570 if (!second_try) {
00571 ConnNetInfo_ExtendUserHeader
00572 (net_info, "User-Agent: NCBIServiceConnector/"
00573 DISP_PROTOCOL_VERSION
00574 #ifdef NCBI_CXX_TOOLKIT
00575 " (C++ Toolkit)"
00576 #else
00577 " (C Toolkit)"
00578 #endif
00579 "\r\n");
00580 }
00581
00582 if (!net_info->stateless && (!info ||
00583 info->type == fSERV_Firewall ||
00584 info->type == fSERV_Ncbid)) {
00585
00586 EIO_Status status = eIO_Success;
00587 CONNECTOR conn;
00588 char val[40];
00589 CONN c;
00590
00591
00592 uuu->host = 0;
00593 uuu->port = 0;
00594 uuu->ticket = 0;
00595 net_info->max_try = 1;
00596 conn = HTTP_CreateConnectorEx(net_info,
00597 (uuu->params.flags & fHCC_Flushable)
00598 | fHCC_SureFlush,
00599 s_ParseHeader, 0,
00600 uuu, 0);
00601
00602 if (conn && (status = CONN_Create(conn, &c)) == eIO_Success) {
00603 CONN_SetTimeout(c, eIO_Open, timeout);
00604 CONN_SetTimeout(c, eIO_ReadWrite, timeout);
00605 CONN_SetTimeout(c, eIO_Close, timeout);
00606 CONN_Flush(c);
00607
00608 CONN_Close(c);
00609 } else {
00610 const char* error = conn ? IO_StatusStr(status) : 0;
00611 CORE_LOGF_X(4, eLOG_Error,
00612 ("[%s] Unable to create auxiliary HTTP %s%s%s",
00613 uuu->service, conn ? "connection" : "connector",
00614 error && *error ? ": " : "", error ? error : ""));
00615 assert(0);
00616 }
00617 if (!uuu->host)
00618 return 0;
00619 if (uuu->host == (unsigned int)(-1)) {
00620
00621 assert((!info || info->type == fSERV_Firewall) && !second_try);
00622
00623 net_info->stateless = 1;
00624 return s_Open(uuu, timeout, info, net_info, 1);
00625 }
00626 if (net_info->firewall && *net_info->proxy_host)
00627 strcpy(net_info->host, net_info->proxy_host);
00628 else if (ConnNetInfo_GetValue(net_info->service,
00629 "FWDAEMON_COMPATIBILITY",
00630 val, sizeof(val), "")
00631 && *val && (strcmp (val, "1") == 0 ||
00632 strcasecmp(val, "on") == 0 ||
00633 strcasecmp(val, "yes") == 0 ||
00634 strcasecmp(val, "true") == 0)) {
00635 assert(sizeof(kFWDaemon) <= sizeof(net_info->host));
00636 memcpy(net_info->host, kFWDaemon, sizeof(kFWDaemon));
00637 } else
00638 SOCK_ntoa(uuu->host, net_info->host, sizeof(net_info->host));
00639 net_info->port = uuu->port;
00640
00641 return SOCK_CreateConnectorEx(net_info->host,
00642 net_info->port,
00643 1,
00644 &uuu->ticket,
00645 uuu->ticket ? sizeof(uuu->ticket) : 0,
00646 net_info->debug_printout ==
00647 eDebugPrintout_Data ?
00648 fSOCK_LogOn : fSOCK_LogDefault);
00649 }
00650 return HTTP_CreateConnectorEx(net_info,
00651 (uuu->params.flags
00652 & (fHCC_Flushable | fHCC_NoAutoRetry))
00653 | fHCC_AutoReconnect,
00654 s_ParseHeader, s_AdjustNetInfo,
00655 uuu, 0);
00656 }
00657
00658
00659 static EIO_Status s_Close(CONNECTOR connector,
00660 const STimeout* timeout,
00661 int close_dispatcher)
00662 {
00663 SServiceConnector* uuu = (SServiceConnector*) connector->handle;
00664 EIO_Status status = eIO_Success;
00665
00666 if (uuu->meta.close)
00667 status = uuu->meta.close(uuu->meta.c_close, timeout);
00668
00669 if (uuu->name) {
00670 free((void*) uuu->name);
00671 uuu->name = 0;
00672 }
00673
00674 if (close_dispatcher) {
00675 if (uuu->user_header) {
00676 free((void*) uuu->user_header);
00677 uuu->user_header = 0;
00678 }
00679 if (uuu->params.reset)
00680 uuu->params.reset(uuu->params.data);
00681 s_CloseDispatcher(uuu);
00682 }
00683
00684 if (uuu->meta.list) {
00685 SMetaConnector* meta = connector->meta;
00686 METACONN_Remove(meta, uuu->meta.list);
00687 uuu->meta.list = 0;
00688 s_Reset(meta);
00689 }
00690
00691 uuu->status = status;
00692 return status;
00693 }
00694
00695
00696 static const char* s_VT_GetType(CONNECTOR connector)
00697 {
00698 SServiceConnector* uuu = (SServiceConnector*) connector->handle;
00699 return uuu->name ? uuu->name : uuu->service;
00700 }
00701
00702
00703 static EIO_Status s_VT_Open(CONNECTOR connector, const STimeout* timeout)
00704 {
00705 SServiceConnector* uuu = (SServiceConnector*) connector->handle;
00706 SMetaConnector* meta = connector->meta;
00707 EIO_Status status = eIO_Unknown;
00708 const SSERV_Info* info;
00709 SConnNetInfo* net_info;
00710 CONNECTOR conn;
00711
00712 assert(!uuu->meta.list && !uuu->name);
00713 if (!uuu->iter && !s_OpenDispatcher(uuu)) {
00714 uuu->status = status;
00715 return status;
00716 }
00717
00718 for (;;) {
00719 int stateless;
00720
00721 if (uuu->net_info->firewall && strcasecmp(uuu->iter->name, "local"))
00722 info = 0;
00723 else if (!(info = s_GetNextInfo(uuu)))
00724 break;
00725
00726 status = eIO_Unknown;
00727 if (!(net_info = ConnNetInfo_Clone(uuu->net_info)))
00728 break;
00729
00730 net_info->scheme = eURL_Unspec;
00731 conn = s_Open(uuu, timeout, info, net_info, 0);
00732 stateless = net_info->stateless;
00733
00734 ConnNetInfo_Destroy(net_info);
00735
00736 if (!conn) {
00737 if (!info)
00738 break;
00739 else
00740 continue;
00741 }
00742
00743
00744 memset(&uuu->meta, 0, sizeof(uuu->meta));
00745 METACONN_Add(&uuu->meta, conn);
00746
00747 conn->meta = meta;
00748 conn->next = meta->list;
00749 meta->list = conn;
00750
00751 CONN_SET_METHOD(meta, descr, uuu->meta.descr, uuu->meta.c_descr);
00752 CONN_SET_METHOD(meta, wait, uuu->meta.wait, uuu->meta.c_wait);
00753 CONN_SET_METHOD(meta, write, uuu->meta.write, uuu->meta.c_write);
00754 CONN_SET_METHOD(meta, flush, uuu->meta.flush, uuu->meta.c_flush);
00755 CONN_SET_METHOD(meta, read, uuu->meta.read, uuu->meta.c_read);
00756 CONN_SET_METHOD(meta, status, uuu->meta.status, uuu->meta.c_status);
00757 #ifdef IMPLEMENTED__CONN_WaitAsync
00758 CONN_SET_METHOD(meta, wait_async,
00759 uuu->meta.wait_async, uuu->meta.c_wait_async);
00760 #endif
00761 if (uuu->meta.get_type) {
00762 const char* type;
00763 if ((type = uuu->meta.get_type(uuu->meta.c_get_type)) != 0) {
00764 size_t slen = strlen(uuu->service);
00765 size_t tlen = strlen(type);
00766 char* name = (char*) malloc(slen + tlen + 2);
00767 if (name) {
00768 memcpy(name, uuu->service, slen);
00769 name[slen++] = '/';
00770 memcpy(name + slen, type, tlen);
00771 tlen += slen;
00772 name[tlen] = '\0';
00773 uuu->name = name;
00774 }
00775 }
00776 }
00777
00778 status = uuu->meta.open
00779 ? uuu->meta.open(uuu->meta.c_open, timeout) : eIO_Success;
00780 if (status == eIO_Success)
00781 break;
00782
00783 if (!stateless && (!info || info->type == fSERV_Firewall)) {
00784 const char kFWLink[] = {"http://www.ncbi.nlm.nih.gov/IEB/ToolBox/"
00785 "NETWORK/dispatcher.html#Firewalling"};
00786 CORE_LOGF_X(6, eLOG_Error,
00787 ("[%s] %s connection failed (%s) indicating possible "
00788 "firewall configuration problem; please consult <%s>",
00789 uuu->service, !info ? "Firewall" : "Stateful relay",
00790 IO_StatusStr(status), kFWLink));
00791 }
00792
00793 s_Close(connector, timeout, 0);
00794 }
00795
00796 uuu->status = status;
00797 return status;
00798 }
00799
00800
00801
00802 static EIO_Status s_VT_Status(CONNECTOR connector, EIO_Event dir)
00803 {
00804 return ((SServiceConnector*) connector->handle)->status;
00805 }
00806
00807
00808 static EIO_Status s_VT_Close(CONNECTOR connector, const STimeout* timeout)
00809 {
00810 return s_Close(connector, timeout, 1);
00811 }
00812
00813
00814 static void s_Setup(SMetaConnector *meta, CONNECTOR connector)
00815 {
00816 SServiceConnector* uuu = (SServiceConnector*) connector->handle;
00817
00818 CONN_SET_METHOD(meta, get_type, s_VT_GetType, connector);
00819 CONN_SET_METHOD(meta, open, s_VT_Open, connector);
00820 CONN_SET_METHOD(meta, close, s_VT_Close, connector);
00821 CONN_SET_DEFAULT_TIMEOUT(meta, uuu->net_info->timeout);
00822
00823 s_Reset(meta);
00824 }
00825
00826
00827 static void s_Destroy(CONNECTOR connector)
00828 {
00829 SServiceConnector* uuu = (SServiceConnector*) connector->handle;
00830
00831 if (uuu->iter)
00832 s_CloseDispatcher(uuu);
00833 if (uuu->params.cleanup)
00834 uuu->params.cleanup(uuu->params.data);
00835 ConnNetInfo_Destroy(uuu->net_info);
00836 if (uuu->name)
00837 free((void*) uuu->name);
00838 free(uuu);
00839 connector->handle = 0;
00840 free(connector);
00841 }
00842
00843
00844
00845
00846
00847
00848 extern CONNECTOR SERVICE_CreateConnectorEx
00849 (const char* service,
00850 TSERV_Type types,
00851 const SConnNetInfo* net_info,
00852 const SSERVICE_Extra* params)
00853 {
00854 char* x_service;
00855 CONNECTOR ccc;
00856 SServiceConnector* xxx;
00857
00858 if (!service || !*service || !(x_service = SERV_ServiceName(service)))
00859 return 0;
00860
00861 ccc = (SConnector*) malloc(sizeof(SConnector));
00862 xxx = (SServiceConnector*) calloc(1, sizeof(*xxx) + strlen(service));
00863
00864
00865 ccc->handle = xxx;
00866 ccc->next = 0;
00867 ccc->meta = 0;
00868 ccc->setup = s_Setup;
00869 ccc->destroy = s_Destroy;
00870
00871 xxx->types = types;
00872 xxx->net_info = (net_info
00873 ? ConnNetInfo_Clone(net_info)
00874 : ConnNetInfo_Create(service));
00875
00876 if (!ConnNetInfo_SetupStandardArgs(xxx->net_info, x_service)) {
00877 free(x_service);
00878 s_Destroy(ccc);
00879 return 0;
00880 }
00881 strcpy(xxx->service, service);
00882 free(x_service);
00883
00884
00885 if (types & fSERV_Stateless)
00886 xxx->net_info->stateless = 1;
00887 if (types & fSERV_Firewall)
00888 xxx->net_info->firewall = 1;
00889 if (!s_OpenDispatcher(xxx)) {
00890 s_Destroy(ccc);
00891 return 0;
00892 }
00893 assert(xxx->iter != 0);
00894
00895
00896 if (params)
00897 memcpy(&xxx->params, params, sizeof(xxx->params));
00898
00899
00900 return ccc;
00901 }
00902
00903