src/connect/ncbi_service_connector.c

Go to the documentation of this file.
00001 /* $Id: ncbi_service_connector.c 174743 2009-10-30 14:37:53Z lavr $
00002  * ===========================================================================
00003  *
00004  *                            PUBLIC DOMAIN NOTICE
00005  *               National Center for Biotechnology Information
00006  *
00007  *  This software/database is a "United States Government Work" under the
00008  *  terms of the United States Copyright Act.  It was written as part of
00009  *  the author's official duties as a United States Government employee and
00010  *  thus cannot be copyrighted.  This software/database is freely available
00011  *  to the public for use. The National Library of Medicine and the U.S.
00012  *  Government have not placed any restriction on its use or reproduction.
00013  *
00014  *  Although all reasonable efforts have been taken to ensure the accuracy
00015  *  and reliability of the software and data, the NLM and the U.S.
00016  *  Government do not and cannot warrant the performance or results that
00017  *  may be obtained by using this software or data. The NLM and the U.S.
00018  *  Government disclaim all warranties, express or implied, including
00019  *  warranties of performance, merchantability or fitness for any particular
00020  *  purpose.
00021  *
00022  *  Please cite the author in any work or product based on this material.
00023  *
00024  * ===========================================================================
00025  *
00026  * Author:  Anton Lavrentiev
00027  *
00028  * File Description:
00029  *   Implementation of CONNECTOR to a named service
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;               /* Verbal connector type             */
00050     TSERV_Type      types;              /* Server types, record keeping only */
00051     SConnNetInfo*   net_info;           /* Connection information            */
00052     const char*     user_header;        /* User header currently set         */
00053     SERV_ITER       iter;               /* Dispatcher information            */
00054     SMetaConnector  meta;               /* Low level comm.conn and its VT    */
00055     EIO_Status      status;             /* Status of last op                 */
00056     unsigned int    host;               /* Parsed connection info... (n.b.o) */
00057     unsigned short  port;               /*                       ... (h.b.o) */
00058     ticket_t        ticket;             /* Network byte order (none if zero) */
00059     SSERVICE_Extra  params;
00060     char            service[1];         /* Untranslated service name         */
00061 } SServiceConnector;
00062 
00063 
00064 /***********************************************************************
00065  *  INTERNAL -- "s_VT_*" functions for the "virt. table" of connector methods
00066  ***********************************************************************/
00067 
00068 #ifdef __cplusplus
00069 extern "C" {
00070 #endif /* __cplusplus */
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 } /* extern "C" */
00083 #endif /* __cplusplus */
00084 
00085 
00086 static int/*bool*/ 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/*false*/;
00093     }
00094     return 1/*true*/;
00095 }
00096 
00097 
00098 static void s_CloseDispatcher(SServiceConnector* uuu)
00099 {
00100     SERV_Close(uuu->iter);
00101     uuu->iter = 0;
00102 }
00103 
00104 
00105 /* Reset functions, which are implemented only in transport
00106  * connectors, but not in this connector.
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 /* __cplusplus */
00127 
00128 static int/*bool*/ 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/*parsed okay*/;
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/*failed - duplicate connection info*/;
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                 /* Special keyword for switching into stateless mode */
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/*failed - unreadable connection info*/;
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/*failed - bad host:port in connection info*/;
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/*success*/;
00181 
00182     uuu->host = 0;
00183     return 0/*failure*/;
00184 }
00185 
00186 
00187 /*ARGSUSED*/
00188 static int/*bool*/ 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/*true*/;
00253         }
00254     }
00255     return 0/*false*/;
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/*freed!*/)
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/*EOL*/);
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 /* Although all additional HTTP tags that comprise dispatching have
00323  * default values, which in most cases are fine with us, we will use
00324  * these tags explicitly to distinguish the calls originated within the
00325  * service connector from other calls (by Web browsers, for example), and
00326  * let the dispatcher to decide whether to use more expensive dispatching
00327  * (involving loopback connections) in the latter case.
00328  */
00329 
00330 #ifdef __cplusplus
00331 extern "C" {
00332     static int s_AdjustNetInfo(SConnNetInfo*, void*, unsigned int);
00333 }
00334 #endif /* __cplusplus */
00335 
00336 /*ARGSUSED*/
00337 /* This callback is only for services called via direct HTTP */
00338 static int/*bool*/ 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); /* paranoid assertion :-) */
00347     if (uuu->net_info->firewall  &&  !uuu->net_info->stateless)
00348         return 0; /*cannot adjust firewall stateful client*/
00349 
00350     for (;;) {
00351         if (!(info = s_GetNextInfo(uuu)))
00352             return 0/*false - not adjusted*/;
00353         /* Skip any 'stateful_capable' or unconnectable entries here,
00354          * which might have left behind by either a failed stateful
00355          * dispatching with a fallback to stateless HTTP mode or
00356          * a too relaxed server type selection */
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"; /*default*/
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"; /*default*/
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"; /*default*/
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/*false - not adjusted*/;
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/*false - not adjusted*/;
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/*false*/;
00431 
00432     return 1/*true - adjusted*/;
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/*bool*/        second_try)
00441 {
00442     int/*bool*/ but_last = 0/*false*/;
00443     const char* user_header; /* either "" or non-empty dynamic string */
00444     char*       iter_header;
00445     EReqMethod  req_method;
00446 
00447     if (info  &&  info->type != fSERV_Firewall) {
00448         /* Not a firewall/relay connection here */
00449         assert(!second_try);
00450         /* We know the connection point, let's try to use it! */
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             /* Connection directly to NCBID, add NCBID-specific tags */
00459             if (net_info->stateless) {
00460                 /* Connection request with data */
00461                 user_header = "Connection-Mode: STATELESS\r\n"; /*default*/
00462                 req_method  = eReqMethod_Post;
00463             } else {
00464                 /* We will be waiting for conn-info back */
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             /* Connection directly to CGI */
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"; /*default*/
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                 /* We create SOCKET connector here */
00491                 return SOCK_CreateConnectorEx(net_info->host,
00492                                               net_info->port,
00493                                               1/*max.try*/,
00494                                               0/*init.data*/,
00495                                               0/*data.size*/,
00496                                               net_info->debug_printout ==
00497                                               eDebugPrintout_Data ?
00498                                               fSOCK_LogOn : fSOCK_LogDefault);
00499             }
00500             /* Otherwise, it will be a pass-thru connection via dispatcher */
00501             user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/
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/*true*/;
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/*true*/;
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         /* Firewall/relay connection to dispatcher, special tags */
00537         user_header = net_info->stateless
00538             ? "Client-Mode: STATELESS_ONLY\r\n" /*default*/
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; /* special case of assignment of literal "" */
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         /* HTTP connector is auxiliary only */
00586         EIO_Status status = eIO_Success;
00587         CONNECTOR conn;
00588         char val[40];
00589         CONN c;
00590 
00591         /* Clear connection info */
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/*flags*/,
00599                                       s_ParseHeader, 0/*adj.info*/,
00600                                       uuu/*adj.data*/, 0/*cleanup.data*/);
00601         /* Wait for connection info back (error-transparent by DISPD.CGI) */
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             /* This also triggers parse header callback */
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/*failed, no connection info returned*/;
00619         if (uuu->host == (unsigned int)(-1)) {
00620             /* Firewall mode only in stateful mode, fallback requested */
00621             assert((!info  ||  info->type == fSERV_Firewall)  &&  !second_try);
00622             /* Try to use stateless mode instead */
00623             net_info->stateless = 1/*true*/;
00624             return s_Open(uuu, timeout, info, net_info, 1/*second try*/);
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         /* Build and return target SOCKET connector */
00641         return SOCK_CreateConnectorEx(net_info->host,
00642                                       net_info->port,
00643                                       1/*max.try*/,
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/*adj.data*/, 0/*cleanup.data*/);
00656 }
00657 
00658 
00659 static EIO_Status s_Close(CONNECTOR       connector,
00660                           const STimeout* timeout,
00661                           int/*bool*/     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/*!second_try*/);
00732         stateless = net_info->stateless;
00733 
00734         ConnNetInfo_Destroy(net_info);
00735 
00736         if (!conn) {
00737             if (!info/* same as uuu->net_info->firewall*/)
00738                 break;
00739             else
00740                 continue;
00741         }
00742 
00743         /* Setup the new connector on a temporary meta-connector... */
00744         memset(&uuu->meta, 0, sizeof(uuu->meta));
00745         METACONN_Add(&uuu->meta, conn);
00746         /* ...then link it in using current connection's meta */
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/*don't close dispatcher yet!*/);
00794     }
00795 
00796     uuu->status = status;
00797     return status;
00798 }
00799 
00800 
00801 /*ARGSUSED*/
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/*close_dispatcher*/);
00811 }
00812 
00813 
00814 static void s_Setup(SMetaConnector *meta, CONNECTOR connector)
00815 {
00816     SServiceConnector* uuu = (SServiceConnector*) connector->handle;
00817     /* initialize virtual table */
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     /* all the rest is reset to NULL */
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  *  EXTERNAL -- the connector's "constructor"
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     /* initialize connector structures */
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     /* now get ready for first probe dispatching */
00885     if (types & fSERV_Stateless)
00886         xxx->net_info->stateless = 1/*true*/;
00887     if (types & fSERV_Firewall)
00888         xxx->net_info->firewall = 1/*true*/;
00889     if (!s_OpenDispatcher(xxx)) {
00890         s_Destroy(ccc);
00891         return 0;
00892     }
00893     assert(xxx->iter != 0);
00894 
00895     /* finally, store all callback parameters */
00896     if (params)
00897         memcpy(&xxx->params, params, sizeof(xxx->params));
00898 
00899     /* done */
00900     return ccc;
00901 }
00902 
00903 

Generated on Sun Dec 6 22:22:10 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Mon Dec 07 16:20:56 2009 by modify_doxy.py rev. 173732