/* This file is part of Taler Copyright (C) 2008--2014, 2016 GNUnet e.V. Copyright (C) 2018 Taler Systems SA Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Taler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Taler; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /** * @file taler-twister.c * @brief command line utility to batch commands to the twister. * @author Marcello Stanisci */ #include "platform.h" #include "taler_twister_service.h" /** * The handle to the Twister service */ static struct TALER_TWISTER_Handle *tth; /** * The program status; 0 for success. */ static int status; /** * Response code to substitute to the genuine one. 0 for no * substitution. */ static unsigned int hack_response_code; /** * Path to a object to be deleted. The format is "object-like": * path "field0.field1.2.field3" will delete the following object: * * {"field1": {"field2": [0, 1, {"field3": "TO DELETE!"}]}}. */ static char *delete_path; /** * If true, will randomly truncate the proxied response. */ static int malform_response; /** * If true, will randomly truncate the proxied request. */ static int malform_upload; /** * Path to the string-object to flip, belonging to the * response JSON object. */ static char *flip_path_dl; /** * Path to the string-object to flip, belonging to the * request JSON object. */ static char *flip_path_ul; /** * Path to the field to modify, from the response JSON object. */ static char *modify_path_dl; /* * Path to the field to modify, from the request JSON object. */ static char *modify_path_ul; /** * New value for the object pointed by `modify_path_(ul|dl)`. */ static char *modify_value; /** * This option is used to check whether the twister can accept * connections over the unix domain socket interface. Used when * launching it to see if everything (?) is okay. */ static int check_alive; /** * Number of operations we batched. */ static unsigned int num_ops; /** * Task to shutdown and clean up all state * * @param cls NULL */ static void do_shutdown (void *cls) { if (NULL != tth) { TALER_TWISTER_disconnect (tth); tth = NULL; } } /** * Callback invoked after the twister batched one operation. * * @param cls NULL */ static void handle_acknowledgement (void *cls) { num_ops--; if (0 != num_ops) return; status = 0; GNUNET_SCHEDULER_shutdown (); } /** * Method that batches operations into the twister. * * @param cls unused * @param args remaining args, unused * @param cfgfile name of the configuration * @param cfg configuration handle */ static void run (void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { tth = TALER_TWISTER_connect (cfg); GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); if (NULL == tth) { GNUNET_break (0); GNUNET_SCHEDULER_shutdown (); return; } if ( (0 != malform_upload) && (NULL != TALER_TWISTER_malform_upload (tth, &handle_acknowledgement, NULL))) num_ops++; if ( (0 != malform_response) && (NULL != TALER_TWISTER_malform (tth, &handle_acknowledgement, NULL))) num_ops++; if (0 != check_alive) { fprintf (stderr, "Could connect to twister via IPC socket.\n"); status = 0; } if ( (0 != hack_response_code) && (NULL != TALER_TWISTER_change_response_code (tth, hack_response_code, &handle_acknowledgement, NULL)) ) num_ops++; if ( (NULL != flip_path_ul) && (NULL != TALER_TWISTER_flip_upload (tth, flip_path_ul, &handle_acknowledgement, NULL)) ) num_ops++; if ( (NULL != flip_path_dl) && (NULL != TALER_TWISTER_flip_download (tth, flip_path_dl, &handle_acknowledgement, NULL)) ) num_ops++; if ( (NULL != delete_path) && (NULL != TALER_TWISTER_delete_path (tth, delete_path, &handle_acknowledgement, NULL)) ) num_ops++; if (NULL != modify_path_ul) { if (NULL == modify_value) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "New value not given, give -V|--value also\n"); GNUNET_SCHEDULER_shutdown (); return; } if (NULL != TALER_TWISTER_modify_path_ul (tth, modify_path_ul, modify_value, &handle_acknowledgement, NULL)) num_ops++; } if (NULL != modify_path_dl) { if (NULL == modify_value) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "New value not given, give -V|--value also\n"); GNUNET_SCHEDULER_shutdown (); return; } if (NULL != TALER_TWISTER_modify_path_dl (tth, modify_path_dl, modify_value, &handle_acknowledgement, NULL)) num_ops++; } if (0 == num_ops) { fprintf (stderr, "No valid hacks specified!\n"); GNUNET_SCHEDULER_shutdown (); return; } } /** * Main function. * * @param argc number of CLI arguments given + 1. * @param argv array of CLI arguments given, + the binary name. * @return 0 on success */ int main (int argc, char *const *argv) { struct GNUNET_GETOPT_CommandLineOption options[] = { GNUNET_GETOPT_option_string ('X', "modify-ul", "PATH", gettext_noop ("Modify upload object pointed by PATH," " require --value.\n"), &modify_path_ul), GNUNET_GETOPT_option_string ('m', "modify-dl", "PATH", gettext_noop ("Modify download object pointed by PATH," " require --value.\n"), &modify_path_dl), GNUNET_GETOPT_option_string ('F', "flip-ul", "PATH", gettext_noop ("Flip a char in the *string* upload object" " pointed by PATH.\n"), &flip_path_ul), GNUNET_GETOPT_option_string ('f', "flip-dl", "PATH", gettext_noop ("Flip a char in the *string* download" " object pointed by PATH.\n"), &flip_path_dl), GNUNET_GETOPT_option_string ('V', "value", "VALUE", gettext_noop ("Make VALUE the new value of the field" " pointed by PATH. Note: in this version," " numbers will be always parsed and _set_" " as strings."), &modify_value), GNUNET_GETOPT_option_string ('d', "deleteobject", "PATH", gettext_noop ("Delete the object pointed by PATH.\n"), &delete_path), GNUNET_GETOPT_option_flag ('a', "checkalive", gettext_noop ("Check if twister accepts IPC connections\n"), &check_alive), GNUNET_GETOPT_option_flag ('U', "malformupload", gettext_noop ("Randomly truncate proxied request"), &malform_upload), GNUNET_GETOPT_option_flag ('M', "malform", gettext_noop ("Randomly truncate proxied response"), &malform_response), GNUNET_GETOPT_option_uint ('r', "responsecode", "STATUS", gettext_noop ("Set the next response code to STATUS"), &hack_response_code), GNUNET_GETOPT_OPTION_END }; status = 1; if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "taler-twister", gettext_noop ("Control taler-twister service."), options, &run, NULL)) return 2; return status; }