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