ncbi_service_connector.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:38k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_service_connector.c,v $
  4.  * PRODUCTION Revision 1000.0  2003/10/29 16:39:51  gouriano
  5.  * PRODUCTION PRODUCTION: IMPORTED [ORIGINAL] Dev-tree R6.60
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_service_connector.c,v 1000.0 2003/10/29 16:39:51 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Anton Lavrentiev
  35.  *
  36.  * File Description:
  37.  *   Implementation of CONNECTOR to a named service
  38.  *
  39.  */
  40. #include "ncbi_ansi_ext.h"
  41. #include "ncbi_comm.h"
  42. #include "ncbi_priv.h"
  43. #include "ncbi_servicep.h"
  44. #include <connect/ncbi_http_connector.h>
  45. #include <connect/ncbi_service_connector.h>
  46. #include <connect/ncbi_socket_connector.h>
  47. #include <ctype.h>
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. typedef struct SServiceConnectorTag {
  51.     const char*     name;               /* Verbal connector type             */
  52.     const char*     service;            /* Service name (final) to use       */
  53.     TSERV_Type      types;              /* Server types, record keeping only */
  54.     SConnNetInfo*   net_info;           /* Connection information            */
  55.     const char*     user_header;        /* User header currently set         */
  56.     SERV_ITER       iter;               /* Dispatcher information            */
  57.     SMetaConnector  meta;               /* Low level comm.conn and its VT    */
  58.     EIO_Status      status;             /* Status of last op                 */
  59.     unsigned int    host;               /* Parsed connection info...         */
  60.     unsigned short  port;
  61.     ticket_t        ticket;
  62.     SSERVICE_Extra  params;
  63.     char            args[1];            /* Additional CGI parameters         */
  64. } SServiceConnector;
  65. /***********************************************************************
  66.  *  INTERNAL -- "s_VT_*" functions for the "virt. table" of connector methods
  67.  ***********************************************************************/
  68. #ifdef __cplusplus
  69. extern "C" {
  70. #endif /* __cplusplus */
  71.     static const char* s_VT_GetType (CONNECTOR       connector);
  72.     static EIO_Status  s_VT_Open    (CONNECTOR       connector,
  73.                                      const STimeout* timeout);
  74.     static EIO_Status  s_VT_Status  (CONNECTOR       connector,
  75.                                      EIO_Event       dir);
  76.     static EIO_Status  s_VT_Close   (CONNECTOR       connector,
  77.                                      const STimeout* timeout);
  78.     static void        s_Setup      (SMetaConnector* meta,
  79.                                      CONNECTOR       connector);
  80.     static void        s_Destroy    (CONNECTOR       connector);
  81. #ifdef __cplusplus
  82. } /* extern "C" */
  83. #endif /* __cplusplus */
  84. static char* s_GetArgs(const char* client_host)
  85. {
  86.     static const char platform[] = "&platform=";
  87.     static const char address[]  = "address=";
  88.     size_t nodelen, archlen, buflen;
  89.     const char* arch;
  90.     unsigned int ip;
  91.     char addr[80];
  92.     char* p;
  93.     buflen = 0;
  94.     if (*client_host) {
  95.         nodelen = strlen(client_host);
  96.         buflen += sizeof(address) - 1 + nodelen;
  97.         if (!strchr(client_host, '.')                   &&
  98.             (ip = SOCK_gethostbyname(client_host)) != 0 &&
  99.             SOCK_ntoa(ip, addr, sizeof(addr))      == 0) {
  100.             buflen += strlen(addr) + 2;
  101.         } else
  102.             *addr = 0;
  103.     } else
  104.         nodelen = 0;
  105.     if ((arch = CORE_GetPlatform()) != 0 && *arch) {
  106.         archlen = strlen(arch);
  107.         buflen += sizeof(platform) - 1 + archlen;
  108.     } else
  109.         archlen = 0;
  110.     if (!buflen || !(p = (char*) malloc(buflen + 1)))
  111.         return 0;
  112.     buflen = 0;
  113.     if (nodelen) {
  114.         strcpy(&p[buflen], address);
  115.         buflen += sizeof(address) - 1;
  116.         strcpy(&p[buflen], client_host);
  117.         buflen += nodelen;
  118.         if (*addr)
  119.             buflen += sprintf(&p[buflen], "(%s)", addr);
  120.     }
  121.     if (archlen) {
  122.         strcpy(&p[buflen], nodelen ? platform : platform + 1);
  123.         buflen += nodelen ? sizeof(platform) - 1 : sizeof(platform) - 2;
  124.         strcpy(&p[buflen], arch);
  125.         buflen += archlen;
  126.     }
  127.     return p;
  128. }
  129. static int/*bool*/ s_OpenDispatcher(SServiceConnector* uuu)
  130. {
  131.     uuu->user_header = 0;
  132.     if (!(uuu->iter = SERV_OpenEx(uuu->service, uuu->types,
  133.                                   SERV_LOCALHOST, uuu->net_info, 0, 0)))
  134.         return 0/*false*/;
  135.     return 1/*true*/;
  136. }
  137. static void s_CloseDispatcher(SServiceConnector* uuu)
  138. {
  139.     if (uuu->user_header) {
  140.         free((void*) uuu->user_header);
  141.         uuu->user_header = 0;
  142.     }
  143.     SERV_Close(uuu->iter);
  144.     uuu->iter = 0;
  145. }
  146. /* Reset functions, which are implemented only in transport
  147.  * connectors, but not in this connector.
  148.  */
  149. static void s_Reset(SMetaConnector *meta)
  150. {
  151.     CONN_SET_METHOD(meta, descr,      0,             0);
  152.     CONN_SET_METHOD(meta, wait,       0,             0);
  153.     CONN_SET_METHOD(meta, write,      0,             0);
  154.     CONN_SET_METHOD(meta, flush,      0,             0);
  155.     CONN_SET_METHOD(meta, read,       0,             0);
  156.     CONN_SET_METHOD(meta, status,     s_VT_Status,   0);
  157. #ifdef IMPLEMENTED__CONN_WaitAsync
  158.     CONN_SET_METHOD(meta, wait_async, 0,             0);
  159. #endif
  160. }
  161. #ifdef __cplusplus
  162. extern "C" {
  163.     static int s_ParseHeader(const char*, void*, int);
  164. }
  165. #endif /* __cplusplus */
  166. static int/*bool*/ s_ParseHeader(const char* header,
  167.                                  void*       data,
  168.                                  int/*bool*/ server_error)
  169. {
  170.     static const char kStateless[] = "TRY_STATELESS";
  171.     SServiceConnector* uuu = (SServiceConnector*) data;
  172.     SERV_Update(uuu->iter, header);
  173.     if (server_error)
  174.         return 1/*parsed okay*/;
  175.     while (header && *header) {
  176.         if (strncasecmp(header, HTTP_CONNECTION_INFO,
  177.                         sizeof(HTTP_CONNECTION_INFO) - 1) == 0) {
  178.             unsigned int  i1, i2, i3, i4, ticket;
  179.             unsigned char o1, o2, o3, o4;
  180.             char ipaddr[32];
  181.             header += sizeof(HTTP_CONNECTION_INFO) - 1;
  182.             while (*header && isspace((unsigned char)(*header)))
  183.                 header++;
  184.             if (strncasecmp(header, kStateless, sizeof(kStateless) - 1) == 0) {
  185.                 /* Special keyword for switching into stateless mode */
  186.                 uuu->host = (unsigned int)(-1);
  187. #if defined(_DEBUG) && !defined(NDEBUG)
  188.                 if (uuu->net_info->debug_printout)
  189.                     CORE_LOG(eLOG_Warning,
  190.                              "[SERVICE]  Fallback to stateless requested");
  191. #endif
  192.                 break;
  193.             }
  194.             if (sscanf(header, "%u.%u.%u.%u %hu %x",
  195.                        &i1, &i2, &i3, &i4, &uuu->port, &ticket) < 6)
  196.                 return 0/*failed*/;
  197.             o1 = i1; o2 = i2; o3 = i3; o4 = i4;
  198.             sprintf(ipaddr, "%u.%u.%u.%u", o1, o2, o3, o4);
  199.             uuu->host = SOCK_gethostbyname(ipaddr);
  200.             uuu->ticket = SOCK_htonl(ticket);
  201.             break;
  202.         }
  203.         if ((header = strchr(header, 'n')) != 0)
  204.             header++;
  205.     }
  206.     return 1/*success*/;
  207. }
  208. static char* s_AdjustNetParams(SConnNetInfo*  net_info,
  209.                                EReqMethod     req_method,
  210.                                const char*    cgi_name,
  211.                                const char*    service,
  212.                                const char*    args,
  213.                                const char*    cgi_args,
  214.                                const char*    static_header,
  215.                                EMIME_Type     mime_t,
  216.                                EMIME_SubType  mime_s,
  217.                                EMIME_Encoding mime_e,
  218.                                char*          dynamic_header/*will be freed*/)
  219. {
  220.     char content_type[MAX_CONTENT_TYPE_LEN], *retval;
  221.     net_info->req_method = req_method;
  222.     if (cgi_name)
  223.         strncpy0(net_info->path, cgi_name, sizeof(net_info->path) - 1);
  224.     if (cgi_args)
  225.         strncpy0(net_info->args, cgi_args, sizeof(net_info->args) - 1);
  226.     if (service) {
  227.         ConnNetInfo_PrependArg(net_info, args, 0);
  228.         if (!ConnNetInfo_PreOverrideArg(net_info, "service", service)) {
  229.             const char* a = args ? strrchr(args, '&') : 0;
  230.             if (!a)
  231.                 a = args;
  232.             while (a) {
  233.                 ConnNetInfo_DeleteArg(net_info, a + (*a == '&' ? 1 : 0));
  234.                 if (ConnNetInfo_PreOverrideArg(net_info, "service", service))
  235.                     break;
  236.                 if (a != args) {
  237.                     while (a > args) {
  238.                         if (*--a == '&')
  239.                             break;
  240.                     }
  241.                 } else
  242.                     a = 0;
  243.             }
  244.             if (!a) {
  245.                 if (dynamic_header)
  246.                     free(dynamic_header);
  247.                 return 0/*failed*/;
  248.             }
  249.         }
  250.     }
  251.     if (mime_t == SERV_MIME_TYPE_UNDEFINED    ||
  252.         mime_s == SERV_MIME_SUBTYPE_UNDEFINED ||
  253.         !MIME_ComposeContentTypeEx(mime_t, mime_s, mime_e,
  254.                                    content_type, sizeof(content_type))) {
  255.         *content_type = 0;
  256.     }
  257.     if ((retval = (char*) malloc((static_header ? strlen(static_header) : 0) +
  258.                                  strlen(content_type) + 1/*EOL*/ +
  259.                                  (dynamic_header? strlen(dynamic_header) : 0)
  260.                                  )) != 0) {
  261.         strcpy(retval, static_header ? static_header : "");
  262.         strcat(retval, content_type);
  263.         strcat(retval, dynamic_header ? dynamic_header : "");
  264.     }
  265.     if (dynamic_header)
  266.         free(dynamic_header);
  267.     return retval;
  268. }
  269. static const SSERV_Info* s_GetNextInfo(SServiceConnector* uuu)
  270. {
  271.     if (uuu->params.get_next_info)
  272.         return uuu->params.get_next_info(uuu->iter, uuu->params.data);
  273.     else
  274.         return SERV_GetNextInfo(uuu->iter);
  275. }
  276. /* Although all additional HTTP tags, which comprise dispatching, have
  277.  * default values, which in most cases are fine with us, we will use
  278.  * these tags explicitly to distinguish calls originated from within the
  279.  * service connector from the calls from a Web browser, for example.
  280.  * This technique allows the dispatcher to decide whether to use more
  281.  * expensive dispatching (inlovling loopback connections) in case of browser.
  282.  */
  283. #ifdef __cplusplus
  284. extern "C" {
  285.     static int s_AdjustNetInfo(SConnNetInfo*, void*, unsigned int);
  286. }
  287. #endif /* __cplusplus */
  288. /* This callback is only for services called via direct HTTP */
  289. static int/*bool*/ s_AdjustNetInfo(SConnNetInfo* net_info,
  290.                                    void*         data,
  291.                                    unsigned int  n)
  292. {
  293.     SServiceConnector* uuu = (SServiceConnector*) data;
  294.     const char* user_header = 0;
  295.     const SSERV_Info* info;
  296.     assert(n != 0); /* paranoid assertion :-) */
  297.     if (net_info->firewall && !net_info->stateless)
  298.         return 0; /*cannot adjust firewall stateful client*/
  299.     for (;;) {
  300.         if (!(info = s_GetNextInfo(uuu)))
  301.             return 0/*false - not adjusted*/;
  302.         /* Skip any 'stateful_capable' entries here, which might
  303.          * have left behind a failed stateful dispatching with a
  304.          * fallback to stateless HTTP mode */
  305.         if (!info->sful)
  306.             break;
  307.     }
  308.     {{
  309.         char* iter_header = SERV_Print(uuu->iter);
  310.         switch (info->type) {
  311.         case fSERV_Ncbid:
  312.             user_header = "Connection-Mode: STATELESSrn"; /*default*/
  313.             user_header = s_AdjustNetParams(net_info, eReqMethod_Post,
  314.                                             NCBID_WEBPATH,
  315.                                             uuu->service, uuu->args,
  316.                                             SERV_NCBID_ARGS(&info->u.ncbid),
  317.                                             user_header, info->mime_t,
  318.                                             info->mime_s, info->mime_e,
  319.                                             iter_header);
  320.             break;
  321.         case fSERV_Http:
  322.         case fSERV_HttpGet:
  323.         case fSERV_HttpPost:
  324.             user_header = "Client-Mode: STATELESS_ONLYrn"; /*default*/
  325.             user_header = s_AdjustNetParams(net_info,
  326.                                             info->type == fSERV_HttpGet
  327.                                             ? eReqMethod_Get
  328.                                             : (info->type == fSERV_HttpPost
  329.                                                ? eReqMethod_Post
  330.                                                : eReqMethod_Any),
  331.                                             SERV_HTTP_PATH(&info->u.http),
  332.                                             0, 0,
  333.                                             SERV_HTTP_ARGS(&info->u.http),
  334.                                             user_header, info->mime_t,
  335.                                             info->mime_s, info->mime_e,
  336.                                             iter_header);
  337.             break;
  338.         case fSERV_Standalone:
  339.         case fSERV_Firewall:
  340.             user_header = "Client-Mode: STATELESS_ONLYrn"; /*default*/
  341.             user_header = s_AdjustNetParams(net_info, eReqMethod_Post,
  342.                                             uuu->net_info->path,
  343.                                             uuu->service, uuu->args,
  344.                                             uuu->net_info->args,
  345.                                             user_header, info->mime_t,
  346.                                             info->mime_s, info->mime_e,
  347.                                             iter_header);
  348.             break;
  349.         default:
  350.             assert(0);
  351.             if (iter_header)
  352.                 free(iter_header);
  353.             break;
  354.         }
  355.     }}
  356.     if (!user_header)
  357.         return 0/*false - not adjusted*/;
  358.     if (uuu->user_header) {
  359.         ConnNetInfo_DeleteUserHeader(net_info, uuu->user_header);
  360.         free((void*) uuu->user_header);
  361.     }
  362.     uuu->user_header = user_header;
  363.     if (!ConnNetInfo_OverrideUserHeader(net_info, user_header))
  364.         return 0/*false - not adjusted*/;
  365.     if (info->type == fSERV_Ncbid || (info->type & fSERV_Http) != 0) {
  366.         SOCK_ntoa(info->host, net_info->host, sizeof(net_info->host));
  367.         net_info->port = info->port;
  368.     } else {
  369.         strcpy(net_info->host, uuu->net_info->host);
  370.         net_info->port = uuu->net_info->port;
  371.     }
  372.     if (net_info->http_proxy_adjusted)
  373.         net_info->http_proxy_adjusted = 0/*false*/;
  374.     return 1/*true - adjusted*/;
  375. }
  376. static CONNECTOR s_Open(SServiceConnector* uuu,
  377.                         const STimeout*    timeout,
  378.                         const SSERV_Info*  info,
  379.                         SConnNetInfo*      net_info,
  380.                         int/*bool*/        second_try)
  381. {
  382.     const char* user_header = 0; /*may assign "", or be non-empty dynamic str*/
  383.     EReqMethod  req_method;
  384.     if (info && info->type != fSERV_Firewall) {
  385.         /* Not a firewall/relay connection here */
  386.         assert(!net_info->firewall && !second_try);
  387.         /* We know the connection point, let's try to use it! */
  388.         SOCK_ntoa(info->host, net_info->host, sizeof(net_info->host));
  389.         net_info->port = info->port;
  390.         switch (info->type) {
  391.         case fSERV_Ncbid:
  392.             /* Connection directly to NCBID, add NCBID-specific tags */
  393.             if (net_info->stateless) {
  394.                 /* Connection request with data */
  395.                 user_header = "Connection-Mode: STATELESSrn"; /*default*/
  396.                 req_method = eReqMethod_Post;
  397.             } else {
  398.                 /* We will wait for conn-info back */
  399.                 user_header = "Connection-Mode: STATEFULrn";
  400.                 req_method = eReqMethod_Get;
  401.             }
  402.             user_header = s_AdjustNetParams(net_info, req_method,
  403.                                             NCBID_WEBPATH,
  404.                                             uuu->service, uuu->args,
  405.                                             SERV_NCBID_ARGS(&info->u.ncbid),
  406.                                             user_header, info->mime_t,
  407.                                             info->mime_s, info->mime_e, 0);
  408.             if (!user_header)
  409.                 return 0;
  410.             break;
  411.         case fSERV_Http:
  412.         case fSERV_HttpGet:
  413.         case fSERV_HttpPost:
  414.             /* Connection directly to CGI */
  415.             user_header = "Client-Mode: STATELESS_ONLYrn"; /*default*/
  416.             req_method = info->type == fSERV_HttpGet
  417.                 ? eReqMethod_Get : (info->type == fSERV_HttpPost
  418.                                     ? eReqMethod_Post : eReqMethod_Any);
  419.             user_header = s_AdjustNetParams(net_info, req_method,
  420.                                             SERV_HTTP_PATH(&info->u.http),
  421.                                             0, 0,
  422.                                             SERV_HTTP_ARGS(&info->u.http),
  423.                                             user_header, info->mime_t,
  424.                                             info->mime_s, info->mime_e, 0);
  425.             if (!user_header)
  426.                 return 0;
  427.             break;
  428.         case fSERV_Standalone:
  429.             if (net_info->stateless) {
  430.                 /* This will be a pass-thru connection, socket otherwise */
  431.                 user_header = "Client-Mode: STATELESS_ONLYrn"; /*default*/
  432.                 user_header = s_AdjustNetParams(net_info, eReqMethod_Post, 0,
  433.                                                 uuu->service, uuu->args,
  434.                                                 0, user_header, info->mime_t,
  435.                                                 info->mime_s, info->mime_e, 0);
  436.                 if (!user_header)
  437.                     return 0;
  438.             }
  439.             break;
  440.         default:
  441.             assert(0);
  442.             return 0;
  443.         }
  444.     } else {
  445.         EMIME_Type     mime_t;
  446.         EMIME_SubType  mime_s;
  447.         EMIME_Encoding mime_e;
  448.         if (net_info->stateless ||
  449.             (info && (info->u.firewall.type & fSERV_Http))) {
  450.             if (info) {
  451.                 req_method = info->u.firewall.type == fSERV_HttpGet
  452.                     ? eReqMethod_Get : (info->u.firewall.type == fSERV_HttpPost
  453.                                         ? eReqMethod_Post : eReqMethod_Any);
  454.                 net_info->stateless = 1/*true*/;
  455.             } else
  456.                 req_method = eReqMethod_Any;
  457.         } else
  458.             req_method = eReqMethod_Get;
  459.         if (info) {
  460.             mime_t = info->mime_t;
  461.             mime_s = info->mime_s;
  462.             mime_e = info->mime_e;
  463.         } else {
  464.             mime_t = SERV_MIME_TYPE_UNDEFINED;
  465.             mime_s = SERV_MIME_SUBTYPE_UNDEFINED;
  466.             mime_e = eENCOD_None;
  467.         }
  468.         /* Firewall/relay connection to dispatcher, special tags */
  469.         user_header = net_info->stateless
  470.             ? "Client-Mode: STATELESS_ONLYrn" /*default*/
  471.             : "Client-Mode: STATEFUL_CAPABLErn";
  472.         user_header = s_AdjustNetParams(net_info, req_method, 0,
  473.                                         second_try ? 0 : uuu->service,
  474.                                         second_try ? 0 : uuu->args,
  475.                                         0, user_header,
  476.                                         mime_t, mime_s, mime_e, 0);
  477.         if (!user_header)
  478.             return 0;
  479.     }
  480.     if (user_header) {
  481.         /* We create HTTP connector here */
  482.         char* iter_header = SERV_Print(uuu->iter);
  483.         size_t n;
  484.         if (iter_header /*NB: <CR><LF>-terminated*/) {
  485.             if ((n = strlen(user_header)) > 0) {
  486.                 if ((iter_header = (char*)
  487.                      realloc(iter_header, strlen(iter_header) + n + 1)) != 0)
  488.                     strcat(iter_header, user_header);
  489.                 free((char*) user_header);
  490.             }
  491.             user_header = iter_header;
  492.         } else if (!*user_header)
  493.             user_header = 0; /* special case of assignment of literal "" */
  494.         if (uuu->user_header) {
  495.             ConnNetInfo_DeleteUserHeader(net_info, uuu->user_header);
  496.             free((void*) uuu->user_header);
  497.         }
  498.         uuu->user_header = user_header;
  499.         if (!ConnNetInfo_OverrideUserHeader(net_info, user_header))
  500.             return 0;
  501.         if (!second_try) {
  502.             ConnNetInfo_ExtendUserHeader
  503.                 (net_info, "User-Agent: NCBIServiceConnector/"
  504.                  DISP_PROTOCOL_VERSION
  505. #ifdef NCBI_CXX_TOOLKIT
  506.                  " (C++ Toolkit)"
  507. #else
  508.                  " (C Toolkit)"
  509. #endif
  510.                  "rn");
  511.         }
  512.         if (!net_info->stateless && (!info                        ||
  513.                                      info->type == fSERV_Firewall ||
  514.                                      info->type == fSERV_Ncbid)) {
  515.             /* HTTP connector is auxiliary only */
  516.             CONNECTOR conn;
  517.             CONN c;
  518.             /* Clear connection info */
  519.             uuu->host = 0;
  520.             uuu->port = 0;
  521.             uuu->ticket = 0;
  522.             net_info->max_try = 1;
  523.             conn = HTTP_CreateConnectorEx(net_info, fHCC_SureFlush/*flags*/,
  524.                                           s_ParseHeader, 0/*adj.info*/,
  525.                                           uuu/*adj.data*/, 0/*cleanup.data*/);
  526.             /* Wait for connection info back (error-transparent by DISPD.CGI)*/
  527.             if (conn && CONN_Create(conn, &c) == eIO_Success) {
  528.                 CONN_SetTimeout(c, eIO_Open,      timeout);
  529.                 CONN_SetTimeout(c, eIO_ReadWrite, timeout);
  530.                 CONN_SetTimeout(c, eIO_Close,     timeout);
  531.                 CONN_Flush(c);
  532.                 /* This also triggers parse header callback */
  533.                 CONN_Close(c);
  534.             } else {
  535.                 CORE_LOGF(eLOG_Error, ("[SERVICE]  Unable to create aux. %s",
  536.                                        conn ? "connection" : "connector"));
  537.                 assert(0);
  538.             }
  539.             if (!uuu->host)
  540.                 return 0/*failed, no connection info returned*/;
  541.             if (uuu->host == (unsigned int)(-1)) {
  542.                 /* Firewall mode only in stateful mode, fallback requested */
  543.                 assert((!info || info->type == fSERV_Firewall) && !second_try);
  544.                 /* Try to use stateless mode instead */
  545.                 net_info->stateless = 1/*true*/;
  546.                 return s_Open(uuu, timeout, info, net_info, 1/*second try*/);
  547.             }
  548.             if (net_info->firewall && *net_info->proxy_host)
  549.                 strcpy(net_info->host, net_info->proxy_host);
  550.             else
  551.                 SOCK_ntoa(uuu->host, net_info->host, sizeof(net_info->host));
  552.             net_info->port = uuu->port;
  553.             /* Build and return target SOCKET connector */
  554.             return SOCK_CreateConnectorEx(net_info->host, net_info->port,
  555.                                           1/*max.try*/,
  556.                                           &uuu->ticket, sizeof(uuu->ticket),
  557.                                           net_info->debug_printout ==
  558.                                           eDebugPrintout_Data
  559.                                           ? eSCC_DebugPrintout : 0);
  560.         }
  561.         net_info->max_try = uuu->net_info->max_try;
  562.         return HTTP_CreateConnectorEx(net_info, fHCC_AutoReconnect,
  563.                                       s_ParseHeader, s_AdjustNetInfo,
  564.                                       uuu/*adj.data*/, 0/*cleanup.data*/);
  565.     }
  566.     /* We create SOCKET connector here */
  567.     return SOCK_CreateConnectorEx(net_info->host, net_info->port,
  568.                                   1/*max.try*/, 0/*init.data*/, 0/*data.size*/,
  569.                                   net_info->debug_printout ==
  570.                                   eDebugPrintout_Data ? eSCC_DebugPrintout :0);
  571. }
  572. static EIO_Status s_Close(CONNECTOR       connector,
  573.                           const STimeout* timeout,
  574.                           int/*bool*/     close_dispatcher)
  575. {
  576.     SServiceConnector* uuu = (SServiceConnector*) connector->handle;
  577.     EIO_Status status = eIO_Success;
  578.     if (uuu->meta.close)
  579.         status = uuu->meta.close(uuu->meta.c_close, timeout);
  580.     if (uuu->name) {
  581.         free((void*) uuu->name);
  582.         uuu->name = 0;
  583.     }
  584.     if (close_dispatcher) {
  585.         s_CloseDispatcher(uuu);
  586.         if (uuu->params.reset)
  587.             uuu->params.reset(uuu->params.data);
  588.     }
  589.     if (uuu->meta.list) {
  590.         SMetaConnector* meta = connector->meta;
  591.         METACONN_Remove(meta, uuu->meta.list);
  592.         uuu->meta.list = 0;
  593.         s_Reset(meta);
  594.     }
  595.     uuu->status = status;
  596.     return status;
  597. }
  598. static const char* s_VT_GetType(CONNECTOR connector)
  599. {
  600.     SServiceConnector* uuu = (SServiceConnector*) connector->handle;
  601.     return uuu->name ? uuu->name : "SERVICE";
  602. }
  603. static EIO_Status s_VT_Open(CONNECTOR connector, const STimeout* timeout)
  604. {
  605.     SServiceConnector* uuu = (SServiceConnector*) connector->handle;
  606.     SMetaConnector* meta = connector->meta;
  607.     EIO_Status status = eIO_Unknown;
  608.     const SSERV_Info* info;
  609.     SConnNetInfo* net_info;
  610.     CONNECTOR conn;
  611.     assert(!uuu->meta.list && !uuu->name);
  612.     if (!uuu->iter && !s_OpenDispatcher(uuu)) {
  613.         uuu->status = status;
  614.         return status;
  615.     }
  616.     for (;;) {
  617.         if (uuu->net_info->firewall)
  618.             info = 0;
  619.         else if (!(info = s_GetNextInfo(uuu)))
  620.             break;
  621.         status = eIO_Unknown;
  622.         if (!(net_info = ConnNetInfo_Clone(uuu->net_info)))
  623.             break;
  624.         conn = s_Open(uuu, timeout, info, net_info, 0/*second_try - false*/);
  625.         ConnNetInfo_Destroy(net_info);
  626.         if (!conn) {
  627.             if (uuu->net_info->firewall)
  628.                 break;
  629.             else
  630.                 continue;
  631.         }
  632.         /* Setup the new connector on a temporary meta-connector... */
  633.         memset(&uuu->meta, 0, sizeof(uuu->meta));
  634.         METACONN_Add(&uuu->meta, conn);
  635.         /* ...then link the new connector in using current connection's meta */
  636.         conn->meta = meta;
  637.         conn->next = meta->list;
  638.         meta->list = conn;
  639.         CONN_SET_METHOD(meta, descr,  uuu->meta.descr,  uuu->meta.c_descr);
  640.         CONN_SET_METHOD(meta, wait,   uuu->meta.wait,   uuu->meta.c_wait);
  641.         CONN_SET_METHOD(meta, write,  uuu->meta.write,  uuu->meta.c_write);
  642.         CONN_SET_METHOD(meta, flush,  uuu->meta.flush,  uuu->meta.c_flush);
  643.         CONN_SET_METHOD(meta, read,   uuu->meta.read,   uuu->meta.c_read);
  644.         CONN_SET_METHOD(meta, status, uuu->meta.status, uuu->meta.c_status);
  645. #ifdef IMPLEMENTED__CONN_WaitAsync
  646.         CONN_SET_METHOD(meta, wait_async,
  647.                         uuu->meta.wait_async, uuu->meta.c_wait_async);
  648. #endif
  649.         if (uuu->meta.get_type) {
  650.             const char* type;
  651.             if ((type = uuu->meta.get_type(uuu->meta.c_get_type)) != 0) {
  652.                 static const char prefix[] = "SERVICE/";
  653.                 char* name = (char*) malloc(sizeof(prefix) + strlen(type));
  654.                 if (name) {
  655.                     strcpy(&name[0],                prefix);
  656.                     strcpy(&name[sizeof(prefix)-1], type);
  657.                     uuu->name = name;
  658.                 }
  659.             }
  660.         }
  661.         status = uuu->meta.open
  662.             ? uuu->meta.open(uuu->meta.c_open, timeout) : eIO_Success;
  663.         if (status == eIO_Success)
  664.             break;
  665.         s_Close(connector, timeout, 0/*don't close dispatcher!*/);
  666.     }
  667.     uuu->status = status;
  668.     return status;
  669. }
  670. /*ARGSUSED*/
  671. static EIO_Status s_VT_Status(CONNECTOR connector, EIO_Event dir)
  672. {
  673.     return ((SServiceConnector*) connector->handle)->status;
  674. }
  675. static EIO_Status s_VT_Close(CONNECTOR connector, const STimeout* timeout)
  676. {
  677.     return s_Close(connector, timeout, 1/*close_dispatcher*/);
  678. }
  679. static void s_Setup(SMetaConnector *meta, CONNECTOR connector)
  680. {
  681.     SServiceConnector* uuu = (SServiceConnector*) connector->handle;
  682.     /* initialize virtual table */
  683.     CONN_SET_METHOD(meta, get_type,   s_VT_GetType,   connector);
  684.     CONN_SET_METHOD(meta, open,       s_VT_Open,      connector);
  685.     CONN_SET_METHOD(meta, close,      s_VT_Close,     connector);
  686.     CONN_SET_DEFAULT_TIMEOUT(meta, uuu->net_info->timeout);
  687.     /* all the rest is reset to NULL */
  688.     s_Reset(meta);
  689. }
  690. static void s_Destroy(CONNECTOR connector)
  691. {
  692.     SServiceConnector* uuu = (SServiceConnector*) connector->handle;
  693.     s_CloseDispatcher(uuu);
  694.     if (uuu->params.cleanup)
  695.         uuu->params.cleanup(uuu->params.data);
  696.     ConnNetInfo_Destroy(uuu->net_info);
  697.     if (uuu->name)
  698.         free((void*) uuu->name);
  699.     free((void*) uuu->service);
  700.     free(uuu);
  701.     connector->handle = 0;
  702.     free(connector);
  703. }
  704. /***********************************************************************
  705.  *  EXTERNAL -- the connector's "constructor"
  706.  ***********************************************************************/
  707. extern CONNECTOR SERVICE_CreateConnectorEx
  708. (const char*           service,
  709.  TSERV_Type            types,
  710.  const SConnNetInfo*   net_info,
  711.  const SSERVICE_Extra* params)
  712. {
  713.     CONNECTOR          ccc;
  714.     SServiceConnector* xxx;
  715.     char*              x_args;
  716.     SConnNetInfo*      x_net_info;
  717.     if (!service || !*service)
  718.         return 0;
  719.     x_net_info =
  720.         net_info ? ConnNetInfo_Clone(net_info) : ConnNetInfo_Create(service);
  721.     x_args     = s_GetArgs(x_net_info->client_host);
  722.     ccc        = (SConnector*)        malloc(sizeof(SConnector));
  723.     xxx        = (SServiceConnector*) malloc(sizeof(SServiceConnector) +
  724.                                              (x_args ? strlen(x_args) : 0));
  725.     xxx->name     = 0;
  726.     xxx->service  = SERV_ServiceName(service);
  727.     xxx->net_info = x_net_info;
  728.     if (types & fSERV_StatelessOnly)
  729.         xxx->net_info->stateless = 1/*true*/;
  730.     if (types & fSERV_Firewall)
  731.         xxx->net_info->firewall = 1/*true*/;
  732.     xxx->status   = eIO_Success;
  733.     xxx->types    = types;
  734.     xxx->iter     = 0;
  735.     memset(&xxx->params, 0, sizeof(xxx->params));
  736.     memset(&xxx->meta,   0, sizeof(xxx->meta));
  737.     if (x_args) {
  738.         strcpy(xxx->args, x_args);
  739.         free(x_args);
  740.     } else
  741.         xxx->args[0] = '';
  742.     /* initialize connector structure */
  743.     ccc->handle  = xxx;
  744.     ccc->next    = 0;
  745.     ccc->meta    = 0;
  746.     ccc->setup   = s_Setup;
  747.     ccc->destroy = s_Destroy;
  748.     /* now make the first probe dispatching */
  749.     if (!s_OpenDispatcher(xxx)) {
  750.         s_CloseDispatcher(xxx);
  751.         s_Destroy(ccc);
  752.         return 0;
  753.     }
  754.     assert(xxx->iter != 0);
  755.     /* finally, store all callback parameters */
  756.     if (params)
  757.         memcpy(&xxx->params, params, sizeof(xxx->params));
  758.     /* done */
  759.     return ccc;
  760. }
  761. /*
  762.  * --------------------------------------------------------------------------
  763.  * $Log: ncbi_service_connector.c,v $
  764.  * Revision 1000.0  2003/10/29 16:39:51  gouriano
  765.  * PRODUCTION: IMPORTED [ORIGINAL] Dev-tree R6.60
  766.  *
  767.  * Revision 6.60  2003/08/25 14:41:53  lavr
  768.  * Employ new k..Timeout constants  --  log modification only
  769.  *
  770.  * Revision 6.59  2003/05/31 05:16:45  lavr
  771.  * Add ARGSUSED where args are meant to be unused
  772.  *
  773.  * Revision 6.58  2003/05/29 20:13:48  lavr
  774.  * -#include <connect/ncbi_connection.h>
  775.  *
  776.  * Revision 6.57  2003/05/22 20:31:28  lavr
  777.  * Callbacks in the constructor had to be set after successful init only
  778.  *
  779.  * Revision 6.56  2003/05/14 15:43:45  lavr
  780.  * Modify format of host address in dispatcher's CGI query
  781.  *
  782.  * Revision 6.55  2003/05/14 13:55:06  lavr
  783.  * BUGFIX: Buffer overrun in s_GetArgs()
  784.  *
  785.  * Revision 6.54  2003/05/14 04:19:48  lavr
  786.  * BUGFIX: Actually add IP address in "address=" CGI argument
  787.  *
  788.  * Revision 6.53  2003/05/14 03:55:28  lavr
  789.  * Arguments to include host address (for statistics purposes on backends)
  790.  *
  791.  * Revision 6.52  2002/12/19 17:34:58  lavr
  792.  * Do not initiate STATEFUL_CAPABLE challenge with HTTP servers in relay mode
  793.  *
  794.  * Revision 6.51  2002/12/10 22:11:50  lavr
  795.  * Stamp HTTP packets with "User-Agent:" header tag and DISP_PROTOCOL_VERSION
  796.  *
  797.  * Revision 6.50  2002/11/19 19:23:25  lavr
  798.  * Set MIME type whenever possible; introduce status of last op
  799.  *
  800.  * Revision 6.49  2002/11/12 05:52:00  lavr
  801.  * Use client_host from conn.info as value for "address="
  802.  *
  803.  * Revision 6.48  2002/11/01 20:16:05  lavr
  804.  * Expand hostname buffers to hold up to 256 chars
  805.  *
  806.  * Revision 6.47  2002/10/29 22:19:37  lavr
  807.  * Fix proper use of non-transparent proxy if one is specified
  808.  *
  809.  * Revision 6.46  2002/10/28 15:44:00  lavr
  810.  * Use "ncbi_ansi_ext.h" privately and use strncpy0()
  811.  *
  812.  * Revision 6.45  2002/10/22 15:11:24  lavr
  813.  * Zero connector's handle to crash if revisited
  814.  *
  815.  * Revision 6.44  2002/10/21 18:32:28  lavr
  816.  * Append service arguments "address" and "platform" in dispatcher requests
  817.  *
  818.  * Revision 6.43  2002/10/11 19:56:42  lavr
  819.  * Add "myargs" into connector structure (for later use in requests to
  820.  * show address and platform of the dispatcher's requestors)
  821.  *
  822.  * Revision 6.42  2002/09/06 17:45:33  lavr
  823.  * Include <connect/ncbi_priv.h> unconditionally (reported by J.Kans)
  824.  *
  825.  * Revision 6.41  2002/09/06 15:44:02  lavr
  826.  * Use fHCC_SureFlush and CONN_Flush() instead of dummy read
  827.  *
  828.  * Revision 6.40  2002/08/07 16:33:33  lavr
  829.  * Changed EIO_ReadMethod enums accordingly; log moved to end
  830.  *
  831.  * Revision 6.39  2002/06/10 19:51:43  lavr
  832.  * Wrong assertion removed from FIREWALL open case
  833.  *
  834.  * Revision 6.38  2002/05/07 15:31:47  lavr
  835.  * +#include <stdio.h>: noticed by J.Kans
  836.  *
  837.  * Revision 6.37  2002/05/06 19:17:33  lavr
  838.  * Take advantage of SERV_ServiceName()
  839.  *
  840.  * Revision 6.36  2002/04/26 16:28:51  lavr
  841.  * SSERVICE_Params: reset added for use in open/close pairs
  842.  * No checks for kDefaultTimeout: now real timeouts always go from CONN
  843.  *
  844.  * Revision 6.35  2002/03/30 03:34:32  lavr
  845.  * BUGFIX: Memory leak from SERV_ITER in usused connector
  846.  *
  847.  * Revision 6.34  2002/03/22 22:18:28  lavr
  848.  * Remove uuu->conn (contained in uuu->meta.list); honor timeout on open
  849.  *
  850.  * Revision 6.33  2002/03/22 19:52:18  lavr
  851.  * Do not include <stdio.h>: included from ncbi_util.h or ncbi_priv.h
  852.  *
  853.  * Revision 6.32  2002/03/19 22:14:53  lavr
  854.  * Proper indentation of nested preprocessor directives
  855.  *
  856.  * Revision 6.31  2002/03/11 22:00:22  lavr
  857.  * Support encoding in MIME content type for server data
  858.  *
  859.  * Revision 6.30  2001/12/04 15:56:47  lavr
  860.  * Use strdup() instead of explicit strcpy(malloc(...), ...)
  861.  *
  862.  * Revision 6.29  2001/10/26 21:17:59  lavr
  863.  * 'service=name' now always precedes other params in connects to DISPD/NCBID
  864.  *
  865.  * Revision 6.28  2001/09/28 20:51:31  lavr
  866.  * Comments revised; parameter (and SHttpConnector's) names adjusted
  867.  * Retry logic moved entirely into s_Adjust()
  868.  *
  869.  * Revision 6.27  2001/09/24 20:29:36  lavr
  870.  * +SSERVICE_Extra* parameter in constructor; store and use of this parameter
  871.  *
  872.  * Revision 6.26  2001/09/10 21:21:20  lavr
  873.  * Support for temporary switching into firewall mode as per dispatcher request
  874.  *
  875.  * Revision 6.25  2001/07/26 15:12:17  lavr
  876.  * while(1) -> for(;;)
  877.  *
  878.  * Revision 6.24  2001/06/05 14:11:29  lavr
  879.  * SERV_MIME_UNDEFINED split into 2 (typed) constants:
  880.  * SERV_MIME_TYPE_UNDEFINED and SERV_MIME_SUBTYPE_UNDEFINED
  881.  *
  882.  * Revision 6.23  2001/06/04 17:02:17  lavr
  883.  * Insert MIME type/subtype in Content-Type for servers,
  884.  * which have this feature configured
  885.  *
  886.  * Revision 6.22  2001/05/30 18:46:38  lavr
  887.  * Always call dispatcher in header-parsing callback (to see err.msg. if any)
  888.  *
  889.  * Revision 6.21  2001/05/23 21:53:19  lavr
  890.  * Do not close dispatcher in Open; leave it as it is
  891.  *
  892.  * Revision 6.20  2001/05/17 15:03:07  lavr
  893.  * Typos corrected
  894.  *
  895.  * Revision 6.19  2001/05/11 15:32:05  lavr
  896.  * Minor patch in code of 'fallback to STATELESS'
  897.  *
  898.  * Revision 6.18  2001/05/08 20:27:05  lavr
  899.  * Patches in re-try code
  900.  *
  901.  * Revision 6.17  2001/05/03 16:37:09  lavr
  902.  * Flow control fixed in s_Open for firewall connection
  903.  *
  904.  * Revision 6.16  2001/04/26 20:20:57  lavr
  905.  * Default tags are explicitly used to differ from a Web browser
  906.  *
  907.  * Revision 6.15  2001/04/25 15:49:54  lavr
  908.  * Memory leaks in Open (when unsuccessful) fixed
  909.  *
  910.  * Revision 6.14  2001/04/24 21:36:50  lavr
  911.  * More structured code to re-try abrupted connection/mapping attempts
  912.  *
  913.  * Revision 6.13  2001/03/07 23:01:07  lavr
  914.  * fSERV_Any used instead of 0 in SERVICE_CreateConnector
  915.  *
  916.  * Revision 6.12  2001/03/06 23:55:37  lavr
  917.  * SOCK_gethostaddr -> SOCK_gethostbyname
  918.  *
  919.  * Revision 6.11  2001/03/02 20:10:07  lavr
  920.  * Typo fixed
  921.  *
  922.  * Revision 6.10  2001/03/01 00:32:15  lavr
  923.  * FIX: Empty update does not generate parse error
  924.  *
  925.  * Revision 6.9  2001/02/09 17:35:45  lavr
  926.  * Modified: fSERV_StatelessOnly overrides info->stateless
  927.  * Bug fixed: free(type) -> free(name)
  928.  *
  929.  * Revision 6.8  2001/01/25 17:04:43  lavr
  930.  * Reversed:: DESTROY method calls free() to delete connector structure
  931.  *
  932.  * Revision 6.7  2001/01/23 23:09:19  lavr
  933.  * Flags added to 'Ex' constructor
  934.  *
  935.  * Revision 6.6  2001/01/11 16:38:18  lavr
  936.  * free(connector) removed from s_Destroy function
  937.  * (now always called from outside, in METACONN_Remove)
  938.  *
  939.  * Revision 6.5  2001/01/08 22:39:40  lavr
  940.  * Further development of service-mapping protocol: stateless/stateful
  941.  * is now separated from firewall/direct mode (see also in few more files)
  942.  *
  943.  * Revision 6.4  2001/01/03 22:35:53  lavr
  944.  * Next working revision (bugfixes and protocol changes)
  945.  *
  946.  * Revision 6.3  2000/12/29 18:05:12  lavr
  947.  * First working revision.
  948.  *
  949.  * Revision 6.2  2000/10/20 17:34:39  lavr
  950.  * Partially working service connector (service mapping works)
  951.  * Checkin for backup purposes
  952.  *
  953.  * Revision 6.1  2000/10/07 22:14:07  lavr
  954.  * Initial revision, placeholder mostly
  955.  *
  956.  * ==========================================================================
  957.  */