Line data Source code
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 6655 : run_daemon (void *cls) 93 : { 94 6655 : struct DaemonEntry *de = cls; 95 : 96 6655 : de->mhd_task = NULL; 97 : do { 98 6663 : de->triggered = false; 99 6663 : GNUNET_assert (MHD_YES == 100 : MHD_run (de->mhd)); 101 6663 : } while (de->triggered); 102 6655 : prepare_daemon (de); 103 6655 : } 104 : 105 : 106 : static void 107 6769 : 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 115073 : FD_ZERO (&rs); 120 115073 : FD_ZERO (&ws); 121 115073 : FD_ZERO (&es); 122 6769 : wrs = GNUNET_NETWORK_fdset_create (); 123 6769 : wws = GNUNET_NETWORK_fdset_create (); 124 6769 : max = -1; 125 6769 : GNUNET_assert (MHD_YES == 126 : MHD_get_fdset (de->mhd, 127 : &rs, 128 : &ws, 129 : &es, 130 : &max)); 131 6769 : haveto = MHD_get_timeout (de->mhd, 132 : &timeout); 133 6769 : if (haveto == MHD_YES) 134 5641 : tv = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 135 : timeout); 136 : else 137 1128 : tv = GNUNET_TIME_UNIT_FOREVER_REL; 138 6769 : GNUNET_NETWORK_fdset_copy_native (wrs, 139 : &rs, 140 : max + 1); 141 6769 : GNUNET_NETWORK_fdset_copy_native (wws, 142 : &ws, 143 : max + 1); 144 6769 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 145 : "Adding run_daemon select task\n"); 146 : de->mhd_task 147 6769 : = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, 148 : tv, 149 : wrs, 150 : wws, 151 : &run_daemon, 152 : de); 153 6769 : GNUNET_NETWORK_fdset_destroy (wrs); 154 6769 : GNUNET_NETWORK_fdset_destroy (wws); 155 6769 : } 156 : 157 : 158 : void 159 114 : TALER_MHD_daemon_start (struct MHD_Daemon *daemon) 160 : { 161 : struct DaemonEntry *de; 162 : 163 114 : de = GNUNET_new (struct DaemonEntry); 164 114 : de->mhd = daemon; 165 114 : GNUNET_CONTAINER_DLL_insert (mhd_head, 166 : mhd_tail, 167 : de); 168 114 : prepare_daemon (de); 169 114 : } 170 : 171 : 172 : void 173 57 : TALER_MHD_daemons_halt (void) 174 : { 175 57 : for (struct DaemonEntry *de = mhd_head; 176 171 : NULL != de; 177 114 : de = de->next) 178 : { 179 114 : if (NULL != de->mhd_task) 180 : { 181 114 : GNUNET_SCHEDULER_cancel (de->mhd_task); 182 114 : de->mhd_task = NULL; 183 : } 184 114 : de->triggered = false; 185 : } 186 57 : } 187 : 188 : 189 : void 190 0 : TALER_MHD_daemons_quiesce (void) 191 : { 192 0 : for (struct DaemonEntry *de = mhd_head; 193 0 : NULL != de; 194 0 : de = de->next) 195 : { 196 : int fd; 197 : 198 0 : if (NULL != de->mhd_task) 199 : { 200 0 : GNUNET_SCHEDULER_cancel (de->mhd_task); 201 0 : de->mhd_task = NULL; 202 : } 203 0 : de->triggered = false; 204 0 : fd = MHD_quiesce_daemon (de->mhd); 205 0 : GNUNET_break (0 == close (fd)); 206 : } 207 0 : } 208 : 209 : 210 : void 211 57 : TALER_MHD_daemons_destroy (void) 212 : { 213 : struct DaemonEntry *de; 214 : 215 171 : while (NULL != (de = mhd_head)) 216 : { 217 114 : struct MHD_Daemon *mhd = de->mhd; 218 : 219 114 : if (NULL != de->mhd_task) 220 : { 221 0 : GNUNET_SCHEDULER_cancel (de->mhd_task); 222 0 : de->mhd_task = NULL; 223 : } 224 114 : MHD_stop_daemon (mhd); 225 114 : GNUNET_CONTAINER_DLL_remove (mhd_head, 226 : mhd_tail, 227 : de); 228 114 : GNUNET_free (de); 229 : } 230 57 : } 231 : 232 : 233 : void 234 238 : TALER_MHD_daemon_trigger (void) 235 : { 236 238 : for (struct DaemonEntry *de = mhd_head; 237 714 : NULL != de; 238 476 : de = de->next) 239 : { 240 476 : if (NULL != de->mhd_task) 241 : { 242 468 : GNUNET_SCHEDULER_cancel (de->mhd_task); 243 468 : de->mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon, 244 : de); 245 : } 246 : else 247 : { 248 8 : de->triggered = true; 249 : } 250 : } 251 238 : } 252 : 253 : 254 : /* end of mhd_run.c */