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