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 }