aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-02-16 06:48:12 +0100
committerChristian Grothoff <christian@grothoff.org>2018-02-16 06:48:12 +0100
commita104a2a46a8d3ef1787f7171295af3acc63c4912 (patch)
tree353d56594506c6611dcfcf5fc6beba764a27fc3a
parent6450f55f0c18d7a4b2fac829d9eff5d567348d19 (diff)
downloadlibmicrohttpd-a104a2a46a8d3ef1787f7171295af3acc63c4912.tar.gz
libmicrohttpd-a104a2a46a8d3ef1787f7171295af3acc63c4912.zip
implementing daemon_close_all_connections
-rw-r--r--src/include/microhttpd2.h6
-rw-r--r--src/lib/Makefile.am1
-rw-r--r--src/lib/daemon_close_all_connections.c229
-rw-r--r--src/lib/daemon_close_all_connections.h42
-rw-r--r--src/lib/daemon_destroy.c2
-rw-r--r--src/lib/daemon_start.c3
6 files changed, 281 insertions, 2 deletions
diff --git a/src/include/microhttpd2.h b/src/include/microhttpd2.h
index 6b2f59fd..77181f44 100644
--- a/src/include/microhttpd2.h
+++ b/src/include/microhttpd2.h
@@ -729,6 +729,12 @@ enum MHD_StatusCode
729 * some reason. 729 * some reason.
730 */ 730 */
731 MHD_SC_IP_COUNTER_FAILURE = 50052, 731 MHD_SC_IP_COUNTER_FAILURE = 50052,
732
733 /**
734 * Application violated our API by calling shutdown
735 * while having an upgrade connection still open.
736 */
737 MHD_SC_SHUTDOWN_WITH_OPEN_UPGRADED_CONNECTION = 50053,
732 738
733}; 739};
734 740
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 1667978a..a811a2fd 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -64,6 +64,7 @@ libmicrohttpd_la_SOURCES = \
64 connection_info.c \ 64 connection_info.c \
65 connection_options.c \ 65 connection_options.c \
66 connection_update_last_activity.c connection_update_last_activity.h \ 66 connection_update_last_activity.c connection_update_last_activity.h \
67 daemon_close_all_connections.c daemon_close_all_connections.h \
67 daemon_create.c \ 68 daemon_create.c \
68 daemon_destroy.c \ 69 daemon_destroy.c \
69 daemon_epoll.c daemon_epoll.h \ 70 daemon_epoll.c daemon_epoll.h \
diff --git a/src/lib/daemon_close_all_connections.c b/src/lib/daemon_close_all_connections.c
new file mode 100644
index 00000000..0d6dd85d
--- /dev/null
+++ b/src/lib/daemon_close_all_connections.c
@@ -0,0 +1,229 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file lib/daemon_close_all_connections.c
22 * @brief function to close all connections open at a daemon
23 * @author Christian Grothoff
24 */
25#include "internal.h"
26#include "connection_close.h"
27#include "connection_finish_forward.h"
28#include "daemon_close_all_connections.h"
29#include "upgrade_process.h"
30
31
32/**
33 * Close the given connection, remove it from all of its
34 * DLLs and move it into the cleanup queue.
35 * @remark To be called only from thread that
36 * process daemon's select()/poll()/etc.
37 *
38 * @param pos connection to move to cleanup
39 */
40static void
41close_connection (struct MHD_Connection *pos)
42{
43 struct MHD_Daemon *daemon = pos->daemon;
44
45 if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model)
46 {
47 MHD_connection_mark_closed_ (pos);
48 return; /* must let thread to do the rest */
49 }
50 MHD_connection_close_ (pos,
51 MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
52
53 MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
54
55 mhd_assert (! pos->suspended);
56 mhd_assert (! pos->resuming);
57 if (pos->connection_timeout ==
58 pos->daemon->connection_default_timeout)
59 XDLL_remove (daemon->normal_timeout_head,
60 daemon->normal_timeout_tail,
61 pos);
62 else
63 XDLL_remove (daemon->manual_timeout_head,
64 daemon->manual_timeout_tail,
65 pos);
66 DLL_remove (daemon->connections_head,
67 daemon->connections_tail,
68 pos);
69 DLL_insert (daemon->cleanup_head,
70 daemon->cleanup_tail,
71 pos);
72
73 MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
74}
75
76
77/**
78 * Close all connections for the daemon. Must only be called when
79 * MHD_Daemon::shutdown was set to true.
80 *
81 * @remark To be called only from thread that process daemon's
82 * select()/poll()/etc.
83 *
84 * @param daemon daemon to close down
85 */
86void
87MHD_daemon_close_all_connections_ (struct MHD_Daemon *daemon)
88{
89 struct MHD_Connection *pos;
90 const bool used_thr_p_c = (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_model);
91#ifdef UPGRADE_SUPPORT
92 const bool upg_allowed = (! daemon->disallow_upgrade);
93#endif /* UPGRADE_SUPPORT */
94#if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
95 struct MHD_UpgradeResponseHandle *urh;
96 struct MHD_UpgradeResponseHandle *urhn;
97 const bool used_tls = (NULL != daemon->tls_api);
98
99 mhd_assert (NULL == daemon->worker_pool);
100 mhd_assert (daemon->shutdown);
101 /* give upgraded HTTPS connections a chance to finish */
102 /* 'daemon->urh_head' is not used in thread-per-connection mode. */
103 for (urh = daemon->urh_tail; NULL != urh; urh = urhn)
104 {
105 urhn = urh->prev;
106 /* call generic forwarding function for passing data
107 with chance to detect that application is done. */
108 MHD_upgrade_response_handle_process_ (urh);
109 MHD_connection_finish_forward_ (urh->connection);
110 urh->clean_ready = true;
111 /* Resuming will move connection to cleanup list. */
112 MHD_resume_connection (urh->connection);
113 }
114#endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
115
116 /* Give suspended connections a chance to resume to avoid
117 running into the check for there not being any suspended
118 connections left in case of a tight race with a recently
119 resumed connection. */
120 if (! daemon->disallow_suspend_resume)
121 {
122 daemon->resuming = true; /* Force check for pending resume. */
123 resume_suspended_connections (daemon);
124 }
125 /* first, make sure all threads are aware of shutdown; need to
126 traverse DLLs in peace... */
127 MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
128#ifdef UPGRADE_SUPPORT
129 if (upg_allowed)
130 {
131 struct MHD_Connection * susp;
132
133 susp = daemon->suspended_connections_tail;
134 while (NULL != susp)
135 {
136 if (NULL == susp->request.urh) /* "Upgraded" connection? */
137 MHD_PANIC (_("MHD_stop_daemon() called while we have suspended connections.\n"));
138#ifdef HTTPS_SUPPORT
139 else if (used_tls &&
140 used_thr_p_c &&
141 (! susp->request.urh->clean_ready) )
142 shutdown (susp->request.urh->app.socket,
143 SHUT_RDWR); /* Wake thread by shutdown of app socket. */
144#endif /* HTTPS_SUPPORT */
145 else
146 {
147#ifdef HAVE_MESSAGES
148 if (! susp->request.urh->was_closed)
149 MHD_DLOG (daemon,
150 MHD_SC_SHUTDOWN_WITH_OPEN_UPGRADED_CONNECTION,
151 _("Initiated daemon shutdown while \"upgraded\" connection was not closed.\n"));
152#endif
153 susp->request.urh->was_closed = true;
154 /* If thread-per-connection is used, connection's thread
155 * may still processing "upgrade" (exiting). */
156 if (! used_thr_p_c)
157 MHD_connection_finish_forward_ (susp);
158 /* Do not use MHD_resume_connection() as mutex is
159 * already locked. */
160 susp->resuming = true;
161 daemon->resuming = true;
162 }
163 susp = susp->prev;
164 }
165 }
166 else /* This 'else' is combined with next 'if' */
167#endif /* UPGRADE_SUPPORT */
168 if (NULL != daemon->suspended_connections_head)
169 MHD_PANIC (_("MHD_stop_daemon() called while we have suspended connections.\n"));
170 for (pos = daemon->connections_tail; NULL != pos; pos = pos->prev)
171 {
172 shutdown (pos->socket_fd,
173 SHUT_RDWR);
174#if MHD_WINSOCK_SOCKETS
175 if ( (used_thr_p_c) &&
176 (MHD_ITC_IS_VALID_(daemon->itc)) &&
177 (! MHD_itc_activate_ (daemon->itc,
178 "e")) )
179 MHD_PANIC (_("Failed to signal shutdown via inter-thread communication channel"));
180#endif
181 }
182
183 /* now, collect per-connection threads */
184 if (used_thr_p_c)
185 {
186 pos = daemon->connections_tail;
187 while (NULL != pos)
188 {
189 if (! pos->thread_joined)
190 {
191 MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
192 if (! MHD_join_thread_ (pos->pid.handle))
193 MHD_PANIC (_("Failed to join a thread\n"));
194 MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
195 pos->thread_joined = true;
196 /* The thread may have concurrently modified the DLL,
197 need to restart from the beginning */
198 pos = daemon->connections_tail;
199 continue;
200 }
201 pos = pos->prev;
202 }
203 }
204 MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
205
206#ifdef UPGRADE_SUPPORT
207 /* Finished threads with "upgraded" connections need to be moved
208 * to cleanup list by resume_suspended_connections(). */
209 /* "Upgraded" connections that were not closed explicitly by
210 * application should be moved to cleanup list too. */
211 if (upg_allowed)
212 {
213 daemon->resuming = true; /* Force check for pending resume. */
214 resume_suspended_connections (daemon);
215 }
216#endif /* UPGRADE_SUPPORT */
217
218 /* now that we're alone, move everyone to cleanup */
219 while (NULL != (pos = daemon->connections_tail))
220 {
221 if ( (used_thr_p_c) &&
222 (! pos->thread_joined) )
223 MHD_PANIC (_("Failed to join a thread\n"));
224 close_connection (pos);
225 }
226 MHD_cleanup_connections (daemon);
227}
228
229/* end of daemon_close_all_connections.c */
diff --git a/src/lib/daemon_close_all_connections.h b/src/lib/daemon_close_all_connections.h
new file mode 100644
index 00000000..340b0d47
--- /dev/null
+++ b/src/lib/daemon_close_all_connections.h
@@ -0,0 +1,42 @@
1/*
2 This file is part of libmicrohttpd
3 Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20/**
21 * @file lib/daemon_close_all_connections.h
22 * @brief function to close all connections open at a daemon
23 * @author Christian Grothoff
24 */
25#ifndef DAEMON_CLOSE_ALL_CONNECTIONS_H
26#define DAEMON_CLOSE_ALL_CONNECTIONS_H
27
28
29/**
30 * Close all connections for the daemon. Must only be called when
31 * MHD_Daemon::shutdown was set to true.
32 *
33 * @remark To be called only from thread that process daemon's
34 * select()/poll()/etc.
35 *
36 * @param daemon daemon to close down
37 */
38void
39MHD_daemon_close_all_connections_ (struct MHD_Daemon *daemon)
40 MHD_NONNULL (1);
41
42#endif
diff --git a/src/lib/daemon_destroy.c b/src/lib/daemon_destroy.c
index 14cc0b20..054ca188 100644
--- a/src/lib/daemon_destroy.c
+++ b/src/lib/daemon_destroy.c
@@ -147,7 +147,7 @@ MHD_daemon_destroy (struct MHD_Daemon *daemon)
147 { 147 {
148 /* No internal threads are used for polling sockets 148 /* No internal threads are used for polling sockets
149 (external event loop) */ 149 (external event loop) */
150 close_all_connections (daemon); 150 MHD_daemon_close_all_connections_ (daemon);
151 } 151 }
152 if (MHD_ITC_IS_VALID_ (daemon->itc)) 152 if (MHD_ITC_IS_VALID_ (daemon->itc))
153 MHD_itc_destroy_chk_ (daemon->itc); 153 MHD_itc_destroy_chk_ (daemon->itc);
diff --git a/src/lib/daemon_start.c b/src/lib/daemon_start.c
index d2db4d79..f9838d9f 100644
--- a/src/lib/daemon_start.c
+++ b/src/lib/daemon_start.c
@@ -23,6 +23,7 @@
23 * @author Christian Grothoff 23 * @author Christian Grothoff
24 */ 24 */
25#include "internal.h" 25#include "internal.h"
26#include "daemon_close_all_connections.h"
26#include "daemon_select.h" 27#include "daemon_select.h"
27 28
28 29
@@ -639,7 +640,7 @@ MHD_polling_thread (void *cls)
639 /* Resume any pending for resume connections, join 640 /* Resume any pending for resume connections, join
640 * all connection's threads (if any) and finally cleanup 641 * all connection's threads (if any) and finally cleanup
641 * everything. */ 642 * everything. */
642 close_all_connections (daemon); 643 MHD_daemon_close_all_connections_ (daemon);
643 644
644 return (MHD_THRD_RTRN_TYPE_)0; 645 return (MHD_THRD_RTRN_TYPE_)0;
645} 646}