error handling
[oweals/gnunet.git] / src / ats-tests / ats-testing-experiment.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2010-2013 GNUnet e.V.
4
5    GNUnet is free software: you can redistribute it and/or modify it
6    under the terms of the GNU Affero General Public License as published
7    by the Free Software Foundation, either version 3 of the License,
8    or (at your option) any later version.
9
10    GNUnet 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 GNU
13    Affero General Public License for more details.
14
15    You should have received a copy of the GNU Affero General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 /**
21  * @file ats-tests/ats-testing-experiment.c
22  * @brief ats benchmark: controlled experiment execution
23  * @author Christian Grothoff
24  * @author Matthias Wachs
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "ats-testing.h"
29
30 const char *
31 print_op (enum OperationType op)
32 {
33   switch (op)
34   {
35   case START_SEND:
36     return "START_SEND";
37
38   case STOP_SEND:
39     return "STOP_SEND";
40
41   case START_PREFERENCE:
42     return "START_PREFERENCE";
43
44   case STOP_PREFERENCE:
45     return "STOP_PREFERENCE";
46
47   default:
48     break;
49   }
50   return "";
51 }
52
53
54 static struct Experiment *
55 create_experiment ()
56 {
57   struct Experiment *e;
58
59   e = GNUNET_new (struct Experiment);
60   e->name = NULL;
61   e->num_masters = 0;
62   e->num_slaves = 0;
63   e->start = NULL;
64   e->total_duration = GNUNET_TIME_UNIT_ZERO;
65   return e;
66 }
67
68
69 static void
70 free_experiment (struct Experiment *e)
71 {
72   struct Episode *cur;
73   struct Episode *next;
74   struct GNUNET_ATS_TEST_Operation *cur_o;
75   struct GNUNET_ATS_TEST_Operation *next_o;
76
77   next = e->start;
78   for (cur = next; NULL != cur; cur = next)
79   {
80     next = cur->next;
81
82     next_o = cur->head;
83     for (cur_o = next_o; NULL != cur_o; cur_o = next_o)
84     {
85       next_o = cur_o->next;
86       GNUNET_free (cur_o);
87     }
88     GNUNET_free (cur);
89   }
90
91   GNUNET_free_non_null (e->name);
92   GNUNET_free_non_null (e->cfg_file);
93   GNUNET_free (e);
94 }
95
96
97 static int
98 load_episode (struct Experiment *e,
99               struct Episode *cur,
100               struct GNUNET_CONFIGURATION_Handle *cfg)
101 {
102   struct GNUNET_ATS_TEST_Operation *o;
103   char *sec_name;
104   char *op_name;
105   char *op;
106   char *type;
107   char *pref;
108   int op_counter = 0;
109
110   fprintf (stderr, "Parsing episode %u\n", cur->id);
111   GNUNET_asprintf (&sec_name, "episode-%u", cur->id);
112
113   while (1)
114   {
115     /* Load operation */
116     GNUNET_asprintf (&op_name, "op-%u-operation", op_counter);
117     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
118                                                                 sec_name,
119                                                                 op_name, &op))
120     {
121       GNUNET_free (op_name);
122       break;
123     }
124     o = GNUNET_new (struct GNUNET_ATS_TEST_Operation);
125     /* operations = set_rate, start_send, stop_send, set_preference */
126     if (0 == strcmp (op, "start_send"))
127     {
128       o->type = START_SEND;
129     }
130     else if (0 == strcmp (op, "stop_send"))
131     {
132       o->type = STOP_SEND;
133     }
134     else if (0 == strcmp (op, "start_preference"))
135     {
136       o->type = START_PREFERENCE;
137     }
138     else if (0 == strcmp (op, "stop_preference"))
139     {
140       o->type = STOP_PREFERENCE;
141     }
142     else
143     {
144       fprintf (stderr, "Invalid operation %u `%s' in episode %u\n",
145                op_counter, op, cur->id);
146       GNUNET_free (op);
147       GNUNET_free (op_name);
148       GNUNET_free (o);
149       GNUNET_free (sec_name);
150       return GNUNET_SYSERR;
151     }
152     GNUNET_free (op_name);
153
154     /* Get source */
155     GNUNET_asprintf (&op_name, "op-%u-src", op_counter);
156     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
157                                                                 sec_name,
158                                                                 op_name,
159                                                                 &o->src_id))
160     {
161       fprintf (stderr, "Missing src in operation %u `%s' in episode %u\n",
162                op_counter, op, cur->id);
163       GNUNET_free (op);
164       GNUNET_free (op_name);
165       GNUNET_free (o);
166       GNUNET_free (sec_name);
167       return GNUNET_SYSERR;
168     }
169     if (o->src_id > (e->num_masters - 1))
170     {
171       fprintf (stderr, "Invalid src %llu in operation %u `%s' in episode %u\n",
172                o->src_id, op_counter, op, cur->id);
173       GNUNET_free (op);
174       GNUNET_free (op_name);
175       GNUNET_free (o);
176       GNUNET_free (sec_name);
177       return GNUNET_SYSERR;
178     }
179     GNUNET_free (op_name);
180
181     /* Get destination */
182     GNUNET_asprintf (&op_name, "op-%u-dest", op_counter);
183     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
184                                                                 sec_name,
185                                                                 op_name,
186                                                                 &o->dest_id))
187     {
188       fprintf (stderr, "Missing src in operation %u `%s' in episode %u\n",
189                op_counter, op, cur->id);
190       GNUNET_free (op);
191       GNUNET_free (op_name);
192       GNUNET_free (o);
193       GNUNET_free (sec_name);
194       return GNUNET_SYSERR;
195     }
196     if (o->dest_id > (e->num_slaves - 1))
197     {
198       fprintf (stderr,
199                "Invalid destination %llu in operation %u `%s' in episode %u\n",
200                o->dest_id, op_counter, op, cur->id);
201       GNUNET_free (op);
202       GNUNET_free (op_name);
203       GNUNET_free (o);
204       GNUNET_free (sec_name);
205       return GNUNET_SYSERR;
206     }
207     GNUNET_free (op_name);
208
209     GNUNET_asprintf (&op_name, "op-%u-type", op_counter);
210     if ((GNUNET_SYSERR != GNUNET_CONFIGURATION_get_value_string (cfg,
211                                                                  sec_name,
212                                                                  op_name,
213                                                                  &type)) &&
214         (STOP_SEND != o->type) &&
215         (STOP_PREFERENCE != o->type))
216     {
217       /* Load arguments for set_rate, start_send, set_preference */
218       if (0 == strcmp (type, "constant"))
219       {
220         o->gen_type = GNUNET_ATS_TEST_TG_CONSTANT;
221       }
222       else if (0 == strcmp (type, "linear"))
223       {
224         o->gen_type = GNUNET_ATS_TEST_TG_LINEAR;
225       }
226       else if (0 == strcmp (type, "sinus"))
227       {
228         o->gen_type = GNUNET_ATS_TEST_TG_SINUS;
229       }
230       else if (0 == strcmp (type, "random"))
231       {
232         o->gen_type = GNUNET_ATS_TEST_TG_RANDOM;
233       }
234       else
235       {
236         fprintf (stderr, "Invalid type %u `%s' in episode %u\n",
237                  op_counter, op, cur->id);
238         GNUNET_free (type);
239         GNUNET_free (op);
240         GNUNET_free (op_name);
241         GNUNET_free (sec_name);
242         GNUNET_free (o);
243         return GNUNET_SYSERR;
244       }
245       GNUNET_free (op_name);
246
247       /* Get base rate */
248       GNUNET_asprintf (&op_name, "op-%u-base-rate", op_counter);
249       if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
250                                                                   sec_name,
251                                                                   op_name,
252                                                                   &o->base_rate))
253       {
254         fprintf (stderr,
255                  "Missing base rate in operation %u `%s' in episode %u\n",
256                  op_counter, op, cur->id);
257         GNUNET_free (type);
258         GNUNET_free (op);
259         GNUNET_free (op_name);
260         GNUNET_free (sec_name);
261         GNUNET_free (o);
262         return GNUNET_SYSERR;
263       }
264       GNUNET_free (op_name);
265
266       /* Get max rate */
267       GNUNET_asprintf (&op_name, "op-%u-max-rate", op_counter);
268       if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
269                                                                   sec_name,
270                                                                   op_name,
271                                                                   &o->max_rate))
272       {
273         if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
274             (GNUNET_ATS_TEST_TG_RANDOM == o->gen_type) ||
275             (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
276         {
277           fprintf (stderr,
278                    "Missing max rate in operation %u `%s' in episode %u\n",
279                    op_counter, op, cur->id);
280           GNUNET_free (type);
281           GNUNET_free (op_name);
282           GNUNET_free (op);
283           GNUNET_free (o);
284           GNUNET_free (sec_name);
285           return GNUNET_SYSERR;
286         }
287       }
288       GNUNET_free (op_name);
289
290       /* Get period */
291       GNUNET_asprintf (&op_name, "op-%u-period", op_counter);
292       if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
293                                                                 sec_name,
294                                                                 op_name,
295                                                                 &o->period))
296       {
297         o->period = cur->duration;
298       }
299       GNUNET_free (op_name);
300
301       if (START_PREFERENCE == o->type)
302       {
303         /* Get frequency */
304         GNUNET_asprintf (&op_name, "op-%u-frequency", op_counter);
305         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
306                                                                   sec_name,
307                                                                   op_name,
308                                                                   &o->frequency))
309         {
310           fprintf (stderr,
311                    "Missing frequency in operation %u `%s' in episode %u\n",
312                    op_counter, op, cur->id);
313           GNUNET_free (type);
314           GNUNET_free (op_name);
315           GNUNET_free (op);
316           GNUNET_free (o);
317           GNUNET_free (sec_name);
318           return GNUNET_SYSERR;
319         }
320         GNUNET_free (op_name);
321
322         /* Get preference */
323         GNUNET_asprintf (&op_name, "op-%u-pref", op_counter);
324         if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
325                                                                     sec_name,
326                                                                     op_name,
327                                                                     &pref))
328         {
329           fprintf (stderr,
330                    "Missing preference in operation %u `%s' in episode %u\n",
331                    op_counter, op, cur->id);
332           GNUNET_free (type);
333           GNUNET_free (op_name);
334           GNUNET_free (op);
335           GNUNET_free_non_null (pref);
336           GNUNET_free (o);
337           GNUNET_free (sec_name);
338           return GNUNET_SYSERR;
339         }
340
341         if (0 == strcmp (pref, "bandwidth"))
342           o->pref_type = GNUNET_ATS_PREFERENCE_BANDWIDTH;
343         else if (0 == strcmp (pref, "latency"))
344           o->pref_type = GNUNET_ATS_PREFERENCE_LATENCY;
345         else
346         {
347           fprintf (stderr,
348                    "Invalid preference in operation %u `%s' in episode %u\n",
349                    op_counter, op, cur->id);
350           GNUNET_free (type);
351           GNUNET_free (op_name);
352           GNUNET_free (op);
353           GNUNET_free_non_null (pref);
354           GNUNET_free (o);
355           GNUNET_free (sec_name);
356           return GNUNET_SYSERR;
357         }
358         GNUNET_free (pref);
359         GNUNET_free (op_name);
360       }
361     }
362
363     /* Safety checks */
364     if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
365         (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
366     {
367       if ((o->max_rate - o->base_rate) > o->base_rate)
368       {
369         /* This will cause an underflow */
370         GNUNET_break (0);
371       }
372       fprintf (stderr,
373                "Selected max rate and base rate cannot be used for desired traffic form!\n");
374     }
375
376     if ((START_SEND == o->type) || (START_PREFERENCE == o->type))
377       fprintf (stderr,
378                "Found operation %u in episode %u: %s [%llu]->[%llu] == %s, %llu -> %llu in %s\n",
379                op_counter, cur->id, print_op (o->type), o->src_id,
380                o->dest_id, (NULL != type) ? type : "",
381                o->base_rate, o->max_rate,
382                GNUNET_STRINGS_relative_time_to_string (o->period, GNUNET_YES));
383     else
384       fprintf (stderr, "Found operation %u in episode %u: %s [%llu]->[%llu]\n",
385                op_counter, cur->id, print_op (o->type), o->src_id, o->dest_id);
386
387     GNUNET_free_non_null (type);
388     GNUNET_free (op);
389
390     GNUNET_CONTAINER_DLL_insert (cur->head, cur->tail, o);
391     op_counter++;
392   }
393   GNUNET_free (sec_name);
394
395   return GNUNET_OK;
396 }
397
398
399 static int
400 load_episodes (struct Experiment *e, struct GNUNET_CONFIGURATION_Handle *cfg)
401 {
402   int e_counter = 0;
403   char *sec_name;
404   struct GNUNET_TIME_Relative e_duration;
405   struct Episode *cur;
406   struct Episode *last;
407
408   e_counter = 0;
409   last = NULL;
410   while (1)
411   {
412     GNUNET_asprintf (&sec_name, "episode-%u", e_counter);
413     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
414                                                               sec_name,
415                                                               "duration",
416                                                               &e_duration))
417     {
418       GNUNET_free (sec_name);
419       break;
420     }
421
422     cur = GNUNET_new (struct Episode);
423     cur->duration = e_duration;
424     cur->id = e_counter;
425
426     if (GNUNET_OK != load_episode (e, cur, cfg))
427     {
428       GNUNET_free (sec_name);
429       GNUNET_free (cur);
430       return GNUNET_SYSERR;
431     }
432
433     fprintf (stderr, "Found episode %u with duration %s \n",
434              e_counter,
435              GNUNET_STRINGS_relative_time_to_string (cur->duration,
436                                                      GNUNET_YES));
437
438     /* Update experiment */
439     e->num_episodes++;
440     e->total_duration = GNUNET_TIME_relative_add (e->total_duration,
441                                                   cur->duration);
442     /* Put in linked list */
443     if (NULL == last)
444       e->start = cur;
445     else
446       last->next = cur;
447
448     GNUNET_free (sec_name);
449     e_counter++;
450     last = cur;
451   }
452   return e_counter;
453 }
454
455
456 static void
457 timeout_experiment (void *cls)
458 {
459   struct Experiment *e = cls;
460
461   e->experiment_timeout_task = NULL;
462   fprintf (stderr, "Experiment timeout!\n");
463
464   if (NULL != e->episode_timeout_task)
465   {
466     GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
467     e->episode_timeout_task = NULL;
468   }
469
470   e->e_done_cb (e, GNUNET_TIME_absolute_get_duration (e->start_time),
471                 GNUNET_SYSERR);
472 }
473
474
475 static void
476 enforce_start_send (struct GNUNET_ATS_TEST_Operation *op)
477 {
478   struct BenchmarkPeer *peer;
479   struct BenchmarkPartner *partner;
480
481   peer = GNUNET_ATS_TEST_get_peer (op->src_id);
482   if (NULL == peer)
483   {
484     GNUNET_break (0);
485     return;
486   }
487
488   partner = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
489   if (NULL == partner)
490   {
491     GNUNET_break (0);
492     return;
493   }
494
495   fprintf (stderr, "Found master %llu slave %llu\n", op->src_id, op->dest_id);
496
497   if (NULL != partner->tg)
498   {
499     fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",
500              op->src_id, op->dest_id);
501     GNUNET_ATS_TEST_generate_traffic_stop (partner->tg);
502     partner->tg = NULL;
503   }
504
505   partner->tg = GNUNET_ATS_TEST_generate_traffic_start (peer, partner,
506                                                         op->gen_type,
507                                                         op->base_rate,
508                                                         op->max_rate,
509                                                         op->period,
510                                                         GNUNET_TIME_UNIT_FOREVER_REL);
511 }
512
513
514 static void
515 enforce_stop_send (struct GNUNET_ATS_TEST_Operation *op)
516 {
517   struct BenchmarkPartner *p;
518
519   p = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
520   if (NULL == p)
521   {
522     GNUNET_break (0);
523     return;
524   }
525
526   fprintf (stderr, "Found master %llu slave %llu\n", op->src_id, op->dest_id);
527
528   if (NULL != p->tg)
529   {
530     fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",
531              op->src_id, op->dest_id);
532     GNUNET_ATS_TEST_generate_traffic_stop (p->tg);
533     p->tg = NULL;
534   }
535 }
536
537
538 static void
539 enforce_start_preference (struct GNUNET_ATS_TEST_Operation *op)
540 {
541   struct BenchmarkPeer *peer;
542   struct BenchmarkPartner *partner;
543
544   peer = GNUNET_ATS_TEST_get_peer (op->src_id);
545   if (NULL == peer)
546   {
547     GNUNET_break (0);
548     return;
549   }
550
551   partner = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
552   if (NULL == partner)
553   {
554     GNUNET_break (0);
555     return;
556   }
557
558   fprintf (stderr, "Found master %llu slave %llu\n", op->src_id, op->dest_id);
559
560   if (NULL != partner->pg)
561   {
562     fprintf (stderr, "Stopping traffic between master %llu slave %llu\n",
563              op->src_id, op->dest_id);
564     GNUNET_ATS_TEST_generate_preferences_stop (partner->pg);
565     partner->pg = NULL;
566   }
567
568   partner->pg = GNUNET_ATS_TEST_generate_preferences_start (peer, partner,
569                                                             op->gen_type,
570                                                             op->base_rate,
571                                                             op->max_rate,
572                                                             op->period,
573                                                             op->frequency,
574                                                             op->pref_type);
575 }
576
577
578 static void
579 enforce_stop_preference (struct GNUNET_ATS_TEST_Operation *op)
580 {
581   struct BenchmarkPartner *p;
582
583   p = GNUNET_ATS_TEST_get_partner (op->src_id, op->dest_id);
584   if (NULL == p)
585   {
586     GNUNET_break (0);
587     return;
588   }
589
590   fprintf (stderr, "Found master %llu slave %llu\n", op->src_id, op->dest_id);
591
592   if (NULL != p->pg)
593   {
594     fprintf (stderr, "Stopping preference between master %llu slave %llu\n",
595              op->src_id, op->dest_id);
596     GNUNET_ATS_TEST_generate_preferences_stop (p->pg);
597     p->pg = NULL;
598   }
599 }
600
601
602 static void
603 enforce_episode (struct Episode *ep)
604 {
605   struct GNUNET_ATS_TEST_Operation *cur;
606
607   for (cur = ep->head; NULL != cur; cur = cur->next)
608   {
609     fprintf (stderr, "Enforcing operation: %s [%llu]->[%llu] == %llu\n",
610              print_op (cur->type), cur->src_id, cur->dest_id, cur->base_rate);
611     switch (cur->type)
612     {
613     case START_SEND:
614       enforce_start_send (cur);
615       break;
616
617     case STOP_SEND:
618       enforce_stop_send (cur);
619       break;
620
621     case START_PREFERENCE:
622       enforce_start_preference (cur);
623       break;
624
625     case STOP_PREFERENCE:
626       enforce_stop_preference (cur);
627       break;
628
629     default:
630       break;
631     }
632   }
633 }
634
635
636 static void
637 timeout_episode (void *cls)
638 {
639   struct Experiment *e = cls;
640
641   e->episode_timeout_task = NULL;
642   if (NULL != e->ep_done_cb)
643     e->ep_done_cb (e->cur);
644
645   /* Scheduling next */
646   e->cur = e->cur->next;
647   if (NULL == e->cur)
648   {
649     /* done */
650     fprintf (stderr, "Last episode done!\n");
651     if (NULL != e->experiment_timeout_task)
652     {
653       GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
654       e->experiment_timeout_task = NULL;
655     }
656     e->e_done_cb (e, GNUNET_TIME_absolute_get_duration (e->start_time),
657                   GNUNET_OK);
658     return;
659   }
660
661   fprintf (stderr, "Running episode %u with timeout %s\n",
662            e->cur->id,
663            GNUNET_STRINGS_relative_time_to_string (e->cur->duration,
664                                                    GNUNET_YES));
665   enforce_episode (e->cur);
666
667   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
668                                                           &timeout_episode, e);
669 }
670
671
672 void
673 GNUNET_ATS_TEST_experimentation_run (struct Experiment *e,
674                                      GNUNET_ATS_TESTING_EpisodeDoneCallback
675                                      ep_done_cb,
676                                      GNUNET_ATS_TESTING_ExperimentDoneCallback
677                                      e_done_cb)
678 {
679   fprintf (stderr, "Running experiment `%s'  with timeout %s\n", e->name,
680            GNUNET_STRINGS_relative_time_to_string (e->max_duration,
681                                                    GNUNET_YES));
682   e->e_done_cb = e_done_cb;
683   e->ep_done_cb = ep_done_cb;
684   e->start_time = GNUNET_TIME_absolute_get ();
685
686   /* Start total time out */
687   e->experiment_timeout_task = GNUNET_SCHEDULER_add_delayed (e->max_duration,
688                                                              &timeout_experiment,
689                                                              e);
690
691   /* Start */
692   e->cur = e->start;
693   fprintf (stderr, "Running episode %u with timeout %s\n",
694            e->cur->id,
695            GNUNET_STRINGS_relative_time_to_string (e->cur->duration,
696                                                    GNUNET_YES));
697   enforce_episode (e->cur);
698   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
699                                                           &timeout_episode, e);
700 }
701
702
703 struct Experiment *
704 GNUNET_ATS_TEST_experimentation_load (const char *filename)
705 {
706   struct Experiment *e;
707   struct GNUNET_CONFIGURATION_Handle *cfg;
708
709   e = NULL;
710
711   cfg = GNUNET_CONFIGURATION_create ();
712   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, filename))
713   {
714     fprintf (stderr, "Failed to load `%s'\n", filename);
715     GNUNET_CONFIGURATION_destroy (cfg);
716     return NULL;
717   }
718
719   e = create_experiment ();
720
721   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "experiment",
722                                                               "name", &e->name))
723   {
724     fprintf (stderr, "Invalid %s", "name");
725     free_experiment (e);
726     return NULL;
727   }
728   else
729     fprintf (stderr, "Experiment name: `%s'\n", e->name);
730
731   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg,
732                                                                 "experiment",
733                                                                 "cfg_file",
734                                                                 &e->cfg_file))
735   {
736     fprintf (stderr, "Invalid %s", "cfg_file");
737     free_experiment (e);
738     return NULL;
739   }
740   else
741     fprintf (stderr, "Experiment name: `%s'\n", e->cfg_file);
742
743   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "experiment",
744                                                               "masters",
745                                                               &e->num_masters))
746   {
747     fprintf (stderr, "Invalid %s", "masters");
748     free_experiment (e);
749     return NULL;
750   }
751   else
752     fprintf (stderr, "Experiment masters: `%llu'\n",
753              e->num_masters);
754
755   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg, "experiment",
756                                                               "slaves",
757                                                               &e->num_slaves))
758   {
759     fprintf (stderr, "Invalid %s", "slaves");
760     free_experiment (e);
761     return NULL;
762   }
763   else
764     fprintf (stderr, "Experiment slaves: `%llu'\n",
765              e->num_slaves);
766
767   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg, "experiment",
768                                                             "log_freq",
769                                                             &e->log_freq))
770   {
771     fprintf (stderr, "Invalid %s", "log_freq");
772     free_experiment (e);
773     return NULL;
774   }
775   else
776     fprintf (stderr, "Experiment logging frequency: `%s'\n",
777              GNUNET_STRINGS_relative_time_to_string (e->log_freq, GNUNET_YES));
778
779   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg, "experiment",
780                                                             "max_duration",
781                                                             &e->max_duration))
782   {
783     fprintf (stderr, "Invalid %s", "max_duration");
784     free_experiment (e);
785     return NULL;
786   }
787   else
788     fprintf (stderr, "Experiment duration: `%s'\n",
789              GNUNET_STRINGS_relative_time_to_string (e->max_duration,
790                                                      GNUNET_YES));
791
792   load_episodes (e, cfg);
793   fprintf (stderr, "Loaded %u episodes with total duration %s\n",
794            e->num_episodes,
795            GNUNET_STRINGS_relative_time_to_string (e->total_duration,
796                                                    GNUNET_YES));
797
798   GNUNET_CONFIGURATION_destroy (cfg);
799   return e;
800 }
801
802
803 void
804 GNUNET_ATS_TEST_experimentation_stop (struct Experiment *e)
805 {
806   if (NULL != e->experiment_timeout_task)
807   {
808     GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
809     e->experiment_timeout_task = NULL;
810   }
811   if (NULL != e->episode_timeout_task)
812   {
813     GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
814     e->episode_timeout_task = NULL;
815   }
816   free_experiment (e);
817 }
818
819
820 /* end of file ats-testing-experiment.c*/