more testing changes
[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_NO
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, 160)
50
51 #define CONNECT_ATTEMPTS 8
52
53 /**
54  * Prototype of a function called whenever two peers would be connected
55  * in a certain topology.
56  */
57 typedef int (*GNUNET_TESTING_ConnectionProcessor)
58 (struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second);
59
60 struct RestartContext
61 {
62   /**
63    * The group of peers being restarted
64    */
65   struct GNUNET_TESTING_PeerGroup *peer_group;
66
67   /**
68    * How many peers have been restarted thus far
69    */
70   unsigned int peers_restarted;
71
72   /**
73    * How many peers got an error when restarting
74    */
75   unsigned int peers_restart_failed;
76
77   /**
78    * The function to call once all peers have been restarted
79    */
80   GNUNET_TESTING_NotifyCompletion callback;
81
82   /**
83    * Closure for callback function
84    */
85   void *callback_cls;
86
87 };
88
89 struct CreateTopologyContext
90 {
91
92   /**
93    * Function to call with number of connections
94    */
95   GNUNET_TESTING_NotifyConnections cont;
96
97   /**
98    * Closure for connection notification
99    */
100   void *cls;
101 };
102
103 #if OLD
104 struct PeerConnection
105 {
106   /*
107    * Linked list
108    */
109   struct PeerConnection *next;
110
111   /*
112    * Pointer to daemon handle
113    */
114   struct GNUNET_TESTING_Daemon *daemon;
115
116 };
117 #endif
118
119 /**
120  * Data we keep per peer.
121  */
122 struct PeerData
123 {
124   /**
125    * (Initial) configuration of the host.
126    * (initial because clients could change
127    *  it and we would not know about those
128    *  updates).
129    */
130   struct GNUNET_CONFIGURATION_Handle *cfg;
131
132   /**
133    * Handle for controlling the daemon.
134    */
135   struct GNUNET_TESTING_Daemon *daemon;
136
137   /**
138    * The peergroup this peer belongs to.
139    */
140   struct GNUNET_TESTING_PeerGroup *pg;
141
142   /**
143    * Linked list of peer connections (pointers)
144    */
145   //struct PeerConnection *connected_peers;
146   /**
147    * Hash map of allowed peer connections (F2F created topology)
148    */
149   struct GNUNET_CONTAINER_MultiHashMap *allowed_peers;
150
151   /**
152    * Hash map of blacklisted peers
153    */
154   struct GNUNET_CONTAINER_MultiHashMap *blacklisted_peers;
155
156   /**
157    * Hash map of peer connections
158    */
159   struct GNUNET_CONTAINER_MultiHashMap *connect_peers;
160
161   /**
162    * Temporary hash map of peer connections
163    */
164   struct GNUNET_CONTAINER_MultiHashMap *connect_peers_working_set;
165
166   /**
167    * Temporary variable for topology creation, should be reset before
168    * creating any topology so the count is valid once finished.
169    */
170   int num_connections;
171 };
172
173
174 /**
175  * Data we keep per host.
176  */
177 struct HostData
178 {
179   /**
180    * Name of the host.
181    */
182   char *hostname;
183
184   /**
185    * Lowest port that we have not yet used
186    * for GNUnet.
187    */
188   uint16_t minport;
189 };
190
191
192 /**
193  * Handle to a group of GNUnet peers.
194  */
195 struct GNUNET_TESTING_PeerGroup
196 {
197   /**
198    * Our scheduler.
199    */
200   struct GNUNET_SCHEDULER_Handle *sched;
201
202   /**
203    * Configuration template.
204    */
205   const struct GNUNET_CONFIGURATION_Handle *cfg;
206
207   /**
208    * Function to call on each started daemon.
209    */
210   GNUNET_TESTING_NotifyDaemonRunning cb;
211
212   /**
213    * Closure for cb.
214    */
215   void *cb_cls;
216
217   /*
218    * Function to call on each topology connection created
219    */
220   GNUNET_TESTING_NotifyConnection notify_connection;
221
222   /*
223    * Callback for notify_connection
224    */
225   void *notify_connection_cls;
226
227   /**
228    * NULL-terminated array of information about
229    * hosts.
230    */
231   struct HostData *hosts;
232
233   /**
234    * Array of "total" peers.
235    */
236   struct PeerData *peers;
237
238   /**
239    * Number of peers in this group.
240    */
241   unsigned int total;
242
243   /**
244    * At what time should we fail the peer startup process?
245    */
246   struct GNUNET_TIME_Absolute max_timeout;
247 };
248
249 /**
250  * Convert unique ID to hash code.
251  *
252  * @param uid unique ID to convert
253  * @param hash set to uid (extended with zeros)
254  */
255 static void
256 hash_from_uid (uint32_t uid,
257                GNUNET_HashCode *hash)
258 {
259   memset (hash, 0, sizeof(GNUNET_HashCode));
260   *((uint32_t*)hash) = uid;
261 }
262
263 /**
264  * Convert hash code to unique ID.
265  *
266  * @param uid unique ID to convert
267  * @param hash set to uid (extended with zeros)
268  */
269 static void
270 uid_from_hash (const GNUNET_HashCode *hash, uint32_t *uid)
271 {
272   memcpy (uid, hash, sizeof(uint32_t));
273 }
274
275 struct UpdateContext
276 {
277   struct GNUNET_CONFIGURATION_Handle *ret;
278   unsigned int nport;
279   const char *hostname;
280 };
281
282
283 struct ConnectContext
284 {
285   struct GNUNET_TESTING_Daemon *first;
286
287   struct GNUNET_TESTING_Daemon *second;
288
289   struct GNUNET_TESTING_PeerGroup *pg;
290 };
291
292 /**
293  * Number of connects we are waiting on, allows us to rate limit
294  * connect attempts.
295  */
296 static int outstanding_connects;
297
298
299 /**
300  * Function to iterate over options.  Copies
301  * the options to the target configuration,
302  * updating PORT values as needed.
303  *
304  * @param cls closure
305  * @param section name of the section
306  * @param option name of the option
307  * @param value value of the option
308  */
309 static void
310 update_config (void *cls,
311                const char *section, const char *option, const char *value)
312 {
313   struct UpdateContext *ctx = cls;
314   unsigned int ival;
315   char cval[12];
316
317   if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
318     {
319       GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++);
320       value = cval;
321     }
322
323   if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL))
324     {
325       value = ctx->hostname;
326     }
327
328   GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value);
329 }
330
331
332 /**
333  * Create a new configuration using the given configuration
334  * as a template; however, each PORT in the existing cfg
335  * must be renumbered by incrementing "*port".  If we run
336  * out of "*port" numbers, return NULL.
337  *
338  * @param cfg template configuration
339  * @param port port numbers to use, update to reflect
340  *             port numbers that were used
341  * @param hostname hostname of the controlling host, to allow control connections from
342  *
343  * @return new configuration, NULL on error
344  */
345 static struct GNUNET_CONFIGURATION_Handle *
346 make_config (const struct GNUNET_CONFIGURATION_Handle *cfg, uint16_t * port, const char *hostname)
347 {
348   struct UpdateContext uc;
349   uint16_t orig;
350   char *control_host;
351   char *allowed_hosts;
352
353   orig = *port;
354   uc.nport = *port;
355   uc.ret = GNUNET_CONFIGURATION_create ();
356   uc.hostname = hostname;
357
358   GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
359   if (uc.nport >= HIGH_PORT)
360     {
361       *port = orig;
362       GNUNET_CONFIGURATION_destroy (uc.ret);
363       return NULL;
364     }
365
366   if (GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "control_host", &control_host) == GNUNET_OK)
367     {
368       GNUNET_asprintf(&allowed_hosts, "%s; 127.0.0.1;", control_host);
369       GNUNET_CONFIGURATION_set_value_string(uc.ret, "core", "ACCEPT_FROM", allowed_hosts);
370       GNUNET_free_non_null(control_host);
371       GNUNET_free(allowed_hosts);
372     }
373
374
375   /* arm needs to know to allow connections from the host on which it is running,
376    * otherwise gnunet-arm is unable to connect to it in some instances */
377   if (hostname != NULL)
378     {
379       GNUNET_asprintf(&allowed_hosts, "%s; 127.0.0.1;", hostname);
380       GNUNET_CONFIGURATION_set_value_string(uc.ret, "arm", "ACCEPT_FROM", allowed_hosts);
381       GNUNET_free(allowed_hosts);
382     }
383
384   *port = (uint16_t) uc.nport;
385   return uc.ret;
386 }
387
388
389 /*
390  * Add entries to the peers connect list
391  *
392  * @param pg the peer group we are working with
393  * @param first index of the first peer
394  * @param second index of the second peer
395  *
396  * @return the number of connections added (can be 0, 1 or 2)
397  *         technically should only be 0 or 2, but the small price
398  *         of iterating over the lists (hashmaps in the future)
399  *         for being sure doesn't bother me!
400  *
401  */
402 static int
403 add_actual_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
404 {
405   int added;
406   int add_first;
407   int add_second;
408
409   GNUNET_HashCode hash_first;
410   GNUNET_HashCode hash_second;
411
412   hash_from_uid(first, &hash_first);
413   hash_from_uid(second, &hash_second);
414
415   add_first = GNUNET_NO;
416   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].connect_peers, &hash_second))
417     {
418       add_first = GNUNET_YES;
419     }
420
421   add_second = GNUNET_NO;
422   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].connect_peers, &hash_first))
423     {
424       add_second = GNUNET_YES;
425     }
426
427   added = 0;
428   if (add_first)
429     {
430       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[first].connect_peers, &hash_second, pg->peers[second].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
431       pg->peers[first].num_connections++;
432       added++;
433     }
434
435   if (add_second)
436     {
437       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[second].connect_peers, &hash_first, pg->peers[first].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
438       pg->peers[second].num_connections++;
439       added++;
440     }
441
442   return added;
443 }
444
445
446 /*
447  * Add entries to the peers allowed connections list
448  *
449  * @param pg the peer group we are working with
450  * @param first index of the first peer
451  * @param second index of the second peer
452  *
453  * @return the number of connections added (can be 0, 1 or 2)
454  *         technically should only be 0 or 2, but the small price
455  *         of iterating over the lists (hashmaps in the future)
456  *         for being sure doesn't bother me!
457  *
458  */
459 static int
460 add_allowed_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
461 {
462   int added;
463 #if OLD
464   struct PeerConnection *first_iter;
465   struct PeerConnection *second_iter;
466   struct PeerConnection *new_first;
467   struct PeerConnection *new_second;
468 #endif
469   int add_first;
470   int add_second;
471
472   GNUNET_HashCode hash_first;
473   GNUNET_HashCode hash_second;
474
475   hash_from_uid(first, &hash_first);
476   hash_from_uid(second, &hash_second);
477
478   add_first = GNUNET_NO;
479   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].allowed_peers, &hash_second))
480     {
481       add_first = GNUNET_YES;
482     }
483
484   add_second = GNUNET_NO;
485   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].allowed_peers, &hash_first))
486     {
487       add_second = GNUNET_YES;
488     }
489 #if OLD
490   first_iter = pg->peers[first].connected_peers;
491   while (first_iter != NULL)
492     {
493       if (first_iter->daemon == pg->peers[second].daemon)
494         add_first = GNUNET_NO;
495       first_iter = first_iter->next;
496     }
497
498   second_iter = pg->peers[second].connected_peers;
499   add_second = GNUNET_YES;
500   while (second_iter != NULL)
501     {
502       if (second_iter->daemon == pg->peers[first].daemon)
503         add_second = GNUNET_NO;
504       second_iter = second_iter->next;
505     }
506 #endif
507
508   added = 0;
509   if (add_first)
510     {
511       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[first].allowed_peers, &hash_second, pg->peers[second].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
512 #if OLD
513       new_first = GNUNET_malloc(sizeof(struct PeerConnection));
514       new_first->daemon = pg->peers[second].daemon;
515       new_first->next = pg->peers[first].connected_peers;
516       pg->peers[first].connected_peers = new_first;
517 #endif
518       pg->peers[first].num_connections++;
519       added++;
520     }
521
522   if (add_second)
523     {
524       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[second].allowed_peers, &hash_first, pg->peers[first].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
525 #if OLD
526       new_second = GNUNET_malloc(sizeof(struct PeerConnection));
527       new_second->daemon = pg->peers[first].daemon;
528       new_second->next = pg->peers[second].connected_peers;
529       pg->peers[second].connected_peers = new_second;
530       pg->peers[first].num_connections++;
531 #endif
532       pg->peers[second].num_connections++;
533       added++;
534     }
535
536   return added;
537 }
538
539 /*
540  * Add entries to the peers blacklisted list
541  *
542  * @param pg the peer group we are working with
543  * @param first index of the first peer
544  * @param second index of the second peer
545  *
546  * @return the number of connections added (can be 0, 1 or 2)
547  *
548  */
549 static int
550 blacklist_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
551 {
552   int added;
553   int add_first;
554   int add_second;
555   GNUNET_HashCode hash_first;
556   GNUNET_HashCode hash_second;
557
558   hash_from_uid(first, &hash_first);
559   hash_from_uid(second, &hash_second);
560
561   add_first = GNUNET_NO;
562   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].blacklisted_peers, &hash_second))
563     {
564       add_first = GNUNET_YES;
565     }
566
567   add_second = GNUNET_NO;
568   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].blacklisted_peers, &hash_first))
569     {
570       add_second = GNUNET_YES;
571     }
572
573   added = 0;
574   if (add_first)
575     {
576       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[first].blacklisted_peers, &hash_second, pg->peers[second].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
577       pg->peers[first].num_connections++;
578       added++;
579     }
580
581   if (add_second)
582     {
583       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[second].blacklisted_peers, &hash_first, pg->peers[first].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
584       pg->peers[second].num_connections++;
585       added++;
586     }
587
588   return added;
589 }
590
591 /*
592  * Remove entries from the peers blacklisted list
593  *
594  * @param pg the peer group we are working with
595  * @param first index of the first peer
596  * @param second index of the second peer
597  *
598  * @return the number of connections removed (can be 0, 1 or 2)
599  *
600  */
601 static int
602 unblacklist_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
603 {
604   int removed;
605   int remove_first;
606   int remove_second;
607   GNUNET_HashCode hash_first;
608   GNUNET_HashCode hash_second;
609
610   hash_from_uid(first, &hash_first);
611   hash_from_uid(second, &hash_second);
612
613   remove_first = GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].blacklisted_peers, &hash_second);
614   remove_second = GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].blacklisted_peers, &hash_first);
615
616   removed = 0;
617   if (remove_first)
618     {
619       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[first].blacklisted_peers, &hash_second, pg->peers[second].daemon));
620       removed++;
621     }
622
623   if (remove_second)
624     {
625       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[second].blacklisted_peers, &hash_first, pg->peers[first].daemon));
626       removed++;
627     }
628
629   return removed;
630 }
631
632 /**
633  * Scale free network construction as described in:
634  *
635  * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
636  *
637  * Start with a network of "one" peer, then progressively add
638  * peers up to the total number.  At each step, iterate over
639  * all possible peers and connect new peer based on number of
640  * existing connections of the target peer.
641  *
642  * @param pg the peer group we are dealing with
643  * @param proc the connection processor to use
644  *
645  * @return the number of connections created
646  */
647 static int
648 create_scale_free (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
649 {
650
651   unsigned int total_connections;
652   unsigned int outer_count;
653   unsigned int i;
654   unsigned int previous_total_connections;
655   double random;
656   double probability;
657
658   GNUNET_assert(pg->total > 1);
659
660   /* Add a connection between the first two nodes */
661   total_connections = proc(pg, 0, 1);
662
663   for (outer_count = 1; outer_count < pg->total; outer_count++)
664     {
665       previous_total_connections = total_connections;
666       for (i = 0; i < outer_count; i++)
667         {
668           probability = pg->peers[i].num_connections / (double)previous_total_connections;
669           random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
670                                                       (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
671 #if VERBOSE_TESTING
672           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
673                       "Considering connecting peer %d to peer %d\n",
674                       outer_count, i);
675 #endif
676           if (random < probability)
677             {
678 #if VERBOSE_TESTING
679               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680                           "Connecting peer %d to peer %d\n",
681                           outer_count, i);
682 #endif
683               total_connections += proc(pg, outer_count, i);
684             }
685         }
686     }
687
688   return total_connections;
689 }
690
691 int
692 create_small_world_ring(struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
693 {
694   unsigned int i, j;
695   int nodeToConnect;
696   unsigned int natLog;
697   unsigned int randomPeer;
698   double random, logNModifier, percentage;
699   unsigned int smallWorldConnections;
700   int connsPerPeer;
701   char *p_string;
702   int max;
703   int min;
704   unsigned int useAnd;
705   int connect_attempts;
706
707   logNModifier = 0.5; /* FIXME: default value? */
708   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
709                                                          "TESTING",
710                                                          "LOGNMODIFIER",
711                                                          &p_string))
712     {
713       if (sscanf(p_string, "%lf", &logNModifier) != 1)
714         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
715                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
716                     p_string,
717                     "LOGNMODIFIER",
718                     "TESTING");
719       GNUNET_free (p_string);
720     }
721   percentage = 0.5; /* FIXME: default percentage? */
722   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
723                                                          "TESTING",
724                                                          "PERCENTAGE",
725                                                          &p_string))
726     {
727       if (sscanf(p_string, "%lf", &percentage) != 1)
728         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
729                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
730                     p_string,
731                     "PERCENTAGE",
732                     "TESTING");
733       GNUNET_free (p_string);
734     }
735   natLog = log (pg->total);
736   connsPerPeer = ceil (natLog * logNModifier);
737
738   if (connsPerPeer % 2 == 1)
739     connsPerPeer += 1;
740
741   smallWorldConnections = 0;
742   connect_attempts = 0;
743   for (i = 0; i < pg->total; i++)
744     {
745       useAnd = 0;
746       max = i + connsPerPeer / 2;
747       min = i - connsPerPeer / 2;
748
749       if (max > pg->total - 1)
750         {
751           max = max - pg->total;
752           useAnd = 1;
753         }
754
755       if (min < 0)
756         {
757           min = pg->total - 1 + min;
758           useAnd = 1;
759         }
760
761       for (j = 0; j < connsPerPeer / 2; j++)
762         {
763           random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
764                                                       (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
765           if (random < percentage)
766             {
767               /* Connect to uniformly selected random peer */
768               randomPeer =
769                 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
770                                    pg->total);
771               while ((((randomPeer < max) && (randomPeer > min))
772                       && (useAnd == 0)) || (((randomPeer > min)
773                                              || (randomPeer < max))
774                                             && (useAnd == 1)))
775                 {
776                   randomPeer =
777                       GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
778                                                          pg->total);
779                 }
780               smallWorldConnections +=
781                 proc (pg, i, randomPeer);
782             }
783           else
784             {
785               nodeToConnect = i + j + 1;
786               if (nodeToConnect > pg->total - 1)
787                 {
788                   nodeToConnect = nodeToConnect - pg->total;
789                 }
790               connect_attempts +=
791                 proc (pg, i, nodeToConnect);
792             }
793         }
794
795     }
796
797   connect_attempts += smallWorldConnections;
798
799   return connect_attempts;
800 }
801
802
803 static int
804 create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
805 {
806   unsigned int outer_count, inner_count;
807   unsigned int cutoff;
808   int connect_attempts;
809   double nat_percentage;
810   char *p_string;
811
812   nat_percentage = 0.6; /* FIXME: default percentage? */
813   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
814                                                          "TESTING",
815                                                          "NATPERCENTAGE",
816                                                          &p_string))
817     {
818       if (sscanf(p_string, "%lf", &nat_percentage) != 1)
819         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
820                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
821                     p_string,
822                     "NATPERCENTAGE",
823                     "TESTING");
824       GNUNET_free (p_string);
825     }
826
827
828
829   cutoff = (unsigned int) (nat_percentage * pg->total);
830
831   connect_attempts = 0;
832
833   for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
834     {
835       for (inner_count = outer_count + 1; inner_count < pg->total;
836            inner_count++)
837         {
838           if ((outer_count > cutoff) || (inner_count > cutoff))
839             {
840 #if VERBOSE_TESTING
841               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
842                           "Connecting peer %d to peer %d\n",
843                           outer_count, inner_count);
844 #endif
845               connect_attempts += proc(pg, outer_count, inner_count);
846             }
847         }
848     }
849
850   return connect_attempts;
851
852 }
853
854
855
856 static int
857 create_small_world (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
858 {
859   unsigned int i, j, k;
860   unsigned int square;
861   unsigned int rows;
862   unsigned int cols;
863   unsigned int toggle = 1;
864   unsigned int nodeToConnect;
865   unsigned int natLog;
866   unsigned int node1Row;
867   unsigned int node1Col;
868   unsigned int node2Row;
869   unsigned int node2Col;
870   unsigned int distance;
871   double probability, random, percentage;
872   unsigned int smallWorldConnections;
873   char *p_string;
874   int connect_attempts;
875   square = floor (sqrt (pg->total));
876   rows = square;
877   cols = square;
878
879   percentage = 0.5; /* FIXME: default percentage? */
880   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
881                                                          "TESTING",
882                                                          "PERCENTAGE",
883                                                          &p_string))
884     {
885       if (sscanf(p_string, "%lf", &percentage) != 1)
886         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
887                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
888                     p_string,
889                     "PERCENTAGE",
890                     "TESTING");
891       GNUNET_free (p_string);
892     }
893   probability = 0.5; /* FIXME: default percentage? */
894   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
895                                                          "TESTING",
896                                                          "PROBABILITY",
897                                                          &p_string))
898     {
899       if (sscanf(p_string, "%lf", &probability) != 1)
900         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
901                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
902                     p_string,
903                     "PROBABILITY",
904                     "TESTING");
905       GNUNET_free (p_string);
906     }
907   if (square * square != pg->total)
908     {
909       while (rows * cols < pg->total)
910         {
911           if (toggle % 2 == 0)
912             rows++;
913           else
914             cols++;
915
916           toggle++;
917         }
918     }
919 #if VERBOSE_TESTING
920       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
921                   _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
922                   rows, cols);
923 #endif
924
925   connect_attempts = 0;
926   /* Rows and columns are all sorted out, now iterate over all nodes and connect each
927    * to the node to its right and above.  Once this is over, we'll have our torus!
928    * Special case for the last node (if the rows and columns are not equal), connect
929    * to the first in the row to maintain topology.
930    */
931   for (i = 0; i < pg->total; i++)
932     {
933       /* First connect to the node to the right */
934       if (((i + 1) % cols != 0) && (i + 1 != pg->total))
935         nodeToConnect = i + 1;
936       else if (i + 1 == pg->total)
937         nodeToConnect = rows * cols - cols;
938       else
939         nodeToConnect = i - cols + 1;
940
941       connect_attempts += proc (pg, i, nodeToConnect);
942
943       if (i < cols)
944         nodeToConnect = (rows * cols) - cols + i;
945       else
946         nodeToConnect = i - cols;
947
948       if (nodeToConnect < pg->total)
949         connect_attempts += proc (pg, i, nodeToConnect);
950     }
951   natLog = log (pg->total);
952 #if VERBOSE_TESTING > 2
953   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
954               _("natural log of %d is %d, will run %d iterations\n"),
955              pg->total, natLog, (int) (natLog * percentage));
956   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Total connections added thus far: %u!\n"), connect_attempts);
957 #endif
958   smallWorldConnections = 0;
959   for (i = 0; i < (int) (natLog * percentage); i++)
960     {
961       for (j = 0; j < pg->total; j++)
962         {
963           /* Determine the row and column of node at position j on the 2d torus */
964           node1Row = j / cols;
965           node1Col = j - (node1Row * cols);
966           for (k = 0; k < pg->total; k++)
967             {
968               /* Determine the row and column of node at position k on the 2d torus */
969               node2Row = k / cols;
970               node2Col = k - (node2Row * cols);
971               /* Simple Cartesian distance */
972               distance = abs (node1Row - node2Row) + abs (node1Col - node2Col);
973               if (distance > 1)
974                 {
975                   /* Calculate probability as 1 over the square of the distance */
976                   probability = 1.0 / (distance * distance);
977                   /* Choose a random value between 0 and 1 */
978                   random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
979                                                               (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
980                   /* If random < probability, then connect the two nodes */
981                   if (random < probability)
982                     smallWorldConnections += proc (pg, j, k);
983
984                 }
985             }
986         }
987     }
988   connect_attempts += smallWorldConnections;
989 #if VERBOSE_TESTING > 2
990           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991                       _("Total connections added for small world: %d!\n"),
992                       smallWorldConnections);
993 #endif
994   return connect_attempts;
995 }
996
997
998
999 static int
1000 create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1001 {
1002   double temp_rand;
1003   unsigned int outer_count;
1004   unsigned int inner_count;
1005   int connect_attempts;
1006   double probability;
1007   char *p_string;
1008
1009   probability = 0.5; /* FIXME: default percentage? */
1010   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
1011                                                          "TESTING",
1012                                                          "PROBABILITY",
1013                                                          &p_string))
1014     {
1015       if (sscanf(p_string, "%lf", &probability) != 1)
1016         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1017                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1018                     p_string,
1019                     "PROBABILITY",
1020                     "TESTING");
1021       GNUNET_free (p_string);
1022     }
1023   connect_attempts = 0;
1024   for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
1025     {
1026       for (inner_count = outer_count + 1; inner_count < pg->total;
1027            inner_count++)
1028         {
1029           temp_rand = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
1030                                                          (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
1031 #if VERBOSE_TESTING
1032           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1033                       _("rand is %f probability is %f\n"), temp_rand,
1034                       probability);
1035 #endif
1036           if (temp_rand < probability)
1037             {
1038               connect_attempts += proc (pg, outer_count, inner_count);
1039             }
1040         }
1041     }
1042
1043   return connect_attempts;
1044 }
1045
1046 static int
1047 create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1048 {
1049   unsigned int i;
1050   unsigned int square;
1051   unsigned int rows;
1052   unsigned int cols;
1053   unsigned int toggle = 1;
1054   unsigned int nodeToConnect;
1055   int connect_attempts;
1056
1057   connect_attempts = 0;
1058
1059   square = floor (sqrt (pg->total));
1060   rows = square;
1061   cols = square;
1062
1063   if (square * square != pg->total)
1064     {
1065       while (rows * cols < pg->total)
1066         {
1067           if (toggle % 2 == 0)
1068             rows++;
1069           else
1070             cols++;
1071
1072           toggle++;
1073         }
1074     }
1075 #if VERBOSE_TESTING
1076       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1077                   _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
1078                   rows, cols);
1079 #endif
1080   /* Rows and columns are all sorted out, now iterate over all nodes and connect each
1081    * to the node to its right and above.  Once this is over, we'll have our torus!
1082    * Special case for the last node (if the rows and columns are not equal), connect
1083    * to the first in the row to maintain topology.
1084    */
1085   for (i = 0; i < pg->total; i++)
1086     {
1087       /* First connect to the node to the right */
1088       if (((i + 1) % cols != 0) && (i + 1 != pg->total))
1089         nodeToConnect = i + 1;
1090       else if (i + 1 == pg->total)
1091         nodeToConnect = rows * cols - cols;
1092       else
1093         nodeToConnect = i - cols + 1;
1094 #if VERBOSE_TESTING
1095           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1096                       "Connecting peer %d to peer %d\n",
1097                       i, nodeToConnect);
1098 #endif
1099       connect_attempts += proc(pg, i, nodeToConnect);
1100
1101       /* Second connect to the node immediately above */
1102       if (i < cols)
1103         nodeToConnect = (rows * cols) - cols + i;
1104       else
1105         nodeToConnect = i - cols;
1106
1107       if (nodeToConnect < pg->total)
1108         {
1109 #if VERBOSE_TESTING
1110           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1111                       "Connecting peer %d to peer %d\n",
1112                       i, nodeToConnect);
1113 #endif
1114           connect_attempts += proc(pg, i, nodeToConnect);
1115         }
1116
1117     }
1118
1119   return connect_attempts;
1120 }
1121
1122
1123
1124 static int
1125 create_clique (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1126 {
1127   unsigned int outer_count;
1128   unsigned int inner_count;
1129   int connect_attempts;
1130
1131   connect_attempts = 0;
1132
1133   for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
1134     {
1135       for (inner_count = outer_count + 1; inner_count < pg->total;
1136            inner_count++)
1137         {
1138 #if VERBOSE_TESTING
1139           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1140                       "Connecting peer %d to peer %d\n",
1141                       outer_count, inner_count);
1142 #endif
1143           connect_attempts += proc(pg, outer_count, inner_count);
1144         }
1145     }
1146
1147   return connect_attempts;
1148 }
1149
1150
1151 static int
1152 create_ring (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1153 {
1154   unsigned int count;
1155   int connect_attempts;
1156
1157   connect_attempts = 0;
1158
1159   /* Connect each peer to the next highest numbered peer */
1160   for (count = 0; count < pg->total - 1; count++)
1161     {
1162 #if VERBOSE_TESTING
1163           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1164                       "Connecting peer %d to peer %d\n",
1165                       count, count + 1);
1166 #endif
1167       connect_attempts += proc(pg, count, count + 1);
1168     }
1169
1170   /* Connect the last peer to the first peer */
1171   connect_attempts += proc(pg, pg->total - 1, 0);
1172
1173   return connect_attempts;
1174 }
1175
1176
1177 /**
1178  * Iterator for writing friends of a peer to a file.
1179  *
1180  * @param cls closure, an open writable file handle
1181  * @param key the key the daemon was stored under
1182  * @param value the GNUNET_TESTING_Daemon that needs to be written.
1183  *
1184  * @return GNUNET_YES to continue iteration
1185  *
1186  * TODO: Could replace friend_file_iterator and blacklist_file_iterator
1187  *       with a single file_iterator that takes a closure which contains
1188  *       the prefix to write before the peer.  Then this could be used
1189  *       for blacklisting multiple transports and writing the friend
1190  *       file.  I'm sure *someone* will complain loudly about other
1191  *       things that negate these functions even existing so no point in
1192  *       "fixing" now.
1193  */
1194 static int
1195 friend_file_iterator (void *cls,
1196                   const GNUNET_HashCode * key,
1197                   void *value)
1198 {
1199   FILE *temp_friend_handle = cls;
1200   struct GNUNET_TESTING_Daemon *peer = value;
1201   struct GNUNET_PeerIdentity *temppeer;
1202   struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
1203
1204   temppeer = &peer->id;
1205   GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
1206   fprintf(temp_friend_handle, "%s\n", (char *)&peer_enc);
1207
1208   return GNUNET_YES;
1209 }
1210
1211
1212 /**
1213  * Iterator for writing blacklist data to appropriate files.
1214  *
1215  * @param cls closure, an open writable file handle
1216  * @param key the key the daemon was stored under
1217  * @param value the GNUNET_TESTING_Daemon that needs to be written.
1218  *
1219  * @return GNUNET_YES to continue iteration
1220  */
1221 static int
1222 blacklist_file_iterator (void *cls,
1223                          const GNUNET_HashCode * key,
1224                          void *value)
1225 {
1226   FILE *temp_blacklist_handle = cls;
1227   struct GNUNET_TESTING_Daemon *peer = value;
1228   struct GNUNET_PeerIdentity *temppeer;
1229   struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
1230
1231   temppeer = &peer->id;
1232   GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
1233   fprintf(temp_blacklist_handle, "tcp:%s\n", (char *)&peer_enc);
1234
1235   return GNUNET_YES;
1236 }
1237
1238 /*
1239  * Create the friend files based on the PeerConnection's
1240  * of each peer in the peer group, and copy the files
1241  * to the appropriate place
1242  *
1243  * @param pg the peer group we are dealing with
1244  */
1245 static int
1246 create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
1247 {
1248   FILE *temp_friend_handle;
1249   unsigned int pg_iter;
1250   char *temp_service_path;
1251   pid_t *pidarr;
1252   char *arg;
1253   char * mytemp;
1254   enum GNUNET_OS_ProcessStatusType type;
1255   unsigned long return_code;
1256   int count;
1257   int ret;
1258   int max_wait = 10;
1259
1260   pidarr = GNUNET_malloc(sizeof(pid_t) * pg->total);
1261   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1262     {
1263       mytemp = GNUNET_DISK_mktemp("friends");
1264       GNUNET_assert(mytemp != NULL);
1265       temp_friend_handle = fopen (mytemp, "wt");
1266       GNUNET_assert(temp_friend_handle != NULL);
1267       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].allowed_peers, &friend_file_iterator, temp_friend_handle);
1268       fclose(temp_friend_handle);
1269
1270       if (GNUNET_OK !=
1271           GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
1272         {
1273           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1274                       _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
1275                       "SERVICEHOME",
1276                       "PATHS");
1277           if (UNLINK (mytemp) != 0)
1278             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
1279           GNUNET_free (mytemp);
1280           break;
1281         }
1282
1283       if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
1284         {
1285           GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
1286           pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
1287                                          "mv", mytemp, arg, NULL);
1288 #if VERBOSE_TESTING
1289           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1290                       _("Copying file with command cp %s %s\n"), mytemp, arg);
1291 #endif
1292
1293           GNUNET_free(arg);
1294         }
1295       else /* Remote, scp the file to the correct place */
1296         {
1297           if (NULL != pg->peers[pg_iter].daemon->username)
1298             GNUNET_asprintf (&arg, "%s@%s:%s/friends", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
1299           else
1300             GNUNET_asprintf (&arg, "%s:%s/friends", pg->peers[pg_iter].daemon->hostname, temp_service_path);
1301           pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
1302                                          "scp", mytemp, arg, NULL);
1303
1304 #if VERBOSE_TESTING
1305           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1306                       _("Copying file with command scp %s %s\n"), mytemp, arg);
1307 #endif
1308           GNUNET_free(arg);
1309         }
1310       GNUNET_free (temp_service_path);
1311       GNUNET_free (mytemp);
1312     }
1313
1314   count = 0;
1315   ret = GNUNET_SYSERR;
1316   while ((count < max_wait) && (ret != GNUNET_OK))
1317     {
1318       ret = GNUNET_OK;
1319       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1320         {
1321 #if VERBOSE_TESTING
1322           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1323                       _("Checking copy status of file %d\n"), pg_iter);
1324 #endif
1325           if (pidarr[pg_iter] != 0) /* Check for already completed! */
1326             {
1327               if (GNUNET_OS_process_status(pidarr[pg_iter], &type, &return_code) != GNUNET_OK)
1328                 {
1329                   ret = GNUNET_SYSERR;
1330                 }
1331               else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
1332                 {
1333                   ret = GNUNET_SYSERR;
1334                 }
1335               else
1336                 {
1337                   pidarr[pg_iter] = 0;
1338 #if VERBOSE_TESTING
1339             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1340                       _("File %d copied\n"), pg_iter);
1341 #endif
1342                 }
1343             }
1344         }
1345       count++;
1346       if (ret == GNUNET_SYSERR)
1347         {
1348           sleep(1);
1349         }
1350     }
1351
1352 #if VERBOSE_TESTING
1353     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1354                 _("Finished copying all friend files!\n"));
1355 #endif
1356   GNUNET_free(pidarr);
1357   return ret;
1358 }
1359
1360
1361 /*
1362  * Create the blacklist files based on the PeerConnection's
1363  * of each peer in the peer group, and copy the files
1364  * to the appropriate place.
1365  *
1366  * @param pg the peer group we are dealing with
1367  */
1368 static int
1369 create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg)
1370 {
1371   FILE *temp_friend_handle;
1372   unsigned int pg_iter;
1373   char *temp_service_path;
1374   pid_t *pidarr;
1375   char *arg;
1376   char *mytemp;
1377   enum GNUNET_OS_ProcessStatusType type;
1378   unsigned long return_code;
1379   int count;
1380   int ret;
1381   int max_wait = 10;
1382
1383   pidarr = GNUNET_malloc(sizeof(pid_t) * pg->total);
1384   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1385     {
1386       mytemp = GNUNET_DISK_mktemp("blacklist");
1387       GNUNET_assert(mytemp != NULL);
1388       temp_friend_handle = fopen (mytemp, "wt");
1389       GNUNET_assert(temp_friend_handle != NULL);
1390       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].blacklisted_peers, &blacklist_file_iterator, temp_friend_handle);
1391       fclose(temp_friend_handle);
1392
1393       if (GNUNET_OK !=
1394           GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
1395         {
1396           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1397                       _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
1398                       "SERVICEHOME",
1399                       "PATHS");
1400           if (UNLINK (mytemp) != 0)
1401             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
1402           GNUNET_free (mytemp);
1403           break;
1404         }
1405
1406       if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
1407         {
1408           GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path);
1409           pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
1410                                          "mv", mytemp, arg, NULL);
1411 #if VERBOSE_TESTING
1412           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1413                       _("Copying file with command cp %s %s\n"), mytemp, arg);
1414 #endif
1415
1416           GNUNET_free(arg);
1417         }
1418       else /* Remote, scp the file to the correct place */
1419         {
1420           if (NULL != pg->peers[pg_iter].daemon->username)
1421             GNUNET_asprintf (&arg, "%s@%s:%s/blacklist", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
1422           else
1423             GNUNET_asprintf (&arg, "%s:%s/blacklist", pg->peers[pg_iter].daemon->hostname, temp_service_path);
1424           pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
1425                                          "scp", mytemp, arg, NULL);
1426
1427 #if VERBOSE_TESTING
1428           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1429                       _("Copying file with command scp %s %s\n"), mytemp, arg);
1430 #endif
1431           GNUNET_free(arg);
1432         }
1433       GNUNET_free (temp_service_path);
1434       GNUNET_free (mytemp);
1435     }
1436
1437   count = 0;
1438   ret = GNUNET_SYSERR;
1439   while ((count < max_wait) && (ret != GNUNET_OK))
1440     {
1441       ret = GNUNET_OK;
1442       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1443         {
1444 #if VERBOSE_TESTING
1445           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1446                       _("Checking copy status of file %d\n"), pg_iter);
1447 #endif
1448           if (pidarr[pg_iter] != 0) /* Check for already completed! */
1449             {
1450               if (GNUNET_OS_process_status(pidarr[pg_iter], &type, &return_code) != GNUNET_OK)
1451                 {
1452                   ret = GNUNET_SYSERR;
1453                 }
1454               else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
1455                 {
1456                   ret = GNUNET_SYSERR;
1457                 }
1458               else
1459                 {
1460                   pidarr[pg_iter] = 0;
1461 #if VERBOSE_TESTING
1462             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1463                       _("File %d copied\n"), pg_iter);
1464 #endif
1465                 }
1466             }
1467         }
1468       count++;
1469       if (ret == GNUNET_SYSERR)
1470         {
1471           sleep(1);
1472         }
1473     }
1474
1475 #if VERBOSE_TESTING
1476     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1477                 _("Finished copying all blacklist files!\n"));
1478 #endif
1479   GNUNET_free(pidarr);
1480   return ret;
1481 }
1482
1483
1484 /**
1485  * Internal notification of a connection, kept so that we can ensure some connections
1486  * happen instead of flooding all testing daemons with requests to connect.
1487  */
1488 static void internal_connect_notify (void *cls,
1489                                      const struct GNUNET_PeerIdentity *first,
1490                                      const struct GNUNET_PeerIdentity *second,
1491                                      const struct GNUNET_CONFIGURATION_Handle *first_cfg,
1492                                      const struct GNUNET_CONFIGURATION_Handle *second_cfg,
1493                                      struct GNUNET_TESTING_Daemon *first_daemon,
1494                                      struct GNUNET_TESTING_Daemon *second_daemon,
1495                                      const char *emsg)
1496 {
1497   struct GNUNET_TESTING_PeerGroup *pg = cls;
1498   outstanding_connects--;
1499
1500   pg->notify_connection(pg->notify_connection_cls, first, second, first_cfg, second_cfg, first_daemon, second_daemon, emsg);
1501
1502 }
1503
1504 static void schedule_connect(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1505 {
1506   struct ConnectContext *connect_context = cls;
1507
1508   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1509     return;
1510
1511   if (outstanding_connects > MAX_OUTSTANDING_CONNECTIONS)
1512     {
1513 #if VERBOSE_TESTING > 2
1514           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1515                       _("Delaying connect, we have too many outstanding connections!\n"));
1516 #endif
1517       GNUNET_SCHEDULER_add_delayed(connect_context->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3), &schedule_connect, connect_context);
1518     }
1519   else
1520     {
1521 #if VERBOSE_TESTING > 2
1522           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1523                       _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
1524 #endif
1525       outstanding_connects++;
1526       GNUNET_TESTING_daemons_connect (connect_context->first,
1527                                       connect_context->second,
1528                                       CONNECT_TIMEOUT,
1529                                       CONNECT_ATTEMPTS,
1530                                       &internal_connect_notify,
1531                                       connect_context->pg);
1532       GNUNET_free(connect_context);
1533     }
1534 }
1535
1536 /**
1537  * Iterator for actually scheduling connections to be created
1538  * between two peers.
1539  *
1540  * @param cls closure, a GNUNET_TESTING_Daemon
1541  * @param key the key the second Daemon was stored under
1542  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
1543  *
1544  * @return GNUNET_YES to continue iteration
1545  */
1546 static int
1547 connect_iterator (void *cls,
1548                   const GNUNET_HashCode * key,
1549                   void *value)
1550 {
1551   struct PeerData *first = cls;
1552   struct GNUNET_TESTING_Daemon *second = value;
1553   struct ConnectContext *connect_context;
1554
1555   connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
1556   connect_context->pg = first->pg;
1557   connect_context->first = first->daemon;
1558   connect_context->second = second;
1559   GNUNET_SCHEDULER_add_now(first->pg->sched, &schedule_connect, connect_context);
1560
1561   return GNUNET_YES;
1562 }
1563
1564 /**
1565  * Iterator for copying all entries in the allowed hashmap to the
1566  * connect hashmap.
1567  *
1568  * @param cls closure, a GNUNET_TESTING_Daemon
1569  * @param key the key the second Daemon was stored under
1570  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
1571  *
1572  * @return GNUNET_YES to continue iteration
1573  */
1574 static int
1575 copy_topology_iterator (void *cls,
1576                   const GNUNET_HashCode * key,
1577                   void *value)
1578 {
1579   struct PeerData *first = cls;
1580
1581   GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(first->connect_peers, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1582
1583   return GNUNET_YES;
1584 }
1585
1586 /**
1587  * Make the peers to connect the same as those that are allowed to be
1588  * connected.
1589  *
1590  * @param pg the peer group
1591  */
1592 static int
1593 copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg)
1594 {
1595   unsigned int pg_iter;
1596   int ret;
1597   int total;
1598
1599   total = 0;
1600   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1601     {
1602       ret = GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].allowed_peers, &copy_topology_iterator, &pg->peers[pg_iter]);
1603       if (GNUNET_SYSERR == ret)
1604         return GNUNET_SYSERR;
1605
1606       total = total + ret;
1607     }
1608
1609   return total;
1610 }
1611
1612
1613 /*
1614  * Connect the topology as specified by the PeerConnection's
1615  * of each peer in the peer group
1616  *
1617  * @param pg the peer group we are dealing with
1618  *
1619  * @return the number of connections that will be attempted
1620  */
1621 static int
1622 connect_topology (struct GNUNET_TESTING_PeerGroup *pg)
1623 {
1624   unsigned int pg_iter;
1625   int ret;
1626   int total;
1627 #if OLD
1628   struct PeerConnection *connection_iter;
1629   struct ConnectContext *connect_context;
1630 #endif
1631
1632   total = 0;
1633   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1634     {
1635       ret = GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &connect_iterator, &pg->peers[pg_iter]);
1636       if (GNUNET_SYSERR == ret)
1637         return GNUNET_SYSERR;
1638
1639       total = total + ret;
1640
1641 #if OLD
1642       connection_iter = ;
1643       while (connection_iter != NULL)
1644         {
1645           connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
1646           connect_context->pg = pg;
1647           connect_context->first = ;
1648           connect_context->second = connection_iter->daemon;
1649           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_connect, connect_context);
1650           connection_iter = connection_iter->next;
1651         }
1652 #endif
1653     }
1654   return total;
1655 }
1656
1657
1658 /*
1659  * Takes a peer group and creates a topology based on the
1660  * one specified.  Creates a topology means generates friend
1661  * files for the peers so they can only connect to those allowed
1662  * by the topology.  This will only have an effect once peers
1663  * are started if the FRIENDS_ONLY option is set in the base
1664  * config.  Also takes an optional restrict topology which
1665  * disallows direct TCP connections UNLESS they are specified in
1666  * the restricted topology.
1667  *
1668  * @param pg the peer group struct representing the running peers
1669  * @param topology which topology to connect the peers in
1670  * @param restrict_topology allow only direct TCP connections in this topology
1671  *                          use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions
1672  *
1673  * @return the maximum number of connections were all allowed peers
1674  *         connected to each other
1675  */
1676 int
1677 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg,
1678                                 enum GNUNET_TESTING_Topology topology,
1679                                 enum GNUNET_TESTING_Topology restrict_topology)
1680 {
1681   int ret;
1682   int num_connections;
1683   int unblacklisted_connections;
1684
1685   GNUNET_assert (pg->notify_connection != NULL);
1686   ret = GNUNET_OK;
1687
1688   switch (topology)
1689     {
1690     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
1691 #if VERBOSE_TESTING
1692       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1693                   _("Creating clique topology\n"));
1694 #endif
1695       num_connections = create_clique (pg, &add_allowed_connections);
1696       break;
1697     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
1698 #if VERBOSE_TESTING
1699       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1700                   _("Creating small world (ring) topology\n"));
1701 #endif
1702       num_connections = create_small_world_ring (pg, &add_allowed_connections);
1703       break;
1704     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
1705 #if VERBOSE_TESTING
1706       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1707                   _("Creating small world (2d-torus) topology\n"));
1708 #endif
1709       num_connections = create_small_world (pg, &add_allowed_connections);
1710       break;
1711     case GNUNET_TESTING_TOPOLOGY_RING:
1712 #if VERBOSE_TESTING
1713       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1714                   _("Creating ring topology\n"));
1715 #endif
1716       num_connections = create_ring (pg, &add_allowed_connections);
1717       break;
1718     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
1719 #if VERBOSE_TESTING
1720       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1721                   _("Creating 2d torus topology\n"));
1722 #endif
1723       num_connections = create_2d_torus (pg, &add_allowed_connections);
1724       break;
1725     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
1726 #if VERBOSE_TESTING
1727       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1728                   _("Creating Erdos-Renyi topology\n"));
1729 #endif
1730       num_connections = create_erdos_renyi (pg, &add_allowed_connections);
1731       break;
1732     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
1733 #if VERBOSE_TESTING
1734       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1735                   _("Creating InterNAT topology\n"));
1736 #endif
1737       num_connections = create_nated_internet (pg, &add_allowed_connections);
1738       break;
1739     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
1740 #if VERBOSE_TESTING
1741       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1742                   _("Creating Scale Free topology\n"));
1743 #endif
1744       num_connections = create_scale_free (pg, &add_allowed_connections);
1745       break;
1746     case GNUNET_TESTING_TOPOLOGY_NONE:
1747       num_connections = 0;
1748       break;
1749     default:
1750       num_connections = 0;
1751       break;
1752     }
1753   if (num_connections < 1)
1754     return GNUNET_SYSERR;
1755
1756   if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
1757     {
1758       ret = create_and_copy_friend_files(pg);
1759     }
1760
1761   if (ret != GNUNET_OK)
1762     {
1763 #if VERBOSE_TESTING
1764       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1765                   _("Failed during friend file copying!\n"));
1766 #endif
1767       return GNUNET_SYSERR;
1768     }
1769   else
1770     {
1771 #if VERBOSE_TESTING
1772           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1773                       _("Friend files created/copied successfully!\n"));
1774 #endif
1775     }
1776
1777   /**
1778    * Use the create clique method to initially set all connections
1779    * as blacklisted.
1780    */
1781   create_clique (pg, &blacklist_connections);
1782   unblacklisted_connections = 0;
1783   /**
1784    * Un-blacklist connections as per the topology specified
1785    */
1786   switch (restrict_topology)
1787     {
1788     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
1789 #if VERBOSE_TESTING
1790       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1791                   _("Blacklisting all but clique topology\n"));
1792 #endif
1793       unblacklisted_connections = create_clique (pg, &unblacklist_connections);
1794       break;
1795     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
1796 #if VERBOSE_TESTING
1797       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1798                   _("Blacklisting all but small world (ring) topology\n"));
1799 #endif
1800       unblacklisted_connections = create_small_world_ring (pg, &unblacklist_connections);
1801       break;
1802     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
1803 #if VERBOSE_TESTING
1804       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1805                   _("Blacklisting all but small world (2d-torus) topology\n"));
1806 #endif
1807       unblacklisted_connections = create_small_world (pg, &unblacklist_connections);
1808       break;
1809     case GNUNET_TESTING_TOPOLOGY_RING:
1810 #if VERBOSE_TESTING
1811       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1812                   _("Blacklisting all but ring topology\n"));
1813 #endif
1814       unblacklisted_connections = create_ring (pg, &unblacklist_connections);
1815       break;
1816     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
1817 #if VERBOSE_TESTING
1818       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1819                   _("Blacklisting all but 2d torus topology\n"));
1820 #endif
1821       unblacklisted_connections = create_2d_torus (pg, &unblacklist_connections);
1822       break;
1823     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
1824 #if VERBOSE_TESTING
1825       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1826                   _("Blacklisting all but Erdos-Renyi topology\n"));
1827 #endif
1828       unblacklisted_connections = create_erdos_renyi (pg, &unblacklist_connections);
1829       break;
1830     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
1831 #if VERBOSE_TESTING
1832       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1833                   _("Blacklisting all but InterNAT topology\n"));
1834 #endif
1835       unblacklisted_connections = create_nated_internet (pg, &unblacklist_connections);
1836       break;
1837     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
1838 #if VERBOSE_TESTING
1839       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1840                   _("Blacklisting all but Scale Free topology\n"));
1841 #endif
1842       unblacklisted_connections = create_scale_free (pg, &unblacklist_connections);
1843       break;
1844     case GNUNET_TESTING_TOPOLOGY_NONE:
1845       /* Fall through */
1846     default:
1847       break;
1848     }
1849
1850   if (unblacklisted_connections > 0)
1851   {
1852     ret = create_and_copy_blacklist_files(pg);
1853     if (ret != GNUNET_OK)
1854       {
1855 #if VERBOSE_TESTING
1856         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1857                     _("Failed during blacklist file copying!\n"));
1858 #endif
1859         return GNUNET_SYSERR;
1860       }
1861     else
1862       {
1863 #if VERBOSE_TESTING
1864         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1865                     _("Blacklist files created/copied successfully!\n"));
1866 #endif
1867       }
1868   }
1869
1870
1871   return num_connections;
1872 }
1873
1874 struct RandomContext
1875 {
1876   /**
1877    * The peergroup
1878    */
1879   struct GNUNET_TESTING_PeerGroup *pg;
1880
1881   /**
1882    * uid of the first peer
1883    */
1884   uint32_t first_uid;
1885
1886   /**
1887    * Peer data for first peer.
1888    */
1889   struct PeerData *first;
1890
1891   /**
1892    * Random percentage to use
1893    */
1894   double percentage;
1895 };
1896
1897 struct MinimumContext
1898 {
1899   /**
1900    * The peergroup
1901    */
1902   struct GNUNET_TESTING_PeerGroup *pg;
1903
1904   /**
1905    * uid of the first peer
1906    */
1907   uint32_t first_uid;
1908
1909   /**
1910    * Peer data for first peer.
1911    */
1912   struct PeerData *first;
1913
1914   /**
1915    * Number of conns per peer
1916    */
1917   unsigned int num_to_add;
1918
1919   /**
1920    * Permuted array of all possible connections.  Only add the Nth
1921    * peer if it's in the Nth position.
1922    */
1923   unsigned int *pg_array;
1924
1925   /**
1926    * What number is the current element we are iterating over?
1927    */
1928   unsigned int current;
1929 };
1930
1931 struct DFSContext
1932 {
1933   /**
1934    * The peergroup
1935    */
1936   struct GNUNET_TESTING_PeerGroup *pg;
1937
1938   /**
1939    * uid of the first peer
1940    */
1941   uint32_t first_uid;
1942
1943   /**
1944    * uid of the second peer
1945    */
1946   uint32_t second_uid;
1947
1948   /**
1949    * Peer data for first peer.
1950    */
1951   struct PeerData *first;
1952
1953   /**
1954    * Which peer has been chosen as the one to add?
1955    */
1956   unsigned int chosen;
1957
1958   /**
1959    * What number is the current element we are iterating over?
1960    */
1961   unsigned int current;
1962 };
1963
1964 /**
1965  * Iterator for choosing random peers to connect.
1966  *
1967  * @param cls closure, a RandomContext
1968  * @param key the key the second Daemon was stored under
1969  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
1970  *
1971  * @return GNUNET_YES to continue iteration
1972  */
1973 static int
1974 random_connect_iterator (void *cls,
1975                   const GNUNET_HashCode * key,
1976                   void *value)
1977 {
1978   struct RandomContext *random_ctx = cls;
1979   double random_number;
1980   uint32_t second_pos;
1981   GNUNET_HashCode first_hash;
1982   random_number = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
1983                    (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
1984   if (random_number < random_ctx->percentage)
1985   {
1986     GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(random_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1987   }
1988   /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */
1989   uid_from_hash(key, &second_pos);
1990   hash_from_uid(random_ctx->first_uid, &first_hash);
1991   GNUNET_assert(random_ctx->pg->total > second_pos);
1992   GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(random_ctx->pg->peers[second_pos].connect_peers, &first_hash, random_ctx->first->daemon));
1993
1994   return GNUNET_YES;
1995 }
1996
1997 /**
1998  * Iterator for adding at least X peers to a peers connection set.
1999  *
2000  * @param cls closure, MinimumContext
2001  * @param key the key the second Daemon was stored under
2002  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2003  *
2004  * @return GNUNET_YES to continue iteration
2005  */
2006 static int
2007 minimum_connect_iterator (void *cls,
2008                   const GNUNET_HashCode * key,
2009                   void *value)
2010 {
2011   struct MinimumContext *min_ctx = cls;
2012   uint32_t second_pos;
2013   GNUNET_HashCode first_hash;
2014   unsigned int i;
2015
2016   if (GNUNET_CONTAINER_multihashmap_size(min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add)
2017   {
2018     for (i = 0; i < min_ctx->num_to_add; i++)
2019     {
2020       if (min_ctx->pg_array[i] == min_ctx->current)
2021       {
2022         GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(min_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2023         uid_from_hash(key, &second_pos);
2024         hash_from_uid(min_ctx->first_uid, &first_hash);
2025         GNUNET_assert(min_ctx->pg->total > second_pos);
2026         GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(min_ctx->pg->peers[second_pos].connect_peers_working_set, &first_hash, min_ctx->first->daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2027         /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */
2028         GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(min_ctx->pg->peers[second_pos].connect_peers, &first_hash, min_ctx->first->daemon));
2029       }
2030     }
2031     min_ctx->current++;
2032     return GNUNET_YES;
2033   }
2034   else
2035     return GNUNET_NO; /* We can stop iterating, we have enough peers! */
2036
2037 }
2038
2039
2040 /**
2041  * Iterator for adding peers to a connection set based on a depth first search.
2042  *
2043  * @param cls closure, MinimumContext
2044  * @param key the key the second daemon was stored under
2045  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2046  *
2047  * @return GNUNET_YES to continue iteration
2048  */
2049 static int
2050 dfs_connect_iterator (void *cls,
2051                   const GNUNET_HashCode * key,
2052                   void *value)
2053 {
2054   struct DFSContext *dfs_ctx = cls;
2055   GNUNET_HashCode first_hash;
2056
2057   if (dfs_ctx->current == dfs_ctx->chosen)
2058     {
2059       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(dfs_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2060       uid_from_hash(key, &dfs_ctx->second_uid);
2061       hash_from_uid(dfs_ctx->first_uid, &first_hash);
2062       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(dfs_ctx->pg->peers[dfs_ctx->second_uid].connect_peers_working_set, &first_hash, dfs_ctx->first->daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2063       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(dfs_ctx->pg->peers[dfs_ctx->second_uid].connect_peers, &first_hash, dfs_ctx->first->daemon));
2064       /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */
2065       return GNUNET_NO; /* We have found our peer, don't iterate more */
2066     }
2067
2068   dfs_ctx->current++;
2069   return GNUNET_YES;
2070 }
2071
2072
2073 /**
2074  * From the set of connections possible, choose percentage percent of connections
2075  * to actually connect.
2076  *
2077  * @param pg the peergroup we are dealing with
2078  * @param percentage what percent of total connections to make
2079  */
2080 void
2081 choose_random_connections(struct GNUNET_TESTING_PeerGroup *pg, double percentage)
2082 {
2083   struct RandomContext random_ctx;
2084   uint32_t pg_iter;
2085
2086   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2087     {
2088       random_ctx.first_uid = pg_iter;
2089       random_ctx.first = &pg->peers[pg_iter];
2090       random_ctx.percentage = percentage;
2091       random_ctx.pg = pg;
2092       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(pg->total);
2093       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &random_connect_iterator, &random_ctx);
2094       /* Now remove the old connections */
2095       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2096       /* And replace with the random set */
2097       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2098     }
2099 }
2100
2101 /**
2102  * From the set of connections possible, choose at least num connections per
2103  * peer.
2104  *
2105  * @param pg the peergroup we are dealing with
2106  * @param num how many connections at least should each peer have (if possible)?
2107  */
2108 void
2109 choose_minimum(struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2110 {
2111   struct MinimumContext minimum_ctx;
2112   uint32_t pg_iter;
2113
2114   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2115     {
2116       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2117     }
2118
2119   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2120     {
2121       minimum_ctx.first_uid = pg_iter;
2122       minimum_ctx.pg_array = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2123       minimum_ctx.first = &pg->peers[pg_iter];
2124       minimum_ctx.pg = pg;
2125       minimum_ctx.num_to_add = num;
2126       minimum_ctx.current = 0;
2127       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(pg->total);
2128       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &minimum_connect_iterator, &minimum_ctx);
2129     }
2130
2131   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2132     {
2133       /* Remove the "old" connections */
2134       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2135       /* And replace with the working set */
2136       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2137       fprintf(stderr, "Finished! Hashmap size %u\n", GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2138     }
2139
2140 }
2141
2142
2143 static unsigned int count_workingset_connections(struct GNUNET_TESTING_PeerGroup *pg)
2144 {
2145   unsigned int count;
2146   unsigned int pg_iter;
2147
2148   count = 0;
2149
2150   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2151     {
2152       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2153     }
2154
2155   return count;
2156 }
2157
2158
2159 static unsigned int count_allowed_connections(struct GNUNET_TESTING_PeerGroup *pg)
2160 {
2161   unsigned int count;
2162   unsigned int pg_iter;
2163
2164   count = 0;
2165
2166   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2167     {
2168       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers);
2169     }
2170
2171   return count;
2172 }
2173
2174 /**
2175  * From the set of connections possible, choose at least num connections per
2176  * peer based on depth first traversal of peer connections.  If DFS leaves
2177  * peers unconnected, ensure those peers get connections.
2178  *
2179  * @param pg the peergroup we are dealing with
2180  * @param num how many connections at least should each peer have (if possible)?
2181  */
2182 void
2183 perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2184 {
2185   struct DFSContext dfs_ctx;
2186   uint32_t pg_iter;
2187   uint32_t dfs_count;
2188   uint32_t starting_peer;
2189   uint32_t least_connections;
2190   GNUNET_HashCode second_hash;
2191
2192   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2193     {
2194       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2195     }
2196
2197   starting_peer = 0;
2198   dfs_count = 0;
2199   while ((count_workingset_connections(pg) < num * pg->total) && (count_allowed_connections(pg) > 0))
2200     {
2201       if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */
2202         {
2203           least_connections = -1; /* Set to very high number */
2204           for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2205             {
2206               if (GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set) < least_connections)
2207                 {
2208                   starting_peer = pg_iter;
2209                   least_connections = GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2210                 }
2211             }
2212         }
2213
2214       if (GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers) == 0)  /* Ensure there is at least one peer left to connect! */
2215         {
2216           dfs_count = 0;
2217           continue;
2218         }
2219
2220       /* Choose a random peer from the chosen peers set of connections to add */
2221       dfs_ctx.chosen = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers));
2222       dfs_ctx.first_uid = starting_peer;
2223       dfs_ctx.first = &pg->peers[starting_peer];
2224       dfs_ctx.pg = pg;
2225       dfs_ctx.current = 0;
2226
2227       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[starting_peer].connect_peers, &dfs_connect_iterator, &dfs_ctx);
2228       /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */
2229       hash_from_uid(dfs_ctx.second_uid, &second_hash);
2230       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[starting_peer].connect_peers, &second_hash, pg->peers[dfs_ctx.second_uid].daemon));
2231       starting_peer = dfs_ctx.second_uid;
2232     }
2233
2234   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2235     {
2236
2237     }
2238
2239   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2240     {
2241       /* Remove the "old" connections */
2242       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2243       /* And replace with the working set */
2244       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2245       fprintf(stderr, "Finished! Hashmap size %u\n", GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2246     }
2247
2248 }
2249
2250 /*
2251  * @param pg the peer group struct representing the running peers
2252  * @param topology which topology to connect the peers in
2253  * @param options options for connecting the topology
2254  * @param option_modifier modifier for options that take a parameter
2255  *
2256  * There are many ways to connect peers that are supported by this function.
2257  * To connect peers in the same topology that was created via the
2258  * GNUNET_TESTING_create_topology, the topology variable must be set to
2259  * GNUNET_TESTING_TOPOLOGY_NONE.  If the topology variable is specified,
2260  * a new instance of that topology will be generated and attempted to be
2261  * connected.  This could result in some connections being impossible,
2262  * because some topologies are non-deterministic.
2263  *
2264  */
2265 int
2266 GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
2267                                  enum GNUNET_TESTING_Topology topology,
2268                                  enum GNUNET_TESTING_TopologyOption options,
2269                                  double option_modifier)
2270 {
2271   int num_connections;
2272
2273   switch (topology)
2274       {
2275       case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2276   #if VERBOSE_TESTING
2277         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2278                     _("Creating clique topology\n"));
2279   #endif
2280         num_connections = create_clique (pg, &add_actual_connections);
2281         break;
2282       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2283   #if VERBOSE_TESTING
2284         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2285                     _("Creating small world (ring) topology\n"));
2286   #endif
2287         num_connections = create_small_world_ring (pg, &add_actual_connections);
2288         break;
2289       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2290   #if VERBOSE_TESTING
2291         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2292                     _("Creating small world (2d-torus) topology\n"));
2293   #endif
2294         num_connections = create_small_world (pg, &add_actual_connections);
2295         break;
2296       case GNUNET_TESTING_TOPOLOGY_RING:
2297   #if VERBOSE_TESTING
2298         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2299                     _("Creating ring topology\n"));
2300   #endif
2301         num_connections = create_ring (pg, &add_actual_connections);
2302         break;
2303       case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2304   #if VERBOSE_TESTING
2305         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2306                     _("Creating 2d torus topology\n"));
2307   #endif
2308         num_connections = create_2d_torus (pg, &add_actual_connections);
2309         break;
2310       case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2311   #if VERBOSE_TESTING
2312         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2313                     _("Creating Erdos-Renyi topology\n"));
2314   #endif
2315         num_connections = create_erdos_renyi (pg, &add_actual_connections);
2316         break;
2317       case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2318   #if VERBOSE_TESTING
2319         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2320                     _("Creating InterNAT topology\n"));
2321   #endif
2322         num_connections = create_nated_internet (pg, &add_actual_connections);
2323         break;
2324       case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2325   #if VERBOSE_TESTING
2326         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2327                     _("Creating Scale Free topology\n"));
2328   #endif
2329         num_connections = create_scale_free (pg, &add_actual_connections);
2330         break;
2331       case GNUNET_TESTING_TOPOLOGY_NONE:
2332         num_connections = copy_allowed_topology(pg);
2333         break;
2334       default:
2335         GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Unknown topology specification, can't connect peers!\n");
2336         return GNUNET_SYSERR;
2337       }
2338
2339   switch (options)
2340     {
2341     case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM: /* Create a random subset of total connections based on parameter */
2342       choose_random_connections(pg, option_modifier);
2343       break;
2344     case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM: /* Create at least X connections per peer (if possible!) */
2345       choose_minimum(pg, (unsigned int)option_modifier);
2346       break;
2347     case GNUNET_TESTING_TOPOLOGY_OPTION_DFS: /* Choose a random starting point, randomly walk graph, try to get each peer X connections */
2348       perform_dfs(pg, (int)option_modifier);
2349       break;
2350     case GNUNET_TESTING_TOPOLOGY_OPTION_NONE:
2351       /* Fall through */
2352     case GNUNET_TESTING_TOPOLOGY_OPTION_ALL:
2353       /* Fall through */
2354     default:
2355       break;
2356     }
2357
2358   return connect_topology(pg);
2359 }
2360
2361 /**
2362  * Function which continues a peer group starting up
2363  * after successfully generating hostkeys for each peer.
2364  *
2365  * @param pg the peer group to continue starting
2366  *
2367  */
2368 void
2369 GNUNET_TESTING_daemons_continue_startup(struct GNUNET_TESTING_PeerGroup *pg)
2370 {
2371   unsigned int i;
2372
2373   for (i = 0; i < pg->total; i++)
2374     {
2375       GNUNET_TESTING_daemon_continue_startup(pg->peers[i].daemon);
2376     }
2377 }
2378
2379 /**
2380  * Start count gnunetd processes with the same set of transports and
2381  * applications.  The port numbers (any option called "PORT") will be
2382  * adjusted to ensure that no two peers running on the same system
2383  * have the same port(s) in their respective configurations.
2384  *
2385  * @param sched scheduler to use
2386  * @param cfg configuration template to use
2387  * @param total number of daemons to start
2388  * @param timeout total time allowed for peers to start
2389  * @param hostkey_callback function to call on each peers hostkey generation
2390  *        if NULL, peers will be started by this call, if non-null,
2391  *        GNUNET_TESTING_daemons_continue_startup must be called after
2392  *        successful hostkey generation
2393  * @param hostkey_cls closure for hostkey callback
2394  * @param cb function to call on each daemon that was started
2395  * @param cb_cls closure for cb
2396  * @param connect_callback function to call each time two hosts are connected
2397  * @param connect_callback_cls closure for connect_callback
2398  * @param hostnames space-separated list of hostnames to use; can be NULL (to run
2399  *        everything on localhost).
2400  * @return NULL on error, otherwise handle to control peer group
2401  */
2402 struct GNUNET_TESTING_PeerGroup *
2403 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
2404                               const struct GNUNET_CONFIGURATION_Handle *cfg,
2405                               unsigned int total,
2406                               struct GNUNET_TIME_Relative timeout,
2407                               GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback,
2408                               void *hostkey_cls,
2409                               GNUNET_TESTING_NotifyDaemonRunning cb,
2410                               void *cb_cls,
2411                               GNUNET_TESTING_NotifyConnection
2412                               connect_callback, void *connect_callback_cls,
2413                               const char *hostnames)
2414 {
2415   struct GNUNET_TESTING_PeerGroup *pg;
2416   const char *rpos;
2417   char *pos;
2418   char *start;
2419   const char *hostname;
2420   char *baseservicehome;
2421   char *newservicehome;
2422   char *tmpdir;
2423   struct GNUNET_CONFIGURATION_Handle *pcfg;
2424   unsigned int off;
2425   unsigned int hostcnt;
2426   uint16_t minport;
2427
2428   if (0 == total)
2429     {
2430       GNUNET_break (0);
2431       return NULL;
2432     }
2433
2434   pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
2435   pg->sched = sched;
2436   pg->cfg = cfg;
2437   pg->cb = cb;
2438   pg->cb_cls = cb_cls;
2439   pg->notify_connection = connect_callback;
2440   pg->notify_connection_cls = connect_callback_cls;
2441   pg->total = total;
2442   pg->max_timeout = GNUNET_TIME_relative_to_absolute(timeout);
2443   pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
2444   if (NULL != hostnames)
2445     {
2446       off = 2;
2447       /* skip leading spaces */
2448       while ((0 != *hostnames) && (isspace (*hostnames)))
2449         hostnames++;
2450       rpos = hostnames;
2451       while ('\0' != *rpos)
2452         {
2453           if (isspace (*rpos))
2454             off++;
2455           rpos++;
2456         }
2457       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
2458       off = 0;
2459       start = GNUNET_strdup (hostnames);
2460       pos = start;
2461       while ('\0' != *pos)
2462         {
2463           if (isspace (*pos))
2464             {
2465               *pos = '\0';
2466               if (strlen (start) > 0)
2467                 {
2468                   pg->hosts[off].minport = LOW_PORT;
2469                   pg->hosts[off++].hostname = start;
2470                 }
2471               start = pos + 1;
2472             }
2473           pos++;
2474         }
2475       if (strlen (start) > 0)
2476         {
2477           pg->hosts[off].minport = LOW_PORT;
2478           pg->hosts[off++].hostname = start;
2479         }
2480       if (off == 0)
2481         {
2482           GNUNET_free (start);
2483           GNUNET_free (pg->hosts);
2484           pg->hosts = NULL;
2485         }
2486       hostcnt = off;
2487       minport = 0;              /* make gcc happy */
2488     }
2489   else
2490     {
2491       hostcnt = 0;
2492       minport = LOW_PORT;
2493     }
2494   for (off = 0; off < total; off++)
2495     {
2496       if (hostcnt > 0)
2497         {
2498           hostname = pg->hosts[off % hostcnt].hostname;
2499           pcfg = make_config (cfg, &pg->hosts[off % hostcnt].minport, hostname);
2500         }
2501       else
2502         {
2503           hostname = NULL;
2504           pcfg = make_config (cfg, &minport, hostname);
2505         }
2506
2507       if (NULL == pcfg)
2508         {
2509           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2510                       _
2511                       ("Could not create configuration for peer number %u on `%s'!\n"),
2512                       off, hostname == NULL ? "localhost" : hostname);
2513           continue;
2514         }
2515
2516       if (GNUNET_YES ==
2517           GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
2518                                                  &baseservicehome))
2519         {
2520           GNUNET_asprintf (&newservicehome,
2521                            "%s/%d/", baseservicehome, off);
2522           GNUNET_free (baseservicehome);
2523         }
2524       else
2525         {
2526           tmpdir = getenv ("TMPDIR");
2527           tmpdir = tmpdir ? tmpdir : "/tmp";
2528           GNUNET_asprintf (&newservicehome,
2529                            "%s/%s/%d/",
2530                            tmpdir,
2531                            "gnunet-testing-test-test", off);
2532         }
2533       GNUNET_CONFIGURATION_set_value_string (pcfg,
2534                                              "PATHS",
2535                                              "SERVICEHOME", newservicehome);
2536       GNUNET_free (newservicehome);
2537       pg->peers[off].cfg = pcfg;
2538       pg->peers[off].allowed_peers = GNUNET_CONTAINER_multihashmap_create(total);
2539       pg->peers[off].connect_peers = GNUNET_CONTAINER_multihashmap_create(total);
2540       pg->peers[off].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create(total);
2541       pg->peers[off].pg = pg;
2542       pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
2543                                                            pcfg,
2544                                                            timeout,
2545                                                            hostname,
2546                                                            hostkey_callback,
2547                                                            hostkey_cls,
2548                                                            cb, cb_cls);
2549       if (NULL == pg->peers[off].daemon)
2550         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2551                     _("Could not start peer number %u!\n"), off);
2552
2553     }
2554   return pg;
2555 }
2556
2557 /*
2558  * Get a daemon by number, so callers don't have to do nasty
2559  * offsetting operation.
2560  */
2561 struct GNUNET_TESTING_Daemon *
2562 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
2563 {
2564   if (position < pg->total)
2565     return pg->peers[position].daemon;
2566   else
2567     return NULL;
2568 }
2569
2570 /**
2571  * Prototype of a function that will be called when a
2572  * particular operation was completed the testing library.
2573  *
2574  * @param id id of the peer that was restarted
2575  * @param cfg handle to the configuration of the peer
2576  * @param d handle to the daemon that was restarted
2577  * @param emsg NULL on success
2578  */
2579 void restart_callback (void *cls,
2580                        const struct GNUNET_PeerIdentity *id,
2581                        const struct GNUNET_CONFIGURATION_Handle *cfg,
2582                        struct GNUNET_TESTING_Daemon *d,
2583                        const char *emsg)
2584 {
2585   struct RestartContext *restart_context = cls;
2586
2587   if (emsg == NULL)
2588     {
2589       restart_context->peers_restarted++;
2590     }
2591   else
2592     {
2593       restart_context->peers_restart_failed++;
2594     }
2595
2596   if (restart_context->peers_restarted == restart_context->peer_group->total)
2597     {
2598       restart_context->callback(restart_context->callback_cls, NULL);
2599       GNUNET_free(restart_context);
2600     }
2601   else if (restart_context->peers_restart_failed + restart_context->peers_restarted == restart_context->peer_group->total)
2602     {
2603       restart_context->callback(restart_context->callback_cls, "Failed to restart peers!");
2604       GNUNET_free(restart_context);
2605     }
2606
2607 }
2608
2609 void
2610 churn_stop_callback (void *cls, const char *emsg)
2611 {
2612
2613 }
2614
2615 void
2616 churn_start_callback (void *cls,
2617                       const struct GNUNET_PeerIdentity *id,
2618                       const struct GNUNET_CONFIGURATION_Handle *cfg,
2619                       struct GNUNET_TESTING_Daemon *d,
2620                       const char *emsg)
2621 {
2622
2623 }
2624
2625 /**
2626  * Context for handling churning a peer group
2627  */
2628 struct ChurnContext
2629 {
2630
2631 };
2632
2633 /**
2634  * Simulate churn by stopping some peers (and possibly
2635  * re-starting others if churn is called multiple times).  This
2636  * function can only be used to create leave-join churn (peers "never"
2637  * leave for good).  First "voff" random peers that are currently
2638  * online will be taken offline; then "von" random peers that are then
2639  * offline will be put back online.  No notifications will be
2640  * generated for any of these operations except for the callback upon
2641  * completion.  Note that the implementation is at liberty to keep
2642  * the ARM service itself (but none of the other services or daemons)
2643  * running even though the "peer" is being varied offline.
2644  *
2645  * @param pg handle for the peer group
2646  * @param voff number of peers that should go offline
2647  * @param von number of peers that should come back online;
2648  *            must be zero on first call (since "testbed_start"
2649  *            always starts all of the peers)
2650  * @param timeout how long to wait for operations to finish before
2651  *        giving up
2652  * @param cb function to call at the end
2653  * @param cb_cls closure for cb
2654  */
2655 void
2656 GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg,
2657                               unsigned int voff,
2658                               unsigned int von,
2659                               struct GNUNET_TIME_Relative timeout,
2660                               GNUNET_TESTING_NotifyCompletion cb,
2661                               void *cb_cls)
2662 {
2663   struct ChurnContext *churn_ctx;
2664   unsigned int running;
2665   unsigned int stopped;
2666   unsigned int i;
2667   unsigned int *running_arr;
2668   unsigned int *stopped_arr;
2669   unsigned int *running_permute;
2670   unsigned int *stopped_permute;
2671
2672   running = 0;
2673   stopped = 0;
2674
2675   for (i = 0; i < pg->total; i++)
2676   {
2677     if (pg->peers[i].daemon->running == GNUNET_YES)
2678     {
2679       running++;
2680     }
2681     else
2682     {
2683       stopped++;
2684     }
2685   }
2686
2687   if (voff > running)
2688   {
2689     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to stop more peers than are currently running!\n");
2690     cb(cb_cls, "Trying to stop more peers than are currently running!");
2691     return;
2692   }
2693
2694   if (von > stopped)
2695   {
2696     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to start more peers than are currently stopped!\n");
2697     cb(cb_cls, "Trying to start more peers than are currently stopped!");
2698     return;
2699   }
2700
2701   churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
2702   running_arr = GNUNET_malloc(running * sizeof(unsigned int));
2703   stopped_arr = GNUNET_malloc(stopped * sizeof(unsigned int));
2704   running_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, running);
2705   stopped_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, stopped);
2706
2707   running = 0;
2708   stopped = 0;
2709
2710   for (i = 0; i < pg->total; i++)
2711   {
2712     if (pg->peers[i].daemon->running == GNUNET_YES)
2713     {
2714       running_arr[running] = i;
2715       running++;
2716     }
2717     else
2718     {
2719       stopped_arr[stopped] = i;
2720       stopped++;
2721     }
2722   }
2723
2724   for (i = 0; i < voff; i++)
2725   {
2726     GNUNET_TESTING_daemon_stop(pg->peers[running_arr[running_permute[i]]].daemon, timeout, &churn_stop_callback, churn_ctx, GNUNET_NO, GNUNET_YES);
2727   }
2728
2729   for (i = 0; i < von; i++)
2730   {
2731     GNUNET_TESTING_daemon_start_stopped(pg->peers[stopped_arr[stopped_permute[i]]].daemon, timeout, &churn_start_callback, churn_ctx);
2732   }
2733
2734 }
2735
2736
2737 /**
2738  * Restart all peers in the given group.
2739  *
2740  * @param pg the handle to the peer group
2741  * @param timeout how long to wait on failure
2742  * @param callback function to call on completion (or failure)
2743  * @param callback_cls closure for the callback function
2744  */
2745 void
2746 GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyCompletion callback, void *callback_cls)
2747 {
2748   struct RestartContext *restart_context;
2749   unsigned int off;
2750
2751   if (pg->total > 0)
2752     {
2753       restart_context = GNUNET_malloc(sizeof(struct RestartContext));
2754       restart_context->peer_group = pg;
2755       restart_context->peers_restarted = 0;
2756       restart_context->callback = callback;
2757       restart_context->callback_cls = callback_cls;
2758
2759       for (off = 0; off < pg->total; off++)
2760         {
2761           GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, restart_context);
2762         }
2763     }
2764 }
2765
2766 /**
2767  * Shutdown all peers started in the given group.
2768  *
2769  * @param pg handle to the peer group
2770  * @param timeout how long to wait for shutdown
2771  *
2772  */
2773 void
2774 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, struct GNUNET_TIME_Relative timeout)
2775 {
2776   unsigned int off;
2777
2778   for (off = 0; off < pg->total; off++)
2779     {
2780       /* FIXME: should we wait for our
2781          continuations to be called here? This
2782          would require us to take a continuation
2783          as well... */
2784
2785       if (NULL != pg->peers[off].daemon)
2786         GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, timeout, NULL, NULL, GNUNET_YES, GNUNET_NO);
2787       if (NULL != pg->peers[off].cfg)
2788         GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
2789
2790       if (pg->peers[off].allowed_peers != NULL)
2791         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].allowed_peers);
2792       if (pg->peers[off].connect_peers != NULL)
2793         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].connect_peers);
2794       if (pg->peers[off].blacklisted_peers != NULL)
2795         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].blacklisted_peers);
2796
2797     }
2798   GNUNET_free (pg->peers);
2799   if (NULL != pg->hosts)
2800     {
2801       GNUNET_free (pg->hosts[0].hostname);
2802       GNUNET_free (pg->hosts);
2803     }
2804   GNUNET_free (pg);
2805 }
2806
2807
2808 /* end of testing_group.c */