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