diff options
author | Aris Adamantiadis <aris@0xbadc0de.be> | 2005-10-25 23:02:25 +0000 |
---|---|---|
committer | Aris Adamantiadis <aris@0xbadc0de.be> | 2005-10-25 23:02:25 +0000 |
commit | d86f0017545f0076a1136b5c6f8b0a7a58366342 (patch) | |
tree | 6b28fc5766ad23b3c8c9dbb1ffa2bbfae4cbc808 | |
parent | 5f7c84f900b81e3bbff55378f8170ddf150daf9c (diff) | |
download | libssh-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-x | configure | 14 | ||||
-rw-r--r-- | configure.in | 15 | ||||
-rw-r--r-- | include/libssh/libssh.h | 7 | ||||
-rw-r--r-- | libssh/channels.c | 154 | ||||
-rw-r--r-- | sample.c | 60 |
5 files changed, 218 insertions, 32 deletions
@@ -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; +} @@ -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; |