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