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