1
1

Make use of poll() and add a poll-emulation for win32.

git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@772 7dcaeef0-15fb-0310-b436-a5af3365683c
Этот коммит содержится в:
Andreas Schneider 2009-06-04 07:23:55 +00:00
родитель 70c9da4fb0
Коммит 87995db8fe
4 изменённых файлов: 233 добавлений и 96 удалений

Просмотреть файл

@ -133,6 +133,28 @@ typedef BN_CTX* bignum_CTX;
#include <sys/time.h>
#endif
/* poll support */
#ifdef HAVE_POLL
#include <poll.h>
typedef struct pollfd pollfd_t;
#else /* HAVE_POLL */
typedef struct pollfd_s {
socket_t fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
} pollfd_t;
#define POLLIN 0x001 /* There is data to read. */
#define POLLPRI 0x002 /* There is urgent data to read. */
#define POLLOUT 0x004 /* Writing now will not block. */
#define POLLERR 0x008 /* Error condition. */
#define POLLHUP 0x010 /* Hung up. */
#define POLLNVAL 0x020 /* Invalid polling request. */
typedef unsigned long int nfds_t;
#endif /* HAVE_POLL */
/* wrapper.c */
MD5CTX md5_init(void);
void md5_update(MD5CTX c, const void *data, unsigned long len);
@ -474,6 +496,9 @@ STRING *agent_sign_data(struct ssh_session *session,
struct public_key_struct *pubkey);
#endif
/* poll.c */
int ssh_poll(pollfd_t *fds, nfds_t nfds, int timeout);
/* socket.c */
struct socket;

Просмотреть файл

@ -84,6 +84,7 @@ set(libssh_SRCS
misc.c
options.c
packet.c
poll.c
session.c
socket.c
string.c

204
libssh/poll.c Обычный файл
Просмотреть файл

@ -0,0 +1,204 @@
/*
* poll.c - poll wrapper
*
* This file is part of the SSH Library
*
* Copyright (c) 2003-2008 by Aris Adamantiadis
*
* The SSH Library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at your
* option) any later version.
*
* The SSH Library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the SSH Library; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
*
* vim: ts=2 sw=2 et cindent
*/
/* This code is based on glib's gpoll */
#include "config.h"
#include "libssh/priv.h"
#ifdef HAVE_POLL
#include <poll.h>
int ssh_poll(pollfd_t *fds, nfds_t nfds, int timeout) {
return poll((struct pollfd *) fds, nfds, timeout);
}
#else /* HAVE_POLL */
#ifdef _WIN32
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
#include <winsock2.h>
int ssh_poll(pollfd_t *fds, nfds_t nfds, int timeout) {
return WSAPoll(fds, nfds, timeout);
}
#else /* _WIN32_WINNT */
#ifndef STRICT
#define STRICT
#endif
#include <stdio.h>
#include <windows.h>
static int poll_rest (HANDLE *handles, int nhandles,
pollfd_t *fds, nfds_t nfds, int timeout) {
DWORD ready;
pollfd_t *f;
int recursed_result;
if (nhandles == 0) {
/* No handles to wait for, just the timeout */
if (timeout == INFINITE) {
ready = WAIT_FAILED;
} else {
SleepEx(timeout, 1);
ready = WAIT_TIMEOUT;
}
} else {
/* Wait for just handles */
ready = WaitForMultipleObjectsEx(nhandles, handles, FALSE, timeout, TRUE);
#if 0
if (ready == WAIT_FAILED) {
fprintf(stderr, "WaitForMultipleObjectsEx failed: %d\n", GetLastError());
}
#endif
}
if (ready == WAIT_FAILED) {
return -1;
} else if (ready == WAIT_TIMEOUT || ready == WAIT_IO_COMPLETION) {
return 0;
} else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles) {
for (f = fds; f < &fds[nfds]; f++) {
if ((HANDLE) f->fd == handles[ready - WAIT_OBJECT_0]) {
f->revents = f->events;
}
}
/*
* If no timeout and polling several handles, recurse to poll
* the rest of them.
*/
if (timeout == 0 && nhandles > 1) {
/* Remove the handle that fired */
int i;
if (ready < nhandles - 1) {
for (i = ready - WAIT_OBJECT_0 + 1; i < nhandles; i++) {
handles[i-1] = handles[i];
}
}
nhandles--;
recursed_result = poll_rest(handles, nhandles, fds, nfds, 0);
if (recursed_result < 0) {
return -1;
}
return recursed_result + 1;
}
return 1;
}
return 0;
}
int ssh_poll(pollfd_t *fds, nfds_t nfds, int timeout) {
HANDLE handles[MAXIMUM_WAIT_OBJECTS];
pollfd_t *f;
int nhandles = 0;
int rc = -1;
if (fds == NULL) {
errno = EFAULT;
return -1;
}
if (nfds >= MAXIMUM_WAIT_OBJECTS) {
errno = EINVAL;
return -1;
}
for (f = fds; f < &fds[nfds]; f++) {
if (f->fd > 0) {
int i;
/*
* Don't add the same handle several times into the array, as
* docs say that is not allowed, even if it actually does seem
* to work.
*/
for (i = 0; i < nhandles; i++) {
if (handles[i] == (HANDLE) f->fd) {
break;
}
}
if (i == nhandles) {
if (nhandles == MAXIMUM_WAIT_OBJECTS) {
break;
} else {
handles[nhandles++] = (HANDLE) f->fd;
}
}
}
}
if (timeout == -1) {
timeout = INFINITE;
}
if (nhandles > 1) {
/*
* First check if one or several of them are immediately
* available.
*/
rc = poll_rest(handles, nhandles, fds, nfds, 0);
/*
* If not, and we have a significant timeout, poll again with
* timeout then. Note that this will return indication for only
* one event, or only for messages. We ignore timeouts less than
* ten milliseconds as they are mostly pointless on Windows, the
* MsgWaitForMultipleObjectsEx() call will timeout right away
* anyway.
*/
if (rc == 0 && (timeout == INFINITE || timeout >= 10)) {
rc = poll_rest(handles, nhandles, fds, nfds, timeout);
}
} else {
/*
* Just polling for one thing, so no need to check first if
* available immediately
*/
rc = poll_rest(handles, nhandles, fds, nfds, timeout);
}
if (rc < 0) {
for (f = fds; f < &fds[nfds]; f++) {
f->revents = 0;
}
errno = EBADF;
}
return rc;
}
#endif /* _WIN32_WINNT */
#endif /* _WIN32 */
#endif /* HAVE_POLL */

Просмотреть файл

@ -36,22 +36,6 @@
#endif
#include "libssh/priv.h"
#if !defined(HAVE_SELECT) && !defined(HAVE_POLL)
#error Your system must have either select() or poll()
#endif
#if !defined(HAVE_POLL) && !defined(_WIN32)
#warning your system does not have poll. Select has known limitations
#define SELECT_LIMIT_CHECK
#endif
#ifdef HAVE_POLL
#define USE_POLL
#include <poll.h>
#else
#define USE_SELECT
#endif
/** \defgroup ssh_socket SSH Sockets
* \addtogroup ssh_socket
* @{
@ -472,86 +456,10 @@ int ssh_socket_wait_for_data(struct socket *s, SSH_SESSION *session, u32 len) {
return SSH_OK;
}
#ifdef USE_SELECT
/* ssh_socket_poll, select() version */
/* \internal
* \brief polls the socket for data
* \param session ssh session
* \param writeable value pointed to set to 1 if it is possible to write
* \param except value pointed to set to 1 if there is an exception
* \return 1 if it is possible to read, 0 otherwise, -1 on error
*/
/* ssh_socket_poll */
int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
SSH_SESSION *session = s->session;
struct timeval sometime;
fd_set rdes; // read set
fd_set wdes; // writing set
fd_set edes; // exception set
int fdmax =- 1;
enter_function();
FD_ZERO(&rdes);
FD_ZERO(&wdes);
FD_ZERO(&edes);
if (!ssh_socket_is_open(s)) {
*except = 1;
*writeable = 0;
return 0;
}
#ifdef SELECT_LIMIT_CHECK
// some systems don't handle the fds > FD_SETSIZE
if(s->fd > FD_SETSIZE){
ssh_set_error(session, SSH_REQUEST_DENIED,
"File descriptor out of range for select: %d", s->fd);
leave_function();
return -1;
}
#endif
if (!s->data_to_read) {
ssh_socket_fd_set(s, &rdes, &fdmax);
}
if (!s->data_to_write) {
ssh_socket_fd_set(s, &wdes, &fdmax);
}
ssh_socket_fd_set(s, &edes, &fdmax);
/* Set to return immediately (no blocking) */
sometime.tv_sec = 0;
sometime.tv_usec = 0;
/* Make the call, and listen for errors */
if (select(fdmax, &rdes, &wdes, &edes, &sometime) < 0) {
ssh_set_error(session, SSH_FATAL, "select(): %s", strerror(errno));
leave_function();
return -1;
}
if (!s->data_to_read) {
s->data_to_read = ssh_socket_fd_isset(s, &rdes);
}
if (!s->data_to_write) {
s->data_to_write = ssh_socket_fd_isset(s, &wdes);
}
if (!s->data_except) {
s->data_except = ssh_socket_fd_isset(s, &edes);
}
*except = s->data_except;
*writeable = s->data_to_write;
leave_function();
return (s->data_to_read || (buffer_get_rest_len(s->in_buffer) > 0));
}
#endif
#ifdef USE_POLL
/* ssh_socket_poll, poll() version */
int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
SSH_SESSION *session = s->session;
struct pollfd fd[1];
pollfd_t fd[1];
int rc = -1;
enter_function();
@ -573,7 +481,7 @@ int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
}
/* Make the call, and listen for errors */
rc = poll(fd, 1, 0);
rc = ssh_poll(fd, 1, 0);
if (rc < 0) {
ssh_set_error(session, SSH_FATAL, "poll(): %s", strerror(errno));
leave_function();
@ -596,7 +504,6 @@ int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
leave_function();
return (s->data_to_read || (buffer_get_rest_len(s->in_buffer) > 0));
}
#endif
/** \internal
* \brief nonblocking flush of the output buffer