src/connect/ncbi_service.c

Go to the documentation of this file.
00001 /* $Id: ncbi_service.c 175891 2009-11-12 18:24:56Z lavr $
00002  * ===========================================================================
00003  *
00004  *                            PUBLIC DOMAIN NOTICE
00005  *               National Center for Biotechnology Information
00006  *
00007  *  This software/database is a "United States Government Work" under the
00008  *  terms of the United States Copyright Act.  It was written as part of
00009  *  the author's official duties as a United States Government employee and
00010  *  thus cannot be copyrighted.  This software/database is freely available
00011  *  to the public for use. The National Library of Medicine and the U.S.
00012  *  Government have not placed any restriction on its use or reproduction.
00013  *
00014  *  Although all reasonable efforts have been taken to ensure the accuracy
00015  *  and reliability of the software and data, the NLM and the U.S.
00016  *  Government do not and cannot warrant the performance or results that
00017  *  may be obtained by using this software or data. The NLM and the U.S.
00018  *  Government disclaim all warranties, express or implied, including
00019  *  warranties of performance, merchantability or fitness for any particular
00020  *  purpose.
00021  *
00022  *  Please cite the author in any work or product based on this material.
00023  *
00024  * ===========================================================================
00025  *
00026  * Author:  Anton Lavrentiev
00027  *
00028  * File Description:
00029  *   Top-level API to resolve NCBI service name to the server meta-address.
00030  *
00031  */
00032 
00033 #include "ncbi_ansi_ext.h"
00034 #include "ncbi_dispd.h"
00035 #include "ncbi_lbsmd.h"
00036 #include "ncbi_local.h"
00037 #include "ncbi_priv.h"
00038 #include <ctype.h>
00039 #include <stdlib.h>
00040 #include <time.h>
00041 
00042 #define NCBI_USE_ERRCODE_X   Connect_Service
00043 
00044 #define CONN_SERVICE_NAME  DEF_CONN_REG_SECTION "_" REG_CONN_SERVICE_NAME
00045 
00046 
00047 static ESwitch s_Fast = eOff;
00048 
00049 
00050 ESwitch SERV_DoFastOpens(ESwitch on)
00051 {
00052     ESwitch retval = s_Fast;
00053     if (on != eDefault)
00054         s_Fast = on;
00055     return retval;
00056 }
00057 
00058 
00059 static char* s_ServiceName(const char* service, size_t depth)
00060 {
00061     char   buf[128];
00062     char   srv[128];
00063     size_t len;
00064     char*  s;
00065 
00066     if (depth > 7) {
00067         CORE_LOGF_X(7, eLOG_Error,
00068                     ("[%s]  Maximal service name recursion depth reached: %lu",
00069                      service, (unsigned long) depth));
00070         return 0/*failure*/;
00071     }
00072     if (!service  ||  !*service  ||
00073         (len = strlen(service)) + sizeof(CONN_SERVICE_NAME) >= sizeof(buf)) {
00074         CORE_LOGF_X(8, eLOG_Error,
00075                     ("[%s]  %s service name",
00076                      !service ? "<NULL>" :  service,
00077                      !service ?  "NULL"  : *service ? "Too long" : "Empty"));
00078         return 0/*failure*/;
00079     }
00080     s = (char*) memcpy(buf, service, len) + len;
00081     *s++ = '_';
00082     memcpy(s, CONN_SERVICE_NAME, sizeof(CONN_SERVICE_NAME));
00083     /* Looking for "service_CONN_SERVICE_NAME" in the environment */
00084     if (!(s = getenv(strupr(buf)))  ||  !*s) {
00085         /* Looking for "CONN_SERVICE_NAME" in registry's section [service] */
00086         buf[len++] = '\0';
00087         CORE_REG_GET(buf, buf + len, srv, sizeof(srv), 0);
00088         s = srv;
00089     }
00090     if (!*s  ||  strcasecmp(s, service) == 0)
00091         return strdup(service);
00092     return s_ServiceName(s, ++depth);
00093 }
00094 
00095 
00096 char* SERV_ServiceName(const char* service)
00097 {
00098     return s_ServiceName(service, 0);
00099 }
00100 
00101 
00102 static int/*bool*/ s_AddSkipInfo(SERV_ITER   iter,
00103                                  const char* name,
00104                                  SSERV_Info* info)
00105 {
00106     size_t n;
00107     assert(name);
00108     for (n = 0; n < iter->n_skip; n++) {
00109         if (strcasecmp(name, SERV_NameOfInfo(iter->skip[n])) == 0  &&
00110             (SERV_EqualInfo(info, iter->skip[n])  ||
00111              (iter->skip[n]->type == fSERV_Firewall  &&
00112               iter->skip[n]->u.firewall.type == info->u.firewall.type))) {
00113             /* Replace older version */
00114             if (iter->last == iter->skip[n])
00115                 iter->last = info;
00116             free(iter->skip[n]);
00117             iter->skip[n] = info;
00118             return 1;
00119         }
00120     }
00121     if (iter->n_skip == iter->a_skip) {
00122         SSERV_Info** temp;
00123         n = iter->a_skip + 10;
00124         temp = (SSERV_Info**)
00125             (iter->skip
00126              ? realloc(iter->skip, n * sizeof(*temp))
00127              : malloc (            n * sizeof(*temp)));
00128         if (!temp)
00129             return 0;
00130         iter->skip = temp;
00131         iter->a_skip = n;
00132     }
00133     iter->skip[iter->n_skip++] = info;
00134     return 1;
00135 }
00136 
00137 
00138 #ifdef __GNUC__
00139 inline
00140 #endif /*__GNUC__*/
00141 static int/*bool*/ s_IsMapperConfigured(const char* service, const char* key)
00142 {
00143     char val[80];
00144     if (s_Fast)
00145         return 0;
00146     ConnNetInfo_GetValue(service, key, val, sizeof(val), 0);
00147     return *val  &&  (strcmp    (val, "1")    == 0  ||
00148                       strcasecmp(val, "on")   == 0  ||
00149                       strcasecmp(val, "yes")  == 0  ||
00150                       strcasecmp(val, "true") == 0);
00151 }
00152 
00153 
00154 static SERV_ITER s_Open(const char*          service,
00155                         unsigned/*bool*/     ismask,
00156                         TSERV_Type           types,
00157                         unsigned int         preferred_host,
00158                         unsigned short       preferred_port,
00159                         double               preference,
00160                         const SConnNetInfo*  net_info,
00161                         const SSERV_InfoCPtr skip[],
00162                         size_t               n_skip,
00163                         unsigned/*bool*/     external,
00164                         const char*          arg,
00165                         const char*          val,
00166                         SSERV_Info**         info,
00167                         HOST_INFO*           host_info)
00168 {
00169     int/*bool*/ do_lbsmd = -1/*unassigned*/, do_dispd = -1/*unassigned*/;
00170     const SSERV_VTable* op;
00171     SERV_ITER iter;
00172     const char* s;
00173     
00174     if (!service || !*service)
00175         return 0;
00176     if (!(s = ismask || s_Fast ? strdup(service) : s_ServiceName(service, 0)))
00177         return 0;
00178     if (!*s || !(iter = (SERV_ITER) calloc(1, sizeof(*iter)))) {
00179         free((void*) s);
00180         return 0;
00181     }
00182 
00183     iter->name              = s;
00184     iter->type              = types & fSERV_All;
00185     iter->host              = (preferred_host == SERV_LOCALHOST
00186                                ? SOCK_GetLocalHostAddress(eDefault)
00187                                : preferred_host);
00188     iter->port              = preferred_port;
00189     iter->pref              = (preference < 0.0
00190                                ? -1.0
00191                                :  0.01 * (preference > 100.0
00192                                           ? 100.0
00193                                           : preference));
00194     if (ismask)
00195         iter->ismask        = 1;
00196     if (types & fSERV_IncludeDown)
00197         iter->ok_down       = 1;
00198     if (types & fSERV_IncludeSuppressed)
00199         iter->ok_suppressed = 1;
00200     if (types & fSERV_ReverseDns)
00201         iter->reverse_dns   = 1;
00202     if (types & fSERV_Stateless)
00203         iter->stateless     = 1;
00204     iter->external          = external;
00205     if (arg  &&  *arg) {
00206         iter->arg           = arg;
00207         iter->arglen        = strlen(arg);
00208         if (val) {
00209             iter->val       = val;
00210             iter->vallen    = strlen(val);
00211         }
00212     }
00213     iter->time              = (TNCBI_Time) time(0);
00214 
00215     if (n_skip) {
00216         size_t i;
00217         for (i = 0; i < n_skip; i++) {
00218             const char* name = (iter->ismask  ||  skip[i]->type == fSERV_Dns
00219                                 ? SERV_NameOfInfo(skip[i]) : "");
00220             SSERV_Info* temp = SERV_CopyInfoEx(skip[i],
00221                                                !iter->reverse_dns  ||  *name ?
00222                                                name : s);
00223             if (temp) {
00224                 temp->time = NCBI_TIME_INFINITE;
00225                 if (!s_AddSkipInfo(iter, name, temp)) {
00226                     free(temp);
00227                     temp = 0;
00228                 }
00229             }
00230             if (!temp) {
00231                 SERV_Close(iter);
00232                 return 0;
00233             }
00234         }
00235     }
00236     assert(n_skip == iter->n_skip);
00237 
00238     if (net_info) {
00239         if (net_info->firewall)
00240             iter->type |= fSERV_Firewall;
00241         if (net_info->stateless)
00242             iter->stateless = 1;
00243         if (net_info->lb_disable)
00244             do_lbsmd = 0/*false*/;
00245     } else
00246         do_dispd = 0/*false*/;
00247     /* Ugly optimization not to access the registry more than necessary */
00248     if ((!s_IsMapperConfigured(service, REG_CONN_LOCAL_ENABLE)  ||
00249          !(op = SERV_LOCAL_Open(iter, info, host_info)))  &&
00250         (!do_lbsmd  ||
00251          !(do_lbsmd= !s_IsMapperConfigured(service, REG_CONN_LBSMD_DISABLE)) ||
00252          !(op = SERV_LBSMD_Open(iter, info, host_info,
00253                                 !do_dispd  ||
00254                                 !(do_dispd = !s_IsMapperConfigured
00255                                   (service, REG_CONN_DISPD_DISABLE)))))  &&
00256         (!do_dispd  ||
00257          !(do_dispd= !s_IsMapperConfigured(service, REG_CONN_DISPD_DISABLE)) ||
00258          !(op = SERV_DISPD_Open(iter, net_info, info, host_info)))) {
00259         if (!do_lbsmd  &&  !do_dispd) {
00260             CORE_LOGF_X(1, eLOG_Error,
00261                         ("[%s]  No service mappers available", service));
00262         }
00263         SERV_Close(iter);
00264         return 0;
00265     }
00266 
00267     assert(op != 0);
00268     iter->op = op;
00269     return iter;
00270 }
00271 
00272 
00273 SERV_ITER SERV_OpenSimple(const char* service)
00274 {
00275     SConnNetInfo* net_info = ConnNetInfo_Create(service);
00276     SERV_ITER iter = SERV_Open(service, fSERV_Any, 0, net_info);
00277     ConnNetInfo_Destroy(net_info);
00278     return iter;
00279 }
00280 
00281 
00282 SERV_ITER SERV_Open(const char*         service,
00283                     TSERV_Type          types,
00284                     unsigned int        preferred_host,
00285                     const SConnNetInfo* net_info)
00286 {
00287     return s_Open(service, 0/*not mask*/, types,
00288                   preferred_host, 0/*preferred_port*/, 0.0/*preference*/,
00289                   net_info, 0/*skip*/, 0/*n_skip*/,
00290                   0/*not external*/, 0/*arg*/, 0/*val*/,
00291                   0/*info*/, 0/*host_info*/);
00292 }
00293 
00294 
00295 SERV_ITER SERV_OpenEx(const char*          service,
00296                       TSERV_Type           types,
00297                       unsigned int         preferred_host,
00298                       const SConnNetInfo*  net_info,
00299                       const SSERV_InfoCPtr skip[],
00300                       size_t               n_skip)
00301 {
00302     return s_Open(service, 0/*not mask*/, types,
00303                   preferred_host, 0/*preferred_port*/, 0.0/*preference*/,
00304                   net_info, skip, n_skip,
00305                   0/*not external*/, 0/*arg*/, 0/*val*/,
00306                   0/*info*/, 0/*host_info*/);
00307 }
00308 
00309 
00310 SERV_ITER SERV_OpenP(const char*          service,
00311                      TSERV_Type           types,
00312                      unsigned int         preferred_host,
00313                      unsigned short       preferred_port,
00314                      double               preference,
00315                      const SConnNetInfo*  net_info,
00316                      const SSERV_InfoCPtr skip[],
00317                      size_t               n_skip,
00318                      int/*bool*/          external,
00319                      const char*          arg,
00320                      const char*          val)
00321 {
00322     return s_Open(service, strpbrk(service, "?*") != 0, types,
00323                   preferred_host, preferred_port, preference,
00324                   net_info, skip, n_skip,
00325                   external, arg, val,
00326                   0/*info*/, 0/*host_info*/);
00327 }
00328 
00329 
00330 static void s_SkipSkip(SERV_ITER iter)
00331 {
00332     size_t n;
00333     if (iter->time  &&  (iter->ismask  ||  (iter->type & fSERV_Promiscuous)))
00334         return;
00335     n = 0;
00336     while (n < iter->n_skip) {
00337         SSERV_Info* temp = iter->skip[n];
00338         if (temp->time != NCBI_TIME_INFINITE
00339             &&  (!iter->time
00340                  ||  ((temp->type != fSERV_Dns  ||  temp->host)
00341                       &&  temp->time < iter->time))) {
00342             if (n < --iter->n_skip) {
00343                 memmove(iter->skip + n, iter->skip + n + 1,
00344                         sizeof(*iter->skip)*(iter->n_skip - n));
00345             }
00346             if (iter->last == temp)
00347                 iter->last = 0;
00348             free(temp);
00349         } else
00350             n++;
00351     }
00352 }
00353 
00354 
00355 static SSERV_Info* s_GetNextInfo(SERV_ITER   iter,
00356                                  HOST_INFO*  host_info,
00357                                  int/*bool*/ internal)
00358 {
00359     SSERV_Info* info = 0;
00360     assert(iter  &&  iter->op);
00361     if (iter->op->GetNextInfo) {
00362         if (!internal) {
00363             iter->time = (TNCBI_Time) time(0);
00364             s_SkipSkip(iter);
00365         }
00366         /* Obtain a fresh entry from the actual mapper */
00367         while ((info = (*iter->op->GetNextInfo)(iter, host_info)) != 0) {
00368             /* This should never actually be used for LBSMD dispatcher,
00369              * as all exclusion logic is already done in it internally. */
00370             int/*bool*/ go =
00371                 !info->host  ||  iter->pref >= 0.0  ||
00372                 !iter->host  ||  (iter->host == info->host  &&
00373                                   (!iter->port  ||  iter->port == info->port));
00374             if (go  &&  internal)
00375                 break;
00376             if (!s_AddSkipInfo(iter, SERV_NameOfInfo(info), info)) {
00377                 free(info);
00378                 info = 0;
00379             }
00380             if (go  ||  !info)
00381                 break;
00382         }
00383     }
00384     if (!internal)
00385         iter->last = info;
00386     return info;
00387 }
00388 
00389 
00390 static SSERV_Info* s_GetInfo(const char*          service,
00391                              TSERV_Type           types,
00392                              unsigned int         preferred_host,
00393                              unsigned short       preferred_port,
00394                              double               preference,
00395                              const SConnNetInfo*  net_info,
00396                              const SSERV_InfoCPtr skip[],
00397                              size_t               n_skip,
00398                              int /*bool*/         external,
00399                              const char*          arg,
00400                              const char*          val,
00401                              HOST_INFO*           host_info)
00402 {
00403     SSERV_Info* info = 0;
00404     SERV_ITER iter = s_Open(service, 0/*not mask*/, types,
00405                             preferred_host, preferred_port, preference,
00406                             net_info, skip, n_skip,
00407                             external, arg, val,
00408                             &info, host_info);
00409     if (iter  &&  iter->op  &&  !info) {
00410         /* All LOCAL/DISPD searches end up here, but none LBSMD ones */
00411         info = s_GetNextInfo(iter, host_info, 1/*internal*/);
00412     }
00413     SERV_Close(iter);
00414     return info;
00415 }
00416 
00417 
00418 SSERV_Info* SERV_GetInfo(const char*         service,
00419                          TSERV_Type          types,
00420                          unsigned int        preferred_host,
00421                          const SConnNetInfo* net_info)
00422 {
00423     return s_GetInfo(service, types,
00424                      preferred_host, 0/*preferred_port*/, 0.0/*preference*/,
00425                      net_info, 0/*skip*/, 0/*n_skip*/,
00426                      0/*not external*/, 0/*arg*/, 0/*val*/,
00427                      0/*host_info*/);
00428 }
00429 
00430 
00431 SSERV_Info* SERV_GetInfoEx(const char*          service,
00432                            TSERV_Type           types,
00433                            unsigned int         preferred_host,
00434                            const SConnNetInfo*  net_info,
00435                            const SSERV_InfoCPtr skip[],
00436                            size_t               n_skip,
00437                            HOST_INFO*           host_info)
00438 {
00439     return s_GetInfo(service, types,
00440                      preferred_host, 0/*preferred_host*/, 0.0/*preference*/,
00441                      net_info, skip, n_skip,
00442                      0/*not external*/, 0/*arg*/, 0/*val*/,
00443                      host_info);
00444 }
00445 
00446 
00447 SSERV_Info* SERV_GetInfoP(const char*          service,
00448                           TSERV_Type           types,
00449                           unsigned int         preferred_host,
00450                           unsigned short       preferred_port,
00451                           double               preference,
00452                           const SConnNetInfo*  net_info,
00453                           const SSERV_InfoCPtr skip[],
00454                           size_t               n_skip,
00455                           int/*bool*/          external, 
00456                           const char*          arg,
00457                           const char*          val,
00458                           HOST_INFO*           host_info)
00459 {
00460     return s_GetInfo(service, types,
00461                      preferred_host, preferred_port, preference,
00462                      net_info, skip, n_skip,
00463                      external, arg, val,
00464                      host_info);
00465 }
00466 
00467 
00468 const SSERV_Info* SERV_GetNextInfoEx(SERV_ITER  iter,
00469                                      HOST_INFO* host_info)
00470 {
00471     return iter  &&  iter->op ? s_GetNextInfo(iter, host_info, 0) : 0;
00472 }
00473 
00474 
00475 const SSERV_Info* SERV_GetNextInfo(SERV_ITER iter)
00476 {
00477     return iter  &&  iter->op ? s_GetNextInfo(iter, 0, 0) : 0;
00478 }
00479 
00480 
00481 const char* SERV_MapperName(SERV_ITER iter)
00482 {
00483     return iter  &&  iter->op ? iter->op->name : 0;
00484 }
00485 
00486 
00487 const char* SERV_CurrentName(SERV_ITER iter)
00488 {
00489     const char* name = SERV_NameOfInfo(iter->last);
00490     return name  &&  *name ? name : iter->name;
00491 }
00492 
00493 
00494 int/*bool*/ SERV_Penalize(SERV_ITER iter, double fine)
00495 {
00496     if (!iter  ||  !iter->op  ||  !iter->op->Feedback  ||  !iter->last)
00497         return 0/*false*/;
00498     return (*iter->op->Feedback)(iter, fine, 1/*i.e.fine*/);
00499 }
00500 
00501 
00502 int/*bool*/ SERV_Rerate(SERV_ITER iter, double rate)
00503 {
00504     if (!iter  ||  !iter->op  ||  !iter->op->Feedback  ||  !iter->last)
00505         return 0/*false*/;
00506     return (*iter->op->Feedback)(iter, rate, 0/*i.e.rate*/);
00507 }
00508 
00509 
00510 void SERV_Reset(SERV_ITER iter)
00511 {
00512     if (!iter)
00513         return;
00514     iter->last  = 0;
00515     iter->time  = 0;
00516     s_SkipSkip(iter);
00517     if (iter->op  &&  iter->op->Reset)
00518         (*iter->op->Reset)(iter);
00519 }
00520 
00521 
00522 void SERV_Close(SERV_ITER iter)
00523 {
00524     size_t i;
00525     if (!iter)
00526         return;
00527     SERV_Reset(iter);
00528     for (i = 0; i < iter->n_skip; i++)
00529         free(iter->skip[i]);
00530     iter->n_skip = 0;
00531     if (iter->op) {
00532         if (iter->op->Close)
00533             (*iter->op->Close)(iter);
00534         iter->op = 0;
00535     }
00536     if (iter->skip)
00537         free(iter->skip);
00538     if (iter->name)
00539         free((void*) iter->name);
00540     free(iter);
00541 }
00542 
00543 
00544 int/*bool*/ SERV_Update(SERV_ITER iter, const char* text, int code)
00545 {
00546     static const char used_server_info[] = "Used-Server-Info-";
00547     int retval = 0/*not updated yet*/;
00548 
00549     if (iter  &&  iter->op  &&  text) {
00550         const char *c, *b;
00551         iter->time = (TNCBI_Time) time(0);
00552         for (b = text; (c = strchr(b, '\n')) != 0; b = c + 1) {
00553             size_t len = (size_t)(c - b);
00554             SSERV_Info* info;
00555             unsigned int d1;
00556             char* p, *t;
00557             int d2;
00558 
00559             if (!(t = (char*) malloc(len + 1)))
00560                 continue;
00561             memcpy(t, b, len);
00562             if (t[len - 1] == '\r')
00563                 t[len - 1] = '\0';
00564             else
00565                 t[len] = '\0';
00566             p = t;
00567             if (iter->op->Update  &&  (*iter->op->Update)(iter, p, code))
00568                 retval = 1/*updated*/;
00569             if (!strncasecmp(p, used_server_info, sizeof(used_server_info) - 1)
00570                 &&  isdigit((unsigned char) p[sizeof(used_server_info) - 1])) {
00571                 p += sizeof(used_server_info) - 1;
00572                 if (sscanf(p, "%u: %n", &d1, &d2) >= 1  &&
00573                     (info = SERV_ReadInfoEx(p + d2, "")) != 0) {
00574                     if (!s_AddSkipInfo(iter, "", info))
00575                         free(info);
00576                     else
00577                         retval = 1/*updated*/;
00578                 }
00579             }
00580             free(t);
00581         }
00582     }
00583     return retval;
00584 }
00585 
00586 
00587 static void s_SetDefaultReferer(SERV_ITER iter, SConnNetInfo* net_info)
00588 {
00589     char* str, *referer = 0;
00590 
00591     if (strcasecmp(iter->op->name, "DISPD") == 0)
00592         referer = ConnNetInfo_URL(net_info);
00593     else if ((str = strdup(iter->op->name)) != 0) {
00594         const char* host = net_info->client_host;
00595         const char* args = net_info->args;
00596         const char* name = iter->name;
00597 
00598         if (!*net_info->client_host
00599             &&  !SOCK_gethostbyaddr(0, net_info->client_host,
00600                                     sizeof(net_info->client_host))) {
00601             SOCK_gethostname(net_info->client_host,
00602                              sizeof(net_info->client_host));
00603         }
00604         if (!(referer = (char*) malloc(3 + 1 + 1 + 1 + 2*strlen(strlwr(str)) +
00605                                        strlen(host) + (args[0]
00606                                                        ? strlen(args)
00607                                                        : 8 + strlen(name))))) {
00608             return;
00609         }
00610         strcat(strcat(strcat(strcat(strcpy
00611                                     (referer, str), "://"), host), "/"), str);
00612         if (args[0])
00613             strcat(strcat(referer, "?"),         args);
00614         else
00615             strcat(strcat(referer, "?service="), name);
00616         free(str);
00617     }
00618     assert(!net_info->http_referer);
00619     net_info->http_referer = referer;
00620 }
00621 
00622 
00623 char* SERV_Print(SERV_ITER iter, SConnNetInfo* net_info, int/*bool*/ but_last)
00624 {
00625     static const char kClientRevision[] = "Client-Revision: %hu.%hu\r\n";
00626     static const char kAcceptedServerTypes[] = "Accepted-Server-Types:";
00627     static const char kUsedServerInfo[] = "Used-Server-Info: ";
00628     static const char kServerCount[] = "Server-Count: ";
00629     static const char kSkipInfo[] = "Skip-Info-%u: ";
00630     static const char kAffinity[] = "Affinity: ";
00631     char buffer[128], *str;
00632     size_t buflen, i;
00633     TSERV_Type t;
00634     BUF buf = 0;
00635 
00636     /* Put client version number */
00637     buflen = sprintf(buffer, kClientRevision,
00638                      SERV_CLIENT_REVISION_MAJOR, SERV_CLIENT_REVISION_MINOR);
00639     assert(buflen < sizeof(buffer));
00640     if (!BUF_Write(&buf, buffer, buflen)) {
00641         BUF_Destroy(buf);
00642         return 0;
00643     }
00644     if (iter) {
00645         if (net_info && !net_info->http_referer && iter->op && iter->op->name)
00646             s_SetDefaultReferer(iter, net_info);
00647         /* Form accepted server types */
00648         buflen = sizeof(kAcceptedServerTypes) - 1;
00649         memcpy(buffer, kAcceptedServerTypes, buflen);
00650         for (t = 1; t; t <<= 1) {
00651             if (iter->type & t) {
00652                 const char* name = SERV_TypeStr((ESERV_Type) t);
00653                 size_t namelen = strlen(name);
00654                 if (!namelen || buflen + 1 + namelen + 2 >= sizeof(buffer))
00655                     break;
00656                 buffer[buflen++] = ' ';
00657                 memcpy(buffer + buflen, name, namelen);
00658                 buflen += namelen;
00659             }
00660         }
00661         if (buffer[buflen - 1] != ':') {
00662             strcpy(&buffer[buflen], "\r\n");
00663             assert(strlen(buffer) == buflen+2  &&  buflen+2 < sizeof(buffer));
00664             if (!BUF_Write(&buf, buffer, buflen + 2)) {
00665                 BUF_Destroy(buf);
00666                 return 0;
00667             }
00668         }
00669         if (iter->ismask  ||  (iter->pref  &&  iter->host)) {
00670             /* How many server-infos for the dispatcher to send to us */
00671             if (!BUF_Write(&buf, kServerCount, sizeof(kServerCount) - 1)  ||
00672                 !BUF_Write(&buf,
00673                            iter->ismask ? "10" : "ALL",
00674                            iter->ismask ?   2  :    3)                    ||
00675                 !BUF_Write(&buf, "\r\n", 2)) {
00676                 BUF_Destroy(buf);
00677                 return 0;
00678             }
00679         }
00680         if (iter->arglen) {
00681             /* Affinity */
00682             if (!BUF_Write(&buf, kAffinity, sizeof(kAffinity) - 1)           ||
00683                 !BUF_Write(&buf, iter->arg, iter->arglen)                    ||
00684                 (iter->val  &&  (!BUF_Write(&buf, "=", 1)                    ||
00685                                  !BUF_Write(&buf, iter->val, iter->vallen))) ||
00686                 !BUF_Write(&buf, "\r\n", 2)) {
00687                 BUF_Destroy(buf);
00688                 return 0;
00689             }
00690         }
00691         /* Drop any outdated skip entries */
00692         iter->time = (TNCBI_Time) time(0);
00693         s_SkipSkip(iter);
00694         /* Put all the rest into rejection list */
00695         for (i = 0; i < iter->n_skip; i++) {
00696             /* NB: all skip infos are now kept with names (perhaps, empty) */
00697             const char* name = SERV_NameOfInfo(iter->skip[i]);
00698             if (!(str = SERV_WriteInfo(iter->skip[i])))
00699                 break;
00700             if (but_last  &&  iter->last == iter->skip[i]) {
00701                 buflen = sizeof(kUsedServerInfo) - 1;
00702                 memcpy(buffer, kUsedServerInfo, buflen);
00703             } else
00704                 buflen = sprintf(buffer, kSkipInfo, (unsigned) i + 1); 
00705             assert(buflen < sizeof(buffer) - 1);
00706             if (!BUF_Write(&buf, buffer, buflen)                  ||
00707                 (name  &&  !BUF_Write(&buf, name, strlen(name)))  ||
00708                 (name  &&  *name  &&  !BUF_Write(&buf, " ", 1))   ||
00709                 !BUF_Write(&buf, str, strlen(str))                ||
00710                 !BUF_Write(&buf, "\r\n", 2)) {
00711                 free(str);
00712                 break;
00713             }
00714             free(str);
00715         }
00716         if (i < iter->n_skip) {
00717             BUF_Destroy(buf);
00718             return 0;
00719         }
00720     }
00721     /* Ok then, we have filled the entire header, <CR><LF> terminated */
00722     if ((buflen = BUF_Size(buf)) != 0) {
00723         if ((str = (char*) malloc(buflen + 1)) != 0) {
00724             if (BUF_Read(buf, str, buflen) != buflen) {
00725                 free(str);
00726                 str = 0;
00727             } else
00728                 str[buflen] = '\0';
00729         }
00730     } else
00731         str = 0;
00732     BUF_Destroy(buf);
00733     return str;
00734 }
00735 
00736 
00737 /*
00738  * Note parameters' ranges here:
00739  * 0.0 <= pref <= 1.0
00740  * 0.0 <  gap  <= 1.0
00741  * n >= 2
00742  * Hence, the formula below always yields a value in the range [0.0 .. 1.0].
00743  */
00744 double SERV_Preference(double pref, double gap, size_t n)
00745 {
00746     double spread;
00747     assert(0.0 <= pref && pref <= 1.0);
00748     assert(0.0 <  gap  && gap  <= 1.0);
00749     assert(n >= 2);
00750     if (gap >= pref)
00751         return gap;
00752     spread = 14.0/(n + 12.0);
00753     if (gap >= spread/((double) n))
00754         return pref;
00755     else
00756         return 2.0/spread*gap*pref;
00757 }
00758 
00759 
00760 unsigned short SERV_ServerPort(const char*  name,
00761                                unsigned int host)
00762 {
00763     SSERV_Info*    info;
00764     unsigned short port;
00765 
00766     /* FIXME:  SERV_LOCALHOST may not need to be resolved here,
00767      *         but taken from LBSMD table (or resolved later in DISPD/LOCAL
00768      *         if needed).
00769      */
00770     if (!host  ||  host == SERV_LOCALHOST)
00771         host = SOCK_GetLocalHostAddress(eDefault);
00772     if (!(info = s_GetInfo(name, fSERV_Standalone | fSERV_Promiscuous,
00773                            host, 0/*pref. port*/, -1.0/*latch host*/,
00774                            0/*net_info*/, 0/*skip*/, 0/*n_skip*/,
00775                            0/*not external*/, 0/*arg*/, 0/*val*/,
00776                            0/*host_info*/))) {
00777         return 0;
00778     }
00779     assert(info->host == host);
00780     port = info->port;
00781     free((void*) info);
00782     assert(port);
00783     return port;
00784 }
00785 
00786 

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