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 (5540B)


      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   de->mhd_task
    145     = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
    146                                    tv,
    147                                    wrs,
    148                                    wws,
    149                                    &run_daemon,
    150                                    de);
    151   GNUNET_NETWORK_fdset_destroy (wrs);
    152   GNUNET_NETWORK_fdset_destroy (wws);
    153 }
    154 
    155 
    156 void
    157 TALER_MHD_daemon_start (struct MHD_Daemon *daemon)
    158 {
    159   struct DaemonEntry *de;
    160 
    161   de = GNUNET_new (struct DaemonEntry);
    162   de->mhd = daemon;
    163   GNUNET_CONTAINER_DLL_insert (mhd_head,
    164                                mhd_tail,
    165                                de);
    166   prepare_daemon (de);
    167 }
    168 
    169 
    170 void
    171 TALER_MHD_daemons_halt (void)
    172 {
    173   for (struct DaemonEntry *de = mhd_head;
    174        NULL != de;
    175        de = de->next)
    176   {
    177     if (NULL != de->mhd_task)
    178     {
    179       GNUNET_SCHEDULER_cancel (de->mhd_task);
    180       de->mhd_task = NULL;
    181     }
    182     de->triggered = false;
    183   }
    184 }
    185 
    186 
    187 void
    188 TALER_MHD_daemons_quiesce (void)
    189 {
    190   for (struct DaemonEntry *de = mhd_head;
    191        NULL != de;
    192        de = de->next)
    193   {
    194     int fd;
    195 
    196     if (NULL != de->mhd_task)
    197     {
    198       GNUNET_SCHEDULER_cancel (de->mhd_task);
    199       de->mhd_task = NULL;
    200     }
    201     de->triggered = false;
    202     fd = MHD_quiesce_daemon  (de->mhd);
    203     GNUNET_break (0 == close (fd));
    204   }
    205 }
    206 
    207 
    208 void
    209 TALER_MHD_daemons_destroy (void)
    210 {
    211   struct DaemonEntry *de;
    212 
    213   while (NULL != (de = mhd_head))
    214   {
    215     struct MHD_Daemon *mhd = de->mhd;
    216 
    217     if (NULL != de->mhd_task)
    218     {
    219       GNUNET_SCHEDULER_cancel (de->mhd_task);
    220       de->mhd_task = NULL;
    221     }
    222     MHD_stop_daemon (mhd);
    223     GNUNET_CONTAINER_DLL_remove (mhd_head,
    224                                  mhd_tail,
    225                                  de);
    226     GNUNET_free (de);
    227   }
    228 }
    229 
    230 
    231 void
    232 TALER_MHD_daemon_trigger (void)
    233 {
    234   for (struct DaemonEntry *de = mhd_head;
    235        NULL != de;
    236        de = de->next)
    237   {
    238     if (NULL != de->mhd_task)
    239     {
    240       GNUNET_SCHEDULER_cancel (de->mhd_task);
    241       de->mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon,
    242                                                de);
    243     }
    244     else
    245     {
    246       de->triggered = true;
    247     }
    248   }
    249 }
    250 
    251 
    252 /* end of mhd_run.c */