[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Remote EOF and MinGW builds


Hi,

it seems to me as if the recent Windows MinGW builds are broken. They eat remote EOF messages. The code emulating "poll()" is most likely causing this.

As far as I know poll() and select() offer the same functionality. Select() needs a little more memory than poll(), but it is way more platform independent. Thus I've adopted the library to use select(). This makes the files "poll.h" and "poll.c" obsolete.

Futhermore you find a patch for channel_is_eof(). Remote EOF where ignored, as long as the error buffer or the write buffer is not empty. This seemed wrong to me, a remote EOF should always win...

After applying these changes, the librarys seems to works with MinGW and Windows as it should and stopped eating EOF's ... ;-)

Regards

Thomas


*** ./../../patch/channels.c	2010-03-02 23:46:18.073000000 +0100
--- ./channels.c	2010-03-02 23:03:32.948242200 +0100
***************
*** 357,364 ****
  
    channel = channel_from_msg(session);
    if (channel == NULL) {
!     ssh_log(session, SSH_LOG_FUNCTIONS,
!         "%s", ssh_get_error(session));
      leave_function();
      return;
    }
--- 357,363 ----
  
    channel = channel_from_msg(session);
    if (channel == NULL) {
!     ssh_log(session, SSH_LOG_FUNCTIONS,"%s", ssh_get_error(session));
      leave_function();
      return;
    }
***************
*** 1013,1029 ****
   *
   * @param channel       The channel to check.
   *
!  * @return 0 if there is no EOF, nonzero otherwise.
   */
! int channel_is_eof(ssh_channel channel) {
!   if ((channel->stdout_buffer &&
!         buffer_get_rest_len(channel->stdout_buffer) > 0) ||
!       (channel->stderr_buffer &&
!        buffer_get_rest_len(channel->stderr_buffer) > 0)) {
!     return 0;
!   }
  
!   return (channel->remote_eof != 0);
  }
  
  /**
--- 1012,1032 ----
   *
   * @param channel       The channel to check.
   *
!  * @return SSH_EOF in case of an EOF, otherwise SSH_OK
   */
! int channel_is_eof(ssh_channel channel)
! {
!   // An remote eof wins!
!   if (channel->remote_eof)
!    return SSH_EOF;
! 
!   if ((!channel->stdout_buffer) || (buffer_get_rest_len(channel->stdout_buffer) < 0))
!     return SSH_EOF;
! 
!   if ((!channel->stderr_buffer) || (buffer_get_rest_len(channel->stderr_buffer) > 0))
! 	return SSH_EOF;
  
!   return SSH_OK;
  }
  
  /**
***************
*** 1860,1868 ****
   * @warning The read function using a buffer has been renamed to
   *          channel_read_buffer().
   */
! int channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr) {
    ssh_session session = channel->session;
!   ssh_buffer stdbuf = channel->stdout_buffer;
    uint32_t len;
  
    enter_function();
--- 1863,1872 ----
   * @warning The read function using a buffer has been renamed to
   *          channel_read_buffer().
   */
! int channel_read(ssh_channel channel, void *dest, uint32_t count, int is_stderr)
! {
    ssh_session session = channel->session;
!   ssh_buffer stdbuf;
    uint32_t len;
  
    enter_function();
***************
*** 1872,1880 ****
      return 0;
    }
  
!   if (is_stderr) {
!     stdbuf=channel->stderr_buffer;
!   }
  
    /*
     * We may have problem if the window is too small to accept as much data
--- 1876,1885 ----
      return 0;
    }
  
!   if (is_stderr)
!     stdbuf = channel->stderr_buffer;
!   else
! 	stdbuf = channel->stdout_buffer;
  
    /*
     * We may have problem if the window is too small to accept as much data
***************
*** 1999,2011 ****
   */
  int channel_poll(ssh_channel channel, int is_stderr){
    ssh_session session = channel->session;
!   ssh_buffer stdbuf = channel->stdout_buffer;
  
    enter_function();
  
!   if (is_stderr) {
      stdbuf = channel->stderr_buffer;
!   }
  
    while (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) {
      if (ssh_handle_packets(channel->session) <= 0) {
--- 2004,2017 ----
   */
  int channel_poll(ssh_channel channel, int is_stderr){
    ssh_session session = channel->session;
!   ssh_buffer stdbuf;
  
    enter_function();
  
!   if (is_stderr)
      stdbuf = channel->stderr_buffer;
!   else
! 	stdbuf = channel->stdout_buffer;
  
    while (buffer_get_rest_len(stdbuf) == 0 && channel->remote_eof == 0) {
      if (ssh_handle_packets(channel->session) <= 0) {
***************
*** 2014,2022 ****
    }
  
    if (buffer_get_rest_len(stdbuf) > 0)
      return buffer_get_rest_len(stdbuf);
  
!   if (channel->remote_eof) {
      leave_function();
      return SSH_EOF;
    }
--- 2020,2032 ----
    }
  
    if (buffer_get_rest_len(stdbuf) > 0)
+   {
+ 	leave_function();
      return buffer_get_rest_len(stdbuf);
+   }
  
!   if (channel->remote_eof)
!   {
      leave_function();
      return SSH_EOF;
    }


*** ./../../patch/socket.c	2010-03-02 23:46:03.182000000 +0100
--- ./socket.c	2010-03-02 21:36:42.300781200 +0100
***************
*** 26,42 ****
  #include <stdlib.h>
  #include <stdio.h>
  #ifdef _WIN32
! #include <winsock2.h>
  #else
! #include <fcntl.h>
! #include <sys/types.h>
! #include <sys/socket.h>
! #include <sys/un.h>
  #endif
  #include "libssh/priv.h"
  #include "libssh/socket.h"
  #include "libssh/buffer.h"
- #include "libssh/poll.h"
  #include "libssh/session.h"
  
  /** \defgroup ssh_socket SSH Sockets
--- 26,41 ----
  #include <stdlib.h>
  #include <stdio.h>
  #ifdef _WIN32
!   #include <winsock2.h>
  #else
!   #include <fcntl.h>
!   #include <sys/types.h>
!   #include <sys/socket.h>
!   #include <sys/un.h>
  #endif
  #include "libssh/priv.h"
  #include "libssh/socket.h"
  #include "libssh/buffer.h"
  #include "libssh/session.h"
  
  /** \defgroup ssh_socket SSH Sockets
***************
*** 47,54 ****
  struct socket {
    socket_t fd;
    int last_errno;
!   int data_to_read; /* reading now on socket will
!                        not block */
    int data_to_write;
    int data_except;
    ssh_buffer out_buffer;
--- 46,52 ----
  struct socket {
    socket_t fd;
    int last_errno;
!   int data_to_read; /* reading now on socket will not block */
    int data_to_write;
    int data_except;
    ssh_buffer out_buffer;
***************
*** 460,506 ****
  }
  
  /* ssh_socket_poll */
! int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
    ssh_session session = s->session;
-   ssh_pollfd_t fd[1];
    int rc = -1;
  
    enter_function();
  
!   if (!ssh_socket_is_open(s)) {
      *except = 1;
      *writeable = 0;
      return 0;
    }
  
!   fd->fd = s->fd;
!   fd->events = 0;
  
!   if (!s->data_to_read) {
!     fd->events |= POLLIN;
!   }
!   if (!s->data_to_write) {
!     fd->events |= POLLOUT;
!   }
  
!   /* Make the call, and listen for errors */
!   rc = ssh_poll(fd, 1, 0);
!   if (rc < 0) {
!     ssh_set_error(session, SSH_FATAL, "poll(): %s", strerror(errno));
!     leave_function();
!     return -1;
!   }
  
!   if (!s->data_to_read) {
!     s->data_to_read = fd->revents & POLLIN;
!   }
!   if (!s->data_to_write) {
!     s->data_to_write = fd->revents & POLLOUT;
!   }
!   if (!s->data_except) {
!     s->data_except = fd->revents & POLLERR;
    }
  
    *except = s->data_except;
    *writeable = s->data_to_write;
  
--- 458,521 ----
  }
  
  /* ssh_socket_poll */
! /** \internal
!  * \Checks if the socket is ready for reading, ready for writing, or has an error condition
!  * \param s the socket
!  * \param [out] a non-zero value to indicate that socket is ready to write
!  * \param [out] a non-zero value a pending socket error
!  * \returns a non-zero value if data is ready to read
!  */
! int ssh_socket_poll(struct socket *s, int *writeable, int *except)
! {
    ssh_session session = s->session;
    int rc = -1;
  
    enter_function();
  
!   if (!ssh_socket_is_open(s))
!   {
      *except = 1;
      *writeable = 0;
      return 0;
    }
  
!   // We define these function only when needed...
!   fd_set read_fds, write_fds, except_fds;
  
!   // Clear out all fd_sets
!   FD_ZERO(&read_fds);
!   FD_ZERO(&write_fds);
!   FD_ZERO(&except_fds);
  
!   if (!s->data_to_read)
!     FD_SET(s->fd, &read_fds);
  
!   if (!s->data_to_write)
! 	FD_SET(s->fd, &write_fds);
! 
!   struct timeval tv = {0, 0};
! 
!   rc = select((s->fd)+1,&read_fds, &write_fds, NULL,  &tv);
! 
!   if (rc == -1)
!   {
!     ssh_set_error(session, SSH_FATAL, "select(): %s", strerror(errno));
! 	leave_function();
! 	return -1;
    }
  
+   // Check if socket is ready to read
+   if (!s->data_to_read)
+     s->data_to_read = FD_ISSET(s->fd,&read_fds);
+ 
+   // Check if socket is ready to write
+   if (!s->data_to_write)
+     s->data_to_write = FD_ISSET(s->fd,&write_fds);
+ 
+   // Check if socket has a pending error
+   if (!s->data_except)
+     s->data_except = FD_ISSET(s->fd,&except_fds);
+ 
    *except = s->data_except;
    *writeable = s->data_to_write;
  



Follow-Ups:
Re: Remote EOF and MinGW buildsAndreas Schneider <mail@xxxxxxxxxxxx>
Archive administrator: postmaster@lists.cynapses.org