diff options
Diffstat (limited to 'src/exchange/taler-exchange-httpd.c')
-rw-r--r-- | src/exchange/taler-exchange-httpd.c | 554 |
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 | */ |
70 | struct GNUNET_CONFIGURATION_Handle *TEH_cfg; | 69 | const 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; | |||
101 | static unsigned int connection_timeout = 30; | 100 | static 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 | */ |
108 | static unsigned int num_threads = 0; | 105 | static int connection_close; |
109 | 106 | ||
110 | /** | 107 | /** |
111 | * The HTTP Daemon. | 108 | * Value to return from main() |
112 | */ | 109 | */ |
113 | static struct MHD_Daemon *mhd; | 110 | static 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; | |||
118 | static uint16_t serve_port; | 115 | static uint16_t serve_port; |
119 | 116 | ||
120 | /** | 117 | /** |
121 | * Path for the unix domain-socket | ||
122 | * to run the daemon on. | ||
123 | */ | ||
124 | static char *serve_unixpath; | ||
125 | |||
126 | /** | ||
127 | * File mode for unix-domain socket. | ||
128 | */ | ||
129 | static 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 | */ |
134 | static unsigned long long req_count; | 120 | static 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 | */ |
1255 | static char *input_filename; | 1225 | static char *input_filename; |
1256 | 1226 | ||
1257 | /** | ||
1258 | * We finished handling the request and should now terminate. | ||
1259 | */ | ||
1260 | static 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 | */ | ||
1299 | static void | ||
1300 | run_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 | */ |
1361 | static int | 1374 | static void |
1362 | run_single_request (void) | 1375 | do_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 | */ |
1464 | static int | 1399 | static void |
1465 | run_main_loop (int fh, | 1400 | run (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 | |||
1592 | main (int argc, | 1501 | main (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 | ||