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); }
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; }
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 */ }
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); } }
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); } }
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); } } }
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); } }
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; }
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; }
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; }
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); } } }
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); }
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); }
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 */ }
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; }
/* 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; }
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; }
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; }
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; }