Exemple #1
0
int
crm_remote_accept(int ssock)
{
    int csock = 0;
    int rc = 0;
    unsigned laddr = 0;
    struct sockaddr_storage addr;
    char addr_str[INET6_ADDRSTRLEN];
#ifdef TCP_USER_TIMEOUT
    int optval;
    long sbd_timeout = crm_get_sbd_timeout();
#endif

    /* accept the connection */
    laddr = sizeof(addr);
    memset(&addr, 0, sizeof(addr));
    csock = accept(ssock, (struct sockaddr *)&addr, &laddr);
    crm_sockaddr2str(&addr, addr_str);
    crm_info("New remote connection from %s", addr_str);

    if (csock == -1) {
        crm_err("accept socket failed");
        return -1;
    }

    rc = crm_set_nonblocking(csock);
    if (rc < 0) {
        crm_err("Could not set socket non-blocking: %s " CRM_XS " rc=%d",
                pcmk_strerror(rc), rc);
        close(csock);
        return rc;
    }

#ifdef TCP_USER_TIMEOUT
    if (sbd_timeout > 0) {
        optval = sbd_timeout / 2; /* time to fail and retry before watchdog */
        rc = setsockopt(csock, SOL_TCP, TCP_USER_TIMEOUT,
                        &optval, sizeof(optval));
        if (rc < 0) {
            crm_err("setting TCP_USER_TIMEOUT (%d) on client socket failed",
                    optval);
            close(csock);
            return rc;
        }
    }
#endif

    return csock;
}
static int
bind_and_listen(struct addrinfo *addr)
{
    int optval;
    int fd;
    int rc;
    char buffer[INET6_ADDRSTRLEN] = { 0, };

    crm_sockaddr2str(addr->ai_addr, buffer);
    crm_trace("Attempting to bind to address %s", buffer);

    fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
    if (fd < 0) {
        crm_perror(LOG_ERR, "Listener socket creation failed");
        return -1;
    }

    /* reuse address */
    optval = 1;
    rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    if (rc < 0) {
        crm_perror(LOG_ERR, "Local address reuse not allowed on %s", buffer);
        close(fd);
        return -1;
    }

    if (addr->ai_family == AF_INET6) {
        optval = 0;
        rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval));
        if (rc < 0) {
            crm_perror(LOG_INFO, "Couldn't disable IPV6-only on %s", buffer);
            close(fd);
            return -1;
        }
    }

    if (bind(fd, addr->ai_addr, addr->ai_addrlen) != 0) {
        crm_perror(LOG_ERR, "Cannot bind to %s", buffer);
        close(fd);
        return -1;
    }

    if (listen(fd, 10) == -1) {
        crm_perror(LOG_ERR, "Cannot listen on %s", buffer);
        close(fd);
        return -1;
    }
    return fd;
}
Exemple #3
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;
}
Exemple #4
0
static int
cib_remote_listen(gpointer data)
{
    int csock = 0;
    unsigned laddr;
    struct sockaddr_storage addr;
    char ipstr[INET6_ADDRSTRLEN];
    int ssock = *(int *)data;
    int rc;

    crm_client_t *new_client = NULL;

    static struct mainloop_fd_callbacks remote_client_fd_callbacks = {
        .dispatch = cib_remote_msg,
        .destroy = cib_remote_connection_destroy,
    };

    /* accept the connection */
    laddr = sizeof(addr);
    memset(&addr, 0, sizeof(addr));
    csock = accept(ssock, (struct sockaddr *)&addr, &laddr);
    if (csock == -1) {
        crm_perror(LOG_ERR, "Could not accept socket connection");
        return TRUE;
    }

    crm_sockaddr2str(&addr, ipstr);
    crm_debug("New %s connection from %s",
              ((ssock == remote_tls_fd)? "secure" : "clear-text"), ipstr);

    rc = crm_set_nonblocking(csock);
    if (rc < 0) {
        crm_err("Could not set socket non-blocking: %s " CRM_XS " rc=%d",
                pcmk_strerror(rc), rc);
        close(csock);
        return TRUE;
    }

    num_clients++;

    crm_client_init();
    new_client = crm_client_alloc(NULL);
    new_client->remote = calloc(1, sizeof(crm_remote_t));

    if (ssock == remote_tls_fd) {
#ifdef HAVE_GNUTLS_GNUTLS_H
        new_client->kind = CRM_CLIENT_TLS;

        /* create gnutls session for the server socket */
        new_client->remote->tls_session = pcmk__new_tls_session(csock,
                                                                GNUTLS_SERVER,
                                                                GNUTLS_CRD_ANON,
                                                                anon_cred_s);
        if (new_client->remote->tls_session == NULL) {
            close(csock);
            return TRUE;
        }
#endif
    } else {
        new_client->kind = CRM_CLIENT_TCP;
        new_client->remote->tcp_socket = csock;
    }

    // Require the client to authenticate within this time
    new_client->remote->auth_timeout = g_timeout_add(REMOTE_AUTH_TIMEOUT,
                                                     remote_auth_timeout_cb,
                                                     new_client);
    crm_info("Remote CIB client pending authentication "
             CRM_XS " %p id: %s", new_client, new_client->id);

    new_client->remote->source =
        mainloop_add_fd("cib-remote-client", G_PRIORITY_DEFAULT, csock, new_client,
                        &remote_client_fd_callbacks);

    return TRUE;
}