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