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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_dispd.c,v $
  4.  * PRODUCTION Revision 1000.0  2003/10/29 16:36:28  gouriano
  5.  * PRODUCTION PRODUCTION: IMPORTED [ORIGINAL] Dev-tree R6.61
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_dispd.c,v 1000.0 2003/10/29 16:36:28 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.  *   Low-level API to resolve NCBI service name to the server meta-address
  38.  *   with the use of NCBI network dispatcher (DISPD).
  39.  *
  40.  */
  41. #include "ncbi_ansi_ext.h"
  42. #include "ncbi_comm.h"
  43. #include "ncbi_dispd.h"
  44. #include "ncbi_priv.h"
  45. #include <connect/ncbi_connection.h>
  46. #include <connect/ncbi_http_connector.h>
  47. #include <ctype.h>
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <time.h>
  51. /* Lower bound of up-to-date/out-of-date ratio */
  52. #define SERV_DISPD_STALE_RATIO_OK  0.8
  53. /* Default rate increase if svc runs locally */
  54. #define SERV_DISPD_LOCAL_SVC_BONUS 1.2
  55. /* Dispatcher messaging support */
  56. static int               s_MessageIssued = 0;
  57. static FDISP_MessageHook s_MessageHook = 0;
  58. #ifdef __cplusplus
  59. extern "C" {
  60. #endif
  61.     static void        s_Reset      (SERV_ITER);
  62.     static SSERV_Info* s_GetNextInfo(SERV_ITER, HOST_INFO*);
  63.     static int/*bool*/ s_Update     (SERV_ITER, TNCBI_Time, const char*);
  64.     static void        s_Close      (SERV_ITER);
  65.     static const SSERV_VTable s_op = {
  66.         s_Reset, s_GetNextInfo, s_Update, 0/*Penalize*/, s_Close, "DISPD"
  67.     };
  68. #ifdef __cplusplus
  69. } /* extern "C" */
  70. #endif
  71. static int s_RandomSeed = 0;
  72. typedef struct {
  73.     SSERV_Info*   info;
  74.     double        status;
  75. } SDISPD_Node;
  76. typedef struct {
  77.     int/*bool*/   disp_fail;
  78.     SConnNetInfo* net_info;
  79.     SDISPD_Node*  s_node;
  80.     size_t        n_node;
  81.     size_t        n_max_node;
  82. } SDISPD_Data;
  83. static int/*bool*/ s_AddServerInfo(SDISPD_Data* data, SSERV_Info* info)
  84. {
  85.     size_t i;
  86.     /* First check that the new server info updates an existing one */
  87.     for (i = 0; i < data->n_node; i++) {
  88.         if (SERV_EqualInfo(data->s_node[i].info, info)) {
  89.             /* Replace older version */
  90.             free(data->s_node[i].info);
  91.             data->s_node[i].info = info;
  92.             return 1;
  93.         }
  94.     }
  95.     /* Next, add new service to the list */
  96.     if (data->n_node == data->n_max_node) {
  97.         size_t n = data->n_max_node + 10;
  98.         SDISPD_Node* temp;
  99.         if (data->s_node)
  100.             temp = (SDISPD_Node*) realloc(data->s_node, sizeof(*temp) * n);
  101.         else
  102.             temp = (SDISPD_Node*) malloc(sizeof(*temp) * n);
  103.         if (!temp)
  104.             return 0;
  105.         data->s_node = temp;
  106.         data->n_max_node = n;
  107.     }
  108.     data->s_node[data->n_node++].info = info;
  109.     return 1;
  110. }
  111. #ifdef __cplusplus
  112. extern "C" {
  113.     static int s_ParseHeader(const char*, void*, int);
  114. }
  115. #endif /* __cplusplus */
  116. /*ARGSUSED*/
  117. static int/*bool*/ s_ParseHeader(const char* header, void *iter,
  118.                                  int/*ignored*/ server_error)
  119. {
  120.     SERV_Update((SERV_ITER) iter, header);
  121.     return 1/*header parsed okay*/;
  122. }
  123. #ifdef __cplusplus
  124. extern "C" {
  125.     static int s_Adjust(SConnNetInfo*, void*, unsigned int);
  126. }
  127. #endif /* __cplusplus */
  128. /*ARGSUSED*/
  129. /* This callback is only for services called via direct HTTP */
  130. static int/*bool*/ s_Adjust(SConnNetInfo* net_info,
  131.                             void*         iter,
  132.                             unsigned int  n)
  133. {
  134.     SDISPD_Data* data = (SDISPD_Data*)((SERV_ITER) iter)->data;
  135.     return data->disp_fail ? 0/*failed*/ : 1/*try again*/;
  136. }
  137. static int/*bool*/ s_Resolve(SERV_ITER iter)
  138. {
  139.     static const char service[]  = "service";
  140.     static const char address[]  = "address";
  141.     static const char platform[] = "platform";
  142.     SDISPD_Data* data = (SDISPD_Data*) iter->data;
  143.     SConnNetInfo *net_info = data->net_info;
  144.     CONNECTOR conn = 0;
  145.     const char *arch;
  146.     unsigned int ip;
  147.     char addr[64];
  148.     char* s;
  149.     CONN c;
  150.     /* Dispatcher CGI arguments (sacrifice some if they all do not fit) */
  151.     if ((arch = CORE_GetPlatform()) != 0 && *arch)
  152.         ConnNetInfo_PreOverrideArg(net_info, platform, arch);
  153.     if (*net_info->client_host && !strchr(net_info->client_host, '.') &&
  154.         (ip = SOCK_gethostbyname(net_info->client_host)) != 0 &&
  155.         SOCK_ntoa(ip, addr, sizeof(addr)) == 0) {
  156.         if ((s= malloc(strlen(net_info->client_host) + strlen(addr) + 3)) != 0)
  157.             sprintf(s, "%s(%s)", net_info->client_host, addr);
  158.         else
  159.             s = net_info->client_host;
  160.     } else
  161.         s = net_info->client_host;
  162.     if (s && *s)
  163.         ConnNetInfo_PreOverrideArg(net_info, address, s);
  164.     if (s != net_info->client_host)
  165.         free(s);
  166.     if (!ConnNetInfo_PreOverrideArg(net_info, service, iter->service)) {
  167.         ConnNetInfo_DeleteArg(net_info, platform);
  168.         if (!ConnNetInfo_PreOverrideArg(net_info, service, iter->service)) {
  169.             ConnNetInfo_DeleteArg(net_info, address);
  170.             if (!ConnNetInfo_PreOverrideArg(net_info, service, iter->service))
  171.                 return 0/*failed*/;
  172.         }
  173.     }
  174.     /* Reset request method to be GET ('cause no HTTP body will follow) */
  175.     net_info->req_method = eReqMethod_Get;
  176.     /* Obtain additional header information */
  177.     if ((!(s = SERV_Print(iter))
  178.          || ConnNetInfo_OverrideUserHeader(net_info, s))                     &&
  179.         ConnNetInfo_OverrideUserHeader(net_info, net_info->stateless
  180.                                        ?"Client-Mode: STATELESS_ONLYrn"
  181.                                        :"Client-Mode: STATEFUL_CAPABLErn") &&
  182.         ConnNetInfo_OverrideUserHeader(net_info,
  183.                                        "Dispatch-Mode: INFORMATION_ONLYrn")){
  184.         ConnNetInfo_OverrideUserHeader
  185.             (net_info, "User-Agent: NCBIServiceDispatcher/"
  186.              DISP_PROTOCOL_VERSION
  187. #ifdef NCBI_CXX_TOOLKIT
  188.              " (C++ Toolkit)"
  189. #else
  190.              " (C Toolkit)"
  191. #endif
  192.              "rn");
  193.         data->disp_fail = 0;
  194.         /* All the rest in the net_info structure is fine with us */
  195.         conn = HTTP_CreateConnectorEx(net_info, fHCC_SureFlush, s_ParseHeader,
  196.                                       s_Adjust, iter/*data*/, 0/*cleanup*/);
  197.     }
  198.     if (s) {
  199.         ConnNetInfo_DeleteUserHeader(net_info, s);
  200.         free(s);
  201.     }
  202.     if (!conn || CONN_Create(conn, &c) != eIO_Success) {
  203.         CORE_LOGF(eLOG_Error, ("[DISPATCHER]  Unable to create aux. %s",
  204.                                conn ? "connection" : "connector"));
  205.         assert(0);
  206.         return 0/*failed*/;
  207.     }
  208.     /* This will also send all the HTTP data, and trigger header callback */
  209.     CONN_Flush(c);
  210.     CONN_Close(c);
  211.     return ((SDISPD_Data*) iter->data)->n_node != 0;
  212. }
  213. static int/*bool*/ s_Update(SERV_ITER iter, TNCBI_Time now, const char* text)
  214. {
  215.     static const char server_info[] = "Server-Info-";
  216.     SDISPD_Data* data = (SDISPD_Data*) iter->data;
  217.     size_t len = strlen(text);
  218.     if (len >= sizeof(server_info) &&
  219.         strncasecmp(text, server_info, sizeof(server_info) - 1) == 0) {
  220.         const char* p = text + sizeof(server_info) - 1;
  221.         SSERV_Info* info;
  222.         unsigned int d1;
  223.         int d2;
  224.         if (sscanf(p, "%u: %n", &d1, &d2) < 1)
  225.             return 0/*not updated*/;
  226.         if ((info = SERV_ReadInfo(p + d2)) != 0) {
  227.             assert(info->rate != 0.0);
  228.             info->time += now; /* expiration time now */
  229.             if (s_AddServerInfo(data, info))
  230.                 return 1/*updated*/;
  231.             free(info);
  232.         }
  233.     } else if (len >= sizeof(HTTP_DISP_FAILURES) &&
  234.                strncasecmp(text, HTTP_DISP_FAILURES,
  235.                            sizeof(HTTP_DISP_FAILURES) - 1) == 0) {
  236. #if defined(_DEBUG) && !defined(NDEBUG)
  237.         const char* p = text + sizeof(HTTP_DISP_FAILURES) - 1;
  238.         while (*p && isspace((unsigned char)(*p)))
  239.             p++;
  240.         if (data->net_info->debug_printout)
  241.             CORE_LOGF(eLOG_Warning, ("[DISPATCHER]  %s", p));
  242. #endif
  243.         data->disp_fail = 1;
  244.         return 1/*updated*/;
  245.     } else if (len >= sizeof(HTTP_DISP_MESSAGE) &&
  246.                strncasecmp(text, HTTP_DISP_MESSAGE,
  247.                            sizeof(HTTP_DISP_MESSAGE) - 1) == 0) {
  248.         const char* p = text + sizeof(HTTP_DISP_MESSAGE) - 1;
  249.         while (*p && isspace((unsigned char)(*p)))
  250.             p++;
  251.         if (s_MessageHook) {
  252.             if (s_MessageIssued <= 0) {
  253.                 s_MessageIssued = 1;
  254.                 s_MessageHook(p);
  255.             }
  256.         } else {
  257.             s_MessageIssued = -1;
  258.             CORE_LOGF(eLOG_Warning, ("[DISPATCHER]  %s", p));
  259.         }
  260.     }
  261.     return 0/*not updated*/;
  262. }
  263. static int/*bool*/ s_IsUpdateNeeded(SDISPD_Data *data)
  264. {
  265.     double status = 0.0, total = 0.0;
  266.     if (data->n_node) {
  267.         TNCBI_Time t = (TNCBI_Time) time(0);
  268.         size_t i = 0;
  269.         while (i < data->n_node) {
  270.             SSERV_Info* info = data->s_node[i].info;
  271.             total += info->rate;
  272.             if (info->time < t) {
  273.                 if (i < --data->n_node)
  274.                     memmove(data->s_node + i, data->s_node + i + 1,
  275.                             (data->n_node - i)*sizeof(*data->s_node));
  276.                 free(info);
  277.             } else {
  278.                 status += info->rate;
  279.                 i++;
  280.             }
  281.         }
  282.     }
  283.     return total == 0.0 ? 1 : (status/total < SERV_DISPD_STALE_RATIO_OK);
  284. }
  285. static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info)
  286. {
  287.     double total = 0.0, point = 0.0, access = 0.0, p = 0.0, status;
  288.     SDISPD_Data* data = (SDISPD_Data*) iter->data;
  289.     SSERV_Info* info;
  290.     size_t i;
  291.     if (!data)
  292.         return 0;
  293.     if (s_IsUpdateNeeded(data) && !s_Resolve(iter))
  294.         return 0;
  295.     assert(data->n_node != 0);
  296.     for (i = 0; i < data->n_node; i++) {
  297.         info = data->s_node[i].info;
  298.         status = info->rate;
  299.         assert(status != 0.0);
  300.         if (info->host == iter->preferred_host) {
  301.             if (info->coef <= 0.0 || iter->preference) {
  302.                 status *= SERV_DISPD_LOCAL_SVC_BONUS;
  303.                 if (access < status &&
  304.                     (iter->preference || info->coef < 0.0)) {
  305.                     access =  status;
  306.                     point  =  total + status; /* Latch this local server */
  307.                     p      = -info->coef;
  308.                     assert(point > 0.0);
  309.                 }
  310.             } else
  311.                 status *= info->coef;
  312.         }
  313.         total                 += status;
  314.         data->s_node[i].status = total;
  315.     }
  316.     if (point > 0.0 && iter->preference) {
  317.         if (total != access) {
  318.             p = SERV_Preference(iter->preference, access/total, data->n_node);
  319.             status = total*p;
  320.             p = total*(1.0 - p)/(total - access);
  321.             for (i = 0; i < data->n_node; i++) {
  322.                 data->s_node[i].status *= p;
  323.                 if (p*point <= data->s_node[i].status)
  324.                     data->s_node[i].status += status - p*access;
  325.             }
  326.         }
  327.         point = -1.0;
  328.     }
  329.     /* We take pre-chosen local server only if its status is not less than
  330.        p% of the average remaining status; otherwise, we ignore the server,
  331.        and apply the generic procedure by seeding a random point. */
  332.     if (point <= 0.0 || access*(data->n_node - 1) < p*0.01*(total - access))
  333.         point = (total * rand()) / (double) RAND_MAX;
  334.     for (i = 0; i < data->n_node; i++) {
  335.         if (point <= data->s_node[i].status)
  336.             break;
  337.     }
  338.     assert(i < data->n_node);
  339.     info = data->s_node[i].info;
  340.     info->rate = data->s_node[i].status - (i ? data->s_node[i-1].status : 0.0);
  341.     if (i < --data->n_node) {
  342.         memmove(data->s_node + i, data->s_node + i + 1,
  343.                 (data->n_node - i)*sizeof(*data->s_node));
  344.     }
  345.     if (host_info)
  346.         *host_info = 0;
  347.     return info;
  348. }
  349. static void s_Reset(SERV_ITER iter)
  350. {
  351.     SDISPD_Data* data = (SDISPD_Data*) iter->data;
  352.     if (data && data->s_node) {
  353.         size_t i;
  354.         assert(data->n_max_node);
  355.         for (i = 0; i < data->n_node; i++)
  356.             free(data->s_node[i].info);
  357.         data->n_node = 0;
  358.     }
  359. }
  360. static void s_Close(SERV_ITER iter)
  361. {
  362.     SDISPD_Data* data = (SDISPD_Data*) iter->data;
  363.     assert(data->n_node == 0); /* s_Reset() had to be called before */
  364.     if (data->s_node)
  365.         free(data->s_node);
  366.     ConnNetInfo_Destroy(data->net_info);
  367.     free(data);
  368.     iter->data = 0;
  369. }
  370. /***********************************************************************
  371.  *  EXTERNAL
  372.  ***********************************************************************/
  373. /*ARGSUSED*/
  374. const SSERV_VTable* SERV_DISPD_Open(SERV_ITER iter,
  375.                                     const SConnNetInfo* net_info,
  376.                                     SSERV_Info** info, HOST_INFO* u/*unused*/)
  377. {
  378.     SDISPD_Data* data;
  379.     if (!(data = (SDISPD_Data*) calloc(1, sizeof(*data))))
  380.         return 0;
  381.     if (!s_RandomSeed) {
  382.         s_RandomSeed = (int) time(0) + (int) SOCK_gethostbyname(0);
  383.         srand(s_RandomSeed);
  384.     }
  385.     data->net_info = ConnNetInfo_Clone(net_info); /*called with non-NULL*/
  386.     if (iter->type & fSERV_StatelessOnly)
  387.         data->net_info->stateless = 1/*true*/;
  388.     if (iter->type & fSERV_Firewall)
  389.         data->net_info->firewall = 1/*true*/;
  390.     iter->data = data;
  391.     iter->op = &s_op; /* SERV_Update() - from HTTP callback - expects this */
  392.     if (!s_Resolve(iter)) {
  393.         iter->op = 0;
  394.         s_Reset(iter);
  395.         s_Close(iter);
  396.         return 0;
  397.     }
  398.     /* call GetNextInfo if info is needed */
  399.     if (info)
  400.         *info = 0;
  401.     return &s_op;
  402. }
  403. void DISP_SetMessageHook(FDISP_MessageHook hook)
  404. {
  405.     if (hook) {
  406.         if (hook != s_MessageHook)
  407.             s_MessageIssued = s_MessageIssued ? -1 : -2;
  408.     } else if (s_MessageIssued < -1)
  409.         s_MessageIssued = 0;
  410.     s_MessageHook = hook;
  411. }
  412. /*
  413.  * --------------------------------------------------------------------------
  414.  * $Log: ncbi_dispd.c,v $
  415.  * Revision 1000.0  2003/10/29 16:36:28  gouriano
  416.  * PRODUCTION: IMPORTED [ORIGINAL] Dev-tree R6.61
  417.  *
  418.  * Revision 6.61  2003/10/14 14:40:07  lavr
  419.  * Fix to avoid resolving empty client's host name
  420.  *
  421.  * Revision 6.60  2003/10/10 19:33:24  lavr
  422.  * Do not generate address CGI parameter if host address is unknown
  423.  *
  424.  * Revision 6.59  2003/08/11 19:07:03  lavr
  425.  * +DISP_SetMessageHook() and implementation of message delivery
  426.  *
  427.  * Revision 6.58  2003/05/31 05:14:38  lavr
  428.  * Add ARGSUSED where args are meant to be unused
  429.  *
  430.  * Revision 6.57  2003/05/22 20:31:40  lavr
  431.  * Comment change
  432.  *
  433.  * Revision 6.56  2003/05/14 15:43:31  lavr
  434.  * Add host address in dispatcher's CGI query
  435.  *
  436.  * Revision 6.55  2003/02/13 21:38:22  lavr
  437.  * Comply with new SERV_Preference() prototype
  438.  *
  439.  * Revision 6.54  2003/02/06 17:35:36  lavr
  440.  * Move reset of disp_fail to correct place in s_Resolve()
  441.  *
  442.  * Revision 6.53  2003/02/04 22:02:44  lavr
  443.  * Introduce adjustment routine and disp_fail member to avoid MAX_TRY retrying
  444.  *
  445.  * Revision 6.52  2003/01/31 21:17:37  lavr
  446.  * Implementation of perference for preferred host
  447.  *
  448.  * Revision 6.51  2002/12/10 22:11:50  lavr
  449.  * Stamp HTTP packets with "User-Agent:" header tag and DISP_PROTOCOL_VERSION
  450.  *
  451.  * Revision 6.50  2002/11/19 19:21:40  lavr
  452.  * Use client_host from net_info instead of obtaining it explicitly
  453.  *
  454.  * Revision 6.49  2002/11/01 20:14:07  lavr
  455.  * Expand hostname buffers to hold up to 256 chars
  456.  *
  457.  * Revision 6.48  2002/10/28 20:12:56  lavr
  458.  * Module renamed and host info API included
  459.  *
  460.  * Revision 6.47  2002/10/28 15:46:21  lavr
  461.  * Use "ncbi_ansi_ext.h" privately
  462.  *
  463.  * Revision 6.46  2002/10/21 18:32:35  lavr
  464.  * Append service arguments "address" and "platform" in dispatcher requests
  465.  *
  466.  * Revision 6.45  2002/10/11 19:55:20  lavr
  467.  * Append dispatcher request query with address and platform information
  468.  * (as the old dispatcher used to do). Also, take advantage of various new
  469.  * ConnNetInfo_*UserHeader() routines when preparing aux HTTP request.
  470.  *
  471.  * Revision 6.44  2002/09/24 15:08:50  lavr
  472.  * Change non-zero rate assertion into more readable (info->rate != 0.0)
  473.  *
  474.  * Revision 6.43  2002/09/18 16:31:38  lavr
  475.  * Temporary fix for precision loss removed & replaced with assert()
  476.  *
  477.  * Revision 6.42  2002/09/06 17:45:40  lavr
  478.  * Include <connect/ncbi_priv.h> unconditionally (reported by J.Kans)
  479.  *
  480.  * Revision 6.41  2002/09/06 15:44:19  lavr
  481.  * Use fHCC_SureFlush and CONN_Flush() instead of dummy read
  482.  *
  483.  * Revision 6.40  2002/08/12 15:13:50  lavr
  484.  * Temporary fix for precision loss in transmission of SERV_Info as text
  485.  *
  486.  * Revision 6.39  2002/08/07 16:33:43  lavr
  487.  * Changed EIO_ReadMethod enums accordingly; log moved to end
  488.  *
  489.  * Revision 6.38  2002/05/07 15:31:50  lavr
  490.  * +#include <stdio.h>: noticed by J.Kans
  491.  *
  492.  * Revision 6.37  2002/05/06 19:18:12  lavr
  493.  * Few changes to comply with the rest of API
  494.  *
  495.  * Revision 6.36  2002/04/13 06:40:05  lavr
  496.  * Few tweaks to reduce the number of syscalls made
  497.  *
  498.  * Revision 6.35  2002/03/11 22:01:47  lavr
  499.  * Threshold for choosing a local server explained better
  500.  *
  501.  * Revision 6.34  2001/12/04 15:57:05  lavr
  502.  * Change log correction
  503.  *
  504.  * Revision 6.33  2001/10/01 19:53:39  lavr
  505.  * -s_FreeData(), -s_ResetData() - do everything in s_Close()/s_Reset() instead
  506.  *
  507.  * Revision 6.32  2001/09/29 19:33:04  lavr
  508.  * BUGFIX: SERV_Update() requires VT bound (was not the case in constructor)
  509.  *
  510.  * Revision 6.31  2001/09/29 18:41:03  lavr
  511.  * "Server-Keyed-Info:" removed from protocol
  512.  *
  513.  * Revision 6.30  2001/09/28 20:52:16  lavr
  514.  * Update VT method revised as now called on a per-line basis
  515.  *
  516.  * Revision 6.29  2001/09/24 20:30:01  lavr
  517.  * Reset() VT method added and utilized
  518.  *
  519.  * Revision 6.28  2001/09/10 21:23:53  lavr
  520.  * "Relay-Mode:" tag eliminated from the dispatcher protocol
  521.  *
  522.  * Revision 6.27  2001/07/24 18:02:02  lavr
  523.  * Seed random generator at Open()
  524.  *
  525.  * Revision 6.26  2001/07/18 17:41:25  lavr
  526.  * BUGFIX: In code for selecting services by preferred host
  527.  *
  528.  * Revision 6.25  2001/07/03 20:49:44  lavr
  529.  * RAND_MAX included in the interval search
  530.  *
  531.  * Revision 6.24  2001/06/25 15:36:38  lavr
  532.  * s_GetNextInfo now takes one additional argument for host environment
  533.  *
  534.  * Revision 6.23  2001/06/20 17:27:49  kans
  535.  * include <time.h> for Mac compiler
  536.  *
  537.  * Revision 6.22  2001/06/19 19:12:01  lavr
  538.  * Type change: size_t -> TNCBI_Size; time_t -> TNCBI_Time
  539.  *
  540.  * Revision 6.21  2001/05/17 15:02:51  lavr
  541.  * Typos corrected
  542.  *
  543.  * Revision 6.20  2001/05/11 15:30:31  lavr
  544.  * Protocol change: REQUEST_FAILED -> DISP_FAILURES
  545.  *
  546.  * Revision 6.19  2001/05/03 16:58:16  lavr
  547.  * FIX: Percent is taken of local bonus coef instead of the value itself
  548.  *
  549.  * Revision 6.18  2001/05/03 16:35:53  lavr
  550.  * Local bonus coefficient modified: meaning of negative value changed
  551.  *
  552.  * Revision 6.17  2001/04/26 20:20:01  lavr
  553.  * Better way of choosing local server with a tiny (e.g. penalized) status
  554.  *
  555.  * Revision 6.16  2001/04/24 21:35:46  lavr
  556.  * Treatment of new bonus coefficient for local servers
  557.  *
  558.  * Revision 6.15  2001/03/21 21:24:11  lavr
  559.  * Type match (int) for %n in scanf
  560.  *
  561.  * Revision 6.14  2001/03/06 23:57:27  lavr
  562.  * SERV_DISPD_LOCAL_SVC_BONUS used for services running locally
  563.  *
  564.  * Revision 6.13  2001/03/05 23:10:46  lavr
  565.  * SERV_ReadInfo takes only one argument now
  566.  *
  567.  * Revision 6.12  2001/03/01 00:33:12  lavr
  568.  * FIXES: Empty update does not generate parse error
  569.  *        Dispathing error is only logged in debug mode; milder severity
  570.  *
  571.  * Revision 6.11  2001/02/09 17:36:48  lavr
  572.  * Modified: fSERV_StatelessOnly overrides info->stateless
  573.  *
  574.  * Revision 6.10  2001/01/25 17:06:36  lavr
  575.  * s_FreeData now calls ConnNetInfo_Destroy() unconditionally
  576.  *
  577.  * Revision 6.9  2001/01/12 23:51:40  lavr
  578.  * Message logging modified for use LOG facility only
  579.  *
  580.  * Revision 6.8  2001/01/08 23:48:14  lavr
  581.  * (unsigned char) conversion in isspace
  582.  *
  583.  * Revision 6.7  2001/01/08 22:40:23  lavr
  584.  * Further development of service-mapping protocol: stateless/stateful
  585.  * is now separated from firewall/direct mode (see also in few more files)
  586.  *
  587.  * Revision 6.6  2000/12/29 18:05:46  lavr
  588.  * First working revision.
  589.  *
  590.  * Revision 6.5  2000/10/20 17:36:05  lavr
  591.  * Partially working dispd dispatcher client (service mapping works)
  592.  * Checkin for backup purposes; working code '#if 0'-ed out
  593.  *
  594.  * Revision 6.4  2000/10/05 22:43:30  lavr
  595.  * Another dummy revision: still in development
  596.  *
  597.  * Revision 6.3  2000/10/05 22:34:23  lavr
  598.  * Temporary (dummy) revision for compilation to go
  599.  *
  600.  * Revision 6.2  2000/05/22 16:53:12  lavr
  601.  * Rename service_info -> server_info everywhere (including
  602.  * file names) as the latter name is more relevant
  603.  *
  604.  * Revision 6.1  2000/05/12 18:43:59  lavr
  605.  * Initial revision
  606.  *
  607.  * ==========================================================================
  608.  */