root/plugin/ipc/ssh/util_ssh.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. buffer_init
  2. buffer_free
  3. buffer_readjust
  4. buffer_ready_for_read
  5. buffer_read
  6. buffer_ready_for_write
  7. buffer_write
  8. set_nonblock
  9. signal_handler
  10. client_loop

   1 #include <unistd.h>
   2 #include <sys/errno.h>
   3 #include <sys/fcntl.h>
   4 #include <sys/types.h>
   5 #include <stdio.h>
   6 #include <stdlib.h>
   7 #include <signal.h>
   8 #include <string.h>
   9 #include <assert.h>
  10 
  11 #define MAX(a,b) ((a) < (b) ? (b) : (a))
  12 
  13 #define MAX_BUFFER_SIZE (64*1024)
  14 
  15 struct Buffer {
  16   char *buf;
  17   int  off;
  18   int  end;
  19   int  len;
  20 };
  21 
  22 static void buffer_init(struct Buffer *buf);
  23 static void buffer_free(struct Buffer *buf);
  24 static void buffer_read(struct Buffer *buf, int fd);
  25 static void buffer_write(struct Buffer *buf, int fd);
  26 
  27 int quit_pending = 0;
  28 pid_t childPid = -1;
  29 int remoteSock;
  30 static struct Buffer stdin_buffer, stdout_buffer, stderr_buffer;
  31 
  32 static void buffer_init(struct Buffer *buf)
  33 {
  34   assert(buf != NULL);
  35   buf->buf = (char*) malloc(MAX_BUFFER_SIZE);
  36   assert(buf->buf != NULL);
  37   buf->off = 0;
  38   buf->end = 0;
  39   buf->len = MAX_BUFFER_SIZE;
  40 }
  41 
  42 static void buffer_free(struct Buffer *buf)
  43 {
  44   free(buf->buf);
  45   buf->buf = NULL;
  46   buf->len = 0;
  47 }
  48 
  49 static void buffer_readjust(struct Buffer *buf)
  50 {
  51   memmove(buf->buf, &buf->buf[buf->off], buf->end - buf->off);
  52   buf->end -= buf->off;
  53   buf->off = 0;
  54 }
  55 
  56 static bool buffer_ready_for_read(struct Buffer *buf)
  57 {
  58   assert(buf->buf != NULL && buf->len != 0);
  59   return buf->end < buf->len - 1;
  60 }
  61 
  62 static void buffer_read(struct Buffer *buf, int fd)
  63 {
  64   assert(buf->buf != NULL && buf->len != 0);
  65 
  66   if (buf->end < buf->len) {
  67     size_t max = buf->len - buf->end;
  68     ssize_t rc = read(fd, &buf->buf[buf->end], max);
  69     if (rc == 0 || (rc == -1 && errno != EINTR)) {
  70       quit_pending = 1;
  71       return;
  72     }
  73     buf->end += rc;
  74   }
  75 }
  76 
  77 static bool buffer_ready_for_write(struct Buffer *buf)
  78 {
  79   assert(buf->buf != NULL && buf->len != 0);
  80   return buf->end > buf->off;
  81 }
  82 
  83 static void buffer_write(struct Buffer *buf, int fd)
  84 {
  85   assert(buf->buf != NULL && buf->len != 0);
  86 
  87   assert(buf->end > buf->off);
  88   size_t max = buf->end - buf->off;
  89   ssize_t rc = write(fd,  &buf->buf[buf->off], max);
  90   if (rc == -1 && errno != EINTR) {
  91     quit_pending = 1;
  92     return;
  93   }
  94   buf->off += rc;
  95   if (buf->off > buf->len / 2) {
  96     buffer_readjust(buf);
  97   }
  98 }
  99 
 100 
 101 /* set/unset filedescriptor to non-blocking */
 102 static void set_nonblock(int fd)
 103 {
 104   int val;
 105   val = fcntl(fd, F_GETFL, 0);
 106   if (val < 0) {
 107     perror("fcntl failed");
 108   }
 109   val |= O_NONBLOCK;
 110   if (fcntl(fd, F_SETFL, val) == -1) {
 111     perror("fcntl failed");
 112   }
 113 }
 114 
 115 /*
 116  * Signal handler for signals that cause the program to terminate.  These
 117  * signals must be trapped to restore terminal modes.
 118  */
 119 static void signal_handler(int sig)
 120 {
 121   quit_pending = 1;
 122   if (childPid != -1) {
 123     kill(childPid, sig);
 124   }
 125 }
 126 
 127 void client_loop(int ssh_stdin, int ssh_stdout, int ssh_stderr, int sock)
 128 {
 129   remoteSock = sock;
 130   /* Initialize buffers. */
 131   buffer_init(&stdin_buffer);
 132   buffer_init(&stdout_buffer);
 133   buffer_init(&stderr_buffer);
 134 
 135   /* enable nonblocking unless tty */
 136   set_nonblock(fileno(stdin));
 137   set_nonblock(fileno(stdout));
 138   set_nonblock(fileno(stderr));
 139 
 140   /*
 141    * Set signal handlers, (e.g. to restore non-blocking mode)
 142    * but don't overwrite SIG_IGN, matches behaviour from rsh(1)
 143    */
 144   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
 145     signal(SIGHUP, signal_handler);
 146   if (signal(SIGINT, SIG_IGN) != SIG_IGN)
 147     signal(SIGINT, signal_handler);
 148   if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
 149     signal(SIGQUIT, signal_handler);
 150   if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
 151     signal(SIGTERM, signal_handler);
 152   //signal(SIGWINCH, window_change_handler);
 153 
 154   fd_set readset, writeset, errorset;
 155   int max_fd = 0;
 156 
 157   max_fd = MAX(ssh_stdin, ssh_stdout);
 158   max_fd = MAX(max_fd, ssh_stderr);
 159 
 160   /* Main loop of the client for the interactive session mode. */
 161   while (!quit_pending) {
 162     struct timeval tv = {10, 0};
 163     FD_ZERO(&readset);
 164     FD_ZERO(&writeset);
 165     FD_ZERO(&errorset);
 166     FD_SET(remoteSock, &errorset);
 167 
 168     if (buffer_ready_for_read(&stdin_buffer)) {
 169       FD_SET(STDIN_FILENO, &readset);
 170     }
 171     if (buffer_ready_for_read(&stdout_buffer)) {
 172       FD_SET(ssh_stdout, &readset);
 173     }
 174     if (buffer_ready_for_read(&stderr_buffer)) {
 175       FD_SET(ssh_stderr, &readset);
 176     }
 177 
 178     if (buffer_ready_for_write(&stdin_buffer)) {
 179       FD_SET(ssh_stdin, &writeset);
 180     }
 181     if (buffer_ready_for_write(&stdout_buffer)) {
 182       FD_SET(STDOUT_FILENO, &writeset);
 183     }
 184     if (buffer_ready_for_write(&stderr_buffer)) {
 185       FD_SET(STDERR_FILENO, &writeset);
 186     }
 187 
 188     int ret = select(max_fd, &readset, &writeset, &errorset, &tv);
 189     if (ret == -1 && errno == EINTR) {
 190       continue;
 191     }
 192     if (ret == -1) {
 193       perror("select failed");
 194       return;
 195     }
 196 
 197     if (quit_pending)
 198       break;
 199 
 200     //Read from our STDIN or stdout/err of ssh
 201     if (FD_ISSET(STDIN_FILENO, &readset)) {
 202       buffer_read(&stdin_buffer, STDIN_FILENO);
 203     }
 204     if (FD_ISSET(ssh_stdout, &readset)) {
 205       buffer_read(&stdout_buffer, ssh_stdout);
 206     }
 207     if (FD_ISSET(ssh_stderr, &readset)) {
 208       buffer_read(&stderr_buffer, ssh_stderr);
 209     }
 210 
 211     // Write to our stdout/err or stdin of ssh
 212     if (FD_ISSET(ssh_stdin, &writeset)) {
 213       buffer_write(&stdin_buffer, ssh_stdin);
 214     }
 215     if (FD_ISSET(STDOUT_FILENO, &writeset)) {
 216       buffer_write(&stdout_buffer, STDOUT_FILENO);
 217     }
 218     if (FD_ISSET(STDERR_FILENO, &writeset)) {
 219       buffer_write(&stderr_buffer, STDERR_FILENO);
 220     }
 221 
 222     if (FD_ISSET(remoteSock, &errorset)) {
 223       break;
 224     }
 225 
 226     if (quit_pending)
 227       break;
 228   }
 229 
 230   /* Write pending data to our stdout/stderr */
 231   if (buffer_ready_for_write(&stdout_buffer)) {
 232     buffer_write(&stdout_buffer, STDOUT_FILENO);
 233   }
 234   if (buffer_ready_for_write(&stderr_buffer)) {
 235     buffer_write(&stderr_buffer, STDERR_FILENO);
 236   }
 237 
 238   /* Clear and free any buffers. */
 239   buffer_free(&stdin_buffer);
 240   buffer_free(&stdout_buffer);
 241   buffer_free(&stderr_buffer);
 242 }

/* [<][>][^][v][top][bottom][index][help] */