diff options
author | Andreas Schneider <mail@cynapses.org> | 2009-05-04 10:42:07 +0000 |
---|---|---|
committer | Andreas Schneider <mail@cynapses.org> | 2009-05-04 10:42:07 +0000 |
commit | 0b7ae624a3ac3d22d377390e3a44703b6c7c8963 (patch) | |
tree | f1b9dba961ebc09055fdf51c205b88ee15e98cd4 /libssh | |
parent | d9a0b9070186d4e56dbb303efdc4eb5cb9cb98be (diff) | |
download | libssh-0b7ae624a3ac3d22d377390e3a44703b6c7c8963.tar.gz libssh-0b7ae624a3ac3d22d377390e3a44703b6c7c8963.tar.xz libssh-0b7ae624a3ac3d22d377390e3a44703b6c7c8963.zip |
Improve channel_select().
git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@708 7dcaeef0-15fb-0310-b436-a5af3365683c
Diffstat (limited to 'libssh')
-rw-r--r-- | libssh/channels.c | 252 |
1 files changed, 132 insertions, 120 deletions
diff --git a/libssh/channels.c b/libssh/channels.c index 228b326c..0edc785c 100644 --- a/libssh/channels.c +++ b/libssh/channels.c @@ -1712,137 +1712,149 @@ static int count_ptrs(CHANNEL **ptrs) { return c; } -/** the list of pointers are then actualized and will only contain pointers to - * channels that are respectively readable, writable or have an exception to trap - * \brief act as the standard select(2) for channels - * \param readchans a NULL pointer or an array of channel pointers, finished by a NULL - * \param writechans a NULL pointer or an array of channel pointers, finished by a NULL - * \param exceptchans a NULL pointer or an array of channel pointers, finished by a NULL - * \param timeout timeout as defined by select(2) - * \return SSH_SUCCESS operation successful\n - * SSH_EINTR select(2) syscall was interrupted, relaunch the function +/** + * @brief Act like the standard select(2) on channels. + * + * The list of pointers are then actualized and will only contain pointers to + * channels that are respectively readable, writable or have an exception to + * trap. + * + * @param readchans A NULL pointer or an array of channel pointers, + * terminated by a NULL. + * + * @param writechans A NULL pointer or an array of channel pointers, + * terminated by a NULL. + * + * @param exceptchans A NULL pointer or an array of channel pointers, + * terminated by a NULL. + * + * @param timeout Timeout as defined by select(2). + * + * @return SSH_SUCCESS operation successful\n + * SSH_EINTR select(2) syscall was interrupted, relaunch the function */ -int channel_select(CHANNEL **readchans, CHANNEL **writechans, CHANNEL **exceptchans, struct - timeval * timeout){ - fd_set rset; - fd_set wset; - fd_set eset; - CHANNEL *dummy=NULL; - CHANNEL **rchans, **wchans, **echans; - int fdmax=-1; - int i; - int r; - /* 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; +int channel_select(CHANNEL **readchans, CHANNEL **writechans, + CHANNEL **exceptchans, struct timeval * timeout) { + CHANNEL **rchans, **wchans, **echans; + CHANNEL *dummy = NULL; + fd_set rset; + fd_set wset; + fd_set eset; + int fdmax = -1; + int rc; + int i; + + /* don't allow NULL pointers */ + if (readchans == NULL) { + readchans = &dummy; + } + + if (writechans == NULL) { + writechans = &dummy; + } + + if (exceptchans == NULL) { + exceptchans = &dummy; + } + + if (readchans[0] == NULL && writechans[0] == NULL && exceptchans[0] == NULL) { + /* No channel to poll?? Go away! */ + return 0; + } + + /* Prepare the outgoing temporary arrays */ + rchans = malloc(sizeof(CHANNEL *) * (count_ptrs(readchans) + 1)); + if (rchans == NULL) { + return SSH_ERROR; + } + + wchans = malloc(sizeof(CHANNEL *) * (count_ptrs(writechans) + 1)); + if (wchans == NULL) { + SAFE_FREE(rchans); + return SSH_ERROR; + } + + echans = malloc(sizeof(CHANNEL *) * (count_ptrs(exceptchans) + 1)); + if (echans == NULL) { + SAFE_FREE(rchans); + SAFE_FREE(wchans); + return SSH_ERROR; + } + + /* + * 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] != NULL || wchans[0] != NULL || echans[0] != NULL) { + /* 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 *)); + SAFE_FREE(rchans); + SAFE_FREE(wchans); + SAFE_FREE(echans); + return 0; } - /* prepare the outgoing temporary arrays */ - rchans = malloc(sizeof(CHANNEL *) * (count_ptrs(readchans) + 1)); - if (rchans == NULL) { - return SSH_ERROR; + /* + * 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] != NULL; i++) { + if (!ssh_socket_fd_isset(readchans[i]->session->socket, &rset)) { + ssh_socket_fd_set(readchans[i]->session->socket, &rset, &fdmax); + } } - wchans = malloc(sizeof(CHANNEL *) * (count_ptrs(writechans) + 1)); - if (wchans == NULL) { - SAFE_FREE(rchans); - return SSH_ERROR; + + for (i = 0; writechans[i] != NULL; i++) { + if (!ssh_socket_fd_isset(writechans[i]->session->socket, &wset)) { + ssh_socket_fd_set(writechans[i]->session->socket, &wset, &fdmax); + } } - echans = malloc(sizeof(CHANNEL *) * (count_ptrs(exceptchans) + 1)); - if (echans == NULL) { + + for (i = 0; exceptchans[i] != NULL; i++) { + if (!ssh_socket_fd_isset(exceptchans[i]->session->socket, &eset)) { + ssh_socket_fd_set(exceptchans[i]->session->socket, &eset, &fdmax); + } + } + + /* Here we go */ + rc = select(fdmax, &rset, &wset, &eset, timeout); + /* Leave if select was interrupted */ + if (rc == EINTR) { SAFE_FREE(rchans); SAFE_FREE(wchans); - return SSH_ERROR; + SAFE_FREE(echans); + return SSH_EINTR; } - /* 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; - } - /* 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){ - if(!ssh_socket_fd_isset(readchans[i]->session->socket,&rset)) - ssh_socket_fd_set(readchans[i]->session->socket, &rset, &fdmax); - } - for(i=0;writechans[i];++i){ - if(!ssh_socket_fd_isset(writechans[i]->session->socket,&wset)) - ssh_socket_fd_set(writechans[i]->session->socket,&wset, &fdmax); - } - for(i=0;exceptchans[i];++i){ - if(!ssh_socket_fd_isset(exceptchans[i]->session->socket,&eset)) - ssh_socket_fd_set(exceptchans[i]->session->socket,&eset,&fdmax); - } + for (i = 0; readchans[i] != NULL; i++) { + if (ssh_socket_fd_isset(readchans[i]->session->socket, &rset)) { + ssh_socket_set_toread(readchans[i]->session->socket); + } + } -/* 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] != NULL; i++) { + if (ssh_socket_fd_isset(writechans[i]->session->socket, &wset)) { + ssh_socket_set_towrite(writechans[i]->session->socket); + } + } - } - 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] != NULL; i++) { + if (ssh_socket_fd_isset(exceptchans[i]->session->socket, &eset)) { + ssh_socket_set_except(exceptchans[i]->session->socket); + } + } + } while(1); /* Return to do loop */ - 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 */ - r=select(fdmax,&rset,&wset,&eset,timeout); - /* leave if select was interrupted */ - if(r==EINTR){ - free(rchans); - free(wchans); - free(echans); - return SSH_EINTR; - } - for(i=0;readchans[i];++i){ - if(ssh_socket_fd_isset(readchans[i]->session->socket,&rset)) - ssh_socket_set_toread(readchans[i]->session->socket); - } - for(i=0;writechans[i];++i){ - if(ssh_socket_fd_isset(writechans[i]->session->socket,&wset)) - ssh_socket_set_towrite(writechans[i]->session->socket); - } - for(i=0;exceptchans[i];++i){ - if(ssh_socket_fd_isset(exceptchans[i]->session->socket,&eset)) - ssh_socket_set_except(exceptchans[i]->session->socket); - } - } while(1); /* return to do loop */ - /* not reached */ - return 0; + /* not reached */ + return 0; } /** @} */ |