aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2005-10-25 23:02:25 +0000
committerAris Adamantiadis <aris@0xbadc0de.be>2005-10-25 23:02:25 +0000
commitd86f0017545f0076a1136b5c6f8b0a7a58366342 (patch)
tree6b28fc5766ad23b3c8c9dbb1ffa2bbfae4cbc808
parent5f7c84f900b81e3bbff55378f8170ddf150daf9c (diff)
downloadlibssh-d86f0017545f0076a1136b5c6f8b0a7a58366342.tar.gz
libssh-d86f0017545f0076a1136b5c6f8b0a7a58366342.tar.xz
libssh-d86f0017545f0076a1136b5c6f8b0a7a58366342.zip
channel_select(). this function rocks !
I adapted the sample.c file. the select_loop function is bloated and fails to demonstrate how libssh is simple to handle... it looks to run at first try. git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@39 7dcaeef0-15fb-0310-b436-a5af3365683c
-rwxr-xr-xconfigure14
-rw-r--r--configure.in15
-rw-r--r--include/libssh/libssh.h7
-rw-r--r--libssh/channels.c154
-rw-r--r--sample.c60
5 files changed, 218 insertions, 32 deletions
diff --git a/configure b/configure
index cf03f7a8..27aa18bc 100755
--- a/configure
+++ b/configure
@@ -3852,6 +3852,20 @@ fi
done
+#Warn user when no openssl available
+#FIXME ! how to make it work with gcrypt ?
+if test x"$ac_cv_header_openssl_aes_h" != x"yes" ||
+x"$ac_cv_header_openssl_blowfish_h" != x"yes"; then
+ echo "Can't find valid openssl files e.g openssl/aes.h"
+ echo "Please install Openssl-devel"
+ exit
+fi
+
+if ! test x"$ac_cv_header_zlib_h" = x"yes"; then
+ echo "Can't find zlib.h"
+ echo "Compression support won't be compiled in"
+fi
+
# Checks for typedefs, structures, and compiler characteristics.
echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
diff --git a/configure.in b/configure.in
index 2f7a7db0..af9729dd 100644
--- a/configure.in
+++ b/configure.in
@@ -54,6 +54,21 @@ sys/time.h termios.h unistd.h openssl/aes.h openssl/blowfish.h \
openssl/des.h zlib.h sys/poll.h stdint.h pty.h pam/pam_appl.h \
security/pam_appl.h gcrypt.h])
+#Warn user when no openssl available
+#FIXME ! how to make it work with gcrypt ?
+#I can't make it work. help would be appreciated
+#if test x"$ac_cv_header_openssl_aes_h" != x"yes" ||
+#x"$ac_cv_header_openssl_blowfish_h" != x"yes"; then
+# echo "Can't find valid openssl files [e.g openssl/aes.h]"
+# echo "Please install Openssl-devel"
+# exit
+#fi
+
+#if ! test x"$ac_cv_header_zlib_h" != x"yes"; then
+# echo "Can't find zlib.h"
+# echo "Compression support won't be compiled in"
+#fi
+
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_HEADER_TIME
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
index f49b3f5c..5f8765fe 100644
--- a/include/libssh/libssh.h
+++ b/include/libssh/libssh.h
@@ -110,6 +110,10 @@ SSH_SESSION *ssh_new();
void ssh_set_options(SSH_SESSION *session, SSH_OPTIONS *options);
int ssh_get_fd(SSH_SESSION *session);
void ssh_silent_disconnect(SSH_SESSION *session);
+void ssh_set_fd_toread(SSH_SESSION *session);
+void ssh_set_fd_towrite(SSH_SESSION *session);
+void ssh_set_fd_except(SSH_SESSION *session);
+
/* client.c */
int ssh_connect(SSH_SESSION *session);
@@ -185,6 +189,9 @@ int channel_poll(CHANNEL *channel, int is_stderr);
int channel_close(CHANNEL *channel);
int channel_read_nonblocking(CHANNEL *channel, char *dest, int len, 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
+ timeval * timeout);
/* in options.c */
SSH_OPTIONS *ssh_options_new();
diff --git a/libssh/channels.c b/libssh/channels.c
index 8a0b1fa1..a89d0034 100644
--- a/libssh/channels.c
+++ b/libssh/channels.c
@@ -477,6 +477,10 @@ int channel_is_open(CHANNEL *channel){
return (channel->open!=0);
}
+int channel_is_closed(CHANNEL *channel){
+ return (channel->open==0);
+}
+
int channel_is_eof(CHANNEL *channel){
if((channel->stdout_buffer && buffer_get_rest_len(channel->stdout_buffer)
>0) || (channel->stderr_buffer && buffer_get_rest_len(
@@ -702,18 +706,146 @@ int channel_read_nonblocking(CHANNEL *channel, char *dest, int len, int is_stder
SSH_SESSION *channel_get_session(CHANNEL *channel){
return channel->session;
}
-/*
-int channel_select(CHANNEL *readchans, CHANNEL *writechans, CHANNEL *exceptchans, struct
+
+/* This function acts as a meta select. */
+/* first, channels are analyzed to seek potential can-write or can-read ones. */
+/* Then, if no channel has been elected, it goes in a loop with the posix select(2) */
+/* this is made in two parts : Protocol select and Network select */
+
+/* the protocol select does not use the network functions at all */
+
+static int channel_protocol_select(CHANNEL **rchans, CHANNEL **wchans, CHANNEL **echans,
+ CHANNEL **rout, CHANNEL **wout, CHANNEL **eout){
+ CHANNEL *chan;
+ int i,j;
+ j=0;
+ for(i=0;rchans[i];++i){
+ chan=rchans[i];
+ while(chan->open && chan->session->data_to_read){
+ channel_poll(chan,0);
+ }
+ if( (chan->stdout_buffer && buffer_get_len(chan->stdout_buffer)>0) ||
+ (chan->stderr_buffer && buffer_get_len(chan->stderr_buffer)>0)){
+ rout[j]=chan;
+ ++j;
+ }
+ }
+ rout[j]=NULL;
+ j=0;
+ for(i=0;wchans[i];++i){
+ chan=wchans[i];
+ /* it's not our business to seek if the file descriptor is writable */
+ if(chan->session->data_to_write && chan->open && (chan->remote_window>0)){
+ wout[j]=chan;
+ ++j;
+ }
+ }
+ wout[j]=NULL;
+ j=0;
+ for(i=0;echans[i];++i){
+ chan=echans[i];
+ if(chan->session->fd==-1 || !chan->open || chan->remote_eof || chan->session->data_except){
+ eout[j]=chan;
+ ++j;
+ }
+ }
+ wout[j]=NULL;
+ return 0;
+}
+
+/* just count number of pointers in the array */
+static int count_ptrs(CHANNEL **ptrs){
+ int c;
+ for(c=0;ptrs[c];++c)
+ ;
+ return c;
+}
+
+int channel_select(CHANNEL **readchans, CHANNEL **writechans, CHANNEL **exceptchans, struct
timeval * timeout){
fd_set rset;
fd_set wset;
fd_set eset;
- int rmax=-1, wmax=-1, emax=-1; // nothing to do with the low quality editor :)
- int i;
- FD_ZERO(rset);
- FD_ZERO(wset);
- FD_ZERO(eset);
- for(i=0;readchans[i];++i){
- if(!readchans[i].
-
-*/ \ No newline at end of file
+ CHANNEL *dummy=NULL;
+ CHANNEL **rchans, **wchans, **echans;
+ int fdmax=-1;
+ int i,fd;
+ /* don't allow NULL pointers */
+ if(!readchans)
+ readchans=&dummy;
+ if(!writechans)
+ writechans=&dummy;
+ if(!exceptchans)
+ exceptchans=&dummy;
+ if(!readchans[0] && !writechans[0] && !exceptchans[0]){
+ /* no channel to poll ?? go away ! */
+ return 0;
+ }
+ /* prepare the outgoing temporary arrays */
+ rchans=malloc(sizeof(CHANNEL *) * (count_ptrs(readchans)+1));
+ wchans=malloc(sizeof(CHANNEL *) * (count_ptrs(writechans)+1));
+ echans=malloc(sizeof(CHANNEL *) * (count_ptrs(exceptchans)+1));
+
+ /* first, try without doing network stuff */
+ /* then, select and redo the networkless stuff */
+ do {
+ channel_protocol_select(readchans,writechans,exceptchans,rchans,wchans,echans);
+ if(rchans[0]||wchans[0]||echans[0]){
+ /* we've got one without doing any select */
+ /* overwrite the begining arrays */
+ memcpy(readchans,rchans, (count_ptrs(rchans)+1)*sizeof(CHANNEL *));
+ memcpy(writechans,wchans, (count_ptrs(wchans)+1)*sizeof(CHANNEL *));
+ memcpy(exceptchans,echans, (count_ptrs(echans)+1)*sizeof(CHANNEL *));
+ free(rchans);
+ free(wchans);
+ free(echans);
+ return 0;
+ }
+ ssh_say(3,"doing a select for the different channels\n");
+ /* since we verified the invalid fd cases into the networkless select,
+ we can be sure all fd are valid ones */
+ FD_ZERO(&rset);
+ FD_ZERO(&wset);
+ FD_ZERO(&eset);
+ for(i=0;readchans[i];++i){
+ fd=readchans[i]->session->fd;
+ if(!FD_ISSET(fd,&rset)){
+ FD_SET(fd,&rset);
+ if(fd>=fdmax)
+ fdmax=fd+1;
+ }
+ }
+ for(i=0;writechans[i];++i){
+ fd=writechans[i]->session->fd;
+ if(!FD_ISSET(fd,&wset)){
+ FD_SET(fd,&wset);
+ if(fd>=fdmax)
+ fdmax=fd+1;
+ }
+ }
+ for(i=0;exceptchans[i];++i){
+ fd=exceptchans[i]->session->fd;
+ if(!FD_ISSET(fd,&eset)){
+ FD_SET(fd,&eset);
+ if(fd>=fdmax)
+ fdmax=fd+1;
+ }
+ }
+ /* here we go */
+ select(fdmax,&rset,&wset,&eset,timeout);
+ for(i=0;readchans[i];++i){
+ if(FD_ISSET(readchans[i]->session->fd,&rset))
+ readchans[i]->session->data_to_read=1;
+ }
+ for(i=0;writechans[i];++i){
+ if(FD_ISSET(writechans[i]->session->fd,&wset))
+ writechans[i]->session->data_to_write=1;
+ }
+ for(i=0;exceptchans[i];++i){
+ if(FD_ISSET(exceptchans[i]->session->fd,&eset))
+ exceptchans[i]->session->data_except=1;
+ }
+ } while(1); /* return to do loop */
+ /* not reached */
+ return 0;
+}
diff --git a/sample.c b/sample.c
index d25ecf58..bf77f8d2 100644
--- a/sample.c
+++ b/sample.c
@@ -122,10 +122,10 @@ void select_loop(SSH_SESSION *session,CHANNEL *channel){
struct timeval timeout;
char buffer[10];
BUFFER *readbuf=buffer_new();
- CHANNEL *channels[]={channel,NULL};
- CHANNEL *outchannel[2];
+ CHANNEL *channels[2];
int lus;
int eof=0;
+ int maxfd;
int ret;
while(channel){
/* when a signal is caught, ssh_select will return
@@ -141,23 +141,40 @@ void select_loop(SSH_SESSION *session,CHANNEL *channel){
FD_SET(0,&fds);
timeout.tv_sec=30;
timeout.tv_usec=0;
- ret=ssh_select(channels,outchannel,0+1,&fds,&timeout);
- if(signal_delayed)
- sizechanged();
- } while (ret==SSH_EINTR);
- if(FD_ISSET(0,&fds)){
- lus=read(0,buffer,10);
- if(lus){
- channel_write(channel,buffer,lus);
+ FD_SET(ssh_get_fd(session),&fds);
+ maxfd=ssh_get_fd(session)+1;
+ ret=select(maxfd,&fds,NULL,NULL,&timeout);
+ if(ret==EINTR)
+ continue;
+ if(FD_ISSET(0,&fds)){
+ lus=read(0,buffer,10);
+ if(lus)
+ channel_write(channel,buffer,lus);
+ else {
+ eof=1;
+ channel_send_eof(channel);
+ }
}
- else{
- eof=1;
- channel_send_eof(channel);
+ if(FD_ISSET(ssh_get_fd(session),&fds)){
+ ssh_set_fd_toread(session);
}
+ channels[0]=channel; // set the first channel we want to read from
+ channels[1]=NULL;
+ ret=channel_select(channels,NULL,NULL,NULL); // no specific timeout - just poll
+ if(signal_delayed)
+ sizechanged();
+ } while (ret==EINTR || ret==SSH_EINTR);
+
+ // we already looked for input from stdin. Now, we are looking for input from the channel
+
+ if(channel && channel_is_closed(channel)){
+ channel_free(channel);
+ channel=NULL;
+ channels[0]=NULL;
}
- if(outchannel[0]){
- while(channel && channel_poll(outchannel[0],0)){
- lus=channel_read(outchannel[0],readbuf,0,0);
+ if(channels[0]){
+ while(channel && channel_is_open(channel) && channel_poll(channel,0)){
+ lus=channel_read(channel,readbuf,0,0);
if(lus==-1){
ssh_say(0,"error reading channel : %s\n",ssh_get_error(session));
return;
@@ -165,12 +182,12 @@ void select_loop(SSH_SESSION *session,CHANNEL *channel){
if(lus==0){
ssh_say(1,"EOF received\n");
channel_free(channel);
- channel=NULL;
+ channel=channels[0]=NULL;
} else
write(1,buffer_get(readbuf),lus);
}
- while(channel && channel_poll(outchannel[0],1)){ /* stderr */
- lus=channel_read(outchannel[0],readbuf,0,1);
+ while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */
+ lus=channel_read(channel,readbuf,0,1);
if(lus==-1){
ssh_say(0,"error reading channel : %s\n",ssh_get_error(session));
return;
@@ -178,12 +195,12 @@ void select_loop(SSH_SESSION *session,CHANNEL *channel){
if(lus==0){
ssh_say(1,"EOF received\n");
channel_free(channel);
- channel=NULL;
+ channel=channels[0]=NULL;
} else
write(2,buffer_get(readbuf),lus);
}
}
- if(channel && !channel_is_open(channel)){
+ if(channel && channel_is_closed(channel)){
channel_free(channel);
channel=NULL;
}
@@ -191,6 +208,7 @@ void select_loop(SSH_SESSION *session,CHANNEL *channel){
buffer_free(readbuf);
}
+
void shell(SSH_SESSION *session){
CHANNEL *channel;
struct termios terminal_local;