summaryrefslogtreecommitdiff
path: root/src/reducer/anastasis_api_redux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/reducer/anastasis_api_redux.c')
-rw-r--r--src/reducer/anastasis_api_redux.c120
1 files changed, 120 insertions, 0 deletions
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)
{