mhd_run.c (5512B)
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 <gnunet/gnunet_util_lib.h> 23 #include <gnunet/gnunet_json_lib.h> 24 #include <jansson.h> 25 #include <microhttpd.h> 26 #include "taler/taler_util.h" 27 #include "taler/taler_mhd_lib.h" 28 29 30 /** 31 * Entry in list of HTTP servers we are running. 32 */ 33 struct DaemonEntry 34 { 35 /** 36 * Kept in a DLL. 37 */ 38 struct DaemonEntry *next; 39 40 /** 41 * Kept in a DLL. 42 */ 43 struct DaemonEntry *prev; 44 45 /** 46 * The actual daemon. 47 */ 48 struct MHD_Daemon *mhd; 49 50 /** 51 * Task running the HTTP server. 52 */ 53 struct GNUNET_SCHEDULER_Task *mhd_task; 54 55 /** 56 * Set to true if we should immediately MHD_run() again. 57 */ 58 bool triggered; 59 60 }; 61 62 63 /** 64 * Head of list of HTTP servers. 65 */ 66 static struct DaemonEntry *mhd_head; 67 68 /** 69 * Tail of list of HTTP servers. 70 */ 71 static struct DaemonEntry *mhd_tail; 72 73 74 /** 75 * Function that queries MHD's select sets and 76 * starts the task waiting for them. 77 * 78 * @param[in,out] de daemon to start tasks for 79 */ 80 static void 81 prepare_daemon (struct DaemonEntry *de); 82 83 84 /** 85 * Call MHD to process pending requests and then go back 86 * and schedule the next run. 87 * 88 * @param cls our `struct DaemonEntry *` 89 */ 90 static void 91 run_daemon (void *cls) 92 { 93 struct DaemonEntry *de = cls; 94 95 de->mhd_task = NULL; 96 do { 97 de->triggered = false; 98 GNUNET_assert (MHD_YES == 99 MHD_run (de->mhd)); 100 } while (de->triggered); 101 prepare_daemon (de); 102 } 103 104 105 static void 106 prepare_daemon (struct DaemonEntry *de) 107 { 108 fd_set rs; 109 fd_set ws; 110 fd_set es; 111 struct GNUNET_NETWORK_FDSet *wrs; 112 struct GNUNET_NETWORK_FDSet *wws; 113 int max; 114 MHD_UNSIGNED_LONG_LONG timeout; 115 int haveto; 116 struct GNUNET_TIME_Relative tv; 117 118 FD_ZERO (&rs); 119 FD_ZERO (&ws); 120 FD_ZERO (&es); 121 wrs = GNUNET_NETWORK_fdset_create (); 122 wws = GNUNET_NETWORK_fdset_create (); 123 max = -1; 124 GNUNET_assert (MHD_YES == 125 MHD_get_fdset (de->mhd, 126 &rs, 127 &ws, 128 &es, 129 &max)); 130 haveto = MHD_get_timeout (de->mhd, 131 &timeout); 132 if (haveto == MHD_YES) 133 tv = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 134 timeout); 135 else 136 tv = GNUNET_TIME_UNIT_FOREVER_REL; 137 GNUNET_NETWORK_fdset_copy_native (wrs, 138 &rs, 139 max + 1); 140 GNUNET_NETWORK_fdset_copy_native (wws, 141 &ws, 142 max + 1); 143 de->mhd_task 144 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, 145 tv, 146 wrs, 147 wws, 148 &run_daemon, 149 de); 150 GNUNET_NETWORK_fdset_destroy (wrs); 151 GNUNET_NETWORK_fdset_destroy (wws); 152 } 153 154 155 void 156 TALER_MHD_daemon_start (struct MHD_Daemon *daemon) 157 { 158 struct DaemonEntry *de; 159 160 de = GNUNET_new (struct DaemonEntry); 161 de->mhd = daemon; 162 GNUNET_CONTAINER_DLL_insert (mhd_head, 163 mhd_tail, 164 de); 165 prepare_daemon (de); 166 } 167 168 169 void 170 TALER_MHD_daemons_halt (void) 171 { 172 for (struct DaemonEntry *de = mhd_head; 173 NULL != de; 174 de = de->next) 175 { 176 if (NULL != de->mhd_task) 177 { 178 GNUNET_SCHEDULER_cancel (de->mhd_task); 179 de->mhd_task = NULL; 180 } 181 de->triggered = false; 182 } 183 } 184 185 186 void 187 TALER_MHD_daemons_quiesce (void) 188 { 189 for (struct DaemonEntry *de = mhd_head; 190 NULL != de; 191 de = de->next) 192 { 193 int fd; 194 195 if (NULL != de->mhd_task) 196 { 197 GNUNET_SCHEDULER_cancel (de->mhd_task); 198 de->mhd_task = NULL; 199 } 200 de->triggered = false; 201 fd = MHD_quiesce_daemon (de->mhd); 202 GNUNET_break (0 == close (fd)); 203 } 204 } 205 206 207 void 208 TALER_MHD_daemons_destroy (void) 209 { 210 struct DaemonEntry *de; 211 212 while (NULL != (de = mhd_head)) 213 { 214 struct MHD_Daemon *mhd = de->mhd; 215 216 if (NULL != de->mhd_task) 217 { 218 GNUNET_SCHEDULER_cancel (de->mhd_task); 219 de->mhd_task = NULL; 220 } 221 MHD_stop_daemon (mhd); 222 GNUNET_CONTAINER_DLL_remove (mhd_head, 223 mhd_tail, 224 de); 225 GNUNET_free (de); 226 } 227 } 228 229 230 void 231 TALER_MHD_daemon_trigger (void) 232 { 233 for (struct DaemonEntry *de = mhd_head; 234 NULL != de; 235 de = de->next) 236 { 237 if (NULL != de->mhd_task) 238 { 239 GNUNET_SCHEDULER_cancel (de->mhd_task); 240 de->mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon, 241 de); 242 } 243 else 244 { 245 de->triggered = true; 246 } 247 } 248 } 249 250 251 /* end of mhd_run.c */