|
|
|
@ -36,12 +36,43 @@ typedef struct openssl_context openssl_context; |
|
|
|
|
|
|
|
|
|
struct openssl_connection_ctx { |
|
|
|
|
SSL *ssl; |
|
|
|
|
liConnection *con; |
|
|
|
|
|
|
|
|
|
int con_events; |
|
|
|
|
liJob con_handle_events_job; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct openssl_context { |
|
|
|
|
SSL_CTX *ssl_ctx; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static void openssl_con_handle_events_cb(liJob *job) { |
|
|
|
|
openssl_connection_ctx *conctx = LI_CONTAINER_OF(job, openssl_connection_ctx, con_handle_events_job); |
|
|
|
|
liConnection *con = conctx->con; |
|
|
|
|
|
|
|
|
|
connection_handle_io(con); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void openssl_io_cb(struct ev_loop *loop, ev_io *w, int revents) { |
|
|
|
|
liConnection *con = (liConnection*) w->data; |
|
|
|
|
openssl_connection_ctx *conctx = con->srv_sock_data; |
|
|
|
|
|
|
|
|
|
if (revents & EV_ERROR) { |
|
|
|
|
/* if this happens, we have a serious bug in the event handling */ |
|
|
|
|
VR_ERROR(con->mainvr, "%s", "EV_ERROR encountered, dropping connection!"); |
|
|
|
|
li_connection_error(con); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
con->can_read = TRUE; |
|
|
|
|
con->can_write = TRUE; |
|
|
|
|
|
|
|
|
|
/* disable all events; they will get reactivated later */ |
|
|
|
|
li_ev_io_set_events(loop, w, 0); |
|
|
|
|
|
|
|
|
|
li_job_now(&con->wrk->jobqueue, &conctx->con_handle_events_job); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static gboolean openssl_con_new(liConnection *con) { |
|
|
|
|
liServer *srv = con->srv; |
|
|
|
|
openssl_context *ctx = con->srv_sock->data; |
|
|
|
@ -50,6 +81,9 @@ static gboolean openssl_con_new(liConnection *con) { |
|
|
|
|
con->srv_sock_data = NULL; |
|
|
|
|
|
|
|
|
|
conctx->ssl = SSL_new(ctx->ssl_ctx); |
|
|
|
|
conctx->con = con; |
|
|
|
|
li_job_init(&conctx->con_handle_events_job, openssl_con_handle_events_cb); |
|
|
|
|
conctx->con_events = 0; |
|
|
|
|
|
|
|
|
|
if (NULL == conctx->ssl) { |
|
|
|
|
ERROR(srv, "SSL_new: %s", ERR_error_string(ERR_get_error(), NULL)); |
|
|
|
@ -66,6 +100,8 @@ static gboolean openssl_con_new(liConnection *con) { |
|
|
|
|
con->srv_sock_data = conctx; |
|
|
|
|
con->info.is_ssl = TRUE; |
|
|
|
|
|
|
|
|
|
ev_set_cb(&con->sock_watcher, openssl_io_cb); |
|
|
|
|
|
|
|
|
|
return TRUE; |
|
|
|
|
|
|
|
|
|
fail: |
|
|
|
@ -91,10 +127,22 @@ static void openssl_con_close(liConnection *con) { |
|
|
|
|
|
|
|
|
|
con->srv_sock_data = NULL; |
|
|
|
|
con->info.is_ssl = FALSE; |
|
|
|
|
li_job_clear(&conctx->con_handle_events_job); |
|
|
|
|
|
|
|
|
|
g_slice_free(openssl_connection_ctx, conctx); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void openssl_update_events(liConnection *con, int events) { |
|
|
|
|
openssl_connection_ctx *conctx = con->srv_sock_data; |
|
|
|
|
|
|
|
|
|
/* new events -> add them to socket watcher too */ |
|
|
|
|
if (0 != (events & ~conctx->con_events)) { |
|
|
|
|
li_ev_io_add_events(con->wrk->loop, &con->sock_watcher, events); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
conctx->con_events = events; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static liNetworkStatus openssl_con_write(liConnection *con, goffset write_max) { |
|
|
|
|
const ssize_t blocksize = 16*1024; /* 16k */ |
|
|
|
|
char *block_data; |
|
|
|
@ -134,7 +182,10 @@ static liNetworkStatus openssl_con_write(liConnection *con, goffset write_max) { |
|
|
|
|
|
|
|
|
|
switch ((ssl_r = SSL_get_error(conctx->ssl, r))) { |
|
|
|
|
case SSL_ERROR_WANT_READ: |
|
|
|
|
li_ev_io_add_events(con->wrk->loop, &con->sock_watcher, EV_READ); |
|
|
|
|
return LI_NETWORK_STATUS_WAIT_FOR_EVENT; |
|
|
|
|
case SSL_ERROR_WANT_WRITE: |
|
|
|
|
li_ev_io_add_events(con->wrk->loop, &con->sock_watcher, EV_WRITE); |
|
|
|
|
return LI_NETWORK_STATUS_WAIT_FOR_EVENT; |
|
|
|
|
case SSL_ERROR_SYSCALL: |
|
|
|
|
/* perhaps we have error waiting in our error-queue */ |
|
|
|
@ -242,9 +293,17 @@ static liNetworkStatus openssl_con_read(liConnection *con) { |
|
|
|
|
|
|
|
|
|
err = SSL_get_error(conctx->ssl, r); |
|
|
|
|
|
|
|
|
|
if (SSL_ERROR_WANT_READ == err || SSL_ERROR_WANT_WRITE == err) { |
|
|
|
|
switch (err) { |
|
|
|
|
case SSL_ERROR_WANT_READ: |
|
|
|
|
li_ev_io_add_events(con->wrk->loop, &con->sock_watcher, EV_READ); |
|
|
|
|
/* ignore requirement that we should pass the same buffer again */ |
|
|
|
|
return (len > 0) ? LI_NETWORK_STATUS_SUCCESS : LI_NETWORK_STATUS_WAIT_FOR_EVENT; |
|
|
|
|
case SSL_ERROR_WANT_WRITE: |
|
|
|
|
li_ev_io_add_events(con->wrk->loop, &con->sock_watcher, EV_WRITE); |
|
|
|
|
/* ignore requirement that we should pass the same buffer again */ |
|
|
|
|
return (len > 0) ? LI_NETWORK_STATUS_SUCCESS : LI_NETWORK_STATUS_WAIT_FOR_EVENT; |
|
|
|
|
default: |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
switch (err) { |
|
|
|
@ -361,6 +420,7 @@ static void openssl_setup_listen_cb(liServer *srv, int fd, gpointer data) { |
|
|
|
|
srv_sock->new_cb = openssl_con_new; |
|
|
|
|
srv_sock->close_cb = openssl_con_close; |
|
|
|
|
srv_sock->release_cb = openssl_sock_release; |
|
|
|
|
srv_sock->update_events_cb = openssl_update_events; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static gboolean openssl_setup(liServer *srv, liPlugin* p, liValue *val, gpointer userdata) { |
|
|
|
|