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