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.tar.bz2 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 * ANASTASIS_ActionCallback cb, void *cb_cls); +/** + * Dummy cleanup function. + */ +static void +dummy_cleanup (void *cls) +{ + GNUNET_assert (0); +} + + +/** + * Handle an action using an external reducer, i.e. + * by shelling out to another process. + */ +static struct ANASTASIS_ReduxAction * +redux_action_external (const char *ext_reducer, + const json_t *state, + const char *action, + const json_t *arguments, + ANASTASIS_ActionCallback cb, + void *cb_cls) +{ + struct ANASTASIS_ReduxAction *act = NULL; + int pipefd_stdout[2]; + int pipefd_stdin[2]; + pid_t pid = 0; + int status; + FILE *reducer_stdout; + FILE *reducer_stdin; + json_t *next_state; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Using external reducer '%s'\n", + ext_reducer); + + GNUNET_assert (0 == pipe (pipefd_stdout)); + GNUNET_assert (0 == pipe (pipefd_stdin)); + pid = fork (); + if (pid == 0) + { + /* Child */ + + char *arg_str = json_dumps (arguments, JSON_COMPACT); + + close (pipefd_stdout[0]); + dup2 (pipefd_stdout[1], STDOUT_FILENO); + + close (pipefd_stdin[1]); + dup2 (pipefd_stdin[0], STDIN_FILENO); + + /* Unset environment variable, otherwise anastasis-reducer + would recursively shell out to itself. */ + unsetenv ("ANASTASIS_EXTERNAL_REDUCER"); + + execlp (ext_reducer, + ext_reducer, + "-a", + arg_str, + action, + NULL); + GNUNET_assert (0); + } + + /* Only parent reaches here */ + + close (pipefd_stdout[1]); + close (pipefd_stdin[0]); + + reducer_stdout = fdopen (pipefd_stdout[0], + "r"); + reducer_stdin = fdopen (pipefd_stdin[1], + "w"); + + GNUNET_assert (0 == json_dumpf (state, + reducer_stdin, + JSON_COMPACT)); + + GNUNET_assert (0 == fclose (reducer_stdin)); + reducer_stdin = NULL; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Wrote old state to reducer stdin.\n"); + + next_state = json_loadf (reducer_stdout, + 0, + NULL); + + /* FIXME: report error instead! */ + GNUNET_assert (NULL != next_state); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Waiting for external reducer to terminate.\n"); + GNUNET_assert (0 == fclose (reducer_stdout)); + reducer_stdout = NULL; + waitpid (pid, &status, 0); + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "External reducer finished with exit status '%d'\n", + status); + + act = GNUNET_new (struct ANASTASIS_ReduxAction); + /* Callback is called immediately, cleanup must never be called */ + act->cleanup = &dummy_cleanup; + + cb (cb_cls, + TALER_EC_NONE, + next_state); + return act; +} + struct ANASTASIS_ReduxAction * ANASTASIS_redux_action (const json_t *state, @@ -1540,6 +1650,16 @@ ANASTASIS_redux_action (const json_t *state, const char *s = json_string_value (json_object_get (state, "backup_state")); enum ANASTASIS_GenericState gs; + const char *ext_reducer = getenv ("ANASTASIS_EXTERNAL_REDUCER"); + + /* If requested, handle action with external reducer, used for testing. */ + if (NULL != ext_reducer) + return redux_action_external (ext_reducer, + state, + action, + arguments, + cb, + cb_cls); if (NULL == s) { |