diff --git a/plugins/corerouter/corerouter.c b/plugins/corerouter/corerouter.c index de254c9a..59dc97b6 100644 --- a/plugins/corerouter/corerouter.c +++ b/plugins/corerouter/corerouter.c @@ -65,6 +65,7 @@ void uwsgi_cr_peer_reset(struct corerouter_peer *peer) { free(peer->tmp_socket_name); peer->tmp_socket_name = NULL; } + cr_del_timeout(peer->session->corerouter, peer); if (peer->fd != -1) { @@ -84,7 +85,14 @@ 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; @@ -115,6 +123,7 @@ void uwsgi_cr_peer_del(struct corerouter_peer *peer) { free(peer->key); } free(peer); + return 0; } void uwsgi_opt_corerouter(char *opt, char *value, void *cr) { @@ -397,7 +406,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; @@ -415,7 +424,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 @@ -427,7 +436,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 901c5b4c..e2164879 100644 --- a/plugins/corerouter/cr.h +++ b/plugins/corerouter/cr.h @@ -195,6 +195,9 @@ struct corerouter_peer { char proto; int free_key; + + 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; }