Пример #1
0
/*!
 * \internal
 * \brief tcp connection to server at specified port
 * \retval negative, failed to connect.
 * \retval positive, sock fd
 */
int
crm_remote_tcp_connect_async(const char *host, int port, int timeout, /*ms */
                             int *timer_id, void *userdata, void (*callback) (void *userdata, int sock))
{
    char buffer[256];
    struct addrinfo *res = NULL;
    struct addrinfo *rp = NULL;
    struct addrinfo hints;
    const char *server = host;
    int ret_ga;
    int sock = -1;

    /* getaddrinfo */
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;        /* Allow IPv4 or IPv6 */
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_CANONNAME;

    crm_debug("Looking up %s", server);
    ret_ga = getaddrinfo(server, NULL, &hints, &res);
    if (ret_ga) {
        crm_err("getaddrinfo: %s", gai_strerror(ret_ga));
        return -1;
    }

    if (!res || !res->ai_addr) {
        crm_err("getaddrinfo failed");
        goto async_cleanup;
    }

    for (rp = res; rp != NULL; rp = rp->ai_next) {
        struct sockaddr *addr = rp->ai_addr;

        if (!addr) {
            continue;
        }

        if (rp->ai_canonname) {
            server = res->ai_canonname;
        }
        crm_debug("Got address %s for %s", server, host);

        /* create socket */
        sock = socket(rp->ai_family, SOCK_STREAM, IPPROTO_TCP);
        if (sock == -1) {
            crm_err("Socket creation failed for remote client connection.");
            continue;
        }

        memset(buffer, 0, DIMOF(buffer));
        if (addr->sa_family == AF_INET6) {
            struct sockaddr_in6 *addr_in = (struct sockaddr_in6 *)(void*)addr;

            addr_in->sin6_port = htons(port);
            inet_ntop(addr->sa_family, &addr_in->sin6_addr, buffer, DIMOF(buffer));

        } else {
            struct sockaddr_in *addr_in = (struct sockaddr_in *)(void*)addr;

            addr_in->sin_port = htons(port);
            inet_ntop(addr->sa_family, &addr_in->sin_addr, buffer, DIMOF(buffer));
        }

        crm_info("Attempting to connect to remote server at %s:%d", buffer, port);

        if (callback) {
            if (internal_tcp_connect_async
                (sock, rp->ai_addr, rp->ai_addrlen, timeout, timer_id, userdata, callback) == 0) {
                goto async_cleanup; /* Success for now, we'll hear back later in the callback */
            }

        } else {
            if (internal_tcp_connect(sock, rp->ai_addr, rp->ai_addrlen) == 0) {
                break;          /* Success */
            }
        }

        close(sock);
        sock = -1;
    }

async_cleanup:

    if (res) {
        freeaddrinfo(res);
    }
    return sock;
}
Пример #2
0
/*!
 * \internal
 * \brief Connect to server at specified TCP port
 *
 * \param[in]  host      Name of server to connect to
 * \param[in]  port      Server port to connect to
 * \param[in]  timeout   Report error if not connected in this many milliseconds
 * \param[out] timer_id  If non-NULL, will be set to timer ID, if asynchronous
 * \param[in]  userdata  Data to pass to callback, if asynchronous
 * \param[in]  callback  If non-NULL, connect asynchronously then call this
 *
 * \return File descriptor of connected socket on success, -ENOTCONN otherwise
 */
int
crm_remote_tcp_connect_async(const char *host, int port, int timeout,
                             int *timer_id, void *userdata,
                             void (*callback) (void *userdata, int sock))
{
    char buffer[INET6_ADDRSTRLEN];
    struct addrinfo *res = NULL;
    struct addrinfo *rp = NULL;
    struct addrinfo hints;
    const char *server = host;
    int ret_ga;
    int sock = -ENOTCONN;

    // Get host's IP address(es)
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;        /* Allow IPv4 or IPv6 */
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_CANONNAME;
    ret_ga = getaddrinfo(server, NULL, &hints, &res);
    if (ret_ga) {
        crm_err("Unable to get IP address info for %s: %s",
                server, gai_strerror(ret_ga));
        goto async_cleanup;
    }
    if (!res || !res->ai_addr) {
        crm_err("Unable to get IP address info for %s: no result", server);
        goto async_cleanup;
    }

    // getaddrinfo() returns a list of host's addresses, try them in order
    for (rp = res; rp != NULL; rp = rp->ai_next) {
        struct sockaddr *addr = rp->ai_addr;

        if (!addr) {
            continue;
        }

        if (rp->ai_canonname) {
            server = res->ai_canonname;
        }
        crm_debug("Got canonical name %s for %s", server, host);

        sock = socket(rp->ai_family, SOCK_STREAM, IPPROTO_TCP);
        if (sock == -1) {
            crm_perror(LOG_WARNING, "creating socket for connection to %s",
                       server);
            sock = -ENOTCONN;
            continue;
        }

        /* Set port appropriately for address family */
        /* (void*) casts avoid false-positive compiler alignment warnings */
        if (addr->sa_family == AF_INET6) {
            ((struct sockaddr_in6 *)(void*)addr)->sin6_port = htons(port);
        } else {
            ((struct sockaddr_in *)(void*)addr)->sin_port = htons(port);
        }

        memset(buffer, 0, DIMOF(buffer));
        crm_sockaddr2str(addr, buffer);
        crm_info("Attempting TCP connection to %s:%d", buffer, port);

        if (callback) {
            if (internal_tcp_connect_async
                (sock, rp->ai_addr, rp->ai_addrlen, timeout, timer_id, userdata, callback) == 0) {
                goto async_cleanup; /* Success for now, we'll hear back later in the callback */
            }

        } else if (internal_tcp_connect(sock, rp->ai_addr, rp->ai_addrlen) == 0) {
            break;          /* Success */
        }

        close(sock);
        sock = -ENOTCONN;
    }

async_cleanup:

    if (res) {
        freeaddrinfo(res);
    }
    return sock;
}