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_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); } }
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 ssize_t rb_ssl_read_or_write(rw_t r_or_w, rb_fde_t *F, void *rbuf, const void *wbuf, size_t count) { int ret; unsigned long err; SSL *ssl = F->ssl; switch(r_or_w) { case DOREAD: ret = SSL_read(ssl, rbuf, (int)count); break; case DOWRITE: ret = SSL_write(ssl, wbuf, (int)count); break; } if(ret < 0) { switch (SSL_get_error(ssl, ret)) { case SSL_ERROR_WANT_READ: errno = EAGAIN; return RB_RW_SSL_NEED_READ; case SSL_ERROR_WANT_WRITE: errno = EAGAIN; return RB_RW_SSL_NEED_WRITE; case SSL_ERROR_ZERO_RETURN: return 0; case SSL_ERROR_SYSCALL: err = get_last_err(); if(err == 0) { F->sslerr.ssl_errno = 0; return RB_RW_IO_ERROR; } break; default: err = get_last_err(); break; } F->sslerr.ssl_errno = err; if(err > 0) { errno = EIO; /* not great but... */ return RB_RW_SSL_ERROR; } return RB_RW_IO_ERROR; } return (ssize_t)ret; }
void rb_ssl_accept_setup(rb_fde_t *F, rb_fde_t *new_F, struct sockaddr *st, rb_socklen_t addrlen) { if(new_F->sctx == NULL) return; new_F->type |= RB_FD_SSL; new_F->ssl = SSL_new(new_F->sctx->ssl_ctx); if(new_F->ssl == NULL) { new_F->sslerr.ssl_errno = get_last_err(); rb_lib_log("rb_ssl_accept_setup: SSL_new() fails: %s", ERR_error_string(new_F->sslerr.ssl_errno, NULL)); new_F->accept->callback(new_F, RB_ERROR_SSL, NULL, 0, new_F->accept->data); return; } new_F->accept = rb_malloc(sizeof(struct acceptdata)); new_F->accept->callback = F->accept->callback; new_F->accept->data = F->accept->data; rb_settimeout(new_F, 10, rb_ssl_timeout, NULL); memcpy(&new_F->accept->S, st, addrlen); new_F->accept->addrlen = addrlen; SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F)); rb_setup_ssl_cb(new_F); rb_ssl_accept_common(new_F); }
void rb_ssl_start_accepted(rb_fde_t *new_F, ACCB * cb, void *data, int timeout) { if(new_F->sctx == NULL) return; new_F->type |= RB_FD_SSL; new_F->ssl = SSL_new(new_F->sctx->ssl_ctx); if(new_F->ssl == NULL) { new_F->sslerr.ssl_errno = get_last_err(); rb_lib_log("rb_ssl_start_accepted: SSL_new() fails: %s", ERR_error_string(new_F->sslerr.ssl_errno, NULL)); cb(new_F, RB_ERROR_SSL, NULL, 0, data); return; } new_F->accept = rb_malloc(sizeof(struct acceptdata)); new_F->accept->callback = cb; new_F->accept->data = data; rb_settimeout(new_F, timeout, rb_ssl_timeout, NULL); new_F->accept->addrlen = 0; SSL_set_fd((SSL *) new_F->ssl, rb_get_fd(new_F)); rb_setup_ssl_cb(new_F); rb_ssl_accept_common(new_F); }
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_shutdown(rb_fde_t *F) { int i; if(F == NULL || F->ssl == NULL) return; SSL_set_shutdown((SSL *) F->ssl, SSL_RECEIVED_SHUTDOWN); for(i = 0; i < 4; i++) { if(SSL_shutdown((SSL *) F->ssl)) break; } get_last_err(); SSL_free((SSL *) F->ssl); }