aboutsummaryrefslogtreecommitdiff
path: root/src/supplemental/http/http_server.c
diff options
context:
space:
mode:
authorGarrett D'Amore <garrett@damore.org>2023-12-17 19:03:29 -0800
committerGarrett D'Amore <garrett@damore.org>2023-12-17 19:09:30 -0800
commit8ff9663c06a18d6c7fe0605de679948d3c4de9d7 (patch)
tree3a5e1884816c7e693eadc83a0f45ddac167c8494 /src/supplemental/http/http_server.c
parent8ccc10bf6a7ce305e5197e8eaf931ac7dc8612c0 (diff)
downloadnng-8ff9663c06a18d6c7fe0605de679948d3c4de9d7.tar.gz
nng-8ff9663c06a18d6c7fe0605de679948d3c4de9d7.tar.bz2
nng-8ff9663c06a18d6c7fe0605de679948d3c4de9d7.zip
fixes #1735 websocket should send, and wait for, WS_CLOSE frames on shutdown
fixes #1733 deadlock in websocket listener close
Diffstat (limited to 'src/supplemental/http/http_server.c')
-rw-r--r--src/supplemental/http/http_server.c67
1 files changed, 41 insertions, 26 deletions
diff --git a/src/supplemental/http/http_server.c b/src/supplemental/http/http_server.c
index 6759b859..42ff5dd9 100644
--- a/src/supplemental/http/http_server.c
+++ b/src/supplemental/http/http_server.c
@@ -73,8 +73,8 @@ struct nng_http_server {
nni_list handlers;
nni_list conns;
nni_mtx mtx;
- nni_cv cv;
bool closed;
+ bool fini; // if nni_http_server_fini was called
nni_aio * accaio;
nng_stream_listener *listener;
int port; // native order
@@ -301,8 +301,8 @@ http_sc_reap(void *arg)
if (nni_list_node_active(&sc->node)) {
nni_list_remove(&s->conns, sc);
}
- if (nni_list_empty(&s->conns)) {
- nni_cv_wake(&s->cv);
+ if (nni_list_empty(&s->conns) && (s->fini)) {
+ nni_reap(&http_server_reap_list, s);
}
nni_mtx_unlock(&s->mtx);
@@ -909,13 +909,7 @@ http_server_fini(nni_http_server *s)
nni_aio_stop(s->accaio);
nni_mtx_lock(&s->mtx);
- if (!nni_list_empty(&s->conns)) {
- // Try to reap later, after the connections are done reaping.
- // (Note, connections will all have been closed already.)
- nni_reap(&http_server_reap_list, s);
- nni_mtx_unlock(&s->mtx);
- return;
- }
+ NNI_ASSERT(nni_list_empty(&s->conns));
nng_stream_listener_free(s->listener);
while ((h = nni_list_first(&s->handlers)) != NULL) {
nni_list_remove(&s->handlers, h);
@@ -932,7 +926,6 @@ http_server_fini(nni_http_server *s)
nni_mtx_fini(&s->errors_mtx);
nni_aio_free(s->accaio);
- nni_cv_fini(&s->cv);
nni_mtx_fini(&s->mtx);
nni_strfree(s->hostname);
NNI_FREE_STRUCT(s);
@@ -958,7 +951,6 @@ http_server_init(nni_http_server **serverp, const nni_url *url)
}
nni_mtx_init(&s->mtx);
nni_mtx_init(&s->errors_mtx);
- nni_cv_init(&s->cv, &s->mtx);
NNI_LIST_INIT(&s->handlers, nni_http_handler, node);
NNI_LIST_INIT(&s->conns, http_sconn, node);
@@ -1048,10 +1040,8 @@ nni_http_server_start(nni_http_server *s)
}
static void
-http_server_stop(nni_http_server *s)
+http_server_close(nni_http_server *s)
{
- http_sconn *sc;
-
if (s->closed) {
return;
}
@@ -1063,29 +1053,48 @@ http_server_stop(nni_http_server *s)
if (s->listener) {
nng_stream_listener_close(s->listener);
}
+}
+
+static void
+http_server_stop(nni_http_server *s)
+{
+ http_sconn *sc;
+
+ http_server_close(s);
// Stopping the server is a hard stop -- it aborts any work
// being done by clients. (No graceful shutdown).
NNI_LIST_FOREACH (&s->conns, sc) {
http_sc_close_locked(sc);
}
-
- while (!nni_list_empty(&s->conns)) {
- nni_cv_wait(&s->cv);
- }
}
void
nni_http_server_stop(nni_http_server *s)
{
nni_mtx_lock(&s->mtx);
- s->starts--;
+ if (s->starts != 0) {
+ s->starts--;
+ }
if (s->starts == 0) {
http_server_stop(s);
}
nni_mtx_unlock(&s->mtx);
}
+void
+nni_http_server_close(nni_http_server *s)
+{
+ nni_mtx_lock(&s->mtx);
+ if (s->starts != 0) {
+ s->starts--;
+ }
+ if (s->starts == 0) {
+ http_server_close(s);
+ }
+ nni_mtx_unlock(&s->mtx);
+}
+
static int
http_server_set_err(nni_http_server *s, uint16_t code, void *body, size_t len)
{
@@ -1910,12 +1919,18 @@ nni_http_server_fini(nni_http_server *s)
{
nni_mtx_lock(&http_servers_lk);
s->refcnt--;
- if (s->refcnt == 0) {
- nni_mtx_lock(&s->mtx);
- http_server_stop(s);
- nni_mtx_unlock(&s->mtx);
- nni_list_remove(&http_servers, s);
- nni_reap(&http_server_reap_list, s);
+ if (s->refcnt != 0) {
+ nni_mtx_unlock(&http_servers_lk);
+ return;
}
+ nni_list_remove(&http_servers, s);
nni_mtx_unlock(&http_servers_lk);
+
+ nni_mtx_lock(&s->mtx);
+ http_server_stop(s);
+ s->fini = true;
+ if (nni_list_empty(&s->conns)) {
+ nni_reap(&http_server_reap_list, s);
+ }
+ nni_mtx_unlock(&s->mtx);
}