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