LCOV - code coverage report
Current view: top level - sync - sync-httpd.c (source / functions) Hit Total Coverage
Test: GNU Taler sync coverage report Lines: 135 174 77.6 %
Date: 2021-05-09 06:21:04 Functions: 9 9 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   (C) 2019 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 General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file sync/sync-httpd.c
      18             :  * @brief HTTP serving layer intended to provide basic backup operations
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include <microhttpd.h>
      23             : #include <gnunet/gnunet_util_lib.h>
      24             : #include "sync_util.h"
      25             : #include "sync-httpd.h"
      26             : #include "sync-httpd_mhd.h"
      27             : #include "sync_database_lib.h"
      28             : #include "sync-httpd_backup.h"
      29             : #include "sync-httpd_config.h"
      30             : #include "sync-httpd_terms.h"
      31             : 
      32             : /**
      33             :  * Backlog for listen operation on unix-domain sockets.
      34             :  */
      35             : #define UNIX_BACKLOG 500
      36             : 
      37             : 
      38             : /**
      39             :  * Should a "Connection: close" header be added to each HTTP response?
      40             :  */
      41             : static int SH_sync_connection_close;
      42             : 
      43             : /**
      44             :  * Upload limit to the service, in megabytes.
      45             :  */
      46             : unsigned long long int SH_upload_limit_mb;
      47             : 
      48             : /**
      49             :  * Annual fee for the backup account.
      50             :  */
      51             : struct TALER_Amount SH_annual_fee;
      52             : 
      53             : /**
      54             :  * Our Taler backend to process payments.
      55             :  */
      56             : char *SH_backend_url;
      57             : 
      58             : /**
      59             :  * Our fulfillment URL.
      60             :  */
      61             : char *SH_fulfillment_url;
      62             : 
      63             : /**
      64             :  * Our context for making HTTP requests.
      65             :  */
      66             : struct GNUNET_CURL_Context *SH_ctx;
      67             : 
      68             : /**
      69             :  * Reschedule context for #SH_ctx.
      70             :  */
      71             : static struct GNUNET_CURL_RescheduleContext *rc;
      72             : 
      73             : /**
      74             :  * Task running the HTTP server.
      75             :  */
      76             : static struct GNUNET_SCHEDULER_Task *mhd_task;
      77             : 
      78             : /**
      79             :  * Global return code
      80             :  */
      81             : static int result;
      82             : 
      83             : /**
      84             :  * The MHD Daemon
      85             :  */
      86             : static struct MHD_Daemon *mhd;
      87             : 
      88             : /**
      89             :  * Connection handle to the our database
      90             :  */
      91             : struct SYNC_DatabasePlugin *db;
      92             : 
      93             : /**
      94             :  * Username and password to use for client authentication
      95             :  * (optional).
      96             :  */
      97             : static char *userpass;
      98             : 
      99             : /**
     100             :  * Type of the client's TLS certificate (optional).
     101             :  */
     102             : static char *certtype;
     103             : 
     104             : /**
     105             :  * File with the client's TLS certificate (optional).
     106             :  */
     107             : static char *certfile;
     108             : 
     109             : /**
     110             :  * File with the client's TLS private key (optional).
     111             :  */
     112             : static char *keyfile;
     113             : 
     114             : /**
     115             :  * This value goes in the Authorization:-header.
     116             :  */
     117             : static char *apikey;
     118             : 
     119             : /**
     120             :  * Passphrase to decrypt client's TLS private key file (optional).
     121             :  */
     122             : static char *keypass;
     123             : 
     124             : 
     125             : /**
     126             :  * A client has requested the given url using the given method
     127             :  * (#MHD_HTTP_METHOD_GET, #MHD_HTTP_METHOD_PUT,
     128             :  * #MHD_HTTP_METHOD_DELETE, #MHD_HTTP_METHOD_POST, etc).  The callback
     129             :  * must call MHD callbacks to provide content to give back to the
     130             :  * client and return an HTTP status code (i.e. #MHD_HTTP_OK,
     131             :  * #MHD_HTTP_NOT_FOUND, etc.).
     132             :  *
     133             :  * @param cls argument given together with the function
     134             :  *        pointer when the handler was registered with MHD
     135             :  * @param url the requested url
     136             :  * @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
     137             :  *        #MHD_HTTP_METHOD_PUT, etc.)
     138             :  * @param version the HTTP version string (i.e.
     139             :  *        #MHD_HTTP_VERSION_1_1)
     140             :  * @param upload_data the data being uploaded (excluding HEADERS,
     141             :  *        for a POST that fits into memory and that is encoded
     142             :  *        with a supported encoding, the POST data will NOT be
     143             :  *        given in upload_data and is instead available as
     144             :  *        part of #MHD_get_connection_values; very large POST
     145             :  *        data *will* be made available incrementally in
     146             :  *        @a upload_data)
     147             :  * @param upload_data_size set initially to the size of the
     148             :  *        @a upload_data provided; the method must update this
     149             :  *        value to the number of bytes NOT processed;
     150             :  * @param con_cls pointer that the callback can set to some
     151             :  *        address and that will be preserved by MHD for future
     152             :  *        calls for this request; since the access handler may
     153             :  *        be called many times (i.e., for a PUT/POST operation
     154             :  *        with plenty of upload data) this allows the application
     155             :  *        to easily associate some request-specific state.
     156             :  *        If necessary, this state can be cleaned up in the
     157             :  *        global #MHD_RequestCompletedCallback (which
     158             :  *        can be set with the #MHD_OPTION_NOTIFY_COMPLETED).
     159             :  *        Initially, `*con_cls` will be NULL.
     160             :  * @return #MHD_YES if the connection was handled successfully,
     161             :  *         #MHD_NO if the socket must be closed due to a serious
     162             :  *         error while handling the request
     163             :  */
     164             : static MHD_RESULT
     165          16 : url_handler (void *cls,
     166             :              struct MHD_Connection *connection,
     167             :              const char *url,
     168             :              const char *method,
     169             :              const char *version,
     170             :              const char *upload_data,
     171             :              size_t *upload_data_size,
     172             :              void **con_cls)
     173             : {
     174             :   static struct SH_RequestHandler handlers[] = {
     175             :     /* Landing page, tell humans to go away. */
     176             :     { "/", MHD_HTTP_METHOD_GET, "text/plain",
     177             :       "Hello, I'm sync. This HTTP server is not for humans.\n", 0,
     178             :       &SH_MHD_handler_static_response, MHD_HTTP_OK },
     179             :     { "/agpl", MHD_HTTP_METHOD_GET, "text/plain",
     180             :       NULL, 0,
     181             :       &SH_handler_config, MHD_HTTP_FOUND },
     182             :     { "/config", MHD_HTTP_METHOD_GET, "text/json",
     183             :       NULL, 0,
     184             :       &SH_handler_terms, MHD_HTTP_OK },
     185             :     { "/terms", MHD_HTTP_METHOD_GET, "text/plain",
     186             :       NULL, 0,
     187             :       &SH_handler_terms, MHD_HTTP_OK },
     188             :     {NULL, NULL, NULL, NULL, 0, 0 }
     189             :   };
     190             :   static struct SH_RequestHandler h404 = {
     191             :     "", NULL, "text/html",
     192             :     "<html><title>404: not found</title></html>", 0,
     193             :     &SH_MHD_handler_static_response, MHD_HTTP_NOT_FOUND
     194             :   };
     195             : 
     196             :   struct TM_HandlerContext *hc;
     197             :   struct GNUNET_AsyncScopeId aid;
     198          16 :   const char *correlation_id = NULL;
     199             :   struct SYNC_AccountPublicKeyP account_pub;
     200             : 
     201             :   (void) cls;
     202             :   (void) version;
     203          16 :   hc = *con_cls;
     204          16 :   if (NULL == hc)
     205             :   {
     206           9 :     GNUNET_async_scope_fresh (&aid);
     207             :     /* We only read the correlation ID on the first callback for every client */
     208           9 :     correlation_id = MHD_lookup_connection_value (connection,
     209             :                                                   MHD_HEADER_KIND,
     210             :                                                   "Sync-Correlation-Id");
     211           9 :     if ((NULL != correlation_id) &&
     212           0 :         (GNUNET_YES != GNUNET_CURL_is_valid_scope_id (correlation_id)))
     213             :     {
     214           0 :       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
     215             :                   "illegal incoming correlation ID\n");
     216           0 :       correlation_id = NULL;
     217             :     }
     218             :   }
     219             :   else
     220             :   {
     221           7 :     aid = hc->async_scope_id;
     222             :   }
     223          16 :   GNUNET_SCHEDULER_begin_async_scope (&aid);
     224             : 
     225          16 :   if (NULL != correlation_id)
     226           0 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     227             :                 "Handling request for (%s) URL '%s', correlation_id=%s\n",
     228             :                 method,
     229             :                 url,
     230             :                 correlation_id);
     231             :   else
     232          16 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     233             :                 "Handling request (%s) for URL '%s'\n",
     234             :                 method,
     235             :                 url);
     236             : 
     237          16 :   if (0 == strncmp (url,
     238             :                     "/backups/",
     239             :                     strlen ("/backups/")))
     240             :   {
     241          15 :     const char *ac = &url[strlen ("/backups/")];
     242             : 
     243          15 :     if (GNUNET_OK !=
     244          15 :         GNUNET_CRYPTO_eddsa_public_key_from_string (ac,
     245             :                                                     strlen (ac),
     246             :                                                     &account_pub.eddsa_pub))
     247             :     {
     248           0 :       GNUNET_break_op (0);
     249           0 :       return TALER_MHD_reply_with_error (connection,
     250             :                                          MHD_HTTP_BAD_REQUEST,
     251             :                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
     252             :                                          ac);
     253             :     }
     254          15 :     if (0 == strcasecmp (method,
     255             :                          MHD_HTTP_METHOD_OPTIONS))
     256             :     {
     257           0 :       return TALER_MHD_reply_cors_preflight (connection);
     258             :     }
     259          15 :     if (0 == strcasecmp (method,
     260             :                          MHD_HTTP_METHOD_GET))
     261             :     {
     262           3 :       return SH_backup_get (connection,
     263             :                             &account_pub);
     264             :     }
     265          12 :     if (0 == strcasecmp (method,
     266             :                          MHD_HTTP_METHOD_POST))
     267             :     {
     268             :       int ret;
     269             : 
     270          12 :       ret = SH_backup_post (connection,
     271             :                             con_cls,
     272             :                             &account_pub,
     273             :                             upload_data,
     274             :                             upload_data_size);
     275          12 :       hc = *con_cls;
     276          12 :       if (NULL != hc)
     277             :       {
     278             :         /* Store the async context ID, so we can restore it if
     279             :          * we get another callback for this request. */
     280          12 :         hc->async_scope_id = aid;
     281             :       }
     282          12 :       return ret;
     283             :     }
     284             :   }
     285           1 :   for (unsigned int i = 0; NULL != handlers[i].url; i++)
     286             :   {
     287           1 :     struct SH_RequestHandler *rh = &handlers[i];
     288             : 
     289           1 :     if (0 == strcmp (url,
     290             :                      rh->url))
     291             :     {
     292           1 :       if (0 == strcasecmp (method,
     293             :                            MHD_HTTP_METHOD_OPTIONS))
     294             :       {
     295           0 :         return TALER_MHD_reply_cors_preflight (connection);
     296             :       }
     297           1 :       if ( (NULL == rh->method) ||
     298           1 :            (0 == strcasecmp (method,
     299             :                              rh->method)) )
     300             :       {
     301             :         MHD_RESULT ret;
     302             : 
     303           1 :         ret = rh->handler (rh,
     304             :                            connection,
     305             :                            con_cls,
     306             :                            upload_data,
     307             :                            upload_data_size);
     308           1 :         hc = *con_cls;
     309           1 :         if (NULL != hc)
     310             :         {
     311             :           /* Store the async context ID, so we can restore it if
     312             :            * we get another callback for this request. */
     313           0 :           hc->async_scope_id = aid;
     314             :         }
     315           1 :         return ret;
     316             :       }
     317             :     }
     318             :   }
     319           0 :   return SH_MHD_handler_static_response (&h404,
     320             :                                          connection,
     321             :                                          con_cls,
     322             :                                          upload_data,
     323             :                                          upload_data_size);
     324             : }
     325             : 
     326             : 
     327             : /**
     328             :  * Shutdown task. Invoked when the application is being terminated.
     329             :  *
     330             :  * @param cls NULL
     331             :  */
     332             : static void
     333           1 : do_shutdown (void *cls)
     334             : {
     335             :   (void) cls;
     336           1 :   SH_resume_all_bc ();
     337           1 :   if (NULL != mhd_task)
     338             :   {
     339           1 :     GNUNET_SCHEDULER_cancel (mhd_task);
     340           1 :     mhd_task = NULL;
     341             :   }
     342           1 :   if (NULL != SH_ctx)
     343             :   {
     344           1 :     GNUNET_CURL_fini (SH_ctx);
     345           1 :     SH_ctx = NULL;
     346             :   }
     347           1 :   if (NULL != rc)
     348             :   {
     349           1 :     GNUNET_CURL_gnunet_rc_destroy (rc);
     350           1 :     rc = NULL;
     351             :   }
     352           1 :   if (NULL != mhd)
     353             :   {
     354           1 :     MHD_stop_daemon (mhd);
     355           1 :     mhd = NULL;
     356             :   }
     357           1 :   if (NULL != db)
     358             :   {
     359           1 :     SYNC_DB_plugin_unload (db);
     360           1 :     db = NULL;
     361             :   }
     362           1 : }
     363             : 
     364             : 
     365             : /**
     366             :  * Function called whenever MHD is done with a request.  If the
     367             :  * request was a POST, we may have stored a `struct Buffer *` in the
     368             :  * @a con_cls that might still need to be cleaned up.  Call the
     369             :  * respective function to free the memory.
     370             :  *
     371             :  * @param cls client-defined closure
     372             :  * @param connection connection handle
     373             :  * @param con_cls value as set by the last call to
     374             :  *        the #MHD_AccessHandlerCallback
     375             :  * @param toe reason for request termination
     376             :  * @see #MHD_OPTION_NOTIFY_COMPLETED
     377             :  * @ingroup request
     378             :  */
     379             : static void
     380           9 : handle_mhd_completion_callback (void *cls,
     381             :                                 struct MHD_Connection *connection,
     382             :                                 void **con_cls,
     383             :                                 enum MHD_RequestTerminationCode toe)
     384             : {
     385           9 :   struct TM_HandlerContext *hc = *con_cls;
     386             : 
     387             :   (void) cls;
     388             :   (void) connection;
     389           9 :   if (NULL == hc)
     390           4 :     return;
     391           5 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     392             :               "Finished handling request with status %d\n",
     393             :               (int) toe);
     394           5 :   hc->cc (hc);
     395           5 :   *con_cls = NULL;
     396             : }
     397             : 
     398             : 
     399             : /**
     400             :  * Function that queries MHD's select sets and
     401             :  * starts the task waiting for them.
     402             :  */
     403             : static struct GNUNET_SCHEDULER_Task *
     404             : prepare_daemon (void);
     405             : 
     406             : 
     407             : /**
     408             :  * Set if we should immediately #MHD_run again.
     409             :  */
     410             : static int triggered;
     411             : 
     412             : 
     413             : /**
     414             :  * Call MHD to process pending requests and then go back
     415             :  * and schedule the next run.
     416             :  *
     417             :  * @param cls the `struct MHD_Daemon` of the HTTP server to run
     418             :  */
     419             : static void
     420          25 : run_daemon (void *cls)
     421             : {
     422             :   (void) cls;
     423          25 :   mhd_task = NULL;
     424             :   do {
     425          25 :     triggered = 0;
     426          25 :     GNUNET_assert (MHD_YES == MHD_run (mhd));
     427          25 :   } while (0 != triggered);
     428          25 :   mhd_task = prepare_daemon ();
     429          25 : }
     430             : 
     431             : 
     432             : /**
     433             :  * Kick MHD to run now, to be called after MHD_resume_connection().
     434             :  * Basically, we need to explicitly resume MHD's event loop whenever
     435             :  * we made progress serving a request.  This function re-schedules
     436             :  * the task processing MHD's activities to run immediately.
     437             :  */
     438             : void
     439           3 : SH_trigger_daemon ()
     440             : {
     441           3 :   if (NULL != mhd_task)
     442             :   {
     443           3 :     GNUNET_SCHEDULER_cancel (mhd_task);
     444           3 :     mhd_task = GNUNET_SCHEDULER_add_now (&run_daemon,
     445             :                                          NULL);
     446             :   }
     447             :   else
     448             :   {
     449           0 :     triggered = 1;
     450             :   }
     451           3 : }
     452             : 
     453             : 
     454             : /**
     455             :  * Kick GNUnet Curl scheduler to begin curl interactions.
     456             :  */
     457             : void
     458           3 : SH_trigger_curl ()
     459             : {
     460           3 :   GNUNET_CURL_gnunet_scheduler_reschedule (&rc);
     461           3 : }
     462             : 
     463             : 
     464             : /**
     465             :  * Function that queries MHD's select sets and
     466             :  * starts the task waiting for them.
     467             :  *
     468             :  * @param daemon_handle HTTP server to prepare to run
     469             :  */
     470             : static struct GNUNET_SCHEDULER_Task *
     471          26 : prepare_daemon ()
     472             : {
     473             :   struct GNUNET_SCHEDULER_Task *ret;
     474             :   fd_set rs;
     475             :   fd_set ws;
     476             :   fd_set es;
     477             :   struct GNUNET_NETWORK_FDSet *wrs;
     478             :   struct GNUNET_NETWORK_FDSet *wws;
     479             :   int max;
     480             :   MHD_UNSIGNED_LONG_LONG timeout;
     481             :   int haveto;
     482             :   struct GNUNET_TIME_Relative tv;
     483             : 
     484          26 :   FD_ZERO (&rs);
     485          26 :   FD_ZERO (&ws);
     486          26 :   FD_ZERO (&es);
     487          26 :   wrs = GNUNET_NETWORK_fdset_create ();
     488          26 :   wws = GNUNET_NETWORK_fdset_create ();
     489          26 :   max = -1;
     490          26 :   GNUNET_assert (MHD_YES ==
     491             :                  MHD_get_fdset (mhd,
     492             :                                 &rs,
     493             :                                 &ws,
     494             :                                 &es,
     495             :                                 &max));
     496          26 :   haveto = MHD_get_timeout (mhd, &timeout);
     497          26 :   if (haveto == MHD_YES)
     498          19 :     tv.rel_value_us = (uint64_t) timeout * 1000LL;
     499             :   else
     500           7 :     tv = GNUNET_TIME_UNIT_FOREVER_REL;
     501          26 :   GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
     502          26 :   GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
     503          26 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     504             :               "Adding run_daemon select task\n");
     505          26 :   ret = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH,
     506             :                                      tv,
     507             :                                      wrs,
     508             :                                      wws,
     509             :                                      &run_daemon,
     510             :                                      NULL);
     511          26 :   GNUNET_NETWORK_fdset_destroy (wrs);
     512          26 :   GNUNET_NETWORK_fdset_destroy (wws);
     513          26 :   return ret;
     514             : }
     515             : 
     516             : 
     517             : /**
     518             :  * Main function that will be run by the scheduler.
     519             :  *
     520             :  * @param cls closure
     521             :  * @param args remaining command-line arguments
     522             :  * @param cfgfile name of the configuration file used (for saving, can be
     523             :  *        NULL!)
     524             :  * @param config configuration
     525             :  */
     526             : static void
     527           1 : run (void *cls,
     528             :      char *const *args,
     529             :      const char *cfgfile,
     530             :      const struct GNUNET_CONFIGURATION_Handle *config)
     531             : {
     532             :   int fh;
     533             :   enum TALER_MHD_GlobalOptions go;
     534             :   uint16_t port;
     535             : 
     536           1 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     537             :               "Starting sync-httpd\n");
     538           1 :   go = TALER_MHD_GO_NONE;
     539           1 :   if (SH_sync_connection_close)
     540           0 :     go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE;
     541           1 :   TALER_MHD_setup (go);
     542           1 :   result = GNUNET_SYSERR;
     543           1 :   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
     544             :                                  NULL);
     545           1 :   GNUNET_assert (GNUNET_OK ==
     546             :                  GNUNET_log_setup ("sync-httpd",
     547             :                                    "WARNING",
     548             :                                    NULL));
     549           1 :   if (GNUNET_OK !=
     550           1 :       GNUNET_CONFIGURATION_get_value_number (config,
     551             :                                              "sync",
     552             :                                              "UPLOAD_LIMIT_MB",
     553             :                                              &SH_upload_limit_mb))
     554             :   {
     555           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     556             :                                "sync",
     557             :                                "UPLOAD_LIMIT_MB");
     558           0 :     GNUNET_SCHEDULER_shutdown ();
     559           0 :     return;
     560             :   }
     561           1 :   if (GNUNET_OK !=
     562           1 :       TALER_config_get_amount (config,
     563             :                                "sync",
     564             :                                "ANNUAL_FEE",
     565             :                                &SH_annual_fee))
     566             :   {
     567           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     568             :                                "sync",
     569             :                                "ANNUAL_FEE");
     570           0 :     GNUNET_SCHEDULER_shutdown ();
     571           0 :     return;
     572             :   }
     573           1 :   if (GNUNET_OK !=
     574           1 :       GNUNET_CONFIGURATION_get_value_string (config,
     575             :                                              "sync",
     576             :                                              "PAYMENT_BACKEND_URL",
     577             :                                              &SH_backend_url))
     578             :   {
     579           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     580             :                                "sync",
     581             :                                "PAYMENT_BACKEND_URL");
     582           0 :     GNUNET_SCHEDULER_shutdown ();
     583           0 :     return;
     584             :   }
     585           1 :   if (GNUNET_OK !=
     586           1 :       GNUNET_CONFIGURATION_get_value_string (config,
     587             :                                              "sync",
     588             :                                              "FULFILLMENT_URL",
     589             :                                              &SH_fulfillment_url))
     590             :   {
     591           0 :     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
     592             :                                "sync",
     593             :                                "BASE_URL");
     594           0 :     GNUNET_SCHEDULER_shutdown ();
     595           0 :     return;
     596             :   }
     597             : 
     598             :   /* setup HTTP client event loop */
     599           1 :   SH_ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
     600             :                              &rc);
     601           1 :   rc = GNUNET_CURL_gnunet_rc_create (SH_ctx);
     602           1 :   if (NULL != userpass)
     603           0 :     GNUNET_CURL_set_userpass (SH_ctx,
     604             :                               userpass);
     605           1 :   if (NULL != keyfile)
     606           0 :     GNUNET_CURL_set_tlscert (SH_ctx,
     607             :                              certtype,
     608             :                              certfile,
     609             :                              keyfile,
     610             :                              keypass);
     611           1 :   if (NULL != apikey)
     612             :   {
     613             :     char *auth_header;
     614             : 
     615           0 :     GNUNET_asprintf (&auth_header,
     616             :                      "%s: %s",
     617             :                      MHD_HTTP_HEADER_AUTHORIZATION,
     618             :                      apikey);
     619           0 :     if (GNUNET_OK !=
     620           0 :         GNUNET_CURL_append_header (SH_ctx,
     621             :                                    auth_header))
     622             :     {
     623           0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     624             :                   "Failed so set %s header, trying without\n",
     625             :                   MHD_HTTP_HEADER_AUTHORIZATION);
     626             :     }
     627           0 :     GNUNET_free (auth_header);
     628             :   }
     629             : 
     630           1 :   if (NULL ==
     631           1 :       (db = SYNC_DB_plugin_load (config)))
     632             :   {
     633           0 :     GNUNET_SCHEDULER_shutdown ();
     634           0 :     return;
     635             :   }
     636             : 
     637           1 :   fh = TALER_MHD_bind (config,
     638             :                        "sync",
     639             :                        &port);
     640           1 :   if ( (0 == port) &&
     641             :        (-1 == fh) )
     642             :   {
     643           0 :     GNUNET_SCHEDULER_shutdown ();
     644           0 :     return;
     645             :   }
     646           1 :   mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME | MHD_USE_DUAL_STACK,
     647             :                           port,
     648             :                           NULL, NULL,
     649             :                           &url_handler, NULL,
     650             :                           MHD_OPTION_LISTEN_SOCKET, fh,
     651             :                           MHD_OPTION_NOTIFY_COMPLETED,
     652             :                           &handle_mhd_completion_callback, NULL,
     653             :                           MHD_OPTION_CONNECTION_TIMEOUT, (unsigned
     654             :                                                           int) 10 /* 10s */,
     655             :                           MHD_OPTION_END);
     656           1 :   if (NULL == mhd)
     657             :   {
     658           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     659             :                 "Failed to launch HTTP service, exiting.\n");
     660           0 :     GNUNET_SCHEDULER_shutdown ();
     661           0 :     return;
     662             :   }
     663           1 :   result = GNUNET_OK;
     664           1 :   mhd_task = prepare_daemon ();
     665             : }
     666             : 
     667             : 
     668             : /**
     669             :  * The main function of the serve tool
     670             :  *
     671             :  * @param argc number of arguments from the command line
     672             :  * @param argv command line arguments
     673             :  * @return 0 ok, 1 on error
     674             :  */
     675             : int
     676           1 : main (int argc,
     677             :       char *const *argv)
     678             : {
     679           1 :   struct GNUNET_GETOPT_CommandLineOption options[] = {
     680           1 :     GNUNET_GETOPT_option_string ('A',
     681             :                                  "auth",
     682             :                                  "USERNAME:PASSWORD",
     683             :                                  "use the given USERNAME and PASSWORD for client authentication",
     684             :                                  &userpass),
     685           1 :     GNUNET_GETOPT_option_flag ('C',
     686             :                                "connection-close",
     687             :                                "force HTTP connections to be closed after each request",
     688             :                                &SH_sync_connection_close),
     689           1 :     GNUNET_GETOPT_option_string ('k',
     690             :                                  "key",
     691             :                                  "KEYFILE",
     692             :                                  "file with the private TLS key for TLS client authentication",
     693             :                                  &keyfile),
     694           1 :     GNUNET_GETOPT_option_string ('p',
     695             :                                  "pass",
     696             :                                  "KEYFILEPASSPHRASE",
     697             :                                  "passphrase needed to decrypt the TLS client private key file",
     698             :                                  &keypass),
     699           1 :     GNUNET_GETOPT_option_string ('K',
     700             :                                  "apikey",
     701             :                                  "APIKEY",
     702             :                                  "API key to use in the HTTP request",
     703             :                                  &apikey),
     704           1 :     GNUNET_GETOPT_option_string ('t',
     705             :                                  "type",
     706             :                                  "CERTTYPE",
     707             :                                  "type of the TLS client certificate, defaults to PEM if not specified",
     708             :                                  &certtype),
     709             :     GNUNET_GETOPT_OPTION_END
     710             :   };
     711             : 
     712             :   /* FIRST get the libtalerutil initialization out
     713             :      of the way. Then throw that one away, and force
     714             :      the SYNC defaults to be used! */
     715           1 :   (void) TALER_project_data_default ();
     716           1 :   GNUNET_OS_init (SYNC_project_data_default ());
     717           1 :   if (GNUNET_OK !=
     718           1 :       GNUNET_PROGRAM_run (argc, argv,
     719             :                           "sync-httpd",
     720             :                           "sync HTTP interface",
     721             :                           options,
     722             :                           &run, NULL))
     723           0 :     return 3;
     724           1 :   return (GNUNET_OK == result) ? 0 : 1;
     725             : }

Generated by: LCOV version 1.14