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_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); } } }
static void rb_ssl_tryaccept(rb_fde_t *F, void *data) { int ret; struct acceptdata *ad; lrb_assert(F->accept != NULL); ret = do_ssl_handshake(F, rb_ssl_tryaccept, NULL); /* do_ssl_handshake does the rb_setselect */ if(ret == 0) return; ad = F->accept; F->accept = NULL; rb_settimeout(F, 0, NULL, NULL); rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); if(ret > 0) ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); else ad->callback(F, RB_ERROR_SSL, NULL, 0, ad->data); rb_free(ad); }
static int rb_epoll_sched_event_timerfd(struct ev_entry *event, int when) { struct itimerspec ts; static char buf[FD_DESC_SZ + 8]; int fd; rb_fde_t *F; if((fd = timerfd_create(CLOCK_REALTIME, 0)) < 0) { rb_lib_log("timerfd_create: %s\n", strerror(errno)); return 0; } memset(&ts, 0, sizeof(ts)); ts.it_value.tv_sec = when; ts.it_value.tv_nsec = 0; if(event->frequency != 0) ts.it_interval = ts.it_value; if(timerfd_settime(fd, 0, &ts, NULL) < 0) { rb_lib_log("timerfd_settime: %s\n", strerror(errno)); close(fd); return 0; } rb_snprintf(buf, sizeof(buf), "timerfd: %s", event->name); F = rb_open(fd, RB_FD_UNKNOWN, buf); rb_set_nb(F); event->comm_ptr = F; rb_setselect(F, RB_SELECT_READ, rb_read_timerfd, event); return 1; }
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_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_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 void rb_ssl_tryaccept(rb_fde_t *F, void *data) { int ssl_err; lrb_assert(F->accept != NULL); int flags; struct acceptdata *ad; if(!SSL_is_init_finished((SSL *) F->ssl)) { if((ssl_err = SSL_accept((SSL *) F->ssl)) <= 0) { switch (ssl_err = SSL_get_error((SSL *) F->ssl, ssl_err)) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: if(ssl_err == SSL_ERROR_WANT_WRITE) flags = RB_SELECT_WRITE; else flags = RB_SELECT_READ; F->ssl_errno = get_last_err(); rb_setselect(F, flags, rb_ssl_tryaccept, NULL); break; case SSL_ERROR_SYSCALL: F->accept->callback(F, RB_ERROR, NULL, 0, F->accept->data); break; default: F->ssl_errno = get_last_err(); F->accept->callback(F, RB_ERROR_SSL, NULL, 0, F->accept->data); break; } return; } } rb_settimeout(F, 0, NULL, NULL); rb_setselect(F, RB_SELECT_READ | RB_SELECT_WRITE, NULL, NULL); ad = F->accept; F->accept = NULL; ad->callback(F, RB_OK, (struct sockaddr *)&ad->S, ad->addrlen, ad->data); rb_free(ad); }
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); } }
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 */ }