Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Channel cannot be closed or freed early while executing a long running command #1218

Open
zhaojh329 opened this issue Nov 12, 2023 · 1 comment

Comments

@zhaojh329
Copy link

Describe the bug
Channel cannot be closed or freed early while execute a command that will last a long time.

To Reproduce

This code execs a command sleep 100 and I cannot close the channel early.

#include <libssh2.h>

#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdio.h>
#include <stdlib.h>

static const char *hostname = "127.0.0.1";
static const char *commandline = "sleep 100";
static const char *username = "root";
static const char *password = "1";

static int waitsocket(libssh2_socket_t socket_fd, LIBSSH2_SESSION *session)
{
    struct timeval timeout;
    int rc;
    fd_set fd;
    fd_set *writefd = NULL;
    fd_set *readfd = NULL;
    int dir;

    timeout.tv_sec = 10;
    timeout.tv_usec = 0;

    FD_ZERO(&fd);

    FD_SET(socket_fd, &fd);

    /* now make sure we wait in the correct direction */
    dir = libssh2_session_block_directions(session);

    if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)
        readfd = &fd;

    if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)
        writefd = &fd;

    rc = select((int)(socket_fd + 1), readfd, writefd, NULL, &timeout);

    return rc;
}

int main(int argc, char *argv[])
{
    uint32_t hostaddr;
    libssh2_socket_t sock;
    struct sockaddr_in sin;
    int rc;
    LIBSSH2_SESSION *session = NULL;
    LIBSSH2_CHANNEL *channel;
    int exitcode;

    rc = libssh2_init(0);
    if(rc) {
        fprintf(stderr, "libssh2 initialization failed (%d)\n", rc);
        return 1;
    }

    hostaddr = inet_addr(hostname);

    sock = socket(AF_INET, SOCK_STREAM, 0);
    if(sock == LIBSSH2_INVALID_SOCKET) {
        fprintf(stderr, "failed to create socket!\n");
        goto shutdown;
    }

    sin.sin_family = AF_INET;
    sin.sin_port = htons(22);
    sin.sin_addr.s_addr = hostaddr;
    if(connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in))) {
        fprintf(stderr, "failed to connect!\n");
        goto shutdown;
    }

    session = libssh2_session_init();
    if(!session) {
        fprintf(stderr, "Could not initialize SSH session!\n");
        goto shutdown;
    }

    libssh2_session_set_blocking(session, 0);

    while((rc = libssh2_session_handshake(session, sock)) ==
          LIBSSH2_ERROR_EAGAIN);
    if(rc) {
        fprintf(stderr, "Failure establishing SSH session: %d\n", rc);
        goto shutdown;
    }

    while((rc = libssh2_userauth_password(session, username, password)) ==
            LIBSSH2_ERROR_EAGAIN);
    if(rc) {
        fprintf(stderr, "Authentication by password failed!\n");
        goto shutdown;
    }

    do {
        channel = libssh2_channel_open_session(session);
        if(channel ||
           libssh2_session_last_error(session, NULL, NULL, 0) !=
           LIBSSH2_ERROR_EAGAIN)
            break;
        waitsocket(sock, session);
    } while(1);

    if(!channel) {
        fprintf(stderr, "Error\n");
        exit(1);
    }

    while((rc = libssh2_channel_exec(channel, commandline)) ==
          LIBSSH2_ERROR_EAGAIN) {
        waitsocket(sock, session);
    }
    if(rc) {
        fprintf(stderr, "exec error\n");
        exit(1);
    }

    exitcode = 127;
    while((rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN)
        waitsocket(sock, session);

    if(rc == 0)
        exitcode = libssh2_channel_get_exit_status(channel);

    fprintf(stderr, "\nEXIT: %d\n", exitcode);

    libssh2_channel_free(channel);

shutdown:

    if(session) {
        libssh2_session_disconnect(session, "Normal Shutdown");
        libssh2_session_free(session);
    }

    if(sock != LIBSSH2_INVALID_SOCKET) {
        close(sock);
    }

    fprintf(stderr, "all done\n");

    libssh2_exit();

    return 0;
}

Expected behavior
Channel can be freed early while execute a command that will last a long time.

Version (please complete the following information):

  • OS and version: Ubuntu 22.04.2 LTS
  • libssh2 version: 1.10.0
  • crypto backend and version: OpenSSL 3.0.2

Additional context

@vszakats vszakats changed the title Channel cannot be closed or freed early while execute a command that will last a long time. Channel cannot be closed or freed early while executing a long running command Dec 6, 2023
@rmsh1216
Copy link
Contributor

rmsh1216 commented Apr 8, 2024

In my opinion, it is normal to wait for the command to finish, regardless of how long the command takes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants