From 9012ead72c9a0d94c30c09ab79f78b32b32fbf9d Mon Sep 17 00:00:00 2001 From: Unbit Date: Fri, 24 Oct 2014 11:49:18 +0200 Subject: [PATCH] backported https fix for ssl shutdown --- plugins/corerouter/corerouter.c | 15 ++++++++---- plugins/corerouter/cr.h | 3 +++ plugins/http/https.c | 42 +++++++++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/plugins/corerouter/corerouter.c b/plugins/corerouter/corerouter.c index 1f869557..bd0a68af 100644 --- a/plugins/corerouter/corerouter.c +++ b/plugins/corerouter/corerouter.c @@ -84,7 +84,13 @@ void uwsgi_cr_peer_reset(struct corerouter_peer *peer) { } // destroy a peer -void uwsgi_cr_peer_del(struct corerouter_peer *peer) { +int uwsgi_cr_peer_del(struct corerouter_peer *peer) { + // first of all check if we need to run a flush procedure + if (peer->flush && !peer->is_flushing) { + peer->is_flushing = 1; + // on success, suspend the execution + if (peer->flush(peer) >= 0) return -1; + } struct corerouter_peer *prev = peer->prev; struct corerouter_peer *next = peer->next; @@ -111,6 +117,7 @@ void uwsgi_cr_peer_del(struct corerouter_peer *peer) { uwsgi_buffer_destroy(peer->out); } free(peer); + return 0; } void uwsgi_opt_corerouter(char *opt, char *value, void *cr) { @@ -383,7 +390,7 @@ void corerouter_close_peer(struct uwsgi_corerouter *ucr, struct corerouter_peer } end: - uwsgi_cr_peer_del(peer); + if (uwsgi_cr_peer_del(peer) < 0) return; if (peer == cs->main_peer) { cs->main_peer = NULL; @@ -401,7 +408,7 @@ void corerouter_close_session(struct uwsgi_corerouter *ucr, struct corerouter_se struct corerouter_peer *main_peer = cr_session->main_peer; if (main_peer) { - uwsgi_cr_peer_del(main_peer); + if (uwsgi_cr_peer_del(main_peer) < 0) return; } // free peers @@ -413,7 +420,7 @@ void corerouter_close_session(struct uwsgi_corerouter *ucr, struct corerouter_se if (ucr->subscriptions && tmp_peer->un && tmp_peer->un->len) { tmp_peer->un->reference--; } - uwsgi_cr_peer_del(tmp_peer); + if (uwsgi_cr_peer_del(tmp_peer) < 0) return; } // could be used to free additional resources diff --git a/plugins/corerouter/cr.h b/plugins/corerouter/cr.h index d8419c93..12da56db 100644 --- a/plugins/corerouter/cr.h +++ b/plugins/corerouter/cr.h @@ -190,6 +190,9 @@ struct corerouter_peer { struct corerouter_peer *next; int current_timeout; + + ssize_t (*flush)(struct corerouter_peer *); + int is_flushing; }; struct uwsgi_corerouter { diff --git a/plugins/http/https.c b/plugins/http/https.c index 4ea29680..da4a3deb 100644 --- a/plugins/http/https.c +++ b/plugins/http/https.c @@ -374,6 +374,47 @@ ssize_t hr_ssl_read(struct corerouter_peer *main_peer) { return -1; } +ssize_t hr_ssl_shutdown(struct corerouter_peer *peer) { + // ensure no hooks are set + if (uwsgi_cr_set_hooks(peer, NULL, NULL)) return -1; + + struct corerouter_session *cs = peer->session; + struct http_session *hr = (struct http_session *) cs; + + int ret = SSL_shutdown(hr->ssl); + if (ret < 0) return -1; + if (ret == 1) return 0; + + int err = 0; + + if (ERR_peek_error()) { + err = SSL_get_error(hr->ssl, ret); + } + + // no error, close the connection + if (err == 0 || err == SSL_ERROR_ZERO_RETURN) return -1; + + if (err == SSL_ERROR_WANT_READ) { + if (uwsgi_cr_set_hooks(peer, hr_ssl_shutdown, NULL)) return -1; + return 1; + } + + else if (err == SSL_ERROR_WANT_WRITE) { + if (uwsgi_cr_set_hooks(peer, NULL, hr_ssl_shutdown)) return -1; + return 1; + } + + else if (err == SSL_ERROR_SYSCALL) { + uwsgi_cr_error(peer, "hr_ssl_shutdown()"); + } + + else if (err == SSL_ERROR_SSL && uwsgi.ssl_verbose) { + ERR_print_errors_fp(stderr); + } + + return -1; +} + void hr_setup_ssl(struct http_session *hr, struct uwsgi_gateway_socket *ugs) { hr->ssl = SSL_new(ugs->ctx); SSL_set_fd(hr->ssl, hr->session.main_peer->fd); @@ -382,6 +423,7 @@ void hr_setup_ssl(struct http_session *hr, struct uwsgi_gateway_socket *ugs) { SSL_set_ex_data(hr->ssl, uhttp.spdy_index, hr); #endif uwsgi_cr_set_hooks(hr->session.main_peer, hr_ssl_read, NULL); + hr->session.main_peer->flush = hr_ssl_shutdown; hr->session.close = hr_session_ssl_close; hr->func_write = hr_ssl_write; }