aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libssh/libssh.h7
-rw-r--r--libssh/channels.c349
-rw-r--r--libssh/libssh.map4
-rw-r--r--libssh/sftp.c6
-rw-r--r--sample.c4
-rw-r--r--samplesshd.c2
6 files changed, 247 insertions, 125 deletions
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
index 828655ee..4567e049 100644
--- a/include/libssh/libssh.h
+++ b/include/libssh/libssh.h
@@ -281,11 +281,14 @@ int channel_request_sftp(CHANNEL *channel);
int channel_write(CHANNEL *channel, const void *data, u32 len);
int channel_send_eof(CHANNEL *channel);
int channel_is_eof(CHANNEL *channel);
-int channel_read(CHANNEL *channel, BUFFER *buffer, u32 bytes, int is_stderr);
+int channel_read(CHANNEL *channel, void *dest, u32 count, int is_stderr);
+int channel_read_buffer(CHANNEL *channel, BUFFER *buffer, u32 count,
+ int is_stderr);
int channel_poll(CHANNEL *channel, int is_stderr);
int channel_close(CHANNEL *channel);
void channel_set_blocking(CHANNEL *channel, int blocking);
-int channel_read_nonblocking(CHANNEL *channel, char *dest, u32 len, int is_stderr);
+int channel_read_nonblocking(CHANNEL *channel, void *dest, u32 count,
+ int is_stderr);
int channel_is_open(CHANNEL *channel);
int channel_is_closed(CHANNEL *channel);
int channel_select(CHANNEL **readchans, CHANNEL **writechans, CHANNEL **exceptchans, struct
diff --git a/libssh/channels.c b/libssh/channels.c
index 5949f78d..4fbe3f82 100644
--- a/libssh/channels.c
+++ b/libssh/channels.c
@@ -1335,90 +1335,248 @@ error:
/* TODO : fix the delayed close thing */
/* TODO : fix the blocking behaviours */
-/* reads into a channel and put result into buffer */
-/* returns number of bytes read, 0 if eof or such and -1 in case of error */
-/* if bytes != 0, the exact number of bytes are going to be read */
-/** \brief reads data from a channel
- * \param channel channel
- * \param buffer buffer which will get the data
- * \param bytes number of bytes to be read. If it is bigger
- * than 0, the exact size will be read, else (bytes=0) it will return
- * once anything is available
- * \param is_stderr boolean value to mark reading from the stderr flow.
- * \return number of bytes read\n
- * 0 on end of file\n
- * SSH_ERROR on error
+
+/**
+ * @brief Read data from a channel into a buffer.
+ *
+ * @param channel The channel to read from.
+ *
+ * @param buffer The buffer which will get the data.
+ *
+ * @param count The count of bytes to be read. If it is biggerthan 0,
+ * the exact size will be read, else (bytes=0) it will
+ * return once anything is available.
+ *
+ * @param is_stderr A boolean value to mark reading from the stderr stream.
+ *
+ * @return The number of bytes read, 0 on end of file or SSH_ERROR on error.
*/
-int channel_read(CHANNEL *channel, BUFFER *buffer, u32 bytes, int is_stderr) {
- BUFFER *stdbuf=NULL;
- SSH_SESSION *session=channel->session;
- u32 maxread=bytes;
- u32 len;
+int channel_read_buffer(CHANNEL *channel, BUFFER *buffer, u32 count,
+ int is_stderr) {
+ SSH_SESSION *session=channel->session;
+ BUFFER *stdbuf = channel->stdout_buffer;
+ u32 maxread = count;
+ u32 len;
- buffer_reinit(buffer);
- enter_function();
- if(bytes==0)
- maxread=MAX_PACKET_LEN;
- /* maybe i should always set a buffer to avoid races between channel_default_bufferize and channel_read */
- if(is_stderr)
- stdbuf=channel->stderr_buffer;
- else
- stdbuf=channel->stdout_buffer;
+ buffer_reinit(buffer);
- /* We may have problem if the window is too small to accept as much data as asked */
- ssh_log(session, SSH_LOG_PROTOCOL,
- "Read (%d) buffered : %d bytes. Window: %d",
- bytes,
- buffer_get_rest_len(stdbuf),
- channel->local_window);
- if(bytes > buffer_get_rest_len(stdbuf) + channel->local_window) {
- if (grow_window(session, channel, bytes - buffer_get_rest_len(stdbuf)) < 0) {
- leave_function();
- return -1;
- }
+ enter_function();
+
+ if (count == 0) {
+ maxread = MAX_PACKET_LEN;
+ }
+
+ if (is_stderr) {
+ stdbuf = channel->stderr_buffer;
+ }
+
+ /*
+ * We may have problem if the window is too small to accept as much data
+ * as asked
+ */
+ ssh_log(session, SSH_LOG_PROTOCOL,
+ "Read (%d) buffered: %d bytes. Window: %d",
+ count,
+ buffer_get_rest_len(stdbuf),
+ channel->local_window);
+
+ if (count > buffer_get_rest_len(stdbuf) + channel->local_window) {
+ if (grow_window(session, channel,
+ count - buffer_get_rest_len(stdbuf)) < 0) {
+ leave_function();
+ return -1;
}
- /* block reading if asked bytes=0 */
- while((buffer_get_rest_len(stdbuf)==0) || (buffer_get_rest_len(stdbuf) < bytes)){
- if(channel->remote_eof && buffer_get_rest_len(stdbuf)==0){
- leave_function();
- return 0;
- }
- if(channel->remote_eof)
- break; /* return the resting bytes in buffer */
- if(buffer_get_rest_len(stdbuf)>=maxread) // stop reading when buffer is full enough
- break;
- if ((packet_read(session)) != SSH_OK ||
- (packet_translate(session) != SSH_OK)) {
- leave_function();
- return -1;
- }
- packet_parse(session);
+ }
+ /* block reading if asked bytes=0 */
+ while (buffer_get_rest_len(stdbuf) == 0 ||
+ buffer_get_rest_len(stdbuf) < count) {
+ if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) {
+ leave_function();
+ return 0;
}
- if(channel->local_window < WINDOWLIMIT) {
- if (grow_window(session, channel, 0) < 0) {
- leave_function();
- return -1;
- }
+ if (channel->remote_eof) {
+ /* Return the resting bytes in buffer */
+ break;
}
- if(bytes==0){
- /* write the ful buffer informations */
- if (buffer_add_data(buffer, buffer_get_rest(stdbuf),
- buffer_get_rest_len(stdbuf)) < 0) {
- leave_function();
- return -1;
- }
- buffer_reinit(stdbuf);
- } else {
- len=buffer_get_rest_len(stdbuf);
- len= (len>bytes?bytes:len); /* read bytes bytes if len is greater, everything otherwise */
- if (buffer_add_data(buffer, buffer_get_rest(stdbuf), len) < 0) {
- leave_function();
- return -1;
- }
- buffer_pass_bytes(stdbuf,len);
+ if (buffer_get_rest_len(stdbuf) >= maxread) {
+ /* Stop reading when buffer is full enough */
+ break;
+ }
+
+ if ((packet_read(session)) != SSH_OK ||
+ (packet_translate(session) != SSH_OK)) {
+ leave_function();
+ return -1;
+ }
+ packet_parse(session);
+ }
+
+ if(channel->local_window < WINDOWLIMIT) {
+ if (grow_window(session, channel, 0) < 0) {
+ leave_function();
+ return -1;
+ }
+ }
+
+ if (count == 0) {
+ /* write the ful buffer informations */
+ if (buffer_add_data(buffer, buffer_get_rest(stdbuf),
+ buffer_get_rest_len(stdbuf)) < 0) {
+ leave_function();
+ return -1;
+ }
+ buffer_reinit(stdbuf);
+ } else {
+ /* Read bytes bytes if len is greater, everything otherwise */
+ len = buffer_get_rest_len(stdbuf);
+ len = (len > count ? count : len);
+ if (buffer_add_data(buffer, buffer_get_rest(stdbuf), len) < 0) {
+ leave_function();
+ return -1;
+ }
+ buffer_pass_bytes(stdbuf,len);
+ }
+
+ leave_function();
+ return buffer_get_len(buffer);
+}
+
+/* TODO FIXME Fix the delayed close thing */
+/* TODO FIXME Fix the blocking behaviours */
+
+/**
+ * @brief Reads data from a channel.
+ *
+ * @param channel The channel to read from.
+ *
+ * @param dest The destination buffer which will get the data.
+ *
+ * @param count The count of bytes to be read.
+ *
+ * @param is_stderr A boolean value to mark reading from the stderr flow.
+ *
+ * @return The number of bytes read, 0 on end of file or SSH_ERROR on error.
+ */
+int channel_read(CHANNEL *channel, void *dest, u32 count, int is_stderr) {
+ SSH_SESSION *session = channel->session;
+ BUFFER *stdbuf = channel->stdout_buffer;
+ u32 len;
+
+ enter_function();
+
+ if (count == 0) {
+ leave_function();
+ return 0;
+ }
+
+ if (is_stderr) {
+ stdbuf=channel->stderr_buffer;
+ }
+
+ /*
+ * We may have problem if the window is too small to accept as much data
+ * as asked
+ */
+ ssh_log(session, SSH_LOG_PROTOCOL,
+ "Read (%d) buffered : %d bytes. Window: %d",
+ count,
+ buffer_get_rest_len(stdbuf),
+ channel->local_window);
+
+ if (count > buffer_get_rest_len(stdbuf) + channel->local_window) {
+ if (grow_window(session, channel,
+ count - buffer_get_rest_len(stdbuf)) < 0) {
+ leave_function();
+ return -1;
+ }
+ }
+
+ /* block reading if asked bytes=0 */
+ while (buffer_get_rest_len(stdbuf) == 0 ||
+ buffer_get_rest_len(stdbuf) < count) {
+ if (channel->remote_eof && buffer_get_rest_len(stdbuf) == 0) {
+ leave_function();
+ return 0;
+ }
+
+ if (channel->remote_eof) {
+ /* Return the resting bytes in buffer */
+ break;
+ }
+
+ if (buffer_get_rest_len(stdbuf) >= count) {
+ /* Stop reading when buffer is full enough */
+ break;
+ }
+
+ if ((packet_read(session)) != SSH_OK ||
+ (packet_translate(session) != SSH_OK)) {
+ leave_function();
+ return -1;
+ }
+ packet_parse(session);
+ }
+
+ if (channel->local_window < WINDOWLIMIT) {
+ if (grow_window(session, channel, 0) < 0) {
+ leave_function();
+ return -1;
}
+ }
+
+ len = buffer_get_rest_len(stdbuf);
+ /* Read count bytes if len is greater, everything otherwise */
+ len = (len > count ? count : len);
+ memcpy(dest, buffer_get_rest(stdbuf), len);
+ buffer_pass_bytes(stdbuf,len);
+
+ leave_function();
+ return len;
+}
+
+/**
+ * @brief Do a nonblocking read on the channel.
+ *
+ * A nonblocking read on the specified channel. it will return <= count bytes of
+ * data read atomicly.
+ *
+ * @param channel The channel to read from.
+ *
+ * @param dest A pointer to a destination buffer.
+ *
+ * @param count The count of bytes of data to be read.
+ *
+ * @param is_stderr A boolean to select the stderr stream.
+ *
+ * @return The number of bytes read, 0 if nothing is available or
+ * SSH_ERROR on error.
+ *
+ * @warning Don't forget to check for EOF as it would return 0 here.
+ *
+ * @see channel_is_eof()
+ */
+int channel_read_nonblocking(CHANNEL *channel, void *dest, u32 count,
+ int is_stderr) {
+ SSH_SESSION *session = channel->session;
+ u32 to_read;
+ int rc;
+
+ enter_function();
+
+ to_read = channel_poll(channel, is_stderr);
+
+ if (to_read <= 0) {
leave_function();
- return buffer_get_len(buffer);
+ return to_read; /* may be an error code */
+ }
+
+ if (to_read > count) {
+ to_read = count;
+ }
+ rc = channel_read(channel, dest, to_read, is_stderr);
+
+ leave_function();
+ return rc;
}
/** \brief polls the channel for data to read
@@ -1453,45 +1611,6 @@ int channel_poll(CHANNEL *channel, int is_stderr){
return buffer_get_rest_len(buffer);
}
-/* nonblocking read on the specified channel. it will return <=len bytes of data read
- atomicly. */
-/** This read will make a nonblocking read (unlike channel_read()) and won't force you
- * to deal with BUFFER's
- * \brief nonblocking read
- * \param channel channel
- * \param dest pointer to destination for data
- * \param len maximum length of data to be read
- * \param is_stderr boolean to select the stderr stream
- * \return number of bytes read\n
- * 0 if nothing is available\n
- * SSH_ERROR on error
- * \warning don't forget to check for EOF as it would
- * return 0 here
- * \see channel_is_eof()
- */
-int channel_read_nonblocking(CHANNEL *channel, char *dest, u32 len, int is_stderr){
- SSH_SESSION *session = channel->session;
- BUFFER *buffer;
- int lu;
- u32 to_read;
-
- enter_function();
- to_read=channel_poll(channel,is_stderr);
- buffer=buffer_new();
- if(to_read<=0){
- buffer_free(buffer);
- leave_function();
- return to_read; /* may be an error code */
- }
- if(to_read>len)
- to_read=len;
- lu=channel_read(channel,buffer,to_read,is_stderr);
- memcpy(dest,buffer_get(buffer),lu>=0?lu:0);
- buffer_free(buffer);
- leave_function();
- return lu;
-}
-
/** \brief recover the session in which belong a channel
* \param channel channel
* \return the session pointer
diff --git a/libssh/libssh.map b/libssh/libssh.map
index c28d2e10..c8652129 100644
--- a/libssh/libssh.map
+++ b/libssh/libssh.map
@@ -18,8 +18,8 @@ SSH_0.3 {
channel_request_pty; channel_request_pty_size; channel_change_pty_size;
channel_request_shell; channel_request_subsystem; channel_request_env;
channel_request_exec; channel_request_sftp; channel_write;
- channel_send_eof; channel_read; channel_poll; channel_close;
- channel_read_nonblocking; channel_is_open;
+ channel_send_eof; channel_read_buffer; channel_read; channel_read_nonblocking;
+ channel_poll; channel_close; channel_is_open;
channel_is_closed; channel_is_eof; channel_select;
ssh_options_new; ssh_options_copy; ssh_options_free; ssh_options_set_wanted_algos;
ssh_options_set_username; ssh_options_set_port; ssh_options_getopt;
diff --git a/libssh/sftp.c b/libssh/sftp.c
index 55dd93fc..24666c8a 100644
--- a/libssh/sftp.c
+++ b/libssh/sftp.c
@@ -237,7 +237,7 @@ SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp) {
return NULL;
}
- if (channel_read(sftp->channel, packet->payload, 4, 0) <= 0) {
+ if (channel_read_buffer(sftp->channel, packet->payload, 4, 0) <= 0) {
buffer_free(packet->payload);
SAFE_FREE(packet);
sftp_leave_function();
@@ -252,7 +252,7 @@ SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp) {
}
size = ntohl(size);
- if (channel_read(sftp->channel, packet->payload, 1, 0) <= 0) {
+ if (channel_read_buffer(sftp->channel, packet->payload, 1, 0) <= 0) {
buffer_free(packet->payload);
SAFE_FREE(packet);
sftp_leave_function();
@@ -261,7 +261,7 @@ SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp) {
buffer_get_u8(packet->payload, &packet->type);
if (size > 1) {
- if (channel_read(sftp->channel, packet->payload, size - 1, 0) <= 0) {
+ if (channel_read_buffer(sftp->channel, packet->payload, size - 1, 0) <= 0) {
buffer_free(packet->payload);
SAFE_FREE(packet);
sftp_leave_function();
diff --git a/sample.c b/sample.c
index 13f4e921..67d17657 100644
--- a/sample.c
+++ b/sample.c
@@ -188,7 +188,7 @@ static void select_loop(SSH_SESSION *session,CHANNEL *channel){
}
if(channels[0]){
while(channel && channel_is_open(channel) && channel_poll(channel,0)){
- lus=channel_read(channel,readbuf,0,0);
+ lus=channel_read_buffer(channel,readbuf,0,0);
if(lus==-1){
fprintf(stderr, "Error reading channel: %s\n",
ssh_get_error(session));
@@ -204,7 +204,7 @@ static void select_loop(SSH_SESSION *session,CHANNEL *channel){
write(1,buffer_get(readbuf),lus);
}
while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */
- lus=channel_read(channel,readbuf,0,1);
+ lus=channel_read_buffer(channel,readbuf,0,1);
if(lus==-1){
fprintf(stderr, "Error reading channel: %s\n",
ssh_get_error(session));
diff --git a/samplesshd.c b/samplesshd.c
index ee16725c..edd2d172 100644
--- a/samplesshd.c
+++ b/samplesshd.c
@@ -145,7 +145,7 @@ int main(int argc, char **argv){
printf("it works !\n");
buf=buffer_new();
do{
- i=channel_read(chan,buf,0,0);
+ i=channel_read_buffer(chan,buf,0,0);
if(i>0)
write(1,buffer_get(buf),buffer_get_len(buf));
} while (i>0);