Blame src/poll.c

Packit 6c0a39
/*
Packit 6c0a39
 * poll.c - poll wrapper
Packit 6c0a39
 *
Packit 6c0a39
 * This file is part of the SSH Library
Packit 6c0a39
 *
Packit 6c0a39
 * Copyright (c) 2009-2013 by Andreas Schneider <asn@cryptomilk.org>
Packit 6c0a39
 * Copyright (c) 2003-2013 by Aris Adamantiadis
Packit 6c0a39
 * Copyright (c) 2009 Aleksandar Kanchev
Packit 6c0a39
 *
Packit 6c0a39
 * The SSH Library is free software; you can redistribute it and/or modify
Packit 6c0a39
 * it under the terms of the GNU Lesser General Public License as published by
Packit 6c0a39
 * the Free Software Foundation; either version 2.1 of the License, or (at your
Packit 6c0a39
 * option) any later version.
Packit 6c0a39
 *
Packit 6c0a39
 * The SSH Library is distributed in the hope that it will be useful, but
Packit 6c0a39
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 6c0a39
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
Packit 6c0a39
 * License for more details.
Packit 6c0a39
 *
Packit 6c0a39
 * You should have received a copy of the GNU Lesser General Public License
Packit 6c0a39
 * along with the SSH Library; see the file COPYING.  If not, write to
Packit 6c0a39
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
Packit 6c0a39
 * MA 02111-1307, USA.
Packit 6c0a39
 */
Packit 6c0a39
Packit 6c0a39
#include "config.h"
Packit 6c0a39
Packit 6c0a39
#include <errno.h>
Packit 6c0a39
#include <stdlib.h>
Packit 6c0a39
Packit 6c0a39
#include "libssh/priv.h"
Packit 6c0a39
#include "libssh/libssh.h"
Packit 6c0a39
#include "libssh/poll.h"
Packit 6c0a39
#include "libssh/socket.h"
Packit 6c0a39
#include "libssh/session.h"
Packit 6c0a39
#include "libssh/misc.h"
Packit 6c0a39
#ifdef WITH_SERVER
Packit 6c0a39
#include "libssh/server.h"
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
Packit 6c0a39
#ifndef SSH_POLL_CTX_CHUNK
Packit 6c0a39
#define SSH_POLL_CTX_CHUNK			5
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @defgroup libssh_poll The SSH poll functions.
Packit 6c0a39
 * @ingroup libssh
Packit 6c0a39
 *
Packit 6c0a39
 * Add a generic way to handle sockets asynchronously.
Packit 6c0a39
 *
Packit 6c0a39
 * It's based on poll objects, each of which store a socket, its events and a
Packit 6c0a39
 * callback, which gets called whenever an event is set. The poll objects are
Packit 6c0a39
 * attached to a poll context, which should be allocated on per thread basis.
Packit 6c0a39
 *
Packit 6c0a39
 * Polling the poll context will poll all the attached poll objects and call
Packit 6c0a39
 * their callbacks (handlers) if any of the socket events are set. This should
Packit 6c0a39
 * be done within the main loop of an application.
Packit 6c0a39
 *
Packit 6c0a39
 * @{
Packit 6c0a39
 */
Packit 6c0a39
Packit 6c0a39
struct ssh_poll_handle_struct {
Packit 6c0a39
  ssh_poll_ctx ctx;
Packit 6c0a39
  ssh_session session;
Packit 6c0a39
  union {
Packit 6c0a39
    socket_t fd;
Packit 6c0a39
    size_t idx;
Packit 6c0a39
  } x;
Packit 6c0a39
  short events;
Packit 6c0a39
  int lock;
Packit 6c0a39
  ssh_poll_callback cb;
Packit 6c0a39
  void *cb_data;
Packit 6c0a39
};
Packit 6c0a39
Packit 6c0a39
struct ssh_poll_ctx_struct {
Packit 6c0a39
  ssh_poll_handle *pollptrs;
Packit 6c0a39
  ssh_pollfd_t *pollfds;
Packit 6c0a39
  size_t polls_allocated;
Packit 6c0a39
  size_t polls_used;
Packit 6c0a39
  size_t chunk_size;
Packit 6c0a39
};
Packit 6c0a39
Packit 6c0a39
#ifdef HAVE_POLL
Packit 6c0a39
#include <poll.h>
Packit 6c0a39
Packit 6c0a39
void ssh_poll_init(void) {
Packit 6c0a39
    return;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void ssh_poll_cleanup(void) {
Packit 6c0a39
    return;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
Packit 6c0a39
  return poll((struct pollfd *) fds, nfds, timeout);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
#else /* HAVE_POLL */
Packit 6c0a39
Packit 6c0a39
typedef int (*poll_fn)(ssh_pollfd_t *, nfds_t, int);
Packit 6c0a39
static poll_fn ssh_poll_emu;
Packit 6c0a39
Packit 6c0a39
#include <sys/types.h>
Packit 6c0a39
#include <stdbool.h>
Packit 6c0a39
Packit 6c0a39
#ifdef _WIN32
Packit 6c0a39
#ifndef STRICT
Packit 6c0a39
#define STRICT
Packit 6c0a39
#endif /* STRICT */
Packit 6c0a39
Packit 6c0a39
#include <time.h>
Packit 6c0a39
#include <windows.h>
Packit 6c0a39
#include <winsock2.h>
Packit 6c0a39
#else /* _WIN32 */
Packit 6c0a39
#include <sys/select.h>
Packit 6c0a39
#include <sys/socket.h>
Packit 6c0a39
Packit 6c0a39
# ifdef HAVE_SYS_TIME_H
Packit 6c0a39
#  include <sys/time.h>
Packit 6c0a39
# endif
Packit 6c0a39
Packit 6c0a39
#endif /* _WIN32 */
Packit 6c0a39
Packit 6c0a39
#ifdef HAVE_UNISTD_H
Packit 6c0a39
#include <unistd.h>
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
static bool bsd_socket_not_connected(int sock_err)
Packit 6c0a39
{
Packit 6c0a39
    switch (sock_err) {
Packit 6c0a39
#ifdef _WIN32
Packit 6c0a39
    case WSAENOTCONN:
Packit 6c0a39
#else
Packit 6c0a39
    case ENOTCONN:
Packit 6c0a39
#endif
Packit 6c0a39
        return true;
Packit 6c0a39
    default:
Packit 6c0a39
        return false;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    return false;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static bool bsd_socket_reset(int sock_err)
Packit 6c0a39
{
Packit 6c0a39
    switch (sock_err) {
Packit 6c0a39
#ifdef _WIN32
Packit 6c0a39
    case WSAECONNABORTED:
Packit 6c0a39
    case WSAECONNRESET:
Packit 6c0a39
    case WSAENETRESET:
Packit 6c0a39
    case WSAESHUTDOWN:
Packit 6c0a39
    case WSAECONNREFUSED:
Packit 6c0a39
    case WSAETIMEDOUT:
Packit 6c0a39
#else
Packit 6c0a39
    case ECONNABORTED:
Packit 6c0a39
    case ECONNRESET:
Packit 6c0a39
    case ENETRESET:
Packit 6c0a39
    case ESHUTDOWN:
Packit 6c0a39
#endif
Packit 6c0a39
        return true;
Packit 6c0a39
    default:
Packit 6c0a39
        return false;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    return false;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static short bsd_socket_compute_revents(int fd, short events)
Packit 6c0a39
{
Packit 6c0a39
    int save_errno = errno;
Packit 6c0a39
    int sock_errno = errno;
Packit 6c0a39
    char data[64] = {0};
Packit 6c0a39
    short revents = 0;
Packit 6c0a39
    int flags = MSG_PEEK;
Packit 6c0a39
    int ret;
Packit 6c0a39
Packit 6c0a39
#ifdef MSG_NOSIGNAL
Packit 6c0a39
    flags |= MSG_NOSIGNAL;
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
    /* support for POLLHUP */
Packit 6c0a39
#ifdef _WIN32
Packit 6c0a39
    WSASetLastError(0);
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
    ret = recv(fd, data, 64, flags);
Packit 6c0a39
Packit 6c0a39
    errno = save_errno;
Packit 6c0a39
Packit 6c0a39
#ifdef _WIN32
Packit 6c0a39
    sock_errno = WSAGetLastError();
Packit 6c0a39
    WSASetLastError(0);
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
    if (ret > 0 || bsd_socket_not_connected(sock_errno)) {
Packit 6c0a39
        revents = (POLLIN | POLLRDNORM) & events;
Packit 6c0a39
    } else if (ret == 0 || bsd_socket_reset(sock_errno)) {
Packit 6c0a39
        errno = sock_errno;
Packit 6c0a39
        revents = POLLHUP;
Packit 6c0a39
    } else {
Packit 6c0a39
        revents = POLLERR;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    return revents;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/*
Packit 6c0a39
 * This is a poll(2)-emulation using select for systems not providing a native
Packit 6c0a39
 * poll implementation.
Packit 6c0a39
 *
Packit 6c0a39
 * Keep in mind that select is terribly inefficient. The interface is simply not
Packit 6c0a39
 * meant to be used with maximum descriptor value greater, say, 32 or so.  With
Packit 6c0a39
 * a value as high as 1024 on Linux you'll pay dearly in every single call.
Packit 6c0a39
 * poll() will be orders of magnitude faster.
Packit 6c0a39
 */
Packit 6c0a39
static int bsd_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout)
Packit 6c0a39
{
Packit 6c0a39
    fd_set readfds, writefds, exceptfds;
Packit 6c0a39
    struct timeval tv, *ptv = NULL;
Packit 6c0a39
    socket_t max_fd;
Packit 6c0a39
    int rc;
Packit 6c0a39
    nfds_t i;
Packit 6c0a39
Packit 6c0a39
    if (fds == NULL) {
Packit 6c0a39
        errno = EFAULT;
Packit 6c0a39
        return -1;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    ZERO_STRUCT(readfds);
Packit 6c0a39
    FD_ZERO(&readfds);
Packit 6c0a39
    ZERO_STRUCT(writefds);
Packit 6c0a39
    FD_ZERO(&writefds);
Packit 6c0a39
    ZERO_STRUCT(exceptfds);
Packit 6c0a39
    FD_ZERO(&exceptfds);
Packit 6c0a39
Packit 6c0a39
    /* compute fd_sets and find largest descriptor */
Packit 6c0a39
    for (rc = -1, max_fd = 0, i = 0; i < nfds; i++) {
Packit 6c0a39
        if (fds[i].fd == SSH_INVALID_SOCKET) {
Packit 6c0a39
            continue;
Packit 6c0a39
        }
Packit 6c0a39
#ifndef _WIN32
Packit 6c0a39
        if (fds[i].fd >= FD_SETSIZE) {
Packit 6c0a39
            rc = -1;
Packit 6c0a39
            break;
Packit 6c0a39
        }
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
        if (fds[i].events & (POLLIN | POLLRDNORM)) {
Packit 6c0a39
            FD_SET (fds[i].fd, &readfds);
Packit 6c0a39
        }
Packit 6c0a39
        if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) {
Packit 6c0a39
            FD_SET (fds[i].fd, &writefds);
Packit 6c0a39
        }
Packit 6c0a39
        if (fds[i].events & (POLLPRI | POLLRDBAND)) {
Packit 6c0a39
            FD_SET (fds[i].fd, &exceptfds);
Packit 6c0a39
        }
Packit 6c0a39
        if (fds[i].fd > max_fd &&
Packit 6c0a39
                (fds[i].events & (POLLIN | POLLOUT | POLLPRI |
Packit 6c0a39
                                  POLLRDNORM | POLLRDBAND |
Packit 6c0a39
                                  POLLWRNORM | POLLWRBAND))) {
Packit 6c0a39
            max_fd = fds[i].fd;
Packit 6c0a39
            rc = 0;
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    if (max_fd == SSH_INVALID_SOCKET || rc == -1) {
Packit 6c0a39
        errno = EINVAL;
Packit 6c0a39
        return -1;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    if (timeout < 0) {
Packit 6c0a39
        ptv = NULL;
Packit 6c0a39
    } else {
Packit 6c0a39
        ptv = &tv;
Packit 6c0a39
        if (timeout == 0) {
Packit 6c0a39
            tv.tv_sec = 0;
Packit 6c0a39
            tv.tv_usec = 0;
Packit 6c0a39
        } else {
Packit 6c0a39
            tv.tv_sec = timeout / 1000;
Packit 6c0a39
            tv.tv_usec = (timeout % 1000) * 1000;
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    rc = select(max_fd + 1, &readfds, &writefds, &exceptfds, ptv);
Packit 6c0a39
    if (rc < 0) {
Packit 6c0a39
        return -1;
Packit 6c0a39
    }
Packit 6c0a39
    /* A timeout occured */
Packit 6c0a39
    if (rc == 0) {
Packit 6c0a39
        return 0;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    for (rc = 0, i = 0; i < nfds; i++) {
Packit 6c0a39
        if (fds[i].fd >= 0) {
Packit 6c0a39
            fds[i].revents = 0;
Packit 6c0a39
Packit 6c0a39
            if (FD_ISSET(fds[i].fd, &readfds)) {
Packit 6c0a39
                fds[i].revents = bsd_socket_compute_revents(fds[i].fd,
Packit 6c0a39
                                                            fds[i].events);
Packit 6c0a39
            }
Packit 6c0a39
            if (FD_ISSET(fds[i].fd, &writefds)) {
Packit 6c0a39
                fds[i].revents |= fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND);
Packit 6c0a39
            }
Packit 6c0a39
Packit 6c0a39
            if (FD_ISSET(fds[i].fd, &exceptfds)) {
Packit 6c0a39
                fds[i].revents |= fds[i].events & (POLLPRI | POLLRDBAND);
Packit 6c0a39
            }
Packit 6c0a39
Packit 6c0a39
            if (fds[i].revents != 0) {
Packit 6c0a39
                rc++;
Packit 6c0a39
            }
Packit 6c0a39
        } else {
Packit 6c0a39
            fds[i].revents = POLLNVAL;
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    return rc;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void ssh_poll_init(void) {
Packit 6c0a39
    ssh_poll_emu = bsd_poll;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
void ssh_poll_cleanup(void) {
Packit 6c0a39
    ssh_poll_emu = bsd_poll;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
int ssh_poll(ssh_pollfd_t *fds, nfds_t nfds, int timeout) {
Packit 6c0a39
    return (ssh_poll_emu)(fds, nfds, timeout);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
#endif /* HAVE_POLL */
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Allocate a new poll object, which could be used within a poll context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  fd           Socket that will be polled.
Packit 6c0a39
 * @param  events       Poll events that will be monitored for the socket. i.e.
Packit 6c0a39
 *                      POLLIN, POLLPRI, POLLOUT
Packit 6c0a39
 * @param  cb           Function to be called if any of the events are set.
Packit 6c0a39
 *                      The prototype of cb is:
Packit 6c0a39
 *                      int (*ssh_poll_callback)(ssh_poll_handle p, socket_t fd,
Packit 6c0a39
 *                                                 int revents, void *userdata);
Packit 6c0a39
 * @param  userdata     Userdata to be passed to the callback function. NULL if
Packit 6c0a39
 *                      not needed.
Packit 6c0a39
 *
Packit 6c0a39
 * @return              A new poll object, NULL on error
Packit 6c0a39
 */
Packit 6c0a39
Packit 6c0a39
ssh_poll_handle ssh_poll_new(socket_t fd, short events, ssh_poll_callback cb,
Packit 6c0a39
    void *userdata) {
Packit 6c0a39
    ssh_poll_handle p;
Packit 6c0a39
Packit 6c0a39
    p = malloc(sizeof(struct ssh_poll_handle_struct));
Packit 6c0a39
    if (p == NULL) {
Packit 6c0a39
        return NULL;
Packit 6c0a39
    }
Packit 6c0a39
    ZERO_STRUCTP(p);
Packit 6c0a39
Packit 6c0a39
    p->x.fd = fd;
Packit 6c0a39
    p->events = events;
Packit 6c0a39
    p->cb = cb;
Packit 6c0a39
    p->cb_data = userdata;
Packit 6c0a39
Packit 6c0a39
    return p;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Free a poll object.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  p            Pointer to an already allocated poll object.
Packit 6c0a39
 */
Packit 6c0a39
Packit 6c0a39
void ssh_poll_free(ssh_poll_handle p) {
Packit 6c0a39
	if(p->ctx != NULL){
Packit 6c0a39
		ssh_poll_ctx_remove(p->ctx,p);
Packit 6c0a39
		p->ctx=NULL;
Packit 6c0a39
	}
Packit 6c0a39
  SAFE_FREE(p);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Get the poll context of a poll object.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  p            Pointer to an already allocated poll object.
Packit 6c0a39
 *
Packit 6c0a39
 * @return              Poll context or NULL if the poll object isn't attached.
Packit 6c0a39
 */
Packit 6c0a39
ssh_poll_ctx ssh_poll_get_ctx(ssh_poll_handle p) {
Packit 6c0a39
  return p->ctx;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Get the events of a poll object.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  p            Pointer to an already allocated poll object.
Packit 6c0a39
 *
Packit 6c0a39
 * @return              Poll events.
Packit 6c0a39
 */
Packit 6c0a39
short ssh_poll_get_events(ssh_poll_handle p) {
Packit 6c0a39
  return p->events;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Set the events of a poll object. The events will also be propagated
Packit 6c0a39
 *         to an associated poll context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  p            Pointer to an already allocated poll object.
Packit 6c0a39
 * @param  events       Poll events.
Packit 6c0a39
 */
Packit 6c0a39
void ssh_poll_set_events(ssh_poll_handle p, short events) {
Packit 6c0a39
  p->events = events;
Packit 6c0a39
  if (p->ctx != NULL && !p->lock) {
Packit 6c0a39
    p->ctx->pollfds[p->x.idx].events = events;
Packit 6c0a39
  }
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Set the file descriptor of a poll object. The FD will also be propagated
Packit 6c0a39
 *         to an associated poll context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  p            Pointer to an already allocated poll object.
Packit 6c0a39
 * @param  fd       New file descriptor.
Packit 6c0a39
 */
Packit 6c0a39
void ssh_poll_set_fd(ssh_poll_handle p, socket_t fd) {
Packit 6c0a39
  if (p->ctx != NULL) {
Packit 6c0a39
    p->ctx->pollfds[p->x.idx].fd = fd;
Packit 6c0a39
  } else {
Packit 6c0a39
  	p->x.fd = fd;
Packit 6c0a39
  }
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Add extra events to a poll object. Duplicates are ignored.
Packit 6c0a39
 *         The events will also be propagated to an associated poll context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  p            Pointer to an already allocated poll object.
Packit 6c0a39
 * @param  events       Poll events.
Packit 6c0a39
 */
Packit 6c0a39
void ssh_poll_add_events(ssh_poll_handle p, short events) {
Packit 6c0a39
  ssh_poll_set_events(p, ssh_poll_get_events(p) | events);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Remove events from a poll object. Non-existent are ignored.
Packit 6c0a39
 *         The events will also be propagated to an associated poll context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  p            Pointer to an already allocated poll object.
Packit 6c0a39
 * @param  events       Poll events.
Packit 6c0a39
 */
Packit 6c0a39
void ssh_poll_remove_events(ssh_poll_handle p, short events) {
Packit 6c0a39
  ssh_poll_set_events(p, ssh_poll_get_events(p) & ~events);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Get the raw socket of a poll object.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  p            Pointer to an already allocated poll object.
Packit 6c0a39
 *
Packit 6c0a39
 * @return              Raw socket.
Packit 6c0a39
 */
Packit 6c0a39
Packit 6c0a39
socket_t ssh_poll_get_fd(ssh_poll_handle p) {
Packit 6c0a39
  if (p->ctx != NULL) {
Packit 6c0a39
    return p->ctx->pollfds[p->x.idx].fd;
Packit 6c0a39
  }
Packit 6c0a39
Packit 6c0a39
  return p->x.fd;
Packit 6c0a39
}
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Set the callback of a poll object.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  p            Pointer to an already allocated poll object.
Packit 6c0a39
 * @param  cb           Function to be called if any of the events are set.
Packit 6c0a39
 * @param  userdata     Userdata to be passed to the callback function. NULL if
Packit 6c0a39
 *                      not needed.
Packit 6c0a39
 */
Packit 6c0a39
void ssh_poll_set_callback(ssh_poll_handle p, ssh_poll_callback cb, void *userdata) {
Packit 6c0a39
  if (cb != NULL) {
Packit 6c0a39
    p->cb = cb;
Packit 6c0a39
    p->cb_data = userdata;
Packit 6c0a39
  }
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Create a new poll context. It could be associated with many poll object
Packit 6c0a39
 *         which are going to be polled at the same time as the poll context. You
Packit 6c0a39
 *         would need a single poll context per thread.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  chunk_size   The size of the memory chunk that will be allocated, when
Packit 6c0a39
 *                      more memory is needed. This is for efficiency reasons,
Packit 6c0a39
 *                      i.e. don't allocate memory for each new poll object, but
Packit 6c0a39
 *                      for the next 5. Set it to 0 if you want to use the
Packit 6c0a39
 *                      library's default value.
Packit 6c0a39
 */
Packit 6c0a39
ssh_poll_ctx ssh_poll_ctx_new(size_t chunk_size) {
Packit 6c0a39
    ssh_poll_ctx ctx;
Packit 6c0a39
Packit 6c0a39
    ctx = malloc(sizeof(struct ssh_poll_ctx_struct));
Packit 6c0a39
    if (ctx == NULL) {
Packit 6c0a39
        return NULL;
Packit 6c0a39
    }
Packit 6c0a39
    ZERO_STRUCTP(ctx);
Packit 6c0a39
Packit 6c0a39
    if (chunk_size == 0) {
Packit 6c0a39
        chunk_size = SSH_POLL_CTX_CHUNK;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    ctx->chunk_size = chunk_size;
Packit 6c0a39
Packit 6c0a39
    return ctx;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Free a poll context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  ctx          Pointer to an already allocated poll context.
Packit 6c0a39
 */
Packit 6c0a39
void ssh_poll_ctx_free(ssh_poll_ctx ctx) {
Packit 6c0a39
  if (ctx->polls_allocated > 0) {
Packit 6c0a39
    while (ctx->polls_used > 0){
Packit 6c0a39
      ssh_poll_handle p = ctx->pollptrs[0];
Packit 6c0a39
      /*
Packit 6c0a39
       * The free function calls ssh_poll_ctx_remove() and decrements
Packit 6c0a39
       * ctx->polls_used
Packit 6c0a39
       */
Packit 6c0a39
      ssh_poll_free(p);
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    SAFE_FREE(ctx->pollptrs);
Packit 6c0a39
    SAFE_FREE(ctx->pollfds);
Packit 6c0a39
  }
Packit 6c0a39
Packit 6c0a39
  SAFE_FREE(ctx);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int ssh_poll_ctx_resize(ssh_poll_ctx ctx, size_t new_size) {
Packit 6c0a39
  ssh_poll_handle *pollptrs;
Packit 6c0a39
  ssh_pollfd_t *pollfds;
Packit 6c0a39
Packit 6c0a39
  pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle) * new_size);
Packit 6c0a39
  if (pollptrs == NULL) {
Packit 6c0a39
    return -1;
Packit 6c0a39
  }
Packit 6c0a39
  ctx->pollptrs = pollptrs;
Packit 6c0a39
Packit 6c0a39
  pollfds = realloc(ctx->pollfds, sizeof(ssh_pollfd_t) * new_size);
Packit 6c0a39
  if (pollfds == NULL) {
Packit 6c0a39
    pollptrs = realloc(ctx->pollptrs, sizeof(ssh_poll_handle) * ctx->polls_allocated);
Packit 6c0a39
    if (pollptrs == NULL) {
Packit 6c0a39
        return -1;
Packit 6c0a39
    }
Packit 6c0a39
    ctx->pollptrs = pollptrs;
Packit 6c0a39
    return -1;
Packit 6c0a39
  }
Packit 6c0a39
Packit 6c0a39
  ctx->pollfds = pollfds;
Packit 6c0a39
  ctx->polls_allocated = new_size;
Packit 6c0a39
Packit 6c0a39
  return 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Add a poll object to a poll context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  ctx          Pointer to an already allocated poll context.
Packit 6c0a39
 * @param  p            Pointer to an already allocated poll object.
Packit 6c0a39
 *
Packit 6c0a39
 * @return              0 on success, < 0 on error
Packit 6c0a39
 */
Packit 6c0a39
int ssh_poll_ctx_add(ssh_poll_ctx ctx, ssh_poll_handle p) {
Packit 6c0a39
  socket_t fd;
Packit 6c0a39
Packit 6c0a39
  if (p->ctx != NULL) {
Packit 6c0a39
    /* already attached to a context */
Packit 6c0a39
    return -1;
Packit 6c0a39
  }
Packit 6c0a39
Packit 6c0a39
  if (ctx->polls_used == ctx->polls_allocated &&
Packit 6c0a39
      ssh_poll_ctx_resize(ctx, ctx->polls_allocated + ctx->chunk_size) < 0) {
Packit 6c0a39
    return -1;
Packit 6c0a39
  }
Packit 6c0a39
Packit 6c0a39
  fd = p->x.fd;
Packit 6c0a39
  p->x.idx = ctx->polls_used++;
Packit 6c0a39
  ctx->pollptrs[p->x.idx] = p;
Packit 6c0a39
  ctx->pollfds[p->x.idx].fd = fd;
Packit 6c0a39
  ctx->pollfds[p->x.idx].events = p->events;
Packit 6c0a39
  ctx->pollfds[p->x.idx].revents = 0;
Packit 6c0a39
  p->ctx = ctx;
Packit 6c0a39
Packit 6c0a39
  return 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Add a socket object to a poll context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  ctx          Pointer to an already allocated poll context.
Packit 6c0a39
 * @param  s            A SSH socket handle
Packit 6c0a39
 *
Packit 6c0a39
 * @return              0 on success, < 0 on error
Packit 6c0a39
 */
Packit 6c0a39
int ssh_poll_ctx_add_socket (ssh_poll_ctx ctx, ssh_socket s)
Packit 6c0a39
{
Packit 6c0a39
    ssh_poll_handle p;
Packit 6c0a39
    int ret;
Packit 6c0a39
Packit 6c0a39
    p = ssh_socket_get_poll_handle(s);
Packit 6c0a39
    if (p == NULL) {
Packit 6c0a39
        return -1;
Packit 6c0a39
    }
Packit 6c0a39
    ret = ssh_poll_ctx_add(ctx,p);
Packit 6c0a39
    return ret;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Remove a poll object from a poll context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  ctx          Pointer to an already allocated poll context.
Packit 6c0a39
 * @param  p            Pointer to an already allocated poll object.
Packit 6c0a39
 */
Packit 6c0a39
void ssh_poll_ctx_remove(ssh_poll_ctx ctx, ssh_poll_handle p) {
Packit 6c0a39
  size_t i;
Packit 6c0a39
Packit 6c0a39
  i = p->x.idx;
Packit 6c0a39
  p->x.fd = ctx->pollfds[i].fd;
Packit 6c0a39
  p->ctx = NULL;
Packit 6c0a39
Packit 6c0a39
  ctx->polls_used--;
Packit 6c0a39
Packit 6c0a39
  /* fill the empty poll slot with the last one */
Packit 6c0a39
  if (ctx->polls_used > 0 && ctx->polls_used != i) {
Packit 6c0a39
    ctx->pollfds[i] = ctx->pollfds[ctx->polls_used];
Packit 6c0a39
    ctx->pollptrs[i] = ctx->pollptrs[ctx->polls_used];
Packit 6c0a39
    ctx->pollptrs[i]->x.idx = i;
Packit 6c0a39
  }
Packit 6c0a39
Packit 6c0a39
  /* this will always leave at least chunk_size polls allocated */
Packit 6c0a39
  if (ctx->polls_allocated - ctx->polls_used > ctx->chunk_size) {
Packit 6c0a39
    ssh_poll_ctx_resize(ctx, ctx->polls_allocated - ctx->chunk_size);
Packit 6c0a39
  }
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Poll all the sockets associated through a poll object with a
Packit 6c0a39
 *         poll context. If any of the events are set after the poll, the
Packit 6c0a39
 *         call back function of the socket will be called.
Packit 6c0a39
 *         This function should be called once within the programs main loop.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  ctx          Pointer to an already allocated poll context.
Packit 6c0a39
 * @param  timeout      An upper limit on the time for which ssh_poll_ctx() will
Packit 6c0a39
 *                      block, in milliseconds. Specifying a negative value
Packit 6c0a39
 *                      means an infinite timeout. This parameter is passed to
Packit 6c0a39
 *                      the poll() function.
Packit 6c0a39
 * @returns SSH_OK      No error.
Packit 6c0a39
 *          SSH_ERROR   Error happened during the poll.
Packit 6c0a39
 *          SSH_AGAIN   Timeout occured
Packit 6c0a39
 */
Packit 6c0a39
Packit 6c0a39
int ssh_poll_ctx_dopoll(ssh_poll_ctx ctx, int timeout)
Packit 6c0a39
{
Packit 6c0a39
    int rc;
Packit 6c0a39
    size_t i, used;
Packit 6c0a39
    ssh_poll_handle p;
Packit 6c0a39
    socket_t fd;
Packit 6c0a39
    int revents;
Packit 6c0a39
    struct ssh_timestamp ts;
Packit 6c0a39
Packit 6c0a39
    if (ctx->polls_used == 0) {
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    ssh_timestamp_init(&ts);
Packit 6c0a39
    do {
Packit 6c0a39
        int tm = ssh_timeout_update(&ts, timeout);
Packit 6c0a39
        rc = ssh_poll(ctx->pollfds, ctx->polls_used, tm);
Packit 6c0a39
    } while (rc == -1 && errno == EINTR);
Packit 6c0a39
Packit 6c0a39
    if (rc < 0) {
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
    if (rc == 0) {
Packit 6c0a39
        return SSH_AGAIN;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    used = ctx->polls_used;
Packit 6c0a39
    for (i = 0; i < used && rc > 0; ) {
Packit 6c0a39
        if (!ctx->pollfds[i].revents || ctx->pollptrs[i]->lock) {
Packit 6c0a39
            i++;
Packit 6c0a39
        } else {
Packit 6c0a39
            int ret;
Packit 6c0a39
Packit 6c0a39
            p = ctx->pollptrs[i];
Packit 6c0a39
            fd = ctx->pollfds[i].fd;
Packit 6c0a39
            revents = ctx->pollfds[i].revents;
Packit 6c0a39
            /* avoid having any event caught during callback */
Packit 6c0a39
            ctx->pollfds[i].events = 0;
Packit 6c0a39
            p->lock = 1;
Packit 6c0a39
            if (p->cb && (ret = p->cb(p, fd, revents, p->cb_data)) < 0) {
Packit 6c0a39
                if (ret == -2) {
Packit 6c0a39
                    return -1;
Packit 6c0a39
                }
Packit 6c0a39
                /* the poll was removed, reload the used counter and start again */
Packit 6c0a39
                used = ctx->polls_used;
Packit 6c0a39
                i = 0;
Packit 6c0a39
            } else {
Packit 6c0a39
                ctx->pollfds[i].revents = 0;
Packit 6c0a39
                ctx->pollfds[i].events = p->events;
Packit 6c0a39
                p->lock = 0;
Packit 6c0a39
                i++;
Packit 6c0a39
            }
Packit 6c0a39
Packit 6c0a39
            rc--;
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    return rc;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @internal
Packit 6c0a39
 * @brief gets the default poll structure for the current session,
Packit 6c0a39
 * when used in blocking mode.
Packit 6c0a39
 * @param session SSH session
Packit 6c0a39
 * @returns the default ssh_poll_ctx
Packit 6c0a39
 */
Packit 6c0a39
ssh_poll_ctx ssh_poll_get_default_ctx(ssh_session session){
Packit 6c0a39
	if(session->default_poll_ctx != NULL)
Packit 6c0a39
		return session->default_poll_ctx;
Packit 6c0a39
	/* 2 is enough for the default one */
Packit 6c0a39
	session->default_poll_ctx = ssh_poll_ctx_new(2);
Packit 6c0a39
	return session->default_poll_ctx;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/* public event API */
Packit 6c0a39
Packit 6c0a39
struct ssh_event_fd_wrapper {
Packit 6c0a39
    ssh_event_callback cb;
Packit 6c0a39
    void * userdata;
Packit 6c0a39
};
Packit 6c0a39
Packit 6c0a39
struct ssh_event_struct {
Packit 6c0a39
    ssh_poll_ctx ctx;
Packit 6c0a39
#ifdef WITH_SERVER
Packit 6c0a39
    struct ssh_list *sessions;
Packit 6c0a39
#endif
Packit 6c0a39
};
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Create a new event context. It could be associated with many
Packit 6c0a39
 *         ssh_session objects and socket fd which are going to be polled at the
Packit 6c0a39
 *         same time as the event context. You would need a single event context
Packit 6c0a39
 *         per thread.
Packit 6c0a39
 * 
Packit 6c0a39
 * @return  The ssh_event object on success, NULL on failure.
Packit 6c0a39
 */
Packit 6c0a39
ssh_event ssh_event_new(void) {
Packit 6c0a39
    ssh_event event;
Packit 6c0a39
Packit 6c0a39
    event = malloc(sizeof(struct ssh_event_struct));
Packit 6c0a39
    if (event == NULL) {
Packit 6c0a39
        return NULL;
Packit 6c0a39
    }
Packit 6c0a39
    ZERO_STRUCTP(event);
Packit 6c0a39
Packit 6c0a39
    event->ctx = ssh_poll_ctx_new(2);
Packit 6c0a39
    if(event->ctx == NULL) {
Packit 6c0a39
        free(event);
Packit 6c0a39
        return NULL;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
#ifdef WITH_SERVER
Packit 6c0a39
    event->sessions = ssh_list_new();
Packit 6c0a39
    if(event->sessions == NULL) {
Packit 6c0a39
        ssh_poll_ctx_free(event->ctx);
Packit 6c0a39
        free(event);
Packit 6c0a39
        return NULL;
Packit 6c0a39
    }
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
    return event;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
static int ssh_event_fd_wrapper_callback(ssh_poll_handle p, socket_t fd, int revents,
Packit 6c0a39
                                                            void *userdata) {
Packit 6c0a39
    struct ssh_event_fd_wrapper *pw = (struct ssh_event_fd_wrapper *)userdata;
Packit 6c0a39
Packit 6c0a39
    (void)p;
Packit 6c0a39
    if(pw->cb != NULL) {
Packit 6c0a39
        return pw->cb(fd, revents, pw->userdata);
Packit 6c0a39
    }
Packit 6c0a39
    return 0;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief Add a fd to the event and assign it a callback,
Packit 6c0a39
 * when used in blocking mode.
Packit 6c0a39
 * @param event         The ssh_event
Packit 6c0a39
 * @param  fd           Socket that will be polled.
Packit 6c0a39
 * @param  events       Poll events that will be monitored for the socket. i.e.
Packit 6c0a39
 *                      POLLIN, POLLPRI, POLLOUT
Packit 6c0a39
 * @param  cb           Function to be called if any of the events are set.
Packit 6c0a39
 *                      The prototype of cb is:
Packit 6c0a39
 *                      int (*ssh_event_callback)(socket_t fd, int revents,
Packit 6c0a39
 *                                                          void *userdata);
Packit 6c0a39
 * @param  userdata     Userdata to be passed to the callback function. NULL if
Packit 6c0a39
 *                      not needed.
Packit 6c0a39
 *
Packit 6c0a39
 * @returns SSH_OK      on success
Packit 6c0a39
 *          SSH_ERROR   on failure
Packit 6c0a39
 */
Packit 6c0a39
int ssh_event_add_fd(ssh_event event, socket_t fd, short events,
Packit 6c0a39
                                    ssh_event_callback cb, void *userdata) {
Packit 6c0a39
    ssh_poll_handle p;
Packit 6c0a39
    struct ssh_event_fd_wrapper *pw;
Packit 6c0a39
    
Packit 6c0a39
    if(event == NULL || event->ctx == NULL || cb == NULL
Packit 6c0a39
                                           || fd == SSH_INVALID_SOCKET) {
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
    pw = malloc(sizeof(struct ssh_event_fd_wrapper));
Packit 6c0a39
    if(pw == NULL) {
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    pw->cb = cb;
Packit 6c0a39
    pw->userdata = userdata;
Packit 6c0a39
Packit 6c0a39
    /* pw is freed by ssh_event_remove_fd */
Packit 6c0a39
    p = ssh_poll_new(fd, events, ssh_event_fd_wrapper_callback, pw);
Packit 6c0a39
    if(p == NULL) {
Packit 6c0a39
        free(pw);
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    if(ssh_poll_ctx_add(event->ctx, p) < 0) {
Packit 6c0a39
        free(pw);
Packit 6c0a39
        ssh_poll_free(p);
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
    return SSH_OK;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief Add a poll handle to the event.
Packit 6c0a39
 *
Packit 6c0a39
 * @param   event     the ssh_event
Packit 6c0a39
 *
Packit 6c0a39
 * @param   p         the poll handle
Packit 6c0a39
 *
Packit 6c0a39
 * @returns SSH_OK    on success
Packit 6c0a39
 *          SSH_ERROR on failure
Packit 6c0a39
 */
Packit 6c0a39
int ssh_event_add_poll(ssh_event event, ssh_poll_handle p)
Packit 6c0a39
{
Packit 6c0a39
    return ssh_poll_ctx_add(event->ctx, p);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief remove a poll handle to the event.
Packit 6c0a39
 *
Packit 6c0a39
 * @param   event     the ssh_event
Packit 6c0a39
 *
Packit 6c0a39
 * @param   p         the poll handle
Packit 6c0a39
 */
Packit 6c0a39
void ssh_event_remove_poll(ssh_event event, ssh_poll_handle p)
Packit 6c0a39
{
Packit 6c0a39
    ssh_poll_ctx_remove(event->ctx,p);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief remove the poll handle from session and assign them to a event,
Packit 6c0a39
 * when used in blocking mode.
Packit 6c0a39
 *
Packit 6c0a39
 * @param event     The ssh_event object
Packit 6c0a39
 * @param session   The session to add to the event.
Packit 6c0a39
 *
Packit 6c0a39
 * @returns SSH_OK      on success
Packit 6c0a39
 *          SSH_ERROR   on failure
Packit 6c0a39
 */
Packit 6c0a39
int ssh_event_add_session(ssh_event event, ssh_session session) {
Packit 6c0a39
    ssh_poll_handle p;
Packit 6c0a39
#ifdef WITH_SERVER
Packit 6c0a39
    struct ssh_iterator *iterator;
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
    if(event == NULL || event->ctx == NULL || session == NULL) {
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
    if(session->default_poll_ctx == NULL) {
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
    while (session->default_poll_ctx->polls_used > 0) {
Packit 6c0a39
        p = session->default_poll_ctx->pollptrs[0];
Packit 6c0a39
        /*
Packit 6c0a39
         * ssh_poll_ctx_remove() decrements
Packit 6c0a39
         * session->default_poll_ctx->polls_used
Packit 6c0a39
         */
Packit 6c0a39
        ssh_poll_ctx_remove(session->default_poll_ctx, p);
Packit 6c0a39
        ssh_poll_ctx_add(event->ctx, p);
Packit 6c0a39
        /* associate the pollhandler with a session so we can put it back
Packit 6c0a39
         * at ssh_event_free()
Packit 6c0a39
         */
Packit 6c0a39
        p->session = session;
Packit 6c0a39
    }
Packit 6c0a39
#ifdef WITH_SERVER
Packit 6c0a39
    iterator = ssh_list_get_iterator(event->sessions);
Packit 6c0a39
    while(iterator != NULL) {
Packit 6c0a39
        if((ssh_session)iterator->data == session) {
Packit 6c0a39
            /* allow only one instance of this session */
Packit 6c0a39
            return SSH_OK;
Packit 6c0a39
        }
Packit 6c0a39
        iterator = iterator->next;
Packit 6c0a39
    }
Packit 6c0a39
    if(ssh_list_append(event->sessions, session) == SSH_ERROR) {
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
#endif
Packit 6c0a39
    return SSH_OK;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief Add a connector to the SSH event loop
Packit 6c0a39
 *
Packit 6c0a39
 * @param[in] event The SSH event loop
Packit 6c0a39
 *
Packit 6c0a39
 * @param[in] connector The connector object
Packit 6c0a39
 *
Packit 6c0a39
 * @return SSH_OK
Packit 6c0a39
 *
Packit 6c0a39
 * @return SSH_ERROR in case of error
Packit 6c0a39
 */
Packit 6c0a39
int ssh_event_add_connector(ssh_event event, ssh_connector connector){
Packit 6c0a39
    return ssh_connector_set_event(connector, event);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief Poll all the sockets and sessions associated through an event object.i
Packit 6c0a39
 *
Packit 6c0a39
 * If any of the events are set after the poll, the call back functions of the
Packit 6c0a39
 * sessions or sockets will be called.
Packit 6c0a39
 * This function should be called once within the programs main loop.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  event        The ssh_event object to poll.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  timeout      An upper limit on the time for which the poll will
Packit 6c0a39
 *                      block, in milliseconds. Specifying a negative value
Packit 6c0a39
 *                      means an infinite timeout. This parameter is passed to
Packit 6c0a39
 *                      the poll() function.
Packit 6c0a39
 * @returns SSH_OK      on success.
Packit 6c0a39
 *          SSH_ERROR   Error happened during the poll.
Packit 6c0a39
 *          SSH_AGAIN   Timeout occured
Packit 6c0a39
 */
Packit 6c0a39
int ssh_event_dopoll(ssh_event event, int timeout) {
Packit 6c0a39
    int rc;
Packit 6c0a39
Packit 6c0a39
    if(event == NULL || event->ctx == NULL) {
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
    rc = ssh_poll_ctx_dopoll(event->ctx, timeout);
Packit 6c0a39
    return rc;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Remove a socket fd from an event context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  event        The ssh_event object.
Packit 6c0a39
 * @param  fd           The fd to remove.
Packit 6c0a39
 *
Packit 6c0a39
 * @returns SSH_OK      on success
Packit 6c0a39
 *          SSH_ERROR   on failure
Packit 6c0a39
 */
Packit 6c0a39
int ssh_event_remove_fd(ssh_event event, socket_t fd) {
Packit 6c0a39
    register size_t i, used;
Packit 6c0a39
    int rc = SSH_ERROR;
Packit 6c0a39
Packit 6c0a39
    if(event == NULL || event->ctx == NULL) {
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    used = event->ctx->polls_used;
Packit 6c0a39
    for (i = 0; i < used; i++) {
Packit 6c0a39
        if(fd == event->ctx->pollfds[i].fd) {
Packit 6c0a39
            ssh_poll_handle p = event->ctx->pollptrs[i];
Packit 6c0a39
            if (p->session != NULL){
Packit 6c0a39
            	/* we cannot free that handle, it's owned by its session */
Packit 6c0a39
            	continue;
Packit 6c0a39
            }
Packit 6c0a39
            if (p->cb == ssh_event_fd_wrapper_callback) {
Packit 6c0a39
                struct ssh_event_fd_wrapper *pw = p->cb_data;
Packit 6c0a39
                SAFE_FREE(pw);
Packit 6c0a39
            }
Packit 6c0a39
Packit 6c0a39
            /*
Packit 6c0a39
             * The free function calls ssh_poll_ctx_remove() and decrements
Packit 6c0a39
             * event->ctx->polls_used.
Packit 6c0a39
             */
Packit 6c0a39
            ssh_poll_free(p);
Packit 6c0a39
            rc = SSH_OK;
Packit 6c0a39
Packit 6c0a39
            /* restart the loop */
Packit 6c0a39
            used = event->ctx->polls_used;
Packit 6c0a39
            i = 0;
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    return rc;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Remove a session object from an event context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  event        The ssh_event object.
Packit 6c0a39
 * @param  session      The session to remove.
Packit 6c0a39
 *
Packit 6c0a39
 * @returns SSH_OK      on success
Packit 6c0a39
 *          SSH_ERROR   on failure
Packit 6c0a39
 */
Packit 6c0a39
int ssh_event_remove_session(ssh_event event, ssh_session session) {
Packit 6c0a39
    ssh_poll_handle p;
Packit 6c0a39
    register size_t i, used;
Packit 6c0a39
    int rc = SSH_ERROR;
Packit 6c0a39
#ifdef WITH_SERVER
Packit 6c0a39
    struct ssh_iterator *iterator;
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
    if(event == NULL || event->ctx == NULL || session == NULL) {
Packit 6c0a39
        return SSH_ERROR;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    used = event->ctx->polls_used;
Packit 6c0a39
    for(i = 0; i < used; i++) {
Packit 6c0a39
    	p = event->ctx->pollptrs[i];
Packit 6c0a39
    	if(p->session == session){
Packit 6c0a39
            /*
Packit 6c0a39
             * ssh_poll_ctx_remove() decrements
Packit 6c0a39
             * event->ctx->polls_used
Packit 6c0a39
             */
Packit 6c0a39
            ssh_poll_ctx_remove(event->ctx, p);
Packit 6c0a39
            p->session = NULL;
Packit 6c0a39
            ssh_poll_ctx_add(session->default_poll_ctx, p);
Packit 6c0a39
            rc = SSH_OK;
Packit 6c0a39
            /*
Packit 6c0a39
             * Restart the loop!
Packit 6c0a39
             * A session can initially have two pollhandlers.
Packit 6c0a39
             */
Packit 6c0a39
            used = event->ctx->polls_used;
Packit 6c0a39
            i = 0;
Packit 6c0a39
Packit 6c0a39
        }
Packit 6c0a39
    }
Packit 6c0a39
#ifdef WITH_SERVER
Packit 6c0a39
    iterator = ssh_list_get_iterator(event->sessions);
Packit 6c0a39
    while(iterator != NULL) {
Packit 6c0a39
        if((ssh_session)iterator->data == session) {
Packit 6c0a39
            ssh_list_remove(event->sessions, iterator);
Packit 6c0a39
            /* there should be only one instance of this session */
Packit 6c0a39
            break;
Packit 6c0a39
        }
Packit 6c0a39
        iterator = iterator->next;
Packit 6c0a39
    }
Packit 6c0a39
#endif
Packit 6c0a39
Packit 6c0a39
    return rc;
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/** @brief Remove a connector from an event context
Packit 6c0a39
 * @param[in] event The ssh_event object.
Packit 6c0a39
 * @param[in] connector connector object to remove
Packit 6c0a39
 * @return SSH_OK on success
Packit 6c0a39
 * @return SSH_ERROR on failure
Packit 6c0a39
 */
Packit 6c0a39
int ssh_event_remove_connector(ssh_event event, ssh_connector connector){
Packit 6c0a39
    (void)event;
Packit 6c0a39
    return ssh_connector_remove_event(connector);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/**
Packit 6c0a39
 * @brief  Free an event context.
Packit 6c0a39
 *
Packit 6c0a39
 * @param  event        The ssh_event object to free.
Packit 6c0a39
 *                      Note: you have to manually remove sessions and socket
Packit 6c0a39
 *                      fds before freeing the event object.
Packit 6c0a39
 *
Packit 6c0a39
 */
Packit 6c0a39
void ssh_event_free(ssh_event event)
Packit 6c0a39
{
Packit 6c0a39
    size_t used, i;
Packit 6c0a39
    ssh_poll_handle p;
Packit 6c0a39
Packit 6c0a39
    if(event == NULL) {
Packit 6c0a39
        return;
Packit 6c0a39
    }
Packit 6c0a39
Packit 6c0a39
    if (event->ctx != NULL) {
Packit 6c0a39
        used = event->ctx->polls_used;
Packit 6c0a39
        for(i = 0; i < used; i++) {
Packit 6c0a39
            p = event->ctx->pollptrs[i];
Packit 6c0a39
            if (p->session != NULL) {
Packit 6c0a39
                ssh_poll_ctx_remove(event->ctx, p);
Packit 6c0a39
                ssh_poll_ctx_add(p->session->default_poll_ctx, p);
Packit 6c0a39
                p->session = NULL;
Packit 6c0a39
                used = 0;
Packit 6c0a39
            }
Packit 6c0a39
        }
Packit 6c0a39
Packit 6c0a39
        ssh_poll_ctx_free(event->ctx);
Packit 6c0a39
    }
Packit 6c0a39
#ifdef WITH_SERVER
Packit 6c0a39
    if(event->sessions != NULL) {
Packit 6c0a39
        ssh_list_free(event->sessions);
Packit 6c0a39
    }
Packit 6c0a39
#endif
Packit 6c0a39
    free(event);
Packit 6c0a39
}
Packit 6c0a39
Packit 6c0a39
/** @} */