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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_service.c,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 18:45:22  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.52
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_service.c,v 1000.3 2004/06/01 18:45:22 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.  *   Top-level API to resolve NCBI service name to the server meta-address.
  38.  *
  39.  */
  40. #include "ncbi_ansi_ext.h"
  41. #include "ncbi_dispd.h"
  42. #include "ncbi_lbsmd.h"
  43. #include "ncbi_priv.h"
  44. #include <ctype.h>
  45. #include <stdlib.h>
  46. #include <time.h>
  47. #define SERV_SERVICE_NAME "SERVICE_NAME"
  48. static char* s_ServiceName(const char* service, size_t depth)
  49. {
  50.     char *s, *p;
  51.     char key[128];
  52.     char srv[128];
  53.     if (++depth > 8 || !service || !*service ||
  54.         sizeof(DEF_CONN_REG_SECTION) + sizeof(SERV_SERVICE_NAME) +
  55.         strlen(service) >= sizeof(key))
  56.         return 0/*failure*/;
  57.     s = key;
  58.     strcpy(s, DEF_CONN_REG_SECTION);
  59.     s += sizeof(DEF_CONN_REG_SECTION) - 1;
  60.     *s++ = '_';
  61.     strcpy(s, SERV_SERVICE_NAME);
  62.     s += sizeof(SERV_SERVICE_NAME) - 1;
  63.     *s++ = '_';
  64.     strcpy(s, service);
  65.     strupr(key);
  66.     /* Looking for "CONN_SERVICE_NAME_service" in environment */
  67.     if (!(p = getenv(key))) {
  68.         *--s = '';
  69.         /* Looking for "CONN_SERVICE_NAME" in registry's section [service] */
  70.         CORE_REG_GET(service, key, srv, sizeof(srv), 0);
  71.         if (!*srv)
  72.             return strdup(service);
  73.     } else
  74.         strncpy0(srv, p, sizeof(srv) - 1);
  75.     /* No cycle detection in service name redefinition */
  76.     return s_ServiceName(srv, depth);
  77. }
  78. char* SERV_ServiceName(const char* service)
  79. {
  80.     return s_ServiceName(service, 0);
  81. }
  82. SERV_ITER SERV_OpenSimple(const char* service)
  83. {
  84.     SConnNetInfo* net_info = ConnNetInfo_Create(service);
  85.     SERV_ITER iter = SERV_Open(service, fSERV_Any, 0, net_info);
  86.     ConnNetInfo_Destroy(net_info);
  87.     return iter;
  88. }
  89. static int/*bool*/ s_AddSkipInfo(SERV_ITER iter, SSERV_Info* info)
  90. {
  91.     if (iter->n_skip == iter->n_max_skip) {
  92.         SSERV_Info** temp;
  93.         size_t n = iter->n_max_skip + 10;
  94.         if (iter->skip)
  95.             temp = (SSERV_Info**) realloc(iter->skip, sizeof(*temp) * n);
  96.         else
  97.             temp = (SSERV_Info**) malloc(sizeof(*temp) * n);
  98.         if (!temp)
  99.             return 0;
  100.         iter->skip = temp;
  101.         iter->n_max_skip = n;
  102.     }
  103.     iter->skip[iter->n_skip++] = info;
  104.     return 1;
  105. }
  106. static SERV_ITER s_Open(const char* service, TSERV_Type type,
  107.                         unsigned int preferred_host, double preference,
  108.                         const SConnNetInfo* net_info,
  109.                         const SSERV_Info* const skip[], size_t n_skip,
  110.                         SSERV_Info** info, HOST_INFO* host_info, int external)
  111. {
  112.     const char* s = s_ServiceName(service, 0);
  113.     const SSERV_VTable* op;
  114.     SERV_ITER iter;
  115.     
  116.     if (!s || !*s || !(iter = (SERV_ITER) malloc(sizeof(*iter))))
  117.         return 0;
  118.     iter->service        = s;
  119.     iter->type           = type;
  120.     iter->preferred_host = preferred_host == SERV_LOCALHOST
  121.         ? SOCK_gethostbyname(0) : preferred_host;
  122.     iter->preference = 0.01*(preference < 0.0   ? 0.0   :
  123.                              preference > 100.0 ? 100.0 : preference);
  124.     iter->n_skip         = iter->n_max_skip = 0;
  125.     iter->skip           = 0;
  126.     iter->last           = 0;
  127.     iter->op             = 0;
  128.     iter->data           = 0;
  129.     iter->external       = external;
  130.     if (n_skip) {
  131.         size_t i;
  132.         for (i = 0; i < n_skip; i++) {
  133.             size_t   skipinfolen = SERV_SizeOfInfo(skip[i]);
  134.             SSERV_Info* skipinfo = (SSERV_Info*) malloc(skipinfolen);
  135.             if (!skipinfo) {
  136.                 SERV_Close(iter);
  137.                 return 0;
  138.             }
  139.             memcpy(skipinfo, skip[i], skipinfolen);
  140.             skipinfo->time = (TNCBI_Time)(-1);
  141.             if (!s_AddSkipInfo(iter, skipinfo)) {
  142.                 free(skipinfo);
  143.                 SERV_Close(iter);
  144.             }
  145.         }
  146.     }
  147.     assert(n_skip == iter->n_skip);
  148.     if (!net_info) {
  149.         if (!(op = SERV_LBSMD_Open(iter, info, host_info))) {
  150.             /* LBSMD failed in non-DISPD mapping */
  151.             SERV_Close(iter);
  152.             return 0;
  153.         }
  154.     } else {
  155.         if (net_info->stateless)
  156.             iter->type |= fSERV_StatelessOnly;
  157.         if (net_info->firewall)
  158.             iter->type |= fSERV_Firewall;
  159.         if ((net_info->lb_disable ||
  160.              !(op = SERV_LBSMD_Open(iter, info, host_info))) &&
  161.             !(op = SERV_DISPD_Open(iter, net_info, info, host_info))) {
  162.             SERV_Close(iter);
  163.             return 0;
  164.         }
  165.     }
  166.     assert(op != 0);
  167.     iter->op = op;
  168.     return iter;
  169. }
  170. SERV_ITER SERV_OpenEx(const char* service,
  171.                       TSERV_Type type, unsigned int preferred_host,
  172.                       const SConnNetInfo* net_info,
  173.                       const SSERV_Info* const skip[], size_t n_skip)
  174. {
  175.     return s_Open(service, type, preferred_host, 0.0,
  176.                   net_info, skip, n_skip, 0, 0, 0/*not external*/);
  177. }
  178. SERV_ITER SERV_OpenP(const char* service, TSERV_Type type,
  179.                      unsigned int preferred_host, double preference,
  180.                      int/*bool*/ external)
  181. {
  182.     return s_Open(service, type, preferred_host, preference,
  183.                   0, 0, 0, 0, 0, external);
  184. }
  185. static SSERV_Info* s_GetInfo(const char* service, TSERV_Type type,
  186.                              unsigned int preferred_host, double preference,
  187.                              const SConnNetInfo* net_info,
  188.                              const SSERV_Info* const skip[], size_t n_skip,
  189.                              HOST_INFO* host_info, int/*bool*/ external)
  190. {
  191.     SSERV_Info* info = 0;
  192.     SERV_ITER iter= s_Open(service, type, preferred_host, preference,
  193.                            net_info, skip, n_skip, &info, host_info, external);
  194.     if (iter && !info && iter->op && iter->op->GetNextInfo)
  195.         info = (*iter->op->GetNextInfo)(iter, host_info);
  196.     SERV_Close(iter);
  197.     return info;
  198. }
  199. SSERV_Info* SERV_GetInfoEx(const char* service, TSERV_Type type,
  200.                            unsigned int preferred_host,
  201.                            const SConnNetInfo* net_info,
  202.                            const SSERV_Info* const skip[], size_t n_skip,
  203.                            HOST_INFO* host_info)
  204. {
  205.     return s_GetInfo(service, type, preferred_host, 0.0,
  206.                      net_info, skip, n_skip, host_info, 0/*not external*/);
  207. }
  208. SSERV_Info* SERV_GetInfoP(const char* service, TSERV_Type type,
  209.                           unsigned int preferred_host, double preference,
  210.                           int/*bool*/ external)
  211. {
  212.     return s_GetInfo(service, type, preferred_host, preference,
  213.                      0, 0, 0, 0, external);
  214. }
  215. static void s_SkipSkip(SERV_ITER iter)
  216. {
  217.     if (iter->n_skip) {
  218.         TNCBI_Time t = (TNCBI_Time) time(0);
  219.         size_t i = 0;
  220.         while (i < iter->n_skip) {
  221.             SSERV_Info* info = iter->skip[i];
  222.             if (info->time < t) {
  223.                 if (i < --iter->n_skip)
  224.                     memmove(iter->skip + i, iter->skip + i + 1,
  225.                             sizeof(*iter->skip)*(iter->n_skip - i));
  226.                 if (info == iter->last)
  227.                     iter->last = 0;
  228.                 free(info);
  229.             } else
  230.                 i++;
  231.         }
  232.     }
  233. }
  234. const SSERV_Info* SERV_GetNextInfoEx(SERV_ITER iter, HOST_INFO* host_info)
  235. {
  236.     SSERV_Info* info = 0;
  237.     if (iter && iter->op) {
  238.         /* First, remove all outdated entries from our skip list */
  239.         s_SkipSkip(iter);
  240.         /* Next, obtain a fresh entry from the actual mapper */
  241.         if (iter->op->GetNextInfo &&
  242.             (info = (*iter->op->GetNextInfo)(iter, host_info)) != 0 &&
  243.             !s_AddSkipInfo(iter, info)) {
  244.             free(info);
  245.             info = 0;
  246.         }
  247.         iter->last = info;
  248.     }
  249.     return info;
  250. }
  251. const char* SERV_MapperName(SERV_ITER iter)
  252. {
  253.     return iter && iter->op ? iter->op->name : 0;
  254. }
  255. int/*bool*/ SERV_Penalize(SERV_ITER iter, double fine)
  256. {
  257.     if (!iter || !iter->op || !iter->op->Penalize || !iter->last)
  258.         return 0;
  259.     return (*iter->op->Penalize)(iter, fine);
  260. }
  261. char* SERV_GetConfig(void)
  262. {
  263.     return SERV_LBSMD_GetConfig();
  264. }
  265. void SERV_Reset(SERV_ITER iter)
  266. {
  267.     size_t i;
  268.     if (!iter)
  269.         return;
  270.     for (i = 0; i < iter->n_skip; i++)
  271.         free(iter->skip[i]);
  272.     iter->n_skip = 0;
  273.     iter->last = 0;
  274.     if (iter->op && iter->op->Reset)
  275.         (*iter->op->Reset)(iter);
  276. }
  277. void SERV_Close(SERV_ITER iter)
  278. {
  279.     if (!iter)
  280.         return;
  281.     SERV_Reset(iter);
  282.     if (iter->op && iter->op->Close)
  283.         (*iter->op->Close)(iter);
  284.     if (iter->skip)
  285.         free(iter->skip);
  286.     if (iter->service)
  287.         free((void*) iter->service);
  288.     free(iter);
  289. }
  290. int/*bool*/ SERV_Update(SERV_ITER iter, const char* text)
  291. {
  292.     static const char used_server_info[] = "Used-Server-Info-";
  293.     int retval = 0/*not updated yet*/;
  294.     if (iter && iter->op && text) {
  295.         TNCBI_Time now = (TNCBI_Time) time(0);
  296.         const char *c, *b;
  297.         for (b = text; (c = strchr(b, 'n')) != 0; b = c + 1) {
  298.             size_t len = (size_t)(c - b);
  299.             SSERV_Info* info;
  300.             unsigned int d1;
  301.             char* p, *t;
  302.             int d2;
  303.             if (!(t = (char*) malloc(len + 1)))
  304.                 continue;
  305.             memcpy(t, b, len);
  306.             if (t[len - 1] == 'r')
  307.                 t[len - 1] = 0;
  308.             else
  309.                 t[len] = 0;
  310.             p = t;
  311.             if (iter->op->Update && (*iter->op->Update)(iter, now, p))
  312.                 retval = 1/*updated*/;
  313.             if (strncasecmp(p, used_server_info,
  314.                             sizeof(used_server_info) - 1) == 0) {
  315.                 p += sizeof(used_server_info) - 1;
  316.                 if (sscanf(p, "%u: %n", &d1, &d2) >= 1 &&
  317.                     (info = SERV_ReadInfo(p + d2)) != 0) {
  318.                     if (!s_AddSkipInfo(iter, info))
  319.                         free(info);
  320.                     else
  321.                         retval = 1/*updated*/;
  322.                 }
  323.             }
  324.             free(t);
  325.         }
  326.     }
  327.     return retval;
  328. }
  329. char* SERV_Print(SERV_ITER iter)
  330. {
  331.     static const char client_revision[] = "Client-Revision: %hu.%hurn";
  332.     static const char accepted_types[] = "Accepted-Server-Types:";
  333.     char buffer[128], *str;
  334.     TSERV_Type type, t;
  335.     size_t buflen, i;
  336.     BUF buf = 0;
  337.     /* Put client version number */
  338.     buflen = sprintf(buffer, client_revision,
  339.                      SERV_CLIENT_REVISION_MAJOR, SERV_CLIENT_REVISION_MINOR);
  340.     assert(buflen < sizeof(buffer));
  341.     if (!BUF_Write(&buf, buffer, buflen)) {
  342.         BUF_Destroy(buf);
  343.         return 0;
  344.     }
  345.     if (iter) {
  346.         /* Form accepted server types */
  347.         buflen = sizeof(accepted_types) - 1;
  348.         memcpy(buffer, accepted_types, buflen);
  349.         type = (TSERV_Type) (iter->type & ~fSERV_StatelessOnly);
  350.         for (t = 1; t; t <<= 1) {
  351.             if (type & t) {
  352.                 const char* name = SERV_TypeStr((ESERV_Type) t);
  353.                 size_t namelen = strlen(name);
  354.                 if (!namelen || buflen + 1 + namelen + 2 >= sizeof(buffer))
  355.                     break;
  356.                 buffer[buflen++] = ' ';
  357.                 strcpy(&buffer[buflen], name);
  358.                 buflen += namelen;
  359.             }
  360.         }
  361.         if (buffer[buflen - 1] != ':') {
  362.             strcpy(&buffer[buflen], "rn");
  363.             assert(strlen(buffer) == buflen+2  &&  buflen+2 < sizeof(buffer));
  364.             if (!BUF_Write(&buf, buffer, buflen + 2)) {
  365.                 BUF_Destroy(buf);
  366.                 return 0;
  367.             }
  368.         }
  369.         /* Drop any outdated skip entries */
  370.         s_SkipSkip(iter);
  371.         /* Put all the rest into rejection list */
  372.         for (i = 0; i < iter->n_skip; i++) {
  373.             if (!(str = SERV_WriteInfo(iter->skip[i])))
  374.                 break;
  375.             buflen = sprintf(buffer, "Skip-Info-%u: ", (unsigned) i + 1); 
  376.             assert(buflen < sizeof(buffer)-1);
  377.             if (!BUF_Write(&buf, buffer, buflen) ||
  378.                 !BUF_Write(&buf, str, strlen(str)) ||
  379.                 !BUF_Write(&buf, "rn", 2)) {
  380.                 free(str);
  381.                 break;
  382.             }
  383.             free(str);
  384.         }
  385.         if (i < iter->n_skip) {
  386.             BUF_Destroy(buf);
  387.             return 0;
  388.         }
  389.     }
  390.     /* Ok then, we have filled the entire header, <CR><LF> terminated */
  391.     if ((buflen = BUF_Size(buf)) != 0) {
  392.         if ((str = (char*) malloc(buflen + 1)) != 0) {
  393.             if (BUF_Read(buf, str, buflen) != buflen) {
  394.                 free(str);
  395.                 str = 0;
  396.             } else
  397.                 str[buflen] = '';
  398.         }
  399.     } else
  400.         str = 0;
  401.     BUF_Destroy(buf);
  402.     return str;
  403. }
  404. /*
  405.  * Note parameters' ranges here:
  406.  * 0.0 <= pref <= 1.0
  407.  * 0.0 <  gap  <= 1.0
  408.  * n >= 2
  409.  * Hence, the formula below always yields a value in the range [0.0 .. 1.0].
  410.  */
  411. double SERV_Preference(double pref, double gap, unsigned int n)
  412. {
  413.     assert(0.0 <= pref && pref <= 1.0);
  414.     assert(0.0 <  gap  && gap  <= 1.0);
  415.     assert(n >= 2);
  416.     if (gap >= pref)
  417.         return gap;
  418.     else if (gap >= 0.75*(1.0/(double) n))
  419.         return pref;
  420.     else
  421.         return 2.5*gap*pref;
  422. }
  423. /*
  424.  * --------------------------------------------------------------------------
  425.  * $Log: ncbi_service.c,v $
  426.  * Revision 1000.3  2004/06/01 18:45:22  gouriano
  427.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.52
  428.  *
  429.  * Revision 6.52  2004/05/17 18:19:43  lavr
  430.  * Mark skip infos with maximal time instead of calculating 1 year from now
  431.  *
  432.  * Revision 6.51  2004/03/23 02:28:21  lavr
  433.  * Limit service name resolution recursion by 8
  434.  *
  435.  * Revision 6.50  2004/01/30 14:37:26  lavr
  436.  * Client revision made independent of CVS revisions
  437.  *
  438.  * Revision 6.49  2003/09/02 21:17:15  lavr
  439.  * Clean up included headers
  440.  *
  441.  * Revision 6.48  2003/06/26 15:20:46  lavr
  442.  * Additional parameter "external" in implementation of generic methods
  443.  *
  444.  * Revision 6.47  2003/06/09 19:53:01  lavr
  445.  * +SERV_OpenP()
  446.  *
  447.  * Revision 6.46  2003/04/30 17:00:47  lavr
  448.  * Name collision resolved
  449.  *
  450.  * Revision 6.45  2003/02/28 14:49:04  lavr
  451.  * SERV_Preference(): redeclare last argument 'unsigned'
  452.  *
  453.  * Revision 6.44  2003/02/13 22:04:16  lavr
  454.  * Document SERV_Preference() domain, change last argument, tweak formula
  455.  *
  456.  * Revision 6.43  2003/01/31 21:19:30  lavr
  457.  * +SERV_GetInfoP(), preference measure for preferred host, SERV_Preference()
  458.  *
  459.  * Revision 6.42  2002/11/12 05:53:01  lavr
  460.  * Fit a long line within 80 chars
  461.  *
  462.  * Revision 6.41  2002/10/28 20:16:00  lavr
  463.  * Take advantage of host info API
  464.  *
  465.  * Revision 6.40  2002/10/28 15:43:49  lavr
  466.  * Use "ncbi_ansi_ext.h" privately and use strncpy0()
  467.  *
  468.  * Revision 6.39  2002/10/11 19:48:10  lavr
  469.  * +SERV_GetConfig()
  470.  * const dropped in return value of SERV_ServiceName()
  471.  *
  472.  * Revision 6.38  2002/09/04 15:11:41  lavr
  473.  * Log moved to end
  474.  *
  475.  * Revision 6.37  2002/05/06 19:16:50  lavr
  476.  * +#include <stdio.h>, +SERV_ServiceName() - translation of service name
  477.  *
  478.  * Revision 6.36  2002/04/15 20:07:09  lavr
  479.  * Use size_t for iterating over skip_info's
  480.  *
  481.  * Revision 6.35  2002/04/13 06:35:11  lavr
  482.  * Fast track routine SERV_GetInfoEx(), many syscalls optimizations
  483.  *
  484.  * Revision 6.34  2002/03/22 19:51:28  lavr
  485.  * Do not explicitly include <assert.h>: included from ncbi_core.h
  486.  *
  487.  * Revision 6.33  2002/03/11 21:59:32  lavr
  488.  * 'Client version' changed into 'Client revision'
  489.  *
  490.  * Revision 6.32  2001/11/09 20:03:14  lavr
  491.  * Minor fix to remove a trailing space in client version tag
  492.  *
  493.  * Revision 6.31  2001/10/01 19:52:38  lavr
  494.  * Call update directly; do not remove time from server specs in SERV_Print()
  495.  *
  496.  * Revision 6.30  2001/09/29 19:33:04  lavr
  497.  * BUGFIX: SERV_Update() requires VT bound (was not the case in constructor)
  498.  *
  499.  * Revision 6.29  2001/09/28 22:03:12  vakatov
  500.  * Included missing <connect/ncbi_ansi_ext.h>
  501.  *
  502.  * Revision 6.28  2001/09/28 20:50:16  lavr
  503.  * SERV_Update() modified to capture Used-Server-Info tags;
  504.  * Update VT method changed - now called on per-line basis;
  505.  * Few bugfixes related to keeping last info correct
  506.  *
  507.  * Revision 6.27  2001/09/24 20:28:48  lavr
  508.  * +SERV_Reset(); SERV_Close() changed to utilize SERV_Reset()
  509.  *
  510.  * Revision 6.26  2001/09/10 21:19:48  lavr
  511.  * SERV_Print():  Client version tag added
  512.  * SERV_OpenEx(): Firewall type handling
  513.  *
  514.  * Revision 6.25  2001/08/20 21:58:19  lavr
  515.  * Parameter change for clarity: info -> net_info if type is SConnNetInfo
  516.  *
  517.  * Revision 6.24  2001/06/25 15:35:54  lavr
  518.  * Added function: SERV_GetNextInfoEx
  519.  *
  520.  * Revision 6.23  2001/06/20 17:27:49  kans
  521.  * include <time.h> for Mac compiler
  522.  *
  523.  * Revision 6.22  2001/06/19 19:12:01  lavr
  524.  * Type change: size_t -> TNCBI_Size; time_t -> TNCBI_Time
  525.  *
  526.  * Revision 6.21  2001/05/24 21:28:12  lavr
  527.  * Timeout for skip servers increased to 1 year period
  528.  *
  529.  * Revision 6.20  2001/05/17 15:02:51  lavr
  530.  * Typos corrected
  531.  *
  532.  * Revision 6.19  2001/04/24 21:37:26  lavr
  533.  * New code for: SERV_MapperName() and SERV_Penalize().
  534.  *
  535.  * Revision 6.18  2001/03/21 21:23:30  lavr
  536.  * Explicit type conversion size_t -> unsigned in printf
  537.  *
  538.  * Revision 6.17  2001/03/20 22:03:32  lavr
  539.  * BUGFIX in SERV_Print (miscalculation of buflen for accepted server types)
  540.  *
  541.  * Revision 6.16  2001/03/06 23:55:25  lavr
  542.  * SOCK_gethostaddr -> SOCK_gethostbyname
  543.  *
  544.  * Revision 6.15  2001/03/05 23:10:29  lavr
  545.  * SERV_WriteInfo takes only one argument now
  546.  *
  547.  * Revision 6.14  2001/03/02 20:09:51  lavr
  548.  * Support added for SERV_LOCALHOST as preferred_host.
  549.  *
  550.  * Revision 6.13  2001/03/01 00:31:23  lavr
  551.  * SERV_OpenSimple now builds SConnNetInfo to use both LBSMD and DISPD.CGI
  552.  *
  553.  * Revision 6.12  2001/02/09 17:33:06  lavr
  554.  * Modified: fSERV_StatelessOnly overrides info->stateless
  555.  *
  556.  * Revision 6.11  2001/01/25 17:05:32  lavr
  557.  * Bugfix in SERV_OpenEx: op was not inited to 0
  558.  *
  559.  * Revision 6.10  2001/01/08 23:47:29  lavr
  560.  * (unsigned char) conversion in isspace
  561.  *
  562.  * Revision 6.9  2001/01/08 22:38:34  lavr
  563.  * Numerous patches to code after debugging
  564.  *
  565.  * Revision 6.8  2000/12/29 18:01:27  lavr
  566.  * SERV_Print introduced; pool of skipped services now follows
  567.  * expiration times of services and is updated on that basis.
  568.  *
  569.  * Revision 6.7  2000/12/06 22:20:30  lavr
  570.  * Skip info list is not maintained forever; instead the entries get
  571.  * deleted in accordance with their expiration period
  572.  *
  573.  * Revision 6.6  2000/10/20 17:19:04  lavr
  574.  * SConnNetInfo made 'const' as a parameter to 'SERV_Open*'
  575.  * 'SERV_Update' added as a private interface
  576.  *
  577.  * Revision 6.5  2000/10/05 22:36:21  lavr
  578.  * Additional parameters in call to DISPD mapper
  579.  *
  580.  * Revision 6.4  2000/05/31 23:12:23  lavr
  581.  * First try to assemble things together to get working service mapper
  582.  *
  583.  * Revision 6.3  2000/05/22 16:53:11  lavr
  584.  * Rename service_info -> server_info everywhere (including
  585.  * file names) as the latter name is more relevant
  586.  *
  587.  * Revision 6.2  2000/05/12 21:42:59  lavr
  588.  * Cleaned up for the C++ compilation, etc.
  589.  *
  590.  * Revision 6.1  2000/05/12 18:50:20  lavr
  591.  * First working revision
  592.  *
  593.  * ==========================================================================
  594.  */