exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

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 */