コード例 #1
0
ファイル: rmt_net.c プロジェクト: ainilife/redis-migrate-tool
static int
rmt_resolve_unix(char *name, struct sockinfo *si)
{
    struct sockaddr_un *un;

    if (strlen(name) >= RMT_UNIX_ADDRSTRLEN) {
        return RMT_ERROR;
    }

    un = &si->addr.un;

    un->sun_family = AF_UNIX;
    rmt_memcpy(un->sun_path, name, strlen(name));
    un->sun_path[strlen(name)] = '\0';

    si->family = AF_UNIX;
    si->addrlen = sizeof(*un);
    /* si->addr is an alias of un */

    return RMT_OK;
}
コード例 #2
0
int rmt_tcp_context_connect(tcp_context *tc, const char *host, int port,
                                   const struct timeval *timeout,
                                   const char *source_addr) {
    tc->port = port;

    if(tc->host != NULL)
    {
        free(tc->host);
        tc->host = NULL;
    }

    tc->host = rmt_strdup(host);

    if (timeout) {
        if (tc->timeout == NULL) {
            tc->timeout = rmt_alloc(sizeof(struct timeval));
        }

        rmt_memcpy(tc->timeout, timeout, sizeof(struct timeval));
    } else {
        if (tc->timeout)
            rmt_free(tc->timeout);
        tc->timeout = NULL;
    }

    if (tc->source_addr != NULL) {
        free(tc->source_addr);
        tc->source_addr = NULL;
    }

    if (source_addr) {
        tc->source_addr = rmt_strdup(source_addr);
    }

    if (!(tc->flags & RMT_RECONNECT)) {
        tc->flags |= RMT_RECONNECT;
    }
    
    return _rmt_tcp_context_connect(tc);
}
コード例 #3
0
ファイル: rmt_net.c プロジェクト: ainilife/redis-migrate-tool
int rmt_tcp_context_connect_old(tcp_context *tc, const char *host, int port,
                                   const struct timeval *timeout,
                                   const char *source_addr) {
    int ret;
    int s, n;
    char _port[6];  /* strlen("65535"); */
    struct addrinfo hints, *servinfo, *bservinfo, *p, *b;
    int blocking = (tc->flags & RMT_BLOCK);
    int reuseaddr = (tc->flags & RMT_REUSEADDR);
    int reuses = 0;
    int yes = 1;

    tc->port = port;

    if(tc->host != NULL)
    {
        free(tc->host);
        tc->host = NULL;
    }

    tc->host = rmt_strdup(host);

    if (timeout) {
        if (tc->timeout == NULL) {
            tc->timeout = rmt_alloc(sizeof(struct timeval));
        }

        rmt_memcpy(tc->timeout, timeout, sizeof(struct timeval));
    } else {
        if (tc->timeout)
            rmt_free(tc->timeout);
        tc->timeout = NULL;
    }

    if (tc->source_addr != NULL) {
        free(tc->source_addr);
        tc->source_addr = NULL;
    }

    if (source_addr) {
        tc->source_addr = rmt_strdup(source_addr);
    }

    rmt_snprintf(_port, 6, "%d", port);
    rmt_memset(&hints,0,sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;

    /* Try with IPv6 if no IPv4 address was found. We do it in this order since
     * in a Redis client you can't afford to test if you have IPv6 connectivity
     * as this would add latency to every connect. Otherwise a more sensible
     * route could be: Use IPv6 if both addresses are available and there is IPv6
     * connectivity. */
    if ((ret = rmt_getaddrinfo(tc->host,_port,&hints,&servinfo)) != 0) {
         hints.ai_family = AF_INET6;
         if ((ret = rmt_getaddrinfo(tc->host,_port,&hints,&servinfo)) != 0) {
            log_error("ERROR: rmt_getaddrinfo error: %s", gai_strerror(ret));
            return RMT_ERROR;
        }
    }
    
    for (p = servinfo; p != NULL; p = p->ai_next) {
addrretry:
        if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1)
            continue;

        tc->sd = s;
        if (rmt_set_nonblocking(tc->sd) < 0)
        {
            log_error("ERROR: set nonblock on socket %d on addr '%s:%d' failed: %s", 
                s, tc->host, tc->port, strerror(errno));
            rmt_tcp_context_close_sd(tc);
            goto error;
        }
        
        if (tc->source_addr) {
            int bound = 0;
            /* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */
            if ((ret = rmt_getaddrinfo(tc->source_addr, NULL, &hints, &bservinfo)) != 0) {
                log_error("ERROR: can't get %s addr: %s", tc->source_addr, gai_strerror(ret));
                rmt_tcp_context_close_sd(tc);
                goto error;
            }

            if (reuseaddr) {
                n = 1;
                if (rmt_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n,
                               sizeof(n)) < 0) 
                {
                    log_error("ERROR: set SO_REUSEADDR on socket %d on addr '%s:%d' failed: %s", 
                        tc->sd, tc->host, tc->port, strerror(errno));
                    rmt_tcp_context_close_sd(tc);
                    goto error;
                }
            }

            for (b = bservinfo; b != NULL; b = b->ai_next) {
                if (bind(s,b->ai_addr,b->ai_addrlen) != -1) {
                    bound = 1;
                    break;
                }
            }
            
            freeaddrinfo(bservinfo);
            
            if (!bound) {
                log_error("ERROR: can't bind socket: %s", strerror(errno));
                rmt_tcp_context_close_sd(tc);
                goto error;
            }
        }
        
        if (connect(s,p->ai_addr,p->ai_addrlen) == -1) {
            if (errno == EHOSTUNREACH) {
                rmt_tcp_context_close_sd(tc);
                continue;
            } else if (errno == EINPROGRESS && !blocking) {
                /* This is ok. */
            } else if (errno == EADDRNOTAVAIL && reuseaddr) {
                if (++reuses >= RMT_CONNECT_RETRIES) {
                    log_error("ERROR: retry too many times: %s", strerror(errno));
                    rmt_tcp_context_close_sd(tc);
                    goto error;
                } else {
                    goto addrretry;
                }
            } else {
                if (rmt_tcp_context_wait_ready(tc,tc->timeout) != RMT_OK)
                    goto error;
            }
        }
        
        if (blocking && rmt_set_blocking(tc->sd) < 0)
        {
            log_error("ERROR: set block on socket %d on addr '%s:%d' failed: %s", 
                tc->sd, tc->host, tc->port, strerror(errno));
            rmt_tcp_context_close_sd(tc);
            goto error;
        }

        if (rmt_setsockopt(tc->sd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1)
        {
            log_error("ERROR: set TCP_NODELAY on socket %d on addr '%s:%d' failed: %s", 
                tc->sd, tc->host, tc->port, strerror(errno));
            rmt_tcp_context_close_sd(tc);
            goto error;
        }
        
        tc->flags |= RMT_CONNECTED;
        ret = RMT_OK;
        goto end;
    }
    
    if (p == NULL) {
        log_error("ERROR: can't create socket: %s", strerror(errno));
        goto error;
    }

error:
    ret = RMT_ERROR;
end:
    freeaddrinfo(servinfo);
    return ret;  // Need to return RMT_OK if alright
}
コード例 #4
0
ファイル: rmt_net.c プロジェクト: ainilife/redis-migrate-tool
static int
rmt_resolve_inet(char *name, int port, struct sockinfo *si)
{
    int status;
    struct addrinfo *ai, *cai; /* head and current addrinfo */
    struct addrinfo hints;
    char *node, service[RMT_UINTMAX_MAXLEN];
    bool found;

    ASSERT(rmt_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 = 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;
    }

    rmt_snprintf(service, RMT_UINTMAX_MAXLEN, "%d", port);

    status = getaddrinfo(node, service, &hints, &ai);
    if (status < 0) {
        log_error("ERROR: address resolution of node '%s' service '%s' failed: %s",
                  node, service, gai_strerror(status));
        return RMT_ERROR;
    }

    /*
     * 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 = 0; cai != NULL; cai = cai->ai_next) {
        si->family = cai->ai_family;
        si->addrlen = cai->ai_addrlen;
        rmt_memcpy(&si->addr, cai->ai_addr, si->addrlen);
        found = 1;
        break;
    }

    freeaddrinfo(ai);

    return !found ? RMT_ERROR : RMT_OK;
}