diff options
author | Florian Dold <florian@dold.me> | 2021-10-04 17:26:30 +0200 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2021-10-04 17:26:30 +0200 |
commit | a4b3524111d176d7374db1340f0d996eecfadff1 (patch) | |
tree | d402af36a6a3b402baf4e9c49f35a593b9d057f3 | |
parent | 0e60574acfb81d6bc279aac469e023e5c689a21d (diff) | |
download | anastasis-a4b3524111d176d7374db1340f0d996eecfadff1.tar.gz anastasis-a4b3524111d176d7374db1340f0d996eecfadff1.zip |
allow external reducer binary to process actions
m--------- | contrib/gana | 0 | ||||
-rw-r--r-- | src/reducer/anastasis_api_redux.c | 120 |
2 files changed, 120 insertions, 0 deletions
diff --git a/contrib/gana b/contrib/gana | |||
Subproject 3b638032297cfed132912dfe82a1c47033eff03 | Subproject 90aee6a0ba5c9e3e52074a2dabe1b3b9421ad16 | ||
diff --git a/src/reducer/anastasis_api_redux.c b/src/reducer/anastasis_api_redux.c index 851be12..796e60d 100644 --- a/src/reducer/anastasis_api_redux.c +++ b/src/reducer/anastasis_api_redux.c | |||
@@ -1480,6 +1480,116 @@ typedef struct ANASTASIS_ReduxAction * | |||
1480 | ANASTASIS_ActionCallback cb, | 1480 | ANASTASIS_ActionCallback cb, |
1481 | void *cb_cls); | 1481 | void *cb_cls); |
1482 | 1482 | ||
1483 | /** | ||
1484 | * Dummy cleanup function. | ||
1485 | */ | ||
1486 | static void | ||
1487 | dummy_cleanup (void *cls) | ||
1488 | { | ||
1489 | GNUNET_assert (0); | ||
1490 | } | ||
1491 | |||
1492 | |||
1493 | /** | ||
1494 | * Handle an action using an external reducer, i.e. | ||
1495 | * by shelling out to another process. | ||
1496 | */ | ||
1497 | static struct ANASTASIS_ReduxAction * | ||
1498 | redux_action_external (const char *ext_reducer, | ||
1499 | const json_t *state, | ||
1500 | const char *action, | ||
1501 | const json_t *arguments, | ||
1502 | ANASTASIS_ActionCallback cb, | ||
1503 | void *cb_cls) | ||
1504 | { | ||
1505 | struct ANASTASIS_ReduxAction *act = NULL; | ||
1506 | int pipefd_stdout[2]; | ||
1507 | int pipefd_stdin[2]; | ||
1508 | pid_t pid = 0; | ||
1509 | int status; | ||
1510 | FILE *reducer_stdout; | ||
1511 | FILE *reducer_stdin; | ||
1512 | json_t *next_state; | ||
1513 | |||
1514 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1515 | "Using external reducer '%s'\n", | ||
1516 | ext_reducer); | ||
1517 | |||
1518 | GNUNET_assert (0 == pipe (pipefd_stdout)); | ||
1519 | GNUNET_assert (0 == pipe (pipefd_stdin)); | ||
1520 | pid = fork (); | ||
1521 | if (pid == 0) | ||
1522 | { | ||
1523 | /* Child */ | ||
1524 | |||
1525 | char *arg_str = json_dumps (arguments, JSON_COMPACT); | ||
1526 | |||
1527 | close (pipefd_stdout[0]); | ||
1528 | dup2 (pipefd_stdout[1], STDOUT_FILENO); | ||
1529 | |||
1530 | close (pipefd_stdin[1]); | ||
1531 | dup2 (pipefd_stdin[0], STDIN_FILENO); | ||
1532 | |||
1533 | /* Unset environment variable, otherwise anastasis-reducer | ||
1534 | would recursively shell out to itself. */ | ||
1535 | unsetenv ("ANASTASIS_EXTERNAL_REDUCER"); | ||
1536 | |||
1537 | execlp (ext_reducer, | ||
1538 | ext_reducer, | ||
1539 | "-a", | ||
1540 | arg_str, | ||
1541 | action, | ||
1542 | NULL); | ||
1543 | GNUNET_assert (0); | ||
1544 | } | ||
1545 | |||
1546 | /* Only parent reaches here */ | ||
1547 | |||
1548 | close (pipefd_stdout[1]); | ||
1549 | close (pipefd_stdin[0]); | ||
1550 | |||
1551 | reducer_stdout = fdopen (pipefd_stdout[0], | ||
1552 | "r"); | ||
1553 | reducer_stdin = fdopen (pipefd_stdin[1], | ||
1554 | "w"); | ||
1555 | |||
1556 | GNUNET_assert (0 == json_dumpf (state, | ||
1557 | reducer_stdin, | ||
1558 | JSON_COMPACT)); | ||
1559 | |||
1560 | GNUNET_assert (0 == fclose (reducer_stdin)); | ||
1561 | reducer_stdin = NULL; | ||
1562 | |||
1563 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1564 | "Wrote old state to reducer stdin.\n"); | ||
1565 | |||
1566 | next_state = json_loadf (reducer_stdout, | ||
1567 | 0, | ||
1568 | NULL); | ||
1569 | |||
1570 | /* FIXME: report error instead! */ | ||
1571 | GNUNET_assert (NULL != next_state); | ||
1572 | |||
1573 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1574 | "Waiting for external reducer to terminate.\n"); | ||
1575 | GNUNET_assert (0 == fclose (reducer_stdout)); | ||
1576 | reducer_stdout = NULL; | ||
1577 | waitpid (pid, &status, 0); | ||
1578 | |||
1579 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1580 | "External reducer finished with exit status '%d'\n", | ||
1581 | status); | ||
1582 | |||
1583 | act = GNUNET_new (struct ANASTASIS_ReduxAction); | ||
1584 | /* Callback is called immediately, cleanup must never be called */ | ||
1585 | act->cleanup = &dummy_cleanup; | ||
1586 | |||
1587 | cb (cb_cls, | ||
1588 | TALER_EC_NONE, | ||
1589 | next_state); | ||
1590 | return act; | ||
1591 | } | ||
1592 | |||
1483 | 1593 | ||
1484 | struct ANASTASIS_ReduxAction * | 1594 | struct ANASTASIS_ReduxAction * |
1485 | ANASTASIS_redux_action (const json_t *state, | 1595 | ANASTASIS_redux_action (const json_t *state, |
@@ -1540,6 +1650,16 @@ ANASTASIS_redux_action (const json_t *state, | |||
1540 | const char *s = json_string_value (json_object_get (state, | 1650 | const char *s = json_string_value (json_object_get (state, |
1541 | "backup_state")); | 1651 | "backup_state")); |
1542 | enum ANASTASIS_GenericState gs; | 1652 | enum ANASTASIS_GenericState gs; |
1653 | const char *ext_reducer = getenv ("ANASTASIS_EXTERNAL_REDUCER"); | ||
1654 | |||
1655 | /* If requested, handle action with external reducer, used for testing. */ | ||
1656 | if (NULL != ext_reducer) | ||
1657 | return redux_action_external (ext_reducer, | ||
1658 | state, | ||
1659 | action, | ||
1660 | arguments, | ||
1661 | cb, | ||
1662 | cb_cls); | ||
1543 | 1663 | ||
1544 | if (NULL == s) | 1664 | if (NULL == s) |
1545 | { | 1665 | { |