コード例 #1
0
/*!
    \reimp
*/
qint64 QxtSshChannel::readData(char* buff, qint64 len) {
    ssize_t ret=libssh2_channel_read_ex(d->d_channel, d->d_read_stream_id,buff, len);
    if(ret<0){
        if(ret==LIBSSH2_ERROR_EAGAIN){
            return 0;
        }else{
#ifdef QXT_DEBUG_SSH
            qDebug()<<"read err"<<ret;
#endif
            return -1;
        }
    }
    return ret;
}
コード例 #2
0
BinaryNode *SSH2Channel::readBinary(qore_size_t size, int stream_id, int timeout_ms, ExceptionSink *xsink) {
   AutoLocker al(parent->m);
   if (check_open(xsink))
      return 0;

   SimpleRefHolder<BinaryNode> bin(new BinaryNode);

   BlockingHelper bh(parent);

   qore_offset_t rc;
   // bytes read
   qore_size_t b_read = 0;
   // bytes remaining
   qore_size_t b_remaining = size;
   while (true) {
      char buffer[QSSH2_BUFSIZE];
      qore_size_t to_read = QSSH2_BUFSIZE < b_remaining ? QSSH2_BUFSIZE : b_remaining;
      rc = libssh2_channel_read_ex(channel, stream_id, buffer, to_read);

      //printd(5, "SSH2Channel::read() rc=%lld (EAGAIN=%d)\n", rc, LIBSSH2_ERROR_EAGAIN);
      if (rc > 0) {
	 bin->append(buffer, rc);
	 b_read += rc;
	 b_remaining -= rc;
	 if (b_read >= size)
	    break;
	 continue;
      }

      if (!rc || rc == LIBSSH2_ERROR_EAGAIN) {
	 rc = parent->waitSocketUnlocked(timeout_ms);
	 if (!rc) {
	    xsink->raiseException(SSH2CHANNEL_TIMEOUT, "read timeout after %dms reading %lld byte%s of %lld requested", timeout_ms, b_read, b_read == 1 ? "" : "s", size);
	    return 0;
	 }
	 if (rc < 0) {
	    xsink->raiseException(SSH2CHANNEL_TIMEOUT, strerror(errno));
	    return 0;
	 }
      }
   }

   if (rc < 0 && rc != LIBSSH2_ERROR_EAGAIN) {
      parent->doSessionErrUnlocked(xsink);
      return 0;
   }

   return bin.release();
}
コード例 #3
0
ファイル: channel.c プロジェクト: elektro79/ssh4py
static PyObject *
channel_read(SSH2_ChannelObj *self, PyObject *args)
{
	int ret;
	int bufsiz;
	int stream_id = 0;
	PyObject *buf;

	if (!PyArg_ParseTuple(args, "i|i:read", &bufsiz, &stream_id))
		return NULL;

	if (bufsiz < 0) {
		PyErr_SetString(PyExc_ValueError, "negative size");
		return NULL;
	}

	if ((buf = PyBytes_FromStringAndSize(NULL, bufsiz)) == NULL)
		return NULL;

	Py_BEGIN_ALLOW_THREADS
	ret = libssh2_channel_read_ex(self->channel, stream_id, PyBytes_AS_STRING(buf), bufsiz);
	Py_END_ALLOW_THREADS

	if (ret < 0) {
		Py_DECREF(buf);

		/* We have to work around a bug in libssh2, that _libssh2_error() is not
		 * called by libssh2_channel_read_ex() when the transport layer returns
		 * LIBSSH2_ERROR_EAGAIN. So in that case the last error is not set and
		 * the RAISE_SSH2_ERROR macro will not be able to raise the correct exception.
		 * Thanks to Daniel Stenberg, who has fixed that issue now (see 2db4863).
		 * However in order that our bindings work correctly with older versions
		 * of libssh2, we need the workaround below. */
		if (ret == LIBSSH2_ERROR_EAGAIN) {
			PyObject *exc;
			PyObject *value;

			exc = PyObject_CallFunction(SSH2_Error, "s", "Would block");
			value=Py_BuildValue("i", ret);
			PyObject_SetAttrString(exc, "errno", value);
			PyErr_SetObject(SSH2_Error, exc);
			Py_DECREF(exc);
			Py_DECREF(value);
			return NULL;
		}

		RAISE_SSH2_ERROR(self->session)
	}
コード例 #4
0
void cql_ccm_bridge_t::terminal_read_stream(cql_escape_sequences_remover_t& buffer, int stream) {
  char buf[128];

  while (true) {
    // disable blocking
    libssh2_session_set_blocking(_ssh_internals->_session, 0);

    ssize_t readed = libssh2_channel_read_ex(_ssh_internals->_channel, stream, buf, sizeof(buf));

    // return if no data to read
    if (readed == LIBSSH2_ERROR_EAGAIN || readed == 0) {
      return;
    }

    // some error occurred
    if (readed < 0) {
      throw cql_ccm_bridge_exception_t("error during reading from socket");
    }

    buffer.push_character_range(buf, buf + readed);
  }
}
コード例 #5
0
ファイル: process.cpp プロジェクト: bytemaster/mace
 int process_d::read_some( char* data, size_t len, int stream_id ) {
     if( !sshc->my->m_session ) { MACE_SSH_THROW( "Session closed\n" ); }
    
    int rc;
    char* buf = data;
    size_t buflen = len;
    do {
        rc = libssh2_channel_read_ex( chan, stream_id, buf, buflen );
        if( rc > 0 ) {
           buf += rc;
           buflen -= rc;
           return buf-data;
        } else if( rc == 0 ) {
           if( libssh2_channel_eof( chan ) )  {
             return -1; // eof
           }
           sshc->my->wait_on_socket();
        } else {
          if( rc == LIBSSH2_ERROR_EAGAIN ) {
            if( 0 < (buf-data) ) {
              return buf-data;
            }
            else  {
              sshc->my->wait_on_socket();
              rc = 0;
              continue;
            }
          } else {
            char* msg;
            if( !sshc || !sshc->my || !sshc->my->m_session ) { MACE_SSH_THROW( "Session closed" ); }
            slog( "my: %1%", sshc->my );
            rc   = libssh2_session_last_error( sshc->my->m_session, &msg, 0, 0 );
            MACE_SSH_THROW( "read failed: %1% - %2%", %rc %msg  ); return buf-data;
          }
        }
    } while( rc >= 0 && buflen);
    return buf-data;
 }
コード例 #6
0
static size_t php_ssh2_channel_stream_read(php_stream *stream, char *buf, size_t count TSRMLS_DC)
{
	php_ssh2_channel_data *abstract = (php_ssh2_channel_data*)stream->abstract;
	ssize_t readstate;
	LIBSSH2_SESSION *session;

	stream->eof = libssh2_channel_eof(abstract->channel);
	libssh2_channel_set_blocking(abstract->channel, abstract->is_blocking);
	session = (LIBSSH2_SESSION *)zend_fetch_resource(NULL TSRMLS_CC, abstract->session_rsrc, PHP_SSH2_SESSION_RES_NAME, NULL, 1, le_ssh2_session);

#ifdef PHP_SSH2_SESSION_TIMEOUT
	if (abstract->is_blocking) {
		libssh2_session_set_timeout(session, abstract->timeout);
	}
#endif

	readstate = libssh2_channel_read_ex(abstract->channel, abstract->streamid, buf, count);

#ifdef PHP_SSH2_SESSION_TIMEOUT
	if (abstract->is_blocking) {
		libssh2_session_set_timeout(session, 0);
	}
#endif
	if (readstate == LIBSSH2_ERROR_EAGAIN) {
		readstate = 0;
	}

	if (readstate < 0) {
		char *error_msg = NULL;
		if (libssh2_session_last_error(session, &error_msg, NULL, 0) == readstate) {
			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failure '%s' (%ld)", error_msg, readstate);
		}

		stream->eof = 1;
		readstate = 0;
	}
	return readstate;
}
コード例 #7
0
BinaryNode *SSH2Channel::readBinary(ExceptionSink *xsink, int stream_id, int timeout_ms) {
   AutoLocker al(parent->m);
   if (check_open(xsink))
      return 0;

   SimpleRefHolder<BinaryNode> bin(new BinaryNode);

   BlockingHelper bh(parent);

   qore_offset_t rc;
   bool first = true;
   do {
     loop0:
      char buffer[QSSH2_BUFSIZE];
      rc = libssh2_channel_read_ex(channel, stream_id, buffer, QSSH2_BUFSIZE);
      //printd(5, "SSH2Channel::readBinary() rc=%ld (EAGAIN=%d)\n", rc, LIBSSH2_ERROR_EAGAIN);

      if (rc > 0) {
	 bin->append(buffer, rc);
      }
      else if (rc == LIBSSH2_ERROR_EAGAIN && !bin->size() && first) {
	 first = false;
	 if ((rc = parent->waitSocketUnlocked(xsink, SSH2CHANNEL_TIMEOUT, "SSH2CHANNEL-READBINARY-ERROR", "SSH2Channel::readBinary", timeout_ms)))
	    return 0;
	 goto loop0;
      }
   }
   while (rc > 0);

   if (rc < 0 && rc != LIBSSH2_ERROR_EAGAIN) {
      parent->doSessionErrUnlocked(xsink);
      return 0;
   }

   return bin.release();
}
コード例 #8
0
QoreStringNode *SSH2Channel::read(ExceptionSink *xsink, int stream_id, int timeout_ms) {
   AutoLocker al(parent->m);
   if (check_open(xsink))
      return 0;

   QoreStringNodeHolder str(new QoreStringNode(enc));

   BlockingHelper bh(parent);

   qore_offset_t rc;
   bool first = true;
   do {
     loop0:
      char buffer[QSSH2_BUFSIZE];
      rc = libssh2_channel_read_ex(channel, stream_id, buffer, QSSH2_BUFSIZE);
      //printd(0, "SSH2Channel::read() rc=%ld (EAGAIN=%d)\n", rc, LIBSSH2_ERROR_EAGAIN);

      if (rc > 0) {
	 str->concat(buffer, rc);
      }
      else if (rc == LIBSSH2_ERROR_EAGAIN && !str->strlen() && first) {
	 first = false;
	 if ((rc = parent->waitSocketUnlocked(xsink, SSH2CHANNEL_TIMEOUT, "SSH2CHANNEL-READ-ERROR", "SSH2Channel::read", timeout_ms)))
	    return 0;
	 goto loop0;
      }
   }
   while (rc > 0);

   if (rc < 0 && rc != LIBSSH2_ERROR_EAGAIN) {
      parent->doSessionErrUnlocked(xsink);
      return 0;
   }

   return str.release();
}
コード例 #9
0
ファイル: ssh_lib.c プロジェクト: allspace/fexec
int ssh_exec(ssh_conn_t *conn, param_t *params)
{
	LIBSSH2_CHANNEL *channel;
    int rc;
    int exitcode = 127;
    char *exitsignal=(char *)"none";	
	const char *commandline = params->command;

    /* Exec non-blocking on the remove host */
    while( (channel = libssh2_channel_open_session(conn->session)) == NULL &&
           libssh2_session_last_error(conn->session,NULL,NULL,0) ==
           LIBSSH2_ERROR_EAGAIN )
    {
        waitsocket(conn);
    }
    if( channel == NULL )
    {
        fprintf(stderr,"Error\n");
        return ( 1 );
    }
	
	rc = ssh_setenv(channel, params);
	if(rc<0)
	{
		if(rc==LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED)
			printf("Error: Environment variable is not accepted by target SSH server.");
		goto shutdown;
	}
	
    while( (rc = libssh2_channel_exec(channel, commandline)) ==
           LIBSSH2_ERROR_EAGAIN )
    {
        waitsocket(conn);
    }
    if( rc != 0 )
    {
        fprintf(stderr,"Error\n");
        return ( 1 );
    }
	
	int stream_id = 0;
    for( ;; )
    {
        /* loop until we block */
        int rc;
        do
        {
            char buffer[0x4000];
            rc = libssh2_channel_read_ex( channel, stream_id, buffer, sizeof(buffer) );
            if( rc > 0 )
            {
				fwrite(buffer, sizeof(char), rc, stream_id==0?stdout:stderr);
            }else{
                if( rc != LIBSSH2_ERROR_EAGAIN ) goto shutdown;
            }
        }
        while( rc > 0 );

        /* this is due to blocking that would occur otherwise so we loop on
           this condition */
        if( rc == LIBSSH2_ERROR_EAGAIN )
        {
            waitsocket(conn);
        }
        else
            break;
			
		stream_id = stream_id==0?1:0;
    }
    
    while( (rc = libssh2_channel_close(channel)) == LIBSSH2_ERROR_EAGAIN )
        waitsocket(conn);

    if( rc == 0 )
    {
        exitcode = libssh2_channel_get_exit_status( channel );
        libssh2_channel_get_exit_signal(channel, &exitsignal,
                                        NULL, NULL, NULL, NULL, NULL);
    }


shutdown:
    libssh2_channel_free(channel);
    channel = NULL;

    return exitcode;
}
コード例 #10
0
ファイル: scp.c プロジェクト: 95rangerxlt/cocoagit
/* {{{ libssh2_scp_send_ex
 * Send a file using SCP
 *
 * NOTE:  Will block in a busy loop on error.  This has to be done,
 *        otherwise the blocking error code would erase the true
 *        cause of the error.
 */
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_send_ex(LIBSSH2_SESSION * session, const char *path, int mode,
                    size_t size, long mtime, long atime)
{
    int path_len = strlen(path);
    unsigned const char *base;
    int rc;

    if (session->scpSend_state == libssh2_NB_state_idle) {
        session->scpSend_command_len = path_len + sizeof("scp -t ");

        if (mtime || atime) {
            session->scpSend_command_len++;
        }

        session->scpSend_command =
            LIBSSH2_ALLOC(session, session->scpSend_command_len);
        if (!session->scpSend_command) {
            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                          "Unable to allocate a command buffer for scp session",
                          0);
            return NULL;
        }

        if (mtime || atime) {
            memcpy(session->scpSend_command, "scp -pt ",
                   sizeof("scp -pt ") - 1);
            memcpy(session->scpSend_command + sizeof("scp -pt ") - 1, path,
                   path_len);
        } else {
            memcpy(session->scpSend_command, "scp -t ", sizeof("scp -t ") - 1);
            memcpy(session->scpSend_command + sizeof("scp -t ") - 1, path,
                   path_len);
        }
        session->scpSend_command[session->scpSend_command_len - 1] = '\0';

        _libssh2_debug(session, LIBSSH2_DBG_SCP,
                       "Opening channel for SCP send");
        /* Allocate a channel */

        session->scpSend_state = libssh2_NB_state_created;
    }

    if (session->scpSend_state == libssh2_NB_state_created) {
        session->scpSend_channel =
            libssh2_channel_open_ex(session, "session", sizeof("session") - 1,
                                    LIBSSH2_CHANNEL_WINDOW_DEFAULT,
                                    LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0);
        if (!session->scpSend_channel) {
            if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
                /* previous call set libssh2_session_last_error(), pass it through */
                LIBSSH2_FREE(session, session->scpSend_command);
                session->scpSend_command = NULL;
                session->scpSend_state = libssh2_NB_state_idle;
                return NULL;
            } else if (libssh2_session_last_errno(session) ==
                       LIBSSH2_ERROR_EAGAIN) {
                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                              "Would block starting up channel", 0);
                return NULL;
            }
        }

        session->scpSend_state = libssh2_NB_state_sent;
    }

    if (session->scpSend_state == libssh2_NB_state_sent) {
        /* Request SCP for the desired file */
        rc = libssh2_channel_process_startup(session->scpSend_channel, "exec",
                                             sizeof("exec") - 1,
                                             (char *) session->scpSend_command,
                                             session->scpSend_command_len);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block requesting SCP startup", 0);
            return NULL;
        } else if (rc) {
            /* previous call set libssh2_session_last_error(), pass it through */
            LIBSSH2_FREE(session, session->scpSend_command);
            session->scpSend_command = NULL;
            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                          "Unknown error while getting error string", 0);
            goto scp_send_error;
        }
        LIBSSH2_FREE(session, session->scpSend_command);
        session->scpSend_command = NULL;

        session->scpSend_state = libssh2_NB_state_sent1;
    }

    if (session->scpSend_state == libssh2_NB_state_sent1) {
        /* Wait for ACK */
        rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
                                     (char *) session->scpSend_response, 1);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block waiting for response from remote", 0);
            return NULL;
        } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                          "Invalid ACK response from remote", 0);
            goto scp_send_error;
        }

        if (mtime || atime) {
            /* Send mtime and atime to be used for file */
            session->scpSend_response_len =
                snprintf((char *) session->scpSend_response,
                         LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", mtime,
                         atime);
            _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
                           session->scpSend_response);
        }

        session->scpSend_state = libssh2_NB_state_sent2;
    }

    /* Send mtime and atime to be used for file */
    if (mtime || atime) {
        if (session->scpSend_state == libssh2_NB_state_sent2) {
            rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
                                          (char *) session->scpSend_response,
                                          session->scpSend_response_len);
            if (rc == PACKET_EAGAIN) {
                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                              "Would block sending time data for SCP file", 0);
                return NULL;
            } else if (rc != session->scpSend_response_len) {
                libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                              "Unable to send time data for SCP file", 0);
                goto scp_send_error;
            }

            session->scpSend_state = libssh2_NB_state_sent3;
        }

        if (session->scpSend_state == libssh2_NB_state_sent3) {
            /* Wait for ACK */
            rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
                                         (char *) session->scpSend_response,
                                         1);
            if (rc == PACKET_EAGAIN) {
                libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                              "Would block waiting for response", 0);
                return NULL;
            } else if ((rc <= 0) || (session->scpSend_response[0] != 0)) {
                libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                              "Invalid ACK response from remote", 0);
                goto scp_send_error;
            }

            session->scpSend_state = libssh2_NB_state_sent4;
        }
    } else {
        if (session->scpSend_state == libssh2_NB_state_sent2) {
            session->scpSend_state = libssh2_NB_state_sent4;
        }
    }

    if (session->scpSend_state == libssh2_NB_state_sent4) {
        /* Send mode, size, and basename */
        base = (unsigned char *) strrchr(path, '/');
        if (base) {
            base++;
        } else {
            base = (unsigned char *) path;
        }

        session->scpSend_response_len =
            snprintf((char *) session->scpSend_response,
                     LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %lu %s\n", mode,
                     (unsigned long) size, base);
        _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sent %s",
                       session->scpSend_response);

        session->scpSend_state = libssh2_NB_state_sent5;
    }

    if (session->scpSend_state == libssh2_NB_state_sent5) {
        rc = libssh2_channel_write_ex(session->scpSend_channel, 0,
                                      (char *) session->scpSend_response,
                                      session->scpSend_response_len);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block send core file data for SCP file", 0);
            return NULL;
        } else if (rc != session->scpSend_response_len) {
            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                          "Unable to send core file data for SCP file", 0);
            goto scp_send_error;
        }

        session->scpSend_state = libssh2_NB_state_sent6;
    }

    if (session->scpSend_state == libssh2_NB_state_sent6) {
        /* Wait for ACK */
        rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
                                     (char *) session->scpSend_response, 1);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block waiting for response", 0);
            return NULL;
        } else if (rc <= 0) {
            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                          "Invalid ACK response from remote", 0);
            goto scp_send_error;
        } else if (session->scpSend_response[0] != 0) {
            /*
             * Set this as the default error for here, if
             * we are successful it will be replaced
             */
            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                          "Invalid ACK response from remote", 0);

            session->scpSend_err_len =
                libssh2_channel_packet_data_len(session->scpSend_channel, 0);
            session->scpSend_err_msg =
                LIBSSH2_ALLOC(session, session->scpSend_err_len + 1);
            if (!session->scpSend_err_msg) {
                goto scp_send_error;
            }
            memset(session->scpSend_err_msg, 0, session->scpSend_err_len + 1);

            /* Read the remote error message */
            rc = libssh2_channel_read_ex(session->scpSend_channel, 0,
                                         session->scpSend_err_msg,
                                         session->scpSend_err_len);
            if (rc <= 0) {
                /*
                 * Since we have alread started reading this packet, it is
                 * already in the systems so it can't return PACKET_EAGAIN
                 */
                LIBSSH2_FREE(session, session->scpSend_err_msg);
                session->scpSend_err_msg = NULL;
                goto scp_send_error;
            }

            libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                          session->scpSend_err_msg, 1);
            session->scpSend_err_msg = NULL;
            goto scp_send_error;
        }
    }

    session->scpSend_state = libssh2_NB_state_idle;

    return session->scpSend_channel;

  scp_send_error:
    while (libssh2_channel_free(session->scpSend_channel) == PACKET_EAGAIN);
    session->scpSend_channel = NULL;
    session->scpSend_state = libssh2_NB_state_idle;
    return NULL;
}
コード例 #11
0
ファイル: scp.c プロジェクト: 95rangerxlt/cocoagit
/* {{{ libssh2_scp_recv
 * Open a channel and request a remote file via SCP
 *
 * NOTE:  Will block in a busy loop on error.  This has to be done,
 *        otherwise the blocking error code would erase the true
 *        cause of the error.
 */
LIBSSH2_API LIBSSH2_CHANNEL *
libssh2_scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb)
{
    int path_len = strlen(path);
    int rc;

    if (session->scpRecv_state == libssh2_NB_state_idle) {
        session->scpRecv_mode = 0;
        session->scpRecv_size = 0;
        session->scpRecv_mtime = 0;
        session->scpRecv_atime = 0;

        session->scpRecv_command_len = path_len + sizeof("scp -f ");

        if (sb) {
            session->scpRecv_command_len++;
        }

        session->scpRecv_command =
            LIBSSH2_ALLOC(session, session->scpRecv_command_len);
        if (!session->scpRecv_command) {
            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                          "Unable to allocate a command buffer for SCP session",
                          0);
            return NULL;
        }
        if (sb) {
            memcpy(session->scpRecv_command, "scp -pf ",
                   sizeof("scp -pf ") - 1);
            memcpy(session->scpRecv_command + sizeof("scp -pf ") - 1, path,
                   path_len);
        } else {
            memcpy(session->scpRecv_command, "scp -f ", sizeof("scp -f ") - 1);
            memcpy(session->scpRecv_command + sizeof("scp -f ") - 1, path,
                   path_len);
        }
        session->scpRecv_command[session->scpRecv_command_len - 1] = '\0';

        _libssh2_debug(session, LIBSSH2_DBG_SCP,
                       "Opening channel for SCP receive");

        session->scpRecv_state = libssh2_NB_state_created;
    }

    if (session->scpRecv_state == libssh2_NB_state_created) {
        /* Allocate a channel */
        do {
            session->scpRecv_channel =
                libssh2_channel_open_ex(session, "session",
                                        sizeof("session") - 1,
                                        LIBSSH2_CHANNEL_WINDOW_DEFAULT,
                                        LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL,
                                        0);
            if (!session->scpRecv_channel) {
                if (libssh2_session_last_errno(session) !=
                    LIBSSH2_ERROR_EAGAIN) {
                    LIBSSH2_FREE(session, session->scpRecv_command);
                    session->scpRecv_command = NULL;
                    session->scpRecv_state = libssh2_NB_state_idle;
                    return NULL;
                } else if (libssh2_session_last_errno(session) ==
                           LIBSSH2_ERROR_EAGAIN) {
                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                  "Would block starting up channel", 0);
                    return NULL;
                }
            }
        } while (!session->scpRecv_channel);

        session->scpRecv_state = libssh2_NB_state_sent;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent) {
        /* Request SCP for the desired file */
        rc = libssh2_channel_process_startup(session->scpRecv_channel, "exec",
                                             sizeof("exec") - 1,
                                             (char *) session->scpRecv_command,
                                             session->scpRecv_command_len);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block requesting SCP startup", 0);
            return NULL;
        } else if (rc) {
            LIBSSH2_FREE(session, session->scpRecv_command);
            session->scpRecv_command = NULL;
            goto scp_recv_error;
        }
        LIBSSH2_FREE(session, session->scpRecv_command);
        session->scpRecv_command = NULL;

        _libssh2_debug(session, LIBSSH2_DBG_SCP, "Sending initial wakeup");
        /* SCP ACK */
        session->scpRecv_response[0] = '\0';

        session->scpRecv_state = libssh2_NB_state_sent1;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent1) {
        rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
                                      (char *) session->scpRecv_response, 1);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block sending initial wakeup", 0);
            return NULL;
        } else if (rc != 1) {
            goto scp_recv_error;
        }

        /* Parse SCP response */
        session->scpRecv_response_len = 0;

        session->scpRecv_state = libssh2_NB_state_sent2;
    }

    if ((session->scpRecv_state == libssh2_NB_state_sent2)
        || (session->scpRecv_state == libssh2_NB_state_sent3)) {
        while (sb
               && (session->scpRecv_response_len <
                   LIBSSH2_SCP_RESPONSE_BUFLEN)) {
            unsigned char *s, *p;

            if (session->scpRecv_state == libssh2_NB_state_sent2) {
                rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
                                             (char *) session->
                                             scpRecv_response +
                                             session->scpRecv_response_len, 1);
                if (rc == PACKET_EAGAIN) {
                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                  "Would block waiting for SCP response", 0);
                    return NULL;
                } else if (rc <= 0) {
                    /* Timeout, give up */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Timed out waiting for SCP response", 0);
                    goto scp_recv_error;
                }
                session->scpRecv_response_len++;

                if (session->scpRecv_response[0] != 'T') {
                    /*
                     * Set this as the default error for here, if
                     * we are successful it will be replaced
                     */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid data in SCP response, missing Time data",
                                  0);

                    session->scpRecv_err_len =
                        libssh2_channel_packet_data_len(session->
                                                        scpRecv_channel, 0);
                    session->scpRecv_err_msg =
                        LIBSSH2_ALLOC(session, session->scpRecv_err_len + 1);
                    if (!session->scpRecv_err_msg) {
                        goto scp_recv_error;
                    }
                    memset(session->scpRecv_err_msg, 0,
                           session->scpRecv_err_len + 1);

                    /* Read the remote error message */
                    rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
                                                 session->scpRecv_err_msg,
                                                 session->scpRecv_err_len);
                    if (rc <= 0) {
                        /*
                         * Since we have alread started reading this packet, it is
                         * already in the systems so it can't return PACKET_EAGAIN
                         */
                        LIBSSH2_FREE(session, session->scpRecv_err_msg);
                        session->scpRecv_err_msg = NULL;
                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                      "Unknown error while getting error string",
                                      0);
                        goto scp_recv_error;
                    }

                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  session->scpRecv_err_msg, 1);
                    session->scpRecv_err_msg = NULL;
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len > 1) &&
                    ((session->
                      scpRecv_response[session->scpRecv_response_len - 1] <
                      '0')
                     || (session->
                         scpRecv_response[session->scpRecv_response_len - 1] >
                         '9'))
                    && (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        ' ')
                    && (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        '\r')
                    && (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        '\n')) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid data in SCP response", 0);
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len < 9)
                    || (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        '\n')) {
                    if (session->scpRecv_response_len ==
                        LIBSSH2_SCP_RESPONSE_BUFLEN) {
                        /* You had your chance */
                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                      "Unterminated response from SCP server",
                                      0);
                        goto scp_recv_error;
                    }
                    /* Way too short to be an SCP response,  or not done yet, short circuit */
                    continue;
                }

                /* We're guaranteed not to go under response_len == 0 by the logic above */
                while ((session->
                        scpRecv_response[session->scpRecv_response_len - 1] ==
                        '\r')
                       || (session->
                           scpRecv_response[session->scpRecv_response_len -
                                            1] == '\n'))
                    session->scpRecv_response_len--;
                session->scpRecv_response[session->scpRecv_response_len] =
                    '\0';

                if (session->scpRecv_response_len < 8) {
                    /* EOL came too soon */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, too short",
                                  0);
                    goto scp_recv_error;
                }

                s = session->scpRecv_response + 1;

                p = (unsigned char *) strchr((char *) s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, malformed mtime",
                                  0);
                    goto scp_recv_error;
                }

                *(p++) = '\0';
                /* Make sure we don't get fooled by leftover values */
                errno = 0;
                session->scpRecv_mtime = strtol((char *) s, NULL, 10);
                if (errno) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, invalid mtime",
                                  0);
                    goto scp_recv_error;
                }
                s = (unsigned char *) strchr((char *) p, ' ');
                if (!s || ((s - p) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, malformed mtime.usec",
                                  0);
                    goto scp_recv_error;
                }

                /* Ignore mtime.usec */
                s++;
                p = (unsigned char *) strchr((char *) s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, too short or malformed",
                                  0);
                    goto scp_recv_error;
                }

                *(p++) = '\0';
                /* Make sure we don't get fooled by leftover values */
                errno = 0;
                session->scpRecv_atime = strtol((char *) s, NULL, 10);
                if (errno) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, invalid atime",
                                  0);
                    goto scp_recv_error;
                }

                /* SCP ACK */
                session->scpRecv_response[0] = '\0';

                session->scpRecv_state = libssh2_NB_state_sent3;
            }

            if (session->scpRecv_state == libssh2_NB_state_sent3) {
                rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
                                              (char *) session->
                                              scpRecv_response, 1);
                if (rc == PACKET_EAGAIN) {
                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                  "Would block waiting to send SCP ACK", 0);
                    return NULL;
                } else if (rc != 1) {
                    goto scp_recv_error;
                }

                _libssh2_debug(session, LIBSSH2_DBG_SCP,
                               "mtime = %ld, atime = %ld",
                               session->scpRecv_mtime, session->scpRecv_atime);

                /* We *should* check that atime.usec is valid, but why let that stop use? */
                break;
            }
        }

        session->scpRecv_state = libssh2_NB_state_sent4;
    }

    if (session->scpRecv_state == libssh2_NB_state_sent4) {
        session->scpRecv_response_len = 0;

        session->scpRecv_state = libssh2_NB_state_sent5;
    }

    if ((session->scpRecv_state == libssh2_NB_state_sent5)
        || (session->scpRecv_state == libssh2_NB_state_sent6)) {
        while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) {
            char *s, *p, *e = NULL;

            if (session->scpRecv_state == libssh2_NB_state_sent5) {
                rc = libssh2_channel_read_ex(session->scpRecv_channel, 0,
                                             (char *) session->
                                             scpRecv_response +
                                             session->scpRecv_response_len, 1);
                if (rc == PACKET_EAGAIN) {
                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                  "Would block waiting for SCP response", 0);
                    return NULL;
                } else if (rc <= 0) {
                    /* Timeout, give up */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Timed out waiting for SCP response", 0);
                    goto scp_recv_error;
                }
                session->scpRecv_response_len++;

                if (session->scpRecv_response[0] != 'C') {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server", 0);
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len > 1) &&
                    (session->
                     scpRecv_response[session->scpRecv_response_len - 1] !=
                     '\r')
                    && (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        '\n')
                    &&
                    ((session->
                      scpRecv_response[session->scpRecv_response_len - 1] < 32)
                     || (session->
                         scpRecv_response[session->scpRecv_response_len - 1] >
                         126))) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid data in SCP response", 0);
                    goto scp_recv_error;
                }

                if ((session->scpRecv_response_len < 7)
                    || (session->
                        scpRecv_response[session->scpRecv_response_len - 1] !=
                        '\n')) {
                    if (session->scpRecv_response_len ==
                        LIBSSH2_SCP_RESPONSE_BUFLEN) {
                        /* You had your chance */
                        libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                      "Unterminated response from SCP server",
                                      0);
                        goto scp_recv_error;
                    }
                    /* Way too short to be an SCP response,  or not done yet, short circuit */
                    continue;
                }

                /* We're guaranteed not to go under response_len == 0 by the logic above */
                while ((session->
                        scpRecv_response[session->scpRecv_response_len - 1] ==
                        '\r')
                       || (session->
                           scpRecv_response[session->scpRecv_response_len -
                                            1] == '\n')) {
                    session->scpRecv_response_len--;
                }
                session->scpRecv_response[session->scpRecv_response_len] =
                    '\0';

                if (session->scpRecv_response_len < 6) {
                    /* EOL came too soon */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, too short",
                                  0);
                    goto scp_recv_error;
                }

                s = (char *) session->scpRecv_response + 1;

                p = strchr(s, ' ');
                if (!p || ((p - s) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, malformed mode",
                                  0);
                    goto scp_recv_error;
                }

                *(p++) = '\0';
                /* Make sure we don't get fooled by leftover values */
                errno = 0;
                session->scpRecv_mode = strtol(s, &e, 8);
                if ((e && *e) || errno) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, invalid mode",
                                  0);
                    goto scp_recv_error;
                }

                s = strchr(p, ' ');
                if (!s || ((s - p) <= 0)) {
                    /* No spaces or space in the wrong spot */
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, too short or malformed",
                                  0);
                    goto scp_recv_error;
                }

                *(s++) = '\0';
                /* Make sure we don't get fooled by leftover values */
                errno = 0;
                session->scpRecv_size = scpsize_strtol(p, &e, 10);
                if ((e && *e) || errno) {
                    libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL,
                                  "Invalid response from SCP server, invalid size",
                                  0);
                    goto scp_recv_error;
                }

                /* SCP ACK */
                session->scpRecv_response[0] = '\0';

                session->scpRecv_state = libssh2_NB_state_sent6;
            }

            if (session->scpRecv_state == libssh2_NB_state_sent6) {
                rc = libssh2_channel_write_ex(session->scpRecv_channel, 0,
                                              (char *) session->
                                              scpRecv_response, 1);
                if (rc == PACKET_EAGAIN) {
                    libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                                  "Would block sending SCP ACK", 0);
                    return NULL;
                } else if (rc != 1) {
                    goto scp_recv_error;
                }
                _libssh2_debug(session, LIBSSH2_DBG_SCP,
                               "mode = 0%lo size = %ld", session->scpRecv_mode,
                               session->scpRecv_size);

                /* We *should* check that basename is valid, but why let that stop us? */
                break;
            }
        }

        session->scpRecv_state = libssh2_NB_state_sent7;
    }

    if (sb) {
        memset(sb, 0, sizeof(struct stat));

        sb->st_mtime = session->scpRecv_mtime;
        sb->st_atime = session->scpRecv_atime;
        sb->st_size = session->scpRecv_size;
        sb->st_mode = session->scpRecv_mode;
    }

    session->scpRecv_state = libssh2_NB_state_idle;
    return session->scpRecv_channel;

  scp_recv_error:
    while (libssh2_channel_free(session->scpRecv_channel) == PACKET_EAGAIN);
    session->scpRecv_channel = NULL;
    session->scpRecv_state = libssh2_NB_state_idle;
    return NULL;
}