small whitespace change
[oweals/gnunet.git] / src / testing / testing_group.c
1 /*
2       This file is part of GNUnet
3       (C) 2008, 2009 Christian Grothoff (and other contributing authors)
4
5       GNUnet is free software; you can redistribute it and/or modify
6       it under the terms of the GNU General Public License as published
7       by the Free Software Foundation; either version 2, or (at your
8       option) any later version.
9
10       GNUnet is distributed in the hope that it will be useful, but
11       WITHOUT ANY WARRANTY; without even the implied warranty of
12       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13       General Public License for more details.
14
15       You should have received a copy of the GNU General Public License
16       along with GNUnet; see the file COPYING.  If not, write to the
17       Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18       Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * @file testing/testing_group.c
23  * @brief convenience API for writing testcases for GNUnet
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_arm_service.h"
28 #include "gnunet_testing_lib.h"
29
30 #define VERBOSE_TESTING GNUNET_YES
31
32 /**
33  * Lowest port used for GNUnet testing.  Should be high enough to not
34  * conflict with other applications running on the hosts but be low
35  * enough to not conflict with client-ports (typically starting around
36  * 32k).
37  */
38 #define LOW_PORT 10000
39
40 /**
41  * Highest port used for GNUnet testing.  Should be low enough to not
42  * conflict with the port range for "local" ports (client apps; see
43  * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
44  */
45 #define HIGH_PORT 32000
46
47 #define MAX_OUTSTANDING_CONNECTIONS 50
48
49 #define CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 180)
50
51 struct PeerConnection
52 {
53   /*
54    * Linked list
55    */
56   struct PeerConnection *next;
57
58   /*
59    * Pointer to daemon handle
60    */
61   struct GNUNET_TESTING_Daemon *daemon;
62
63 };
64
65 /**
66  * Data we keep per peer.
67  */
68 struct PeerData
69 {
70   /**
71    * (Initial) configuration of the host.
72    * (initial because clients could change
73    *  it and we would not know about those
74    *  updates).
75    */
76   struct GNUNET_CONFIGURATION_Handle *cfg;
77
78   /**
79    * Handle for controlling the daemon.
80    */
81   struct GNUNET_TESTING_Daemon *daemon;
82
83   /*
84    * Linked list of peer connections (simply indexes of PeerGroup)
85    * FIXME: Question, store pointer or integer?  Pointer for now...
86    */
87   struct PeerConnection *connected_peers;
88 };
89
90
91 /**
92  * Data we keep per host.
93  */
94 struct HostData
95 {
96   /**
97    * Name of the host.
98    */
99   char *hostname;
100
101   /**
102    * Lowest port that we have not yet used
103    * for GNUnet.
104    */
105   uint16_t minport;
106 };
107
108
109 /**
110  * Handle to a group of GNUnet peers.
111  */
112 struct GNUNET_TESTING_PeerGroup
113 {
114   /**
115    * Our scheduler.
116    */
117   struct GNUNET_SCHEDULER_Handle *sched;
118
119   /**
120    * Configuration template.
121    */
122   const struct GNUNET_CONFIGURATION_Handle *cfg;
123
124   /**
125    * Function to call on each started daemon.
126    */
127   GNUNET_TESTING_NotifyDaemonRunning cb;
128
129   /**
130    * Closure for cb.
131    */
132   void *cb_cls;
133
134   /*
135    * Function to call on each topology connection created
136    */
137   GNUNET_TESTING_NotifyConnection notify_connection;
138
139   /*
140    * Callback for notify_connection
141    */
142   void *notify_connection_cls;
143
144   /**
145    * NULL-terminated array of information about
146    * hosts.
147    */
148   struct HostData *hosts;
149
150   /**
151    * Array of "total" peers.
152    */
153   struct PeerData *peers;
154
155   /**
156    * Number of peers in this group.
157    */
158   unsigned int total;
159
160 };
161
162
163 struct UpdateContext
164 {
165   struct GNUNET_CONFIGURATION_Handle *ret;
166   unsigned int nport;
167 };
168
169
170 struct ConnectContext
171 {
172   struct GNUNET_TESTING_Daemon *first;
173
174   struct GNUNET_TESTING_Daemon *second;
175
176   struct GNUNET_TESTING_PeerGroup *pg;
177 };
178
179 /**
180  * Number of connects we are waiting on, allows us to rate limit
181  * connect attempts.
182  */
183 static int outstanding_connects;
184
185 /**
186  * Function to iterate over options.  Copies
187  * the options to the target configuration,
188  * updating PORT values as needed.
189  *
190  * @param cls closure
191  * @param section name of the section
192  * @param option name of the option
193  * @param value value of the option
194  */
195 static void
196 update_config (void *cls,
197                const char *section, const char *option, const char *value)
198 {
199   struct UpdateContext *ctx = cls;
200   unsigned int ival;
201   char cval[12];
202
203   if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
204     {
205       GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++);
206       value = cval;
207     }
208   GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value);
209 }
210
211
212 /**
213  * Create a new configuration using the given configuration
214  * as a template; however, each PORT in the existing cfg
215  * must be renumbered by incrementing "*port".  If we run
216  * out of "*port" numbers, return NULL.
217  *
218  * @param cfg template configuration
219  * @param port port numbers to use, update to reflect
220  *             port numbers that were used
221  * @return new configuration, NULL on error
222  */
223 static struct GNUNET_CONFIGURATION_Handle *
224 make_config (const struct GNUNET_CONFIGURATION_Handle *cfg, uint16_t * port)
225 {
226   struct UpdateContext uc;
227   uint16_t orig;
228   char *control_host;
229   char *allowed_hosts;
230
231   orig = *port;
232   uc.nport = *port;
233   uc.ret = GNUNET_CONFIGURATION_create ();
234
235   GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
236   if (uc.nport >= HIGH_PORT)
237     {
238       *port = orig;
239       GNUNET_CONFIGURATION_destroy (uc.ret);
240       return NULL;
241     }
242
243   if (GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "control_host", &control_host) == GNUNET_OK)
244     {
245       GNUNET_asprintf(&allowed_hosts, "%s; 127.0.0.1;", control_host);
246       fprintf(stderr, "FOUND CONTROL_HOST OPTION %s, setting to %s\n", control_host, allowed_hosts);
247       GNUNET_CONFIGURATION_set_value_string(uc.ret, "core", "ACCEPT_FROM", allowed_hosts);
248       GNUNET_free(allowed_hosts);
249     }
250
251   *port = (uint16_t) uc.nport;
252   return uc.ret;
253 }
254
255 /*
256  * Add entries to the peers connected list
257  *
258  * @param pg the peer group we are working with
259  * @param first index of the first peer
260  * @param second index of the second peer
261  *
262  * @return the number of connections added (can be 0, 1 or 2)
263  *
264  * FIXME: add both, or only add one?
265  *      - if both are added, then we have to keep track
266  *        when connecting so we don't double connect
267  *      - if only one is added, we need to iterate over
268  *        both lists to find out if connection already exists
269  *      - having both allows the whitelisting/friend file
270  *        creation to be easier
271  *
272  *      -- For now, add both, we have to iterate over each to
273  *         check for duplicates anyways, so we'll take the performance
274  *         hit assuming we don't have __too__ many connections
275  *
276  */
277 static int
278 add_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
279 {
280   int added;
281   struct PeerConnection *first_iter;
282   struct PeerConnection *second_iter;
283   int add_first;
284   int add_second;
285   struct PeerConnection *new_first;
286   struct PeerConnection *new_second;
287
288   first_iter = pg->peers[first].connected_peers;
289   add_first = GNUNET_YES;
290   while (first_iter != NULL)
291     {
292       if (first_iter->daemon == pg->peers[second].daemon)
293         add_first = GNUNET_NO;
294       first_iter = first_iter->next;
295     }
296
297   second_iter = pg->peers[second].connected_peers;
298   add_second = GNUNET_YES;
299   while (second_iter != NULL)
300     {
301       if (second_iter->daemon == pg->peers[first].daemon)
302         add_second = GNUNET_NO;
303       second_iter = second_iter->next;
304     }
305
306   added = 0;
307   if (add_first)
308     {
309       new_first = GNUNET_malloc(sizeof(struct PeerConnection));
310       new_first->daemon = pg->peers[second].daemon;
311       new_first->next = pg->peers[first].connected_peers;
312       pg->peers[first].connected_peers = new_first;
313       added++;
314     }
315
316   if (add_second)
317     {
318       new_second = GNUNET_malloc(sizeof(struct PeerConnection));
319       new_second->daemon = pg->peers[first].daemon;
320       new_second->next = pg->peers[second].connected_peers;
321       pg->peers[second].connected_peers = new_second;
322       added++;
323     }
324
325   return added;
326 }
327
328 int
329 create_small_world_ring(struct GNUNET_TESTING_PeerGroup *pg)
330 {
331   unsigned int i, j;
332   int nodeToConnect;
333   unsigned int natLog;
334   unsigned int randomPeer;
335   double random, logNModifier, percentage;
336   unsigned int smallWorldConnections;
337   int connsPerPeer;
338   char *p_string;
339   int max;
340   int min;
341   unsigned int useAnd;
342   int connect_attempts;
343
344   logNModifier = 0.5; /* FIXME: default value? */
345   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
346                                                          "TESTING",
347                                                          "LOGNMODIFIER",
348                                                          &p_string))
349     {
350       if (sscanf(p_string, "%lf", &logNModifier) != 1)
351         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
352                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
353                     p_string,
354                     "LOGNMODIFIER",
355                     "TESTING");
356       GNUNET_free (p_string);
357     }
358   percentage = 0.5; /* FIXME: default percentage? */
359   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
360                                                          "TESTING",
361                                                          "PERCENTAGE",
362                                                          &p_string))
363     {
364       if (sscanf(p_string, "%lf", &percentage) != 1)
365         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
366                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
367                     p_string,
368                     "PERCENTAGE",
369                     "TESTING");
370       GNUNET_free (p_string);
371     }
372   natLog = log (pg->total);
373   connsPerPeer = ceil (natLog * logNModifier);
374
375   if (connsPerPeer % 2 == 1)
376     connsPerPeer += 1;
377
378   smallWorldConnections = 0;
379   connect_attempts = 0;
380   for (i = 0; i < pg->total; i++)
381     {
382       useAnd = 0;
383       max = i + connsPerPeer / 2;
384       min = i - connsPerPeer / 2;
385
386       if (max > pg->total - 1)
387         {
388           max = max - pg->total;
389           useAnd = 1;
390         }
391
392       if (min < 0)
393         {
394           min = pg->total - 1 + min;
395           useAnd = 1;
396         }
397
398       for (j = 0; j < connsPerPeer / 2; j++)
399         {
400           random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
401                                                       (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
402           if (random < percentage)
403             {
404               /* Connect to uniformly selected random peer */
405               randomPeer =
406                 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
407                                    pg->total);
408               while ((((randomPeer < max) && (randomPeer > min))
409                       && (useAnd == 0)) || (((randomPeer > min)
410                                              || (randomPeer < max))
411                                             && (useAnd == 1)))
412                 {
413                   randomPeer =
414                       GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
415                                                          pg->total);
416                 }
417               smallWorldConnections +=
418                 add_connections (pg, i, randomPeer);
419             }
420           else
421             {
422               nodeToConnect = i + j + 1;
423               if (nodeToConnect > pg->total - 1)
424                 {
425                   nodeToConnect = nodeToConnect - pg->total;
426                 }
427               connect_attempts +=
428                 add_connections (pg, i, nodeToConnect);
429             }
430         }
431
432     }
433
434   connect_attempts += smallWorldConnections;
435
436   return connect_attempts;
437 }
438
439
440 static int
441 create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg)
442 {
443   unsigned int outer_count, inner_count;
444   unsigned int cutoff;
445   int connect_attempts;
446   double nat_percentage;
447   char *p_string;
448
449   nat_percentage = 0.6; /* FIXME: default percentage? */
450   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
451                                                          "TESTING",
452                                                          "NATPERCENTAGE",
453                                                          &p_string))
454     {
455       if (sscanf(p_string, "%lf", &nat_percentage) != 1)
456         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
457                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
458                     p_string,
459                     "NATPERCENTAGE",
460                     "TESTING");
461       GNUNET_free (p_string);
462     }
463
464
465
466   cutoff = (unsigned int) (nat_percentage * pg->total);
467
468   connect_attempts = 0;
469
470   for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
471     {
472       for (inner_count = outer_count + 1; inner_count < pg->total;
473            inner_count++)
474         {
475           if ((outer_count > cutoff) || (inner_count > cutoff))
476             {
477 #if VERBOSE_TESTING
478               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
479                           "Connecting peer %d to peer %d\n",
480                           outer_count, inner_count);
481 #endif
482               connect_attempts += add_connections(pg, outer_count, inner_count);
483             }
484         }
485     }
486
487   return connect_attempts;
488
489 }
490
491
492
493 static int
494 create_small_world (struct GNUNET_TESTING_PeerGroup *pg)
495 {
496   unsigned int i, j, k;
497   unsigned int square;
498   unsigned int rows;
499   unsigned int cols;
500   unsigned int toggle = 1;
501   unsigned int nodeToConnect;
502   unsigned int natLog;
503   unsigned int node1Row;
504   unsigned int node1Col;
505   unsigned int node2Row;
506   unsigned int node2Col;
507   unsigned int distance;
508   double probability, random, percentage;
509   unsigned int smallWorldConnections;
510   char *p_string;
511   int connect_attempts;
512   square = floor (sqrt (pg->total));
513   rows = square;
514   cols = square;
515
516   percentage = 0.5; /* FIXME: default percentage? */
517   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
518                                                          "TESTING",
519                                                          "PERCENTAGE",
520                                                          &p_string))
521     {
522       if (sscanf(p_string, "%lf", &percentage) != 1)
523         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
524                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
525                     p_string,
526                     "PERCENTAGE",
527                     "TESTING");
528       GNUNET_free (p_string);
529     }
530   probability = 0.5; /* FIXME: default percentage? */
531   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
532                                                          "TESTING",
533                                                          "PROBABILITY",
534                                                          &p_string))
535     {
536       if (sscanf(p_string, "%lf", &probability) != 1)
537         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
538                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
539                     p_string,
540                     "PROBABILITY",
541                     "TESTING");
542       GNUNET_free (p_string);
543     }
544   if (square * square != pg->total)
545     {
546       while (rows * cols < pg->total)
547         {
548           if (toggle % 2 == 0)
549             rows++;
550           else
551             cols++;
552
553           toggle++;
554         }
555     }
556 #if VERBOSE_TESTING
557       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
558                   _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
559                   rows, cols);
560 #endif
561
562   connect_attempts = 0;
563   /* Rows and columns are all sorted out, now iterate over all nodes and connect each
564    * to the node to its right and above.  Once this is over, we'll have our torus!
565    * Special case for the last node (if the rows and columns are not equal), connect
566    * to the first in the row to maintain topology.
567    */
568   for (i = 0; i < pg->total; i++)
569     {
570       /* First connect to the node to the right */
571       if (((i + 1) % cols != 0) && (i + 1 != pg->total))
572         nodeToConnect = i + 1;
573       else if (i + 1 == pg->total)
574         nodeToConnect = rows * cols - cols;
575       else
576         nodeToConnect = i - cols + 1;
577
578       connect_attempts += add_connections (pg, i, nodeToConnect);
579
580       if (i < cols)
581         nodeToConnect = (rows * cols) - cols + i;
582       else
583         nodeToConnect = i - cols;
584
585       if (nodeToConnect < pg->total)
586         connect_attempts += add_connections (pg, i, nodeToConnect);
587     }
588   natLog = log (pg->total);
589 #if VERBOSE_TESTING
590   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
591               _("natural log of %d is %d, will run %d iterations\n"),
592              pg->total, natLog, (int) (natLog * percentage));
593   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Total connections added thus far: %u!\n"), connect_attempts);
594 #endif
595   smallWorldConnections = 0;
596   for (i = 0; i < (int) (natLog * percentage); i++)
597     {
598       for (j = 0; j < pg->total; j++)
599         {
600           /* Determine the row and column of node at position j on the 2d torus */
601           node1Row = j / cols;
602           node1Col = j - (node1Row * cols);
603           for (k = 0; k < pg->total; k++)
604             {
605               /* Determine the row and column of node at position k on the 2d torus */
606               node2Row = k / cols;
607               node2Col = k - (node2Row * cols);
608               /* Simple Cartesian distance */
609               distance = abs (node1Row - node2Row) + abs (node1Col - node2Col);
610               if (distance > 1)
611                 {
612                   /* Calculate probability as 1 over the square of the distance */
613                   probability = 1.0 / (distance * distance);
614                   /* Choose a random value between 0 and 1 */
615                   random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
616                                                               (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
617                   /* If random < probability, then connect the two nodes */
618                   if (random < probability)
619                     smallWorldConnections += add_connections (pg, j, k);
620
621                 }
622             }
623         }
624     }
625   connect_attempts += smallWorldConnections;
626 #if VERBOSE_TESTING
627           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
628                       _("Total connections added for small world: %d!\n"),
629                       smallWorldConnections);
630 #endif
631   return connect_attempts;
632 }
633
634
635
636 static int
637 create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg)
638 {
639   double temp_rand;
640   unsigned int outer_count;
641   unsigned int inner_count;
642   int connect_attempts;
643   double probability;
644   char *p_string;
645
646   probability = 0.5; /* FIXME: default percentage? */
647   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
648                                                          "TESTING",
649                                                          "PROBABILITY",
650                                                          &p_string))
651     {
652       if (sscanf(p_string, "%lf", &probability) != 1)
653         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
654                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
655                     p_string,
656                     "PROBABILITY",
657                     "TESTING");
658       GNUNET_free (p_string);
659     }
660   connect_attempts = 0;
661   for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
662     {
663       for (inner_count = outer_count + 1; inner_count < pg->total;
664            inner_count++)
665         {
666           temp_rand = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
667                                                          (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
668 #if VERBOSE_TESTING
669           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
670                       _("rand is %f probability is %f\n"), temp_rand,
671                       probability);
672 #endif
673           if (temp_rand < probability)
674             {
675               connect_attempts += add_connections (pg, outer_count, inner_count);
676             }
677         }
678     }
679
680   return connect_attempts;
681 }
682
683 static int
684 create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg)
685 {
686   unsigned int i;
687   unsigned int square;
688   unsigned int rows;
689   unsigned int cols;
690   unsigned int toggle = 1;
691   unsigned int nodeToConnect;
692   int connect_attempts;
693
694   connect_attempts = 0;
695
696   square = floor (sqrt (pg->total));
697   rows = square;
698   cols = square;
699
700   if (square * square != pg->total)
701     {
702       while (rows * cols < pg->total)
703         {
704           if (toggle % 2 == 0)
705             rows++;
706           else
707             cols++;
708
709           toggle++;
710         }
711     }
712 #if VERBOSE_TESTING
713       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
714                   _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
715                   rows, cols);
716 #endif
717   /* Rows and columns are all sorted out, now iterate over all nodes and connect each
718    * to the node to its right and above.  Once this is over, we'll have our torus!
719    * Special case for the last node (if the rows and columns are not equal), connect
720    * to the first in the row to maintain topology.
721    */
722   for (i = 0; i < pg->total; i++)
723     {
724       /* First connect to the node to the right */
725       if (((i + 1) % cols != 0) && (i + 1 != pg->total))
726         nodeToConnect = i + 1;
727       else if (i + 1 == pg->total)
728         nodeToConnect = rows * cols - cols;
729       else
730         nodeToConnect = i - cols + 1;
731 #if VERBOSE_TESTING
732           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
733                       "Connecting peer %d to peer %d\n",
734                       i, nodeToConnect);
735 #endif
736       connect_attempts += add_connections(pg, i, nodeToConnect);
737
738       /* Second connect to the node immediately above */
739       if (i < cols)
740         nodeToConnect = (rows * cols) - cols + i;
741       else
742         nodeToConnect = i - cols;
743
744       if (nodeToConnect < pg->total)
745         {
746 #if VERBOSE_TESTING
747           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
748                       "Connecting peer %d to peer %d\n",
749                       i, nodeToConnect);
750 #endif
751           connect_attempts += add_connections(pg, i, nodeToConnect);
752         }
753
754     }
755
756   return connect_attempts;
757 }
758
759
760
761 static int
762 create_clique (struct GNUNET_TESTING_PeerGroup *pg)
763 {
764   unsigned int outer_count;
765   unsigned int inner_count;
766   int connect_attempts;
767
768   connect_attempts = 0;
769
770   for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
771     {
772       for (inner_count = outer_count + 1; inner_count < pg->total;
773            inner_count++)
774         {
775 #if VERBOSE_TESTING
776           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
777                       "Connecting peer %d to peer %d\n",
778                       outer_count, inner_count);
779 #endif
780           connect_attempts += add_connections(pg, outer_count, inner_count);
781         }
782     }
783
784   return connect_attempts;
785 }
786
787
788 static int
789 create_ring (struct GNUNET_TESTING_PeerGroup *pg)
790 {
791   unsigned int count;
792   int connect_attempts;
793
794   connect_attempts = 0;
795
796   /* Connect each peer to the next highest numbered peer */
797   for (count = 0; count < pg->total - 1; count++)
798     {
799 #if VERBOSE_TESTING
800           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
801                       "Connecting peer %d to peer %d\n",
802                       count, count + 1);
803 #endif
804       connect_attempts += add_connections(pg, count, count + 1);
805     }
806
807   /* Connect the last peer to the first peer */
808   connect_attempts += add_connections(pg, pg->total - 1, 0);
809
810   return connect_attempts;
811 }
812
813
814 /*
815  * Create the friend files based on the PeerConnection's
816  * of each peer in the peer group, and copy the files
817  * to the appropriate place
818  *
819  * @param pg the peer group we are dealing with
820  */
821 static int
822 create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
823 {
824   FILE *temp_friend_handle;
825   unsigned int pg_iter;
826   struct PeerConnection *connection_iter;
827   struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
828   char *temp_service_path;
829   pid_t *pidarr;
830   char *arg;
831   struct GNUNET_PeerIdentity *temppeer;
832   char * mytemp;
833   enum GNUNET_OS_ProcessStatusType type;
834   unsigned long return_code;
835   int count;
836   int ret;
837   int max_wait = 10;
838
839   pidarr = GNUNET_malloc(sizeof(pid_t) * pg->total);
840   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
841     {
842       mytemp = GNUNET_DISK_mktemp("friends");
843       temp_friend_handle = fopen (mytemp, "wt");
844       connection_iter = pg->peers[pg_iter].connected_peers;
845       while (connection_iter != NULL)
846         {
847           temppeer = &connection_iter->daemon->id;
848           GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
849           fprintf(temp_friend_handle, "%s\n", (char *)&peer_enc);
850           connection_iter = connection_iter->next;
851         }
852
853       fclose(temp_friend_handle);
854
855       if (GNUNET_OK !=
856           GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
857         {
858           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
859                       _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
860                       "SERVICEHOME",
861                       "PATHS");
862           if (UNLINK (mytemp) != 0)
863             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
864           GNUNET_free (mytemp);
865           break;
866         }
867
868       if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
869         {
870           GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
871           pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
872                                          "mv", mytemp, arg, NULL);
873 #if VERBOSE_TESTING
874           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
875                       _("Copying file with command cp %s %s\n"), mytemp, arg);
876 #endif
877
878           GNUNET_free(arg);
879         }
880       else /* Remote, scp the file to the correct place */
881         {
882           if (NULL != pg->peers[pg_iter].daemon->username)
883             GNUNET_asprintf (&arg, "%s@%s:%s/friends", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
884           else
885             GNUNET_asprintf (&arg, "%s:%s/friends", pg->peers[pg_iter].daemon->hostname, temp_service_path);
886           pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
887                                          "scp", mytemp, arg, NULL);
888
889 #if VERBOSE_TESTING
890           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
891                       _("Copying file with command scp %s %s\n"), mytemp, arg);
892 #endif
893           GNUNET_free(arg);
894         }
895       GNUNET_free (temp_service_path);
896       GNUNET_free (mytemp);
897     }
898
899   count = 0;
900   ret = GNUNET_SYSERR;
901   while ((count < max_wait) && (ret != GNUNET_OK))
902     {
903       ret = GNUNET_OK;
904       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
905         {
906 #if VERBOSE_TESTING
907           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
908                       _("Checking copy status of file %d\n"), pg_iter);
909 #endif
910           if (pidarr[pg_iter] != 0) /* Check for already completed! */
911             {
912               if (GNUNET_OS_process_status(pidarr[pg_iter], &type, &return_code) != GNUNET_OK)
913                 {
914                   ret = GNUNET_SYSERR;
915                 }
916               else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
917                 {
918                   ret = GNUNET_SYSERR;
919                 }
920               else
921                 {
922                   pidarr[pg_iter] = 0;
923 #if VERBOSE_TESTING
924             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
925                       _("File %d copied\n"), pg_iter);
926 #endif
927                 }
928             }
929         }
930       count++;
931       if (ret == GNUNET_SYSERR)
932         {
933           sleep(1);
934         }
935     }
936
937   GNUNET_free(pidarr);
938   return ret;
939 }
940
941 /**
942  * Internal notification of a connection, kept so that we can ensure some connections
943  * happen instead of flooding all testing daemons with requests to connect.
944  */
945 static void internal_connect_notify (void *cls,
946                                      const struct GNUNET_PeerIdentity *first,
947                                      const struct GNUNET_PeerIdentity *second,
948                                      const struct GNUNET_CONFIGURATION_Handle *first_cfg,
949                                      const struct GNUNET_CONFIGURATION_Handle *second_cfg,
950                                      struct GNUNET_TESTING_Daemon *first_daemon,
951                                      struct GNUNET_TESTING_Daemon *second_daemon,
952                                      const char *emsg)
953 {
954   struct GNUNET_TESTING_PeerGroup *pg = cls;
955   outstanding_connects--;
956
957   pg->notify_connection(pg->notify_connection_cls, first, second, first_cfg, second_cfg, first_daemon, second_daemon, emsg);
958
959 }
960
961 static void schedule_connect(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
962 {
963   struct ConnectContext *connect_context = cls;
964
965   if (outstanding_connects > MAX_OUTSTANDING_CONNECTIONS)
966     {
967 #if VERBOSE_TESTING
968           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
969                       _("Delaying connect, we have too many outstanding connections!\n"));
970 #endif
971       GNUNET_SCHEDULER_add_delayed(connect_context->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3), &schedule_connect, connect_context);
972     }
973   else
974     {
975 #if VERBOSE_TESTING
976           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
977                       _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
978 #endif
979       outstanding_connects++;
980       GNUNET_TESTING_daemons_connect (connect_context->first,
981                                       connect_context->second,
982                                       CONNECT_TIMEOUT,
983                                       &internal_connect_notify,
984                                       connect_context->pg);
985       GNUNET_free(connect_context);
986     }
987 }
988
989 /*
990  * Connect the topology as specified by the PeerConnection's
991  * of each peer in the peer group
992  *
993  * @param pg the peer group we are dealing with
994  */
995 static void
996 connect_topology (struct GNUNET_TESTING_PeerGroup *pg)
997 {
998   unsigned int pg_iter;
999   struct PeerConnection *connection_iter;
1000   struct ConnectContext *connect_context;
1001
1002   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1003     {
1004       connection_iter = pg->peers[pg_iter].connected_peers;
1005       while (connection_iter != NULL)
1006         {
1007           connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
1008           connect_context->pg = pg;
1009           connect_context->first = pg->peers[pg_iter].daemon;
1010           connect_context->second = connection_iter->daemon;
1011
1012           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_connect, connect_context);
1013           /*GNUNET_TESTING_daemons_connect (pg->peers[pg_iter].daemon,
1014                                           connection_iter->daemon,
1015                                           CONNECT_TIMEOUT,
1016                                           pg->notify_connection,
1017                                           pg->notify_connection_cls);*/
1018           connection_iter = connection_iter->next;
1019
1020           /*if (outstanding_connects > MAX_OUTSTANDING_CONNECTS)
1021             {
1022 #if VERBOSE_TESTING
1023               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1024                           _("Sleeping to give peers a chance to connect!\n"));
1025 #endif
1026               sleep(2);
1027             } */
1028         }
1029     }
1030 }
1031
1032
1033 /*
1034  * Takes a peer group and attempts to create a topology based on the
1035  * one specified in the configuration file.  Returns the number of connections
1036  * that will attempt to be created, but this will happen asynchronously(?) so
1037  * the caller will have to keep track (via the callback) of whether or not
1038  * the connection actually happened.
1039  *
1040  * @param pg the peer group struct representing the running peers
1041  *
1042  * @return the number of connections should be created by the topology, so the
1043  * caller knows how many to wait for (if it so chooses)
1044  *
1045  */
1046 int
1047 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg)
1048 {
1049   unsigned long long topology_num;
1050   int ret;
1051   int num_connections;
1052
1053   GNUNET_assert (pg->notify_connection != NULL);
1054   ret = GNUNET_OK;
1055   if (GNUNET_YES ==
1056       GNUNET_CONFIGURATION_get_value_number (pg->cfg, "testing", "topology",
1057                                              &topology_num))
1058     {
1059       switch (topology_num)
1060         {
1061         case GNUNET_TESTING_TOPOLOGY_CLIQUE:
1062 #if VERBOSE_TESTING
1063           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1064                       _("Creating clique topology (may take a bit!)\n"));
1065 #endif
1066           num_connections = create_clique (pg);
1067           break;
1068         case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
1069 #if VERBOSE_TESTING
1070           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1071                       _("Creating small world (ring) topology (may take a bit!)\n"));
1072 #endif
1073           num_connections = create_small_world_ring (pg);
1074           break;
1075         case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
1076 #if VERBOSE_TESTING
1077           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1078                       _("Creating small world (2d-torus) topology (may take a bit!)\n"));
1079 #endif
1080           num_connections = create_small_world (pg);
1081           break;
1082         case GNUNET_TESTING_TOPOLOGY_RING:
1083 #if VERBOSE_TESTING
1084           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1085                       _("Creating ring topology (may take a bit!)\n"));
1086 #endif
1087           num_connections = create_ring (pg);
1088           break;
1089         case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
1090 #if VERBOSE_TESTING
1091           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1092                       _("Creating 2d torus topology (may take a bit!)\n"));
1093 #endif
1094           num_connections = create_2d_torus (pg);
1095           break;
1096         case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
1097 #if VERBOSE_TESTING
1098           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1099                       _("Creating Erdos-Renyi topology (may take a bit!)\n"));
1100 #endif
1101           num_connections = create_erdos_renyi (pg);
1102           break;
1103         case GNUNET_TESTING_TOPOLOGY_INTERNAT:
1104 #if VERBOSE_TESTING
1105           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1106                       _("Creating InterNAT topology (may take a bit!)\n"));
1107 #endif
1108           num_connections = create_nated_internet (pg);
1109           break;
1110         case GNUNET_TESTING_TOPOLOGY_NONE:
1111           num_connections = 0;
1112           break;
1113         default:
1114           num_connections = 0;
1115           break;
1116         }
1117       if (num_connections < 1)
1118         return GNUNET_SYSERR;
1119
1120       if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
1121         ret = create_and_copy_friend_files(pg);
1122       if (ret == GNUNET_OK)
1123         connect_topology(pg);
1124       else
1125         {
1126 #if VERBOSE_TESTING
1127           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1128                       _("Failed during friend file copying!\n"));
1129 #endif
1130           return GNUNET_SYSERR;
1131         }
1132     }
1133   else
1134     {
1135       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1136                   _("No topology specified, was one intended?\n"));
1137       return GNUNET_SYSERR;
1138     }
1139
1140   return num_connections;
1141 }
1142
1143 /**
1144  * Start count gnunetd processes with the same set of transports and
1145  * applications.  The port numbers (any option called "PORT") will be
1146  * adjusted to ensure that no two peers running on the same system
1147  * have the same port(s) in their respective configurations.
1148  *
1149  * @param sched scheduler to use
1150  * @param cfg configuration template to use
1151  * @param total number of daemons to start
1152  * @param cb function to call on each daemon that was started
1153  * @param cb_cls closure for cb
1154  * @param connect_callback function to call each time two hosts are connected
1155  * @param connect_callback_cls closure for connect_callback
1156  * @param hostnames space-separated list of hostnames to use; can be NULL (to run
1157  *        everything on localhost).
1158  * @return NULL on error, otherwise handle to control peer group
1159  */
1160 struct GNUNET_TESTING_PeerGroup *
1161 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
1162                               const struct GNUNET_CONFIGURATION_Handle *cfg,
1163                               unsigned int total,
1164                               GNUNET_TESTING_NotifyDaemonRunning cb,
1165                               void *cb_cls,
1166                               GNUNET_TESTING_NotifyConnection
1167                               connect_callback, void *connect_callback_cls,
1168                               const char *hostnames)
1169 {
1170   struct GNUNET_TESTING_PeerGroup *pg;
1171   const char *rpos;
1172   char *pos;
1173   char *start;
1174   const char *hostname;
1175   char *baseservicehome;
1176   char *newservicehome;
1177   char *tmpdir;
1178   struct GNUNET_CONFIGURATION_Handle *pcfg;
1179   unsigned int off;
1180   unsigned int hostcnt;
1181   uint16_t minport;
1182
1183   if (0 == total)
1184     {
1185       GNUNET_break (0);
1186       return NULL;
1187     }
1188
1189   pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
1190   pg->sched = sched;
1191   pg->cfg = cfg;
1192   pg->cb = cb;
1193   pg->cb_cls = cb_cls;
1194   pg->notify_connection = connect_callback;
1195   pg->notify_connection_cls = connect_callback_cls;
1196   pg->total = total;
1197   pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
1198   if (NULL != hostnames)
1199     {
1200       off = 2;
1201       /* skip leading spaces */
1202       while ((0 != *hostnames) && (isspace (*hostnames)))
1203         hostnames++;
1204       rpos = hostnames;
1205       while ('\0' != *rpos)
1206         {
1207           if (isspace (*rpos))
1208             off++;
1209           rpos++;
1210         }
1211       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
1212       off = 0;
1213       start = GNUNET_strdup (hostnames);
1214       pos = start;
1215       while ('\0' != *pos)
1216         {
1217           if (isspace (*pos))
1218             {
1219               *pos = '\0';
1220               if (strlen (start) > 0)
1221                 {
1222                   pg->hosts[off].minport = LOW_PORT;
1223                   pg->hosts[off++].hostname = start;
1224                 }
1225               start = pos + 1;
1226             }
1227           pos++;
1228         }
1229       if (strlen (start) > 0)
1230         {
1231           pg->hosts[off].minport = LOW_PORT;
1232           pg->hosts[off++].hostname = start;
1233         }
1234       if (off == 0)
1235         {
1236           GNUNET_free (start);
1237           GNUNET_free (pg->hosts);
1238           pg->hosts = NULL;
1239         }
1240       hostcnt = off;
1241       minport = 0;              /* make gcc happy */
1242     }
1243   else
1244     {
1245       hostcnt = 0;
1246       minport = LOW_PORT;
1247     }
1248   for (off = 0; off < total; off++)
1249     {
1250       if (hostcnt > 0)
1251         {
1252           hostname = pg->hosts[off % hostcnt].hostname;
1253           pcfg = make_config (cfg, &pg->hosts[off % hostcnt].minport);
1254         }
1255       else
1256         {
1257           hostname = NULL;
1258           pcfg = make_config (cfg, &minport);
1259         }
1260       if (NULL == pcfg)
1261         {
1262           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1263                       _
1264                       ("Could not create configuration for peer number %u on `%s'!\n"),
1265                       off, hostname == NULL ? "localhost" : hostname);
1266           continue;
1267         }
1268
1269       if (GNUNET_YES ==
1270           GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
1271                                                  &baseservicehome))
1272         {
1273           GNUNET_asprintf (&newservicehome,
1274                            "%s/%d/", baseservicehome, off);
1275           GNUNET_free (baseservicehome);
1276         }
1277       else
1278         {
1279           tmpdir = getenv ("TMPDIR");
1280           tmpdir = tmpdir ? tmpdir : "/tmp";
1281           GNUNET_asprintf (&newservicehome,
1282                            "%s/%s/%d/",
1283                            tmpdir,
1284                            "gnunet-testing-test-test", off);
1285         }
1286       GNUNET_CONFIGURATION_set_value_string (pcfg,
1287                                              "PATHS",
1288                                              "SERVICEHOME", newservicehome);
1289       GNUNET_free (newservicehome);
1290       pg->peers[off].cfg = pcfg;
1291       pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
1292                                                            pcfg,
1293                                                            hostname,
1294                                                            cb, cb_cls);
1295       if (NULL == pg->peers[off].daemon)
1296         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1297                     _("Could not start peer number %u!\n"), off);
1298     }
1299   return pg;
1300 }
1301
1302 /*
1303  * Get a daemon by number, so callers don't have to do nasty
1304  * offsetting operation.
1305  */
1306 struct GNUNET_TESTING_Daemon *
1307 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
1308 {
1309   if (position < pg->total)
1310     return pg->peers[position].daemon;
1311   else
1312     return NULL;
1313 }
1314
1315 /**
1316  * Shutdown all peers started in the given group.
1317  *
1318  * @param pg handle to the peer group
1319  */
1320 void
1321 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg)
1322 {
1323   unsigned int off;
1324   struct PeerConnection *pos;
1325   struct PeerConnection *next;
1326
1327   for (off = 0; off < pg->total; off++)
1328     {
1329       /* FIXME: should we wait for our
1330          continuations to be called here? This
1331          would require us to take a continuation
1332          as well... */
1333
1334       if (NULL != pg->peers[off].daemon)
1335         GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, NULL, NULL);
1336       if (NULL != pg->peers[off].cfg)
1337         GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
1338
1339       pos = pg->peers[off].connected_peers;
1340       while (pos != NULL)
1341         {
1342           next = pos->next;
1343           GNUNET_free(pos);
1344           pos = next;
1345         }
1346
1347     }
1348   GNUNET_free (pg->peers);
1349   if (NULL != pg->hosts)
1350     {
1351       GNUNET_free (pg->hosts[0].hostname);
1352       GNUNET_free (pg->hosts);
1353     }
1354   GNUNET_free (pg);
1355 }
1356
1357
1358 /* end of testing_group.c */