string    CSocketAPI::HostPortToString(unsigned int    host,
                                       unsigned short  port)
{
    char   buf[80];
    size_t len = SOCK_HostPortToString(host, port, buf, sizeof(buf));
    return string(buf, len);
}
Exemple #2
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);
}
Exemple #3
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;
}
Exemple #4
0
char* SERV_WriteInfo(const SSERV_Info* info)
{
    char c_t[MAX_CONTENT_TYPE_LEN];    
    const SSERV_Attr* attr;
    size_t reserve;
    char* str;

    if (!(attr = s_GetAttrByType(info->type)))
        return 0;
    if (info->type != fSERV_Dns
        &&  MIME_ComposeContentTypeEx(info->mime_t, info->mime_s,
                                      info->mime_e, c_t, sizeof(c_t))) {
        char* p;
        assert(c_t[strlen(c_t) - 2] == '\r' && c_t[strlen(c_t) - 1] == '\n');
        c_t[strlen(c_t) - 2] = 0;
        p = strchr(c_t, ' ');
        assert(p);
        p++;
        memmove(c_t, p, strlen(p) + 1);
    } else
        *c_t = 0;
    reserve = attr->tag_len+1 + MAX_IP_ADDR_LEN + 1+5/*port*/ + 1+10/*flag*/ +
        1+9/*coef*/ + 3+strlen(c_t)/*cont.type*/ + 1+5/*locl*/ + 1+5/*priv*/ +
        1+7/*quorum*/ + 1+14/*rate*/ + 1+5/*sful*/ + 1+12/*time*/ + 1/*EOL*/;
    /* write server-specific info */
    if ((str = attr->vtable.Write(reserve, &info->u)) != 0) {
        char* s = str;
        size_t n;

        memcpy(s, attr->tag, attr->tag_len);
        s += attr->tag_len;
        *s++ = ' ';
        s += SOCK_HostPortToString(info->host, info->port, s, reserve);
        if ((n = strlen(str + reserve)) != 0) {
            *s++ = ' ';
            memmove(s, str + reserve, n + 1);
            s = str + strlen(str);
        }

        assert(info->flag < (int)(sizeof(k_FlagTag)/sizeof(k_FlagTag[0])));
        if (k_FlagTag[info->flag] && *k_FlagTag[info->flag])
            s += sprintf(s, " %s", k_FlagTag[info->flag]);
        s += sprintf(s, " B=%.2f", info->coef);
        if (*c_t)
            s += sprintf(s, " C=%s", c_t);
        s += sprintf(s, " L=%s", info->locl & 0x0F ? "yes" : "no");
        if (info->type != fSERV_Dns && (info->locl & 0xF0))
            s += sprintf(s, " P=yes");
        if (info->host && info->quorum) {
            if (info->quorum == (unsigned short)(-1))
                s += sprintf(s, " Q=yes");
            else
                s += sprintf(s, " Q=%hu", info->quorum);
        }
        s += sprintf(s," R=%.*f", fabs(info->rate) < 0.01 ? 3 : 2, info->rate);
        if (!(info->type & fSERV_Http) && info->type != fSERV_Dns)
            s += sprintf(s, " S=%s", info->sful ? "yes" : "no");
        s += sprintf(s, " T=%lu", (unsigned long)info->time);
    }
    return str;
}