mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-09 09:54:25 +09:00
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
This commit is contained in:
14
configure
vendored
14
configure
vendored
@@ -3852,6 +3852,20 @@ fi
|
|||||||
done
|
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.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5
|
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
|
echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6
|
||||||
|
|||||||
15
configure.in
15
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 \
|
openssl/des.h zlib.h sys/poll.h stdint.h pty.h pam/pam_appl.h \
|
||||||
security/pam_appl.h gcrypt.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.
|
# Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_C_CONST
|
AC_C_CONST
|
||||||
AC_HEADER_TIME
|
AC_HEADER_TIME
|
||||||
|
|||||||
@@ -110,6 +110,10 @@ SSH_SESSION *ssh_new();
|
|||||||
void ssh_set_options(SSH_SESSION *session, SSH_OPTIONS *options);
|
void ssh_set_options(SSH_SESSION *session, SSH_OPTIONS *options);
|
||||||
int ssh_get_fd(SSH_SESSION *session);
|
int ssh_get_fd(SSH_SESSION *session);
|
||||||
void ssh_silent_disconnect(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 */
|
/* client.c */
|
||||||
int ssh_connect(SSH_SESSION *session);
|
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_close(CHANNEL *channel);
|
||||||
int channel_read_nonblocking(CHANNEL *channel, char *dest, int len, int is_stderr);
|
int channel_read_nonblocking(CHANNEL *channel, char *dest, int len, int is_stderr);
|
||||||
int channel_is_open(CHANNEL *channel);
|
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 */
|
/* in options.c */
|
||||||
|
|
||||||
SSH_OPTIONS *ssh_options_new();
|
SSH_OPTIONS *ssh_options_new();
|
||||||
|
|||||||
@@ -477,6 +477,10 @@ int channel_is_open(CHANNEL *channel){
|
|||||||
return (channel->open!=0);
|
return (channel->open!=0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int channel_is_closed(CHANNEL *channel){
|
||||||
|
return (channel->open==0);
|
||||||
|
}
|
||||||
|
|
||||||
int channel_is_eof(CHANNEL *channel){
|
int channel_is_eof(CHANNEL *channel){
|
||||||
if((channel->stdout_buffer && buffer_get_rest_len(channel->stdout_buffer)
|
if((channel->stdout_buffer && buffer_get_rest_len(channel->stdout_buffer)
|
||||||
>0) || (channel->stderr_buffer && buffer_get_rest_len(
|
>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){
|
SSH_SESSION *channel_get_session(CHANNEL *channel){
|
||||||
return channel->session;
|
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){
|
timeval * timeout){
|
||||||
fd_set rset;
|
fd_set rset;
|
||||||
fd_set wset;
|
fd_set wset;
|
||||||
fd_set eset;
|
fd_set eset;
|
||||||
int rmax=-1, wmax=-1, emax=-1; // nothing to do with the low quality editor :)
|
CHANNEL *dummy=NULL;
|
||||||
int i;
|
CHANNEL **rchans, **wchans, **echans;
|
||||||
FD_ZERO(rset);
|
int fdmax=-1;
|
||||||
FD_ZERO(wset);
|
int i,fd;
|
||||||
FD_ZERO(eset);
|
/* don't allow NULL pointers */
|
||||||
for(i=0;readchans[i];++i){
|
if(!readchans)
|
||||||
if(!readchans[i].
|
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;
|
||||||
|
}
|
||||||
|
|||||||
62
sample.c
62
sample.c
@@ -122,10 +122,10 @@ void select_loop(SSH_SESSION *session,CHANNEL *channel){
|
|||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
char buffer[10];
|
char buffer[10];
|
||||||
BUFFER *readbuf=buffer_new();
|
BUFFER *readbuf=buffer_new();
|
||||||
CHANNEL *channels[]={channel,NULL};
|
CHANNEL *channels[2];
|
||||||
CHANNEL *outchannel[2];
|
|
||||||
int lus;
|
int lus;
|
||||||
int eof=0;
|
int eof=0;
|
||||||
|
int maxfd;
|
||||||
int ret;
|
int ret;
|
||||||
while(channel){
|
while(channel){
|
||||||
/* when a signal is caught, ssh_select will return
|
/* 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);
|
FD_SET(0,&fds);
|
||||||
timeout.tv_sec=30;
|
timeout.tv_sec=30;
|
||||||
timeout.tv_usec=0;
|
timeout.tv_usec=0;
|
||||||
ret=ssh_select(channels,outchannel,0+1,&fds,&timeout);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
if(signal_delayed)
|
||||||
sizechanged();
|
sizechanged();
|
||||||
} while (ret==SSH_EINTR);
|
} while (ret==EINTR || ret==SSH_EINTR);
|
||||||
if(FD_ISSET(0,&fds)){
|
|
||||||
lus=read(0,buffer,10);
|
// we already looked for input from stdin. Now, we are looking for input from the channel
|
||||||
if(lus){
|
|
||||||
channel_write(channel,buffer,lus);
|
if(channel && channel_is_closed(channel)){
|
||||||
}
|
channel_free(channel);
|
||||||
else{
|
channel=NULL;
|
||||||
eof=1;
|
channels[0]=NULL;
|
||||||
channel_send_eof(channel);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(outchannel[0]){
|
if(channels[0]){
|
||||||
while(channel && channel_poll(outchannel[0],0)){
|
while(channel && channel_is_open(channel) && channel_poll(channel,0)){
|
||||||
lus=channel_read(outchannel[0],readbuf,0,0);
|
lus=channel_read(channel,readbuf,0,0);
|
||||||
if(lus==-1){
|
if(lus==-1){
|
||||||
ssh_say(0,"error reading channel : %s\n",ssh_get_error(session));
|
ssh_say(0,"error reading channel : %s\n",ssh_get_error(session));
|
||||||
return;
|
return;
|
||||||
@@ -165,12 +182,12 @@ void select_loop(SSH_SESSION *session,CHANNEL *channel){
|
|||||||
if(lus==0){
|
if(lus==0){
|
||||||
ssh_say(1,"EOF received\n");
|
ssh_say(1,"EOF received\n");
|
||||||
channel_free(channel);
|
channel_free(channel);
|
||||||
channel=NULL;
|
channel=channels[0]=NULL;
|
||||||
} else
|
} else
|
||||||
write(1,buffer_get(readbuf),lus);
|
write(1,buffer_get(readbuf),lus);
|
||||||
}
|
}
|
||||||
while(channel && channel_poll(outchannel[0],1)){ /* stderr */
|
while(channel && channel_is_open(channel) && channel_poll(channel,1)){ /* stderr */
|
||||||
lus=channel_read(outchannel[0],readbuf,0,1);
|
lus=channel_read(channel,readbuf,0,1);
|
||||||
if(lus==-1){
|
if(lus==-1){
|
||||||
ssh_say(0,"error reading channel : %s\n",ssh_get_error(session));
|
ssh_say(0,"error reading channel : %s\n",ssh_get_error(session));
|
||||||
return;
|
return;
|
||||||
@@ -178,12 +195,12 @@ void select_loop(SSH_SESSION *session,CHANNEL *channel){
|
|||||||
if(lus==0){
|
if(lus==0){
|
||||||
ssh_say(1,"EOF received\n");
|
ssh_say(1,"EOF received\n");
|
||||||
channel_free(channel);
|
channel_free(channel);
|
||||||
channel=NULL;
|
channel=channels[0]=NULL;
|
||||||
} else
|
} else
|
||||||
write(2,buffer_get(readbuf),lus);
|
write(2,buffer_get(readbuf),lus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(channel && !channel_is_open(channel)){
|
if(channel && channel_is_closed(channel)){
|
||||||
channel_free(channel);
|
channel_free(channel);
|
||||||
channel=NULL;
|
channel=NULL;
|
||||||
}
|
}
|
||||||
@@ -191,6 +208,7 @@ void select_loop(SSH_SESSION *session,CHANNEL *channel){
|
|||||||
buffer_free(readbuf);
|
buffer_free(readbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void shell(SSH_SESSION *session){
|
void shell(SSH_SESSION *session){
|
||||||
CHANNEL *channel;
|
CHANNEL *channel;
|
||||||
struct termios terminal_local;
|
struct termios terminal_local;
|
||||||
|
|||||||
Reference in New Issue
Block a user