aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormilo <milo@r0ot.me>2012-05-02 19:02:47 +0200
committermilo <milo@r0ot.me>2012-05-05 18:04:13 +0200
commit99f14ec89092d315fbe9909fd0c91a979231fc5e (patch)
tree797e787c26917ea5c81d3ed29304560b2de2a713
parent386b0d087dd3e1056de0a86e242a97b51e2080e3 (diff)
downloadlibssh-99f14ec89092d315fbe9909fd0c91a979231fc5e.tar.gz
libssh-99f14ec89092d315fbe9909fd0c91a979231fc5e.tar.xz
libssh-99f14ec89092d315fbe9909fd0c91a979231fc5e.zip
Manage channel data sequentially, send EOF at the end
-rw-r--r--src/channels.c19
-rw-r--r--src/poll.c76
2 files changed, 91 insertions, 4 deletions
diff --git a/src/channels.c b/src/channels.c
index bc4d9bb..be12d0b 100644
--- a/src/channels.c
+++ b/src/channels.c
@@ -487,10 +487,13 @@ SSH_PACKET_CALLBACK(channel_rcv_change_window) {
SSH_PACKET_CALLBACK(channel_rcv_data){
ssh_channel channel;
ssh_string str;
- ssh_buffer buf;
size_t len;
int is_stderr;
+#ifdef WITH_SERVER
+#else
+ ssh_buffer buf;
int rest;
+#endif
(void)user;
enter_function();
if(type==SSH2_MSG_CHANNEL_DATA)
@@ -555,6 +558,8 @@ SSH_PACKET_CALLBACK(channel_rcv_data){
ssh_string_free(str);
+#ifdef WITH_SERVER
+#else
if(ssh_callbacks_exists(channel->callbacks, channel_data_function)) {
if(is_stderr) {
buf = channel->stderr_buffer;
@@ -571,12 +576,13 @@ SSH_PACKET_CALLBACK(channel_rcv_data){
buffer_pass_bytes(buf, rest);
channel->local_window_buffer -= rest;
}
+ }
+#endif
if (channel->local_window + channel->local_window_buffer < WINDOWLIMIT) {
if (grow_window(session, channel, 0) < 0) {
leave_function();
return -1;
}
- }
}
leave_function();
@@ -603,10 +609,13 @@ SSH_PACKET_CALLBACK(channel_rcv_eof) {
/* channel->remote_window = 0; */
channel->remote_eof = 1;
- if(ssh_callbacks_exists(channel->callbacks, channel_eof_function)) {
- channel->callbacks->channel_eof_function(channel->session,
+ if(ssh_channel_is_eof(channel)) {
+ if(ssh_callbacks_exists(channel->callbacks, channel_eof_function)) {
+ channel->callbacks->channel_eof_function(channel->session,
channel,
channel->callbacks->userdata);
+ channel->remote_eof = 2; /* EOF callback has been called */
+ }
}
leave_function();
@@ -649,11 +658,13 @@ SSH_PACKET_CALLBACK(channel_rcv_close) {
* buffer because the eof is ignored until the buffer is empty.
*/
+ if(ssh_channel_is_eof(channel)) {
if(ssh_callbacks_exists(channel->callbacks, channel_close_function)) {
channel->callbacks->channel_close_function(channel->session,
channel,
channel->callbacks->userdata);
}
+ }
channel->flags &= SSH_CHANNEL_FLAG_CLOSED_REMOTE;
if(channel->flags & SSH_CHANNEL_FLAG_FREED_LOCAL)
ssh_channel_do_free(channel);
diff --git a/src/poll.c b/src/poll.c
index 8dfeb14..b945ff1 100644
--- a/src/poll.c
+++ b/src/poll.c
@@ -38,6 +38,7 @@
#ifdef WITH_SERVER
#include "libssh/server.h"
#include "libssh/misc.h"
+#include "libssh/buffer.h"
#endif
@@ -807,11 +808,86 @@ int ssh_event_add_session(ssh_event event, ssh_session session) {
*/
int ssh_event_dopoll(ssh_event event, int timeout) {
int rc;
+#ifdef WITH_SERVER
+ ssh_session session;
+ struct ssh_iterator *iterator;
+ struct ssh_iterator *channels;
+ ssh_channel channel;
+ int rest;
+ static uint64_t count = 0;
+#endif
+ count++;
if(event == NULL || event->ctx == NULL) {
return SSH_ERROR;
}
rc = ssh_poll_ctx_dopoll(event->ctx, timeout);
+#ifdef WITH_SERVER
+ if(rc < 0 && rc != SSH_AGAIN) {
+ return rc;
+ }
+ iterator = ssh_list_get_iterator(event->sessions);
+ while(iterator != NULL) {
+ session = (ssh_session)iterator->data;
+ if(session->channels == NULL) {
+ iterator = iterator->next;
+ continue;
+ }
+ channels = ssh_list_get_iterator(session->channels);
+ while(channels != NULL) {
+ channel = (ssh_channel)channels->data;
+ if(channel->local_window_buffer > 0) {
+ if ((channel->stderr_buffer &&
+ buffer_get_rest_len(channel->stderr_buffer) > 0)) {
+ rest = channel->callbacks->channel_data_function(
+ channel->session,
+ channel,
+ buffer_get_rest(channel->stderr_buffer),
+ buffer_get_rest_len(channel->stderr_buffer),
+ 1,
+ channel->callbacks->userdata);
+ if(rest > 0) {
+ buffer_pass_bytes(channel->stderr_buffer, rest);
+ channel->local_window_buffer -= rest;
+ }
+ }
+ if ((channel->stdout_buffer &&
+ buffer_get_rest_len(channel->stdout_buffer) > 0)) {
+ rest = channel->callbacks->channel_data_function(
+ channel->session,
+ channel,
+ buffer_get_rest(channel->stdout_buffer),
+ buffer_get_rest_len(channel->stdout_buffer),
+ 0,
+ channel->callbacks->userdata);
+ if(rest > 0) {
+ buffer_pass_bytes(channel->stdout_buffer, rest);
+ channel->local_window_buffer -= rest;
+ }
+ }
+ }
+ if(ssh_channel_is_eof(channel)) {
+ if(channel->remote_eof != 2 &&
+ ssh_callbacks_exists(channel->callbacks,
+ channel_eof_function)) {
+ channel->callbacks->channel_eof_function(channel->session,
+ channel,
+ channel->callbacks->userdata);
+ channel->remote_eof = 2; /* EOF callback has been called */
+ }
+ if(ssh_callbacks_exists(channel->callbacks,
+ channel_close_function)) {
+ channel->callbacks->channel_close_function(channel->session,
+ channel,
+ channel->callbacks->userdata);
+ }
+ }
+ channels = channels->next;
+ }
+ iterator = iterator->next;
+ }
+#endif
+
return rc;
}