daemon_close_all_connections.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. This file is part of libmicrohttpd
  3. Copyright (C) 2007-2018 Daniel Pittman and Christian Grothoff
  4. This library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. This library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with this library; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  15. */
  16. /**
  17. * @file lib/daemon_close_all_connections.c
  18. * @brief function to close all connections open at a daemon
  19. * @author Christian Grothoff
  20. */
  21. #include "internal.h"
  22. #include "connection_cleanup.h"
  23. #include "connection_close.h"
  24. #include "connection_finish_forward.h"
  25. #include "daemon_close_all_connections.h"
  26. #include "request_resume.h"
  27. #include "upgrade_process.h"
  28. /**
  29. * Close the given connection, remove it from all of its
  30. * DLLs and move it into the cleanup queue.
  31. * @remark To be called only from thread that
  32. * process daemon's select()/poll()/etc.
  33. *
  34. * @param pos connection to move to cleanup
  35. */
  36. static void
  37. close_connection (struct MHD_Connection *pos)
  38. {
  39. struct MHD_Daemon *daemon = pos->daemon;
  40. if (MHD_TM_THREAD_PER_CONNECTION == daemon->threading_mode)
  41. {
  42. MHD_connection_mark_closed_ (pos);
  43. return; /* must let thread to do the rest */
  44. }
  45. MHD_connection_close_ (pos,
  46. MHD_REQUEST_TERMINATED_DAEMON_SHUTDOWN);
  47. MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
  48. mhd_assert (! pos->suspended);
  49. mhd_assert (! pos->resuming);
  50. if (pos->connection_timeout ==
  51. pos->daemon->connection_default_timeout)
  52. XDLL_remove (daemon->normal_timeout_head,
  53. daemon->normal_timeout_tail,
  54. pos);
  55. else
  56. XDLL_remove (daemon->manual_timeout_head,
  57. daemon->manual_timeout_tail,
  58. pos);
  59. DLL_remove (daemon->connections_head,
  60. daemon->connections_tail,
  61. pos);
  62. DLL_insert (daemon->cleanup_head,
  63. daemon->cleanup_tail,
  64. pos);
  65. MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
  66. }
  67. /**
  68. * Close all connections for the daemon. Must only be called when
  69. * MHD_Daemon::shutdown was set to true.
  70. *
  71. * @remark To be called only from thread that process daemon's
  72. * select()/poll()/etc.
  73. *
  74. * @param daemon daemon to close down
  75. */
  76. void
  77. MHD_daemon_close_all_connections_ (struct MHD_Daemon *daemon)
  78. {
  79. struct MHD_Connection *pos;
  80. const bool used_thr_p_c = (MHD_TM_THREAD_PER_CONNECTION ==
  81. daemon->threading_mode);
  82. #ifdef UPGRADE_SUPPORT
  83. const bool upg_allowed = (! daemon->disallow_upgrade);
  84. #endif /* UPGRADE_SUPPORT */
  85. #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT)
  86. struct MHD_UpgradeResponseHandle *urh;
  87. struct MHD_UpgradeResponseHandle *urhn;
  88. const bool used_tls = (NULL != daemon->tls_api);
  89. mhd_assert (NULL == daemon->worker_pool);
  90. mhd_assert (daemon->shutdown);
  91. /* give upgraded HTTPS connections a chance to finish */
  92. /* 'daemon->urh_head' is not used in thread-per-connection mode. */
  93. for (urh = daemon->urh_tail; NULL != urh; urh = urhn)
  94. {
  95. urhn = urh->prev;
  96. /* call generic forwarding function for passing data
  97. with chance to detect that application is done. */
  98. MHD_upgrade_response_handle_process_ (urh);
  99. MHD_connection_finish_forward_ (urh->connection);
  100. urh->clean_ready = true;
  101. /* Resuming will move connection to cleanup list. */
  102. MHD_request_resume (&urh->connection->request);
  103. }
  104. #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */
  105. /* Give suspended connections a chance to resume to avoid
  106. running into the check for there not being any suspended
  107. connections left in case of a tight race with a recently
  108. resumed connection. */
  109. if (! daemon->disallow_suspend_resume)
  110. {
  111. daemon->resuming = true; /* Force check for pending resume. */
  112. MHD_resume_suspended_connections_ (daemon);
  113. }
  114. /* first, make sure all threads are aware of shutdown; need to
  115. traverse DLLs in peace... */
  116. MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
  117. #ifdef UPGRADE_SUPPORT
  118. if (upg_allowed)
  119. {
  120. struct MHD_Connection *susp;
  121. susp = daemon->suspended_connections_tail;
  122. while (NULL != susp)
  123. {
  124. if (NULL == susp->request.urh) /* "Upgraded" connection? */
  125. MHD_PANIC (_ (
  126. "MHD_stop_daemon() called while we have suspended connections.\n"));
  127. #ifdef HTTPS_SUPPORT
  128. else if (used_tls &&
  129. used_thr_p_c &&
  130. (! susp->request.urh->clean_ready) )
  131. shutdown (susp->request.urh->app.socket,
  132. SHUT_RDWR); /* Wake thread by shutdown of app socket. */
  133. #endif /* HTTPS_SUPPORT */
  134. else
  135. {
  136. #ifdef HAVE_MESSAGES
  137. if (! susp->request.urh->was_closed)
  138. MHD_DLOG (daemon,
  139. MHD_SC_SHUTDOWN_WITH_OPEN_UPGRADED_CONNECTION,
  140. _ (
  141. "Initiated daemon shutdown while \"upgraded\" connection was not closed.\n"));
  142. #endif
  143. susp->request.urh->was_closed = true;
  144. /* If thread-per-connection is used, connection's thread
  145. * may still processing "upgrade" (exiting). */
  146. if (! used_thr_p_c)
  147. MHD_connection_finish_forward_ (susp);
  148. /* Do not use MHD_resume_connection() as mutex is
  149. * already locked. */
  150. susp->resuming = true;
  151. daemon->resuming = true;
  152. }
  153. susp = susp->prev;
  154. }
  155. }
  156. else /* This 'else' is combined with next 'if' */
  157. #endif /* UPGRADE_SUPPORT */
  158. if (NULL != daemon->suspended_connections_head)
  159. MHD_PANIC (_ (
  160. "MHD_stop_daemon() called while we have suspended connections.\n"));
  161. for (pos = daemon->connections_tail; NULL != pos; pos = pos->prev)
  162. {
  163. shutdown (pos->socket_fd,
  164. SHUT_RDWR);
  165. #if MHD_WINSOCK_SOCKETS
  166. if ( (used_thr_p_c) &&
  167. (MHD_ITC_IS_VALID_ (daemon->itc)) &&
  168. (! MHD_itc_activate_ (daemon->itc,
  169. "e")) )
  170. MHD_PANIC (_ (
  171. "Failed to signal shutdown via inter-thread communication channel"));
  172. #endif
  173. }
  174. /* now, collect per-connection threads */
  175. if (used_thr_p_c)
  176. {
  177. pos = daemon->connections_tail;
  178. while (NULL != pos)
  179. {
  180. if (! pos->thread_joined)
  181. {
  182. MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
  183. if (! MHD_join_thread_ (pos->pid.handle))
  184. MHD_PANIC (_ ("Failed to join a thread\n"));
  185. MHD_mutex_lock_chk_ (&daemon->cleanup_connection_mutex);
  186. pos->thread_joined = true;
  187. /* The thread may have concurrently modified the DLL,
  188. need to restart from the beginning */
  189. pos = daemon->connections_tail;
  190. continue;
  191. }
  192. pos = pos->prev;
  193. }
  194. }
  195. MHD_mutex_unlock_chk_ (&daemon->cleanup_connection_mutex);
  196. #ifdef UPGRADE_SUPPORT
  197. /* Finished threads with "upgraded" connections need to be moved
  198. * to cleanup list by resume_suspended_connections(). */
  199. /* "Upgraded" connections that were not closed explicitly by
  200. * application should be moved to cleanup list too. */
  201. if (upg_allowed)
  202. {
  203. daemon->resuming = true; /* Force check for pending resume. */
  204. MHD_resume_suspended_connections_ (daemon);
  205. }
  206. #endif /* UPGRADE_SUPPORT */
  207. /* now that we're alone, move everyone to cleanup */
  208. while (NULL != (pos = daemon->connections_tail))
  209. {
  210. if ( (used_thr_p_c) &&
  211. (! pos->thread_joined) )
  212. MHD_PANIC (_ ("Failed to join a thread\n"));
  213. close_connection (pos);
  214. }
  215. MHD_connection_cleanup_ (daemon);
  216. }
  217. /* end of daemon_close_all_connections.c */