diff options
-rw-r--r-- | src/include/microhttpd2.h | 6 | ||||
-rw-r--r-- | src/lib/Makefile.am | 1 | ||||
-rw-r--r-- | src/lib/daemon_close_all_connections.c | 229 | ||||
-rw-r--r-- | src/lib/daemon_close_all_connections.h | 42 | ||||
-rw-r--r-- | src/lib/daemon_destroy.c | 2 | ||||
-rw-r--r-- | src/lib/daemon_start.c | 3 |
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 | */ | ||
40 | static void | ||
41 | close_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 | */ | ||
86 | void | ||
87 | MHD_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 | */ | ||
38 | void | ||
39 | MHD_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 | } |