Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2018 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it
6 : under the terms of the GNU General Public License as published
7 : by the Free Software Foundation; either version 3, or (at your
8 : option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with TALER; see the file COPYING. If not, see
17 : <http://www.gnu.org/licenses/>
18 : */
19 :
20 : /**
21 : * @file testing/testing_api_loop.c
22 : * @brief main interpreter loop for testcases
23 : * @author Christian Grothoff
24 : * @author Marcello Stanisci
25 : */
26 : #include "platform.h"
27 : #include "taler_json_lib.h"
28 : #include <gnunet/gnunet_curl_lib.h>
29 : #include "taler_signatures.h"
30 : #include "taler_testing_lib.h"
31 : #include "taler_fakebank_lib.h"
32 :
33 : /**
34 : * Pipe used to communicate child death via signal.
35 : * Must be global, as used in signal handler!
36 : */
37 : static struct GNUNET_DISK_PipeHandle *sigpipe;
38 :
39 :
40 : const struct TALER_TESTING_Command *
41 2 : TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
42 : const char *label)
43 : {
44 2 : if (NULL == label)
45 : {
46 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
47 : "Attempt to lookup command for empty label\n");
48 0 : return NULL;
49 : }
50 : /* Search backwards as we most likely reference recent commands */
51 4 : for (int i = is->ip; i >= 0; i--)
52 : {
53 4 : const struct TALER_TESTING_Command *cmd = &is->commands[i];
54 :
55 : /* Give precedence to top-level commands. */
56 4 : if ( (NULL != cmd->label) &&
57 4 : (0 == strcmp (cmd->label,
58 : label)) )
59 2 : return cmd;
60 :
61 2 : if (TALER_TESTING_cmd_is_batch (cmd))
62 : {
63 : struct TALER_TESTING_Command **batch;
64 : struct TALER_TESTING_Command *current;
65 : struct TALER_TESTING_Command *icmd;
66 : const struct TALER_TESTING_Command *match;
67 :
68 0 : current = TALER_TESTING_cmd_batch_get_current (cmd);
69 0 : GNUNET_assert (GNUNET_OK ==
70 : TALER_TESTING_get_trait_batch_cmds (cmd,
71 : &batch));
72 : /* We must do the loop forward, but we can find the last match */
73 0 : match = NULL;
74 0 : for (unsigned int j = 0;
75 0 : NULL != (icmd = &(*batch)[j])->label;
76 0 : j++)
77 : {
78 0 : if (current == icmd)
79 0 : break; /* do not go past current command */
80 0 : if ( (NULL != icmd->label) &&
81 0 : (0 == strcmp (icmd->label,
82 : label)) )
83 0 : match = icmd;
84 : }
85 0 : if (NULL != match)
86 0 : return match;
87 : }
88 : }
89 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
90 : "Command not found: %s\n",
91 : label);
92 0 : return NULL;
93 :
94 : }
95 :
96 :
97 : /**
98 : * Obtain main execution context for the main loop.
99 : */
100 : struct GNUNET_CURL_Context *
101 10 : TALER_TESTING_interpreter_get_context (struct TALER_TESTING_Interpreter *is)
102 : {
103 10 : return is->ctx;
104 : }
105 :
106 :
107 : struct TALER_FAKEBANK_Handle *
108 0 : TALER_TESTING_interpreter_get_fakebank (struct TALER_TESTING_Interpreter *is)
109 : {
110 0 : return is->fakebank;
111 : }
112 :
113 :
114 : void
115 2 : TALER_TESTING_run_with_fakebank (struct TALER_TESTING_Interpreter *is,
116 : struct TALER_TESTING_Command *commands,
117 : const char *bank_url)
118 : {
119 : char *currency;
120 :
121 2 : if (GNUNET_OK !=
122 2 : TALER_config_get_currency (is->cfg,
123 : ¤cy))
124 : {
125 0 : is->result = GNUNET_SYSERR;
126 0 : return;
127 : }
128 2 : is->fakebank = TALER_TESTING_run_fakebank (bank_url,
129 : currency);
130 2 : GNUNET_free (currency);
131 2 : if (NULL == is->fakebank)
132 : {
133 0 : GNUNET_break (0);
134 0 : is->result = GNUNET_SYSERR;
135 0 : return;
136 : }
137 2 : TALER_TESTING_run (is,
138 : commands);
139 : }
140 :
141 :
142 : /**
143 : * Run the main interpreter loop that performs exchange operations.
144 : *
145 : * @param cls contains the `struct InterpreterState`
146 : */
147 : static void
148 : interpreter_run (void *cls);
149 :
150 :
151 : void
152 22 : TALER_TESTING_interpreter_next (struct TALER_TESTING_Interpreter *is)
153 : {
154 : static unsigned long long ipc;
155 : static struct GNUNET_TIME_Absolute last_report;
156 22 : struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
157 :
158 22 : if (GNUNET_SYSERR == is->result)
159 0 : return; /* ignore, we already failed! */
160 22 : if (TALER_TESTING_cmd_is_batch (cmd))
161 : {
162 0 : TALER_TESTING_cmd_batch_next (is);
163 : }
164 : else
165 : {
166 22 : cmd->finish_time = GNUNET_TIME_absolute_get ();
167 22 : is->ip++;
168 : }
169 22 : if (0 == (ipc % 1000))
170 : {
171 3 : if (0 != ipc)
172 0 : GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
173 : "Interpreter executed 1000 instructions in %s\n",
174 : GNUNET_STRINGS_relative_time_to_string (
175 : GNUNET_TIME_absolute_get_duration (last_report),
176 : GNUNET_YES));
177 3 : last_report = GNUNET_TIME_absolute_get ();
178 : }
179 22 : ipc++;
180 22 : is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
181 : is);
182 : }
183 :
184 :
185 : void
186 0 : TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is)
187 : {
188 0 : struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
189 :
190 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
191 : "Failed at command `%s'\n",
192 : cmd->label);
193 0 : while (TALER_TESTING_cmd_is_batch (cmd))
194 : {
195 0 : cmd = TALER_TESTING_cmd_batch_get_current (cmd);
196 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
197 : "Batch is at command `%s'\n",
198 : cmd->label);
199 : }
200 0 : is->result = GNUNET_SYSERR;
201 0 : GNUNET_SCHEDULER_shutdown ();
202 0 : }
203 :
204 :
205 : struct TALER_TESTING_Command
206 3 : TALER_TESTING_cmd_end (void)
207 : {
208 : static struct TALER_TESTING_Command cmd;
209 3 : cmd.label = NULL;
210 :
211 3 : return cmd;
212 : }
213 :
214 :
215 : const char *
216 0 : TALER_TESTING_interpreter_get_current_label (struct
217 : TALER_TESTING_Interpreter *is)
218 : {
219 0 : struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
220 :
221 0 : return cmd->label;
222 : }
223 :
224 :
225 : static void
226 25 : interpreter_run (void *cls)
227 : {
228 25 : struct TALER_TESTING_Interpreter *is = cls;
229 25 : struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
230 :
231 25 : is->task = NULL;
232 25 : if (NULL == cmd->label)
233 : {
234 :
235 3 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
236 : "Running command END\n");
237 3 : is->result = GNUNET_OK;
238 3 : GNUNET_SCHEDULER_shutdown ();
239 3 : return;
240 : }
241 :
242 22 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
243 : "Running command `%s'\n",
244 : cmd->label);
245 : cmd->start_time
246 22 : = cmd->last_req_time
247 22 : = GNUNET_TIME_absolute_get ();
248 22 : cmd->num_tries = 1;
249 22 : cmd->run (cmd->cls,
250 : cmd,
251 : is);
252 : }
253 :
254 :
255 : /**
256 : * Function run when the test terminates (good or bad).
257 : * Cleans up our state.
258 : *
259 : * @param cls the interpreter state.
260 : */
261 : static void
262 3 : do_shutdown (void *cls)
263 : {
264 3 : struct TALER_TESTING_Interpreter *is = cls;
265 : struct TALER_TESTING_Command *cmd;
266 : const char *label;
267 :
268 3 : label = is->commands[is->ip].label;
269 3 : if (NULL == label)
270 3 : label = "END";
271 3 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
272 : "Executing shutdown at `%s'\n",
273 : label);
274 3 : for (unsigned int j = 0;
275 25 : NULL != (cmd = &is->commands[j])->label;
276 22 : j++)
277 22 : if (NULL != cmd->cleanup)
278 22 : cmd->cleanup (cmd->cls,
279 : cmd);
280 3 : if (NULL != is->exchange)
281 : {
282 0 : TALER_LOG_DEBUG ("Disconnecting the exchange\n");
283 0 : TALER_EXCHANGE_disconnect (is->exchange);
284 0 : is->exchange = NULL;
285 : }
286 3 : if (NULL != is->task)
287 : {
288 0 : GNUNET_SCHEDULER_cancel (is->task);
289 0 : is->task = NULL;
290 : }
291 3 : if (NULL != is->fakebank)
292 : {
293 2 : TALER_FAKEBANK_stop (is->fakebank);
294 2 : is->fakebank = NULL;
295 : }
296 3 : if (NULL != is->ctx)
297 : {
298 3 : GNUNET_CURL_fini (is->ctx);
299 3 : is->ctx = NULL;
300 : }
301 3 : if (NULL != is->rc)
302 : {
303 3 : GNUNET_CURL_gnunet_rc_destroy (is->rc);
304 3 : is->rc = NULL;
305 : }
306 3 : if (NULL != is->timeout_task)
307 : {
308 3 : GNUNET_SCHEDULER_cancel (is->timeout_task);
309 3 : is->timeout_task = NULL;
310 : }
311 3 : if (NULL != is->child_death_task)
312 : {
313 0 : GNUNET_SCHEDULER_cancel (is->child_death_task);
314 0 : is->child_death_task = NULL;
315 : }
316 3 : GNUNET_free (is->commands);
317 3 : }
318 :
319 :
320 : /**
321 : * Function run when the test terminates (good or bad) with timeout.
322 : *
323 : * @param cls the `struct TALER_TESTING_Interpreter *`
324 : */
325 : static void
326 0 : do_timeout (void *cls)
327 : {
328 0 : struct TALER_TESTING_Interpreter *is = cls;
329 :
330 0 : is->timeout_task = NULL;
331 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
332 : "Terminating test due to timeout\n");
333 0 : GNUNET_SCHEDULER_shutdown ();
334 0 : }
335 :
336 :
337 : /**
338 : * Task triggered whenever we receive a SIGCHLD (child
339 : * process died).
340 : *
341 : * @param cls the `struct TALER_TESTING_Interpreter *`
342 : */
343 : static void
344 1 : maint_child_death (void *cls)
345 : {
346 1 : struct TALER_TESTING_Interpreter *is = cls;
347 1 : struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
348 : const struct GNUNET_DISK_FileHandle *pr;
349 : struct GNUNET_OS_Process **processp;
350 : char c[16];
351 : enum GNUNET_OS_ProcessStatusType type;
352 : unsigned long code;
353 :
354 1 : while (TALER_TESTING_cmd_is_batch (cmd))
355 0 : cmd = TALER_TESTING_cmd_batch_get_current (cmd);
356 1 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
357 : "Got SIGCHLD for `%s'.\n",
358 : cmd->label);
359 1 : is->child_death_task = NULL;
360 1 : pr = GNUNET_DISK_pipe_handle (sigpipe,
361 : GNUNET_DISK_PIPE_END_READ);
362 1 : GNUNET_break (0 <
363 : GNUNET_DISK_file_read (pr,
364 : &c,
365 : sizeof (c)));
366 1 : if (GNUNET_OK !=
367 1 : TALER_TESTING_get_trait_process (cmd,
368 : &processp))
369 : {
370 0 : GNUNET_break (0);
371 0 : TALER_TESTING_interpreter_fail (is);
372 0 : return;
373 : }
374 :
375 1 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
376 : "Got the dead child process handle, waiting for termination ...\n");
377 1 : GNUNET_assert (GNUNET_OK ==
378 : GNUNET_OS_process_wait_status (*processp,
379 : &type,
380 : &code));
381 1 : GNUNET_OS_process_destroy (*processp);
382 1 : *processp = NULL;
383 1 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
384 : "... definitively terminated\n");
385 1 : switch (type)
386 : {
387 0 : case GNUNET_OS_PROCESS_UNKNOWN:
388 0 : GNUNET_break (0);
389 0 : TALER_TESTING_interpreter_fail (is);
390 0 : return;
391 0 : case GNUNET_OS_PROCESS_RUNNING:
392 0 : GNUNET_break (0);
393 0 : TALER_TESTING_interpreter_fail (is);
394 0 : return;
395 0 : case GNUNET_OS_PROCESS_STOPPED:
396 0 : GNUNET_break (0);
397 0 : TALER_TESTING_interpreter_fail (is);
398 0 : return;
399 1 : case GNUNET_OS_PROCESS_EXITED:
400 1 : if (0 != code)
401 : {
402 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
403 : "Process exited with unexpected status %u\n",
404 : (unsigned int) code);
405 0 : TALER_TESTING_interpreter_fail (is);
406 0 : return;
407 : }
408 1 : break;
409 0 : case GNUNET_OS_PROCESS_SIGNALED:
410 0 : GNUNET_break (0);
411 0 : TALER_TESTING_interpreter_fail (is);
412 0 : return;
413 : }
414 :
415 1 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
416 : "Dead child, go on with next command.\n");
417 1 : TALER_TESTING_interpreter_next (is);
418 : }
419 :
420 :
421 : void
422 1 : TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is)
423 : {
424 : const struct GNUNET_DISK_FileHandle *pr;
425 :
426 1 : GNUNET_assert (NULL == is->child_death_task);
427 1 : pr = GNUNET_DISK_pipe_handle (sigpipe,
428 : GNUNET_DISK_PIPE_END_READ);
429 : is->child_death_task
430 1 : = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
431 : pr,
432 : &maint_child_death,
433 : is);
434 1 : }
435 :
436 :
437 : void
438 3 : TALER_TESTING_run2 (struct TALER_TESTING_Interpreter *is,
439 : struct TALER_TESTING_Command *commands,
440 : struct GNUNET_TIME_Relative timeout)
441 : {
442 : unsigned int i;
443 :
444 3 : if (NULL != is->timeout_task)
445 : {
446 0 : GNUNET_SCHEDULER_cancel (is->timeout_task);
447 0 : is->timeout_task = NULL;
448 : }
449 : /* get the number of commands */
450 25 : for (i = 0; NULL != commands[i].label; i++)
451 : ;
452 3 : is->commands = GNUNET_malloc_large ( (i + 1)
453 : * sizeof (struct TALER_TESTING_Command));
454 3 : GNUNET_assert (NULL != is->commands);
455 3 : memcpy (is->commands,
456 : commands,
457 : sizeof (struct TALER_TESTING_Command) * i);
458 3 : is->timeout_task = GNUNET_SCHEDULER_add_delayed (
459 : timeout,
460 : &do_timeout,
461 : is);
462 3 : GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
463 : is);
464 3 : is->task = GNUNET_SCHEDULER_add_now (&interpreter_run,
465 : is);
466 3 : }
467 :
468 :
469 : void
470 3 : TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
471 : struct TALER_TESTING_Command *commands)
472 : {
473 3 : TALER_TESTING_run2 (is,
474 : commands,
475 : GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES,
476 : 5));
477 3 : }
478 :
479 :
480 : /**
481 : * Information used by the wrapper around the main
482 : * "run" method.
483 : */
484 : struct MainContext
485 : {
486 : /**
487 : * Main "run" method.
488 : */
489 : TALER_TESTING_Main main_cb;
490 :
491 : /**
492 : * Closure for @e main_cb.
493 : */
494 : void *main_cb_cls;
495 :
496 : /**
497 : * Interpreter state.
498 : */
499 : struct TALER_TESTING_Interpreter *is;
500 :
501 : /**
502 : * URL of the exchange.
503 : */
504 : char *exchange_url;
505 :
506 : };
507 :
508 :
509 : /**
510 : * Signal handler called for SIGCHLD. Triggers the
511 : * respective handler by writing to the trigger pipe.
512 : */
513 : static void
514 1 : sighandler_child_death (void)
515 : {
516 : static char c;
517 1 : int old_errno = errno; /* back-up errno */
518 :
519 1 : GNUNET_break (1 == GNUNET_DISK_file_write
520 : (GNUNET_DISK_pipe_handle (sigpipe,
521 : GNUNET_DISK_PIPE_END_WRITE),
522 : &c, sizeof (c)));
523 1 : errno = old_errno; /* restore errno */
524 1 : }
525 :
526 :
527 : void
528 0 : TALER_TESTING_cert_cb (void *cls,
529 : const struct TALER_EXCHANGE_HttpResponse *hr,
530 : const struct TALER_EXCHANGE_Keys *keys,
531 : enum TALER_EXCHANGE_VersionCompatibility compat)
532 : {
533 0 : struct MainContext *main_ctx = cls;
534 0 : struct TALER_TESTING_Interpreter *is = main_ctx->is;
535 :
536 : (void) compat;
537 0 : if (NULL == keys)
538 : {
539 0 : if (GNUNET_NO == is->working)
540 : {
541 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
542 : "Got NULL response for /keys during startup (%u/%d), retrying!\n",
543 : hr->http_status,
544 : (int) hr->ec);
545 0 : TALER_EXCHANGE_disconnect (is->exchange);
546 0 : GNUNET_assert (
547 : NULL != (is->exchange
548 : = TALER_EXCHANGE_connect (is->ctx,
549 : main_ctx->exchange_url,
550 : &TALER_TESTING_cert_cb,
551 : main_ctx,
552 : TALER_EXCHANGE_OPTION_END)));
553 0 : return;
554 : }
555 : else
556 : {
557 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
558 : "Got NULL response for /keys during execution (%u/%d)!\n",
559 : hr->http_status,
560 : (int) hr->ec);
561 : }
562 : }
563 : else
564 : {
565 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
566 : "Got %d DK from /keys in generation %u\n",
567 : keys->num_denom_keys,
568 : is->key_generation + 1);
569 : }
570 0 : is->key_generation++;
571 0 : is->keys = keys;
572 :
573 : /* /keys has been called for some reason and
574 : * the interpreter is already running. */
575 0 : if (GNUNET_YES == is->working)
576 0 : return;
577 0 : is->working = GNUNET_YES;
578 : /* Trigger the next command. */
579 0 : TALER_LOG_DEBUG ("Cert_cb, scheduling CMD (ip: %d)\n",
580 : is->ip);
581 0 : GNUNET_SCHEDULER_add_now (&interpreter_run,
582 : is);
583 : }
584 :
585 :
586 : /**
587 : * Initialize scheduler loop and curl context for the testcase,
588 : * and responsible to run the "run" method.
589 : *
590 : * @param cls closure, typically the "run" method, the
591 : * interpreter state and a closure for "run".
592 : */
593 : static void
594 3 : main_wrapper_exchange_agnostic (void *cls)
595 : {
596 3 : struct MainContext *main_ctx = cls;
597 :
598 3 : main_ctx->main_cb (main_ctx->main_cb_cls,
599 : main_ctx->is);
600 3 : }
601 :
602 :
603 : /**
604 : * Function run when the test is aborted before we launch the actual
605 : * interpreter. Cleans up our state.
606 : *
607 : * @param cls the main context
608 : */
609 : static void
610 0 : do_abort (void *cls)
611 : {
612 0 : struct MainContext *main_ctx = cls;
613 0 : struct TALER_TESTING_Interpreter *is = main_ctx->is;
614 :
615 0 : is->timeout_task = NULL;
616 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
617 : "Executing abort prior to interpreter launch\n");
618 0 : if (NULL != is->exchange)
619 : {
620 0 : TALER_EXCHANGE_disconnect (is->exchange);
621 0 : is->exchange = NULL;
622 : }
623 0 : if (NULL != is->fakebank)
624 : {
625 0 : TALER_FAKEBANK_stop (is->fakebank);
626 0 : is->fakebank = NULL;
627 : }
628 0 : if (NULL != is->ctx)
629 : {
630 0 : GNUNET_CURL_fini (is->ctx);
631 0 : is->ctx = NULL;
632 : }
633 0 : if (NULL != is->rc)
634 : {
635 0 : GNUNET_CURL_gnunet_rc_destroy (is->rc);
636 0 : is->rc = NULL;
637 : }
638 0 : }
639 :
640 :
641 : /**
642 : * Initialize scheduler loop and curl context for the testcase,
643 : * and responsible to run the "run" method.
644 : *
645 : * @param cls a `struct MainContext *`
646 : */
647 : static void
648 0 : main_wrapper_exchange_connect (void *cls)
649 : {
650 0 : struct MainContext *main_ctx = cls;
651 0 : struct TALER_TESTING_Interpreter *is = main_ctx->is;
652 : char *exchange_url;
653 :
654 0 : if (GNUNET_OK !=
655 0 : GNUNET_CONFIGURATION_get_value_string (is->cfg,
656 : "exchange",
657 : "BASE_URL",
658 : &exchange_url))
659 : {
660 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
661 : "exchange",
662 : "BASE_URL");
663 0 : return;
664 : }
665 0 : main_ctx->exchange_url = exchange_url;
666 0 : is->timeout_task = GNUNET_SCHEDULER_add_shutdown (&do_abort,
667 : main_ctx);
668 0 : is->working = GNUNET_YES;
669 0 : GNUNET_assert (NULL == is->exchange);
670 0 : GNUNET_break (
671 : NULL != (is->exchange =
672 : TALER_EXCHANGE_connect (is->ctx,
673 : exchange_url,
674 : &TALER_TESTING_cert_cb,
675 : main_ctx,
676 : TALER_EXCHANGE_OPTION_END)));
677 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
678 : "Starting main test loop\n");
679 0 : main_ctx->main_cb (main_ctx->main_cb_cls,
680 : is);
681 : }
682 :
683 :
684 : /**
685 : * Load the exchange and auditor key material into @a is.
686 : *
687 : * @param[in,out] is state to initialize
688 : */
689 : static enum GNUNET_GenericReturnValue
690 3 : load_keys (struct TALER_TESTING_Interpreter *is)
691 : {
692 : char *fn;
693 :
694 3 : if (GNUNET_OK !=
695 3 : GNUNET_CONFIGURATION_get_value_filename (is->cfg,
696 : "exchange-offline",
697 : "MASTER_PRIV_FILE",
698 : &fn))
699 : {
700 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
701 : "exchange-offline",
702 : "MASTER_PRIV_FILE");
703 0 : return GNUNET_SYSERR;
704 : }
705 3 : if (GNUNET_SYSERR ==
706 3 : GNUNET_DISK_directory_create_for_file (fn))
707 : {
708 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
709 : "Could not setup directory for master private key file `%s'\n",
710 : fn);
711 0 : GNUNET_free (fn);
712 0 : return GNUNET_SYSERR;
713 : }
714 3 : if (GNUNET_SYSERR ==
715 3 : GNUNET_CRYPTO_eddsa_key_from_file (fn,
716 : GNUNET_YES,
717 : &is->master_priv.eddsa_priv))
718 : {
719 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
720 : "Could not load master private key from `%s'\n",
721 : fn);
722 0 : GNUNET_free (fn);
723 0 : return GNUNET_SYSERR;
724 : }
725 3 : GNUNET_free (fn);
726 3 : GNUNET_CRYPTO_eddsa_key_get_public (&is->master_priv.eddsa_priv,
727 : &is->master_pub.eddsa_pub);
728 :
729 3 : if (GNUNET_OK !=
730 3 : GNUNET_CONFIGURATION_get_value_filename (is->cfg,
731 : "auditor",
732 : "AUDITOR_PRIV_FILE",
733 : &fn))
734 : {
735 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
736 : "auditor",
737 : "AUDITOR_PRIV_FILE");
738 0 : return GNUNET_SYSERR;
739 : }
740 3 : if (GNUNET_SYSERR ==
741 3 : GNUNET_DISK_directory_create_for_file (fn))
742 : {
743 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
744 : "Could not setup directory for auditor private key file `%s'\n",
745 : fn);
746 0 : GNUNET_free (fn);
747 0 : return GNUNET_SYSERR;
748 : }
749 3 : if (GNUNET_SYSERR ==
750 3 : GNUNET_CRYPTO_eddsa_key_from_file (fn,
751 : GNUNET_YES,
752 : &is->auditor_priv.eddsa_priv))
753 : {
754 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
755 : "Could not load auditor private key from `%s'\n",
756 : fn);
757 0 : GNUNET_free (fn);
758 0 : return GNUNET_SYSERR;
759 : }
760 3 : GNUNET_free (fn);
761 3 : GNUNET_CRYPTO_eddsa_key_get_public (&is->auditor_priv.eddsa_priv,
762 : &is->auditor_pub.eddsa_pub);
763 3 : return GNUNET_OK;
764 : }
765 :
766 :
767 : /**
768 : * Load the exchange and auditor URLs from the configuration into @a is.
769 : *
770 : * @param[in,out] is state to initialize
771 : */
772 : static enum GNUNET_GenericReturnValue
773 3 : load_urls (struct TALER_TESTING_Interpreter *is)
774 : {
775 3 : if (GNUNET_OK !=
776 3 : GNUNET_CONFIGURATION_get_value_string (is->cfg,
777 : "auditor",
778 : "BASE_URL",
779 : &is->auditor_url))
780 : {
781 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
782 : "auditor",
783 : "BASE_URL");
784 0 : return GNUNET_SYSERR;
785 : }
786 3 : if (GNUNET_OK !=
787 3 : GNUNET_CONFIGURATION_get_value_string (is->cfg,
788 : "exchange",
789 : "BASE_URL",
790 : &is->exchange_url))
791 : {
792 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
793 : "exchange",
794 : "BASE_URL");
795 0 : GNUNET_free (is->auditor_url);
796 0 : return GNUNET_SYSERR;
797 : }
798 3 : return GNUNET_OK;
799 : }
800 :
801 :
802 : enum GNUNET_GenericReturnValue
803 3 : TALER_TESTING_setup (TALER_TESTING_Main main_cb,
804 : void *main_cb_cls,
805 : const struct GNUNET_CONFIGURATION_Handle *cfg,
806 : struct GNUNET_OS_Process *exchanged,
807 : int exchange_connect)
808 : {
809 3 : struct TALER_TESTING_Interpreter is = {
810 : .cfg = cfg,
811 : .exchanged = exchanged
812 : };
813 3 : struct MainContext main_ctx = {
814 : .main_cb = main_cb,
815 : .main_cb_cls = main_cb_cls,
816 : /* needed to init the curl ctx */
817 : .is = &is,
818 : };
819 : struct GNUNET_SIGNAL_Context *shc_chld;
820 :
821 3 : if (GNUNET_OK !=
822 3 : load_keys (&is))
823 0 : return GNUNET_SYSERR;
824 3 : if (GNUNET_OK !=
825 3 : load_urls (&is))
826 0 : return GNUNET_SYSERR;
827 3 : sigpipe = GNUNET_DISK_pipe (GNUNET_DISK_PF_NONE);
828 3 : GNUNET_assert (NULL != sigpipe);
829 3 : shc_chld = GNUNET_SIGNAL_handler_install (
830 : GNUNET_SIGCHLD,
831 : &sighandler_child_death);
832 3 : is.ctx = GNUNET_CURL_init (
833 : &GNUNET_CURL_gnunet_scheduler_reschedule,
834 : &is.rc);
835 3 : GNUNET_CURL_enable_async_scope_header (is.ctx,
836 : "Taler-Correlation-Id");
837 3 : GNUNET_assert (NULL != is.ctx);
838 3 : is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx);
839 :
840 : /* Blocking */
841 3 : if (GNUNET_YES == exchange_connect)
842 0 : GNUNET_SCHEDULER_run (&main_wrapper_exchange_connect,
843 : &main_ctx);
844 : else
845 3 : GNUNET_SCHEDULER_run (&main_wrapper_exchange_agnostic,
846 : &main_ctx);
847 3 : if (NULL != is.final_cleanup_cb)
848 0 : is.final_cleanup_cb (is.final_cleanup_cb_cls);
849 3 : GNUNET_free (main_ctx.exchange_url);
850 3 : GNUNET_SIGNAL_handler_uninstall (shc_chld);
851 3 : GNUNET_DISK_pipe_close (sigpipe);
852 3 : sigpipe = NULL;
853 3 : GNUNET_free (is.auditor_url);
854 3 : GNUNET_free (is.exchange_url);
855 3 : return is.result;
856 : }
857 :
858 :
859 : /* end of testing_api_loop.c */
|