Example #1
0
static void
rb_read_timerfd(rb_fde_t *F, void *data)
{
	struct ev_entry *event = (struct ev_entry *)data;
	int retlen;
	uint64_t count;

	if(event == NULL)
	{
		rb_close(F);
		return;
	}

	retlen = rb_read(F, &count, sizeof(count));

	if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
	{
		rb_close(F);
		rb_lib_log("rb_read_timerfd: timerfd[%s] closed on error: %s", event->name,
			   strerror(errno));
		return;
	}
	rb_setselect(F, RB_SELECT_READ, rb_read_timerfd, event);
	rb_run_event(event);
}
Example #2
0
static ssize_t
rb_ssl_read_or_write(int r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count)
{
    ssize_t ret;
    gnutls_session_t *ssl = F->ssl;

    if (r_or_w == 0)
        ret = gnutls_record_recv(*ssl, rbuf, count);
    else
        ret = gnutls_record_send(*ssl, wbuf, count);

    if (ret < 0)
    {
        switch (ret)
        {
        case GNUTLS_E_AGAIN:
        case GNUTLS_E_INTERRUPTED:
            if (rb_ignore_errno(errno))
            {
                if (gnutls_record_get_direction(*ssl) == 0)
                    return RB_RW_SSL_NEED_READ;
                else
                    return RB_RW_SSL_NEED_WRITE;
                break;
            }
        default:
            F->ssl_errno = ret;
            errno = EIO;
            return RB_RW_IO_ERROR;
        }
    }
    return ret;
}
Example #3
0
static int
do_ssl_handshake(rb_fde_t *F, PF * callback, void *data)
{
	int ret;
	int flags;

	ret = mbedtls_ssl_handshake(SSL_P(F));
	if(ret < 0)
	{
		if (ret == -1 && rb_ignore_errno(errno))
			ret = MBEDTLS_ERR_SSL_WANT_READ;

		if((ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE))
		{
			if(ret == MBEDTLS_ERR_SSL_WANT_READ)
				flags = RB_SELECT_READ;
			else
				flags = RB_SELECT_WRITE;
			rb_setselect(F, flags, callback, data);
			return 0;
		}

		F->sslerr.ssl_errno = ret;
		return -1;
	}
	return 1;		/* handshake is finished..go about life */
}
Example #4
0
static void
rb_ssl_accept_common(rb_fde_t *new_F)
{
	int ssl_err;
	if((ssl_err = SSL_accept((SSL *) new_F->ssl)) <= 0)
	{
		switch (ssl_err = SSL_get_error((SSL *) new_F->ssl, ssl_err))
		{
		case SSL_ERROR_SYSCALL:
			if(rb_ignore_errno(errno))
		case SSL_ERROR_WANT_READ:
		case SSL_ERROR_WANT_WRITE:
				{
					new_F->ssl_errno = get_last_err();
					rb_setselect(new_F, RB_SELECT_READ | RB_SELECT_WRITE,
						     rb_ssl_tryaccept, NULL);
					return;
				}
		default:
			new_F->ssl_errno = get_last_err();
			new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data);
			return;
		}
	}
	else
	{
		rb_ssl_tryaccept(new_F, NULL);
	}
}
Example #5
0
static void
rb_ssl_tryconn(rb_fde_t *F, int status, void *data)
{
    struct ssl_connect *sconn = data;
    int ssl_err;
    if(status != RB_OK) {
        rb_ssl_connect_realcb(F, status, sconn);
        return;
    }

    F->type |= RB_FD_SSL;
    F->ssl = SSL_new(ssl_client_ctx);
    SSL_set_fd((SSL *) F->ssl, F->fd);
    rb_setup_ssl_cb(F);
    rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
    if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0) {
        switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err)) {
        case SSL_ERROR_SYSCALL:
            if(rb_ignore_errno(errno))
            case SSL_ERROR_WANT_READ:
        case SSL_ERROR_WANT_WRITE: {
            F->ssl_errno = get_last_err();
            rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
                         rb_ssl_tryconn_cb, sconn);
            return;
        }
        default:
            F->ssl_errno = get_last_err();
            rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
            return;
        }
    } else {
        rb_ssl_connect_realcb(F, RB_OK, sconn);
    }
}
Example #6
0
static void
rb_ssl_tryconn_cb(rb_fde_t *F, void *data)
{
	struct ssl_connect *sconn = data;
	int ssl_err;
	if(!SSL_is_init_finished((SSL *) F->ssl))
	{
		if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
		{
			switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
			{
			case SSL_ERROR_SYSCALL:
				if(rb_ignore_errno(errno))
			case SSL_ERROR_WANT_READ:
			case SSL_ERROR_WANT_WRITE:
					{
						F->ssl_errno = get_last_err();
						rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
							     rb_ssl_tryconn_cb, sconn);
						return;
					}
			default:
				F->ssl_errno = get_last_err();
				rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
				return;
			}
		}
		else
		{
			rb_ssl_connect_realcb(F, RB_OK, sconn);
		}
	}
}
Example #7
0
void
rb_ssl_start_connected(rb_fde_t *F, CNCB * callback, void *data, int timeout)
{
	ssl_connect_t *sconn;
	int ssl_err;
	if(F == NULL)
		return;

	sconn = rb_malloc(sizeof(ssl_connect_t));
	sconn->data = data;
	sconn->callback = callback;
	sconn->timeout = timeout;
	F->connect = rb_malloc(sizeof(struct conndata));
	F->connect->callback = callback;
	F->connect->data = data;
	F->type |= RB_FD_SSL;
	F->ssl = SSL_new(F->sctx->ssl_ctx);

        if(F->ssl == NULL)
        {
                F->sslerr.ssl_errno = get_last_err();
                rb_lib_log("rb_ssl_start_Connected: SSL_new() fails: %s", ERR_error_string(F->sslerr.ssl_errno, NULL));
                
                rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
                return;
        }

	SSL_set_fd((SSL *) F->ssl, F->fd);
	rb_setup_ssl_cb(F);
	rb_settimeout(F, sconn->timeout, rb_ssl_tryconn_timeout_cb, sconn);
	if((ssl_err = SSL_connect((SSL *) F->ssl)) <= 0)
	{
		switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err))
		{
		case SSL_ERROR_SYSCALL:
			if(rb_ignore_errno(errno))
		case SSL_ERROR_WANT_READ:
		case SSL_ERROR_WANT_WRITE:
				{
					F->sslerr.ssl_errno = get_last_err();
					rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE,
						     rb_ssl_tryconn_cb, sconn);
					return;
				}
		default:
			F->sslerr.ssl_errno = get_last_err();
			rb_ssl_connect_realcb(F, RB_ERROR_SSL, sconn);
			return;
		}
	}
	else
	{
		rb_ssl_connect_realcb(F, RB_OK, sconn);
	}
}
Example #8
0
int
rb_select_select(long delay)
{
	int num;
	int fd;
	PF *hdl;
	rb_fde_t *F;
	struct timeval to;
	/* Copy over the read/write sets so we don't have to rebuild em */
	memcpy(&tmpreadfds, &select_readfds, sizeof(fd_set));
	memcpy(&tmpwritefds, &select_writefds, sizeof(fd_set));
	for (;;) {
		to.tv_sec = 0;
		to.tv_usec = delay * 1000;
		num = select(rb_maxfd + 1, &tmpreadfds, &tmpwritefds, NULL, &to);
		if (num >= 0)
			break;
		if (rb_ignore_errno(errno))
			continue;
		rb_set_time();
		/* error! */
		return -1;
		/* NOTREACHED */
	}
	rb_set_time();
	if (num == 0)
		return 0;
	/* XXX we *could* optimise by falling out after doing num fds ... */
	for (fd = 0; fd < rb_maxfd + 1; fd++) {
		F = rb_find_fd(fd);
		if (F == NULL)
			continue;
		if (FD_ISSET(fd, &tmpreadfds)) {
			hdl = F->read_handler;
			F->read_handler = NULL;
			if (hdl)
				hdl(F, F->read_data);
		}
		if (!IsFDOpen(F))
			continue;	/* Read handler closed us..go on */
		if (FD_ISSET(fd, &tmpwritefds)) {
			hdl = F->write_handler;
			F->write_handler = NULL;
			if (hdl)
				hdl(F, F->write_data);
		}
		if (F->read_handler == NULL)
			select_update_selectfds(F, RB_SELECT_READ, NULL);
		if (F->write_handler == NULL)
			select_update_selectfds(F, RB_SELECT_WRITE, NULL);
	}
	return 0;
}
Example #9
0
static int
rb_ssl_read_cb(void *opaque, unsigned char *buf, size_t size)
{
	int ret;
	rb_fde_t *F = opaque;

	ret = read(F->fd, buf, size);
	if (ret < 0 && rb_ignore_errno(errno))
		return MBEDTLS_ERR_SSL_WANT_READ;

	return ret;
}
Example #10
0
static int
rb_ssl_write_cb(void *opaque, const unsigned char *buf, size_t size)
{
	rb_fde_t *F = opaque;
	int ret;

	ret = write(F->fd, buf, size);
	if (ret < 0 && rb_ignore_errno(errno))
		return MBEDTLS_ERR_SSL_WANT_WRITE;

	return ret;
}
Example #11
0
static void
signalfd_handler(rb_fde_t *F, void *data)
{
	static struct our_signalfd_siginfo fdsig[SIGFDIOV_COUNT];
	static struct iovec iov[SIGFDIOV_COUNT];
	struct ev_entry *ev;
	int ret, x;

	for(x = 0; x < SIGFDIOV_COUNT; x++)
	{
		iov[x].iov_base = &fdsig[x];
		iov[x].iov_len = sizeof(struct our_signalfd_siginfo);
	}

	while(1)
	{
		ret = readv(rb_get_fd(F), iov, SIGFDIOV_COUNT);

		if(ret == 0 || (ret < 0 && !rb_ignore_errno(errno)))
		{
			rb_close(F);
			rb_epoll_init_event();
			return;
		}

		if(ret < 0)
		{
			rb_setselect(F, RB_SELECT_READ, signalfd_handler, NULL);
			return;
		}
		for(x = 0; x < ret / (int)sizeof(struct our_signalfd_siginfo); x++)
		{
#if __WORDSIZE == 32 && defined(__sparc__)
			uint32_t *q = (uint32_t *)&fdsig[x].svptr;
			ev = (struct ev_entry *)q[0];
#else
			ev = (struct ev_entry *)(uintptr_t)(fdsig[x].svptr);

#endif
			if(ev == NULL)
				continue;
			rb_run_event(ev);
		}
	}
}
Example #12
0
static void
rb_helper_write_sendq(rb_fde_t *F, void *helper_ptr)
{
	rb_helper *helper = helper_ptr;
	int retlen;

	if(rb_linebuf_len(&helper->sendq) > 0)
	{
		while((retlen = rb_linebuf_flush(F, &helper->sendq)) > 0)
			;
		if(retlen == 0 || (retlen < 0 && !rb_ignore_errno(errno)))
		{
			rb_helper_restart(helper);
			return;
		}
	}

	if(rb_linebuf_len(&helper->sendq) > 0)
		rb_setselect(helper->ofd, RB_SELECT_WRITE, rb_helper_write_sendq, helper);
}
Example #13
0
static void
rb_helper_read_cb(rb_fde_t *F, void *data)
{
    rb_helper *helper = (rb_helper *)data;
    char buf[4096];
    ssize_t length;
    if(helper == NULL)
        return;

    while((length = rb_read(helper->ifd, buf, sizeof(buf))) > 0)
    {
        rb_linebuf_parse(helper->recvq, buf, (size_t)length, 0);
        helper->read_cb(helper);
    }
    if(length == 0 || (length < 0 && !rb_ignore_errno(errno)))
    {
        rb_helper_restart(helper);
        return;
    }

    rb_setselect(helper->ifd, RB_SELECT_READ, rb_helper_read_cb, helper);
}
Example #14
0
static int
do_ssl_handshake(rb_fde_t *F, PF * callback)
{
    int ret;
    int flags;

    ret = gnutls_handshake(SSL_P(F));
    if (ret < 0)
    {
        if ((ret == GNUTLS_E_INTERRUPTED && rb_ignore_errno(errno)) || ret == GNUTLS_E_AGAIN)
        {
            if (gnutls_record_get_direction(SSL_P(F)) == 0)
                flags = RB_SELECT_READ;
            else
                flags = RB_SELECT_WRITE;
            rb_setselect(F, flags, callback, NULL);
            return 0;
        }
        F->ssl_errno = ret;
        return -1;
    }
    return 1;       /* handshake is finished..go about life */
}
Example #15
0
int
rb_select_poll(long delay)
{
    int num;
    int fd;
    int ci;
    PF *hdl;
    void *data;
    struct pollfd *pfd;
    int revents;

    num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, delay);
    rb_set_time();
    if(num < 0) {
        if(!rb_ignore_errno(errno))
            return RB_OK;
        else
            return RB_ERROR;
    }
    if(num == 0)
        return RB_OK;

    /* XXX we *could* optimise by falling out after doing num fds ... */
    for(ci = 0; ci < pollfd_list.maxindex + 1; ci++) {
        rb_fde_t *F;
        pfd = &pollfd_list.pollfds[ci];

        revents = pfd->revents;
        fd = pfd->fd;
        if(revents == 0 || fd == -1)
            continue;

        F = rb_find_fd(fd);
        if(F == NULL)
            continue;

        if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
            hdl = F->read_handler;
            data = F->read_data;
            F->read_handler = NULL;
            F->read_data = NULL;
            if(hdl)
                hdl(F, data);
        }

        if(IsFDOpen(F) && (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))) {
            hdl = F->write_handler;
            data = F->write_data;
            F->write_handler = NULL;
            F->write_data = NULL;
            if(hdl)
                hdl(F, data);
        }

        if(F->read_handler == NULL)
            rb_setselect_poll(F, RB_SELECT_READ, NULL, NULL);
        if(F->write_handler == NULL)
            rb_setselect_poll(F, RB_SELECT_WRITE, NULL, NULL);

    }
    return 0;
}
Example #16
0
/* int rb_select(long delay)
 * Input: The maximum time to delay.
 * Output: Returns -1 on error, 0 on success.
 * Side-effects: Deregisters future interest in IO and calls the handlers
 *               if an event occurs for an FD.
 * Comments: Check all connections for new connections and input data
 * that is to be processed. Also check for connections with data queued
 * and whether we can write it out.
 * Called to do the new-style IO, courtesy of squid (like most of this
 * new IO code). This routine handles the stuff we've hidden in
 * rb_setselect and fd_table[] and calls callbacks for IO ready
 * events.
 */
int
rb_select_sigio(long delay)
{
    int num = 0;
    int revents = 0;
    int sig;
    int fd;
    int ci;
    PF *hdl;
    rb_fde_t *F;
    void *data;
    siginfo_t si;

    struct timespec timeout;
    if(rb_sigio_supports_event() || delay >= 0) {
        timeout.tv_sec = (delay / 1000);
        timeout.tv_nsec = (delay % 1000) * 1000000;
    }

    for(;;) {
        if(!sigio_is_screwed) {
            if(can_do_event || delay < 0) {
                sig = sigwaitinfo(&our_sigset, &si);
            } else
                sig = sigtimedwait(&our_sigset, &si, &timeout);

            if(sig > 0) {

                if(sig == SIGIO) {
                    rb_lib_log
                    ("Kernel RT Signal queue overflowed.  Is ulimit -i too small(or perhaps /proc/sys/kernel/rtsig-max on old kernels)");
                    sigio_is_screwed = 1;
                    break;
                }
#ifdef SIGIO_SCHED_EVENT
                if(sig == RTSIGTIM && can_do_event) {
                    struct ev_entry *ev = (struct ev_entry *)si.si_ptr;
                    if(ev == NULL)
                        continue;
                    rb_run_event(ev);
                    continue;
                }
#endif
                fd = si.si_fd;
                pollfd_list.pollfds[fd].revents |= si.si_band;
                revents = pollfd_list.pollfds[fd].revents;
                num++;
                F = rb_find_fd(fd);
                if(F == NULL)
                    continue;

                if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
                    hdl = F->read_handler;
                    data = F->read_data;
                    F->read_handler = NULL;
                    F->read_data = NULL;
                    if(hdl)
                        hdl(F, data);
                }

                if(revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR)) {
                    hdl = F->write_handler;
                    data = F->write_data;
                    F->write_handler = NULL;
                    F->write_data = NULL;
                    if(hdl)
                        hdl(F, data);
                }
            } else
                break;

        } else
            break;
    }

    if(!sigio_is_screwed) {	/* We don't need to proceed */
        rb_set_time();
        return 0;
    }

    signal(RTSIGIO, SIG_IGN);
    signal(RTSIGIO, SIG_DFL);
    sigio_is_screwed = 0;


    num = poll(pollfd_list.pollfds, pollfd_list.maxindex + 1, delay);
    rb_set_time();
    if(num < 0) {
        if(!rb_ignore_errno(errno))
            return RB_OK;
        else
            return RB_ERROR;
    }
    if(num == 0)
        return RB_OK;

    /* XXX we *could* optimise by falling out after doing num fds ... */
    for(ci = 0; ci < pollfd_list.maxindex + 1; ci++) {
        if(((revents = pollfd_list.pollfds[ci].revents) == 0)
                || (pollfd_list.pollfds[ci].fd) == -1)
            continue;
        fd = pollfd_list.pollfds[ci].fd;
        F = rb_find_fd(fd);
        if(F == NULL)
            continue;
        if(revents & (POLLRDNORM | POLLIN | POLLHUP | POLLERR)) {
            hdl = F->read_handler;
            data = F->read_data;
            F->read_handler = NULL;
            F->read_data = NULL;
            if(hdl)
                hdl(F, data);
        }

        if(IsFDOpen(F) && (revents & (POLLWRNORM | POLLOUT | POLLHUP | POLLERR))) {
            hdl = F->write_handler;
            data = F->write_data;
            F->write_handler = NULL;
            F->write_data = NULL;
            if(hdl)
                hdl(F, data);
        }
        if(F->read_handler == NULL)
            rb_setselect_sigio(F, RB_SELECT_READ, NULL, NULL);
        if(F->write_handler == NULL)
            rb_setselect_sigio(F, RB_SELECT_WRITE, NULL, NULL);

    }

    return 0;
}
Example #17
0
int
rb_select_devpoll(long delay)
{
	int num, i;
	struct pollfd pollfds[maxfd];
	struct dvpoll dopoll;

	do
	{
		for(;;)
		{
			dopoll.dp_timeout = delay;
			dopoll.dp_nfds = maxfd;
			dopoll.dp_fds = &pollfds[0];
			num = ioctl(dpfd, DP_POLL, &dopoll);
			if(num >= 0)
				break;
			if(rb_ignore_errno(errno))
				break;
			rb_set_time();
			return RB_ERROR;
		}

		rb_set_time();
		if(num == 0)
			continue;

		for(i = 0; i < num; i++)
		{
			int fd = dopoll.dp_fds[i].fd;
			PF *hdl = NULL;
			rb_fde_t *F = rb_find_fd(fd);
			if((dopoll.dp_fds[i].revents & (POLLRDNORM | POLLIN | POLLHUP |
							POLLERR))
			   && (dopoll.dp_fds[i].events & (POLLRDNORM | POLLIN)))
			{
				if((hdl = F->read_handler) != NULL)
				{
					F->read_handler = NULL;
					hdl(F, F->read_data);
					/*
					 * this call used to be with a NULL pointer, BUT
					 * in the devpoll case we only want to update the
					 * poll set *if* the handler changes state (active ->
					 * NULL or vice versa.)
					 */
					devpoll_update_events(F, RB_SELECT_READ, F->read_handler);
				}
			}

			if(!IsFDOpen(F))
				continue;	/* Read handler closed us..go on to do something more useful */
			if((dopoll.dp_fds[i].revents & (POLLWRNORM | POLLOUT | POLLHUP |
							POLLERR))
			   && (dopoll.dp_fds[i].events & (POLLWRNORM | POLLOUT)))
			{
				if((hdl = F->write_handler) != NULL)
				{
					F->write_handler = NULL;
					hdl(F, F->write_data);
					/* See above similar code in the read case */
					devpoll_update_events(F,
							      RB_SELECT_WRITE, F->write_handler);
				}

			}
		}
		return RB_OK;
	}
	while(0);
	/* XXX Get here, we broke! */
	return 0;
}
Example #18
0
int
rb_select_epoll(long delay)
{
	int num, i, flags, old_flags, op;
	struct epoll_event ep_event;
	int o_errno;
	void *data;

	num = epoll_wait(ep_info->ep, ep_info->pfd, ep_info->pfd_size, delay);

	/* save errno as rb_set_time() will likely clobber it */
	o_errno = errno;
	rb_set_time();
	errno = o_errno;

	if(num < 0 && !rb_ignore_errno(o_errno))
		return RB_ERROR;

	if(num <= 0)
		return RB_OK;

	for(i = 0; i < num; i++)
	{
		PF *hdl;
		rb_fde_t *F = ep_info->pfd[i].data.ptr;
		old_flags = F->pflags;
		if(ep_info->pfd[i].events & (EPOLLIN | EPOLLHUP | EPOLLERR))
		{
			hdl = F->read_handler;
			data = F->read_data;
			F->read_handler = NULL;
			F->read_data = NULL;
			if(hdl)
			{
				hdl(F, data);
			}
		}

		if(!IsFDOpen(F))
			continue;
		if(ep_info->pfd[i].events & (EPOLLOUT | EPOLLHUP | EPOLLERR))
		{
			hdl = F->write_handler;
			data = F->write_data;
			F->write_handler = NULL;
			F->write_data = NULL;

			if(hdl)
			{
				hdl(F, data);
			}
		}

		if(!IsFDOpen(F))
			continue;

		flags = 0;

		if(F->read_handler != NULL)
			flags |= EPOLLIN;
		if(F->write_handler != NULL)
			flags |= EPOLLOUT;

		if(old_flags != flags)
		{
			if(flags == 0)
				op = EPOLL_CTL_DEL;
			else
				op = EPOLL_CTL_MOD;
			F->pflags = ep_event.events = flags;
			ep_event.data.ptr = F;
			if(op == EPOLL_CTL_MOD || op == EPOLL_CTL_ADD)
				ep_event.events |= EPOLLET;

			if(epoll_ctl(ep_info->ep, op, F->fd, &ep_event) != 0)
			{
				rb_lib_log("rb_select_epoll(): epoll_ctl failed: %s",
					   strerror(errno));
			}
		}

	}
	return RB_OK;
}
Example #19
0
int
rb_select_kqueue(long delay)
{
	int num, i;
	struct timespec poll_time;
	struct timespec *pt;
	rb_fde_t *F;


	if(delay < 0)
	{
		pt = NULL;
	}
	else
	{
		pt = &poll_time;
		poll_time.tv_sec = delay / 1000;
		poll_time.tv_nsec = (delay % 1000) * 1000000;
	}

	for(;;)
	{
		num = kevent(kq, kqlst, kqoff, kqout, kqmax, pt);
		kqoff = 0;

		if(num >= 0)
			break;

		if(rb_ignore_errno(errno))
			break;

		rb_set_time();

		return RB_ERROR;

		/* NOTREACHED */
	}

	rb_set_time();

	if(num == 0)
		return RB_OK;	/* No error.. */

	for(i = 0; i < num; i++)
	{
		PF *hdl = NULL;

		if(kqout[i].flags & EV_ERROR)
		{
			errno = kqout[i].data;
			/* XXX error == bad! -- adrian */
			continue;	/* XXX! */
		}

		switch (kqout[i].filter)
		{

		case EVFILT_READ:
			F = kqout[i].udata;
			if((hdl = F->read_handler) != NULL)
			{
				F->read_handler = NULL;
				hdl(F, F->read_data);
			}

			break;

		case EVFILT_WRITE:
			F = kqout[i].udata;
			if((hdl = F->write_handler) != NULL)
			{
				F->write_handler = NULL;
				hdl(F, F->write_data);
			}
			break;
#if defined(EVFILT_TIMER)
		case EVFILT_TIMER:
			rb_run_event(kqout[i].udata);
			break;
#endif
		default:
			/* Bad! -- adrian */
			break;
		}
	}
	return RB_OK;
}