twister

HTTP fault injector for testing
Log | Files | Refs | README | LICENSE

taler-twister.c (8950B)


      1 /*
      2   This file is part of Taler
      3   Copyright (C) 2008--2014, 2016 GNUnet e.V.
      4   Copyright (C) 2018 Taler Systems SA
      5 
      6   Taler is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU General Public License
      8   as published by the Free Software Foundation; either version
      9   3, or (at your option) any later version.
     10 
     11   Taler is distributed in the hope that it will be useful, but
     12   WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     14   See the GNU General Public License for more details.
     15 
     16   You should have received a copy of the GNU General Public
     17   License along with Taler; see the file COPYING.  If not,
     18   write to the Free Software Foundation, Inc., 51 Franklin
     19   Street, Fifth Floor, Boston, MA 02110-1301, USA.
     20 */
     21 
     22 /**
     23  * @file taler-twister.c
     24  * @brief command line utility to batch commands to the twister.
     25  * @author Marcello Stanisci
     26  */
     27 
     28 #include "platform.h"
     29 #include "taler_twister_service.h"
     30 
     31 /**
     32  * The handle to the Twister service
     33  */
     34 static struct TALER_TWISTER_Handle *tth;
     35 
     36 /**
     37  * The program status; 0 for success.
     38  */
     39 static int status;
     40 
     41 /**
     42  * Response code to substitute to the genuine one.  0 for no
     43  * substitution.
     44  */
     45 static unsigned int hack_response_code;
     46 
     47 /**
     48  * Path to a object to be deleted.  The format is "object-like":
     49  * path "field0.field1.2.field3" will delete the following object:
     50  *
     51  * {"field1": {"field2": [0, 1, {"field3": "TO DELETE!"}]}}.
     52  */
     53 static char *delete_path;
     54 
     55 /**
     56  * If true, will randomly truncate the proxied response.
     57  */
     58 static int malform_response;
     59 
     60 /**
     61  * If true, will randomly truncate the proxied request.
     62  */
     63 static int malform_upload;
     64 
     65 /**
     66  * Path to the string-object to flip, belonging to the
     67  * response JSON object.
     68  */
     69 static char *flip_path_dl;
     70 
     71 
     72 /**
     73  * Path to the string-object to flip, belonging to the
     74  * request JSON object.
     75  */
     76 static char *flip_path_ul;
     77 
     78 /**
     79  * Path to the field to modify, from the response JSON object.
     80  */
     81 static char *modify_path_dl;
     82 
     83 /*
     84  * Path to the field to modify, from the request JSON object.
     85  */
     86 static char *modify_path_ul;
     87 
     88 /**
     89  * Name of the header to modify in the HTTP request.
     90  */
     91 static char *modify_header_dl;
     92 
     93 /**
     94  * New value for the object pointed by `modify_path_(ul|dl)`.
     95  */
     96 static char *modify_value;
     97 
     98 /**
     99  * This option is used to check whether the twister can accept
    100  * connections over the unix domain socket interface.  Used when
    101  * launching it to see if everything (?) is okay.
    102  */
    103 static int check_alive;
    104 
    105 /**
    106  * Number of operations we batched.
    107  */
    108 static unsigned int num_ops;
    109 
    110 
    111 /**
    112  * Task to shutdown and clean up all state
    113  *
    114  * @param cls NULL
    115  */
    116 static void
    117 do_shutdown (void *cls)
    118 {
    119   if (NULL != tth)
    120   {
    121     TALER_TWISTER_disconnect (tth);
    122     tth = NULL;
    123   }
    124 }
    125 
    126 
    127 /**
    128  * Callback invoked after the twister batched one operation.
    129  *
    130  * @param cls NULL
    131  */
    132 static void
    133 handle_acknowledgement (void *cls)
    134 {
    135   num_ops--;
    136   if (0 != num_ops)
    137     return;
    138   status = 0;
    139   GNUNET_SCHEDULER_shutdown ();
    140 }
    141 
    142 
    143 /**
    144  * Method that batches operations into the twister.
    145  *
    146  * @param cls unused
    147  * @param args remaining args, unused
    148  * @param cfgfile name of the configuration
    149  * @param cfg configuration handle
    150  */
    151 static void
    152 run (void *cls,
    153      char *const *args,
    154      const char *cfgfile,
    155      const struct GNUNET_CONFIGURATION_Handle *cfg)
    156 {
    157   tth = TALER_TWISTER_connect (cfg);
    158   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
    159                                  NULL);
    160   if (NULL == tth)
    161   {
    162     GNUNET_break (0);
    163     GNUNET_SCHEDULER_shutdown ();
    164     return;
    165   }
    166 
    167   if ( (0 != malform_upload) &&
    168        (NULL != TALER_TWISTER_malform_upload
    169           (tth,
    170           &handle_acknowledgement,
    171           NULL)))
    172     num_ops++;
    173 
    174   if ( (0 != malform_response) &&
    175        (NULL != TALER_TWISTER_malform
    176           (tth,
    177           &handle_acknowledgement,
    178           NULL)))
    179     num_ops++;
    180 
    181   if (0 != check_alive)
    182   {
    183     fprintf (stderr, "Could connect to twister via IPC socket.\n");
    184     status = 0;
    185   }
    186 
    187   if ( (0 != hack_response_code) &&
    188        (NULL != TALER_TWISTER_change_response_code
    189           (tth,
    190           hack_response_code,
    191           &handle_acknowledgement,
    192           NULL)) )
    193     num_ops++;
    194 
    195   if ( (NULL != flip_path_ul) &&
    196        (NULL != TALER_TWISTER_flip_upload
    197           (tth,
    198           flip_path_ul,
    199           &handle_acknowledgement,
    200           NULL)) )
    201     num_ops++;
    202 
    203   if ( (NULL != flip_path_dl) &&
    204        (NULL != TALER_TWISTER_flip_download
    205           (tth,
    206           flip_path_dl,
    207           &handle_acknowledgement,
    208           NULL)) )
    209     num_ops++;
    210 
    211   if ( (NULL != delete_path) &&
    212        (NULL != TALER_TWISTER_delete_path
    213           (tth,
    214           delete_path,
    215           &handle_acknowledgement,
    216           NULL)) )
    217     num_ops++;
    218 
    219   if (NULL != modify_path_ul)
    220   {
    221     if (NULL == modify_value)
    222     {
    223       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    224                   "New value not given, give -V|--value also\n");
    225       GNUNET_SCHEDULER_shutdown ();
    226       return;
    227     }
    228 
    229     if (NULL != TALER_TWISTER_modify_path_ul
    230           (tth,
    231           modify_path_ul,
    232           modify_value,
    233           &handle_acknowledgement,
    234           NULL))
    235       num_ops++;
    236   }
    237 
    238   if (NULL != modify_path_dl)
    239   {
    240     if (NULL == modify_value)
    241     {
    242       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    243                   "New value not given, give -V|--value also\n");
    244       GNUNET_SCHEDULER_shutdown ();
    245       return;
    246     }
    247 
    248     if (NULL != TALER_TWISTER_modify_path_dl
    249           (tth,
    250           modify_path_dl,
    251           modify_value,
    252           &handle_acknowledgement,
    253           NULL))
    254       num_ops++;
    255   }
    256 
    257   if (NULL != modify_header_dl)
    258   {
    259     if (NULL == modify_value)
    260     {
    261       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    262                   "New value not given, give -V|--value also\n");
    263       GNUNET_SCHEDULER_shutdown ();
    264       return;
    265     }
    266 
    267     if (NULL != TALER_TWISTER_modify_header_dl
    268           (tth,
    269           modify_header_dl,
    270           modify_value,
    271           &handle_acknowledgement,
    272           NULL))
    273       num_ops++;
    274   }
    275 
    276   if (0 == num_ops)
    277   {
    278     fprintf (stderr, "No valid hacks specified!\n");
    279     GNUNET_SCHEDULER_shutdown ();
    280     return;
    281   }
    282 }
    283 
    284 
    285 /**
    286  * Main function.
    287  *
    288  * @param argc number of CLI arguments given + 1.
    289  * @param argv array of CLI arguments given, + the binary name.
    290  * @return 0 on success
    291  */
    292 int
    293 main (int argc,
    294       char *const *argv)
    295 {
    296   struct GNUNET_GETOPT_CommandLineOption options[] = {
    297 
    298     GNUNET_GETOPT_option_string
    299       ('X',
    300       "modify-ul",
    301       "PATH",
    302       gettext_noop
    303         ("Modify upload object pointed by PATH,"
    304         " require --value.\n"),
    305       &modify_path_ul),
    306 
    307     GNUNET_GETOPT_option_string
    308       ('m',
    309       "modify-dl",
    310       "PATH",
    311       gettext_noop
    312         ("Modify download object pointed by PATH,"
    313         " require --value.\n"),
    314       &modify_path_dl),
    315 
    316     GNUNET_GETOPT_option_string
    317       ('H',
    318       "modify-header-dl",
    319       "HEADER",
    320       gettext_noop
    321         ("Modify download HTTP header HEADER,"
    322         " require --value.\n"),
    323       &modify_header_dl),
    324 
    325     GNUNET_GETOPT_option_string
    326       ('F',
    327       "flip-ul",
    328       "PATH",
    329       gettext_noop
    330         ("Flip a char in the *string* upload object"
    331         " pointed by PATH.\n"),
    332       &flip_path_ul),
    333 
    334     GNUNET_GETOPT_option_string
    335       ('f',
    336       "flip-dl",
    337       "PATH",
    338       gettext_noop
    339         ("Flip a char in the *string* download"
    340         " object pointed by PATH.\n"),
    341       &flip_path_dl),
    342 
    343     GNUNET_GETOPT_option_string
    344       ('V',
    345       "value",
    346       "VALUE",
    347       gettext_noop
    348         ("Make VALUE the new value of the field"
    349         " pointed by PATH.  Note: in this version,"
    350         " numbers will be always parsed and _set_"
    351         " as strings."),
    352       &modify_value),
    353 
    354     GNUNET_GETOPT_option_string
    355       ('d',
    356       "deleteobject",
    357       "PATH",
    358       gettext_noop
    359         ("Delete the object pointed by PATH.\n"),
    360       &delete_path),
    361 
    362     GNUNET_GETOPT_option_flag
    363       ('a',
    364       "checkalive",
    365       gettext_noop
    366         ("Check if twister accepts IPC connections\n"),
    367       &check_alive),
    368 
    369     GNUNET_GETOPT_option_flag
    370       ('U',
    371       "malformupload",
    372       gettext_noop
    373         ("Randomly truncate proxied request"),
    374       &malform_upload),
    375 
    376     GNUNET_GETOPT_option_flag
    377       ('M',
    378       "malform",
    379       gettext_noop
    380         ("Randomly truncate proxied response"),
    381       &malform_response),
    382 
    383     GNUNET_GETOPT_option_uint
    384       ('r',
    385       "responsecode",
    386       "STATUS",
    387       gettext_noop
    388         ("Set the next response code to STATUS"),
    389       &hack_response_code),
    390     GNUNET_GETOPT_OPTION_END
    391   };
    392   enum GNUNET_GenericReturnValue ret;
    393 
    394   status = 1;
    395   ret = GNUNET_PROGRAM_run (
    396     TWISTER_project_data (),
    397     argc,
    398     argv,
    399     "taler-twister",
    400     gettext_noop ("Control taler-twister service."),
    401     options,
    402     &run, NULL);
    403   if (GNUNET_SYSERR == ret)
    404     return 3;
    405   if (GNUNET_NO == ret)
    406     return 0;
    407   return status;
    408 }