mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-11 18:50:28 +09:00
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
This commit is contained in:
@@ -133,6 +133,28 @@ typedef BN_CTX* bignum_CTX;
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#endif
|
#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 */
|
/* wrapper.c */
|
||||||
MD5CTX md5_init(void);
|
MD5CTX md5_init(void);
|
||||||
void md5_update(MD5CTX c, const void *data, unsigned long len);
|
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);
|
struct public_key_struct *pubkey);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* poll.c */
|
||||||
|
int ssh_poll(pollfd_t *fds, nfds_t nfds, int timeout);
|
||||||
|
|
||||||
/* socket.c */
|
/* socket.c */
|
||||||
|
|
||||||
struct socket;
|
struct socket;
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ set(libssh_SRCS
|
|||||||
misc.c
|
misc.c
|
||||||
options.c
|
options.c
|
||||||
packet.c
|
packet.c
|
||||||
|
poll.c
|
||||||
session.c
|
session.c
|
||||||
socket.c
|
socket.c
|
||||||
string.c
|
string.c
|
||||||
|
|||||||
204
libssh/poll.c
Normal file
204
libssh/poll.c
Normal file
@@ -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
|
#endif
|
||||||
#include "libssh/priv.h"
|
#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
|
/** \defgroup ssh_socket SSH Sockets
|
||||||
* \addtogroup ssh_socket
|
* \addtogroup ssh_socket
|
||||||
* @{
|
* @{
|
||||||
@@ -472,86 +456,10 @@ int ssh_socket_wait_for_data(struct socket *s, SSH_SESSION *session, u32 len) {
|
|||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_SELECT
|
/* ssh_socket_poll */
|
||||||
/* 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
|
|
||||||
*/
|
|
||||||
int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
|
int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
|
||||||
SSH_SESSION *session = s->session;
|
SSH_SESSION *session = s->session;
|
||||||
struct timeval sometime;
|
pollfd_t fd[1];
|
||||||
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];
|
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
|
|
||||||
enter_function();
|
enter_function();
|
||||||
@@ -573,7 +481,7 @@ int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Make the call, and listen for errors */
|
/* Make the call, and listen for errors */
|
||||||
rc = poll(fd, 1, 0);
|
rc = ssh_poll(fd, 1, 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
ssh_set_error(session, SSH_FATAL, "poll(): %s", strerror(errno));
|
ssh_set_error(session, SSH_FATAL, "poll(): %s", strerror(errno));
|
||||||
leave_function();
|
leave_function();
|
||||||
@@ -596,7 +504,6 @@ int ssh_socket_poll(struct socket *s, int *writeable, int *except) {
|
|||||||
leave_function();
|
leave_function();
|
||||||
return (s->data_to_read || (buffer_get_rest_len(s->in_buffer) > 0));
|
return (s->data_to_read || (buffer_get_rest_len(s->in_buffer) > 0));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/** \internal
|
/** \internal
|
||||||
* \brief nonblocking flush of the output buffer
|
* \brief nonblocking flush of the output buffer
|
||||||
|
|||||||
Reference in New Issue
Block a user