struct vnc_proxy
{
    ssh_session session;
    char *remote_host;
    int32_t remote_port;
};
typedef struct vnc_proxy proxy;


ssh_session _ssh_connect(char *ip, char *username, char *password)
{
    ssh_session my_ssh_session = ssh_new();
    if (my_ssh_session == NULL )
        return (NULL );
    int rc = 0;
    int verbosity = SSH_LOG_RARE;
    int port = 22;

    ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, ip);
    ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port);
    ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);

    rc = ssh_connect(my_ssh_session);
    if (rc != SSH_OK)
    {
        fprintf(stderr, "Error connecting to %s: %s\n", ip,
                ssh_get_error(my_ssh_session));
        return (NULL );
    }
    rc = ssh_userauth_password(my_ssh_session, username, password);
    if (rc != SSH_AUTH_SUCCESS)
    {
        fprintf(stderr, "Error authenticating with password (%s %s %s): %s\n",ip,username,password, ssh_get_error(my_ssh_session));
        ssh_disconnect(my_ssh_session);
        ssh_free(my_ssh_session);
        return (NULL );
    }
    //ssh_set_blocking(my_ssh_session, 0);
    return (my_ssh_session);
}

void *vnc_forward_port (void *arg)
{
    proxy *p = arg;
    ssh_session session = p->session;
    char *remote_host=p->remote_host;
    int32_t remote_port=p->remote_port;
    int32_t server_sock = 0;
    int32_t client_sock = -1;
    struct sockaddr_in client_name;
    socklen_t client_name_len = sizeof client_name;
    server_sock = server_startup(remote_port);

    client_sock = accept(server_sock,
                         (struct sockaddr *)&client_name,
                         &client_name_len);
    while (client_sock == -1)
    {
        perror("Error on accept");
        ssh_disconnect(session);
        ssh_free(session);
        free(p);
        pthread_exit(0);
    }
    int32_t client_port = ntohs(client_name.sin_port);
    int32_t size_recv, nwritten, nread = 0;
    uint8_t data[2048];

    fcntl(client_sock, F_SETFL, O_NONBLOCK);
    /*  */
    ssh_channel forwarding_channel;
    forwarding_channel = ssh_channel_new(session);
    int rc = channel_open_forward(forwarding_channel,
                                  remote_host, remote_port,
                                  "127.0.0.1", remote_port);
    if (rc != SSH_OK)
    {
        puts("SSH error");
        goto exit;
    }
    for(;;)
    {
        if((size_recv = recv(client_sock, data, sizeof data, MSG_DONTWAIT) ) < 0)
        {
            if((nread = ssh_channel_read_nonblocking(forwarding_channel, data, sizeof data, 0)) > 0)
            {
                if(send(client_sock,data,nread, MSG_DONTWAIT) < 0)
                {
                    puts("VNC transfer error");
                    goto exit;
                }
            }

        }
        else if (!size_recv)
        {
            puts("The client disconnected, closing tunnel");
            goto exit;
        }
        nwritten = channel_write(forwarding_channel, data, size_recv);
        if (size_recv != nwritten)
        {
            puts("SSH write error");
            goto exit;
        }
       usleep(500); 
    }
exit:
    ssh_channel_send_eof(forwarding_channel);
    ssh_channel_close(forwarding_channel);
    ssh_channel_free(forwarding_channel);
    ssh_disconnect(session);
    ssh_free(session);
    ssh_finalize();
    close(client_sock);
    close(server_sock);
    free(p);
    pthread_exit(0);
}
