 //gcc -Wall -I /usr/include/libssh -I /usr/include -lssh  libssh_client_run process_on_remote_host.cpp.cpp -o libssh_client_run process_on_remote_host.cpp

#include <libssh/libssh.h>
#include <libssh/callbacks.h>
#include <stdlib.h>
#include <stdio.h>
//#include <conio.h>
#include <errno.h>
#include <string.h>
#include <socket.h>
#include "libssh/server.h"

int verify_knownhost(ssh_session session)
{
    enum ssh_known_hosts_e state;
    unsigned char *hash = NULL;
    ssh_key srv_pubkey = NULL;
    size_t hlen;
    char buf[10];
    char *hexa;
    char *p;
    int cmp;
    int rc;
    rc = ssh_get_server_publickey(session, &srv_pubkey);
    if (rc < 0) {
        return -1;
    }
    rc = ssh_get_publickey_hash(srv_pubkey,
                                SSH_PUBLICKEY_HASH_SHA1,
                                &hash,
                                &hlen);
    ssh_key_free(srv_pubkey);
    if (rc < 0) {
        return -1;
    }
    state = ssh_session_is_known_server(session);
    switch (state) {
        case SSH_KNOWN_HOSTS_OK:
            /* OK */
            break;
        case SSH_KNOWN_HOSTS_CHANGED:
            fprintf(stderr, "Host key for server changed: it is now:\n");
            ssh_print_hexa("Public key hash", hash, hlen);
            fprintf(stderr, "For security reasons, connection will be stopped\n");
            ssh_clean_pubkey_hash(&hash);
            return -1;
        case SSH_KNOWN_HOSTS_OTHER:
            fprintf(stderr, "The host key for this server was not found but an other"
                    "type of key exists.\n");
            fprintf(stderr, "An attacker might change the default server key to"
                    "confuse your client into thinking the key does not exist\n");
            ssh_clean_pubkey_hash(&hash);
            return -1;
        case SSH_KNOWN_HOSTS_NOT_FOUND:
            fprintf(stderr, "Could not find known host file.\n");
            fprintf(stderr, "If you accept the host key here, the file will be"
                    "automatically created.\n");
            /* FALL THROUGH to SSH_SERVER_NOT_KNOWN behavior */
        case SSH_KNOWN_HOSTS_UNKNOWN:
            hexa = ssh_get_hexa(hash, hlen);
            fprintf(stderr,"The server is unknown. Do you trust the host key?\n");
            fprintf(stderr, "Public key hash: %s\n", hexa);
            ssh_string_free_char(hexa);
            ssh_clean_pubkey_hash(&hash);
            p = fgets(buf, sizeof(buf), stdin);
            if (p == NULL) {
                return -1;
            }
            cmp = strncasecmp(buf, "yes", 3);
            if (cmp != 0) {
                return -1;
            }
            rc = ssh_session_update_known_hosts(session);
            if (rc < 0) {
                fprintf(stderr, "Error %s\n", strerror(errno));
                return -1;
            }
            break;
        case SSH_KNOWN_HOSTS_ERROR:
            fprintf(stderr, "Error %s", ssh_get_error(session));
            ssh_clean_pubkey_hash(&hash);
            return -1;
    }
    ssh_clean_pubkey_hash(&hash);
    return 0;
}

int show_remote_processes(ssh_session session)
{
  ssh_channel channel;
  int rc,retry=0,rc2;
  char buffer[25600];
  int nbytes;
  channel = ssh_channel_new(session);
  if (channel == NULL)
    return SSH_ERROR;
  do{usleep(1000);}while((rc = ssh_channel_open_session(channel))==SSH_AGAIN);
  //do{usleep(1000);}while((rc = ssh_channel_request_pty(channel))==SSH_AGAIN);
  do{usleep(1000);}while((rc = ssh_channel_request_exec(channel, "mount -v;df -kh"))==SSH_AGAIN);
  
   printf("Reading BUFFER...\n");
  do
  {
	usleep(1000);
	retry++;
    nbytes = ssh_channel_read(channel, buffer, sizeof(buffer), 0);
	rc2 = ssh_channel_is_eof(channel);
	if (nbytes > 0){ printf("BUFFER:%s\n",buffer);}
	 memset(buffer, 0, sizeof(buffer));
  }while (!rc2 && retry < 10000);
  
  //printf("EOF:%d,Signal ret:%d\n",rc2,ssh_channel_request_send_exit_signal(channel,"KILL",0,"Stopping Process","C"));
  printf("EOF:%d,Signal ret:%d\n",rc2,ssh_channel_request_send_signal(channel,"TERM"));
  
   
  if (nbytes < 0)
  {
    ssh_channel_close(channel);
    ssh_channel_free(channel);
    return SSH_ERROR;
  }

  ssh_channel_send_eof(channel);
  ssh_channel_close(channel);
  ssh_channel_free(channel);


  return SSH_OK;
}


void log_callback(ssh_session session, int priority, const char *message) {
   printf("log_callback \n");
 }
 
 int auth_callback(const char *prompt, char *buf, size_t len, int echo, int verify) {
   printf("auth_callback\n");
 }
 
 void connect_status_callback(float status) {
	   printf("connect_status_callback\n"); 
 }
 
 void global_request_callback(ssh_session session, ssh_message message) {
		  printf("global_request_callback\n"); 
 }
 
 
  void log_callback_function(ssh_session session, int priority,
                              const char *message,void *userdata) {
     log_callback(session, priority, message);
   }
 
   int auth_callback_function(const char *prompt, char *buf, size_t len,
                              int echo, int verify, void *userdata) {
     return (auth_callback(prompt, buf, len, echo, verify));
   }
 
   void connect_status_callback_function(void *userdata, float status) {
     connect_status_callback(status);
   }
 
   void global_request_callback_function(ssh_session session,
                                         ssh_message message,void *userdata) {
     global_request_callback(session, message);
   }
 
 
 
int main()
{
  ssh_session my_ssh_session;
  int rc,m_error,port=22;
  char *password;
 const char m_hostname[20]="my_linux_remote_host";
 int m_sd; 
  m_sd = socket(AF_INET, SOCK_STREAM, 0);
   if (m_sd < 0) {
	 printf("socket(AF_INET, SOCK_STREAM, 0) fialed - \n");
     return 0;
   }
 
   struct hostent *server = gethostbyname(m_hostname);
   if (server == NULL) {
     printf("gethostbyname failed - \n" );
     return 0;
   }
 
   struct sockaddr_in serv_addr;
   bzero((char *) &serv_addr, sizeof(serv_addr));
   serv_addr.sin_family = AF_INET;
   bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
   serv_addr.sin_port = htons(22);
 
 
   while (connect(m_sd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) {
     if (errno == EINTR) {
       usleep(1000);
      continue;
     }
     else if (errno != EINPROGRESS) {
       printf("connect failed - \n");
       return 0;
     }
     break;
   }  
  
  // Open session and set options
  my_ssh_session = ssh_new();
  if (my_ssh_session == NULL)
    exit(-1);
  ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, m_hostname);
  ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port);
  ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, "root");
  ssh_options_set(my_ssh_session, SSH_OPTIONS_FD, &m_sd);

  // Connect to server
  ssh_set_blocking(my_ssh_session,0);

 ssh_callbacks_struct m_callbacks;
 
  memset(&m_callbacks, 0, sizeof(m_callbacks));
  //m_callbacks.userdata = this;
  m_callbacks.auth_function = auth_callback_function;
  m_callbacks.log_function = log_callback_function;
  m_callbacks.connect_status_function = connect_status_callback_function;
  m_callbacks.global_request_function = global_request_callback_function;
  ssh_callbacks_init(&m_callbacks);

  rc = ssh_set_callbacks(my_ssh_session, &m_callbacks);
  if (rc == SSH_ERROR) {
    printf("ssh_set_callbacks() failed - \n");
    return false;
  }



do
{
 rc = ssh_connect(my_ssh_session);
if (rc == SSH_AGAIN) {
			printf("ssh_connect:again my_linux_remote_host: %s\n",
            ssh_get_error(my_ssh_session));
			
		} else if (rc == SSH_OK)
		{printf("success");break; }
		else
  {
    printf("Error connecting to my_linux_remote_host: %s\n",
            ssh_get_error(my_ssh_session));
    ssh_free(my_ssh_session);
    exit(-1);
  }
  usleep(1000);
} while (true);
 
 // Verify the server's identity
  // For the source code of verify_knownhost(), check previous example
  if (verify_knownhost(my_ssh_session) < 0)
  {
    ssh_disconnect(my_ssh_session);
    ssh_free(my_ssh_session);
    exit(-1);
  }
  // Authenticate ourselves
  //password = getpass("Password: ");
  do{
			//printf("ssh_userauth_password:Auth again\n");
			usleep(5000);
  }  while((rc = ssh_userauth_password(my_ssh_session, NULL, "password123")) == SSH_AUTH_AGAIN );
  //rc = ssh_userauth_password(my_ssh_session, NULL, password);
  if (rc != SSH_AUTH_SUCCESS)
  {
    fprintf(stderr, "Error authenticating with password: %s, return status: %d\n",
            ssh_get_error(my_ssh_session),rc);
    ssh_disconnect(my_ssh_session);
    ssh_free(my_ssh_session);
    exit(-1);
  }
  //...
  show_remote_processes(my_ssh_session);
  
  ssh_disconnect(my_ssh_session);
  ssh_free(my_ssh_session);
}

