Skip to content

Commit 8ff9663

Browse files
committed
fixes #1735 websocket should send, and wait for, WS_CLOSE frames on shutdown
fixes #1733 deadlock in websocket listener close
1 parent 8ccc10b commit 8ff9663

File tree

3 files changed

+148
-113
lines changed

3 files changed

+148
-113
lines changed

src/supplemental/http/http_api.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright 2019 Staysail Systems, Inc. <info@staysail.tech>
2+
// Copyright 2023 Staysail Systems, Inc. <info@staysail.tech>
33
// Copyright 2018 Capitar IT Group BV <info@capitar.com>
44
// Copyright 2019 Devolutions <info@devolutions.net>
55
//
@@ -216,8 +216,15 @@ extern int nni_http_server_start(nni_http_server *);
216216
// nni_http_server_stop stops the server, closing the listening socket.
217217
// Connections that have been "upgraded" are unaffected. Connections
218218
// associated with a callback will complete their callback, and then close.
219+
// Connections will be aborted but may not have terminated all the way.
219220
extern void nni_http_server_stop(nni_http_server *);
220221

222+
// nni_http_server_close closes down the socket, but does not shut down
223+
// any connections that are already open. This is useful for example
224+
// when shutting down an SP listener, and we don't want to break established
225+
// sessions.
226+
extern void nni_http_server_close(nni_http_server *);
227+
221228
// nni_http_server_set_error_page sets an error page for the named status.
222229
extern int nni_http_server_set_error_page(
223230
nni_http_server *, uint16_t, const char *);

src/supplemental/http/http_server.c

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ struct nng_http_server {
7373
nni_list handlers;
7474
nni_list conns;
7575
nni_mtx mtx;
76-
nni_cv cv;
7776
bool closed;
77+
bool fini; // if nni_http_server_fini was called
7878
nni_aio * accaio;
7979
nng_stream_listener *listener;
8080
int port; // native order
@@ -301,8 +301,8 @@ http_sc_reap(void *arg)
301301
if (nni_list_node_active(&sc->node)) {
302302
nni_list_remove(&s->conns, sc);
303303
}
304-
if (nni_list_empty(&s->conns)) {
305-
nni_cv_wake(&s->cv);
304+
if (nni_list_empty(&s->conns) && (s->fini)) {
305+
nni_reap(&http_server_reap_list, s);
306306
}
307307
nni_mtx_unlock(&s->mtx);
308308

@@ -909,13 +909,7 @@ http_server_fini(nni_http_server *s)
909909
nni_aio_stop(s->accaio);
910910

911911
nni_mtx_lock(&s->mtx);
912-
if (!nni_list_empty(&s->conns)) {
913-
// Try to reap later, after the connections are done reaping.
914-
// (Note, connections will all have been closed already.)
915-
nni_reap(&http_server_reap_list, s);
916-
nni_mtx_unlock(&s->mtx);
917-
return;
918-
}
912+
NNI_ASSERT(nni_list_empty(&s->conns));
919913
nng_stream_listener_free(s->listener);
920914
while ((h = nni_list_first(&s->handlers)) != NULL) {
921915
nni_list_remove(&s->handlers, h);
@@ -932,7 +926,6 @@ http_server_fini(nni_http_server *s)
932926
nni_mtx_fini(&s->errors_mtx);
933927

934928
nni_aio_free(s->accaio);
935-
nni_cv_fini(&s->cv);
936929
nni_mtx_fini(&s->mtx);
937930
nni_strfree(s->hostname);
938931
NNI_FREE_STRUCT(s);
@@ -958,7 +951,6 @@ http_server_init(nni_http_server **serverp, const nni_url *url)
958951
}
959952
nni_mtx_init(&s->mtx);
960953
nni_mtx_init(&s->errors_mtx);
961-
nni_cv_init(&s->cv, &s->mtx);
962954
NNI_LIST_INIT(&s->handlers, nni_http_handler, node);
963955
NNI_LIST_INIT(&s->conns, http_sconn, node);
964956

@@ -1048,10 +1040,8 @@ nni_http_server_start(nni_http_server *s)
10481040
}
10491041

10501042
static void
1051-
http_server_stop(nni_http_server *s)
1043+
http_server_close(nni_http_server *s)
10521044
{
1053-
http_sconn *sc;
1054-
10551045
if (s->closed) {
10561046
return;
10571047
}
@@ -1063,29 +1053,48 @@ http_server_stop(nni_http_server *s)
10631053
if (s->listener) {
10641054
nng_stream_listener_close(s->listener);
10651055
}
1056+
}
1057+
1058+
static void
1059+
http_server_stop(nni_http_server *s)
1060+
{
1061+
http_sconn *sc;
1062+
1063+
http_server_close(s);
10661064

10671065
// Stopping the server is a hard stop -- it aborts any work
10681066
// being done by clients. (No graceful shutdown).
10691067
NNI_LIST_FOREACH (&s->conns, sc) {
10701068
http_sc_close_locked(sc);
10711069
}
1072-
1073-
while (!nni_list_empty(&s->conns)) {
1074-
nni_cv_wait(&s->cv);
1075-
}
10761070
}
10771071

10781072
void
10791073
nni_http_server_stop(nni_http_server *s)
10801074
{
10811075
nni_mtx_lock(&s->mtx);
1082-
s->starts--;
1076+
if (s->starts != 0) {
1077+
s->starts--;
1078+
}
10831079
if (s->starts == 0) {
10841080
http_server_stop(s);
10851081
}
10861082
nni_mtx_unlock(&s->mtx);
10871083
}
10881084

1085+
void
1086+
nni_http_server_close(nni_http_server *s)
1087+
{
1088+
nni_mtx_lock(&s->mtx);
1089+
if (s->starts != 0) {
1090+
s->starts--;
1091+
}
1092+
if (s->starts == 0) {
1093+
http_server_close(s);
1094+
}
1095+
nni_mtx_unlock(&s->mtx);
1096+
}
1097+
10891098
static int
10901099
http_server_set_err(nni_http_server *s, uint16_t code, void *body, size_t len)
10911100
{
@@ -1910,12 +1919,18 @@ nni_http_server_fini(nni_http_server *s)
19101919
{
19111920
nni_mtx_lock(&http_servers_lk);
19121921
s->refcnt--;
1913-
if (s->refcnt == 0) {
1914-
nni_mtx_lock(&s->mtx);
1915-
http_server_stop(s);
1916-
nni_mtx_unlock(&s->mtx);
1917-
nni_list_remove(&http_servers, s);
1918-
nni_reap(&http_server_reap_list, s);
1922+
if (s->refcnt != 0) {
1923+
nni_mtx_unlock(&http_servers_lk);
1924+
return;
19191925
}
1926+
nni_list_remove(&http_servers, s);
19201927
nni_mtx_unlock(&http_servers_lk);
1928+
1929+
nni_mtx_lock(&s->mtx);
1930+
http_server_stop(s);
1931+
s->fini = true;
1932+
if (nni_list_empty(&s->conns)) {
1933+
nni_reap(&http_server_reap_list, s);
1934+
}
1935+
nni_mtx_unlock(&s->mtx);
19211936
}

0 commit comments

Comments
 (0)