Example #1
0
static int/*bool*/ s_AddServerInfo(struct SDISPD_Data* data, SSERV_Info* info)
{
    size_t i;
    const char* name = SERV_NameOfInfo(info);
    /* First check that the new server info updates an existing one */
    for (i = 0; i < data->n_cand; i++) {
        if (strcasecmp(name, SERV_NameOfInfo(data->cand[i].info)) == 0
            &&  SERV_EqualInfo(info, data->cand[i].info)) {
            /* Replace older version */
            free((void*) data->cand[i].info);
            data->cand[i].info = info;
            return 1;
        }
    }
    /* Next, add new service to the list */
    if (data->n_cand == data->a_cand) {
        size_t n = data->a_cand + 10;
        SLB_Candidate* temp = (SLB_Candidate*)
            (data->cand
             ? realloc(data->cand, n * sizeof(*temp))
             : malloc (            n * sizeof(*temp)));
        if (!temp)
            return 0;
        data->cand = temp;
        data->a_cand = n;
    }
    data->cand[data->n_cand++].info = info;
    return 1;
}
Example #2
0
static SSERV_Info* s_GetNextInfo(SERV_ITER   iter,
                                 HOST_INFO*  host_info,
                                 int/*bool*/ internal)
{
    SSERV_Info* info = 0;
    assert(iter  &&  iter->op);
    if (iter->op->GetNextInfo) {
        if (!internal) {
            iter->time = (TNCBI_Time) time(0);
            s_SkipSkip(iter);
        }
        /* Obtain a fresh entry from the actual mapper */
        while ((info = iter->op->GetNextInfo(iter, host_info)) != 0) {
            /* This should never actually be used for LBSMD dispatcher,
             * as all exclusion logic is already done in it internally. */
            int/*bool*/ go =
                !info->host  ||  iter->pref >= 0.0  ||
                !iter->host  ||  (iter->host == info->host  &&
                                  (!iter->port  ||  iter->port == info->port));
            if (go  &&  internal)
                break;
            if (!s_AddSkipInfo(iter, SERV_NameOfInfo(info), info)) {
                free(info);
                info = 0;
            }
            if (go  ||  !info)
                break;
        }
    }
    if (!internal)
        iter->last = info;
    return info;
}
Example #3
0
static int/*bool*/ s_AddSkipInfo(SERV_ITER   iter,
                                 const char* name,
                                 SSERV_Info* info)
{
    size_t n;
    assert(name);
    for (n = 0;  n < iter->n_skip;  n++) {
        if (strcasecmp(name, SERV_NameOfInfo(iter->skip[n])) == 0
            &&  (SERV_EqualInfo(info, iter->skip[n])  ||
                 (iter->skip[n]->type == fSERV_Firewall  &&
                  iter->skip[n]->u.firewall.type == info->u.firewall.type))) {
            /* Replace older version */
            if (iter->last == iter->skip[n])
                iter->last  = info;
            free(iter->skip[n]);
            iter->skip[n] = info;
            return 1;
        }
    }
    if (iter->n_skip == iter->a_skip) {
        SSERV_Info** temp;
        n = iter->a_skip + 10;
        temp = (SSERV_Info**)
            (iter->skip
             ? realloc(iter->skip, n * sizeof(*temp))
             : malloc (            n * sizeof(*temp)));
        if (!temp)
            return 0;
        iter->skip = temp;
        iter->a_skip = n;
    }
    iter->skip[iter->n_skip++] = info;
    return 1;
}
Example #4
0
const char* DBLB_GetServer(const char*             lb_name,
                           TDBLB_Flags             flags,
                           const SDBLB_Preference* preference,
                           const char* const       skip_servers[],
                           SDBLB_ConnPoint*        conn_point,
                           char*                   server_name_buf,
                           size_t                  server_name_buflen,
                           EDBLB_Status*           result)
{
    static const char kPrefix[] = "DB_IP__";
    size_t          len, n, a_skip, n_skip;
    SConnNetInfo*   net_info;
    int/*bool*/     failed;
    unsigned int    x_host;
    unsigned short  x_port;
    double          x_pref;
    SSERV_InfoCPtr* skip;
    SSERV_Info*     info;
    SDBLB_ConnPoint cp;
    EDBLB_Status    x;
    const char*     c;

    if (!result)
        result = &x;
    if (server_name_buf) {
        assert(server_name_buflen);
        server_name_buf[0] = '\0';
    }
    if (!conn_point)
        conn_point = &cp;
    memset(conn_point, 0, sizeof(*conn_point));
    if (!lb_name  ||  !*lb_name) {
        *result = eDBLB_BadName;
        return 0/*failure*/;
    }
    *result = eDBLB_Success;

    if (strchr(lb_name, '.')) {
        cp.host = SOCK_gethostbyname(lb_name);
        if (cp.host == SOCK_GetLoopbackAddress())
            cp.host = /*FIXME?*/SERV_LOCALHOST;
    } else
        cp.host = 0;

    skip = 0;
    n_skip = 0;
    a_skip = 0;
    net_info = 0;
    failed = 0/*false*/;
    if (skip_servers) {
        for (n = 0;  !failed  &&  skip_servers[n];  n++) {
            const char* server = skip_servers[n];
            SSERV_Info* info;
            if (!(len = strlen(server))) {
                continue;
            }
            if (strncasecmp(server, kPrefix, sizeof(kPrefix)-1) == 0
                &&  isdigit((unsigned char) server[sizeof(kPrefix)-1])) {
                c = strstr(server + sizeof(kPrefix)-1, "__");
                if (c) {
                    size_t i = (size_t)(c - server) - (sizeof(kPrefix)-1);
                    char* temp = strdup(server + sizeof(kPrefix)-1);
                    if (temp) {
                        char* s = temp + i;
                        *s++ = ':';
                        memmove(s, s + 1, strlen(s + 1) + 1);
                        server = temp;
                        while (++temp < s) {
                            if (*temp == '_')
                                *temp =  '.';
                        }
                        len -= sizeof(kPrefix);
                    }
                }
            }
            if (SOCK_StringToHostPort(server, &x_host, &x_port)
                != server + len) {
                int/*bool*/ resolved = 0/*false*/;
                const SSERV_Info* temp;
                SERV_ITER iter;

                if (!net_info)
                    net_info = ConnNetInfo_Create(lb_name);
                iter = SERV_Open(skip_servers[n],
                                 fSERV_Standalone | fSERV_Dns
                                 | fSERV_Promiscuous,
                                 0, net_info);
                do {
                    SSERV_Info* dns;
                    temp = SERV_GetNextInfo(iter);
                    if (temp) {
                        x_host = temp->host;
                        if (x_host  &&  s_IsSkipHost(x_host, cp.host)) {
                            failed = 1/*true*/;
                            break;
                        }
                        x_port = temp->port;
                    } else if (!resolved) {
                        x_host = 0;
                        x_port = 0;
                    } else
                        break;
                    if ((dns = SERV_CreateDnsInfo(x_host)) != 0) {
                        dns->port = x_port;
                        s_AddSkip(&skip, &a_skip, &n_skip, x_host
                                  ? dns
                                  : SERV_CopyInfoEx(dns, skip_servers[n]));
                        if (!x_host)
                            free(dns);
                    }
                    resolved = 1/*true*/;
                } while (temp);
                SERV_Close(iter);
                info = 0;
            } else if (s_IsSkipHost(x_host, cp.host)) {
                failed = 1/*true*/;
                info = 0;
            } else if (server != skip_servers[n]) {
                info = SERV_CreateStandaloneInfo(x_host, x_port);
            } else if ((info = SERV_CreateDnsInfo(x_host)) != 0)
                info->port = x_port;
            if (server != skip_servers[n])
                free((void*) server);
            if (info)
                s_AddSkip(&skip, &a_skip, &n_skip, info);
        }
    }

    if (!failed  &&  !cp.host) {
        if (preference) {
            x_host = preference->host;
            x_port = preference->port;
            if ((x_pref = preference->pref) < 0.0)
                x_pref  =  0.0;
            else if (x_pref >= 100.0)
                x_pref  = -1.0;
        } else {
            x_host = 0;
            x_port = 0;
            x_pref = 0.0;
        }

        if (!net_info)
            net_info = ConnNetInfo_Create(lb_name);
        info = SERV_GetInfoP(lb_name, fSERV_ReverseDns | fSERV_Standalone,
                             x_host, x_port, x_pref, net_info,
                             skip, n_skip, 0/*not external*/,
                             0, 0, 0); /* NCBI_FAKE_WARNING: GCC */
        if (!info  &&  (flags & fDBLB_AllowFallbackToStandby)) {
            /*FIXME: eliminate second pass by fix in ordering in ncbi_lbsmd.c*/
            info = SERV_GetInfoP(lb_name, fSERV_ReverseDns | fSERV_Standalone
                                 | fSERV_IncludeSuppressed,
                                 x_host, x_port, x_pref, net_info,
                                 skip, n_skip, 0/*not external*/,
                                 0, 0, 0); /* NCBI_FAKE_WARNING: GCC */
        }
    } else
        info = 0;

    if (!info) {
        if (!failed) {
            if (!cp.host) {
                if (n_skip  &&  (x_host = SOCK_gethostbyname(lb_name)) != 0) {
                    for (n = 0;  n < n_skip;  n++) {
                        if (x_host == skip[n]->host) {
                            failed = 1/*true*/;
                            break;
                        }
                    }
                }
                if (!failed  &&  skip_servers) {
                    for (n = 0;  (c = skip_servers[n]) != 0;  n++) {
                        if (strcasecmp(c, lb_name) == 0) {
                            failed = 1/*true*/;
                            break;
                        }
                    }
                }
            } else if (conn_point != &cp) {
                conn_point->host = cp.host;
                conn_point->time = NCBI_TIME_INFINITE;
            }
        }
        if (!failed  &&  server_name_buf)
            strncpy0(server_name_buf, lb_name, server_name_buflen - 1);
        *result = eDBLB_NotFound;
    } else {
        if (info->type != fSERV_Dns) {
            char* s, buf[80];
            strncpy0(buf, kPrefix, sizeof(buf) - 1);
            SOCK_HostPortToString(info->host, info->port,
                                  buf + sizeof(kPrefix) - 1,
                                  sizeof(buf) - sizeof(kPrefix));
            len = strlen(buf);
            if ((s = strchr(buf, ':')) != 0)
                memmove(s + 1, s, strlen(s) + 1);
            for (n = 0;  n < len;  n++) {
                if (buf[n] == '.'  ||  buf[n] == ':')
                    buf[n] = '_';
            }
            if (server_name_buf)
                strncpy0(server_name_buf, buf, server_name_buflen - 1);
            *result = eDBLB_NoDNSEntry;
        } else if (info->host) {
            c = SERV_NameOfInfo(info);
            assert(c);
            if (server_name_buf)
                strncpy0(server_name_buf, c, server_name_buflen - 1);
        } else {
            failed = 1/*true*/;
            *result = eDBLB_ServiceDown;
        }
        if (!failed) {
            conn_point->host = info->host;
            conn_point->port = info->port;
            conn_point->time = info->time;
        }
        free(info);
    }

    for (n = 0;  n < n_skip;  n++)
        free((void*) skip[n]);
    if (skip)
        free((void*) skip);

    if (net_info)
        ConnNetInfo_Destroy(net_info);

    return failed ? 0 : (server_name_buf ? server_name_buf : lb_name);
}
Example #5
0
static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info)
{
    struct SLOCAL_Data* data = (struct SLOCAL_Data*) iter->data;
    const TSERV_Type type = iter->type & ~fSERV_Firewall;
    int/*bool*/ dns_info_seen = 0/*false*/;
    SSERV_Info* info;
    size_t i, n;

    assert(data);
    if (data->reset) {
        data->reset = 0/*false*/;
        if (!s_LoadServices(iter))
            return 0;
        if (data->n_cand > 1)
            qsort(data->cand, data->n_cand, sizeof(*data->cand), s_Sort);
    }

    i = 0;
    data->i_cand = 0;
    while (i < data->n_cand) {
        /* NB all servers have been loaded in accordance with iter->external */
        info = (SSERV_Info*) data->cand[i].info;
        if (info->rate > 0.0  ||  iter->ok_down) {
            const char* c = SERV_NameOfInfo(info);
            for (n = 0;  n < iter->n_skip;  n++) {
                const SSERV_Info* skip = iter->skip[n];
                const char* s = SERV_NameOfInfo(skip);
                if (*s) {
                    assert(iter->ismask  ||  iter->reverse_dns);
                    if (strcasecmp(s, c) == 0
                        &&  ((skip->type == fSERV_Dns  &&  !skip->host)  ||
                             SERV_EqualInfo(skip, info))) {
                        break;
                    }
                } else if (SERV_EqualInfo(skip, info))
                    break;
                if (iter->reverse_dns  &&  skip->type == fSERV_Dns
                    &&  skip->host == info->host
                    &&  (!skip->port  ||  skip->port == info->port)) {
                    break;
                }
            }
        } else
            n = 0;
        if (!iter->ismask) {
            if (type == fSERV_Any) {
                if (iter->reverse_dns  &&  info->type != fSERV_Dns)
                    dns_info_seen = 1/*true*/;
            } else if ((type & info->type)  &&  info->type == fSERV_Dns)
                dns_info_seen = 1/*true*/;
        }
        if (n < iter->n_skip) {
            if (i < --data->n_cand) {
                memmove(data->cand + i, data->cand + i + 1,
                        (data->n_cand - i) * sizeof(*data->cand));
            }
            free(info);
        } else {
            if (type != fSERV_Any  &&  !(type & info->type))
                break;
            if (type == fSERV_Any  &&  info->type == fSERV_Dns)
                break;
            data->i_cand++;
            data->cand[i].status = info->rate < 0.0 ? 0.0 : info->rate;
            if (iter->ok_down)
                break;
            i++;
        }
    }

    if (data->i_cand) {
        n = LB_Select(iter, data, s_GetCandidate, 1.0);
        info = (SSERV_Info*) data->cand[n].info;
        if (iter->reverse_dns  &&  info->type != fSERV_Dns) {
            dns_info_seen = 0/*false*/;
            for (i = 0;  i < data->n_cand;  i++) {
                SSERV_Info* temp = (SSERV_Info*) data->cand[i].info;
                if (temp->type != fSERV_Dns   ||
                    temp->host != info->host  ||  temp->port != info->port) {
                    continue;
                }
                if (!iter->ismask)
                    dns_info_seen = 1/*true*/;
                if (iter->external  &&  temp->locl)
                    continue; /* external mapping req'd; local server */
                assert(!(temp->locl & 0xF0)); /* no private DNS */
                if (temp->rate > 0.0  ||  iter->ok_down) {
                    data->cand[i].status = data->cand[n].status;
                    info = temp;
                    n = i;
                    break;
                }
            }
            if (i >= data->n_cand  &&  dns_info_seen)
                info = 0;
        }

        if (info) {
            info->rate  = data->cand[n].status;
            info->time += iter->time;
            if (n < --data->n_cand) {
                memmove(data->cand + n, data->cand + n + 1,
                        (data->n_cand - n) * sizeof(*data->cand));
            }
        }
    } else if (iter->last  ||  iter->n_skip  ||  !dns_info_seen) {
        info = 0;
    } else if ((info = SERV_CreateDnsInfo(0)) != 0)
        info->time = NCBI_TIME_INFINITE;

    if (info  &&  host_info)
        *host_info = 0;
    return info;
}
Example #6
0
char* SERV_Print(SERV_ITER iter, SConnNetInfo* net_info, int/*bool*/ but_last)
{
    static const char kClientRevision[] = "Client-Revision: %hu.%hu\r\n";
    static const char kAcceptedServerTypes[] = "Accepted-Server-Types:";
    static const char kUsedServerInfo[] = "Used-Server-Info: ";
    static const char kNcbiFWPorts[] = "NCBI-Firewall-Ports: ";
    static const char kServerCount[] = "Server-Count: ";
    static const char kPreference[] = "Preference: ";
    static const char kSkipInfo[] = "Skip-Info-%u: ";
    static const char kAffinity[] = "Affinity: ";
    char buffer[128], *str;
    size_t buflen, i;
    TSERV_Type t;
    BUF buf = 0;

    /* Put client version number */
    buflen = sprintf(buffer, kClientRevision,
                     SERV_CLIENT_REVISION_MAJOR, SERV_CLIENT_REVISION_MINOR);
    assert(buflen < sizeof(buffer));
    if (!BUF_Write(&buf, buffer, buflen)) {
        BUF_Destroy(buf);
        return 0;
    }
    if (iter) {
        if (net_info && !net_info->http_referer && iter->op && iter->op->name)
            s_SetDefaultReferer(iter, net_info);
        /* Accepted server types */
        buflen = sizeof(kAcceptedServerTypes) - 1;
        memcpy(buffer, kAcceptedServerTypes, buflen);
        for (t = 1;  t;  t <<= 1) {
            if (iter->type & t) {
                const char* name = SERV_TypeStr((ESERV_Type) t);
                size_t namelen = strlen(name);
                if (!namelen  ||  buflen + 1 + namelen + 2 >= sizeof(buffer))
                    break;
                buffer[buflen++] = ' ';
                memcpy(buffer + buflen, name, namelen);
                buflen += namelen;
            }
        }
        if (buffer[buflen - 1] != ':') {
            strcpy(&buffer[buflen], "\r\n");
            assert(strlen(buffer) == buflen+2  &&  buflen+2 < sizeof(buffer));
            if (!BUF_Write(&buf, buffer, buflen + 2)) {
                BUF_Destroy(buf);
                return 0;
            }
        }
        if (iter->ismask  ||  (iter->pref  &&  (iter->host | iter->port))) {
            /* FIXME: To obsolete? */
            /* How many server-infos for the dispatcher to send to us */
            if (!BUF_Write(&buf, kServerCount, sizeof(kServerCount) - 1)  ||
                !BUF_Write(&buf,
                           iter->ismask ? "10\r\n" : "ALL\r\n",
                           iter->ismask ?       4  :        5)) {
                BUF_Destroy(buf);
                return 0;
            }
        }
        if (iter->type & fSERV_Firewall) {
            /* Firewall */
            s_PrintFirewallPorts(buffer, sizeof(buffer), net_info);
            if (*buffer
                &&  (!BUF_Write(&buf, kNcbiFWPorts, sizeof(kNcbiFWPorts)-1)  ||
                     !BUF_Write(&buf, buffer, strlen(buffer))                ||
                     !BUF_Write(&buf, "\r\n", 2))) {
                BUF_Destroy(buf);
                return 0;
            }
        }
        if (iter->pref  &&  (iter->host | iter->port)) {
            /* Preference */
            buflen  = SOCK_HostPortToString(iter->host, iter->port,
                                            buffer, sizeof(buffer));
            buflen += sprintf(buffer + buflen, " %.2lf%%\r\n", iter->pref*1e2);
            if (!BUF_Write(&buf, kPreference, sizeof(kPreference) - 1)  ||
                !BUF_Write(&buf, buffer, buflen)) {
                BUF_Destroy(buf);
                return 0;
            }
        }
        if (iter->arglen) {
            /* Affinity */
            if (!BUF_Write(&buf, kAffinity, sizeof(kAffinity) - 1)           ||
                !BUF_Write(&buf, iter->arg, iter->arglen)                    ||
                (iter->val  &&  (!BUF_Write(&buf, "=", 1)                    ||
                                 !BUF_Write(&buf, iter->val, iter->vallen))) ||
                !BUF_Write(&buf, "\r\n", 2)) {
                BUF_Destroy(buf);
                return 0;
            }
        }
        /* Drop any outdated skip entries */
        iter->time = (TNCBI_Time) time(0);
        s_SkipSkip(iter);
        /* Put all the rest into rejection list */
        for (i = 0;  i < iter->n_skip;  i++) {
            /* NB: all skip infos are now kept with names (perhaps, empty) */
            const char* name    = SERV_NameOfInfo(iter->skip[i]);
            size_t      namelen = name  &&  *name ? strlen(name) : 0;
            if (!(str = SERV_WriteInfo(iter->skip[i])))
                break;
            if (but_last  &&  iter->last == iter->skip[i]) {
                buflen = sizeof(kUsedServerInfo) - 1;
                memcpy(buffer, kUsedServerInfo, buflen);
            } else
                buflen = sprintf(buffer, kSkipInfo, (unsigned) i + 1); 
            assert(buflen < sizeof(buffer) - 1);
            if (!BUF_Write(&buf, buffer, buflen)                ||
                (namelen  &&  !BUF_Write(&buf, name, namelen))  ||
                (namelen  &&  !BUF_Write(&buf, " ", 1))         ||
                !BUF_Write(&buf, str, strlen(str))              ||
                !BUF_Write(&buf, "\r\n", 2)) {
                free(str);
                break;
            }
            free(str);
        }
        if (i < iter->n_skip) {
            BUF_Destroy(buf);
            return 0;
        }
    }
    /* Ok then, we have filled the entire header, <CR><LF> terminated */
    if ((buflen = BUF_Size(buf)) != 0) {
        if ((str = (char*) malloc(buflen + 1)) != 0) {
            if (BUF_Read(buf, str, buflen) != buflen) {
                free(str);
                str = 0;
            } else
                str[buflen] = '\0';
        }
    } else
        str = 0;
    BUF_Destroy(buf);
    return str;
}
Example #7
0
const char* SERV_CurrentName(SERV_ITER iter)
{
    const char* name = SERV_NameOfInfo(iter->last);
    return name  &&  *name ? name : iter->name;
}
Example #8
0
static SERV_ITER s_Open(const char*          service,
                        unsigned/*bool*/     ismask,
                        TSERV_Type           types,
                        unsigned int         preferred_host,
                        unsigned short       preferred_port,
                        double               preference,
                        const SConnNetInfo*  net_info,
                        const SSERV_InfoCPtr skip[],
                        size_t               n_skip,
                        unsigned/*bool*/     external,
                        const char*          arg,
                        const char*          val,
                        SSERV_Info**         info,
                        HOST_INFO*           host_info)
{
    int/*bool*/ do_lbsmd = -1/*unassigned*/, do_dispd = -1/*unassigned*/;
    const SSERV_VTable* op;
    SERV_ITER iter;
    const char* s;

    if (!(s = s_ServiceName(service, ismask, 0)))
        return 0;
    if (!(iter = (SERV_ITER) calloc(1, sizeof(*iter)))) {
        free((void*) s);
        return 0;
    }
    assert(ismask  ||  *s);

    iter->name              = s;
    iter->type              = types & fSERV_All;
    iter->host              = (preferred_host == SERV_LOCALHOST
                               ? SOCK_GetLocalHostAddress(eDefault)
                               : preferred_host);
    iter->port              = preferred_port;
    iter->pref              = (preference < 0.0
                               ? -1.0
                               :  0.01 * (preference > 100.0
                                          ? 100.0
                                          : preference));
    if (ismask)
        iter->ismask        = 1;
    if (types & fSERV_IncludeDown)
        iter->ok_down       = 1;
    if (types & fSERV_IncludeSuppressed)
        iter->ok_suppressed = 1;
    if (types & fSERV_ReverseDns)
        iter->reverse_dns   = 1;
    if (types & fSERV_Stateless)
        iter->stateless     = 1;
    iter->external          = external;
    if (arg  &&  *arg) {
        iter->arg           = arg;
        iter->arglen        = strlen(arg);
        if (val) {
            iter->val       = val;
            iter->vallen    = strlen(val);
        }
    }
    iter->time              = (TNCBI_Time) time(0);

    if (n_skip) {
        size_t i;
        for (i = 0;  i < n_skip;  i++) {
            const char* name = (iter->ismask  ||  skip[i]->type == fSERV_Dns
                                ? SERV_NameOfInfo(skip[i]) : "");
            SSERV_Info* temp = SERV_CopyInfoEx(skip[i],
                                               !iter->reverse_dns  ||  *name ?
                                               name : s);
            if (temp) {
                temp->time = NCBI_TIME_INFINITE;
                if (!s_AddSkipInfo(iter, name, temp)) {
                    free(temp);
                    temp = 0;
                }
            }
            if (!temp) {
                SERV_Close(iter);
                return 0;
            }
        }
    }
    assert(n_skip == iter->n_skip);

    if (net_info) {
        if (net_info->firewall)
            iter->type |= fSERV_Firewall;
        if (net_info->stateless)
            iter->stateless = 1;
        if (net_info->lb_disable)
            do_lbsmd = 0/*false*/;
    } else
        do_dispd = 0/*false*/;
    /* Ugly optimization not to access the registry more than necessary */
    if ((!s_IsMapperConfigured(service, REG_CONN_LOCAL_ENABLE)               ||
         !(op = SERV_LOCAL_Open(iter, info, host_info)))                 &&
        (!do_lbsmd                                                           ||
         !(do_lbsmd= !s_IsMapperConfigured(service, REG_CONN_LBSMD_DISABLE)) ||
         !(op = SERV_LBSMD_Open(iter, info, host_info,
                                !do_dispd                                    ||
                                !(do_dispd = !s_IsMapperConfigured
                                  (service, REG_CONN_DISPD_DISABLE)))))  &&
        (!do_dispd                                                           ||
         !(do_dispd= !s_IsMapperConfigured(service, REG_CONN_DISPD_DISABLE)) ||
         !(op = SERV_DISPD_Open(iter, net_info, info, host_info)))) {
        if (!do_lbsmd  &&  !do_dispd) {
            CORE_LOGF_X(1, eLOG_Error,
                        ("[%s]  No service mappers available", service));
        }
        SERV_Close(iter);
        return 0;
    }

    assert(op != 0);
    iter->op = op;
    return iter;
}
Example #9
0
static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info)
{
    const TSERV_Type types = iter->types & ~fSERV_Firewall;
    size_t i, n, idx[eHost_NoMatch], n_cand, a_cand;
    EHost_Match best_match, match;
    struct SLBSM_Candidate* cand;
    const SLBSM_Service* svc;
    TNCBI_Time dns_info_time;
    const SLBSM_Host* host;
    const char* env, *a;
    SSERV_Info* info;
    const char* name;
    double status;
    int standby;
    HEAP heap;
    char* v;

    heap = (HEAP)(iter->data != iter ? iter->data : 0);
    if (heap) {
#ifdef LBSM_DEBUG
        CORE_LOGF(eLOG_Trace,
                  ("LBSM heap[%p, %p, %d] for \"%s\" detected",
                   heap, HEAP_Base(heap), HEAP_Serial(heap), iter->name));
#endif /*LBSM_DEBUG*/
        /*noop*/;
    } else if (!(heap = s_GetHeapCopy(iter->time))) {
        return iter->external  ||  iter->data == iter  ||  !(types & fSERV_Dns)
            ? 0 : s_FakeDnsReturn(iter, host_info, 0, NCBI_TIME_INFINITE);
    }

    best_match = eHost_InitMatch;
    memset(idx, 0, sizeof(idx));
    standby = -1/*unassigned*/;
    dns_info_time = 0/*none*/;
    n = n_cand = a_cand = 0;
    a = v = 0;
    cand = 0;
    svc = 0;

    name = *iter->name ? iter->name : 0;
    assert(name  ||  iter->ismask); /*NB: ismask ignored for NULL*/
    while ((svc = LBSM_LookupService(heap, name, iter->ismask, svc))) {
        if (svc->entry.good < iter->time)
            continue; /* out-of-date entry */

        if (!svc->info.time)
            continue; /* off */

        if (types != fSERV_Any  &&  !(types & svc->info.type))
            continue; /* type doesn't match */

        if (iter->external  &&  svc->info.locl)
            continue; /* external mapping requested; local/private server */

        if (svc->info.locl & 0xF0) {
            /* private server */
            if (svc->info.host  &&
                svc->info.host != s_GetLocalHostAddress(heap)) {
                continue;
            }
        }

        if (svc->info.type == fSERV_Dns) {
            if (types == fSERV_Any)
                continue; /* DNS entries have to be requested explicitly */
            if (!iter->ismask) {
                if (dns_info_time < svc->info.time)
                    dns_info_time = svc->info.time;
            }
        } else {
            if (iter->stateless  &&  svc->info.sful) {
                /* Skip stateful-only non-CGI (NCBID and standalone) svc */
                if (!(svc->info.type & fSERV_Http))
                    continue;
            }
            if (!iter->ismask  &&  iter->reverse_dns) {
                if (dns_info_time < svc->info.time)
                    dns_info_time = svc->info.time;
            }
        }

        if (svc->info.rate > 0.0  ||  host_info) {
            if (!(host = s_LookupHost(heap, iter, svc))
                &&  svc->info.rate > 0.0) {
                continue; /* no host information for non-static server */
            }
        } else
            host = 0;

        for (n = 0;  n < iter->n_skip;  n++) {
            const SSERV_Info* skip = iter->skip[n];
            const char* s = SERV_NameOfInfo(skip);
            if (*s) {
                assert(iter->ismask  ||  iter->reverse_dns);
                if (strcasecmp(s, (const char*) svc + svc->name) == 0
                    &&  ((skip->type == fSERV_Dns  &&  !skip->host)
                         ||  SERV_EqualInfo(skip, &svc->info))) {
                    break;
                }
            } else if (SERV_EqualInfo(skip, &svc->info))
                break;
            if (skip->type == fSERV_Firewall
                &&  skip->u.firewall.type == svc->info.type) {
                break;
            }
            if (iter->reverse_dns  &&  skip->type == fSERV_Dns
                &&  skip->host == svc->info.host
                &&  (!skip->port  ||  skip->port == svc->info.port)) {
                break;
            }
        }
        /*FIXME*//*CORE_LOG(eLOG_Note, (char*) svc + svc->name);*/
        if (n >= iter->n_skip) {
            status = LBSM_CalculateStatus(svc->info.rate, svc->fine,
                                          svc->info.flag, &host->sys.load);
            if (status <= 0.0) {
                if (!svc->info.rate) {
                    if (!iter->ok_down)
                        continue; /* not operational */
                    status = 0.0;
                } else
                    status = copysign(svc->info.rate, -1.0);
            }
        } else
            status = 0.0; /* dummy assignment to keep no-init warning off */

        if (v) {
            free(v);
            v = 0;
        }
        a = env = 0;
        if (iter->pref < 0.0  &&  iter->host
            &&  (iter->host != svc->info.host
                 ||  (iter->port  &&  iter->port != svc->info.port))) {
            /* not a suitable fixed latching */
            match = eHost_BadMatch;
        } else if (iter->arglen) {
            assert(iter->arg);
            if (!host)
                host = s_LookupHost(heap, iter, svc);
            if ( host  &&  host->env)
                env = (const char*) host + host->env;
            match = s_Match(env,
                            iter->arg, iter->arglen,
                            iter->val, iter->vallen, &a, &v);
            assert(!a  ||  a == iter->arg);
        } else
            match = eHost_GoodMatch;

        if (best_match > match)
            best_match = match;

        if (match > eHost_NoMatch) {
            assert(!v);
            continue;
        }

        if (svc->info.rate) {
            /* NB: server is _not_ down, but it may have been suppressed */
            if (fabs(svc->info.rate) < 0.01) {
                if (!standby) {
                    if (!iter->ok_suppressed)
                        continue;
                    /* this has to be given out as a suppressed one */
                    status = copysign(svc->info.rate, -1.0);
                } else if (standby < 0)
                    standby = 1;
            } else if (standby) {
                standby = 0/*cancel*/;
                if (!iter->ok_suppressed) {
                    memset(idx, 0, sizeof(idx));
                    for (i = 0;  i < n_cand;  i++) {
                        if (cand[i].val)
                            free((void*) cand[i].val);
                    }
                    n_cand = 0;
                } else for (i = 0;  i < n_cand;  i++)
                    cand[i].cand.status = copysign(cand[i].svc->info.rate,-1.);
            }
        }

        if (n < iter->n_skip)
            continue; /* excluded/seen;  NB: dummy assignment goes off here */

        if (!iter->ok_suppressed  &&  status < 0.0)
            continue;

#ifdef NCBI_LB_DEBUG
        if (iter->arglen) {
            char* s = SERV_WriteInfo(&svc->info);
            const char* m;
            assert(s);
            switch (match) {
            case eHost_BestMatch:
                m = "Best match";
                break;
            case eHost_GoodMatch:
                m = "Good match";
                break;
            case eHost_FairMatch:
                m = "Fair match";
                break;
            case eHost_PoorMatch:
                m = "Poor match";
                break;
            case eHost_NoMatch:
                m = "No match";
                break;
            default:
                assert(0);
                m = "?";
                break;
            }
            assert(!a  || *a);
            assert(!v  ||  a);
            CORE_LOGF(eLOG_Note, ("%s%s%s%s: %s%s%s%s%s%s", s,
                                  env ? " <" : "", env ? env : "",
                                  env ? ">"  : "", m,
                                  a   ? ", arg="             : "",
                                  a   ? a                    : "",
                                  v   ? ", val="             : "",
                                  v   ? (*v ? v : "\"\"")    : "",
                                  standby > 0 ? ", standby"  : ""));
            free(s);
        }
#endif /*NCBI_LB_DEBUG*/

        /* This server should be taken into consideration */
        if (n_cand == a_cand) {
            struct SLBSM_Candidate* temp;
            n = a_cand + 10;
            temp = (struct SLBSM_Candidate*)
                (cand
                 ? realloc(cand, n * sizeof(*temp))
                 : malloc (      n * sizeof(*temp)));
            if (!temp)
                break;
            cand = temp;
            a_cand = n;
        }

        if (match < eHost_NoMatch) {
            assert((size_t) match < sizeof(idx)/sizeof(idx[0]));
            n = idx[match];
            if (n < n_cand)
                memmove(&cand[n + 1], &cand[n], sizeof(cand[0])*(n_cand - n));
            for (i = match;  i < sizeof(idx)/sizeof(idx[0]);  i++)
                idx[i]++;
        } else
            n = n_cand;
        cand[n].cand.info   = &svc->info;
        cand[n].cand.status = status;
        cand[n].host        = host;
        cand[n].svc         = svc;
        cand[n].arg         = a;
        cand[n].val         = v;
        a = v = 0;
        n_cand++;
    }
    if (v)
        free(v);

    if (best_match < eHost_NoMatch) {
        assert(!best_match  ||  !idx[best_match - 1]);
        for (n = idx[best_match];  n < n_cand;  n++) {
            if (cand[n].val)
                free((void*) cand[n].val);
        }
        n_cand = idx[best_match];
    }
    if (n_cand) {
        assert(cand);
        do {
            if (standby <= 0) {
                struct SLBSM_Data data;
                data.cand   = cand;
                data.n_cand = n_cand;
                n = LB_Select(iter, &data, s_GetCandidate, LBSMD_LOCAL_BONUS);
            } else {
                qsort(cand, n_cand, sizeof(*cand), s_SortStandbys);
                status = cand[0].cand.status;
                for (n = 1;  n < n_cand;  n++) {
                    if (status != cand[n].cand.status)
                        break;
                }
                n = rand() % n;
            }
            svc = cand[n].svc;
            if (iter->reverse_dns  &&  svc->info.type != fSERV_Dns) {
                svc = 0;
                dns_info_time = 0/*none*/;
                while ((svc = LBSM_LookupService(heap, 0/*all*/, 0, svc)) !=0){
                    if (svc->info.type != fSERV_Dns  ||  !svc->info.time  ||
                        svc->info.host != cand[n].svc->info.host          ||
                        svc->info.port != cand[n].svc->info.port) {
                        continue;
                    }
                    if (!iter->ismask) {
                        if (dns_info_time < svc->info.time)
                            dns_info_time = svc->info.time;
                    }
                    if (iter->external  &&  svc->info.locl)
                        continue;/* external mapping requested; local server */
                    assert(!(svc->info.locl & 0xF0)); /* no private DNS */
                    status = LBSM_CalculateStatus(!svc->info.rate ? 0.0
                                                  : -LBSM_DEFAULT_RATE,
                                                  svc->fine, fSERV_Regular,
                                                  NULL);
                    if (status > 0.0)
                        break;
                    if ((!svc->info.rate  &&  iter->ok_down)  ||
                        ( svc->info.rate  &&  iter->ok_suppressed)) {
                        cand[n].cand.status = !svc->info.rate ? 0.0
                            : copysign(svc->info.rate, -1.0);
                        break;
                    }
                }
                if (!svc  &&  !dns_info_time)
                    svc = cand[n].svc;
            }
            if (svc)
                break;
            if (cand[n].val)
                free((void*) cand[n].val);
            if (n < --n_cand)
                memmove(cand + n, cand + n + 1, (n_cand - n) * sizeof(*cand));
        } while (n_cand);
    } else
        svc = 0;

    if (svc) {
        const char* name = (iter->ismask  ||  iter->reverse_dns ?
                            (const char*) svc + svc->name : "");
        if ((info = SERV_CopyInfoEx(&svc->info, name)) != 0) {
            info->rate = cand[n].cand.status;
            if (info->time != NCBI_TIME_INFINITE)
                info->time  = cand[n].svc->entry.good;
            if (host_info) {
                if ((host = cand[n].host) != 0) {
                    *host_info =
                        HINFO_Create(host->addr, &host->sys, sizeof(host->sys),
                                     host->env
                                     ? (const char*) host + host->env
                                     : 0, cand[n].arg, cand[n].val);
                } else
                    *host_info = 0;
            }
        }
    } else {
        info = !n_cand  &&  dns_info_time
            ? s_FakeDnsReturn(iter, host_info,
                              best_match == eHost_InitMatch ?  0/*down*/ :
                              best_match != eHost_BadMatch  ? -1/*busy*/ : 1,
                              dns_info_time)
            : 0;
    }

    for (n = 0;  n < n_cand;  n++) {
        if (cand[n].val)
            free((void*) cand[n].val);
    }
    if (cand)
        free(cand);

    if (!s_FastHeapAccess) {
#ifdef LBSM_DEBUG
        CORE_LOGF(eLOG_Trace,
                  ("LBSM heap[%p, %p, %d] for \"%s\" released",
                   heap, HEAP_Base(heap), HEAP_Serial(heap), iter->name));
#endif /*LBSM_DEBUG*/
        CORE_LOCK_WRITE;
        HEAP_Detach(heap);
        CORE_UNLOCK;
        heap = 0;
    }
#ifdef LBSM_DEBUG
    else {
        CORE_LOGF(eLOG_Trace,
                  ("LBSM heap[%p, %p, %d] for \"%s\" retained",
                   heap, HEAP_Base(heap), HEAP_Serial(heap), iter->name));
    }
#endif /*LBSM_DEBUG*/
    iter->data = heap;

    return info;
}