aboutsummaryrefslogtreecommitdiff
path: root/src/exchange/taler-exchange-httpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/exchange/taler-exchange-httpd.c')
-rw-r--r--src/exchange/taler-exchange-httpd.c554
1 files changed, 167 insertions, 387 deletions
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index c06695e4d..627ac00f9 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of TALER 2 This file is part of TALER
3 Copyright (C) 2014-2020 Taler Systems SA 3 Copyright (C) 2014-2021 Taler Systems SA
4 4
5 TALER is free software; you can redistribute it and/or modify it under the 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 6 terms of the GNU Affero General Public License as published by the Free Software
@@ -34,7 +34,6 @@
34#include "taler-exchange-httpd_deposits_get.h" 34#include "taler-exchange-httpd_deposits_get.h"
35#include "taler-exchange-httpd_keys.h" 35#include "taler-exchange-httpd_keys.h"
36#include "taler-exchange-httpd_link.h" 36#include "taler-exchange-httpd_link.h"
37#include "taler-exchange-httpd_loop.h"
38#include "taler-exchange-httpd_management.h" 37#include "taler-exchange-httpd_management.h"
39#include "taler-exchange-httpd_melt.h" 38#include "taler-exchange-httpd_melt.h"
40#include "taler-exchange-httpd_mhd.h" 39#include "taler-exchange-httpd_mhd.h"
@@ -53,7 +52,7 @@
53/** 52/**
54 * Backlog for listen operation on unix domain sockets. 53 * Backlog for listen operation on unix domain sockets.
55 */ 54 */
56#define UNIX_BACKLOG 500 55#define UNIX_BACKLOG 50
57 56
58 57
59/** 58/**
@@ -67,7 +66,7 @@ int TEH_allow_keys_timetravel;
67/** 66/**
68 * The exchange's configuration (global) 67 * The exchange's configuration (global)
69 */ 68 */
70struct GNUNET_CONFIGURATION_Handle *TEH_cfg; 69const struct GNUNET_CONFIGURATION_Handle *TEH_cfg;
71 70
72/** 71/**
73 * How long is caching /keys allowed at most? (global) 72 * How long is caching /keys allowed at most? (global)
@@ -101,16 +100,14 @@ char *TEH_currency;
101static unsigned int connection_timeout = 30; 100static unsigned int connection_timeout = 30;
102 101
103/** 102/**
104 * How many threads to use. 103 * -C command-line flag given?
105 * The default value (0) sets the actual number of threads
106 * based on the number of available cores.
107 */ 104 */
108static unsigned int num_threads = 0; 105static int connection_close;
109 106
110/** 107/**
111 * The HTTP Daemon. 108 * Value to return from main()
112 */ 109 */
113static struct MHD_Daemon *mhd; 110static int global_ret;
114 111
115/** 112/**
116 * Port to run the daemon on. 113 * Port to run the daemon on.
@@ -118,17 +115,6 @@ static struct MHD_Daemon *mhd;
118static uint16_t serve_port; 115static uint16_t serve_port;
119 116
120/** 117/**
121 * Path for the unix domain-socket
122 * to run the daemon on.
123 */
124static char *serve_unixpath;
125
126/**
127 * File mode for unix-domain socket.
128 */
129static mode_t unixpath_mode;
130
131/**
132 * Counter for the number of requests this HTTP has processed so far. 118 * Counter for the number of requests this HTTP has processed so far.
133 */ 119 */
134static unsigned long long req_count; 120static unsigned long long req_count;
@@ -302,11 +288,8 @@ handle_mhd_completion_callback (void *cls,
302 288
303 TALER_MHD_parse_post_cleanup_callback (rc->opaque_post_parsing_context); 289 TALER_MHD_parse_post_cleanup_callback (rc->opaque_post_parsing_context);
304 /* Sanity-check that we didn't leave any transactions hanging */ 290 /* Sanity-check that we didn't leave any transactions hanging */
305 /* NOTE: In high-performance production, we could consider 291 GNUNET_break (GNUNET_OK ==
306 removing this as it should not be needed and might be costly 292 TEH_plugin->preflight (TEH_plugin->cls));
307 (to be benchmarked). */
308 TEH_plugin->preflight (TEH_plugin->cls,
309 TEH_plugin->get_session (TEH_plugin->cls));
310 GNUNET_free (rc); 293 GNUNET_free (rc);
311 *con_cls = NULL; 294 *con_cls = NULL;
312 GNUNET_async_scope_restore (&old_scope); 295 GNUNET_async_scope_restore (&old_scope);
@@ -1179,18 +1162,6 @@ exchange_serve_process_config (void)
1179 "Failed to initialize DB subsystem\n"); 1162 "Failed to initialize DB subsystem\n");
1180 return GNUNET_SYSERR; 1163 return GNUNET_SYSERR;
1181 } 1164 }
1182
1183 if (GNUNET_OK !=
1184 TALER_MHD_parse_config (TEH_cfg,
1185 "exchange",
1186 &serve_port,
1187 &serve_unixpath,
1188 &unixpath_mode))
1189 {
1190 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1191 "Failed to setup HTTPd subsystem\n");
1192 return GNUNET_SYSERR;
1193 }
1194 return GNUNET_OK; 1165 return GNUNET_OK;
1195} 1166}
1196 1167
@@ -1248,16 +1219,11 @@ write_stats (void)
1248/* Developer logic for supporting the `-f' option. */ 1219/* Developer logic for supporting the `-f' option. */
1249#if HAVE_DEVELOPER 1220#if HAVE_DEVELOPER
1250 1221
1251
1252/** 1222/**
1253 * Option `-f' (specifies an input file to give to the HTTP server). 1223 * Option `-f' (specifies an input file to give to the HTTP server).
1254 */ 1224 */
1255static char *input_filename; 1225static char *input_filename;
1256 1226
1257/**
1258 * We finished handling the request and should now terminate.
1259 */
1260static int do_terminate;
1261 1227
1262/** 1228/**
1263 * Run 'nc' or 'ncat' as a fake HTTP client using #input_filename 1229 * Run 'nc' or 'ncat' as a fake HTTP client using #input_filename
@@ -1277,7 +1243,8 @@ run_fake_client (void)
1277 "-")) 1243 "-"))
1278 fd = STDIN_FILENO; 1244 fd = STDIN_FILENO;
1279 else 1245 else
1280 fd = open (input_filename, O_RDONLY); 1246 fd = open (input_filename,
1247 O_RDONLY);
1281 if (-1 == fd) 1248 if (-1 == fd)
1282 { 1249 {
1283 fprintf (stderr, 1250 fprintf (stderr,
@@ -1325,6 +1292,50 @@ run_fake_client (void)
1325 1292
1326 1293
1327/** 1294/**
1295 * Run the exchange to serve a single request only, without threads.
1296 *
1297 * @return #GNUNET_OK on success
1298 */
1299static void
1300run_single_request (void)
1301{
1302 pid_t xfork;
1303
1304 xfork = fork ();
1305 if (-1 == xfork)
1306 {
1307 global_ret = EXIT_FAILURE;
1308 GNUNET_SCHEDULER_shutdown ();
1309 return;
1310 }
1311 if (0 == xfork)
1312 {
1313 pid_t cld;
1314
1315 cld = run_fake_client ();
1316 if (-1 == cld)
1317 _exit (EXIT_FAILURE);
1318 _exit (EXIT_SUCCESS);
1319 }
1320
1321 {
1322 int status;
1323
1324 if (xfork != waitpid (xfork,
1325 &status,
1326 0))
1327 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1328 "Waiting for `nc' child failed: %s\n",
1329 strerror (errno));
1330 }
1331}
1332
1333
1334/* end of HAVE_DEVELOPER */
1335#endif
1336
1337
1338/**
1328 * Signature of the callback used by MHD to notify the application 1339 * Signature of the callback used by MHD to notify the application
1329 * about completed connections. If we are running in test-mode with 1340 * about completed connections. If we are running in test-mode with
1330 * an #input_filename, this function is used to terminate the HTTPD 1341 * an #input_filename, this function is used to terminate the HTTPD
@@ -1344,240 +1355,138 @@ connection_done (void *cls,
1344 (void) cls; 1355 (void) cls;
1345 (void) connection; 1356 (void) connection;
1346 (void) socket_context; 1357 (void) socket_context;
1358
1359#if HAVE_DEVELOPER
1347 /* We only act if the connection is closed. */ 1360 /* We only act if the connection is closed. */
1348 if (MHD_CONNECTION_NOTIFY_CLOSED != toe) 1361 if (MHD_CONNECTION_NOTIFY_CLOSED != toe)
1349 return; 1362 return;
1350 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 1363 if (NULL != input_filename)
1351 "Connection done!\n"); 1364 GNUNET_SCHEDULER_shutdown ();
1352 do_terminate = GNUNET_YES; 1365#endif
1353} 1366}
1354 1367
1355 1368
1356/** 1369/**
1357 * Run the exchange to serve a single request only, without threads. 1370 * Function run on shutdown.
1358 * 1371 *
1359 * @return #GNUNET_OK on success 1372 * @param cls NULL
1360 */ 1373 */
1361static int 1374static void
1362run_single_request (void) 1375do_shutdown (void *cls)
1363{ 1376{
1364 pid_t cld; 1377 struct MHD_Daemon *mhd;
1365 int status; 1378 (void) cls;
1366
1367 /* run only the testfile input, then terminate */
1368 mhd
1369 = MHD_start_daemon (MHD_USE_PIPE_FOR_SHUTDOWN
1370 | MHD_USE_DEBUG | MHD_USE_DUAL_STACK
1371 | MHD_USE_TCP_FASTOPEN,
1372 0, /* pick free port */
1373 NULL, NULL,
1374 &handle_mhd_request, NULL,
1375 MHD_OPTION_LISTEN_BACKLOG_SIZE, (unsigned int) 10,
1376 MHD_OPTION_EXTERNAL_LOGGER, &TALER_MHD_handle_logs,
1377 NULL,
1378 MHD_OPTION_NOTIFY_COMPLETED,
1379 &handle_mhd_completion_callback, NULL,
1380 MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout,
1381 MHD_OPTION_NOTIFY_CONNECTION, &connection_done, NULL,
1382 MHD_OPTION_END);
1383 if (NULL == mhd)
1384 {
1385 fprintf (stderr,
1386 "Failed to start HTTP server.\n");
1387 return GNUNET_SYSERR;
1388 }
1389 serve_port = MHD_get_daemon_info (mhd,
1390 MHD_DAEMON_INFO_BIND_PORT)->port;
1391 cld = run_fake_client ();
1392 if (-1 == cld)
1393 return GNUNET_SYSERR;
1394 /* run the event loop until #connection_done() was called */
1395 while (GNUNET_NO == do_terminate)
1396 {
1397 fd_set rs;
1398 fd_set ws;
1399 fd_set es;
1400 struct timeval tv;
1401 MHD_UNSIGNED_LONG_LONG timeout;
1402 int maxsock = -1;
1403 int have_tv;
1404
1405 FD_ZERO (&rs);
1406 FD_ZERO (&ws);
1407 FD_ZERO (&es);
1408 if (MHD_YES !=
1409 MHD_get_fdset (mhd,
1410 &rs,
1411 &ws,
1412 &es,
1413 &maxsock))
1414 {
1415 GNUNET_break (0);
1416 return GNUNET_SYSERR;
1417 }
1418 have_tv = MHD_get_timeout (mhd,
1419 &timeout);
1420 tv.tv_sec = timeout / 1000;
1421 tv.tv_usec = 1000 * (timeout % 1000);
1422 if (-1 == select (maxsock + 1,
1423 &rs,
1424 &ws,
1425 &es,
1426 have_tv ? &tv : NULL))
1427 {
1428 GNUNET_break (0);
1429 return GNUNET_SYSERR;
1430 }
1431 MHD_run (mhd);
1432 }
1433 {
1434 MHD_socket sock = MHD_quiesce_daemon (mhd);
1435 1379
1436 TEH_resume_keys_requests (true); 1380 mhd = TALER_MHD_daemon_stop ();
1437 TEH_reserves_get_cleanup (); 1381 TEH_resume_keys_requests (true);
1382 TEH_reserves_get_cleanup ();
1383 if (NULL != mhd)
1438 MHD_stop_daemon (mhd); 1384 MHD_stop_daemon (mhd);
1439 GNUNET_break (0 == close (sock)); 1385 TALER_EXCHANGEDB_plugin_unload (TEH_plugin);
1440 } 1386 TEH_WIRE_done ();
1441 mhd = NULL;
1442 if (cld != waitpid (cld,
1443 &status,
1444 0))
1445 fprintf (stderr,
1446 "Waiting for `nc' child failed: %s\n",
1447 strerror (errno));
1448 return GNUNET_OK;
1449} 1387}
1450 1388
1451 1389
1452/* end of HAVE_DEVELOPER */
1453#endif
1454
1455
1456/** 1390/**
1457 * Run the ordinary multi-threaded main loop and the logic to 1391 * Main function that will be run by the scheduler.
1458 * wait for CTRL-C.
1459 * 1392 *
1460 * @param fh listen socket 1393 * @param cls closure
1461 * @param argv command line arguments 1394 * @param args remaining command-line arguments
1462 * @return #GNUNET_OK on success 1395 * @param cfgfile name of the configuration file used (for saving, can be
1396 * NULL!)
1397 * @param config configuration
1463 */ 1398 */
1464static int 1399static void
1465run_main_loop (int fh, 1400run (void *cls,
1466 char *const *argv) 1401 char *const *args,
1402 const char *cfgfile,
1403 const struct GNUNET_CONFIGURATION_Handle *config)
1467{ 1404{
1468 int ret; 1405 enum TALER_MHD_GlobalOptions go;
1469 1406 int fh;
1470 GNUNET_assert (0 < num_threads); 1407
1471 1408 go = TALER_MHD_GO_NONE;
1472 mhd 1409 if (connection_close)
1473 = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_PIPE_FOR_SHUTDOWN 1410 go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE;
1474 | MHD_USE_DEBUG | MHD_USE_DUAL_STACK 1411 TALER_MHD_setup (go);
1475 | MHD_USE_INTERNAL_POLLING_THREAD 1412 TEH_cfg = config;
1476 | MHD_ALLOW_SUSPEND_RESUME 1413
1477 | MHD_USE_TCP_FASTOPEN, 1414 if (GNUNET_OK !=
1478 (-1 == fh) ? serve_port : 0, 1415 exchange_serve_process_config ())
1479 NULL, NULL,
1480 &handle_mhd_request, NULL,
1481 MHD_OPTION_THREAD_POOL_SIZE, (unsigned int) num_threads,
1482 MHD_OPTION_LISTEN_BACKLOG_SIZE, (unsigned int) 1024,
1483 MHD_OPTION_LISTEN_SOCKET, fh,
1484 MHD_OPTION_EXTERNAL_LOGGER, &TALER_MHD_handle_logs,
1485 NULL,
1486 MHD_OPTION_NOTIFY_COMPLETED,
1487 &handle_mhd_completion_callback, NULL,
1488 MHD_OPTION_CONNECTION_TIMEOUT, connection_timeout,
1489 MHD_OPTION_END);
1490 if (NULL == mhd)
1491 { 1416 {
1492 fprintf (stderr, 1417 global_ret = EXIT_NOTCONFIGURED;
1493 "Failed to start HTTP server.\n"); 1418 GNUNET_SCHEDULER_shutdown ();
1494 return GNUNET_SYSERR; 1419 return;
1495 } 1420 }
1496 1421 if (GNUNET_OK !=
1497 atexit (&write_stats); 1422 TEH_WIRE_init ())
1498 ret = TEH_loop_run ();
1499 switch (ret)
1500 { 1423 {
1501 case GNUNET_OK: 1424 global_ret = EXIT_FAILURE;
1502 case GNUNET_SYSERR: 1425 GNUNET_SCHEDULER_shutdown ();
1503 { 1426 return;
1504 MHD_socket sock = MHD_quiesce_daemon (mhd); 1427 }
1428 if (GNUNET_OK !=
1429 TEH_keys_init ())
1430 {
1431 global_ret = EXIT_FAILURE;
1432 GNUNET_SCHEDULER_shutdown ();
1433 return;
1434 }
1505 1435
1506 TEH_resume_keys_requests (true); 1436 TEH_load_terms (TEH_cfg);
1507 TEH_reserves_get_cleanup (); 1437 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1508 MHD_stop_daemon (mhd); 1438 NULL);
1509 GNUNET_break (0 == close (sock)); 1439 fh = TALER_MHD_bind (TEH_cfg,
1510 } 1440 "exchange",
1511 mhd = NULL; 1441 &serve_port);
1512 break; 1442 if ( (0 == serve_port) &&
1513 case GNUNET_NO: 1443 (-1 == fh) )
1444 {
1445 GNUNET_SCHEDULER_shutdown ();
1446 return;
1447 }
1448 {
1449 struct MHD_Daemon *mhd;
1450
1451 mhd = MHD_start_daemon (MHD_USE_SUSPEND_RESUME
1452 | MHD_USE_PIPE_FOR_SHUTDOWN
1453 | MHD_USE_DEBUG | MHD_USE_DUAL_STACK
1454 | MHD_USE_TCP_FASTOPEN,
1455 (-1 == fh) ? serve_port : 0,
1456 NULL, NULL,
1457 &handle_mhd_request, NULL,
1458 MHD_OPTION_LISTEN_BACKLOG_SIZE,
1459 (unsigned int) 1024,
1460 MHD_OPTION_LISTEN_SOCKET,
1461 fh,
1462 MHD_OPTION_EXTERNAL_LOGGER,
1463 &TALER_MHD_handle_logs,
1464 NULL,
1465 MHD_OPTION_NOTIFY_COMPLETED,
1466 &handle_mhd_completion_callback,
1467 NULL,
1468 MHD_OPTION_NOTIFY_CONNECTION,
1469 &connection_done,
1470 NULL,
1471 MHD_OPTION_CONNECTION_TIMEOUT,
1472 connection_timeout,
1473 MHD_OPTION_END);
1474 if (NULL == mhd)
1514 { 1475 {
1515 MHD_socket sock = MHD_quiesce_daemon (mhd); 1476 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1516 pid_t chld; 1477 "Failed to launch HTTP service. Is the port in use?\n");
1517 int flags; 1478 GNUNET_SCHEDULER_shutdown ();
1518 1479 return;
1519 /* Set flags to make 'sock' inherited by child */
1520 flags = fcntl (sock, F_GETFD);
1521 GNUNET_assert (-1 != flags);
1522 flags &= ~FD_CLOEXEC;
1523 GNUNET_assert (-1 != fcntl (sock,
1524 F_SETFD,
1525 flags));
1526 chld = fork ();
1527 if (-1 == chld)
1528 {
1529 /* fork() failed, continue clean up, unhappily */
1530 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1531 "fork");
1532 }
1533 if (0 == chld)
1534 {
1535 char pids[12];
1536
1537 /* exec another taler-exchange-httpd, passing on the listen socket;
1538 as in systemd it is expected to be on FD #3 */
1539 if (3 != dup2 (sock, 3))
1540 {
1541 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1542 "dup2");
1543 _exit (1);
1544 }
1545 /* Tell the child that it is the desired recipient for FD #3 */
1546 GNUNET_snprintf (pids,
1547 sizeof (pids),
1548 "%u",
1549 getpid ());
1550 setenv ("LISTEN_PID", pids, 1);
1551 setenv ("LISTEN_FDS", "1", 1);
1552 /* Finally, exec the (presumably) more recent exchange binary */
1553 execvp ("taler-exchange-httpd",
1554 argv);
1555 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1556 "execvp");
1557 _exit (1);
1558 }
1559 /* we're the original process, handle remaining contextions
1560 before exiting; as the listen socket is no longer used,
1561 close it here */
1562 GNUNET_break (0 == close (sock));
1563 while (0 != MHD_get_daemon_info (mhd,
1564 MHD_DAEMON_INFO_CURRENT_CONNECTIONS)->
1565 num_connections)
1566 sleep (1);
1567 /* Now we're really done, practice clean shutdown */
1568 TEH_resume_keys_requests (true);
1569 TEH_reserves_get_cleanup ();
1570 MHD_stop_daemon (mhd);
1571 } 1480 }
1572 break; 1481 global_ret = EXIT_SUCCESS;
1573 default: 1482 TALER_MHD_daemon_start (mhd);
1574 GNUNET_break (0);
1575 TEH_resume_keys_requests (true);
1576 MHD_stop_daemon (mhd);
1577 break;
1578 } 1483 }
1484 atexit (&write_stats);
1579 1485
1580 return ret; 1486#if HAVE_DEVELOPER
1487 if (NULL != input_filename)
1488 run_single_request ();
1489#endif
1581} 1490}
1582 1491
1583 1492
@@ -1592,10 +1501,6 @@ int
1592main (int argc, 1501main (int argc,
1593 char *const *argv) 1502 char *const *argv)
1594{ 1503{
1595 char *cfgfile = NULL;
1596 char *loglev = NULL;
1597 char *logfile = NULL;
1598 int connection_close = GNUNET_NO;
1599 const struct GNUNET_GETOPT_CommandLineOption options[] = { 1504 const struct GNUNET_GETOPT_CommandLineOption options[] = {
1600 GNUNET_GETOPT_option_flag ('a', 1505 GNUNET_GETOPT_option_flag ('a',
1601 "allow-timetravel", 1506 "allow-timetravel",
@@ -1605,7 +1510,6 @@ main (int argc,
1605 "connection-close", 1510 "connection-close",
1606 "force HTTP connections to be closed after each request", 1511 "force HTTP connections to be closed after each request",
1607 &connection_close), 1512 &connection_close),
1608 GNUNET_GETOPT_option_cfgfile (&cfgfile),
1609 GNUNET_GETOPT_option_uint ('t', 1513 GNUNET_GETOPT_option_uint ('t',
1610 "timeout", 1514 "timeout",
1611 "SECONDS", 1515 "SECONDS",
@@ -1613,11 +1517,6 @@ main (int argc,
1613 &connection_timeout), 1517 &connection_timeout),
1614 GNUNET_GETOPT_option_timetravel ('T', 1518 GNUNET_GETOPT_option_timetravel ('T',
1615 "timetravel"), 1519 "timetravel"),
1616 GNUNET_GETOPT_option_uint ('n',
1617 "num-threads",
1618 "NUM_THREADS",
1619 "size of the thread pool",
1620 &num_threads),
1621#if HAVE_DEVELOPER 1520#if HAVE_DEVELOPER
1622 GNUNET_GETOPT_option_filename ('f', 1521 GNUNET_GETOPT_option_filename ('f',
1623 "file-input", 1522 "file-input",
@@ -1627,141 +1526,22 @@ main (int argc,
1627#endif 1526#endif
1628 GNUNET_GETOPT_option_help ( 1527 GNUNET_GETOPT_option_help (
1629 "HTTP server providing a RESTful API to access a Taler exchange"), 1528 "HTTP server providing a RESTful API to access a Taler exchange"),
1630 GNUNET_GETOPT_option_loglevel (&loglev),
1631 GNUNET_GETOPT_option_logfile (&logfile),
1632 GNUNET_GETOPT_option_version (VERSION "-" VCS_VERSION), 1529 GNUNET_GETOPT_option_version (VERSION "-" VCS_VERSION),
1633 GNUNET_GETOPT_OPTION_END 1530 GNUNET_GETOPT_OPTION_END
1634 }; 1531 };
1635 int ret; 1532 enum GNUNET_GenericReturnValue ret;
1636 const char *listen_pid;
1637 const char *listen_fds;
1638 int fh = -1;
1639 enum TALER_MHD_GlobalOptions go;
1640 1533
1641 TALER_OS_init (); 1534 TALER_OS_init ();
1642 ret = GNUNET_GETOPT_run ("taler-exchange-httpd", 1535 ret = GNUNET_PROGRAM_run (argc, argv,
1643 options, 1536 "taler-exchange-httpd",
1644 argc, argv); 1537 "Taler exchange HTTP service",
1538 options,
1539 &run, NULL);
1645 if (GNUNET_SYSERR == ret) 1540 if (GNUNET_SYSERR == ret)
1646 return EXIT_INVALIDARGUMENT; 1541 return EXIT_INVALIDARGUMENT;
1647 if (GNUNET_NO == ret) 1542 if (GNUNET_NO == ret)
1648 return EXIT_SUCCESS; 1543 return EXIT_SUCCESS;
1649 if (0 == num_threads) 1544 return global_ret;
1650 {
1651 cpu_set_t mask;
1652 GNUNET_assert (0 ==
1653 sched_getaffinity (0,
1654 sizeof (cpu_set_t),
1655 &mask));
1656 num_threads = CPU_COUNT (&mask);
1657 }
1658 go = TALER_MHD_GO_NONE;
1659 if (connection_close)
1660 go |= TALER_MHD_GO_FORCE_CONNECTION_CLOSE;
1661 TALER_MHD_setup (go);
1662 GNUNET_assert (GNUNET_OK ==
1663 GNUNET_log_setup ("taler-exchange-httpd",
1664 (NULL == loglev) ? "INFO" : loglev,
1665 logfile));
1666 GNUNET_free (loglev);
1667 GNUNET_free (logfile);
1668 if (NULL == cfgfile)
1669 cfgfile = GNUNET_CONFIGURATION_default_filename ();
1670 if (NULL == cfgfile)
1671 {
1672 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1673 "Can't find default configuration file.\n");
1674 return EXIT_NOTCONFIGURED;
1675 }
1676
1677 TEH_cfg = GNUNET_CONFIGURATION_create ();
1678 if (GNUNET_SYSERR ==
1679 GNUNET_CONFIGURATION_load (TEH_cfg,
1680 cfgfile))
1681 {
1682 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1683 "Malformed configuration file `%s', exit ...\n",
1684 cfgfile);
1685 GNUNET_free (cfgfile);
1686 return EXIT_NOTCONFIGURED;
1687 }
1688 GNUNET_free (cfgfile);
1689 if (GNUNET_OK !=
1690 exchange_serve_process_config ())
1691 return EXIT_NOTCONFIGURED;
1692 TEH_load_terms (TEH_cfg);
1693
1694 /* check for systemd-style FD passing */
1695 listen_pid = getenv ("LISTEN_PID");
1696 listen_fds = getenv ("LISTEN_FDS");
1697 if ( (NULL != listen_pid) &&
1698 (NULL != listen_fds) &&
1699 (getpid () == strtol (listen_pid,
1700 NULL,
1701 10)) &&
1702 (1 == strtoul (listen_fds,
1703 NULL,
1704 10)) )
1705 {
1706 int flags;
1707
1708 fh = 3;
1709 flags = fcntl (fh,
1710 F_GETFD);
1711 if ( (-1 == flags) &&
1712 (EBADF == errno) )
1713 {
1714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1715 "Bad listen socket passed, ignored\n");
1716 fh = -1;
1717 }
1718 flags |= FD_CLOEXEC;
1719 if ( (-1 != fh) &&
1720 (0 != fcntl (fh,
1721 F_SETFD,
1722 flags)) )
1723 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1724 "fcntl");
1725 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1726 "Successfully obtained listen socket from hypervisor\n");
1727 }
1728
1729 /* initialize #internal_key_state with an RC of 1 */
1730 if (GNUNET_OK !=
1731 TEH_WIRE_init ())
1732 return EXIT_FAILURE;
1733 if (GNUNET_OK !=
1734 TEH_keys_init ())
1735 return EXIT_FAILURE;
1736 ret = TEH_loop_init ();
1737 if (GNUNET_OK == ret)
1738 {
1739#if HAVE_DEVELOPER
1740 if (NULL != input_filename)
1741 {
1742 ret = run_single_request ();
1743 }
1744 else
1745#endif
1746 {
1747 /* consider unix path */
1748 if ( (-1 == fh) &&
1749 (NULL != serve_unixpath) )
1750 {
1751 fh = TALER_MHD_open_unix_path (serve_unixpath,
1752 unixpath_mode);
1753 if (-1 == fh)
1754 return EXIT_NOPERMISSION; /* at least most likely */
1755 }
1756 ret = run_main_loop (fh,
1757 argv);
1758 }
1759 /* release signal handlers */
1760 TEH_loop_done ();
1761 }
1762 TALER_EXCHANGEDB_plugin_unload (TEH_plugin);
1763 TEH_WIRE_done ();
1764 return (GNUNET_SYSERR == ret) ? EXIT_FAILURE : EXIT_SUCCESS;
1765} 1545}
1766 1546
1767 1547