mhd_run.c (5540B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2019-2025 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file mhd_run.c 18 * @brief API for running an MHD daemon with the 19 * GNUnet scheduler 20 * @author Christian Grothoff 21 */ 22 #include "taler/platform.h" 23 #include <gnunet/gnunet_util_lib.h> 24 #include <gnunet/gnunet_json_lib.h> 25 #include <jansson.h> 26 #include <microhttpd.h> 27 #include "taler/taler_util.h" 28 #include "taler/taler_mhd_lib.h" 29 30 31 /** 32 * Entry in list of HTTP servers we are running. 33 */ 34 struct DaemonEntry 35 { 36 /** 37 * Kept in a DLL. 38 */ 39 struct DaemonEntry *next; 40 41 /** 42 * Kept in a DLL. 43 */ 44 struct DaemonEntry *prev; 45 46 /** 47 * The actual daemon. 48 */ 49 struct MHD_Daemon *mhd; 50 51 /** 52 * Task running the HTTP server. 53 */ 54 struct GNUNET_SCHEDULER_Task *mhd_task; 55 56 /** 57 * Set to true if we should immediately MHD_run() again. 58 */ 59 bool triggered; 60 61 }; 62 63 64 /** 65 * Head of list of HTTP servers. 66 */ 67 static struct DaemonEntry *mhd_head; 68 69 /** 70 * Tail of list of HTTP servers. 71 */ 72 static struct DaemonEntry *mhd_tail; 73 74 75 /** 76 * Function that queries MHD's select sets and 77 * starts the task waiting for them. 78 * 79 * @param[in,out] de daemon to start tasks for 80 */ 81 static void 82 prepare_daemon (struct DaemonEntry *de); 83 84 85 /** 86 * Call MHD to process pending requests and then go back 87 * and schedule the next run. 88 * 89 * @param cls our `struct DaemonEntry *` 90 */ 91 static void 92 run_daemon (void *cls) 93 { 94 struct DaemonEntry *de = cls; 95 96 de->mhd_task = NULL; 97 do { 98 de->triggered = false; 99 GNUNET_assert (MHD_YES == 100 MHD_run (de->mhd)); 101 } while (de->triggered); 102 prepare_daemon (de); 103 } 104 105 106 static void 107 prepare_daemon (struct DaemonEntry *de) 108 { 109 fd_set rs; 110 fd_set ws; 111 fd_set es; 112 struct GNUNET_NETWORK_FDSet *wrs; 113 struct GNUNET_NETWORK_FDSet *wws; 114 int max; 115 MHD_UNSIGNED_LONG_LONG timeout; 116 int haveto; 117 struct GNUNET_TIME_Relative tv; 118 119 FD_ZERO (&rs); 120 FD_ZERO (&ws); 121 FD_ZERO (&es); 122 wrs = GNUNET_NETWORK_fdset_create (); 123 wws = GNUNET_NETWORK_fdset_create (); 124 max = -1; 125 GNUNET_assert (MHD_YES == 126 MHD_get_fdset (de->mhd, 127 &rs, 128 &ws, 129 &es, 130 &max)); 131 haveto = MHD_get_timeout (de->mhd, 132 &timeout); 133 if (haveto == MHD_YES) 134 tv = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 135 timeout); 136 else 137 tv = GNUNET_TIME_UNIT_FOREVER_REL; 138 GNUNET_NETWORK_fdset_copy_native (wrs, 139 &rs, 140 max + 1); 141 GNUNET_NETWORK_fdset_copy_native (wws, 142 &ws, 143 max + 1); 144 de->mhd_task 145 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, 146 tv, 147 wrs, 148 wws, 149 &run_daemon, 150 de); 151 GNUNET_NETWORK_fdset_destroy (wrs); 152 GNUNET_NETWORK_fdset_destroy (wws); 153 } 154 155 156 void 157 TALER_MHD_daemon_start (struct MHD_Daemon *daemon) 158 { 159 struct DaemonEntry *de; 160 161 de = GNUNET_new (struct DaemonEntry); 162 de->mhd = daemon; 163 GNUNET_CONTAINER_DLL_insert (mhd_head, 164 mhd_tail, 165 de); 166 prepare_daemon (de); 167 } 168 169 170 void 171 TALER_MHD_daemons_halt (void) 172 { 173 for (struct DaemonEntry *de = mhd_head; 174 NULL != de; 175 de = de->next) 176 { 177 if (NULL != de->mhd_task) 178 { 179 GNUNET_SCHEDULER_cancel (de->mhd_task); 180 de->mhd_task = NULL; 181 } 182 de->triggered = false; 183 } 184 } 185 186 187 void 188 TALER_MHD_daemons_quiesce (void) 189 { 190 for (struct DaemonEntry *de = mhd_head; 191 NULL != de; 192 de = de->next) 193 { 194 int fd; 195 196 if (NULL != de->mhd_task) 197 { 198 GNUNET_SCHEDULER_cancel (de->mhd_task); 199 de->mhd_task = NULL; 200 } 201 de->triggered = false; 202 fd = MHD_quiesce_daemon (de->mhd); 203 GNUNET_break (0 == close (fd)); 204 } 205 } 206 207 208 void 209 TALER_MHD_daemons_destroy (void) 210 { 211 struct DaemonEntry *de; 212 213 while (NULL != (de = mhd_head)) 214 { 215 struct MHD_Daemon *mhd = de->mhd; 216 217 if (NULL != de->mhd_task) 218 { 219 GNUNET_SCHEDULER_cancel (de->mhd_task); 220 de->mhd_task = NULL; 221 } 222 MHD_stop_daemon (mhd); 223 GNUNET_CONTAINER_DLL_remove (mhd_head, 224 mhd_tail, 225 de); 226 GNUNET_free (de); 227 } 228 } 229 230 231 void 232 TALER_MHD_daemon_trigger (void) 233 { 234 for (struct DaemonEntry *de = mhd_head; 235 NULL != de; 236 de = de->next) 237 { 238 if (NULL != de->mhd_task) 239 { 240 GNUNET_SCHEDULER_cancel (de->mhd_task); 241 de->mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon, 242 de); 243 } 244 else 245 { 246 de->triggered = true; 247 } 248 } 249 } 250 251 252 /* end of mhd_run.c */