property enforcement
[oweals/gnunet.git] / src / ats / gnunet-ats-solver-eval.c
1 /*
2  This file is part of GNUnet.
3  (C) 2010-2013 Christian Grothoff (and other contributing authors)
4
5  GNUnet is free software; you can redistribute it and/or modify
6  it 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  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  General Public License for more details.
14
15  You should have received a copy of the GNU General Public License
16  along with GNUnet; see the file COPYING.  If not, write to the
17  Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  Boston, MA 02111-1307, USA.
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 "gnunet-ats-solver-eval.h"
29
30 #define BIG_M_STRING "unlimited"
31
32 static struct Experiment *e;
33
34 static struct LoggingHandle *l;
35
36 static struct SolverHandle *sh;
37
38 static struct TestPeer *peer_head;
39 static struct TestPeer *peer_tail;
40
41 /**
42  * cmd option -e: experiment file
43  */
44 static char *opt_exp_file;
45
46 static char *opt_solver;
47
48 /**
49  * cmd option -l: enable logging
50  */
51 static int opt_log;
52
53 /**
54  * cmd option -p: enable plots
55  */
56 static int opt_plot;
57
58 /**
59  * cmd option -v: verbose logs
60  */
61 static int opt_verbose;
62
63 static int res;
64
65 static void
66 end_now ();
67
68 static char *
69 print_generator_type (enum GeneratorType g)
70 {
71   switch (g) {
72     case GNUNET_ATS_TEST_TG_CONSTANT:
73       return "CONSTANT";
74     case GNUNET_ATS_TEST_TG_LINEAR:
75       return "LINEAR";
76     case GNUNET_ATS_TEST_TG_RANDOM:
77       return "RANDOM";
78     case GNUNET_ATS_TEST_TG_SINUS:
79       return "SINUS";
80     default:
81       return "INVALID";
82       break;
83   }
84 }
85
86 struct AddressLookupCtx
87 {
88   struct ATS_Address *res;
89   char *plugin;
90   char *addr;
91 };
92
93
94 int find_address_it (void *cls,
95                      const struct GNUNET_PeerIdentity *key,
96                      void *value)
97 {
98   struct AddressLookupCtx *ctx = cls;
99   struct ATS_Address *addr = value;
100
101   if ( (0 == strcmp (ctx->plugin, addr->plugin)) &&
102        (0 == strcmp (ctx->addr, addr->addr)) )
103   {
104        ctx->res = addr;
105        return GNUNET_NO;
106   }
107   return GNUNET_YES;
108 }
109
110 static struct TestPeer *
111 find_peer_by_id (int id)
112 {
113   struct TestPeer *cur;
114   for (cur = peer_head; NULL != cur; cur = cur->next)
115     if (cur->id == id)
116       return cur;
117   return NULL;
118 }
119
120 static struct TestAddress *
121 find_address_by_id (struct TestPeer *peer, int aid)
122 {
123   struct TestAddress *cur;
124   for (cur = peer->addr_head; NULL != cur; cur = cur->next)
125     if (cur->aid == aid)
126       return cur;
127   return NULL;
128 }
129
130
131
132 /**
133  * Logging
134  */
135
136 static void
137 logging_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
138 {
139   struct LoggingHandle *l = cls;
140
141   l->logging_task = GNUNET_SCHEDULER_NO_TASK;
142
143   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Logging\n");
144
145   l->logging_task = GNUNET_SCHEDULER_add_delayed (l->log_freq, &logging_task, l);
146
147 }
148
149 struct LoggingHandle *
150 GNUNET_ATS_solver_logging_start (struct GNUNET_TIME_Relative freq)
151 {
152   struct LoggingHandle *l;
153   l = GNUNET_new (struct LoggingHandle);
154
155   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start logging every  %s\n",
156       GNUNET_STRINGS_relative_time_to_string(freq, GNUNET_NO));
157
158   /* Iterate over peers */
159
160   l->log_freq = freq;
161   l->logging_task = GNUNET_SCHEDULER_add_now (&logging_task, l);
162
163   return l;
164 }
165
166 void
167 GNUNET_ATS_solver_logging_now (struct LoggingHandle *l)
168 {
169   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Logging\n");
170 }
171
172 void
173 GNUNET_ATS_solver_logging_stop (struct LoggingHandle *l)
174 {
175   if (GNUNET_SCHEDULER_NO_TASK != l->logging_task)
176     GNUNET_SCHEDULER_cancel (l->logging_task);
177
178   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stop logging\n");
179
180   l->logging_task = GNUNET_SCHEDULER_NO_TASK;
181 }
182
183 void
184 GNUNET_ATS_solver_logging_eval (struct LoggingHandle *l)
185 {
186
187 }
188
189 void
190 GNUNET_ATS_solver_logging_free (struct LoggingHandle *l)
191 {
192   if (GNUNET_SCHEDULER_NO_TASK != l->logging_task)
193     GNUNET_SCHEDULER_cancel (l->logging_task);
194   l->logging_task = GNUNET_SCHEDULER_NO_TASK;
195   GNUNET_free (l);
196 }
197
198 /**
199  * Property Generators
200  */
201
202 static struct PropertyGenerator *prop_gen_head;
203 static struct PropertyGenerator *prop_gen_tail;
204
205 static double
206 get_property (struct PropertyGenerator *pg)
207 {
208   struct GNUNET_TIME_Relative time_delta;
209   double delta_value;
210   double pref_value;
211
212   /* Calculate the current preference value */
213   switch (pg->type) {
214     case GNUNET_ATS_TEST_TG_CONSTANT:
215       pref_value = pg->base_value;
216       break;
217     case GNUNET_ATS_TEST_TG_LINEAR:
218       time_delta = GNUNET_TIME_absolute_get_duration(pg->time_start);
219       /* Calculate point of time in the current period */
220       time_delta.rel_value_us = time_delta.rel_value_us %
221           pg->duration_period.rel_value_us;
222       delta_value = ((double) time_delta.rel_value_us  /
223           pg->duration_period.rel_value_us) * (pg->max_value - pg->base_value);
224       if ((pg->max_value < pg->base_value) &&
225           ((pg->max_value - pg->base_value) > pg->base_value))
226       {
227         /* This will cause an underflow */
228         GNUNET_break (0);
229       }
230       pref_value = pg->base_value + delta_value;
231       break;
232     case GNUNET_ATS_TEST_TG_RANDOM:
233       delta_value =  (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
234           10000 * (pg->max_value - pg->base_value)) / 10000;
235       pref_value = pg->base_value + delta_value;
236       break;
237     case GNUNET_ATS_TEST_TG_SINUS:
238       time_delta = GNUNET_TIME_absolute_get_duration(pg->time_start);
239       /* Calculate point of time in the current period */
240       time_delta.rel_value_us = time_delta.rel_value_us %
241           pg->duration_period.rel_value_us;
242       if ((pg->max_value - pg->base_value) > pg->base_value)
243       {
244         /* This will cause an underflow for second half of sinus period,
245          * will be detected in general when experiments are loaded */
246         GNUNET_break (0);
247       }
248       delta_value = (pg->max_value - pg->base_value) *
249           sin ( (2 * M_PI) / ((double) pg->duration_period.rel_value_us) *
250               time_delta.rel_value_us);
251       pref_value = pg->base_value + delta_value;
252       break;
253     default:
254       pref_value = 0.0;
255       break;
256   }
257   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Current property value is %f\n",
258       pref_value);
259   return pref_value;
260 }
261
262
263 static void
264 set_prop_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
265 {
266   struct PropertyGenerator *pg = cls;
267   double pref_value;
268   struct GNUNET_ATS_Information atsi;
269
270   pg->set_task = GNUNET_SCHEDULER_NO_TASK;
271
272   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains_value (sh->addresses,
273       &pg->test_peer->peer_id, pg->test_address->ats_addr))
274   {
275     GNUNET_break (0);
276     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
277         "Setting property generation for unknown address %u\n", pg->address_id);
278     return;
279   }
280
281   pref_value = get_property (pg);
282
283   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
284       "Setting property for peer [%u] address [%u] for %s to %f\n",
285       pg->peer, pg->address_id,
286       GNUNET_ATS_print_property_type (pg->ats_property), pref_value);
287
288
289   atsi.type = pg->ats_property;
290   atsi.value = (uint32_t) pref_value;
291
292   /* set performance here! */
293   sh->env.sf.s_bulk_start (sh->solver);
294   GAS_normalization_normalize_property (sh->addresses,
295       pg->test_address->ats_addr, &atsi, 1);
296   sh->env.sf.s_bulk_stop (sh->solver);
297
298
299   switch (pg->ats_property) {
300     case GNUNET_ATS_PREFERENCE_BANDWIDTH:
301       //p->pref_bandwidth = pref_value;
302       break;
303     case GNUNET_ATS_PREFERENCE_LATENCY:
304       //p->pref_delay = pref_value;
305       break;
306     default:
307       break;
308   }
309
310   pg->set_task = GNUNET_SCHEDULER_add_delayed (pg->frequency,
311       &set_prop_task, pg);
312
313 }
314
315 static struct PropertyGenerator *
316 find_prop_gen (unsigned int peer, unsigned int address,
317     uint32_t ats_property)
318 {
319   struct PropertyGenerator *cur;
320   for (cur = prop_gen_head; NULL != cur; cur = cur->next)
321     if ((cur->peer == peer) && (cur->address_id == address) &&
322         (cur->ats_property == ats_property))
323       return cur;
324   return NULL;
325 }
326
327 void
328 GNUNET_ATS_solver_generate_property_stop (struct PropertyGenerator *pg)
329 {
330   GNUNET_CONTAINER_DLL_remove (prop_gen_head, prop_gen_tail, pg);
331
332   if (GNUNET_SCHEDULER_NO_TASK != pg->set_task)
333   {
334     GNUNET_SCHEDULER_cancel (pg->set_task);
335     pg->set_task = GNUNET_SCHEDULER_NO_TASK;
336   }
337   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
338       "Removing old up preference generator peer [%u] address [%u] `%s'\n",
339       pg->peer, pg->address_id,
340       GNUNET_ATS_print_property_type(pg->ats_property));
341
342   GNUNET_free (pg);
343 }
344
345
346 /**
347  * Generate between the source master and the partner and set preferences with a
348  * value depending on the generator.
349  *
350  * @param src source
351  * @param dest partner
352  * @param type type of preferences to generate
353  * @param base_rate traffic base rate to send data with
354  * @param max_rate  traffic maximum rate to send data with
355  * @param period duration of a period of traffic generation (~ 1/frequency)
356  * @param duration how long to generate traffic
357  * @return the traffic generator
358  */
359 struct PropertyGenerator *
360 GNUNET_ATS_solver_generate_property_start (unsigned int peer,
361     unsigned int address_id,
362     struct TestPeer *test_peer,
363     struct TestAddress *test_address,
364     enum GeneratorType type,
365     long int base_value,
366     long int value_rate,
367     struct GNUNET_TIME_Relative period,
368     struct GNUNET_TIME_Relative frequency,
369     uint32_t ats_property)
370 {
371   struct PropertyGenerator *pg;
372
373   pg = GNUNET_new (struct PropertyGenerator);
374   GNUNET_CONTAINER_DLL_insert (prop_gen_head, prop_gen_tail, pg);
375   pg->type = type;
376   pg->peer = peer;
377   pg->test_address = test_address;
378   pg->test_peer = test_peer;
379   pg->address_id = address_id;
380   pg->ats_property = ats_property;
381   pg->base_value = base_value;
382   pg->max_value = value_rate;
383   pg->duration_period = period;
384   pg->frequency = frequency;
385   pg->time_start = GNUNET_TIME_absolute_get();
386
387   switch (type) {
388     case GNUNET_ATS_TEST_TG_CONSTANT:
389       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
390           "Setting up %s property generator peer [%u] address [%u] `%s'"\
391           "max %u Bips\n",
392           print_generator_type(type), pg->peer, pg->address_id,
393           GNUNET_ATS_print_property_type (ats_property),
394           base_value);
395       break;
396     case GNUNET_ATS_TEST_TG_LINEAR:
397       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
398           "Setting up %s property generator peer [%u] address [%u] `%s' " \
399           "min %u Bips max %u Bips\n",
400           print_generator_type(type), pg->peer, pg->address_id,
401           GNUNET_ATS_print_property_type(ats_property),
402           base_value, value_rate);
403       break;
404     case GNUNET_ATS_TEST_TG_SINUS:
405       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
406           "Setting up %s property generator peer [%u] address [%u] `%s' "\
407           "baserate %u Bips, amplitude %u Bps\n",
408           print_generator_type(type), pg->peer, pg->address_id,
409           GNUNET_ATS_print_property_type(ats_property),
410           base_value, value_rate);
411       break;
412     case GNUNET_ATS_TEST_TG_RANDOM:
413       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
414           "Setting up %s property generator peer [%u] address [%u] `%s' "\
415           "min %u Bips max %u Bps\n",
416           print_generator_type(type), pg->peer, pg->address_id,
417           GNUNET_ATS_print_property_type(ats_property),
418           base_value, value_rate);
419       break;
420     default:
421       break;
422   }
423
424   pg->set_task = GNUNET_SCHEDULER_add_now (&set_prop_task, pg);
425   return pg;
426 }
427
428
429
430 /**
431  * Stop all preferences generators
432  */
433 void
434 GNUNET_ATS_solver_generate_property_stop_all ()
435 {
436   struct PropertyGenerator *cur;
437   struct PropertyGenerator *next;
438   next = prop_gen_head;
439   for (cur = next; NULL != cur; cur = next)
440   {
441       next = cur->next;
442       GNUNET_ATS_solver_generate_property_stop (cur);
443   }
444 }
445
446
447 /**
448  * Preference Generators
449  */
450
451 static struct PreferenceGenerator *pref_gen_head;
452 static struct PreferenceGenerator *pref_gen_tail;
453
454 static double
455 get_preference (struct PreferenceGenerator *pg)
456 {
457   struct GNUNET_TIME_Relative time_delta;
458   double delta_value;
459   double pref_value;
460
461   /* Calculate the current preference value */
462   switch (pg->type) {
463     case GNUNET_ATS_TEST_TG_CONSTANT:
464       pref_value = pg->base_value;
465       break;
466     case GNUNET_ATS_TEST_TG_LINEAR:
467       time_delta = GNUNET_TIME_absolute_get_duration(pg->time_start);
468       /* Calculate point of time in the current period */
469       time_delta.rel_value_us = time_delta.rel_value_us %
470           pg->duration_period.rel_value_us;
471       delta_value = ((double) time_delta.rel_value_us  /
472           pg->duration_period.rel_value_us) * (pg->max_value - pg->base_value);
473       if ((pg->max_value < pg->base_value) &&
474           ((pg->max_value - pg->base_value) > pg->base_value))
475       {
476         /* This will cause an underflow */
477         GNUNET_break (0);
478       }
479       pref_value = pg->base_value + delta_value;
480       break;
481     case GNUNET_ATS_TEST_TG_RANDOM:
482       delta_value =  (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
483           10000 * (pg->max_value - pg->base_value)) / 10000;
484       pref_value = pg->base_value + delta_value;
485       break;
486     case GNUNET_ATS_TEST_TG_SINUS:
487       time_delta = GNUNET_TIME_absolute_get_duration(pg->time_start);
488       /* Calculate point of time in the current period */
489       time_delta.rel_value_us = time_delta.rel_value_us %
490           pg->duration_period.rel_value_us;
491       if ((pg->max_value - pg->base_value) > pg->base_value)
492       {
493         /* This will cause an underflow for second half of sinus period,
494          * will be detected in general when experiments are loaded */
495         GNUNET_break (0);
496       }
497       delta_value = (pg->max_value - pg->base_value) *
498           sin ( (2 * M_PI) / ((double) pg->duration_period.rel_value_us) *
499               time_delta.rel_value_us);
500       pref_value = pg->base_value + delta_value;
501       break;
502     default:
503       pref_value = 0.0;
504       break;
505   }
506   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Current preference value is %f\n",
507       pref_value);
508   return pref_value;
509 }
510
511
512 static void
513 set_pref_task (void *cls,
514                     const struct GNUNET_SCHEDULER_TaskContext *tc)
515 {
516   struct PreferenceGenerator *pg = cls;
517   double pref_value;
518   pg->set_task = GNUNET_SCHEDULER_NO_TASK;
519
520   pref_value = get_preference (pg);
521
522   GNUNET_log(GNUNET_ERROR_TYPE_INFO,
523       "Setting preference for peer [%u] address [%u] for %s to %f\n",
524       pg->peer, pg->address_id,
525       GNUNET_ATS_print_preference_type (pg->kind), pref_value);
526
527   /* set performance here!
528   GNUNET_ATS_performance_change_preference(p->me->ats_perf_handle,
529       &p->dest->id, p->pg->kind, pref_value, GNUNET_ATS_PREFERENCE_END);
530 */
531
532   switch (pg->kind) {
533     case GNUNET_ATS_PREFERENCE_BANDWIDTH:
534       //p->pref_bandwidth = pref_value;
535       break;
536     case GNUNET_ATS_PREFERENCE_LATENCY:
537       //p->pref_delay = pref_value;
538       break;
539     default:
540       break;
541   }
542
543   pg->set_task = GNUNET_SCHEDULER_add_delayed (pg->frequency,
544       set_pref_task, pg);
545
546 }
547
548 static struct PreferenceGenerator *
549 find_pref_gen (unsigned int peer, unsigned int address,
550     enum GNUNET_ATS_PreferenceKind kind)
551 {
552   struct PreferenceGenerator *cur;
553   for (cur = pref_gen_head; NULL != cur; cur = cur->next)
554     if ((cur->peer == peer) && (cur->address_id == address) && (cur->kind == kind))
555       return cur;
556   return NULL;
557 }
558
559 void
560 GNUNET_ATS_solver_generate_preferences_stop (struct PreferenceGenerator *pg)
561 {
562   GNUNET_CONTAINER_DLL_remove (pref_gen_head, pref_gen_tail, pg);
563
564   if (GNUNET_SCHEDULER_NO_TASK != pg->set_task)
565   {
566     GNUNET_SCHEDULER_cancel (pg->set_task);
567     pg->set_task = GNUNET_SCHEDULER_NO_TASK;
568   }
569   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
570       "Removing old up preference generator peer [%u] address [%u] `%s'\n",
571       pg->peer, pg->address_id, GNUNET_ATS_print_preference_type(pg->kind));
572
573   GNUNET_free (pg);
574 }
575
576
577 /**
578  * Generate between the source master and the partner and set preferences with a
579  * value depending on the generator.
580  *
581  * @param src source
582  * @param dest partner
583  * @param type type of preferences to generate
584  * @param base_rate traffic base rate to send data with
585  * @param max_rate  traffic maximum rate to send data with
586  * @param period duration of a period of traffic generation (~ 1/frequency)
587  * @param duration how long to generate traffic
588  * @return the traffic generator
589  */
590 struct PreferenceGenerator *
591 GNUNET_ATS_solver_generate_preferences_start (unsigned int peer,
592     unsigned int address_id,
593     enum GeneratorType type,
594     long int base_value,
595     long int value_rate,
596     struct GNUNET_TIME_Relative period,
597     struct GNUNET_TIME_Relative frequency,
598     enum GNUNET_ATS_PreferenceKind kind)
599 {
600   struct PreferenceGenerator *pg;
601
602   pg = GNUNET_new (struct PreferenceGenerator);
603   GNUNET_CONTAINER_DLL_insert (pref_gen_head, pref_gen_tail, pg);
604   pg->type = type;
605   pg->peer = peer;
606   pg->address_id = address_id;
607   pg->kind = kind;
608   pg->base_value = base_value;
609   pg->max_value = value_rate;
610   pg->duration_period = period;
611   pg->frequency = frequency;
612   pg->time_start = GNUNET_TIME_absolute_get();
613
614   switch (type) {
615     case GNUNET_ATS_TEST_TG_CONSTANT:
616       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
617           "Setting up %s preference generator peer [%u] address [%u] `%s' max %u Bips\n",
618           print_generator_type (type), pg->peer, pg->address_id,
619           GNUNET_ATS_print_preference_type(kind),
620           base_value);
621       break;
622     case GNUNET_ATS_TEST_TG_LINEAR:
623       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
624           "Setting up %s preference generator peer [%u] address [%u] `%s' min %u Bips max %u Bips\n",
625           print_generator_type (type), pg->peer, pg->address_id, GNUNET_ATS_print_preference_type(kind),
626           base_value, value_rate);
627       break;
628     case GNUNET_ATS_TEST_TG_SINUS:
629       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
630           "Setting up %s preference generator peer [%u] address [%u] `%s' baserate %u Bips, amplitude %u Bps\n",
631           print_generator_type (type), pg->peer, pg->address_id, GNUNET_ATS_print_preference_type(kind),
632           base_value, value_rate);
633       break;
634     case GNUNET_ATS_TEST_TG_RANDOM:
635       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
636           "Setting up %s preference generator peer [%u] address [%u] `%s' min %u Bips max %u Bps\n",
637           print_generator_type (type), pg->peer, pg->address_id, GNUNET_ATS_print_preference_type(kind),
638           base_value, value_rate);
639       break;
640     default:
641       break;
642   }
643
644   pg->set_task = GNUNET_SCHEDULER_add_now (&set_pref_task, pg);
645   return pg;
646 }
647
648
649
650 /**
651  * Stop all preferences generators
652  */
653 void
654 GNUNET_ATS_solver_generate_preferences_stop_all ()
655 {
656   struct PreferenceGenerator *cur;
657   struct PreferenceGenerator *next;
658   next = pref_gen_head;
659   for (cur = next; NULL != cur; cur = next)
660   {
661       next = cur->next;
662       GNUNET_ATS_solver_generate_preferences_stop(cur);
663   }
664 }
665
666
667
668 /**
669  * Experiments
670  */
671
672 const char *
673 print_op (enum OperationType op)
674 {
675   switch (op) {
676     case SOLVER_OP_ADD_ADDRESS:
677       return "ADD_ADDRESS";
678     case SOLVER_OP_DEL_ADDRESS:
679       return "DEL_ADDRESS";
680     case SOLVER_OP_START_SET_PREFERENCE:
681       return "START_SET_PREFERENCE";
682     case SOLVER_OP_STOP_SET_PREFERENCE:
683       return "STOP_STOP_PREFERENCE";
684     case SOLVER_OP_START_SET_PROPERTY:
685       return "START_SET_PROPERTY";
686     case SOLVER_OP_STOP_SET_PROPERTY:
687       return "STOP_SET_PROPERTY";
688     case SOLVER_OP_START_REQUEST:
689       return "START_REQUEST";
690     case SOLVER_OP_STOP_REQUEST:
691       return "STOP_REQUEST";
692     default:
693       break;
694   }
695   return "";
696 }
697
698 static struct Experiment *
699 create_experiment ()
700 {
701   struct Experiment *e;
702   e = GNUNET_new (struct Experiment);
703   e->name = NULL;
704   e->num_masters = 0;
705   e->num_slaves = 0;
706   e->start = NULL;
707   e->total_duration = GNUNET_TIME_UNIT_ZERO;
708   return e;
709 }
710
711 static void
712 free_experiment (struct Experiment *e)
713 {
714   struct Episode *cur;
715   struct Episode *next;
716   struct GNUNET_ATS_TEST_Operation *cur_o;
717   struct GNUNET_ATS_TEST_Operation *next_o;
718
719   next = e->start;
720   for (cur = next; NULL != cur; cur = next)
721   {
722     next = cur->next;
723
724     next_o = cur->head;
725     for (cur_o = next_o; NULL != cur_o; cur_o = next_o)
726     {
727       next_o = cur_o->next;
728       GNUNET_free_non_null (cur_o->address);
729       GNUNET_free_non_null (cur_o->plugin);
730       GNUNET_free (cur_o);
731     }
732     GNUNET_free (cur);
733   }
734
735   GNUNET_free_non_null (e->name);
736   GNUNET_free_non_null (e->cfg_file);
737   GNUNET_free (e);
738 }
739
740
741 static int
742 load_op_add_address (struct GNUNET_ATS_TEST_Operation *o,
743     struct Episode *e,
744     int op_counter,
745     char *sec_name,
746     const struct GNUNET_CONFIGURATION_Handle *cfg)
747 {
748   char *op_name;
749
750   /* peer id */
751   GNUNET_asprintf(&op_name, "op-%u-peer-id", op_counter);
752   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
753       sec_name, op_name, &o->peer_id))
754   {
755     fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
756         op_counter, "ADD_ADDRESS", op_name);
757     GNUNET_free (op_name);
758     return GNUNET_SYSERR;
759   }
760   GNUNET_free (op_name);
761
762   /* address id */
763   GNUNET_asprintf(&op_name, "op-%u-address-id", op_counter);
764   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
765       sec_name, op_name, &o->address_id))
766   {
767     fprintf (stderr, "Missing address-id in operation %u `%s' in episode `%s'\n",
768         op_counter, "ADD_ADDRESS", op_name);
769     GNUNET_free (op_name);
770     return GNUNET_SYSERR;
771   }
772   GNUNET_free (op_name);
773
774   /* plugin */
775   GNUNET_asprintf(&op_name, "op-%u-plugin", op_counter);
776   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
777       sec_name, op_name, &o->plugin))
778   {
779     fprintf (stderr, "Missing plugin in operation %u `%s' in episode `%s'\n",
780         op_counter, "ADD_ADDRESS", op_name);
781     GNUNET_free (op_name);
782     return GNUNET_SYSERR;
783   }
784   GNUNET_free (op_name);
785
786   /* address  */
787   GNUNET_asprintf(&op_name, "op-%u-address", op_counter);
788   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
789       sec_name, op_name, &o->address))
790   {
791     fprintf (stderr, "Missing address in operation %u `%s' in episode `%s'\n",
792         op_counter, "ADD_ADDRESS", op_name);
793     GNUNET_free (op_name);
794     return GNUNET_SYSERR;
795   }
796   GNUNET_free (op_name);
797
798   /* session */
799   GNUNET_asprintf(&op_name, "op-%u-address-session", op_counter);
800   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
801       sec_name, op_name, &o->address_session))
802   {
803     fprintf (stderr, "Missing address-session in operation %u `%s' in episode `%s'\n",
804         op_counter, "ADD_ADDRESS", op_name);
805     GNUNET_free (op_name);
806     return GNUNET_SYSERR;
807   }
808   GNUNET_free (op_name);
809
810   /* network */
811   GNUNET_asprintf(&op_name, "op-%u-address-network", op_counter);
812   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
813       sec_name, op_name, &o->address_network))
814   {
815     fprintf (stderr, "Missing address-network in operation %u `%s' in episode `%s'\n",
816         op_counter, "ADD_ADDRESS", op_name);
817     GNUNET_free (op_name);
818     return GNUNET_SYSERR;
819   }
820   GNUNET_free (op_name);
821
822   fprintf (stderr,
823       "Found operation %s: [%llu:%llu] address `%s' plugin `%s' \n",
824       "ADD_ADDRESS", o->peer_id, o->address_id, o->address, o->plugin);
825
826   return GNUNET_OK;
827 }
828
829 static int
830 load_op_del_address (struct GNUNET_ATS_TEST_Operation *o,
831     struct Episode *e,
832     int op_counter,
833     char *sec_name,
834     const struct GNUNET_CONFIGURATION_Handle *cfg)
835 {
836   char *op_name;
837
838   /* peer id */
839   GNUNET_asprintf(&op_name, "op-%u-peer-id", op_counter);
840   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
841       sec_name, op_name, &o->peer_id))
842   {
843     fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
844         op_counter, "DEL_ADDRESS", op_name);
845     GNUNET_free (op_name);
846     return GNUNET_SYSERR;
847   }
848   GNUNET_free (op_name);
849
850   /* address id */
851   GNUNET_asprintf(&op_name, "op-%u-address-id", op_counter);
852   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
853       sec_name, op_name, &o->address_id))
854   {
855     fprintf (stderr, "Missing address-id in operation %u `%s' in episode `%s'\n",
856         op_counter, "DEL_ADDRESS", op_name);
857     GNUNET_free (op_name);
858     return GNUNET_SYSERR;
859   }
860   GNUNET_free (op_name);
861
862   /* plugin */
863   GNUNET_asprintf(&op_name, "op-%u-plugin", op_counter);
864   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
865       sec_name, op_name, &o->plugin))
866   {
867     fprintf (stderr, "Missing plugin in operation %u `%s' in episode `%s'\n",
868         op_counter, "DEL_ADDRESS", op_name);
869     GNUNET_free (op_name);
870     return GNUNET_SYSERR;
871   }
872   GNUNET_free (op_name);
873
874   /* address  */
875   GNUNET_asprintf(&op_name, "op-%u-address", op_counter);
876   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
877       sec_name, op_name, &o->address))
878   {
879     fprintf (stderr, "Missing address in operation %u `%s' in episode `%s'\n",
880         op_counter, "DEL_ADDRESS", op_name);
881     GNUNET_free (op_name);
882     return GNUNET_SYSERR;
883   }
884   GNUNET_free (op_name);
885
886   /* session */
887   GNUNET_asprintf(&op_name, "op-%u-address-session", op_counter);
888   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
889       sec_name, op_name, &o->address_session))
890   {
891     fprintf (stderr, "Missing address-session in operation %u `%s' in episode `%s'\n",
892         op_counter, "DEL_ADDRESS", op_name);
893     GNUNET_free (op_name);
894     return GNUNET_SYSERR;
895   }
896   GNUNET_free (op_name);
897
898   /* network */
899   GNUNET_asprintf(&op_name, "op-%u-address-network", op_counter);
900   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
901       sec_name, op_name, &o->address_network))
902   {
903     fprintf (stderr, "Missing address-network in operation %u `%s' in episode `%s'\n",
904         op_counter, "DEL_ADDRESS", op_name);
905     GNUNET_free (op_name);
906     return GNUNET_SYSERR;
907   }
908   GNUNET_free (op_name);
909
910   fprintf (stderr,
911       "Found operation %s: [%llu:%llu] address `%s' plugin `%s' \n",
912       "DEL_ADDRESS", o->peer_id, o->address_id, o->address, o->plugin);
913
914   return GNUNET_OK;
915 }
916
917 static enum GNUNET_ATS_Property
918 parse_preference_string (const char * str)
919 {
920   int c = 0;
921   char *props[GNUNET_ATS_PreferenceCount] = GNUNET_ATS_PreferenceTypeString;
922
923   for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
924     if (0 == strcmp(str, props[c]))
925       return c;
926   return 0;
927 };
928
929 static int
930 load_op_start_set_preference (struct GNUNET_ATS_TEST_Operation *o,
931     struct Episode *e,
932     int op_counter,
933     char *sec_name,
934     const struct GNUNET_CONFIGURATION_Handle *cfg)
935 {
936   char *op_name;
937   char *type;
938   char *pref;
939
940   /* peer id */
941   GNUNET_asprintf(&op_name, "op-%u-peer-id", op_counter);
942   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
943       sec_name, op_name, &o->peer_id))
944   {
945     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
946         op_counter, "START_SET_PREFERENCE", op_name);
947     GNUNET_free (op_name);
948     return GNUNET_SYSERR;
949   }
950   GNUNET_free (op_name);
951
952   /* address id */
953   GNUNET_asprintf(&op_name, "op-%u-address-id", op_counter);
954   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
955       sec_name, op_name, &o->address_id))
956   {
957     fprintf (stderr, "Missing address-id in operation %u `%s' in episode `%s'\n",
958         op_counter, "START_SET_PREFERENCE", op_name);
959     GNUNET_free (op_name);
960     return GNUNET_SYSERR;
961   }
962   GNUNET_free (op_name);
963
964   /* generator */
965   GNUNET_asprintf(&op_name, "op-%u-gen-type", op_counter);
966   if ( (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg,
967           sec_name, op_name, &type)) )
968   {
969     fprintf (stderr, "Missing type in operation %u `%s' in episode `%s'\n",
970         op_counter, "START_SET_PREFERENCE", op_name);
971     GNUNET_free (op_name);
972     return GNUNET_SYSERR;
973   }
974
975   /* Load arguments for set_rate, start_send, set_preference */
976   if (0 == strcmp (type, "constant"))
977   {
978     o->gen_type = GNUNET_ATS_TEST_TG_CONSTANT;
979   }
980   else if (0 == strcmp (type, "linear"))
981   {
982     o->gen_type = GNUNET_ATS_TEST_TG_LINEAR;
983   }
984   else if (0 == strcmp (type, "sinus"))
985   {
986     o->gen_type = GNUNET_ATS_TEST_TG_SINUS;
987   }
988   else if (0 == strcmp (type, "random"))
989   {
990     o->gen_type = GNUNET_ATS_TEST_TG_RANDOM;
991   }
992   else
993   {
994     fprintf (stderr, "Invalid generator type %u `%s' in episode %u\n",
995         op_counter, op_name, e->id);
996     GNUNET_free (type);
997     GNUNET_free (op_name);
998     return GNUNET_SYSERR;
999   }
1000   GNUNET_free (type);
1001   GNUNET_free (op_name);
1002
1003
1004   /* Get base rate */
1005   GNUNET_asprintf(&op_name, "op-%u-base-rate", op_counter);
1006   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1007       sec_name, op_name, &o->base_rate))
1008   {
1009     fprintf (stderr, "Missing base rate in operation %u `%s' in episode %u\n",
1010         op_counter, op_name, e->id);
1011     GNUNET_free (op_name);
1012     return GNUNET_SYSERR;
1013   }
1014   GNUNET_free (op_name);
1015
1016
1017   /* Get max rate */
1018   GNUNET_asprintf(&op_name, "op-%u-max-rate", op_counter);
1019   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1020       sec_name, op_name, &o->max_rate))
1021   {
1022     if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
1023         (GNUNET_ATS_TEST_TG_RANDOM == o->gen_type) ||
1024         (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
1025     {
1026       fprintf (stderr, "Missing max rate in operation %u `%s' in episode %u\n",
1027           op_counter, op_name, e->id);
1028       GNUNET_free (op_name);
1029       return GNUNET_SYSERR;
1030     }
1031   }
1032   GNUNET_free (op_name);
1033
1034   /* Get period */
1035   GNUNET_asprintf(&op_name, "op-%u-period", op_counter);
1036   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1037       sec_name, op_name, &o->period))
1038   {
1039     o->period = e->duration;
1040   }
1041   GNUNET_free (op_name);
1042
1043   /* Get frequency */
1044   GNUNET_asprintf(&op_name, "op-%u-frequency", op_counter);
1045   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1046       sec_name, op_name, &o->frequency))
1047   {
1048       fprintf (stderr, "Missing frequency in operation %u `%s' in episode %u\n",
1049           op_counter, op_name, e->id);
1050       GNUNET_free (op_name);
1051       return GNUNET_SYSERR;
1052   }
1053   GNUNET_free (op_name);
1054
1055   /* Get preference */
1056   GNUNET_asprintf(&op_name, "op-%u-pref", op_counter);
1057   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1058       sec_name, op_name, &pref))
1059   {
1060       fprintf (stderr, "Missing preference in operation %u `%s' in episode %u\n",
1061           op_counter, op_name, e->id);
1062       GNUNET_free (op_name);
1063       return GNUNET_SYSERR;
1064   }
1065
1066   if (0 == (o->pref_type = parse_preference_string(pref)))
1067   {
1068       fprintf (stderr, "Invalid preference in operation %u `%s' in episode %u\n",
1069           op_counter, op_name, e->id);
1070       GNUNET_free (op_name);
1071       GNUNET_free (pref);
1072       return GNUNET_SYSERR;
1073   }
1074   GNUNET_free (pref);
1075   GNUNET_free (op_name);
1076
1077   fprintf (stderr,
1078       "Found operation %s: [%llu:%llu]: %s = %llu\n",
1079       "START_SET_PREFERENCE", o->peer_id, o->address_id,
1080       GNUNET_ATS_print_preference_type(o->pref_type), o->base_rate);
1081
1082   return GNUNET_OK;
1083 }
1084
1085 static int
1086 load_op_stop_set_preference (struct GNUNET_ATS_TEST_Operation *o,
1087     struct Episode *e,
1088     int op_counter,
1089     char *sec_name,
1090     const struct GNUNET_CONFIGURATION_Handle *cfg)
1091 {
1092   char *op_name;
1093   char *pref;
1094
1095   /* peer id */
1096   GNUNET_asprintf(&op_name, "op-%u-peer-id", op_counter);
1097   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1098       sec_name, op_name, &o->peer_id))
1099   {
1100     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
1101         op_counter, "STOP_SET_PREFERENCE", op_name);
1102     GNUNET_free (op_name);
1103     return GNUNET_SYSERR;
1104   }
1105   GNUNET_free (op_name);
1106
1107   /* address id */
1108   GNUNET_asprintf(&op_name, "op-%u-address-id", op_counter);
1109   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1110       sec_name, op_name, &o->address_id))
1111   {
1112     fprintf (stderr, "Missing address-id in operation %u `%s' in episode `%s'\n",
1113         op_counter, "STOP_SET_PREFERENCE", op_name);
1114     GNUNET_free (op_name);
1115     return GNUNET_SYSERR;
1116   }
1117   GNUNET_free (op_name);
1118
1119   /* Get preference */
1120   GNUNET_asprintf(&op_name, "op-%u-pref", op_counter);
1121   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1122       sec_name, op_name, &pref))
1123   {
1124     fprintf (stderr, "Missing preference in operation %u `%s' in episode `%s'\n",
1125         op_counter, "STOP_SET_PREFERENCE", op_name);
1126       GNUNET_free (op_name);
1127       return GNUNET_SYSERR;
1128   }
1129
1130   if (0 == (o->pref_type = parse_preference_string(pref)))
1131   {
1132       fprintf (stderr, "Invalid preference in operation %u `%s' in episode %u\n",
1133           op_counter, op_name, e->id);
1134       GNUNET_free (op_name);
1135       GNUNET_free (pref);
1136       return GNUNET_SYSERR;
1137   }
1138   GNUNET_free (pref);
1139   GNUNET_free (op_name);
1140
1141   fprintf (stderr,
1142       "Found operation %s: [%llu:%llu]: %s\n",
1143       "STOP_SET_PREFERENCE", o->peer_id, o->address_id,
1144       GNUNET_ATS_print_preference_type(o->pref_type));
1145   return GNUNET_OK;
1146 }
1147
1148 static enum GNUNET_ATS_Property
1149 parse_property_string (const char * str)
1150 {
1151   int c = 0;
1152   char *props[GNUNET_ATS_PropertyCount] = GNUNET_ATS_PropertyStrings;
1153
1154   for (c = 0; c < GNUNET_ATS_PropertyCount; c++)
1155     if (0 == strcmp(str, props[c]))
1156       return c;
1157   return 0;
1158 };
1159
1160 static int
1161 load_op_start_set_property(struct GNUNET_ATS_TEST_Operation *o,
1162     struct Episode *e,
1163     int op_counter,
1164     char *sec_name,
1165     const struct GNUNET_CONFIGURATION_Handle *cfg)
1166 {
1167   char *op_name;
1168   char *type;
1169   char *prop;
1170
1171   /* peer id */
1172   GNUNET_asprintf(&op_name, "op-%u-peer-id", op_counter);
1173   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1174       sec_name, op_name, &o->peer_id))
1175   {
1176     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
1177         op_counter, "START_SET_PROPERTY", op_name);
1178     GNUNET_free (op_name);
1179     return GNUNET_SYSERR;
1180   }
1181   GNUNET_free (op_name);
1182
1183   /* address id */
1184   GNUNET_asprintf(&op_name, "op-%u-address-id", op_counter);
1185   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1186       sec_name, op_name, &o->address_id))
1187   {
1188     fprintf (stderr, "Missing address-id in operation %u `%s' in episode `%s'\n",
1189         op_counter, "START_SET_PROPERTY", op_name);
1190     GNUNET_free (op_name);
1191     return GNUNET_SYSERR;
1192   }
1193   GNUNET_free (op_name);
1194
1195   /* generator */
1196   GNUNET_asprintf(&op_name, "op-%u-gen-type", op_counter);
1197   if ( (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg,
1198           sec_name, op_name, &type)) )
1199   {
1200     fprintf (stderr, "Missing type in operation %u `%s' in episode `%s'\n",
1201         op_counter, "START_SET_PROPERTY", op_name);
1202     GNUNET_free (op_name);
1203     return GNUNET_SYSERR;
1204   }
1205
1206   /* Load arguments for set_rate, start_send, set_preference */
1207   if (0 == strcmp (type, "constant"))
1208   {
1209     o->gen_type = GNUNET_ATS_TEST_TG_CONSTANT;
1210   }
1211   else if (0 == strcmp (type, "linear"))
1212   {
1213     o->gen_type = GNUNET_ATS_TEST_TG_LINEAR;
1214   }
1215   else if (0 == strcmp (type, "sinus"))
1216   {
1217     o->gen_type = GNUNET_ATS_TEST_TG_SINUS;
1218   }
1219   else if (0 == strcmp (type, "random"))
1220   {
1221     o->gen_type = GNUNET_ATS_TEST_TG_RANDOM;
1222   }
1223   else
1224   {
1225     fprintf (stderr, "Invalid generator type %u `%s' in episode %u\n",
1226         op_counter, op_name, e->id);
1227     GNUNET_free (type);
1228     GNUNET_free (op_name);
1229     return GNUNET_SYSERR;
1230   }
1231   GNUNET_free (type);
1232   GNUNET_free (op_name);
1233
1234
1235   /* Get base rate */
1236   GNUNET_asprintf(&op_name, "op-%u-base-rate", op_counter);
1237   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1238       sec_name, op_name, &o->base_rate))
1239   {
1240     fprintf (stderr, "Missing base rate in operation %u `%s' in episode %u\n",
1241         op_counter, op_name, e->id);
1242     GNUNET_free (op_name);
1243     return GNUNET_SYSERR;
1244   }
1245   GNUNET_free (op_name);
1246
1247
1248   /* Get max rate */
1249   GNUNET_asprintf(&op_name, "op-%u-max-rate", op_counter);
1250   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1251       sec_name, op_name, &o->max_rate))
1252   {
1253     if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
1254         (GNUNET_ATS_TEST_TG_RANDOM == o->gen_type) ||
1255         (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
1256     {
1257       fprintf (stderr, "Missing max rate in operation %u `%s' in episode %u\n",
1258           op_counter, op_name, e->id);
1259       GNUNET_free (op_name);
1260       return GNUNET_SYSERR;
1261     }
1262   }
1263   GNUNET_free (op_name);
1264
1265   /* Get period */
1266   GNUNET_asprintf(&op_name, "op-%u-period", op_counter);
1267   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1268       sec_name, op_name, &o->period))
1269   {
1270     o->period = e->duration;
1271   }
1272   GNUNET_free (op_name);
1273
1274   /* Get frequency */
1275   GNUNET_asprintf(&op_name, "op-%u-frequency", op_counter);
1276   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1277       sec_name, op_name, &o->frequency))
1278   {
1279       fprintf (stderr, "Missing frequency in operation %u `%s' in episode %u\n",
1280           op_counter, op_name, e->id);
1281       GNUNET_free (op_name);
1282       return GNUNET_SYSERR;
1283   }
1284   GNUNET_free (op_name);
1285
1286   /* Get preference */
1287   GNUNET_asprintf(&op_name, "op-%u-property", op_counter);
1288   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1289       sec_name, op_name, &prop))
1290   {
1291       fprintf (stderr, "Missing property in operation %u `%s' in episode %u\n",
1292           op_counter, op_name, e->id);
1293       GNUNET_free (op_name);
1294       GNUNET_free_non_null (prop);
1295       return GNUNET_SYSERR;
1296   }
1297
1298   if (0 == (o->prop_type = parse_property_string(prop)))
1299   {
1300       fprintf (stderr, "Invalid property in operation %u `%s' in episode %u\n",
1301           op_counter, op_name, e->id);
1302       GNUNET_free (op_name);
1303       GNUNET_free (prop);
1304       return GNUNET_SYSERR;
1305   }
1306
1307   GNUNET_free (prop);
1308   GNUNET_free (op_name);
1309
1310   fprintf (stderr,
1311       "Found operation %s: [%llu:%llu] %s = %llu\n",
1312       "START_SET_PROPERTY", o->peer_id, o->address_id,
1313       GNUNET_ATS_print_property_type (o->prop_type), o->base_rate);
1314
1315   return GNUNET_OK;
1316 }
1317
1318 static int
1319 load_op_stop_set_property (struct GNUNET_ATS_TEST_Operation *o,
1320     struct Episode *e,
1321     int op_counter,
1322     char *sec_name,
1323     const struct GNUNET_CONFIGURATION_Handle *cfg)
1324 {
1325   char *op_name;
1326   char *pref;
1327
1328   /* peer id */
1329   GNUNET_asprintf(&op_name, "op-%u-peer-id", op_counter);
1330   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1331       sec_name, op_name, &o->peer_id))
1332   {
1333     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
1334         op_counter, "STOP_SET_PROPERTY", op_name);
1335     GNUNET_free (op_name);
1336     return GNUNET_SYSERR;
1337   }
1338   GNUNET_free (op_name);
1339
1340   /* address id */
1341   GNUNET_asprintf(&op_name, "op-%u-address-id", op_counter);
1342   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1343       sec_name, op_name, &o->address_id))
1344   {
1345     fprintf (stderr, "Missing address-id in operation %u `%s' in episode `%s'\n",
1346         op_counter, "STOP_SET_PROPERTY", op_name);
1347     GNUNET_free (op_name);
1348     return GNUNET_SYSERR;
1349   }
1350   GNUNET_free (op_name);
1351
1352   /* Get property */
1353   GNUNET_asprintf(&op_name, "op-%u-property", op_counter);
1354   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1355       sec_name, op_name, &pref))
1356   {
1357     fprintf (stderr, "Missing property in operation %u `%s' in episode `%s'\n",
1358         op_counter, "STOP_SET_PROPERTY", op_name);
1359       GNUNET_free (op_name);
1360       GNUNET_free_non_null (pref);
1361       return GNUNET_SYSERR;
1362   }
1363
1364   if (0 == (o->prop_type = parse_property_string(pref)))
1365   {
1366       fprintf (stderr, "Invalid property in operation %u `%s' in episode %u\n",
1367           op_counter, op_name, e->id);
1368       GNUNET_free (op_name);
1369       GNUNET_free (pref);
1370       GNUNET_free_non_null (pref);
1371       return GNUNET_SYSERR;
1372   }
1373
1374   GNUNET_free (pref);
1375   GNUNET_free (op_name);
1376
1377   fprintf (stderr,
1378       "Found operation %s: [%llu:%llu] %s\n",
1379       "STOP_SET_PROPERTY", o->peer_id, o->address_id,
1380       GNUNET_ATS_print_property_type (o->prop_type));
1381
1382   return GNUNET_OK;
1383 }
1384
1385
1386 static int
1387 load_op_start_request (struct GNUNET_ATS_TEST_Operation *o,
1388     struct Episode *e,
1389     int op_counter,
1390     char *sec_name,
1391     const struct GNUNET_CONFIGURATION_Handle *cfg)
1392 {
1393   char *op_name;
1394
1395   /* peer id */
1396   GNUNET_asprintf(&op_name, "op-%u-peer-id", op_counter);
1397   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1398       sec_name, op_name, &o->peer_id))
1399   {
1400     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
1401         op_counter, "START_REQUEST", op_name);
1402     GNUNET_free (op_name);
1403     return GNUNET_SYSERR;
1404   }
1405   GNUNET_free (op_name);
1406   return GNUNET_OK;
1407 }
1408
1409 static int
1410 load_op_stop_request (struct GNUNET_ATS_TEST_Operation *o,
1411     struct Episode *e,
1412     int op_counter,
1413     char *sec_name,
1414     const struct GNUNET_CONFIGURATION_Handle *cfg)
1415 {
1416   char *op_name;
1417
1418   /* peer id */
1419   GNUNET_asprintf(&op_name, "op-%u-peer-id", op_counter);
1420   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1421       sec_name, op_name, &o->peer_id))
1422   {
1423     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
1424         op_counter, "STOP_REQUEST", op_name);
1425     GNUNET_free (op_name);
1426     return GNUNET_SYSERR;
1427   }
1428   GNUNET_free (op_name);
1429   return GNUNET_OK;
1430 }
1431
1432
1433 static int
1434 load_episode (struct Experiment *e, struct Episode *cur,
1435     struct GNUNET_CONFIGURATION_Handle *cfg)
1436 {
1437   struct GNUNET_ATS_TEST_Operation *o;
1438   char *sec_name;
1439   char *op_name;
1440   char *op;
1441   int op_counter = 0;
1442   int res;
1443   fprintf (stderr, "Parsing episode %u\n",cur->id);
1444   GNUNET_asprintf(&sec_name, "episode-%u", cur->id);
1445
1446   while (1)
1447   {
1448     /* Load operation */
1449     GNUNET_asprintf(&op_name, "op-%u-operation", op_counter);
1450     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg,
1451         sec_name, op_name, &op))
1452     {
1453       GNUNET_free (op_name);
1454       break;
1455     }
1456     o = GNUNET_new (struct GNUNET_ATS_TEST_Operation);
1457     /* operations = set_rate, start_send, stop_send, set_preference */
1458     if (0 == strcmp (op, "address_add"))
1459     {
1460       o->type = SOLVER_OP_ADD_ADDRESS;
1461       res = load_op_add_address (o, cur,
1462           op_counter, sec_name, cfg);
1463     }
1464     else if (0 == strcmp (op, "address_del"))
1465     {
1466       o->type = SOLVER_OP_DEL_ADDRESS;
1467       res = load_op_del_address (o, cur,
1468           op_counter, sec_name, cfg);
1469     }
1470     else if (0 == strcmp (op, "start_set_property"))
1471     {
1472       o->type = SOLVER_OP_START_SET_PROPERTY;
1473       res = load_op_start_set_property (o, cur,
1474           op_counter, sec_name, cfg);
1475     }
1476     else if (0 == strcmp (op, "stop_set_property"))
1477     {
1478       o->type = SOLVER_OP_STOP_SET_PROPERTY;
1479       res = load_op_stop_set_property (o, cur,
1480           op_counter, sec_name, cfg);
1481     }
1482     else if (0 == strcmp (op, "start_set_preference"))
1483     {
1484       o->type = SOLVER_OP_START_SET_PREFERENCE;
1485       res =  load_op_start_set_preference (o, cur,
1486           op_counter, sec_name, cfg);
1487         break;
1488     }
1489     else if (0 == strcmp (op, "stop_set_preference"))
1490     {
1491       o->type = SOLVER_OP_STOP_SET_PREFERENCE;
1492       res =  load_op_stop_set_preference (o, cur,
1493           op_counter, sec_name, cfg);
1494     }
1495     else if (0 == strcmp (op, "start_request"))
1496     {
1497       o->type = SOLVER_OP_START_REQUEST;
1498       res = load_op_start_request (o, cur,
1499           op_counter, sec_name, cfg);
1500     }
1501     else if (0 == strcmp (op, "stop_request"))
1502     {
1503       o->type = SOLVER_OP_STOP_REQUEST;
1504       res = load_op_stop_request(o, cur,
1505           op_counter, sec_name, cfg);
1506     }
1507     else
1508     {
1509       fprintf (stderr, "Invalid operation %u `%s' in episode %u\n",
1510           op_counter, op, cur->id);
1511       res = GNUNET_SYSERR;
1512     }
1513
1514     GNUNET_free (op);
1515     GNUNET_free (op_name);
1516
1517     if (GNUNET_SYSERR == res)
1518     {
1519       GNUNET_free (o);
1520       GNUNET_free (sec_name);
1521       return GNUNET_SYSERR;
1522     }
1523
1524     GNUNET_CONTAINER_DLL_insert_tail (cur->head,cur->tail, o);
1525     op_counter++;
1526   }
1527   GNUNET_free (sec_name);
1528   return GNUNET_OK;
1529 }
1530
1531 static int
1532 load_episodes (struct Experiment *e, struct GNUNET_CONFIGURATION_Handle *cfg)
1533 {
1534   int e_counter = 0;
1535   char *sec_name;
1536   struct GNUNET_TIME_Relative e_duration;
1537   struct Episode *cur;
1538   struct Episode *last;
1539
1540   e_counter = 0;
1541   last = NULL;
1542   while (1)
1543   {
1544     GNUNET_asprintf(&sec_name, "episode-%u", e_counter);
1545     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg,
1546         sec_name, "duration", &e_duration))
1547     {
1548       GNUNET_free (sec_name);
1549       break;
1550     }
1551
1552     cur = GNUNET_new (struct Episode);
1553     cur->duration = e_duration;
1554     cur->id = e_counter;
1555
1556     if (GNUNET_OK != load_episode (e, cur, cfg))
1557     {
1558       GNUNET_free (sec_name);
1559       GNUNET_free (cur);
1560       return GNUNET_SYSERR;
1561     }
1562
1563     fprintf (stderr, "Found episode %u with duration %s \n",
1564         e_counter,
1565         GNUNET_STRINGS_relative_time_to_string(cur->duration, GNUNET_YES));
1566
1567     /* Update experiment */
1568     e->num_episodes ++;
1569     e->total_duration = GNUNET_TIME_relative_add(e->total_duration, cur->duration);
1570     /* Put in linked list */
1571     if (NULL == last)
1572       e->start = cur;
1573     else
1574     last->next = cur;
1575
1576     GNUNET_free (sec_name);
1577     e_counter ++;
1578     last = cur;
1579   }
1580   return e_counter;
1581 }
1582
1583 static void
1584 timeout_experiment (void *cls, const struct GNUNET_SCHEDULER_TaskContext* tc)
1585 {
1586   struct Experiment *e = cls;
1587   e->experiment_timeout_task = GNUNET_SCHEDULER_NO_TASK;
1588   fprintf (stderr, "Experiment timeout!\n");
1589
1590   if (GNUNET_SCHEDULER_NO_TASK != e->episode_timeout_task)
1591   {
1592     GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
1593     e->episode_timeout_task = GNUNET_SCHEDULER_NO_TASK;
1594   }
1595
1596   e->e_done_cb (e, GNUNET_TIME_absolute_get_duration(e->start_time),
1597       GNUNET_SYSERR);
1598 }
1599
1600 struct ATS_Address *
1601 create_ats_address (const struct GNUNET_PeerIdentity *peer,
1602                 const char *plugin_name,
1603                 const void *plugin_addr, size_t plugin_addr_len,
1604                 uint32_t session_id)
1605 {
1606   struct ATS_Address *aa = NULL;
1607
1608   aa = GNUNET_malloc (sizeof (struct ATS_Address) + plugin_addr_len + strlen (plugin_name) + 1);
1609   aa->peer = *peer;
1610   aa->addr_len = plugin_addr_len;
1611   aa->addr = &aa[1];
1612   aa->plugin = (char *) &aa[1] + plugin_addr_len;
1613   memcpy (&aa[1], plugin_addr, plugin_addr_len);
1614   memcpy (aa->plugin, plugin_name, strlen (plugin_name) + 1);
1615   aa->session_id = session_id;
1616   aa->active = GNUNET_NO;
1617   aa->used = GNUNET_NO;
1618   aa->solver_information = NULL;
1619   aa->assigned_bw_in = GNUNET_BANDWIDTH_value_init(0);
1620   aa->assigned_bw_out = GNUNET_BANDWIDTH_value_init(0);
1621   return aa;
1622 }
1623
1624
1625
1626 static void
1627 enforce_add_address (struct GNUNET_ATS_TEST_Operation *op)
1628 {
1629   struct TestPeer *p;
1630   struct TestAddress *a;
1631
1632   if (NULL == (p = find_peer_by_id (op->peer_id)))
1633   {
1634     p = GNUNET_new (struct TestPeer);
1635     p->id = op->peer_id;
1636     memset (&p->peer_id, op->peer_id, sizeof (p->peer_id));
1637     GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, p);
1638   }
1639
1640   if (NULL != (a = find_address_by_id (p, op->address_id)))
1641   {
1642     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Duplicate address %u for peer %u\n",
1643         op->address_id, op->peer_id);
1644   }
1645
1646   a = GNUNET_new (struct TestAddress);
1647   a->aid = op->address_id;
1648   a->ats_addr = create_ats_address (&p->peer_id, op->plugin, op->address,
1649       strlen (op->address) + 1, op->address_session);
1650   memset (&p->peer_id, op->peer_id, sizeof (p->peer_id));
1651   GNUNET_CONTAINER_DLL_insert (p->addr_head, p->addr_tail, a);
1652
1653   GNUNET_CONTAINER_multipeermap_put (sh->addresses, &p->peer_id, a->ats_addr,
1654     GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1655
1656   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Adding address %u for peer %u\n",
1657     op->address_id, op->peer_id);
1658
1659   sh->env.sf.s_add (sh->solver, a->ats_addr, op->address_network);
1660
1661 }
1662
1663
1664 static void
1665 enforce_del_address (struct GNUNET_ATS_TEST_Operation *op)
1666 {
1667   struct TestPeer *p;
1668   struct TestAddress *a;
1669   struct AddressLookupCtx ctx;
1670
1671   if (NULL == (p = find_peer_by_id (op->peer_id)))
1672   {
1673     GNUNET_break (0);
1674     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1675         "Deleting address for unknown peer %u\n", op->peer_id);
1676     return;
1677   }
1678
1679   ctx.plugin = op->plugin;
1680   ctx.addr = op->address;
1681   ctx.res = NULL;
1682   GNUNET_CONTAINER_multipeermap_get_multiple (sh->addresses, &p->peer_id,
1683       find_address_it, &ctx);
1684   if (NULL == ctx.res)
1685   {
1686     GNUNET_break (0);
1687     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1688         "Deleting unknown address for peer %u\n", op->peer_id);
1689     return;
1690   }
1691
1692   if (NULL == (a = find_address_by_id (p, op->address_id)))
1693   {
1694     GNUNET_break (0);
1695     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1696         "Deleting address for unknown peer %u\n", op->peer_id);
1697     return;
1698   }
1699   GNUNET_CONTAINER_DLL_remove (p->addr_head, p->addr_tail, a);
1700
1701   GNUNET_CONTAINER_multipeermap_remove (sh->addresses, &p->peer_id, ctx.res);
1702
1703   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Removing address %u for peer %u\n",
1704       op->address_id, op->peer_id);
1705
1706   sh->env.sf.s_del (sh->solver, ctx.res, GNUNET_NO);
1707   GNUNET_free (ctx.res);
1708
1709 }
1710
1711 static void
1712 enforce_start_property (struct GNUNET_ATS_TEST_Operation *op)
1713 {
1714   struct PropertyGenerator *pg;
1715   struct TestPeer *p;
1716   struct TestAddress *a;
1717
1718   if (NULL != (pg = find_prop_gen (op->peer_id, op->address_id, op->prop_type)))
1719   {
1720     GNUNET_ATS_solver_generate_property_stop (pg);
1721     GNUNET_free (pg);
1722   }
1723
1724   if (NULL == (p = find_peer_by_id (op->peer_id)))
1725   {
1726     GNUNET_break (0);
1727     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1728         "Starting property generation for unknown peer %u\n", op->peer_id);
1729     return;
1730   }
1731
1732   if (NULL == (a = find_address_by_id (p, op->address_id)))
1733   {
1734     GNUNET_break (0);
1735     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1736         "Setting proprterty for unknown address %u\n", op->peer_id);
1737     return;
1738   }
1739
1740   GNUNET_ATS_solver_generate_property_start (op->peer_id,
1741     op->address_id,
1742     p, a,
1743     op->gen_type,
1744     op->base_rate,
1745     op->max_rate,
1746     op->period,
1747     op->frequency,
1748     op->prop_type);
1749 }
1750
1751 static void
1752 enforce_stop_property (struct GNUNET_ATS_TEST_Operation *op)
1753 {
1754   struct PropertyGenerator *pg = find_prop_gen(op->peer_id, op->address_id,
1755       op->prop_type);
1756   if (NULL != pg)
1757       GNUNET_ATS_solver_generate_property_stop (pg);
1758 }
1759
1760 static void
1761 enforce_start_preference (struct GNUNET_ATS_TEST_Operation *op)
1762 {
1763   struct PreferenceGenerator *pg;
1764   if (NULL != (pg = find_pref_gen (op->peer_id, op->address_id, op->pref_type)))
1765   {
1766     GNUNET_ATS_solver_generate_preferences_stop (pg);
1767     GNUNET_free (pg);
1768   }
1769
1770   GNUNET_ATS_solver_generate_preferences_start (op->peer_id,
1771     op->address_id,
1772     op->gen_type,
1773     op->base_rate,
1774     op->max_rate,
1775     op->period,
1776     op->frequency,
1777     op->pref_type);
1778 }
1779
1780 static void
1781 enforce_stop_preference (struct GNUNET_ATS_TEST_Operation *op)
1782 {
1783   struct PreferenceGenerator *pg = find_pref_gen(op->peer_id, op->address_id,
1784       op->pref_type);
1785   if (NULL != pg)
1786       GNUNET_ATS_solver_generate_preferences_stop (pg);
1787 }
1788
1789
1790 static void
1791 enforce_start_request (struct GNUNET_ATS_TEST_Operation *op)
1792 {
1793   struct TestPeer *p;
1794   const struct ATS_Address *res;
1795
1796   if (NULL == (p = find_peer_by_id (op->peer_id)))
1797   {
1798     GNUNET_break (0);
1799     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1800         "Requesting address for unknown peer %u\n", op->peer_id);
1801     return;
1802   }
1803
1804   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Requesting address for peer %u\n",
1805       op->peer_id);
1806
1807   res = sh->env.sf.s_get (sh->solver, &p->peer_id);
1808   if (NULL != res)
1809   {
1810
1811   }
1812
1813 }
1814
1815 static void
1816 enforce_stop_request (struct GNUNET_ATS_TEST_Operation *op)
1817 {
1818   struct TestPeer *p;
1819
1820   if (NULL == (p = find_peer_by_id (op->peer_id)))
1821   {
1822     GNUNET_break (0);
1823     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1824         "Requesting address for unknown peer %u\n", op->peer_id);
1825     return;
1826   }
1827
1828   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stop requesting address for peer %u\n",
1829       op->peer_id);
1830
1831   sh->env.sf.s_get_stop (sh->solver, &p->peer_id);
1832 }
1833
1834 static void enforce_episode (struct Episode *ep)
1835 {
1836   struct GNUNET_ATS_TEST_Operation *cur;
1837   for (cur = ep->head; NULL != cur; cur = cur->next)
1838   {
1839     switch (cur->type) {
1840       case SOLVER_OP_ADD_ADDRESS:
1841         fprintf (stderr, "Enforcing operation: %s [%llu:%llu]\n",
1842             print_op (cur->type), cur->peer_id, cur->address_id);
1843         enforce_add_address (cur);
1844         break;
1845       case SOLVER_OP_DEL_ADDRESS:
1846         fprintf (stderr, "Enforcing operation: %s [%llu:%llu]\n",
1847             print_op (cur->type), cur->peer_id, cur->address_id);
1848         enforce_del_address (cur);
1849         break;
1850       case SOLVER_OP_START_SET_PROPERTY:
1851         fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
1852             print_op (cur->type), cur->peer_id, cur->address_id, cur->base_rate);
1853         enforce_start_property (cur);
1854         break;
1855       case SOLVER_OP_STOP_SET_PROPERTY:
1856         fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
1857             print_op (cur->type), cur->peer_id, cur->address_id, cur->base_rate);
1858         enforce_stop_property (cur);
1859         break;
1860       case SOLVER_OP_START_SET_PREFERENCE:
1861         fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
1862             print_op (cur->type), cur->peer_id, cur->address_id, cur->base_rate);
1863         enforce_start_preference (cur);
1864         break;
1865       case SOLVER_OP_STOP_SET_PREFERENCE:
1866         fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
1867             print_op (cur->type), cur->peer_id, cur->address_id, cur->base_rate);
1868         enforce_stop_preference (cur);
1869         break;
1870       case SOLVER_OP_START_REQUEST:
1871         fprintf (stderr, "Enforcing operation: %s [%llu]\n",
1872             print_op (cur->type), cur->peer_id);
1873         enforce_start_request (cur);
1874         break;
1875       case SOLVER_OP_STOP_REQUEST:
1876         fprintf (stderr, "Enforcing operation: %s [%llu]\n",
1877             print_op (cur->type), cur->peer_id);
1878         enforce_stop_request (cur);
1879         break;
1880       default:
1881         break;
1882     }
1883   }
1884 }
1885
1886 static void
1887 timeout_episode (void *cls, const struct GNUNET_SCHEDULER_TaskContext* tc)
1888 {
1889   struct Experiment *e = cls;
1890   e->episode_timeout_task = GNUNET_SCHEDULER_NO_TASK;
1891   if (NULL != e->ep_done_cb)
1892     e->ep_done_cb (e->cur);
1893
1894   /* Scheduling next */
1895   e->cur = e->cur->next;
1896   if (NULL == e->cur)
1897   {
1898     /* done */
1899     fprintf (stderr, "Last episode done!\n");
1900     if (GNUNET_SCHEDULER_NO_TASK != e->experiment_timeout_task)
1901     {
1902       GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
1903       e->experiment_timeout_task = GNUNET_SCHEDULER_NO_TASK;
1904     }
1905     e->e_done_cb (e, GNUNET_TIME_absolute_get_duration(e->start_time), GNUNET_OK);
1906     return;
1907   }
1908
1909   fprintf (stderr, "Running episode %u with timeout %s\n",
1910       e->cur->id,
1911       GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
1912   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
1913       &timeout_episode, e);
1914   enforce_episode(e->cur);
1915
1916
1917 }
1918
1919
1920 void
1921 GNUNET_ATS_solvers_experimentation_run (struct Experiment *e,
1922     GNUNET_ATS_TESTING_EpisodeDoneCallback ep_done_cb,
1923     GNUNET_ATS_TESTING_ExperimentDoneCallback e_done_cb)
1924 {
1925   fprintf (stderr, "Running experiment `%s'  with timeout %s\n", e->name,
1926       GNUNET_STRINGS_relative_time_to_string(e->max_duration, GNUNET_YES));
1927   e->e_done_cb = e_done_cb;
1928   e->ep_done_cb = ep_done_cb;
1929   e->start_time = GNUNET_TIME_absolute_get();
1930
1931   /* Start total time out */
1932   e->experiment_timeout_task = GNUNET_SCHEDULER_add_delayed (e->max_duration,
1933       &timeout_experiment, e);
1934
1935
1936   /* Start */
1937   if (NULL == e->start)
1938   {
1939     GNUNET_break (0);
1940     return;
1941   }
1942   e->cur = e->start;
1943   fprintf (stderr, "Running episode %u with timeout %s\n",
1944       e->cur->id,
1945       GNUNET_STRINGS_relative_time_to_string(e->cur->duration, GNUNET_YES));
1946   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
1947       &timeout_episode, e);
1948   enforce_episode(e->cur);
1949
1950 }
1951
1952 void
1953 GNUNET_ATS_solvers_experimentation_stop (struct Experiment *e)
1954 {
1955   if (GNUNET_SCHEDULER_NO_TASK != e->experiment_timeout_task)
1956   {
1957     GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
1958     e->experiment_timeout_task = GNUNET_SCHEDULER_NO_TASK;
1959   }
1960   if (GNUNET_SCHEDULER_NO_TASK != e->episode_timeout_task)
1961   {
1962     GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
1963     e->episode_timeout_task = GNUNET_SCHEDULER_NO_TASK;
1964   }
1965   if (NULL != e->cfg)
1966   {
1967     GNUNET_CONFIGURATION_destroy(e->cfg);
1968     e->cfg = NULL;
1969   }
1970   free_experiment (e);
1971 }
1972
1973
1974 struct Experiment *
1975 GNUNET_ATS_solvers_experimentation_load (char *filename)
1976 {
1977   struct Experiment *e;
1978   struct GNUNET_CONFIGURATION_Handle *cfg;
1979   e = NULL;
1980
1981   cfg = GNUNET_CONFIGURATION_create();
1982   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, filename))
1983   {
1984     fprintf (stderr, "Failed to load `%s'\n", filename);
1985     GNUNET_CONFIGURATION_destroy (cfg);
1986     return NULL;
1987   }
1988
1989   e = create_experiment ();
1990
1991   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string(cfg, "experiment",
1992       "name", &e->name))
1993   {
1994     fprintf (stderr, "Invalid %s", "name");
1995     free_experiment (e);
1996     return NULL;
1997   }
1998   else
1999     fprintf (stderr, "Experiment name: `%s'\n", e->name);
2000
2001   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg, "experiment",
2002       "cfg_file", &e->cfg_file))
2003   {
2004     fprintf (stderr, "Invalid %s", "cfg_file");
2005     free_experiment (e);
2006     return NULL;
2007   }
2008   else
2009   {
2010     fprintf (stderr, "Experiment configuration: `%s'\n", e->cfg_file);
2011     e->cfg = GNUNET_CONFIGURATION_create();
2012     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (e->cfg, e->cfg_file))
2013     {
2014       fprintf (stderr, "Invalid configuration %s", "cfg_file");
2015       free_experiment (e);
2016       return NULL;
2017     }
2018
2019   }
2020
2021   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
2022       "masters", &e->num_masters))
2023   {
2024     fprintf (stderr, "Invalid %s", "masters");
2025     free_experiment (e);
2026     return NULL;
2027   }
2028   else
2029     fprintf (stderr, "Experiment masters: `%llu'\n",
2030         e->num_masters);
2031
2032   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number(cfg, "experiment",
2033       "slaves", &e->num_slaves))
2034   {
2035     fprintf (stderr, "Invalid %s", "slaves");
2036     free_experiment (e);
2037     return NULL;
2038   }
2039   else
2040     fprintf (stderr, "Experiment slaves: `%llu'\n",
2041         e->num_slaves);
2042
2043   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg, "experiment",
2044       "log_freq", &e->log_freq))
2045   {
2046     fprintf (stderr, "Invalid %s", "log_freq");
2047     free_experiment (e);
2048     return NULL;
2049   }
2050   else
2051     fprintf (stderr, "Experiment logging frequency: `%s'\n",
2052         GNUNET_STRINGS_relative_time_to_string (e->log_freq, GNUNET_YES));
2053
2054   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time(cfg, "experiment",
2055       "max_duration", &e->max_duration))
2056   {
2057     fprintf (stderr, "Invalid %s", "max_duration");
2058     free_experiment (e);
2059     return NULL;
2060   }
2061   else
2062     fprintf (stderr, "Experiment duration: `%s'\n",
2063         GNUNET_STRINGS_relative_time_to_string (e->max_duration, GNUNET_YES));
2064
2065   if (GNUNET_SYSERR == load_episodes (e, cfg))
2066   {
2067     GNUNET_ATS_solvers_experimentation_stop (e);
2068     GNUNET_CONFIGURATION_destroy (cfg);
2069     e = NULL;
2070     fprintf (stderr, "Failed to load experiment\n");
2071     return NULL;
2072   }
2073   fprintf (stderr, "Loaded %u episodes with total duration %s\n",
2074       e->num_episodes,
2075       GNUNET_STRINGS_relative_time_to_string (e->total_duration, GNUNET_YES));
2076
2077   GNUNET_CONFIGURATION_destroy (cfg);
2078   return e;
2079 }
2080
2081 /**
2082  * Solver
2083  */
2084
2085 void
2086 GNUNET_ATS_solvers_solver_stop (struct SolverHandle *sh)
2087 {
2088  GNUNET_STATISTICS_destroy ((struct GNUNET_STATISTICS_Handle *) sh->env.stats,
2089      GNUNET_NO);
2090  GNUNET_PLUGIN_unload (sh->plugin, sh->solver);
2091  GNUNET_CONTAINER_multipeermap_destroy(sh->addresses);
2092  GNUNET_free (sh->plugin);
2093  GNUNET_free (sh);
2094 }
2095
2096 /**
2097  * Load quotas for networks from configuration
2098  *
2099  * @param cfg configuration handle
2100  * @param out_dest where to write outbound quotas
2101  * @param in_dest where to write inbound quotas
2102  * @param dest_length length of inbound and outbound arrays
2103  * @return number of networks loaded
2104  */
2105 unsigned int
2106 GNUNET_ATS_solvers_load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
2107                                                  unsigned long long *out_dest,
2108                                                  unsigned long long *in_dest,
2109                                                  int dest_length)
2110 {
2111   char *network_str[GNUNET_ATS_NetworkTypeCount] = GNUNET_ATS_NetworkTypeString;
2112   char * entry_in = NULL;
2113   char * entry_out = NULL;
2114   char * quota_out_str;
2115   char * quota_in_str;
2116   int c;
2117   int res;
2118
2119   for (c = 0; (c < GNUNET_ATS_NetworkTypeCount) && (c < dest_length); c++)
2120   {
2121     in_dest[c] = 0;
2122     out_dest[c] = 0;
2123     GNUNET_asprintf (&entry_out, "%s_QUOTA_OUT", network_str[c]);
2124     GNUNET_asprintf (&entry_in, "%s_QUOTA_IN", network_str[c]);
2125
2126     /* quota out */
2127     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_out, &quota_out_str))
2128     {
2129       res = GNUNET_NO;
2130       if (0 == strcmp(quota_out_str, BIG_M_STRING))
2131       {
2132         out_dest[c] = GNUNET_ATS_MaxBandwidth;
2133         res = GNUNET_YES;
2134       }
2135       if ((GNUNET_NO == res) && (GNUNET_OK == GNUNET_STRINGS_fancy_size_to_bytes (quota_out_str, &out_dest[c])))
2136         res = GNUNET_YES;
2137       if ((GNUNET_NO == res) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_out,  &out_dest[c])))
2138          res = GNUNET_YES;
2139
2140       if (GNUNET_NO == res)
2141       {
2142           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
2143               network_str[c], quota_out_str, GNUNET_ATS_DefaultBandwidth);
2144           out_dest[c] = GNUNET_ATS_DefaultBandwidth;
2145       }
2146       else
2147       {
2148           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Outbound quota configure for network `%s' is %llu\n"),
2149               network_str[c], out_dest[c]);
2150       }
2151       GNUNET_free (quota_out_str);
2152     }
2153     else
2154     {
2155       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("No outbound quota configured for network `%s', assigning default bandwidth %llu\n"),
2156           network_str[c], GNUNET_ATS_DefaultBandwidth);
2157       out_dest[c] = GNUNET_ATS_DefaultBandwidth;
2158     }
2159
2160     /* quota in */
2161     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(cfg, "ats", entry_in, &quota_in_str))
2162     {
2163       res = GNUNET_NO;
2164       if (0 == strcmp(quota_in_str, BIG_M_STRING))
2165       {
2166         in_dest[c] = GNUNET_ATS_MaxBandwidth;
2167         res = GNUNET_YES;
2168       }
2169       if ((GNUNET_NO == res) && (GNUNET_OK == GNUNET_STRINGS_fancy_size_to_bytes (quota_in_str, &in_dest[c])))
2170         res = GNUNET_YES;
2171       if ((GNUNET_NO == res) && (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (cfg, "ats", entry_in,  &in_dest[c])))
2172          res = GNUNET_YES;
2173
2174       if (GNUNET_NO == res)
2175       {
2176           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
2177               network_str[c], quota_in_str, GNUNET_ATS_DefaultBandwidth);
2178           in_dest[c] = GNUNET_ATS_DefaultBandwidth;
2179       }
2180       else
2181       {
2182           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Inbound quota configured for network `%s' is %llu\n"),
2183               network_str[c], in_dest[c]);
2184       }
2185       GNUNET_free (quota_in_str);
2186     }
2187     else
2188     {
2189       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("No outbound quota configure for network `%s', assigning default bandwidth %llu\n"),
2190           network_str[c], GNUNET_ATS_DefaultBandwidth);
2191       out_dest[c] = GNUNET_ATS_DefaultBandwidth;
2192     }
2193     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loaded quota for network `%s' (in/out): %llu %llu\n", network_str[c], in_dest[c], out_dest[c]);
2194     GNUNET_free (entry_out);
2195     GNUNET_free (entry_in);
2196   }
2197   return GNUNET_ATS_NetworkTypeCount;
2198 }
2199
2200 /**
2201  * Information callback for the solver
2202  *
2203  * @param op the solver operation
2204  * @param stat status of the solver operation
2205  * @param add additional solver information
2206  */
2207 static void
2208 solver_info_cb (void *cls,
2209     enum GAS_Solver_Operation op,
2210     enum GAS_Solver_Status stat,
2211     enum GAS_Solver_Additional_Information add)
2212 {
2213   char *add_info;
2214   switch (add) {
2215     case GAS_INFO_NONE:
2216       add_info = "GAS_INFO_NONE";
2217       break;
2218     case GAS_INFO_FULL:
2219       add_info = "GAS_INFO_MLP_FULL";
2220       break;
2221     case GAS_INFO_UPDATED:
2222       add_info = "GAS_INFO_MLP_UPDATED";
2223       break;
2224     case GAS_INFO_PROP_ALL:
2225       add_info = "GAS_INFO_PROP_ALL";
2226       break;
2227     case GAS_INFO_PROP_SINGLE:
2228       add_info = "GAS_INFO_PROP_SINGLE";
2229       break;
2230     default:
2231       add_info = "INVALID";
2232       break;
2233   }
2234
2235   switch (op)
2236   {
2237     case GAS_OP_SOLVE_START:
2238       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2239           "Solver notifies `%s' with result `%s' `%s'\n", "GAS_OP_SOLVE_START",
2240           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
2241       return;
2242     case GAS_OP_SOLVE_STOP:
2243       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2244           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
2245           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
2246       return;
2247
2248     case GAS_OP_SOLVE_SETUP_START:
2249       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2250           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_START",
2251           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
2252       return;
2253
2254     case GAS_OP_SOLVE_SETUP_STOP:
2255       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2256           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_SETUP_STOP",
2257           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
2258       return;
2259
2260     case GAS_OP_SOLVE_MLP_LP_START:
2261       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2262           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_START",
2263           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
2264       return;
2265     case GAS_OP_SOLVE_MLP_LP_STOP:
2266       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2267           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_LP_STOP",
2268           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
2269       return;
2270
2271     case GAS_OP_SOLVE_MLP_MLP_START:
2272       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2273           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_START",
2274           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
2275       return;
2276     case GAS_OP_SOLVE_MLP_MLP_STOP:
2277       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2278           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_MLP_STOP",
2279           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
2280       return;
2281     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
2282       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2283           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
2284           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
2285       return;
2286     case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
2287       GNUNET_log(GNUNET_ERROR_TYPE_INFO,
2288           "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
2289           (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
2290       return;
2291     default:
2292       break;
2293     }
2294 }
2295
2296 static void
2297 solver_bandwidth_changed_cb (void *cls, struct ATS_Address *address)
2298 {
2299   if ( (0 == ntohl (address->assigned_bw_out.value__)) &&
2300        (0 == ntohl (address->assigned_bw_in.value__)) )
2301   {
2302     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2303                 "Solver notified to disconnect peer `%s'\n",
2304                 GNUNET_i2s (&address->peer));
2305     return;
2306   }
2307
2308   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2309               "Bandwidth changed addresses %s %p to %u Bps out / %u Bps in\n",
2310               GNUNET_i2s (&address->peer),
2311               address,
2312               (unsigned int) ntohl (address->assigned_bw_out.value__),
2313               (unsigned int) ntohl (address->assigned_bw_in.value__));
2314   /*if (GNUNET_YES == ph.bulk_running)
2315     GNUNET_break (0);*/
2316   return;
2317 }
2318
2319 const double *
2320 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
2321 {
2322   return GAS_normalization_get_preferences_by_peer (id);
2323 }
2324
2325
2326 const double *
2327 get_property_cb (void *cls, const struct ATS_Address *address)
2328 {
2329   return GAS_normalization_get_properties ((struct ATS_Address *) address);
2330 }
2331
2332 static void
2333 normalized_property_changed_cb (void *cls, struct ATS_Address *peer,
2334     uint32_t type, double prop_rel)
2335 {
2336   /* TODO */
2337 }
2338
2339
2340 struct SolverHandle *
2341 GNUNET_ATS_solvers_solver_start (enum GNUNET_ATS_Solvers type)
2342 {
2343   struct SolverHandle *sh;
2344   char * solver_str;
2345
2346   switch (type) {
2347     case GNUNET_ATS_SOLVER_PROPORTIONAL:
2348       solver_str = "proportional";
2349       break;
2350     case GNUNET_ATS_SOLVER_MLP:
2351       solver_str = "mlp";
2352       break;
2353     case GNUNET_ATS_SOLVER_RIL:
2354       solver_str = "ril";
2355       break;
2356     default:
2357       GNUNET_break (0);
2358       return NULL;
2359       break;
2360   }
2361
2362   sh = GNUNET_new (struct SolverHandle);
2363   GNUNET_asprintf (&sh->plugin, "libgnunet_plugin_ats_%s", solver_str);
2364
2365   sh->addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
2366   /* setup environment */
2367   sh->env.cfg = e->cfg;
2368   sh->env.stats = GNUNET_STATISTICS_create ("ats", e->cfg);
2369   sh->env.addresses = sh->addresses;
2370   sh->env.bandwidth_changed_cb = &solver_bandwidth_changed_cb;
2371   sh->env.get_preferences = &get_preferences_cb;
2372   sh->env.get_property = &get_property_cb;
2373   sh->env.network_count = GNUNET_ATS_NetworkTypeCount;
2374   sh->env.info_cb = &solver_info_cb;
2375   sh->env.info_cb_cls = NULL;
2376
2377
2378   /* start normalization */
2379   GAS_normalization_start (NULL, NULL, &normalized_property_changed_cb, NULL );
2380
2381   /* load quotas */
2382   if (GNUNET_ATS_NetworkTypeCount != GNUNET_ATS_solvers_load_quotas (e->cfg,
2383       sh->env.out_quota, sh->env.in_quota, GNUNET_ATS_NetworkTypeCount))
2384   {
2385     GNUNET_break(0);
2386     GNUNET_free (sh->plugin);
2387     GNUNET_free (sh);
2388     end_now ();
2389     return NULL;
2390   }
2391
2392   sh->solver = GNUNET_PLUGIN_load (sh->plugin, &sh->env);
2393   if (NULL == sh->solver)
2394   {
2395     fprintf (stderr, "Failed to load solver `%s'\n", sh->plugin);
2396     GNUNET_break(0);
2397     GNUNET_free (sh->plugin);
2398     GNUNET_free (sh);
2399     end_now ();
2400     return NULL;
2401   }
2402   return sh;
2403 }
2404
2405 static int
2406 free_all_it (void *cls,
2407     const struct GNUNET_PeerIdentity *key,
2408     void *value)
2409 {
2410   struct ATS_Address *address = value;
2411   GNUNET_CONTAINER_multipeermap_remove (sh->env.addresses, key, value);
2412   GNUNET_free (address);
2413
2414   return GNUNET_OK;
2415 }
2416
2417 static void
2418 done ()
2419 {
2420   struct TestPeer *cur;
2421   struct TestPeer *next;
2422   /* Clean up experiment */
2423   GNUNET_ATS_solver_generate_preferences_stop_all ();
2424   GNUNET_ATS_solver_generate_property_stop_all ();
2425
2426   if (NULL != e)
2427   {
2428     GNUNET_ATS_solvers_experimentation_stop (e);
2429     e = NULL;
2430   }
2431
2432   if (NULL != l)
2433   {
2434     GNUNET_ATS_solver_logging_free (l);
2435     l = NULL;
2436   }
2437
2438   next = peer_head;
2439   while  (NULL != (cur = next))
2440   {
2441     next = cur->next;
2442     GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, cur);
2443     GNUNET_CONTAINER_multipeermap_iterate (sh->env.addresses, &free_all_it, NULL);
2444
2445     GNUNET_free (cur);
2446   }
2447   /* Shutdown */
2448   end_now();
2449
2450 }
2451
2452 static void
2453 experiment_done_cb (struct Experiment *e, struct GNUNET_TIME_Relative duration,int success)
2454 {
2455   if (GNUNET_OK == success)
2456     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment done successful in %s\n",
2457         GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
2458   else
2459     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment failed \n");
2460
2461   /* Stop logging */
2462   GNUNET_ATS_solver_logging_stop (l);
2463
2464   /* Stop traffic generation */
2465   // GNUNET_ATS_TEST_generate_traffic_stop_all();
2466
2467   /* Stop all preference generations */
2468   GNUNET_ATS_solver_generate_preferences_stop_all ();
2469
2470   /*
2471   evaluate (duration);
2472   if (opt_log)
2473     GNUNET_ATS_TEST_logging_write_to_file(l, opt_exp_file, opt_plot);
2474
2475   if (NULL != l)
2476   {
2477     GNUNET_ATS_TEST_logging_stop (l);
2478     GNUNET_ATS_TEST_logging_clean_up (l);
2479     l = NULL;
2480   }
2481   */
2482   GNUNET_SCHEDULER_add_now (&done, NULL);
2483 }
2484
2485 static void
2486 episode_done_cb (struct Episode *ep)
2487 {
2488   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Episode %u done\n", ep->id);
2489 }
2490
2491
2492
2493 /**
2494  * Do shutdown
2495  */
2496 static void
2497 end_now ()
2498 {
2499   if (NULL != e)
2500   {
2501     GNUNET_ATS_solvers_experimentation_stop (e);
2502     e = NULL;
2503   }
2504   if (NULL != sh)
2505   {
2506     GNUNET_ATS_solvers_solver_stop (sh);
2507     sh = NULL;
2508   }
2509 }
2510
2511 static void
2512 run (void *cls, char * const *args, const char *cfgfile,
2513     const struct GNUNET_CONFIGURATION_Handle *cfg)
2514 {
2515   enum GNUNET_ATS_Solvers solver;
2516
2517   if (NULL == opt_exp_file)
2518   {
2519     fprintf (stderr, "No experiment given ...\n");
2520     res = 1;
2521     end_now ();
2522     return;
2523   }
2524
2525   if (NULL == opt_solver)
2526   {
2527     fprintf (stderr, "No solver given ...\n");
2528     res = 1;
2529     end_now ();
2530     return;
2531   }
2532
2533   if (0 == strcmp(opt_solver, "mlp"))
2534   {
2535     solver = GNUNET_ATS_SOLVER_MLP;
2536   }
2537   else if (0 == strcmp(opt_solver, "proportional"))
2538   {
2539     solver = GNUNET_ATS_SOLVER_PROPORTIONAL;
2540   }
2541   else if (0 == strcmp(opt_solver, "ril"))
2542   {
2543     solver = GNUNET_ATS_SOLVER_RIL;
2544   }
2545   else
2546   {
2547     fprintf (stderr, "No solver given ...");
2548     res = 1;
2549     end_now ();
2550     return;
2551   }
2552
2553   /* load experiment */
2554   e = GNUNET_ATS_solvers_experimentation_load (opt_exp_file);
2555   if (NULL == e)
2556   {
2557     fprintf (stderr, "Failed to load experiment ...\n");
2558     res = 1;
2559     end_now ();
2560     return;
2561   }
2562
2563   /* load solver */
2564   sh = GNUNET_ATS_solvers_solver_start (solver);
2565   if (NULL == sh)
2566   {
2567     fprintf (stderr, "Failed to start solver ...\n");
2568     end_now ();
2569     res = 1;
2570     return;
2571   }
2572
2573   /* start logging */
2574   l = GNUNET_ATS_solver_logging_start (e->log_freq);
2575
2576   /* run experiment */
2577   GNUNET_ATS_solvers_experimentation_run (e, episode_done_cb,
2578       experiment_done_cb);
2579
2580   /* WAIT */
2581 }
2582
2583
2584 /**
2585  * Main function of the benchmark
2586  *
2587  * @param argc argument count
2588  * @param argv argument values
2589  */
2590 int
2591 main (int argc, char *argv[])
2592 {
2593   opt_exp_file = NULL;
2594   opt_solver = NULL;
2595   opt_log = GNUNET_NO;
2596   opt_plot = GNUNET_NO;
2597
2598   res = 0;
2599
2600   static struct GNUNET_GETOPT_CommandLineOption options[] =
2601   {
2602     { 's', "solver", NULL,
2603         gettext_noop ("solver to use"),
2604         1, &GNUNET_GETOPT_set_string, &opt_solver},
2605     {  'e', "experiment", NULL,
2606       gettext_noop ("experiment to use"),
2607       1, &GNUNET_GETOPT_set_string, &opt_exp_file},
2608     {  'e', "experiment", NULL,
2609       gettext_noop ("experiment to use"),
2610       1, &GNUNET_GETOPT_set_one, &opt_verbose},
2611     GNUNET_GETOPT_OPTION_END
2612   };
2613
2614   GNUNET_PROGRAM_run (argc, argv, "gnunet-ats-solver-eval",
2615       NULL, options, &run, argv[0]);
2616
2617   return res;
2618 }
2619 /* end of file ats-testing-experiment.c*/
2620