Example #1
0
static int
vr_resolve_inet(sds name, int port, struct sockinfo *si)
{
    int status;
    struct addrinfo *ai, *cai; /* head and current addrinfo */
    struct addrinfo hints;
    char *node, service[VR_UINTMAX_MAXLEN];
    bool found;

    ASSERT(vr_valid_port(port));

    memset(&hints, 0, sizeof(hints));
    hints.ai_flags = AI_NUMERICSERV;
    hints.ai_family = AF_UNSPEC;     /* AF_INET or AF_INET6 */
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;
    hints.ai_addrlen = 0;
    hints.ai_addr = NULL;
    hints.ai_canonname = NULL;

    if (name != NULL) {
        node = (char *)name;
    } else {
        /*
         * If AI_PASSIVE flag is specified in hints.ai_flags, and node is
         * NULL, then the returned socket addresses will be suitable for
         * bind(2)ing a socket that will accept(2) connections. The returned
         * socket address will contain the wildcard IP address.
         */
        node = NULL;
        hints.ai_flags |= AI_PASSIVE;
    }

    dsnprintf(service, VR_UINTMAX_MAXLEN, "%d", port);

    /*
     * getaddrinfo() returns zero on success or one of the error codes listed
     * in gai_strerror(3) if an error occurs
     */
    status = getaddrinfo(node, service, &hints, &ai);
    if (status != 0) {
        log_error("address resolution of node '%s' service '%s' failed: %s",
                  node, service, gai_strerror(status));
        return -1;
    }

    /*
     * getaddrinfo() can return a linked list of more than one addrinfo,
     * since we requested for both AF_INET and AF_INET6 addresses and the
     * host itself can be multi-homed. Since we don't care whether we are
     * using ipv4 or ipv6, we just use the first address from this collection
     * in the order in which it was returned.
     *
     * The sorting function used within getaddrinfo() is defined in RFC 3484;
     * the order can be tweaked for a particular system by editing
     * /etc/gai.conf
     */
    for (cai = ai, found = false; cai != NULL; cai = cai->ai_next) {
        si->family = cai->ai_family;
        si->addrlen = cai->ai_addrlen;
        vr_memcpy(&si->addr, cai->ai_addr, si->addrlen);
        found = true;
        break;
    }

    freeaddrinfo(ai);

    return !found ? -1 : 0;
}
Example #2
0
vr_listen *
vr_listen_create(sds listen_str)
{
    rstatus_t status;
    vr_listen *vlisten;
    uint8_t *p, *name;
    uint32_t namelen;

    if (listen_str == NULL) {
        return NULL;
    }

    vlisten = vr_alloc(sizeof(struct vr_listen));
    if (vlisten == NULL) {
        return NULL;
    }

    vlisten->name = NULL;
    vlisten->port = 0;
    memset(&vlisten->info, 0, sizeof(vlisten->info));
    vlisten->sd = -1;
    
    if (listen_str == '/') {
        uint8_t *q, *start, *perm;
        uint32_t permlen;

        /* parse "socket_path permissions" from the end */
        p = listen_str + sdslen(listen_str) - 1;
        start = listen_str;
        q = vr_strrchr(p, start, ' ');
        if (q == NULL) {
            /* no permissions field, so use defaults */
            name = listen_str;
            namelen = sdslen(listen_str);
        } else {
            perm = q + 1;
            permlen = (uint32_t)(p - perm + 1);

            p = q - 1;
            name = start;
            namelen = (uint32_t)(p - start + 1);

            errno = 0;
            vlisten->perm = (mode_t)strtol((char *)perm, NULL, 8);
            if (errno || vlisten->perm > 0777) {
                log_error("config file has an invalid file permission in \"socket_path permission\" format string");
                vr_listen_destroy(vlisten);
                return NULL;
            }
        }
    } else {
        uint8_t *q, *start, *port;
        uint32_t portlen;

        /* parse "hostname:port" from the end */
        p = listen_str + sdslen(listen_str) - 1;
        start = listen_str;
        q = vr_strrchr(p, start, ':');
        if (q == NULL) {
            log_error("config file has an invalid \"hostname:port\" format string");
            vr_listen_destroy(vlisten);
            return NULL;
        }

        port = q + 1;
        portlen = (uint32_t)(p - port + 1);

        p = q - 1;

        name = start;
        namelen = (uint32_t)(p - start + 1);

        vlisten->port = vr_atoi(port, portlen);
        if (vlisten->port < 0 || !vr_valid_port(vlisten->port)) {
            log_error("config file has an invalid port in \"hostname:port\" format string");
            vr_listen_destroy(vlisten);
            return NULL;
        }
    }

    vlisten->name = sdsnewlen(name, namelen);
    if (vlisten->name == NULL) {
        log_error("create a sds string failed: out of memory.");
        vr_listen_destroy(vlisten);
        return NULL;
    }

    status = vr_resolve(vlisten->name, vlisten->port, &vlisten->info);
    if (status != VR_OK) {
        vr_listen_destroy(vlisten);
        return NULL;
    }

    return vlisten;
}