add changelog
[oweals/gnunet.git] / src / ats / gnunet-ats-solver-eval.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 "gnunet-ats-solver-eval.h"
29 #include "gnunet-service-ats_normalization.h"
30 #include "gnunet-service-ats_preferences.c"
31
32 #define BIG_M_STRING "unlimited"
33
34 /**
35  * Handle for statistics.
36  */
37 struct GNUNET_STATISTICS_Handle *GSA_stats;
38
39
40 static struct Experiment *e;
41
42 static struct LoggingHandle *l;
43
44 static struct SolverHandle *sh;
45
46 static struct TestPeer *peer_head;
47
48 static struct TestPeer *peer_tail;
49
50 static double default_properties[GNUNET_ATS_PropertyCount];
51 static double default_preferences[GNUNET_ATS_PreferenceCount];
52
53 /**
54  * cmd option -e: experiment file
55  */
56 static char *opt_exp_file;
57
58 static char *opt_solver;
59
60 /**
61  * cmd option -l: enable logging
62  */
63 static int opt_log;
64
65 /**
66  * cmd option -p: enable plots
67  */
68 static int opt_save;
69
70 /**
71  * cmd option -v: verbose logs
72  */
73 static int opt_verbose;
74
75 /**
76  * cmd option -p: print logs
77  */
78 static int opt_print;
79
80 /**
81  * cmd option -d: disable normalization
82  */
83 static int opt_disable_normalization;
84
85 static int res;
86
87 static void
88 end_now ();
89
90
91 static char *
92 print_generator_type (enum GeneratorType g)
93 {
94   switch (g)
95   {
96   case GNUNET_ATS_TEST_TG_CONSTANT:
97     return "CONSTANT";
98
99   case GNUNET_ATS_TEST_TG_LINEAR:
100     return "LINEAR";
101
102   case GNUNET_ATS_TEST_TG_RANDOM:
103     return "RANDOM";
104
105   case GNUNET_ATS_TEST_TG_SINUS:
106     return "SINUS";
107
108   default:
109     return "INVALID";
110     break;
111   }
112 }
113
114
115 static struct TestPeer *
116 find_peer_by_id (int id)
117 {
118   struct TestPeer *cur;
119
120   for (cur = peer_head; NULL != cur; cur = cur->next)
121     if (cur->id == id)
122       return cur;
123   return NULL;
124 }
125
126
127 static struct TestPeer *
128 find_peer_by_pid (const struct GNUNET_PeerIdentity *pid)
129 {
130   struct TestPeer *cur;
131
132   for (cur = peer_head; NULL != cur; cur = cur->next)
133     if (0 == GNUNET_memcmp (&cur->peer_id, pid))
134       return cur;
135   return NULL;
136 }
137
138
139 static struct TestAddress *
140 find_address_by_id (struct TestPeer *peer, int aid)
141 {
142   struct TestAddress *cur;
143
144   for (cur = peer->addr_head; NULL != cur; cur = cur->next)
145     if (cur->aid == aid)
146       return cur;
147   return NULL;
148 }
149
150
151 /**
152  * Logging
153  */
154 void
155 GNUNET_ATS_solver_logging_now (struct LoggingHandle *l)
156 {
157   struct LoggingTimeStep *lts;
158   struct TestPeer *cur;
159   struct TestAddress *cur_addr;
160   struct LoggingPeer *log_p;
161   struct LoggingAddress *log_a;
162   int c;
163
164   lts = GNUNET_new (struct LoggingTimeStep);
165   GNUNET_CONTAINER_DLL_insert_tail (l->head, l->tail, lts);
166   lts->timestamp = GNUNET_TIME_absolute_get ();
167   if (NULL == lts->prev)
168     lts->delta = GNUNET_TIME_UNIT_ZERO;
169   else
170     lts->delta = GNUNET_TIME_absolute_get_duration (lts->prev->timestamp);
171
172   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Logging %llu, delta %llu\n",
173               lts->timestamp.abs_value_us, lts->delta.rel_value_us);
174
175
176   /* Store logging data here */
177   for (cur = peer_head; NULL != cur; cur = cur->next)
178   {
179     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
180                 "Logging peer id %llu\n", cur->id);
181
182     log_p = GNUNET_new (struct LoggingPeer);
183     log_p->id = cur->id;
184     log_p->peer_id = cur->peer_id;
185     log_p->is_requested = cur->is_requested;
186     for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
187     {
188       log_p->pref_abs[c] = cur->pref_abs[c];
189       log_p->pref_norm[c] = cur->pref_norm[c];
190       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191                   "\t %s = %.2f %.2f [abs/rel]\n",
192                   GNUNET_ATS_print_preference_type (c),
193                   log_p->pref_abs[c], log_p->pref_norm[c]);
194     }
195     GNUNET_CONTAINER_DLL_insert_tail (lts->head, lts->tail, log_p);
196
197     for (cur_addr = cur->addr_head; NULL != cur_addr; cur_addr = cur_addr->next)
198     {
199       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
200                   "Logging peer id %llu address %llu\n",
201                   cur->id, cur_addr->aid);
202       log_a = GNUNET_new (struct LoggingAddress);
203       log_a->aid = cur_addr->aid;
204       log_a->active = cur_addr->ats_addr->active;
205       log_a->network = cur_addr->network;
206       log_a->assigned_bw_in = cur_addr->ats_addr->assigned_bw_in;
207       log_a->assigned_bw_out = cur_addr->ats_addr->assigned_bw_out;
208       for (c = 0; c < GNUNET_ATS_PropertyCount; c++)
209       {
210         log_a->prop_abs[c] = cur_addr->prop_abs[c];
211         log_a->prop_norm[c] = cur_addr->prop_norm[c];
212         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213                     "\t %s = %.2f %.2f [abs/rel]\n",
214                     GNUNET_ATS_print_property_type (c),
215                     log_a->prop_abs[c],
216                     log_a->prop_norm[c]);
217       }
218       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\t Active = %i\n", log_a->active);
219       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\t BW in = %llu\n",
220                   log_a->assigned_bw_in);
221       GNUNET_log (GNUNET_ERROR_TYPE_INFO, "\t BW out = %llu\n",
222                   log_a->assigned_bw_out);
223
224       GNUNET_CONTAINER_DLL_insert_tail (log_p->addr_head, log_p->addr_tail,
225                                         log_a);
226     }
227   }
228 }
229
230
231 static void
232 logging_task (void *cls)
233 {
234   struct LoggingHandle *l = cls;
235
236   l->logging_task = NULL;
237   GNUNET_ATS_solver_logging_now (l);
238   l->logging_task = GNUNET_SCHEDULER_add_delayed (l->log_freq,
239                                                   &logging_task,
240                                                   l);
241 }
242
243
244 struct LoggingHandle *
245 GNUNET_ATS_solver_logging_start (struct GNUNET_TIME_Relative freq)
246 {
247   struct LoggingHandle *l;
248
249   l = GNUNET_new (struct LoggingHandle);
250
251   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Start logging every  %s\n",
252               GNUNET_STRINGS_relative_time_to_string (freq, GNUNET_NO));
253   l->log_freq = freq;
254   l->logging_task = GNUNET_SCHEDULER_add_now (&logging_task, l);
255   return l;
256 }
257
258
259 void
260 GNUNET_ATS_solver_logging_stop (struct LoggingHandle *l)
261 {
262   if (NULL != l->logging_task)
263     GNUNET_SCHEDULER_cancel (l->logging_task);
264
265   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Stop logging\n");
266
267   l->logging_task = NULL;
268 }
269
270
271 static struct LoggingFileHandle *
272 find_logging_file_handle (struct LoggingFileHandle *lf_head,
273                           struct LoggingFileHandle *lf_tail,
274                           int peer_id, int address_id)
275 {
276   struct LoggingFileHandle *res;
277
278   for (res = lf_head; NULL != res; res = res->next)
279     if ((res->pid == peer_id) && (res->aid == address_id))
280       return res;
281   return NULL;
282 }
283
284
285 void
286 GNUNET_ATS_solver_logging_write_to_disk (struct LoggingHandle *l, int
287                                          add_time_stamp,
288                                          char *output_dir)
289 {
290   struct LoggingTimeStep *lts;
291   struct LoggingPeer *log_p;
292   struct LoggingAddress *log_a;
293   struct LoggingFileHandle *lf_head;
294   struct LoggingFileHandle *lf_tail;
295   struct LoggingFileHandle *cur;
296   struct LoggingFileHandle *next;
297   char *filename;
298   char *datastring;
299   char *propstring;
300   char *propstring_tmp;
301   char *prefstring;
302   char *prefstring_tmp;
303   int c;
304   int use_dir;
305
306   use_dir = GNUNET_NO;
307   if (NULL != output_dir)
308   {
309     if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (output_dir))
310     {
311       fprintf (stderr, "Failed to create directory `%s'\n", output_dir);
312       return;
313     }
314     else
315     {
316       fprintf (stderr, "Created directory `%s'\n", output_dir);
317       use_dir = GNUNET_YES;
318     }
319   }
320
321   lf_head = NULL;
322   lf_tail = NULL;
323
324   for (lts = l->head; NULL != lts; lts = lts->next)
325   {
326     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Writing log step %llu\n",
327                 (long long unsigned int) lts->timestamp.abs_value_us);
328
329     for (log_p = lts->head; NULL != log_p; log_p = log_p->next)
330     {
331       for (log_a = log_p->addr_head; NULL != log_a; log_a = log_a->next)
332       {
333         cur = find_logging_file_handle (lf_head, lf_tail, log_p->id,
334                                         log_a->aid);
335         if (NULL == cur)
336         {
337           cur = GNUNET_new (struct LoggingFileHandle);
338           cur->aid = log_a->aid;
339           cur->pid = log_p->id;
340
341           if (GNUNET_YES == add_time_stamp)
342             GNUNET_asprintf (&filename, "%s%s%s_%s_p%u_a%u_%llu.log",
343                              (GNUNET_YES == use_dir) ? output_dir : "",
344                              (GNUNET_YES == use_dir) ? DIR_SEPARATOR_STR : "",
345                              e->log_prefix,
346                              opt_solver,
347                              cur->pid,
348                              cur->aid,
349                              l->head->timestamp.abs_value_us);
350           else
351             GNUNET_asprintf (&filename, "%s%s%s_%s_p%u_a%u.log",
352                              (GNUNET_YES == use_dir) ? output_dir : "",
353                              (GNUNET_YES == use_dir) ? DIR_SEPARATOR_STR : "",
354                              e->log_prefix,
355                              opt_solver,
356                              cur->pid,
357                              cur->aid);
358
359           fprintf (stderr,
360                    "Add writing log data for peer %llu address %llu to file `%s'\n",
361                    cur->pid, cur->aid, filename);
362
363
364           cur->f_hd = GNUNET_DISK_file_open (filename,
365                                              GNUNET_DISK_OPEN_READWRITE
366                                              | GNUNET_DISK_OPEN_CREATE
367                                              | GNUNET_DISK_OPEN_TRUNCATE,
368                                              GNUNET_DISK_PERM_USER_READ
369                                              | GNUNET_DISK_PERM_USER_WRITE
370                                              | GNUNET_DISK_PERM_GROUP_READ
371                                              | GNUNET_DISK_PERM_OTHER_READ);
372           if (NULL == cur->f_hd)
373           {
374             fprintf (stderr, "Cannot open `%s' to write log data!\n", filename);
375             GNUNET_free (filename);
376             GNUNET_free (cur);
377             goto cleanup;
378           }
379           GNUNET_free (filename);
380           GNUNET_CONTAINER_DLL_insert (lf_head, lf_tail, cur);
381
382           GNUNET_asprintf (&datastring,
383                            "#time delta;log duration;peer_requested;addr net; addr_active; bw in; bw out; " \
384                            "UTILIZATION_UP [abs/rel]; UTILIZATION_UP; UTILIZATION_DOWN; UTILIZATION_DOWN; " \
385                            "UTILIZATION_PAYLOAD_UP; UTILIZATION_PAYLOAD_UP; UTILIZATION_PAYLOAD_DOWN; UTILIZATION_PAYLOAD_DOWN;" \
386                            "DELAY; DELAY; " \
387                            "DISTANCE ;DISTANCE ; COST_WAN; COST_WAN; COST_LAN; COST_LAN; " \
388                            "COST_WLAN; COST_WLAN;COST_BT; COST_BT; PREF BW abs; PREF BW rel; PREF LATENCY abs; PREF LATENCY rel;\n");
389           GNUNET_DISK_file_write (cur->f_hd, datastring, strlen (datastring));
390           GNUNET_free (datastring);
391         }
392
393         prefstring = GNUNET_strdup ("");
394         for (c = 1; c < GNUNET_ATS_PreferenceCount; c++)
395         {
396           /*
397              fprintf(stderr,"\t %s = %.2f %.2f [abs/rel]\n",
398               GNUNET_ATS_print_preference_type(c),
399               log_p->pref_abs[c], log_p->pref_norm[c]);
400            */GNUNET_asprintf (&prefstring_tmp, "%s;%.3f;%.3f",
401                            prefstring, log_p->pref_abs[c], log_p->pref_norm[c]);
402
403
404           GNUNET_free (prefstring);
405           prefstring = GNUNET_strdup (prefstring_tmp);
406           GNUNET_free (prefstring_tmp);
407         }
408
409
410         propstring = GNUNET_strdup ("");
411         for (c = 1; c < GNUNET_ATS_PropertyCount; c++)
412         {
413           if (GNUNET_ATS_NETWORK_TYPE == c)
414             continue;
415           /*
416              fprintf(stderr, "\t %s = %.2f %.2f [abs/rel]\n",
417               GNUNET_ATS_print_property_type(c),
418               log_a->prop_abs[c], log_a->prop_norm[c]);*/
419           GNUNET_asprintf (&propstring_tmp, "%s%.3f;%.3f;",
420                            propstring,
421                            log_a->prop_abs[c],
422                            log_a->prop_norm[c]);
423           GNUNET_free (propstring);
424           propstring = GNUNET_strdup (propstring_tmp);
425           GNUNET_free (propstring_tmp);
426         }
427         GNUNET_asprintf (&datastring, "%llu;%llu;%u;%u;%i;%u;%u;%s;%s\n",
428                          GNUNET_TIME_absolute_get_difference (
429                            l->head->timestamp,
430                            lts->timestamp).
431                          rel_value_us / 1000, lts->delta,
432                          log_p->is_requested, log_a->network, log_a->active,
433                          log_a->assigned_bw_in, log_a->assigned_bw_out,
434                          propstring,
435                          prefstring);
436
437         GNUNET_DISK_file_write (cur->f_hd, datastring, strlen (datastring));
438         GNUNET_free (datastring);
439         GNUNET_free (prefstring);
440         GNUNET_free (propstring);
441       }
442     }
443   }
444
445 cleanup:
446   next = lf_head;
447   for (cur = next; NULL != cur; cur = next)
448   {
449     next = cur->next;
450     GNUNET_CONTAINER_DLL_remove (lf_head, lf_tail, cur);
451     if (NULL != cur->f_hd)
452       GNUNET_DISK_file_close (cur->f_hd);
453     GNUNET_free (cur);
454   }
455 }
456
457
458 void
459 GNUNET_ATS_solver_logging_eval (struct LoggingHandle *l)
460 {
461   struct LoggingTimeStep *lts;
462   struct LoggingPeer *log_p;
463   struct LoggingAddress *log_a;
464   int c;
465
466   for (lts = l->head; NULL != lts; lts = lts->next)
467   {
468     fprintf (stderr, "Log step %llu %llu: \n",
469              (long long unsigned int) lts->timestamp.abs_value_us,
470              (long long unsigned int) lts->delta.rel_value_us);
471
472     for (log_p = lts->head; NULL != log_p; log_p = log_p->next)
473     {
474       fprintf (stderr, "\tLogging peer pid %llu\n", log_p->id);
475       for (c = 1; c < GNUNET_ATS_PreferenceCount; c++)
476       {
477         fprintf (stderr, "\t %s = %.2f %.2f [abs/rel]\n",
478                  GNUNET_ATS_print_preference_type (c),
479                  log_p->pref_abs[c], log_p->pref_norm[c]);
480       }
481
482       for (log_a = log_p->addr_head; NULL != log_a; log_a = log_a->next)
483       {
484         fprintf (stderr, "\tPeer pid %llu address %llu: %u %u %u\n",
485                  log_p->id, log_a->aid, log_a->active,
486                  log_a->assigned_bw_in,
487                  log_a->assigned_bw_out);
488
489         for (c = 1; c < GNUNET_ATS_PropertyCount; c++)
490         {
491           if (GNUNET_ATS_NETWORK_TYPE == c)
492             continue;
493           fprintf (stderr, "\t %s = %.2f %.2f [abs/rel]\n",
494                    GNUNET_ATS_print_property_type (c),
495                    log_a->prop_abs[c], log_a->prop_norm[c]);
496         }
497       }
498     }
499   }
500 }
501
502
503 void
504 GNUNET_ATS_solver_logging_free (struct LoggingHandle *l)
505 {
506   struct LoggingTimeStep *lts_cur;
507   struct LoggingTimeStep *lts_next;
508   struct LoggingPeer *log_p_cur;
509   struct LoggingPeer *log_p_next;
510   struct LoggingAddress *log_a_cur;
511   struct LoggingAddress *log_a_next;
512
513   if (NULL != l->logging_task)
514     GNUNET_SCHEDULER_cancel (l->logging_task);
515   l->logging_task = NULL;
516
517   lts_next = l->head;
518   while (NULL != (lts_cur = lts_next))
519   {
520     lts_next = lts_cur->next;
521
522     log_p_next = lts_cur->head;
523     while (NULL != (log_p_cur = log_p_next))
524     {
525       log_p_next = log_p_cur->next;
526
527       log_a_next = log_p_cur->addr_head;
528       while (NULL != (log_a_cur = log_a_next))
529       {
530         log_a_next = log_a_cur->next;
531
532         GNUNET_CONTAINER_DLL_remove (log_p_cur->addr_head, log_p_cur->addr_tail,
533                                      log_a_cur);
534         GNUNET_free (log_a_cur);
535       }
536
537       GNUNET_CONTAINER_DLL_remove (lts_cur->head, lts_cur->tail, log_p_cur);
538       GNUNET_free (log_p_cur);
539     }
540
541     GNUNET_CONTAINER_DLL_remove (l->head, l->tail, lts_cur);
542     GNUNET_free (lts_cur);
543   }
544
545   GNUNET_free (l);
546 }
547
548
549 /**
550  * Property Generators
551  */
552 static struct PropertyGenerator *prop_gen_head;
553 static struct PropertyGenerator *prop_gen_tail;
554
555
556 static double
557 get_property (struct PropertyGenerator *pg)
558 {
559   struct GNUNET_TIME_Relative time_delta;
560   double delta_value;
561   double pref_value;
562
563   /* Calculate the current preference value */
564   switch (pg->type)
565   {
566   case GNUNET_ATS_TEST_TG_CONSTANT:
567     pref_value = pg->base_value;
568     break;
569
570   case GNUNET_ATS_TEST_TG_LINEAR:
571     time_delta = GNUNET_TIME_absolute_get_duration (pg->time_start);
572     /* Calculate point of time in the current period */
573     time_delta.rel_value_us = time_delta.rel_value_us
574                               % pg->duration_period.rel_value_us;
575     delta_value = ((double) time_delta.rel_value_us
576                    / pg->duration_period.rel_value_us) * (pg->max_value
577                                                           - pg->base_value);
578     if ((pg->max_value < pg->base_value) &&
579         ((pg->max_value - pg->base_value) > pg->base_value))
580     {
581       /* This will cause an underflow */
582       GNUNET_break (0);
583     }
584     pref_value = pg->base_value + delta_value;
585     break;
586
587   case GNUNET_ATS_TEST_TG_RANDOM:
588     delta_value = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
589                                                      10000 * (pg->max_value
590                                                               - pg->base_value))
591                   / 10000;
592     pref_value = pg->base_value + delta_value;
593     break;
594
595   case GNUNET_ATS_TEST_TG_SINUS:
596     time_delta = GNUNET_TIME_absolute_get_duration (pg->time_start);
597     /* Calculate point of time in the current period */
598     time_delta.rel_value_us = time_delta.rel_value_us
599                               % pg->duration_period.rel_value_us;
600     if ((pg->max_value - pg->base_value) > pg->base_value)
601     {
602       /* This will cause an underflow for second half of sinus period,
603        * will be detected in general when experiments are loaded */
604       GNUNET_break (0);
605     }
606     delta_value = (pg->max_value - pg->base_value)
607                   * sin ((2 * M_PI)
608                          / ((double) pg->duration_period.rel_value_us)
609                          * time_delta.rel_value_us);
610     pref_value = pg->base_value + delta_value;
611     break;
612
613   default:
614     pref_value = 0.0;
615     break;
616   }
617   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Current property value is %f\n",
618               pref_value);
619   return pref_value;
620 }
621
622
623 static void
624 set_prop_task (void *cls)
625 {
626   struct PropertyGenerator *pg = cls;
627   struct TestPeer *p;
628   struct TestAddress *a;
629   double prop_value;
630   struct GNUNET_ATS_Information atsi;
631
632   pg->set_task = NULL;
633
634   if (GNUNET_NO == GNUNET_CONTAINER_multipeermap_contains_value (sh->addresses,
635                                                                  &pg->test_peer
636                                                                  ->peer_id,
637                                                                  pg->
638                                                                  test_address->
639                                                                  ats_addr))
640   {
641     GNUNET_break (0);
642     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
643                 "Setting property generation for unknown address [%u:%u]\n",
644                 pg->peer, pg->address_id);
645     return;
646   }
647   if (NULL == (p = find_peer_by_id (pg->peer)))
648   {
649     GNUNET_break (0);
650     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
651                 "Setting property generation for unknown peer %u\n",
652                 pg->peer);
653     return;
654   }
655   if (NULL == (a = find_address_by_id (p, pg->address_id)))
656   {
657     GNUNET_break (0);
658     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
659                 "Setting property generation for unknown peer %u\n",
660                 pg->peer);
661     return;
662   }
663
664   prop_value = get_property (pg);
665   a->prop_abs[pg->ats_property] = prop_value;
666
667   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
668               "Setting property for peer [%u] address [%u] for %s to %f\n",
669               pg->peer, pg->address_id,
670               GNUNET_ATS_print_property_type (pg->ats_property), prop_value);
671
672   atsi.type = htonl (pg->ats_property);
673   atsi.value = htonl ((uint32_t) prop_value);
674
675   /* set performance here! */
676   sh->sf->s_bulk_start (sh->sf->cls);
677   if (GNUNET_YES == opt_disable_normalization)
678   {
679     a->prop_abs[pg->ats_property] = prop_value;
680     a->prop_norm[pg->ats_property] = prop_value;
681     sh->sf->s_address_update_property (sh->sf->cls, a->ats_addr,
682                                        pg->ats_property, prop_value,
683                                        prop_value);
684   }
685   else
686     GAS_normalization_update_property (pg->test_address->ats_addr, &atsi, 1);
687   sh->sf->s_bulk_stop (sh->sf->cls);
688
689   pg->set_task = GNUNET_SCHEDULER_add_delayed (pg->frequency,
690                                                &set_prop_task, pg);
691 }
692
693
694 /**
695  * Set ats_property to 0 to find all pgs
696  */
697 static struct PropertyGenerator *
698 find_prop_gen (unsigned int peer, unsigned int address,
699                uint32_t ats_property)
700 {
701   struct PropertyGenerator *cur;
702
703   for (cur = prop_gen_head; NULL != cur; cur = cur->next)
704     if ((cur->peer == peer) && (cur->address_id == address))
705     {
706       if ((cur->ats_property == ats_property) || (0 == ats_property))
707         return cur;
708     }
709   return NULL;
710 }
711
712
713 void
714 GNUNET_ATS_solver_generate_property_stop (struct PropertyGenerator *pg)
715 {
716   GNUNET_CONTAINER_DLL_remove (prop_gen_head, prop_gen_tail, pg);
717
718   if (NULL != pg->set_task)
719   {
720     GNUNET_SCHEDULER_cancel (pg->set_task);
721     pg->set_task = NULL;
722   }
723   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
724               "Removing old up preference generator peer [%u] address [%u] `%s'\n",
725               pg->peer, pg->address_id,
726               GNUNET_ATS_print_property_type (pg->ats_property));
727
728   GNUNET_free (pg);
729 }
730
731
732 /**
733  * Generate between the source master and the partner and set property with a
734  * value depending on the generator.
735  *
736  * @param peer source
737  * @param address_id partner
738  * @param test_peer the peer
739  * @param test_address the address
740  * @param type type of generator
741  * @param base_value base value
742  * @param value_rate maximum value
743  * @param period duration of a period of generation (~ 1/frequency)
744  * @param frequency how long to generate property
745  * @param ats_property ATS property to generate
746  * @return the property generator
747  */
748 struct PropertyGenerator *
749 GNUNET_ATS_solver_generate_property_start (unsigned int peer,
750                                            unsigned int address_id,
751                                            struct TestPeer *test_peer,
752                                            struct TestAddress *test_address,
753                                            enum GeneratorType type,
754                                            long int base_value,
755                                            long int value_rate,
756                                            struct GNUNET_TIME_Relative period,
757                                            struct GNUNET_TIME_Relative
758                                            frequency,
759                                            uint32_t ats_property)
760 {
761   struct PropertyGenerator *pg;
762
763   pg = GNUNET_new (struct PropertyGenerator);
764   GNUNET_CONTAINER_DLL_insert (prop_gen_head, prop_gen_tail, pg);
765   pg->type = type;
766   pg->peer = peer;
767   pg->test_address = test_address;
768   pg->test_peer = test_peer;
769   pg->address_id = address_id;
770   pg->ats_property = ats_property;
771   pg->base_value = base_value;
772   pg->max_value = value_rate;
773   pg->duration_period = period;
774   pg->frequency = frequency;
775   pg->time_start = GNUNET_TIME_absolute_get ();
776
777   switch (type)
778   {
779   case GNUNET_ATS_TEST_TG_CONSTANT:
780     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
781                 "Setting up %s property generator peer [%u] address [%u] `%s'" \
782                 "max %u Bips\n",
783                 print_generator_type (type), pg->peer, pg->address_id,
784                 GNUNET_ATS_print_property_type (ats_property),
785                 base_value);
786     break;
787
788   case GNUNET_ATS_TEST_TG_LINEAR:
789     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
790                 "Setting up %s property generator peer [%u] address [%u] `%s' " \
791                 "min %u Bips max %u Bips\n",
792                 print_generator_type (type), pg->peer, pg->address_id,
793                 GNUNET_ATS_print_property_type (ats_property),
794                 base_value, value_rate);
795     break;
796
797   case GNUNET_ATS_TEST_TG_SINUS:
798     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
799                 "Setting up %s property generator peer [%u] address [%u] `%s' " \
800                 "baserate %u Bips, amplitude %u Bps\n",
801                 print_generator_type (type), pg->peer, pg->address_id,
802                 GNUNET_ATS_print_property_type (ats_property),
803                 base_value, value_rate);
804     break;
805
806   case GNUNET_ATS_TEST_TG_RANDOM:
807     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
808                 "Setting up %s property generator peer [%u] address [%u] `%s' " \
809                 "min %u Bips max %u Bps\n",
810                 print_generator_type (type), pg->peer, pg->address_id,
811                 GNUNET_ATS_print_property_type (ats_property),
812                 base_value, value_rate);
813     break;
814
815   default:
816     break;
817   }
818
819   pg->set_task = GNUNET_SCHEDULER_add_now (&set_prop_task, pg);
820   return pg;
821 }
822
823
824 /**
825  * Stop all preferences generators
826  */
827 void
828 GNUNET_ATS_solver_generate_property_stop_all ()
829 {
830   struct PropertyGenerator *cur;
831   struct PropertyGenerator *next;
832
833   next = prop_gen_head;
834   for (cur = next; NULL != cur; cur = next)
835   {
836     next = cur->next;
837     GNUNET_ATS_solver_generate_property_stop (cur);
838   }
839 }
840
841
842 /**
843  * Preference Generators
844  */
845 static struct PreferenceGenerator *pref_gen_head;
846 static struct PreferenceGenerator *pref_gen_tail;
847
848
849 static double
850 get_preference (struct PreferenceGenerator *pg)
851 {
852   struct GNUNET_TIME_Relative time_delta;
853   double delta_value;
854   double pref_value;
855
856   /* Calculate the current preference value */
857   switch (pg->type)
858   {
859   case GNUNET_ATS_TEST_TG_CONSTANT:
860     pref_value = pg->base_value;
861     break;
862
863   case GNUNET_ATS_TEST_TG_LINEAR:
864     time_delta = GNUNET_TIME_absolute_get_duration (pg->time_start);
865     /* Calculate point of time in the current period */
866     time_delta.rel_value_us = time_delta.rel_value_us
867                               % pg->duration_period.rel_value_us;
868     delta_value = ((double) time_delta.rel_value_us
869                    / pg->duration_period.rel_value_us) * (pg->max_value
870                                                           - pg->base_value);
871     if ((pg->max_value < pg->base_value) &&
872         ((pg->max_value - pg->base_value) > pg->base_value))
873     {
874       /* This will cause an underflow */
875       GNUNET_break (0);
876     }
877     pref_value = pg->base_value + delta_value;
878     break;
879
880   case GNUNET_ATS_TEST_TG_RANDOM:
881     delta_value = (double) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
882                                                      10000 * (pg->max_value
883                                                               - pg->base_value))
884                   / 10000;
885     pref_value = pg->base_value + delta_value;
886     break;
887
888   case GNUNET_ATS_TEST_TG_SINUS:
889     time_delta = GNUNET_TIME_absolute_get_duration (pg->time_start);
890     /* Calculate point of time in the current period */
891     time_delta.rel_value_us = time_delta.rel_value_us
892                               % pg->duration_period.rel_value_us;
893     if ((pg->max_value - pg->base_value) > pg->base_value)
894     {
895       /* This will cause an underflow for second half of sinus period,
896        * will be detected in general when experiments are loaded */
897       GNUNET_break (0);
898     }
899     delta_value = (pg->max_value - pg->base_value)
900                   * sin ((2 * M_PI)
901                          / ((double) pg->duration_period.rel_value_us)
902                          * time_delta.rel_value_us);
903     pref_value = pg->base_value + delta_value;
904     break;
905
906   default:
907     pref_value = 0.0;
908     break;
909   }
910   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Current preference value is %f\n",
911               pref_value);
912   return pref_value;
913 }
914
915
916 static void
917 set_feedback_task (void *cls)
918 {
919   struct PreferenceGenerator *pg = cls;
920   struct TestPeer *p;
921   double feedback;
922   uint32_t bw_acc_out;
923   uint32_t bw_acc_in;
924   uint32_t delay_acc_in;
925   struct GNUNET_TIME_Relative dur;
926   double p_new;
927
928   pg->feedback_task = NULL;
929
930   if (NULL == (p = find_peer_by_id (pg->peer)))
931   {
932     GNUNET_break (0);
933     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
934                 "Setting feedback for unknown peer %u\n", pg->peer);
935     return;
936   }
937
938   switch (pg->kind)
939   {
940   case GNUNET_ATS_PREFERENCE_BANDWIDTH:
941     dur = GNUNET_TIME_absolute_get_duration (pg->feedback_last_bw_update);
942     bw_acc_in = dur.rel_value_us * pg->last_assigned_bw_in
943                 + pg->feedback_bw_in_acc;
944     pg->feedback_bw_in_acc = 0;
945
946     bw_acc_out = dur.rel_value_us * pg->last_assigned_bw_out
947                  + pg->feedback_bw_out_acc;
948     p_new = get_preference (pg);
949     feedback = (p_new / pg->pref_bw_old) * (bw_acc_in + bw_acc_out)
950                / (2 * GNUNET_TIME_absolute_get_duration (
951                     pg->feedback_last).rel_value_us);
952
953     break;
954
955   case GNUNET_ATS_PREFERENCE_LATENCY:
956     dur = GNUNET_TIME_absolute_get_duration (pg->feedback_last_delay_update);
957     delay_acc_in = dur.rel_value_us * pg->last_delay_value
958                    + pg->feedback_delay_acc;
959     pg->feedback_delay_acc = 0;
960
961     p_new = get_preference (pg);
962     feedback = (p_new / pg->pref_latency_old) * (delay_acc_in)
963                / (GNUNET_TIME_absolute_get_duration (
964                     pg->feedback_last).rel_value_us);
965
966     break;
967
968   default:
969     GNUNET_break (0);
970     feedback = 0.0;
971     break;
972   }
973   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
974               "Giving feedback for peer [%u] for client %p pref %s of %.3f\n",
975               pg->peer, NULL + (pg->client_id),
976               GNUNET_ATS_print_preference_type (pg->kind),
977               feedback);
978
979   sh->sf->s_feedback (sh->sf->cls, NULL + (pg->client_id), &p->peer_id,
980                       pg->feedback_frequency, pg->kind, feedback);
981   pg->feedback_last = GNUNET_TIME_absolute_get ();
982
983
984   pg->feedback_bw_out_acc = 0;
985   pg->feedback_bw_in_acc = 0;
986   pg->feedback_last_bw_update = GNUNET_TIME_absolute_get ();
987
988   pg->feedback_delay_acc = 0;
989   pg->feedback_last_delay_update = GNUNET_TIME_absolute_get ();
990
991
992   pg->feedback_task = GNUNET_SCHEDULER_add_delayed (pg->feedback_frequency,
993                                                     &set_feedback_task, pg);
994 }
995
996
997 static void
998 set_pref_task (void *cls)
999 {
1000   struct PreferenceGenerator *pg = cls;
1001   struct TestPeer *p;
1002   double pref_value;
1003
1004   pg->set_task = NULL;
1005
1006   if (NULL == (p = find_peer_by_id (pg->peer)))
1007   {
1008     GNUNET_break (0);
1009     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1010                 "Setting preference for unknown peer %u\n", pg->peer);
1011     return;
1012   }
1013
1014   pref_value = get_preference (pg);
1015   switch (pg->kind)
1016   {
1017   case GNUNET_ATS_PREFERENCE_BANDWIDTH:
1018     pg->pref_bw_old = pref_value;
1019     break;
1020
1021   case GNUNET_ATS_PREFERENCE_LATENCY:
1022     pg->pref_latency_old = pref_value;
1023     break;
1024
1025   default:
1026     break;
1027   }
1028
1029   p->pref_abs[pg->kind] = pref_value;
1030
1031   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1032               "Setting preference for peer [%u] for client %p pref %s to %f\n",
1033               pg->peer, NULL + (pg->client_id),
1034               GNUNET_ATS_print_preference_type (pg->kind), pref_value);
1035
1036   if (GNUNET_YES == opt_disable_normalization)
1037   {
1038     p->pref_abs[pg->kind] = pref_value;
1039     p->pref_norm[pg->kind] = pref_value;
1040     sh->sf->s_pref (sh->sf->cls, &p->peer_id, pg->kind, pref_value);
1041   }
1042   else
1043     update_preference (NULL + (pg->client_id),
1044                        &p->peer_id,
1045                        pg->kind,
1046                        pref_value);
1047
1048   pg->set_task = GNUNET_SCHEDULER_add_delayed (pg->frequency,
1049                                                &set_pref_task,
1050                                                pg);
1051 }
1052
1053
1054 static struct PreferenceGenerator *
1055 find_pref_gen (unsigned int peer, enum GNUNET_ATS_PreferenceKind kind)
1056 {
1057   struct PreferenceGenerator *cur;
1058
1059   for (cur = pref_gen_head; NULL != cur; cur = cur->next)
1060     if (cur->peer == peer)
1061     {
1062       if ((cur->kind == kind) || (GNUNET_ATS_PREFERENCE_END == kind))
1063         return cur;
1064     }
1065   return NULL;
1066 }
1067
1068
1069 void
1070 GNUNET_ATS_solver_generate_preferences_stop (struct PreferenceGenerator *pg)
1071 {
1072   GNUNET_CONTAINER_DLL_remove (pref_gen_head, pref_gen_tail, pg);
1073
1074   if (NULL != pg->feedback_task)
1075   {
1076     GNUNET_SCHEDULER_cancel (pg->feedback_task);
1077     pg->feedback_task = NULL;
1078   }
1079
1080   if (NULL != pg->set_task)
1081   {
1082     GNUNET_SCHEDULER_cancel (pg->set_task);
1083     pg->set_task = NULL;
1084   }
1085   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1086               "Removing old up preference generator peer [%u] `%s'\n",
1087               pg->peer, GNUNET_ATS_print_preference_type (pg->kind));
1088
1089   GNUNET_free (pg);
1090 }
1091
1092
1093 static struct TestAddress*
1094 find_active_address (struct TestPeer *p)
1095 {
1096   struct TestAddress *cur;
1097
1098   for (cur = p->addr_head; NULL != cur; cur = cur->next)
1099     if (GNUNET_YES == cur->ats_addr->active)
1100       return cur;
1101   return NULL;
1102 }
1103
1104
1105 /**
1106  * Generate between the source master and the partner and set property with a
1107  * value depending on the generator.
1108  *
1109  * @param peer source
1110  * @param address_id partner
1111  * @param client_id the client
1112  * @param type type of generator
1113  * @param base_value base value
1114  * @param value_rate maximum value
1115  * @param period duration of a period of generation (~ 1/frequency)
1116  * @param frequency how long to generate property
1117  * @param kind ATS preference to generate
1118  * @param feedback_frequency how often to give feedback
1119  * @return the preference generator
1120  */
1121 struct PreferenceGenerator *
1122 GNUNET_ATS_solver_generate_preferences_start (unsigned int peer,
1123                                               unsigned int address_id,
1124                                               unsigned int client_id,
1125                                               enum GeneratorType type,
1126                                               long int base_value,
1127                                               long int value_rate,
1128                                               struct GNUNET_TIME_Relative
1129                                               period,
1130                                               struct GNUNET_TIME_Relative
1131                                               frequency,
1132                                               enum GNUNET_ATS_PreferenceKind
1133                                               kind,
1134                                               struct GNUNET_TIME_Relative
1135                                               feedback_frequency)
1136 {
1137   struct PreferenceGenerator *pg;
1138   struct TestPeer *p;
1139
1140   if (NULL == (p = find_peer_by_id (peer)))
1141   {
1142     GNUNET_break (0);
1143     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1144                 "Starting preference for unknown peer %u\n", peer);
1145     return NULL;
1146   }
1147
1148   pg = GNUNET_new (struct PreferenceGenerator);
1149   GNUNET_CONTAINER_DLL_insert (pref_gen_head, pref_gen_tail, pg);
1150   pg->type = type;
1151   pg->peer = peer;
1152   pg->client_id = client_id;
1153   pg->kind = kind;
1154   pg->base_value = base_value;
1155   pg->max_value = value_rate;
1156   pg->duration_period = period;
1157   pg->frequency = frequency;
1158   pg->time_start = GNUNET_TIME_absolute_get ();
1159   pg->feedback_frequency = feedback_frequency;
1160
1161   switch (type)
1162   {
1163   case GNUNET_ATS_TEST_TG_CONSTANT:
1164     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1165                 "Setting up %s preference generator peer [%u] `%s' max %u Bips\n",
1166                 print_generator_type (type), pg->peer,
1167                 GNUNET_ATS_print_preference_type (kind),
1168                 base_value);
1169     break;
1170
1171   case GNUNET_ATS_TEST_TG_LINEAR:
1172     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1173                 "Setting up %s preference generator peer [%u] `%s' min %u Bips max %u Bips\n",
1174                 print_generator_type (type), pg->peer,
1175                 GNUNET_ATS_print_preference_type (kind),
1176                 base_value, value_rate);
1177     break;
1178
1179   case GNUNET_ATS_TEST_TG_SINUS:
1180     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1181                 "Setting up %s preference generator peer [%u] `%s' baserate %u Bips, amplitude %u Bps\n",
1182                 print_generator_type (type), pg->peer,
1183                 GNUNET_ATS_print_preference_type (kind),
1184                 base_value, value_rate);
1185     break;
1186
1187   case GNUNET_ATS_TEST_TG_RANDOM:
1188     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1189                 "Setting up %s preference generator peer [%u] `%s' min %u Bips max %u Bps\n",
1190                 print_generator_type (type), pg->peer,
1191                 GNUNET_ATS_print_preference_type (kind),
1192                 base_value, value_rate);
1193     break;
1194
1195   default:
1196     break;
1197   }
1198
1199   pg->set_task = GNUNET_SCHEDULER_add_now (&set_pref_task, pg);
1200   if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
1201       feedback_frequency.rel_value_us)
1202   {
1203     struct TestAddress *addr = find_active_address (p);
1204
1205     pg->last_assigned_bw_in = p->assigned_bw_in;
1206     pg->last_assigned_bw_out = p->assigned_bw_out;
1207     pg->feedback_bw_in_acc = 0;
1208     pg->feedback_bw_out_acc = 0;
1209     pg->last_delay_value = addr->prop_norm[GNUNET_ATS_QUALITY_NET_DELAY];
1210     pg->feedback_delay_acc = 0;
1211
1212     pg->feedback_last_bw_update = GNUNET_TIME_absolute_get ();
1213     pg->feedback_last_delay_update = GNUNET_TIME_absolute_get ();
1214     pg->feedback_last = GNUNET_TIME_absolute_get ();
1215     pg->feedback_task = GNUNET_SCHEDULER_add_delayed (feedback_frequency,
1216                                                       &set_feedback_task, pg);
1217   }
1218
1219   return pg;
1220 }
1221
1222
1223 /**
1224  * Stop all preferences generators
1225  */
1226 void
1227 GNUNET_ATS_solver_generate_preferences_stop_all ()
1228 {
1229   struct PreferenceGenerator *cur;
1230   struct PreferenceGenerator *next;
1231
1232   next = pref_gen_head;
1233   for (cur = next; NULL != cur; cur = next)
1234   {
1235     next = cur->next;
1236     GNUNET_ATS_solver_generate_preferences_stop (cur);
1237   }
1238 }
1239
1240
1241 /**
1242  * Experiments
1243  */
1244 static const char *
1245 print_op (enum OperationType op)
1246 {
1247   switch (op)
1248   {
1249   case SOLVER_OP_ADD_ADDRESS:
1250     return "ADD_ADDRESS";
1251
1252   case SOLVER_OP_DEL_ADDRESS:
1253     return "DEL_ADDRESS";
1254
1255   case SOLVER_OP_START_SET_PREFERENCE:
1256     return "START_SET_PREFERENCE";
1257
1258   case SOLVER_OP_STOP_SET_PREFERENCE:
1259     return "STOP_STOP_PREFERENCE";
1260
1261   case SOLVER_OP_START_SET_PROPERTY:
1262     return "START_SET_PROPERTY";
1263
1264   case SOLVER_OP_STOP_SET_PROPERTY:
1265     return "STOP_SET_PROPERTY";
1266
1267   case SOLVER_OP_START_REQUEST:
1268     return "START_REQUEST";
1269
1270   case SOLVER_OP_STOP_REQUEST:
1271     return "STOP_REQUEST";
1272
1273   default:
1274     break;
1275   }
1276   return "";
1277 }
1278
1279
1280 static struct Experiment *
1281 create_experiment ()
1282 {
1283   struct Experiment *e;
1284
1285   e = GNUNET_new (struct Experiment);
1286   e->name = NULL;
1287   e->start = NULL;
1288   e->total_duration = GNUNET_TIME_UNIT_ZERO;
1289   return e;
1290 }
1291
1292
1293 static void
1294 free_experiment (struct Experiment *e)
1295 {
1296   struct Episode *cur;
1297   struct Episode *next;
1298   struct GNUNET_ATS_TEST_Operation *cur_o;
1299   struct GNUNET_ATS_TEST_Operation *next_o;
1300
1301   next = e->start;
1302   for (cur = next; NULL != cur; cur = next)
1303   {
1304     next = cur->next;
1305
1306     next_o = cur->head;
1307     for (cur_o = next_o; NULL != cur_o; cur_o = next_o)
1308     {
1309       next_o = cur_o->next;
1310       GNUNET_free_non_null (cur_o->address);
1311       GNUNET_free_non_null (cur_o->plugin);
1312       GNUNET_free (cur_o);
1313     }
1314     GNUNET_free (cur);
1315   }
1316
1317   GNUNET_free_non_null (e->name);
1318   GNUNET_free_non_null (e->log_prefix);
1319   GNUNET_free_non_null (e->log_output_dir);
1320   GNUNET_free_non_null (e->cfg_file);
1321   GNUNET_free (e);
1322 }
1323
1324
1325 static int
1326 load_op_add_address (struct GNUNET_ATS_TEST_Operation *o,
1327                      struct Episode *e,
1328                      int op_counter,
1329                      char *sec_name,
1330                      const struct GNUNET_CONFIGURATION_Handle *cfg)
1331 {
1332   char *op_name;
1333   char *op_network;
1334
1335   /* peer pid */
1336   GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
1337   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1338                                                               sec_name, op_name,
1339                                                               &o->peer_id))
1340   {
1341     fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
1342              op_counter, "ADD_ADDRESS", op_name);
1343     GNUNET_free (op_name);
1344     return GNUNET_SYSERR;
1345   }
1346   GNUNET_free (op_name);
1347
1348   /* address pid */
1349   GNUNET_asprintf (&op_name, "op-%u-address-id", op_counter);
1350   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1351                                                               sec_name, op_name,
1352                                                               &o->address_id))
1353   {
1354     fprintf (stderr,
1355              "Missing address-id in operation %u `%s' in episode `%s'\n",
1356              op_counter, "ADD_ADDRESS", op_name);
1357     GNUNET_free (op_name);
1358     return GNUNET_SYSERR;
1359   }
1360   GNUNET_free (op_name);
1361
1362   /* plugin */
1363   GNUNET_asprintf (&op_name, "op-%u-plugin", op_counter);
1364   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1365                                                               sec_name, op_name,
1366                                                               &o->plugin))
1367   {
1368     fprintf (stderr, "Missing plugin in operation %u `%s' in episode `%s'\n",
1369              op_counter, "ADD_ADDRESS", op_name);
1370     GNUNET_free (op_name);
1371     return GNUNET_SYSERR;
1372   }
1373   GNUNET_free (op_name);
1374
1375   /* address  */
1376   GNUNET_asprintf (&op_name, "op-%u-address", op_counter);
1377   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1378                                                               sec_name, op_name,
1379                                                               &o->address))
1380   {
1381     fprintf (stderr, "Missing address in operation %u `%s' in episode `%s'\n",
1382              op_counter, "ADD_ADDRESS", op_name);
1383     GNUNET_free (op_name);
1384     return GNUNET_SYSERR;
1385   }
1386   GNUNET_free (op_name);
1387
1388   /* session */
1389   GNUNET_asprintf (&op_name, "op-%u-address-session", op_counter);
1390   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1391                                                               sec_name, op_name,
1392                                                               &o->
1393                                                               address_session))
1394   {
1395     fprintf (stderr,
1396              "Missing address-session in operation %u `%s' in episode `%s'\n",
1397              op_counter, "ADD_ADDRESS", op_name);
1398     GNUNET_free (op_name);
1399     return GNUNET_SYSERR;
1400   }
1401   GNUNET_free (op_name);
1402
1403   /* network */
1404   GNUNET_asprintf (&op_name, "op-%u-address-network", op_counter);
1405   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1406                                                               sec_name, op_name,
1407                                                               &op_network))
1408   {
1409     fprintf (stderr,
1410              "Missing address-network in operation %u `%s' in episode `%s'\n",
1411              op_counter, "ADD_ADDRESS", op_name);
1412     GNUNET_free (op_name);
1413     return GNUNET_SYSERR;
1414   }
1415   else
1416   {
1417     GNUNET_STRINGS_utf8_toupper (op_network, op_network);
1418     if (0 == strcmp (op_network, "UNSPECIFIED"))
1419     {
1420       o->address_network = GNUNET_NT_UNSPECIFIED;
1421     }
1422     else if (0 == strcmp (op_network, "LOOPBACK"))
1423     {
1424       o->address_network = GNUNET_NT_LOOPBACK;
1425     }
1426     else if (0 == strcmp (op_network, "LAN"))
1427     {
1428       o->address_network = GNUNET_NT_LAN;
1429     }
1430     else if (0 == strcmp (op_network, "WAN"))
1431     {
1432       o->address_network = GNUNET_NT_WAN;
1433     }
1434     else if (0 == strcmp (op_network, "WLAN"))
1435     {
1436       o->address_network = GNUNET_NT_WLAN;
1437     }
1438     else if (0 == strcmp (op_network, "BT"))
1439     {
1440       o->address_network = GNUNET_NT_BT;
1441     }
1442     else
1443     {
1444       fprintf (stderr,
1445                "Invalid address-network in operation %u `%s' in episode `%s': `%s'\n",
1446                op_counter, "ADD_ADDRESS", op_name, op_network);
1447       GNUNET_free (op_network);
1448       GNUNET_free (op_name);
1449       return GNUNET_SYSERR;
1450     }
1451   }
1452   GNUNET_free (op_network);
1453   GNUNET_free (op_name);
1454
1455   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1456               "Found operation %s: [%llu:%llu] address `%s' plugin `%s' \n",
1457               "ADD_ADDRESS", o->peer_id, o->address_id, o->address, o->plugin);
1458
1459   return GNUNET_OK;
1460 }
1461
1462
1463 static int
1464 load_op_del_address (struct GNUNET_ATS_TEST_Operation *o,
1465                      struct Episode *e,
1466                      int op_counter,
1467                      char *sec_name,
1468                      const struct GNUNET_CONFIGURATION_Handle *cfg)
1469 {
1470   char *op_name;
1471
1472   // char *op_network;
1473
1474   /* peer pid */
1475   GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
1476   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1477                                                               sec_name, op_name,
1478                                                               &o->peer_id))
1479   {
1480     fprintf (stderr, "Missing peer-id in operation %u `%s' in episode `%s'\n",
1481              op_counter, "DEL_ADDRESS", op_name);
1482     GNUNET_free (op_name);
1483     return GNUNET_SYSERR;
1484   }
1485   GNUNET_free (op_name);
1486
1487   /* address pid */
1488   GNUNET_asprintf (&op_name, "op-%u-address-id", op_counter);
1489   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1490                                                               sec_name, op_name,
1491                                                               &o->address_id))
1492   {
1493     fprintf (stderr,
1494              "Missing address-id in operation %u `%s' in episode `%s'\n",
1495              op_counter, "DEL_ADDRESS", op_name);
1496     GNUNET_free (op_name);
1497     return GNUNET_SYSERR;
1498   }
1499   GNUNET_free (op_name);
1500
1501 #if 0
1502   /* plugin */
1503   GNUNET_asprintf (&op_name, "op-%u-plugin", op_counter);
1504   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1505                                                               sec_name, op_name,
1506                                                               &o->plugin))
1507   {
1508     fprintf (stderr, "Missing plugin in operation %u `%s' in episode `%s'\n",
1509              op_counter, "DEL_ADDRESS", op_name);
1510     GNUNET_free (op_name);
1511     return GNUNET_SYSERR;
1512   }
1513   GNUNET_free (op_name);
1514
1515   /* address  */
1516   GNUNET_asprintf (&op_name, "op-%u-address", op_counter);
1517   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1518                                                               sec_name, op_name,
1519                                                               &o->address))
1520   {
1521     fprintf (stderr, "Missing address in operation %u `%s' in episode `%s'\n",
1522              op_counter, "DEL_ADDRESS", op_name);
1523     GNUNET_free (op_name);
1524     return GNUNET_SYSERR;
1525   }
1526   GNUNET_free (op_name);
1527
1528   /* session */
1529   GNUNET_asprintf (&op_name, "op-%u-address-session", op_counter);
1530   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1531                                                               sec_name, op_name,
1532                                                               &o->
1533                                                               address_session))
1534   {
1535     fprintf (stderr,
1536              "Missing address-session in operation %u `%s' in episode `%s'\n",
1537              op_counter, "DEL_ADDRESS", op_name);
1538     GNUNET_free (op_name);
1539     return GNUNET_SYSERR;
1540   }
1541   GNUNET_free (op_name);
1542 #endif
1543
1544   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1545               "Found operation %s: [%llu:%llu] address `%s' plugin `%s' \n",
1546               "DEL_ADDRESS", o->peer_id, o->address_id, o->address, o->plugin);
1547
1548   return GNUNET_OK;
1549 }
1550
1551
1552 static enum GNUNET_ATS_Property
1553 parse_preference_string (const char *str)
1554 {
1555   int c = 0;
1556   char *props[GNUNET_ATS_PreferenceCount] = GNUNET_ATS_PreferenceTypeString;
1557
1558   for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
1559     if (0 == strcmp (str, props[c]))
1560       return c;
1561   return 0;
1562 }
1563
1564
1565 static int
1566 load_op_start_set_preference (struct GNUNET_ATS_TEST_Operation *o,
1567                               struct Episode *e,
1568                               int op_counter,
1569                               char *sec_name,
1570                               const struct GNUNET_CONFIGURATION_Handle *cfg)
1571 {
1572   char *op_name;
1573   char *type;
1574   char *pref;
1575
1576   /* peer pid */
1577   GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
1578   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1579                                                               sec_name, op_name,
1580                                                               &o->peer_id))
1581   {
1582     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
1583              op_counter, "START_SET_PREFERENCE", op_name);
1584     GNUNET_free (op_name);
1585     return GNUNET_SYSERR;
1586   }
1587   GNUNET_free (op_name);
1588
1589   /* address pid */
1590   GNUNET_asprintf (&op_name, "op-%u-client-id", op_counter);
1591   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1592                                                               sec_name, op_name,
1593                                                               &o->client_id))
1594   {
1595     fprintf (stderr, "Missing client-id in operation %u `%s' in episode `%s'\n",
1596              op_counter, "START_SET_PREFERENCE", op_name);
1597     GNUNET_free (op_name);
1598     return GNUNET_SYSERR;
1599   }
1600   GNUNET_free (op_name);
1601
1602   /* generator */
1603   GNUNET_asprintf (&op_name, "op-%u-gen-type", op_counter);
1604   if ((GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1605                                                                sec_name,
1606                                                                op_name, &type)))
1607   {
1608     fprintf (stderr, "Missing type in operation %u `%s' in episode `%s'\n",
1609              op_counter, "START_SET_PREFERENCE", op_name);
1610     GNUNET_free (op_name);
1611     return GNUNET_SYSERR;
1612   }
1613
1614   /* Load arguments for set_rate, start_send, set_preference */
1615   if (0 == strcmp (type, "constant"))
1616   {
1617     o->gen_type = GNUNET_ATS_TEST_TG_CONSTANT;
1618   }
1619   else if (0 == strcmp (type, "linear"))
1620   {
1621     o->gen_type = GNUNET_ATS_TEST_TG_LINEAR;
1622   }
1623   else if (0 == strcmp (type, "sinus"))
1624   {
1625     o->gen_type = GNUNET_ATS_TEST_TG_SINUS;
1626   }
1627   else if (0 == strcmp (type, "random"))
1628   {
1629     o->gen_type = GNUNET_ATS_TEST_TG_RANDOM;
1630   }
1631   else
1632   {
1633     fprintf (stderr, "Invalid generator type %u `%s' in episode %u\n",
1634              op_counter, op_name, e->id);
1635     GNUNET_free (type);
1636     GNUNET_free (op_name);
1637     return GNUNET_SYSERR;
1638   }
1639   GNUNET_free (type);
1640   GNUNET_free (op_name);
1641
1642
1643   /* Get base rate */
1644   GNUNET_asprintf (&op_name, "op-%u-base-rate", op_counter);
1645   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1646                                                               sec_name, op_name,
1647                                                               &o->base_rate))
1648   {
1649     fprintf (stderr, "Missing base rate in operation %u `%s' in episode %u\n",
1650              op_counter, op_name, e->id);
1651     GNUNET_free (op_name);
1652     return GNUNET_SYSERR;
1653   }
1654   GNUNET_free (op_name);
1655
1656
1657   /* Get max rate */
1658   GNUNET_asprintf (&op_name, "op-%u-max-rate", op_counter);
1659   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1660                                                               sec_name, op_name,
1661                                                               &o->max_rate))
1662   {
1663     if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
1664         (GNUNET_ATS_TEST_TG_RANDOM == o->gen_type) ||
1665         (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
1666     {
1667       fprintf (stderr, "Missing max rate in operation %u `%s' in episode %u\n",
1668                op_counter, op_name, e->id);
1669       GNUNET_free (op_name);
1670       return GNUNET_SYSERR;
1671     }
1672   }
1673   GNUNET_free (op_name);
1674
1675   /* Get period */
1676   GNUNET_asprintf (&op_name, "op-%u-period", op_counter);
1677   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1678                                                             sec_name, op_name,
1679                                                             &o->period))
1680   {
1681     o->period = e->duration;
1682   }
1683   GNUNET_free (op_name);
1684
1685   /* Get frequency */
1686   GNUNET_asprintf (&op_name, "op-%u-frequency", op_counter);
1687   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1688                                                             sec_name, op_name,
1689                                                             &o->frequency))
1690   {
1691     fprintf (stderr, "Missing frequency in operation %u `%s' in episode %u\n",
1692              op_counter, op_name, e->id);
1693     GNUNET_free (op_name);
1694     return GNUNET_SYSERR;
1695   }
1696   GNUNET_free (op_name);
1697
1698   /* Get preference */
1699   GNUNET_asprintf (&op_name, "op-%u-pref", op_counter);
1700   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1701                                                               sec_name, op_name,
1702                                                               &pref))
1703   {
1704     fprintf (stderr, "Missing preference in operation %u `%s' in episode %u\n",
1705              op_counter, op_name, e->id);
1706     GNUNET_free (op_name);
1707     return GNUNET_SYSERR;
1708   }
1709
1710   if (0 == (o->pref_type = parse_preference_string (pref)))
1711   {
1712     fprintf (stderr, "Invalid preference in operation %u `%s' in episode %u\n",
1713              op_counter, op_name, e->id);
1714     GNUNET_free (op_name);
1715     GNUNET_free (pref);
1716     return GNUNET_SYSERR;
1717   }
1718   GNUNET_free (pref);
1719   GNUNET_free (op_name);
1720
1721   /* Get feedback delay */
1722   GNUNET_asprintf (&op_name, "op-%u-feedback_delay", op_counter);
1723   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_time (cfg,
1724                                                         sec_name, op_name,
1725                                                         &o->feedback_delay))
1726   {
1727     fprintf (stderr,
1728              "Using feedback delay %llu in operation %u `%s' in episode %u\n",
1729              (long long unsigned int) o->feedback_delay.rel_value_us,
1730              op_counter, op_name, e->id);
1731   }
1732   else
1733     o->feedback_delay = GNUNET_TIME_UNIT_FOREVER_REL;
1734   GNUNET_free (op_name);
1735
1736   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1737               "Found operation %s: [%llu:%llu]: %s = %llu\n",
1738               "START_SET_PREFERENCE", o->peer_id, o->address_id,
1739               GNUNET_ATS_print_preference_type (o->pref_type), o->base_rate);
1740
1741   return GNUNET_OK;
1742 }
1743
1744
1745 static int
1746 load_op_stop_set_preference (struct GNUNET_ATS_TEST_Operation *o,
1747                              struct Episode *e,
1748                              int op_counter,
1749                              char *sec_name,
1750                              const struct GNUNET_CONFIGURATION_Handle *cfg)
1751 {
1752   char *op_name;
1753   char *pref;
1754
1755   /* peer pid */
1756   GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
1757   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1758                                                               sec_name, op_name,
1759                                                               &o->peer_id))
1760   {
1761     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
1762              op_counter, "STOP_SET_PREFERENCE", op_name);
1763     GNUNET_free (op_name);
1764     return GNUNET_SYSERR;
1765   }
1766   GNUNET_free (op_name);
1767
1768   /* address pid */
1769   GNUNET_asprintf (&op_name, "op-%u-address-id", op_counter);
1770   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1771                                                               sec_name, op_name,
1772                                                               &o->address_id))
1773   {
1774     fprintf (stderr,
1775              "Missing address-id in operation %u `%s' in episode `%s'\n",
1776              op_counter, "STOP_SET_PREFERENCE", op_name);
1777     GNUNET_free (op_name);
1778     return GNUNET_SYSERR;
1779   }
1780   GNUNET_free (op_name);
1781
1782   /* Get preference */
1783   GNUNET_asprintf (&op_name, "op-%u-pref", op_counter);
1784   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1785                                                               sec_name, op_name,
1786                                                               &pref))
1787   {
1788     fprintf (stderr,
1789              "Missing preference in operation %u `%s' in episode `%s'\n",
1790              op_counter, "STOP_SET_PREFERENCE", op_name);
1791     GNUNET_free (op_name);
1792     return GNUNET_SYSERR;
1793   }
1794
1795   if (0 == (o->pref_type = parse_preference_string (pref)))
1796   {
1797     fprintf (stderr, "Invalid preference in operation %u `%s' in episode %u\n",
1798              op_counter, op_name, e->id);
1799     GNUNET_free (op_name);
1800     GNUNET_free (pref);
1801     return GNUNET_SYSERR;
1802   }
1803   GNUNET_free (pref);
1804   GNUNET_free (op_name);
1805
1806   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1807               "Found operation %s: [%llu:%llu]: %s\n",
1808               "STOP_SET_PREFERENCE", o->peer_id, o->address_id,
1809               GNUNET_ATS_print_preference_type (o->pref_type));
1810   return GNUNET_OK;
1811 }
1812
1813
1814 static enum GNUNET_ATS_Property
1815 parse_property_string (const char *str)
1816 {
1817   enum GNUNET_ATS_Property c;
1818
1819   for (c = 0; c < GNUNET_ATS_PropertyCount; c++)
1820     if (0 == strcmp (str,
1821                      GNUNET_ATS_print_property_type (c)))
1822       return c;
1823   return 0;
1824 }
1825
1826
1827 static int
1828 load_op_start_set_property (struct GNUNET_ATS_TEST_Operation *o,
1829                             struct Episode *e,
1830                             int op_counter,
1831                             char *sec_name,
1832                             const struct GNUNET_CONFIGURATION_Handle *cfg)
1833 {
1834   char *op_name;
1835   char *type;
1836   char *prop;
1837
1838   /* peer pid */
1839   GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
1840   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1841                                                               sec_name, op_name,
1842                                                               &o->peer_id))
1843   {
1844     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
1845              op_counter, "START_SET_PROPERTY", op_name);
1846     GNUNET_free (op_name);
1847     return GNUNET_SYSERR;
1848   }
1849   GNUNET_free (op_name);
1850
1851   /* address pid */
1852   GNUNET_asprintf (&op_name, "op-%u-address-id", op_counter);
1853   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1854                                                               sec_name, op_name,
1855                                                               &o->address_id))
1856   {
1857     fprintf (stderr,
1858              "Missing address-id in operation %u `%s' in episode `%s'\n",
1859              op_counter, "START_SET_PROPERTY", op_name);
1860     GNUNET_free (op_name);
1861     return GNUNET_SYSERR;
1862   }
1863   GNUNET_free (op_name);
1864
1865   /* generator */
1866   GNUNET_asprintf (&op_name, "op-%u-gen-type", op_counter);
1867   if ((GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1868                                                                sec_name,
1869                                                                op_name, &type)))
1870   {
1871     fprintf (stderr, "Missing type in operation %u `%s' in episode `%s'\n",
1872              op_counter, "START_SET_PROPERTY", op_name);
1873     GNUNET_free (op_name);
1874     return GNUNET_SYSERR;
1875   }
1876
1877   /* Load arguments for set_rate, start_send, set_preference */
1878   if (0 == strcmp (type, "constant"))
1879   {
1880     o->gen_type = GNUNET_ATS_TEST_TG_CONSTANT;
1881   }
1882   else if (0 == strcmp (type, "linear"))
1883   {
1884     o->gen_type = GNUNET_ATS_TEST_TG_LINEAR;
1885   }
1886   else if (0 == strcmp (type, "sinus"))
1887   {
1888     o->gen_type = GNUNET_ATS_TEST_TG_SINUS;
1889   }
1890   else if (0 == strcmp (type, "random"))
1891   {
1892     o->gen_type = GNUNET_ATS_TEST_TG_RANDOM;
1893   }
1894   else
1895   {
1896     fprintf (stderr, "Invalid generator type %u `%s' in episode %u\n",
1897              op_counter, op_name, e->id);
1898     GNUNET_free (type);
1899     GNUNET_free (op_name);
1900     return GNUNET_SYSERR;
1901   }
1902   GNUNET_free (type);
1903   GNUNET_free (op_name);
1904
1905
1906   /* Get base rate */
1907   GNUNET_asprintf (&op_name, "op-%u-base-rate", op_counter);
1908   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1909                                                               sec_name, op_name,
1910                                                               &o->base_rate))
1911   {
1912     fprintf (stderr, "Missing base rate in operation %u `%s' in episode %u\n",
1913              op_counter, op_name, e->id);
1914     GNUNET_free (op_name);
1915     return GNUNET_SYSERR;
1916   }
1917   GNUNET_free (op_name);
1918
1919
1920   /* Get max rate */
1921   GNUNET_asprintf (&op_name, "op-%u-max-rate", op_counter);
1922   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
1923                                                               sec_name, op_name,
1924                                                               &o->max_rate))
1925   {
1926     if ((GNUNET_ATS_TEST_TG_LINEAR == o->gen_type) ||
1927         (GNUNET_ATS_TEST_TG_RANDOM == o->gen_type) ||
1928         (GNUNET_ATS_TEST_TG_SINUS == o->gen_type))
1929     {
1930       fprintf (stderr, "Missing max rate in operation %u `%s' in episode %u\n",
1931                op_counter, op_name, e->id);
1932       GNUNET_free (op_name);
1933       return GNUNET_SYSERR;
1934     }
1935   }
1936   GNUNET_free (op_name);
1937
1938   /* Get period */
1939   GNUNET_asprintf (&op_name, "op-%u-period", op_counter);
1940   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1941                                                             sec_name, op_name,
1942                                                             &o->period))
1943   {
1944     o->period = e->duration;
1945   }
1946   GNUNET_free (op_name);
1947
1948   /* Get frequency */
1949   GNUNET_asprintf (&op_name, "op-%u-frequency", op_counter);
1950   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
1951                                                             sec_name, op_name,
1952                                                             &o->frequency))
1953   {
1954     fprintf (stderr, "Missing frequency in operation %u `%s' in episode %u\n",
1955              op_counter, op_name, e->id);
1956     GNUNET_free (op_name);
1957     return GNUNET_SYSERR;
1958   }
1959   GNUNET_free (op_name);
1960
1961   /* Get preference */
1962   GNUNET_asprintf (&op_name, "op-%u-property", op_counter);
1963   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
1964                                                               sec_name, op_name,
1965                                                               &prop))
1966   {
1967     fprintf (stderr, "Missing property in operation %u `%s' in episode %u\n",
1968              op_counter, op_name, e->id);
1969     GNUNET_free (op_name);
1970     GNUNET_free_non_null (prop);
1971     return GNUNET_SYSERR;
1972   }
1973
1974   if (0 == (o->prop_type = parse_property_string (prop)))
1975   {
1976     fprintf (stderr, "Invalid property in operation %u `%s' in episode %u\n",
1977              op_counter, op_name, e->id);
1978     GNUNET_free (op_name);
1979     GNUNET_free (prop);
1980     return GNUNET_SYSERR;
1981   }
1982
1983   GNUNET_free (prop);
1984   GNUNET_free (op_name);
1985
1986   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1987               "Found operation %s: [%llu:%llu] %s = %llu\n",
1988               "START_SET_PROPERTY", o->peer_id, o->address_id,
1989               GNUNET_ATS_print_property_type (o->prop_type), o->base_rate);
1990
1991   return GNUNET_OK;
1992 }
1993
1994
1995 static int
1996 load_op_stop_set_property (struct GNUNET_ATS_TEST_Operation *o,
1997                            struct Episode *e,
1998                            int op_counter,
1999                            char *sec_name,
2000                            const struct GNUNET_CONFIGURATION_Handle *cfg)
2001 {
2002   char *op_name;
2003   char *pref;
2004
2005   /* peer pid */
2006   GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
2007   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
2008                                                               sec_name, op_name,
2009                                                               &o->peer_id))
2010   {
2011     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
2012              op_counter, "STOP_SET_PROPERTY", op_name);
2013     GNUNET_free (op_name);
2014     return GNUNET_SYSERR;
2015   }
2016   GNUNET_free (op_name);
2017
2018   /* address pid */
2019   GNUNET_asprintf (&op_name, "op-%u-address-id", op_counter);
2020   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
2021                                                               sec_name, op_name,
2022                                                               &o->address_id))
2023   {
2024     fprintf (stderr,
2025              "Missing address-id in operation %u `%s' in episode `%s'\n",
2026              op_counter, "STOP_SET_PROPERTY", op_name);
2027     GNUNET_free (op_name);
2028     return GNUNET_SYSERR;
2029   }
2030   GNUNET_free (op_name);
2031
2032   /* Get property */
2033   GNUNET_asprintf (&op_name, "op-%u-property", op_counter);
2034   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
2035                                                               sec_name, op_name,
2036                                                               &pref))
2037   {
2038     fprintf (stderr, "Missing property in operation %u `%s' in episode `%s'\n",
2039              op_counter, "STOP_SET_PROPERTY", op_name);
2040     GNUNET_free (op_name);
2041     GNUNET_free_non_null (pref);
2042     return GNUNET_SYSERR;
2043   }
2044
2045   if (0 == (o->prop_type = parse_property_string (pref)))
2046   {
2047     fprintf (stderr, "Invalid property in operation %u `%s' in episode %u\n",
2048              op_counter, op_name, e->id);
2049     GNUNET_free (op_name);
2050     GNUNET_free_non_null (pref);
2051     return GNUNET_SYSERR;
2052   }
2053
2054   GNUNET_free (pref);
2055   GNUNET_free (op_name);
2056
2057   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2058               "Found operation %s: [%llu:%llu] %s\n",
2059               "STOP_SET_PROPERTY", o->peer_id, o->address_id,
2060               GNUNET_ATS_print_property_type (o->prop_type));
2061
2062   return GNUNET_OK;
2063 }
2064
2065
2066 static int
2067 load_op_start_request (struct GNUNET_ATS_TEST_Operation *o,
2068                        struct Episode *e,
2069                        int op_counter,
2070                        char *sec_name,
2071                        const struct GNUNET_CONFIGURATION_Handle *cfg)
2072 {
2073   char *op_name;
2074
2075   /* peer pid */
2076   GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
2077   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
2078                                                               sec_name, op_name,
2079                                                               &o->peer_id))
2080   {
2081     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
2082              op_counter, "START_REQUEST", op_name);
2083     GNUNET_free (op_name);
2084     return GNUNET_SYSERR;
2085   }
2086   GNUNET_free (op_name);
2087   return GNUNET_OK;
2088 }
2089
2090
2091 static int
2092 load_op_stop_request (struct GNUNET_ATS_TEST_Operation *o,
2093                       struct Episode *e,
2094                       int op_counter,
2095                       char *sec_name,
2096                       const struct GNUNET_CONFIGURATION_Handle *cfg)
2097 {
2098   char *op_name;
2099
2100   /* peer pid */
2101   GNUNET_asprintf (&op_name, "op-%u-peer-id", op_counter);
2102   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_number (cfg,
2103                                                               sec_name, op_name,
2104                                                               &o->peer_id))
2105   {
2106     fprintf (stderr, "Missing peer-id in operation %u  `%s' in episode `%s'\n",
2107              op_counter, "STOP_REQUEST", op_name);
2108     GNUNET_free (op_name);
2109     return GNUNET_SYSERR;
2110   }
2111   GNUNET_free (op_name);
2112   return GNUNET_OK;
2113 }
2114
2115
2116 static int
2117 load_episode (struct Experiment *e, struct Episode *cur,
2118               struct GNUNET_CONFIGURATION_Handle *cfg)
2119 {
2120   struct GNUNET_ATS_TEST_Operation *o;
2121   char *sec_name;
2122   char *op_name;
2123   char *op;
2124   int op_counter = 0;
2125   int res;
2126
2127   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "=== Parsing episode %u\n", cur->id);
2128   GNUNET_asprintf (&sec_name, "episode-%u", cur->id);
2129
2130   while (1)
2131   {
2132     /* Load operation */
2133     GNUNET_asprintf (&op_name, "op-%u-operation", op_counter);
2134     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg,
2135                                                                 sec_name,
2136                                                                 op_name, &op))
2137     {
2138       GNUNET_free (op_name);
2139       break;
2140     }
2141     o = GNUNET_new (struct GNUNET_ATS_TEST_Operation);
2142     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "==== Parsing operation %u: `%s'\n",
2143                 cur->id, op_name);
2144
2145     /* operations = set_rate, start_send, stop_send, set_preference */
2146     if (0 == strcmp (op, "address_add"))
2147     {
2148       o->type = SOLVER_OP_ADD_ADDRESS;
2149       res = load_op_add_address (o, cur,
2150                                  op_counter, sec_name, cfg);
2151     }
2152     else if (0 == strcmp (op, "address_del"))
2153     {
2154       o->type = SOLVER_OP_DEL_ADDRESS;
2155       res = load_op_del_address (o, cur,
2156                                  op_counter, sec_name, cfg);
2157     }
2158     else if (0 == strcmp (op, "start_set_property"))
2159     {
2160       o->type = SOLVER_OP_START_SET_PROPERTY;
2161       res = load_op_start_set_property (o, cur,
2162                                         op_counter, sec_name, cfg);
2163     }
2164     else if (0 == strcmp (op, "stop_set_property"))
2165     {
2166       o->type = SOLVER_OP_STOP_SET_PROPERTY;
2167       res = load_op_stop_set_property (o, cur,
2168                                        op_counter, sec_name, cfg);
2169     }
2170     else if (0 == strcmp (op, "start_set_preference"))
2171     {
2172       o->type = SOLVER_OP_START_SET_PREFERENCE;
2173       res = load_op_start_set_preference (o, cur,
2174                                           op_counter, sec_name, cfg);
2175     }
2176     else if (0 == strcmp (op, "stop_set_preference"))
2177     {
2178       o->type = SOLVER_OP_STOP_SET_PREFERENCE;
2179       res = load_op_stop_set_preference (o, cur,
2180                                          op_counter, sec_name, cfg);
2181     }
2182     else if (0 == strcmp (op, "start_request"))
2183     {
2184       o->type = SOLVER_OP_START_REQUEST;
2185       res = load_op_start_request (o, cur,
2186                                    op_counter, sec_name, cfg);
2187     }
2188     else if (0 == strcmp (op, "stop_request"))
2189     {
2190       o->type = SOLVER_OP_STOP_REQUEST;
2191       res = load_op_stop_request (o, cur,
2192                                   op_counter, sec_name, cfg);
2193     }
2194     else
2195     {
2196       fprintf (stderr, "Invalid operation %u `%s' in episode %u\n",
2197                op_counter, op, cur->id);
2198       res = GNUNET_SYSERR;
2199     }
2200
2201     GNUNET_free (op);
2202     GNUNET_free (op_name);
2203
2204     if (GNUNET_SYSERR == res)
2205     {
2206       GNUNET_free (o);
2207       GNUNET_free (sec_name);
2208       return GNUNET_SYSERR;
2209     }
2210
2211     GNUNET_CONTAINER_DLL_insert_tail (cur->head, cur->tail, o);
2212     op_counter++;
2213   }
2214   GNUNET_free (sec_name);
2215   return GNUNET_OK;
2216 }
2217
2218
2219 static int
2220 load_episodes (struct Experiment *e, struct GNUNET_CONFIGURATION_Handle *cfg)
2221 {
2222   int e_counter = 0;
2223   char *sec_name;
2224   struct GNUNET_TIME_Relative e_duration;
2225   struct Episode *cur;
2226   struct Episode *last;
2227
2228   e_counter = 0;
2229   last = NULL;
2230   while (1)
2231   {
2232     GNUNET_asprintf (&sec_name, "episode-%u", e_counter);
2233     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg,
2234                                                               sec_name,
2235                                                               "duration",
2236                                                               &e_duration))
2237     {
2238       GNUNET_free (sec_name);
2239       break;
2240     }
2241
2242     cur = GNUNET_new (struct Episode);
2243     cur->duration = e_duration;
2244     cur->id = e_counter;
2245
2246     if (GNUNET_OK != load_episode (e, cur, cfg))
2247     {
2248       GNUNET_free (sec_name);
2249       GNUNET_free (cur);
2250       return GNUNET_SYSERR;
2251     }
2252
2253     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Found episode %u with duration %s \n",
2254                 e_counter,
2255                 GNUNET_STRINGS_relative_time_to_string (cur->duration,
2256                                                         GNUNET_YES));
2257
2258     /* Update experiment */
2259     e->num_episodes++;
2260     e->total_duration = GNUNET_TIME_relative_add (e->total_duration,
2261                                                   cur->duration);
2262     /* Put in linked list */
2263     if (NULL == last)
2264       e->start = cur;
2265     else
2266       last->next = cur;
2267
2268     GNUNET_free (sec_name);
2269     e_counter++;
2270     last = cur;
2271   }
2272   return e_counter;
2273 }
2274
2275
2276 static void
2277 timeout_experiment (void *cls)
2278 {
2279   struct Experiment *e = cls;
2280
2281   e->experiment_timeout_task = NULL;
2282   fprintf (stderr, "Experiment timeout!\n");
2283
2284   if (NULL != e->episode_timeout_task)
2285   {
2286     GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
2287     e->episode_timeout_task = NULL;
2288   }
2289
2290   e->e_done_cb (e, GNUNET_TIME_absolute_get_duration (e->start_time),
2291                 GNUNET_SYSERR);
2292 }
2293
2294
2295 struct ATS_Address *
2296 create_ats_address (const struct GNUNET_PeerIdentity *peer,
2297                     const char *plugin_name,
2298                     const void *plugin_addr,
2299                     size_t plugin_addr_len,
2300                     uint32_t session_id,
2301                     uint32_t network)
2302 {
2303   struct ATS_Address *aa = NULL;
2304
2305   aa = GNUNET_malloc (sizeof(struct ATS_Address) + plugin_addr_len + strlen (
2306                         plugin_name) + 1);
2307   aa->atsi = GNUNET_new (struct GNUNET_ATS_Information);
2308   aa->atsi[0].type = htonl (GNUNET_ATS_NETWORK_TYPE);
2309   aa->atsi[0].value = htonl (network);
2310   aa->atsi_count = 1;
2311
2312   aa->peer = *peer;
2313   aa->addr_len = plugin_addr_len;
2314   aa->addr = &aa[1];
2315   aa->plugin = (char *) &aa[1] + plugin_addr_len;
2316   GNUNET_memcpy (&aa[1], plugin_addr, plugin_addr_len);
2317   GNUNET_memcpy (aa->plugin, plugin_name, strlen (plugin_name) + 1);
2318   aa->session_id = session_id;
2319
2320   return aa;
2321 }
2322
2323
2324 static void
2325 enforce_add_address (struct GNUNET_ATS_TEST_Operation *op)
2326 {
2327   struct TestPeer *p;
2328   struct TestAddress *a;
2329   int c;
2330
2331   if (NULL == (p = find_peer_by_id (op->peer_id)))
2332   {
2333     p = GNUNET_new (struct TestPeer);
2334     p->id = op->peer_id;
2335     p->assigned_bw_in = 0;
2336     p->assigned_bw_out = 0;
2337     memset (&p->peer_id, op->peer_id, sizeof(p->peer_id));
2338     for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
2339     {
2340       p->pref_abs[c] = DEFAULT_ABS_PREFERENCE;
2341       p->pref_norm[c] = DEFAULT_REL_PREFERENCE;
2342     }
2343
2344     GNUNET_CONTAINER_DLL_insert (peer_head, peer_tail, p);
2345   }
2346
2347   if (NULL != (find_address_by_id (p, op->address_id)))
2348   {
2349     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Duplicate address %u for peer %u\n",
2350                 op->address_id, op->peer_id);
2351     return;
2352   }
2353
2354   a = GNUNET_new (struct TestAddress);
2355   a->aid = op->address_id;
2356   a->network = op->address_network;
2357   a->ats_addr = create_ats_address (&p->peer_id, op->plugin, op->address,
2358                                     strlen (op->address) + 1,
2359                                     op->address_session, op->address_network);
2360   memset (&p->peer_id, op->peer_id, sizeof(p->peer_id));
2361   GNUNET_CONTAINER_DLL_insert_tail (p->addr_head, p->addr_tail, a);
2362
2363   for (c = 0; c < GNUNET_ATS_PropertyCount; c++)
2364     a->prop_norm[c] = DEFAULT_REL_QUALITY;
2365
2366   GNUNET_CONTAINER_multipeermap_put (sh->addresses, &p->peer_id, a->ats_addr,
2367                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2368
2369   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2370               "Adding address %u for peer %u in network `%s'\n",
2371               op->address_id, op->peer_id, GNUNET_NT_to_string (a->network));
2372
2373   sh->sf->s_add (sh->sf->cls, a->ats_addr, op->address_network);
2374 }
2375
2376
2377 static void
2378 enforce_del_address (struct GNUNET_ATS_TEST_Operation *op)
2379 {
2380   struct TestPeer *p;
2381   struct TestAddress *a;
2382   struct PropertyGenerator *pg;
2383
2384   if (NULL == (p = find_peer_by_id (op->peer_id)))
2385   {
2386     GNUNET_break (0);
2387     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2388                 "Deleting address for unknown peer %u\n", op->peer_id);
2389     return;
2390   }
2391
2392   if (NULL == (a = find_address_by_id (p, op->address_id)))
2393   {
2394     GNUNET_break (0);
2395     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2396                 "Deleting address for unknown peer %u\n", op->peer_id);
2397     return;
2398   }
2399
2400   while (NULL != (pg = find_prop_gen (p->id, a->aid, 0)))
2401   {
2402     GNUNET_ATS_solver_generate_property_stop (pg);
2403   }
2404
2405   GNUNET_assert (GNUNET_YES ==
2406                  GNUNET_CONTAINER_multipeermap_remove (sh->addresses,
2407                                                        &p->peer_id,
2408                                                        a->ats_addr));
2409   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2410               "Removing address %u for peer %u\n",
2411               op->address_id,
2412               op->peer_id);
2413
2414   sh->sf->s_del (sh->sf->cls, a->ats_addr);
2415
2416   if (NULL != l)
2417   {
2418     GNUNET_ATS_solver_logging_now (l);
2419   }
2420   GNUNET_CONTAINER_DLL_remove (p->addr_head, p->addr_tail, a);
2421
2422   GNUNET_free_non_null (a->ats_addr->atsi);
2423   GNUNET_free (a->ats_addr);
2424   GNUNET_free (a);
2425 }
2426
2427
2428 static void
2429 enforce_start_property (struct GNUNET_ATS_TEST_Operation *op)
2430 {
2431   struct PropertyGenerator *pg;
2432   struct TestPeer *p;
2433   struct TestAddress *a;
2434
2435   if (NULL != (pg = find_prop_gen (op->peer_id, op->address_id, op->prop_type)))
2436   {
2437     GNUNET_ATS_solver_generate_property_stop (pg);
2438     GNUNET_free (pg);
2439   }
2440
2441   if (NULL == (p = find_peer_by_id (op->peer_id)))
2442   {
2443     GNUNET_break (0);
2444     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2445                 "Starting property generation for unknown peer %u\n",
2446                 op->peer_id);
2447     return;
2448   }
2449
2450   if (NULL == (a = find_address_by_id (p, op->address_id)))
2451   {
2452     GNUNET_break (0);
2453     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2454                 "Setting property for unknown address %u\n", op->peer_id);
2455     return;
2456   }
2457
2458   GNUNET_ATS_solver_generate_property_start (op->peer_id,
2459                                              op->address_id,
2460                                              p, a,
2461                                              op->gen_type,
2462                                              op->base_rate,
2463                                              op->max_rate,
2464                                              op->period,
2465                                              op->frequency,
2466                                              op->prop_type);
2467 }
2468
2469
2470 static void
2471 enforce_stop_property (struct GNUNET_ATS_TEST_Operation *op)
2472 {
2473   struct PropertyGenerator *pg = find_prop_gen (op->peer_id, op->address_id,
2474                                                 op->prop_type);
2475
2476   if (NULL != pg)
2477   {
2478     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2479                 "Stopping preference generation for peer %u address %u\n",
2480                 op->peer_id,
2481                 op->address_id);
2482     GNUNET_ATS_solver_generate_property_stop (pg);
2483   }
2484   else
2485   {
2486     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2487                 "Cannot find preference generator for peer %u address %u\n",
2488                 op->peer_id, op->address_id);
2489     GNUNET_break (0);
2490   }
2491 }
2492
2493
2494 static void
2495 enforce_start_preference (struct GNUNET_ATS_TEST_Operation *op)
2496 {
2497   struct PreferenceGenerator *pg;
2498
2499   if (NULL != (pg = find_pref_gen (op->peer_id, op->pref_type)))
2500   {
2501     GNUNET_ATS_solver_generate_preferences_stop (pg);
2502     GNUNET_free (pg);
2503   }
2504
2505   if (NULL == (find_peer_by_id (op->peer_id)))
2506   {
2507     GNUNET_break (0);
2508     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2509                 "Starting preference generation for unknown peer %u\n",
2510                 op->peer_id);
2511     return;
2512   }
2513
2514   GNUNET_ATS_solver_generate_preferences_start (op->peer_id,
2515                                                 op->address_id,
2516                                                 op->client_id,
2517                                                 op->gen_type,
2518                                                 op->base_rate,
2519                                                 op->max_rate,
2520                                                 op->period,
2521                                                 op->frequency,
2522                                                 op->pref_type,
2523                                                 op->frequency);
2524 }
2525
2526
2527 static void
2528 enforce_stop_preference (struct GNUNET_ATS_TEST_Operation *op)
2529 {
2530   struct PreferenceGenerator *pg = find_pref_gen (op->peer_id,
2531                                                   op->pref_type);
2532
2533   if (NULL != pg)
2534   {
2535     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2536                 "Stopping property generation for peer %u address %u\n",
2537                 op->peer_id,
2538                 op->address_id);
2539     GNUNET_ATS_solver_generate_preferences_stop (pg);
2540   }
2541   else
2542   {
2543     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2544                 "Cannot find preference generator for peer %u address %u\n",
2545                 op->peer_id, op->address_id);
2546     GNUNET_break (0);
2547   }
2548 }
2549
2550
2551 static void
2552 enforce_start_request (struct GNUNET_ATS_TEST_Operation *op)
2553 {
2554   struct TestPeer *p;
2555
2556   if (NULL == (p = find_peer_by_id (op->peer_id)))
2557   {
2558     GNUNET_break (0);
2559     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2560                 "Requesting address for unknown peer %u\n", op->peer_id);
2561     return;
2562   }
2563
2564   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Requesting address for peer %u\n",
2565               op->peer_id);
2566   p->is_requested = GNUNET_YES;
2567
2568   sh->sf->s_get (sh->sf->cls, &p->peer_id);
2569 }
2570
2571
2572 static void
2573 enforce_stop_request (struct GNUNET_ATS_TEST_Operation *op)
2574 {
2575   struct TestPeer *p;
2576
2577   if (NULL == (p = find_peer_by_id (op->peer_id)))
2578   {
2579     GNUNET_break (0);
2580     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2581                 "Requesting address for unknown peer %u\n", op->peer_id);
2582     return;
2583   }
2584
2585   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2586               "Stop requesting address for peer %u\n",
2587               op->peer_id);
2588   p->is_requested = GNUNET_NO;
2589   p->assigned_bw_in = 0;
2590   p->assigned_bw_out = 0;
2591   sh->sf->s_get_stop (sh->sf->cls, &p->peer_id);
2592
2593   if (NULL != l)
2594   {
2595     GNUNET_ATS_solver_logging_now (l);
2596   }
2597 }
2598
2599
2600 static void
2601 enforce_episode (struct Episode *ep)
2602 {
2603   struct GNUNET_ATS_TEST_Operation *cur;
2604
2605   for (cur = ep->head; NULL != cur; cur = cur->next)
2606   {
2607     switch (cur->type)
2608     {
2609     case SOLVER_OP_ADD_ADDRESS:
2610       fprintf (stderr, "Enforcing operation: %s [%llu:%llu]\n",
2611                print_op (cur->type), cur->peer_id, cur->address_id);
2612       enforce_add_address (cur);
2613       break;
2614
2615     case SOLVER_OP_DEL_ADDRESS:
2616       fprintf (stderr, "Enforcing operation: %s [%llu:%llu]\n",
2617                print_op (cur->type), cur->peer_id, cur->address_id);
2618       enforce_del_address (cur);
2619       break;
2620
2621     case SOLVER_OP_START_SET_PROPERTY:
2622       fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
2623                print_op (cur->type), cur->peer_id, cur->address_id,
2624                cur->base_rate);
2625       enforce_start_property (cur);
2626       break;
2627
2628     case SOLVER_OP_STOP_SET_PROPERTY:
2629       fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
2630                print_op (cur->type), cur->peer_id, cur->address_id,
2631                cur->base_rate);
2632       enforce_stop_property (cur);
2633       break;
2634
2635     case SOLVER_OP_START_SET_PREFERENCE:
2636       fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
2637                print_op (cur->type), cur->peer_id, cur->address_id,
2638                cur->base_rate);
2639       enforce_start_preference (cur);
2640       break;
2641
2642     case SOLVER_OP_STOP_SET_PREFERENCE:
2643       fprintf (stderr, "Enforcing operation: %s [%llu:%llu] == %llu\n",
2644                print_op (cur->type), cur->peer_id, cur->address_id,
2645                cur->base_rate);
2646       enforce_stop_preference (cur);
2647       break;
2648
2649     case SOLVER_OP_START_REQUEST:
2650       fprintf (stderr, "Enforcing operation: %s [%llu]\n",
2651                print_op (cur->type), cur->peer_id);
2652       enforce_start_request (cur);
2653       break;
2654
2655     case SOLVER_OP_STOP_REQUEST:
2656       fprintf (stderr, "Enforcing operation: %s [%llu]\n",
2657                print_op (cur->type), cur->peer_id);
2658       enforce_stop_request (cur);
2659       break;
2660
2661     default:
2662       break;
2663     }
2664   }
2665 }
2666
2667
2668 static void
2669 timeout_episode (void *cls)
2670 {
2671   struct Experiment *e = cls;
2672
2673   e->episode_timeout_task = NULL;
2674   if (NULL != e->ep_done_cb)
2675     e->ep_done_cb (e->cur);
2676
2677   /* Scheduling next */
2678   e->cur = e->cur->next;
2679   if (NULL == e->cur)
2680   {
2681     /* done */
2682     fprintf (stderr, "Last episode done!\n");
2683     if (NULL != e->experiment_timeout_task)
2684     {
2685       GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
2686       e->experiment_timeout_task = NULL;
2687     }
2688     e->e_done_cb (e, GNUNET_TIME_absolute_get_duration (e->start_time),
2689                   GNUNET_OK);
2690     return;
2691   }
2692
2693   fprintf (stderr, "Running episode %u with timeout %s\n",
2694            e->cur->id,
2695            GNUNET_STRINGS_relative_time_to_string (e->cur->duration,
2696                                                    GNUNET_YES));
2697   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
2698                                                           &timeout_episode, e);
2699   enforce_episode (e->cur);
2700 }
2701
2702
2703 void
2704 GNUNET_ATS_solvers_experimentation_run (struct Experiment *e,
2705                                         GNUNET_ATS_TESTING_EpisodeDoneCallback
2706                                         ep_done_cb,
2707                                         GNUNET_ATS_TESTING_ExperimentDoneCallback
2708                                         e_done_cb)
2709 {
2710   fprintf (stderr, "Running experiment `%s'  with timeout %s\n", e->name,
2711            GNUNET_STRINGS_relative_time_to_string (e->max_duration,
2712                                                    GNUNET_YES));
2713   e->e_done_cb = e_done_cb;
2714   e->ep_done_cb = ep_done_cb;
2715   e->start_time = GNUNET_TIME_absolute_get ();
2716
2717   /* Start total time out */
2718   e->experiment_timeout_task = GNUNET_SCHEDULER_add_delayed (e->max_duration,
2719                                                              &timeout_experiment,
2720                                                              e);
2721
2722   /* Start */
2723   if (NULL == e->start)
2724   {
2725     GNUNET_break (0);
2726     return;
2727   }
2728
2729   e->cur = e->start;
2730   fprintf (stderr, "Running episode %u with timeout %s\n",
2731            e->cur->id,
2732            GNUNET_STRINGS_relative_time_to_string (e->cur->duration,
2733                                                    GNUNET_YES));
2734   e->episode_timeout_task = GNUNET_SCHEDULER_add_delayed (e->cur->duration,
2735                                                           &timeout_episode, e);
2736   enforce_episode (e->cur);
2737 }
2738
2739
2740 void
2741 GNUNET_ATS_solvers_experimentation_stop (struct Experiment *e)
2742 {
2743   if (NULL != e->experiment_timeout_task)
2744   {
2745     GNUNET_SCHEDULER_cancel (e->experiment_timeout_task);
2746     e->experiment_timeout_task = NULL;
2747   }
2748   if (NULL != e->episode_timeout_task)
2749   {
2750     GNUNET_SCHEDULER_cancel (e->episode_timeout_task);
2751     e->episode_timeout_task = NULL;
2752   }
2753   if (NULL != e->cfg)
2754   {
2755     GNUNET_CONFIGURATION_destroy (e->cfg);
2756     e->cfg = NULL;
2757   }
2758   free_experiment (e);
2759 }
2760
2761
2762 struct Experiment *
2763 GNUNET_ATS_solvers_experimentation_load (char *filename)
2764 {
2765   struct Experiment *e;
2766   struct GNUNET_CONFIGURATION_Handle *cfg;
2767
2768   e = NULL;
2769
2770   cfg = GNUNET_CONFIGURATION_create ();
2771   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, filename))
2772   {
2773     fprintf (stderr, "Failed to load `%s'\n", filename);
2774     GNUNET_CONFIGURATION_destroy (cfg);
2775     return NULL;
2776   }
2777
2778   e = create_experiment ();
2779
2780   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "experiment",
2781                                                               "name", &e->name))
2782   {
2783     fprintf (stderr, "Invalid %s \n", "name");
2784     free_experiment (e);
2785     return NULL;
2786   }
2787   else
2788     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment name: `%s'\n", e->name);
2789
2790   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_string (cfg, "experiment",
2791                                                               "log_prefix",
2792                                                               &e->log_prefix))
2793   {
2794     fprintf (stderr, "Invalid %s \n", "log_prefix");
2795     free_experiment (e);
2796     return NULL;
2797   }
2798   else
2799     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment logging prefix: `%s'\n",
2800                 e->log_prefix);
2801
2802   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg,
2803                                                                 "experiment",
2804                                                                 "log_output_dir",
2805                                                                 &e->
2806                                                                 log_output_dir))
2807   {
2808     e->log_output_dir = NULL;
2809   }
2810   else
2811     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2812                 "Experiment logging output directory: `%s'\n",
2813                 e->log_output_dir);
2814
2815
2816   if (GNUNET_SYSERR == (e->log_append_time_stamp =
2817                           GNUNET_CONFIGURATION_get_value_yesno (cfg,
2818                                                                 "experiment",
2819                                                                 "log_append_time_stamp")))
2820     e->log_append_time_stamp = GNUNET_YES;
2821   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2822               "Experiment logging append timestamp: `%s'\n",
2823               (GNUNET_YES == e->log_append_time_stamp) ? "yes" : "no");
2824
2825
2826   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_filename (cfg,
2827                                                                 "experiment",
2828                                                                 "cfg_file",
2829                                                                 &e->cfg_file))
2830   {
2831     fprintf (stderr, "Invalid %s \n", "cfg_file");
2832     free_experiment (e);
2833     return NULL;
2834   }
2835   else
2836   {
2837     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment configuration: `%s'\n",
2838                 e->cfg_file);
2839     e->cfg = GNUNET_CONFIGURATION_create ();
2840     if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (e->cfg, e->cfg_file))
2841     {
2842       fprintf (stderr, "Invalid configuration %s \n", "cfg_file");
2843       free_experiment (e);
2844       return NULL;
2845     }
2846   }
2847
2848   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg, "experiment",
2849                                                             "log_freq",
2850                                                             &e->log_freq))
2851   {
2852     fprintf (stderr, "Invalid %s \n", "log_freq");
2853     free_experiment (e);
2854     return NULL;
2855   }
2856   else
2857     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment logging frequency: `%s'\n",
2858                 GNUNET_STRINGS_relative_time_to_string (e->log_freq,
2859                                                         GNUNET_YES));
2860
2861   if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (cfg, "experiment",
2862                                                             "max_duration",
2863                                                             &e->max_duration))
2864   {
2865     fprintf (stderr, "Invalid %s", "max_duration");
2866     free_experiment (e);
2867     return NULL;
2868   }
2869   else
2870     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment duration: `%s'\n",
2871                 GNUNET_STRINGS_relative_time_to_string (e->max_duration,
2872                                                         GNUNET_YES));
2873
2874   if (GNUNET_SYSERR == load_episodes (e, cfg))
2875   {
2876     GNUNET_ATS_solvers_experimentation_stop (e);
2877     GNUNET_CONFIGURATION_destroy (cfg);
2878     e = NULL;
2879     fprintf (stderr, "Failed to load experiment\n");
2880     return NULL;
2881   }
2882   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2883               "Loaded %u episodes with total duration %s\n",
2884               e->num_episodes,
2885               GNUNET_STRINGS_relative_time_to_string (e->total_duration,
2886                                                       GNUNET_YES));
2887
2888   GNUNET_CONFIGURATION_destroy (cfg);
2889   return e;
2890 }
2891
2892
2893 /**
2894  * Solver
2895  */
2896
2897 static int
2898 free_all_it (void *cls,
2899              const struct GNUNET_PeerIdentity *key,
2900              void *value)
2901 {
2902   struct ATS_Address *address = value;
2903
2904   GNUNET_break (GNUNET_OK == GNUNET_CONTAINER_multipeermap_remove (
2905                   sh->env.addresses,
2906                   key, value));
2907   GNUNET_free (address);
2908
2909   return GNUNET_OK;
2910 }
2911
2912
2913 void
2914 GNUNET_ATS_solvers_solver_stop (struct SolverHandle *sh)
2915 {
2916   GNUNET_STATISTICS_destroy ((struct GNUNET_STATISTICS_Handle *) sh->env.stats,
2917                              GNUNET_NO);
2918   GNUNET_PLUGIN_unload (sh->plugin, sh->sf);
2919   sh->sf = NULL;
2920   GAS_normalization_stop ();
2921
2922   GNUNET_CONTAINER_multipeermap_iterate (sh->addresses,
2923                                          &free_all_it,
2924                                          NULL);
2925   GNUNET_CONTAINER_multipeermap_destroy (sh->addresses);
2926   GNUNET_free (sh->plugin);
2927   GNUNET_free (sh);
2928 }
2929
2930
2931 /**
2932  * Load quotas for networks from configuration
2933  *
2934  * @param cfg configuration handle
2935  * @param out_dest where to write outbound quotas
2936  * @param in_dest where to write inbound quotas
2937  * @param dest_length length of inbound and outbound arrays
2938  * @return number of networks loaded
2939  */
2940 unsigned int
2941 GNUNET_ATS_solvers_load_quotas (const struct GNUNET_CONFIGURATION_Handle *cfg,
2942                                 unsigned long long *out_dest,
2943                                 unsigned long long *in_dest,
2944                                 int dest_length)
2945 {
2946   char *entry_in = NULL;
2947   char *entry_out = NULL;
2948   char *quota_out_str;
2949   char *quota_in_str;
2950   int c;
2951   int res;
2952
2953   for (c = 0; (c < GNUNET_NT_COUNT) && (c < dest_length); c++)
2954   {
2955     in_dest[c] = 0;
2956     out_dest[c] = 0;
2957     GNUNET_asprintf (&entry_out,
2958                      "%s_QUOTA_OUT",
2959                      GNUNET_NT_to_string (c));
2960     GNUNET_asprintf (&entry_in,
2961                      "%s_QUOTA_IN",
2962                      GNUNET_NT_to_string (c));
2963
2964     /* quota out */
2965     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "ats",
2966                                                             entry_out,
2967                                                             &quota_out_str))
2968     {
2969       res = GNUNET_NO;
2970       if (0 == strcmp (quota_out_str, BIG_M_STRING))
2971       {
2972         out_dest[c] = GNUNET_ATS_MaxBandwidth;
2973         res = GNUNET_YES;
2974       }
2975       if ((GNUNET_NO == res) && (GNUNET_OK ==
2976                                  GNUNET_STRINGS_fancy_size_to_bytes (
2977                                    quota_out_str, &out_dest[c])))
2978         res = GNUNET_YES;
2979       if ((GNUNET_NO == res) && (GNUNET_OK ==
2980                                  GNUNET_CONFIGURATION_get_value_number (cfg,
2981                                                                         "ats",
2982                                                                         entry_out,
2983                                                                         &
2984                                                                         out_dest
2985                                                                         [c])))
2986         res = GNUNET_YES;
2987
2988       if (GNUNET_NO == res)
2989       {
2990         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2991                     _ (
2992                       "Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
2993                     GNUNET_NT_to_string (c),
2994                     quota_out_str,
2995                     GNUNET_ATS_DefaultBandwidth);
2996         out_dest[c] = GNUNET_ATS_DefaultBandwidth;
2997       }
2998       else
2999       {
3000         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3001                     "Outbound quota configure for network `%s' is %llu\n",
3002                     GNUNET_NT_to_string (c),
3003                     out_dest[c]);
3004       }
3005       GNUNET_free (quota_out_str);
3006     }
3007     else
3008     {
3009       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3010                   _ (
3011                     "No outbound quota configured for network `%s', assigning default bandwidth %llu\n"),
3012                   GNUNET_NT_to_string (c),
3013                   GNUNET_ATS_DefaultBandwidth);
3014       out_dest[c] = GNUNET_ATS_DefaultBandwidth;
3015     }
3016
3017     /* quota in */
3018     if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (cfg, "ats",
3019                                                             entry_in,
3020                                                             &quota_in_str))
3021     {
3022       res = GNUNET_NO;
3023       if (0 == strcmp (quota_in_str, BIG_M_STRING))
3024       {
3025         in_dest[c] = GNUNET_ATS_MaxBandwidth;
3026         res = GNUNET_YES;
3027       }
3028       if ((GNUNET_NO == res) && (GNUNET_OK ==
3029                                  GNUNET_STRINGS_fancy_size_to_bytes (
3030                                    quota_in_str, &in_dest[c])))
3031         res = GNUNET_YES;
3032       if ((GNUNET_NO == res) && (GNUNET_OK ==
3033                                  GNUNET_CONFIGURATION_get_value_number (cfg,
3034                                                                         "ats",
3035                                                                         entry_in,
3036                                                                         &in_dest
3037                                                                         [c])))
3038         res = GNUNET_YES;
3039
3040       if (GNUNET_NO == res)
3041       {
3042         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3043                     _ (
3044                       "Could not load quota for network `%s':  `%s', assigning default bandwidth %llu\n"),
3045                     GNUNET_NT_to_string (c),
3046                     quota_in_str,
3047                     GNUNET_ATS_DefaultBandwidth);
3048         in_dest[c] = GNUNET_ATS_DefaultBandwidth;
3049       }
3050       else
3051       {
3052         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3053                     "Inbound quota configured for network `%s' is %llu\n",
3054                     GNUNET_NT_to_string (c),
3055                     in_dest[c]);
3056       }
3057       GNUNET_free (quota_in_str);
3058     }
3059     else
3060     {
3061       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3062                   _ (
3063                     "No outbound quota configure for network `%s', assigning default bandwidth %llu\n"),
3064                   GNUNET_NT_to_string (c),
3065                   GNUNET_ATS_DefaultBandwidth);
3066       out_dest[c] = GNUNET_ATS_DefaultBandwidth;
3067     }
3068     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3069                 "Loaded quota for network `%s' (in/out): %llu %llu\n",
3070                 GNUNET_NT_to_string (c),
3071                 in_dest[c],
3072                 out_dest[c]);
3073     GNUNET_free (entry_out);
3074     GNUNET_free (entry_in);
3075   }
3076   return GNUNET_NT_COUNT;
3077 }
3078
3079
3080 /**
3081  * Information callback for the solver
3082  *
3083  * @param cls the closure
3084  * @param op the solver operation
3085  * @param stat status of the solver operation
3086  * @param add additional solver information
3087  */
3088 static void
3089 solver_info_cb (void *cls,
3090                 enum GAS_Solver_Operation op,
3091                 enum GAS_Solver_Status stat,
3092                 enum GAS_Solver_Additional_Information add)
3093 {
3094   char *add_info;
3095
3096   switch (add)
3097   {
3098   case GAS_INFO_NONE:
3099     add_info = "GAS_INFO_NONE";
3100     break;
3101
3102   case GAS_INFO_FULL:
3103     add_info = "GAS_INFO_MLP_FULL";
3104     break;
3105
3106   case GAS_INFO_UPDATED:
3107     add_info = "GAS_INFO_MLP_UPDATED";
3108     break;
3109
3110   case GAS_INFO_PROP_ALL:
3111     add_info = "GAS_INFO_PROP_ALL";
3112     break;
3113
3114   case GAS_INFO_PROP_SINGLE:
3115     add_info = "GAS_INFO_PROP_SINGLE";
3116     break;
3117
3118   default:
3119     add_info = "INVALID";
3120     break;
3121   }
3122
3123   switch (op)
3124   {
3125   case GAS_OP_SOLVE_START:
3126     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3127                 "Solver notifies `%s' with result `%s' `%s'\n",
3128                 "GAS_OP_SOLVE_START",
3129                 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
3130     return;
3131
3132   case GAS_OP_SOLVE_STOP:
3133     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3134                 "Solver notifies `%s' with result `%s'\n", "GAS_OP_SOLVE_STOP",
3135                 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL", add_info);
3136     return;
3137
3138   case GAS_OP_SOLVE_SETUP_START:
3139     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3140                 "Solver notifies `%s' with result `%s'\n",
3141                 "GAS_OP_SOLVE_SETUP_START",
3142                 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3143     return;
3144
3145   case GAS_OP_SOLVE_SETUP_STOP:
3146     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3147                 "Solver notifies `%s' with result `%s'\n",
3148                 "GAS_OP_SOLVE_SETUP_STOP",
3149                 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3150     return;
3151
3152   case GAS_OP_SOLVE_MLP_LP_START:
3153     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3154                 "Solver notifies `%s' with result `%s'\n",
3155                 "GAS_OP_SOLVE_LP_START",
3156                 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3157     return;
3158
3159   case GAS_OP_SOLVE_MLP_LP_STOP:
3160     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3161                 "Solver notifies `%s' with result `%s'\n",
3162                 "GAS_OP_SOLVE_LP_STOP",
3163                 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3164     return;
3165
3166   case GAS_OP_SOLVE_MLP_MLP_START:
3167     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3168                 "Solver notifies `%s' with result `%s'\n",
3169                 "GAS_OP_SOLVE_MLP_START",
3170                 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3171     return;
3172
3173   case GAS_OP_SOLVE_MLP_MLP_STOP:
3174     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3175                 "Solver notifies `%s' with result `%s'\n",
3176                 "GAS_OP_SOLVE_MLP_STOP",
3177                 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3178     return;
3179
3180   case GAS_OP_SOLVE_UPDATE_NOTIFICATION_START:
3181     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3182                 "Solver notifies `%s' with result `%s'\n",
3183                 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_START",
3184                 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3185     return;
3186
3187   case GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP:
3188     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3189                 "Solver notifies `%s' with result `%s'\n",
3190                 "GAS_OP_SOLVE_UPDATE_NOTIFICATION_STOP",
3191                 (GAS_STAT_SUCCESS == stat) ? "SUCCESS" : "FAIL");
3192     return;
3193
3194   default:
3195     break;
3196   }
3197 }
3198
3199
3200 static void
3201 solver_bandwidth_changed_cb (void *cls, struct ATS_Address *address)
3202 {
3203   struct GNUNET_TIME_Relative duration;
3204   struct TestPeer *p;
3205   static struct PreferenceGenerator *pg;
3206   uint32_t delta;
3207
3208   if ((0 == address->assigned_bw_out) && (0 == address->assigned_bw_in))
3209   {
3210     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3211                 "Solver notified to disconnect peer `%s'\n",
3212                 GNUNET_i2s (&address->peer));
3213   }
3214   p = find_peer_by_pid (&address->peer);
3215   if (NULL == p)
3216     return;
3217   p->assigned_bw_out = address->assigned_bw_out;
3218   p->assigned_bw_in = address->assigned_bw_in;
3219
3220   for (pg = pref_gen_head; NULL != pg; pg = pg->next)
3221   {
3222     if (pg->peer == p->id)
3223     {
3224       duration = GNUNET_TIME_absolute_get_duration (
3225         pg->feedback_last_bw_update);
3226       delta = duration.rel_value_us * pg->last_assigned_bw_out;
3227       pg->feedback_bw_out_acc += delta;
3228
3229       delta = duration.rel_value_us * pg->last_assigned_bw_in;
3230       pg->feedback_bw_in_acc += delta;
3231
3232       pg->last_assigned_bw_in = address->assigned_bw_in;
3233       pg->last_assigned_bw_out = address->assigned_bw_out;
3234       pg->feedback_last_bw_update = GNUNET_TIME_absolute_get ();
3235     }
3236   }
3237
3238   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3239               "Bandwidth changed addresses %s %p to %u Bps out / %u Bps in\n",
3240               GNUNET_i2s (&address->peer),
3241               address,
3242               address->assigned_bw_out,
3243               address->assigned_bw_in);
3244
3245   if (NULL != l)
3246     GNUNET_ATS_solver_logging_now (l);
3247
3248   return;
3249 }
3250
3251
3252 const double *
3253 get_preferences_cb (void *cls, const struct GNUNET_PeerIdentity *id)
3254 {
3255   struct TestPeer *p;
3256
3257   if (GNUNET_YES == opt_disable_normalization)
3258   {
3259     if (NULL == (p = find_peer_by_pid (id)))
3260       return NULL;
3261     return p->pref_abs;
3262   }
3263   else
3264     return GAS_preference_get_by_peer (NULL,
3265                                        id);
3266 }
3267
3268
3269 struct SolverHandle *
3270 GNUNET_ATS_solvers_solver_start (enum GNUNET_ATS_Solvers type)
3271 {
3272   struct SolverHandle *sh;
3273   char *solver_str;
3274
3275   switch (type)
3276   {
3277   case GNUNET_ATS_SOLVER_PROPORTIONAL:
3278     solver_str = "proportional";
3279     break;
3280
3281   case GNUNET_ATS_SOLVER_MLP:
3282     solver_str = "mlp";
3283     break;
3284
3285   case GNUNET_ATS_SOLVER_RIL:
3286     solver_str = "ril";
3287     break;
3288
3289   default:
3290     GNUNET_break (0);
3291     return NULL;
3292     break;
3293   }
3294
3295   sh = GNUNET_new (struct SolverHandle);
3296   GNUNET_asprintf (&sh->plugin,
3297                    "libgnunet_plugin_ats_%s",
3298                    solver_str);
3299   sh->addresses = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
3300
3301   /* setup environment */
3302   sh->env.cfg = e->cfg;
3303   sh->env.stats = GNUNET_STATISTICS_create ("ats", e->cfg);
3304   sh->env.addresses = sh->addresses;
3305   sh->env.bandwidth_changed_cb = &solver_bandwidth_changed_cb;
3306   sh->env.get_preferences = &get_preferences_cb;
3307   sh->env.network_count = GNUNET_NT_COUNT;
3308   sh->env.info_cb = &solver_info_cb;
3309   sh->env.network_count = GNUNET_NT_COUNT;
3310
3311   /* start normalization */
3312   GAS_normalization_start ();
3313
3314   /* load quotas */
3315   if (GNUNET_NT_COUNT != GNUNET_ATS_solvers_load_quotas (e->cfg,
3316                                                          sh->env.out_quota,
3317                                                          sh->env.in_quota,
3318                                                          GNUNET_NT_COUNT))
3319   {
3320     GNUNET_break (0);
3321     GNUNET_free (sh->plugin);
3322     GNUNET_free (sh);
3323     end_now ();
3324     return NULL;
3325   }
3326
3327   sh->sf = GNUNET_PLUGIN_load (sh->plugin, &sh->env);
3328   if (NULL == sh->sf)
3329   {
3330     fprintf (stderr, "Failed to load solver `%s'\n", sh->plugin);
3331     GNUNET_break (0);
3332     GNUNET_free (sh->plugin);
3333     GNUNET_free (sh);
3334     end_now ();
3335     return NULL;
3336   }
3337   return sh;
3338 }
3339
3340
3341 static void
3342 done ()
3343 {
3344   struct TestPeer *cur;
3345   struct TestPeer *next;
3346
3347   struct TestAddress *cur_a;
3348   struct TestAddress *next_a;
3349
3350   /* Stop logging */
3351   GNUNET_ATS_solver_logging_stop (l);
3352
3353   /* Stop all preference generation */
3354   GNUNET_ATS_solver_generate_preferences_stop_all ();
3355
3356   /* Stop all property generation */
3357   GNUNET_ATS_solver_generate_property_stop_all ();
3358
3359   if (opt_print)
3360   {
3361     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "== Printing log information \n");
3362     GNUNET_ATS_solver_logging_eval (l);
3363   }
3364   if (opt_save)
3365   {
3366     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "== Saving log information \n");
3367     GNUNET_ATS_solver_logging_write_to_disk (l, e->log_append_time_stamp,
3368                                              e->log_output_dir);
3369   }
3370
3371   if (NULL != l)
3372   {
3373     GNUNET_ATS_solver_logging_free (l);
3374     l = NULL;
3375   }
3376
3377   /* Clean up experiment */
3378   if (NULL != e)
3379   {
3380     GNUNET_ATS_solvers_experimentation_stop (e);
3381     e = NULL;
3382   }
3383
3384   next = peer_head;
3385   while (NULL != (cur = next))
3386   {
3387     next = cur->next;
3388     GNUNET_CONTAINER_DLL_remove (peer_head, peer_tail, cur);
3389     next_a = cur->addr_head;
3390     while (NULL != (cur_a = next_a))
3391     {
3392       next_a = cur_a->next;
3393       GNUNET_CONTAINER_DLL_remove (cur->addr_head, cur->addr_tail, cur_a);
3394       GNUNET_free (cur_a);
3395     }
3396     GNUNET_free (cur);
3397   }
3398   if (NULL != sh)
3399   {
3400     GNUNET_ATS_solvers_solver_stop (sh);
3401     sh = NULL;
3402   }
3403
3404   /* Shutdown */
3405   end_now ();
3406 }
3407
3408
3409 static void
3410 experiment_done_cb (struct Experiment *e, struct GNUNET_TIME_Relative duration,
3411                     int success)
3412 {
3413   if (GNUNET_OK == success)
3414     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment done successful in %s\n",
3415                 GNUNET_STRINGS_relative_time_to_string (duration, GNUNET_YES));
3416   else
3417     GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Experiment failed \n");
3418
3419   GNUNET_SCHEDULER_add_now (&done, NULL);
3420 }
3421
3422
3423 static void
3424 episode_done_cb (struct Episode *ep)
3425 {
3426   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Episode %u done\n", ep->id);
3427 }
3428
3429
3430 /**
3431  * Do shutdown
3432  */
3433 static void
3434 end_now ()
3435 {
3436   if (NULL != e)
3437   {
3438     GNUNET_ATS_solvers_experimentation_stop (e);
3439     e = NULL;
3440   }
3441   if (NULL != sh)
3442   {
3443     GNUNET_ATS_solvers_solver_stop (sh);
3444     sh = NULL;
3445   }
3446 }
3447
3448
3449 static void
3450 run (void *cls, char *const *args, const char *cfgfile,
3451      const struct GNUNET_CONFIGURATION_Handle *cfg)
3452 {
3453   enum GNUNET_ATS_Solvers solver;
3454   int c;
3455
3456   if (NULL == opt_exp_file)
3457   {
3458     fprintf (stderr, "No experiment given ...\n");
3459     res = 1;
3460     end_now ();
3461     return;
3462   }
3463
3464   if (NULL == opt_solver)
3465   {
3466     fprintf (stderr, "No solver given ...\n");
3467     res = 1;
3468     end_now ();
3469     return;
3470   }
3471
3472   if (0 == strcmp (opt_solver, "mlp"))
3473   {
3474     solver = GNUNET_ATS_SOLVER_MLP;
3475   }
3476   else if (0 == strcmp (opt_solver, "proportional"))
3477   {
3478     solver = GNUNET_ATS_SOLVER_PROPORTIONAL;
3479   }
3480   else if (0 == strcmp (opt_solver, "ril"))
3481   {
3482     solver = GNUNET_ATS_SOLVER_RIL;
3483   }
3484   else
3485   {
3486     fprintf (stderr, "No solver given ...");
3487     res = 1;
3488     end_now ();
3489     return;
3490   }
3491
3492   for (c = 0; c < GNUNET_ATS_PropertyCount; c++)
3493     default_properties[c] = DEFAULT_REL_QUALITY;
3494
3495   for (c = 0; c < GNUNET_ATS_PreferenceCount; c++)
3496     default_preferences[c] = DEFAULT_REL_PREFERENCE;
3497
3498   /* load experiment */
3499   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "=== Loading experiment\n");
3500   e = GNUNET_ATS_solvers_experimentation_load (opt_exp_file);
3501   if (NULL == e)
3502   {
3503     fprintf (stderr, "Failed to load experiment ...\n");
3504     res = 1;
3505     end_now ();
3506     return;
3507   }
3508
3509   /* load solver */
3510   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "=== Loading solver\n");
3511   sh = GNUNET_ATS_solvers_solver_start (solver);
3512   if (NULL == sh)
3513   {
3514     fprintf (stderr, "Failed to start solver ...\n");
3515     end_now ();
3516     res = 1;
3517     return;
3518   }
3519
3520   /* start logging */
3521   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "=== Start logging \n");
3522   l = GNUNET_ATS_solver_logging_start (e->log_freq);
3523
3524   /* run experiment */
3525   GNUNET_log (GNUNET_ERROR_TYPE_INFO, "=== Running experiment \n");
3526   GNUNET_ATS_solvers_experimentation_run (e, episode_done_cb,
3527                                           experiment_done_cb);
3528
3529   /* WAIT */
3530 }
3531
3532
3533 /**
3534  * Main function of the benchmark
3535  *
3536  * @param argc argument count
3537  * @param argv argument values
3538  */
3539 int
3540 main (int argc, char *argv[])
3541 {
3542   opt_exp_file = NULL;
3543   opt_solver = NULL;
3544   opt_log = GNUNET_NO;
3545   opt_save = GNUNET_NO;
3546
3547   res = 0;
3548
3549   static struct GNUNET_GETOPT_CommandLineOption options[] = {
3550     GNUNET_GETOPT_option_string ('s',
3551                                  "solver",
3552                                  gettext_noop ("solver to use"),
3553                                  &opt_solver),
3554
3555     GNUNET_GETOPT_option_string ('e',
3556                                  "experiment"
3557                                  gettext_noop ("experiment to use"),
3558                                  &opt_exp_file),
3559
3560     GNUNET_GETOPT_option_verbose (&opt_verbose),
3561
3562     GNUNET_GETOPT_option_flag ('p',
3563                                "print",
3564                                gettext_noop ("print logging"),
3565                                &opt_print),
3566
3567     GNUNET_GETOPT_option_flag ('f',
3568                                "file",
3569                                gettext_noop ("save logging to disk"),
3570                                &opt_save),
3571
3572     GNUNET_GETOPT_option_flag ('d',
3573                                "dn",
3574                                gettext_noop ("disable normalization"),
3575                                &opt_disable_normalization),
3576
3577     GNUNET_GETOPT_OPTION_END
3578   };
3579
3580   GNUNET_PROGRAM_run (argc, argv, "gnunet-ats-solver-eval",
3581                       NULL, options, &run, argv[0]);
3582
3583   return res;
3584 }
3585
3586
3587 /* end of file ats-testing-experiment.c*/