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

Generated by: LCOV version 1.14