mhd_run.c (5629B)
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 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 145 "Adding run_daemon select task\n"); 146 de->mhd_task 147 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, 148 tv, 149 wrs, 150 wws, 151 &run_daemon, 152 de); 153 GNUNET_NETWORK_fdset_destroy (wrs); 154 GNUNET_NETWORK_fdset_destroy (wws); 155 } 156 157 158 void 159 TALER_MHD_daemon_start (struct MHD_Daemon *daemon) 160 { 161 struct DaemonEntry *de; 162 163 de = GNUNET_new (struct DaemonEntry); 164 de->mhd = daemon; 165 GNUNET_CONTAINER_DLL_insert (mhd_head, 166 mhd_tail, 167 de); 168 prepare_daemon (de); 169 } 170 171 172 void 173 TALER_MHD_daemons_halt (void) 174 { 175 for (struct DaemonEntry *de = mhd_head; 176 NULL != de; 177 de = de->next) 178 { 179 if (NULL != de->mhd_task) 180 { 181 GNUNET_SCHEDULER_cancel (de->mhd_task); 182 de->mhd_task = NULL; 183 } 184 de->triggered = false; 185 } 186 } 187 188 189 void 190 TALER_MHD_daemons_quiesce (void) 191 { 192 for (struct DaemonEntry *de = mhd_head; 193 NULL != de; 194 de = de->next) 195 { 196 int fd; 197 198 if (NULL != de->mhd_task) 199 { 200 GNUNET_SCHEDULER_cancel (de->mhd_task); 201 de->mhd_task = NULL; 202 } 203 de->triggered = false; 204 fd = MHD_quiesce_daemon (de->mhd); 205 GNUNET_break (0 == close (fd)); 206 } 207 } 208 209 210 void 211 TALER_MHD_daemons_destroy (void) 212 { 213 struct DaemonEntry *de; 214 215 while (NULL != (de = mhd_head)) 216 { 217 struct MHD_Daemon *mhd = de->mhd; 218 219 if (NULL != de->mhd_task) 220 { 221 GNUNET_SCHEDULER_cancel (de->mhd_task); 222 de->mhd_task = NULL; 223 } 224 MHD_stop_daemon (mhd); 225 GNUNET_CONTAINER_DLL_remove (mhd_head, 226 mhd_tail, 227 de); 228 GNUNET_free (de); 229 } 230 } 231 232 233 void 234 TALER_MHD_daemon_trigger (void) 235 { 236 for (struct DaemonEntry *de = mhd_head; 237 NULL != de; 238 de = de->next) 239 { 240 if (NULL != de->mhd_task) 241 { 242 GNUNET_SCHEDULER_cancel (de->mhd_task); 243 de->mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon, 244 de); 245 } 246 else 247 { 248 de->triggered = true; 249 } 250 } 251 } 252 253 254 /* end of mhd_run.c */