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