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 2518 : run_daemon (void *cls)
93 : {
94 2518 : struct DaemonEntry *de = cls;
95 :
96 2518 : de->mhd_task = NULL;
97 : do {
98 2518 : de->triggered = false;
99 2518 : GNUNET_assert (MHD_YES ==
100 : MHD_run (de->mhd));
101 2518 : } while (de->triggered);
102 2518 : prepare_daemon (de);
103 2518 : }
104 :
105 :
106 : static void
107 2564 : 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 43588 : FD_ZERO (&rs);
120 43588 : FD_ZERO (&ws);
121 43588 : FD_ZERO (&es);
122 2564 : wrs = GNUNET_NETWORK_fdset_create ();
123 2564 : wws = GNUNET_NETWORK_fdset_create ();
124 2564 : max = -1;
125 2564 : GNUNET_assert (MHD_YES ==
126 : MHD_get_fdset (de->mhd,
127 : &rs,
128 : &ws,
129 : &es,
130 : &max));
131 2564 : haveto = MHD_get_timeout (de->mhd,
132 : &timeout);
133 2564 : if (haveto == MHD_YES)
134 1778 : tv = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS,
135 : timeout);
136 : else
137 786 : tv = GNUNET_TIME_UNIT_FOREVER_REL;
138 2564 : GNUNET_NETWORK_fdset_copy_native (wrs,
139 : &rs,
140 : max + 1);
141 2564 : GNUNET_NETWORK_fdset_copy_native (wws,
142 : &ws,
143 : max + 1);
144 2564 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
145 : "Adding run_daemon select task\n");
146 : de->mhd_task
147 2564 : = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
148 : tv,
149 : wrs,
150 : wws,
151 : &run_daemon,
152 : de);
153 2564 : GNUNET_NETWORK_fdset_destroy (wrs);
154 2564 : GNUNET_NETWORK_fdset_destroy (wws);
155 2564 : }
156 :
157 :
158 : void
159 46 : TALER_MHD_daemon_start (struct MHD_Daemon *daemon)
160 : {
161 : struct DaemonEntry *de;
162 :
163 46 : de = GNUNET_new (struct DaemonEntry);
164 46 : de->mhd = daemon;
165 46 : GNUNET_CONTAINER_DLL_insert (mhd_head,
166 : mhd_tail,
167 : de);
168 46 : prepare_daemon (de);
169 46 : }
170 :
171 :
172 : void
173 23 : TALER_MHD_daemons_halt (void)
174 : {
175 23 : for (struct DaemonEntry *de = mhd_head;
176 69 : NULL != de;
177 46 : de = de->next)
178 : {
179 46 : if (NULL != de->mhd_task)
180 : {
181 46 : GNUNET_SCHEDULER_cancel (de->mhd_task);
182 46 : de->mhd_task = NULL;
183 : }
184 46 : de->triggered = false;
185 : }
186 23 : }
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 23 : TALER_MHD_daemons_destroy (void)
212 : {
213 : struct DaemonEntry *de;
214 :
215 69 : while (NULL != (de = mhd_head))
216 : {
217 46 : struct MHD_Daemon *mhd = de->mhd;
218 :
219 46 : if (NULL != de->mhd_task)
220 : {
221 0 : GNUNET_SCHEDULER_cancel (de->mhd_task);
222 0 : de->mhd_task = NULL;
223 : }
224 46 : MHD_stop_daemon (mhd);
225 46 : GNUNET_CONTAINER_DLL_remove (mhd_head,
226 : mhd_tail,
227 : de);
228 46 : GNUNET_free (de);
229 : }
230 23 : }
231 :
232 :
233 : void
234 222 : TALER_MHD_daemon_trigger (void)
235 : {
236 222 : for (struct DaemonEntry *de = mhd_head;
237 666 : NULL != de;
238 444 : de = de->next)
239 : {
240 444 : if (NULL != de->mhd_task)
241 : {
242 444 : GNUNET_SCHEDULER_cancel (de->mhd_task);
243 444 : de->mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon,
244 : de);
245 : }
246 : else
247 : {
248 0 : de->triggered = true;
249 : }
250 : }
251 222 : }
252 :
253 :
254 : /* end of mhd_run.c */
|