some testing changes, including an api change that likely breaks things for others
[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 <<<<<<< .mine
1876   pg->notify_connection(pg->notify_connection_cls, first, second, distance, first_cfg, second_cfg, first_daemon, second_daemon, emsg);
1877 =======
1878   pg->notify_connection(pg->notify_connection_cls, 
1879                         first,
1880                         second, 
1881                         first_cfg, second_cfg, 
1882                         first_daemon, second_daemon, 
1883                         emsg);
1884 >>>>>>> .r11782
1885
1886 }
1887
1888
1889 static void schedule_connect(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1890 {
1891   struct ConnectContext *connect_context = cls;
1892
1893   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
1894     return;
1895
1896   if (outstanding_connects > MAX_OUTSTANDING_CONNECTIONS)
1897     {
1898 #if VERBOSE_TESTING > 2
1899           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1900                       _("Delaying connect, we have too many outstanding connections!\n"));
1901 #endif
1902       GNUNET_SCHEDULER_add_delayed(connect_context->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3), &schedule_connect, connect_context);
1903     }
1904   else
1905     {
1906 #if VERBOSE_TESTING > 2
1907           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1908                       _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
1909 #endif
1910       outstanding_connects++;
1911       GNUNET_TESTING_daemons_connect (connect_context->first,
1912                                       connect_context->second,
1913                                       CONNECT_TIMEOUT,
1914                                       CONNECT_ATTEMPTS,
1915                                       &internal_connect_notify,
1916                                       connect_context->pg);
1917       GNUNET_free(connect_context);
1918     }
1919 }
1920
1921
1922 /**
1923  * Iterator for actually scheduling connections to be created
1924  * between two peers.
1925  *
1926  * @param cls closure, a GNUNET_TESTING_Daemon
1927  * @param key the key the second Daemon was stored under
1928  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
1929  *
1930  * @return GNUNET_YES to continue iteration
1931  */
1932 static int
1933 connect_iterator (void *cls,
1934                   const GNUNET_HashCode * key,
1935                   void *value)
1936 {
1937   struct PeerData *first = cls;
1938   struct GNUNET_TESTING_Daemon *second = value;
1939   struct ConnectContext *connect_context;
1940
1941   connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
1942   connect_context->pg = first->pg;
1943   connect_context->first = first->daemon;
1944   connect_context->second = second;
1945   GNUNET_SCHEDULER_add_now(first->pg->sched, &schedule_connect, connect_context);
1946
1947   return GNUNET_YES;
1948 }
1949
1950
1951 /**
1952  * Iterator for copying all entries in the allowed hashmap to the
1953  * connect hashmap.
1954  *
1955  * @param cls closure, a GNUNET_TESTING_Daemon
1956  * @param key the key the second Daemon was stored under
1957  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
1958  *
1959  * @return GNUNET_YES to continue iteration
1960  */
1961 static int
1962 copy_topology_iterator (void *cls,
1963                   const GNUNET_HashCode * key,
1964                   void *value)
1965 {
1966   struct PeerData *first = cls;
1967
1968   GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(first->connect_peers, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
1969
1970   return GNUNET_YES;
1971 }
1972
1973 /**
1974  * Make the peers to connect the same as those that are allowed to be
1975  * connected.
1976  *
1977  * @param pg the peer group
1978  */
1979 static int
1980 copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg)
1981 {
1982   unsigned int pg_iter;
1983   int ret;
1984   int total;
1985
1986   total = 0;
1987   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1988     {
1989       ret = GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].allowed_peers, &copy_topology_iterator, &pg->peers[pg_iter]);
1990       if (GNUNET_SYSERR == ret)
1991         return GNUNET_SYSERR;
1992
1993       total = total + ret;
1994     }
1995
1996   return total;
1997 }
1998
1999
2000 /**
2001  * Connect the topology as specified by the PeerConnection's
2002  * of each peer in the peer group
2003  *
2004  * @param pg the peer group we are dealing with
2005  * @return the number of connections that will be attempted
2006  */
2007 static int
2008 connect_topology (struct GNUNET_TESTING_PeerGroup *pg)
2009 {
2010   unsigned int pg_iter;
2011   int ret;
2012   int total;
2013 #if OLD
2014   struct PeerConnection *connection_iter;
2015   struct ConnectContext *connect_context;
2016 #endif
2017
2018   total = 0;
2019   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2020     {
2021       ret = GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &connect_iterator, &pg->peers[pg_iter]);
2022       if (GNUNET_SYSERR == ret)
2023         return GNUNET_SYSERR;
2024
2025       total = total + ret;
2026
2027 #if OLD
2028       connection_iter = ;
2029       while (connection_iter != NULL)
2030         {
2031           connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
2032           connect_context->pg = pg;
2033           connect_context->first = ;
2034           connect_context->second = connection_iter->daemon;
2035           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_connect, connect_context);
2036           connection_iter = connection_iter->next;
2037         }
2038 #endif
2039     }
2040   return total;
2041 }
2042
2043
2044 /**
2045  * Takes a peer group and creates a topology based on the
2046  * one specified.  Creates a topology means generates friend
2047  * files for the peers so they can only connect to those allowed
2048  * by the topology.  This will only have an effect once peers
2049  * are started if the FRIENDS_ONLY option is set in the base
2050  * config.  Also takes an optional restrict topology which
2051  * disallows direct TCP connections UNLESS they are specified in
2052  * the restricted topology.
2053  *
2054  * @param pg the peer group struct representing the running peers
2055  * @param topology which topology to connect the peers in
2056  * @param restrict_topology allow only direct TCP connections in this topology
2057  *                          use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions
2058  * @param restrict_transports space delimited list of transports to blacklist
2059  *                            to create restricted topology
2060  *
2061  * @return the maximum number of connections were all allowed peers
2062  *         connected to each other
2063  */
2064 int
2065 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg,
2066                                 enum GNUNET_TESTING_Topology topology,
2067                                 enum GNUNET_TESTING_Topology restrict_topology,
2068                                 char *restrict_transports)
2069 {
2070   int ret;
2071   int num_connections;
2072   int unblacklisted_connections;
2073
2074   GNUNET_assert (pg->notify_connection != NULL);
2075   ret = GNUNET_OK;
2076
2077   switch (topology)
2078     {
2079     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2080 #if VERBOSE_TOPOLOGY
2081       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2082                   _("Creating clique topology\n"));
2083 #endif
2084       num_connections = create_clique (pg, &add_allowed_connections);
2085       break;
2086     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2087 #if VERBOSE_TOPOLOGY
2088       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2089                   _("Creating small world (ring) topology\n"));
2090 #endif
2091       num_connections = create_small_world_ring (pg, &add_allowed_connections);
2092       break;
2093     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2094 #if VERBOSE_TOPOLOGY
2095       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2096                   _("Creating small world (2d-torus) topology\n"));
2097 #endif
2098       num_connections = create_small_world (pg, &add_allowed_connections);
2099       break;
2100     case GNUNET_TESTING_TOPOLOGY_RING:
2101 #if VERBOSE_TOPOLOGY
2102       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2103                   _("Creating ring topology\n"));
2104 #endif
2105       num_connections = create_ring (pg, &add_allowed_connections);
2106       break;
2107     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2108 #if VERBOSE_TOPOLOGY
2109       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2110                   _("Creating 2d torus topology\n"));
2111 #endif
2112       num_connections = create_2d_torus (pg, &add_allowed_connections);
2113       break;
2114     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2115 #if VERBOSE_TOPOLOGY
2116       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2117                   _("Creating Erdos-Renyi topology\n"));
2118 #endif
2119       num_connections = create_erdos_renyi (pg, &add_allowed_connections);
2120       break;
2121     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2122 #if VERBOSE_TOPOLOGY
2123       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2124                   _("Creating InterNAT topology\n"));
2125 #endif
2126       num_connections = create_nated_internet (pg, &add_allowed_connections);
2127       break;
2128     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2129 #if VERBOSE_TESTING
2130       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2131                   _("Creating Scale Free topology\n"));
2132 #endif
2133       num_connections = create_scale_free (pg, &add_allowed_connections);
2134       break;
2135     case GNUNET_TESTING_TOPOLOGY_LINE:
2136 #if VERBOSE_TESTING
2137       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2138                   _("Creating straight line topology\n"));
2139 #endif
2140       num_connections = create_line (pg, &add_allowed_connections);
2141       break;
2142     case GNUNET_TESTING_TOPOLOGY_NONE:
2143       num_connections = 0;
2144       break;
2145     default:
2146       num_connections = 0;
2147       break;
2148     }
2149   if (num_connections < 1)
2150     return GNUNET_SYSERR;
2151
2152   if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
2153     {
2154       ret = create_and_copy_friend_files(pg);
2155     }
2156
2157   if (ret != GNUNET_OK)
2158     {
2159 #if VERBOSE_TESTING
2160       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2161                   _("Failed during friend file copying!\n"));
2162 #endif
2163       return GNUNET_SYSERR;
2164     }
2165   else
2166     {
2167 #if VERBOSE_TESTING
2168           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2169                       _("Friend files created/copied successfully!\n"));
2170 #endif
2171     }
2172
2173   /* Use the create clique method to initially set all connections as blacklisted. */
2174   create_clique (pg, &blacklist_connections);
2175   unblacklisted_connections = 0;
2176   /* Un-blacklist connections as per the topology specified */
2177   switch (restrict_topology)
2178     {
2179     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2180 #if VERBOSE_TESTING
2181       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2182                   _("Blacklisting all but clique topology\n"));
2183 #endif
2184       unblacklisted_connections = create_clique (pg, &unblacklist_connections);
2185       break;
2186     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2187 #if VERBOSE_TESTING
2188       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2189                   _("Blacklisting all but small world (ring) topology\n"));
2190 #endif
2191       unblacklisted_connections = create_small_world_ring (pg, &unblacklist_connections);
2192       break;
2193     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2194 #if VERBOSE_TESTING
2195       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2196                   _("Blacklisting all but small world (2d-torus) topology\n"));
2197 #endif
2198       unblacklisted_connections = create_small_world (pg, &unblacklist_connections);
2199       break;
2200     case GNUNET_TESTING_TOPOLOGY_RING:
2201 #if VERBOSE_TESTING
2202       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2203                   _("Blacklisting all but ring topology\n"));
2204 #endif
2205       unblacklisted_connections = create_ring (pg, &unblacklist_connections);
2206       break;
2207     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2208 #if VERBOSE_TESTING
2209       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2210                   _("Blacklisting all but 2d torus topology\n"));
2211 #endif
2212       unblacklisted_connections = create_2d_torus (pg, &unblacklist_connections);
2213       break;
2214     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2215 #if VERBOSE_TESTING
2216       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2217                   _("Blacklisting all but Erdos-Renyi topology\n"));
2218 #endif
2219       unblacklisted_connections = create_erdos_renyi (pg, &unblacklist_connections);
2220       break;
2221     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2222 #if VERBOSE_TESTING
2223       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2224                   _("Blacklisting all but InterNAT topology\n"));
2225 #endif
2226       unblacklisted_connections = create_nated_internet (pg, &unblacklist_connections);
2227       break;
2228     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2229 #if VERBOSE_TESTING
2230       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2231                   _("Blacklisting all but Scale Free topology\n"));
2232 #endif
2233       unblacklisted_connections = create_scale_free (pg, &unblacklist_connections);
2234       break;
2235     case GNUNET_TESTING_TOPOLOGY_LINE:
2236 #if VERBOSE_TESTING
2237       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2238                   _("Blacklisting all but straight line topology\n"));
2239 #endif
2240       unblacklisted_connections = create_line (pg, &unblacklist_connections);
2241       break;
2242     case GNUNET_TESTING_TOPOLOGY_NONE:
2243       /* Fall through */
2244     default:
2245       break;
2246     }
2247
2248   if ((unblacklisted_connections > 0) && (restrict_transports != NULL))
2249   {
2250     ret = create_and_copy_blacklist_files(pg, restrict_transports);
2251     if (ret != GNUNET_OK)
2252       {
2253 #if VERBOSE_TESTING
2254         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2255                     _("Failed during blacklist file copying!\n"));
2256 #endif
2257         return GNUNET_SYSERR;
2258       }
2259     else
2260       {
2261 #if VERBOSE_TESTING
2262         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2263                     _("Blacklist files created/copied successfully!\n"));
2264 #endif
2265       }
2266   }
2267   return num_connections;
2268 }
2269
2270 struct RandomContext
2271 {
2272   /**
2273    * The peergroup
2274    */
2275   struct GNUNET_TESTING_PeerGroup *pg;
2276
2277   /**
2278    * uid of the first peer
2279    */
2280   uint32_t first_uid;
2281
2282   /**
2283    * Peer data for first peer.
2284    */
2285   struct PeerData *first;
2286
2287   /**
2288    * Random percentage to use
2289    */
2290   double percentage;
2291 };
2292
2293 struct MinimumContext
2294 {
2295   /**
2296    * The peergroup
2297    */
2298   struct GNUNET_TESTING_PeerGroup *pg;
2299
2300   /**
2301    * uid of the first peer
2302    */
2303   uint32_t first_uid;
2304
2305   /**
2306    * Peer data for first peer.
2307    */
2308   struct PeerData *first;
2309
2310   /**
2311    * Number of conns per peer
2312    */
2313   unsigned int num_to_add;
2314
2315   /**
2316    * Permuted array of all possible connections.  Only add the Nth
2317    * peer if it's in the Nth position.
2318    */
2319   unsigned int *pg_array;
2320
2321   /**
2322    * What number is the current element we are iterating over?
2323    */
2324   unsigned int current;
2325 };
2326
2327 struct DFSContext
2328 {
2329   /**
2330    * The peergroup
2331    */
2332   struct GNUNET_TESTING_PeerGroup *pg;
2333
2334   /**
2335    * uid of the first peer
2336    */
2337   uint32_t first_uid;
2338
2339   /**
2340    * uid of the second peer
2341    */
2342   uint32_t second_uid;
2343
2344   /**
2345    * Peer data for first peer.
2346    */
2347   struct PeerData *first;
2348
2349   /**
2350    * Which peer has been chosen as the one to add?
2351    */
2352   unsigned int chosen;
2353
2354   /**
2355    * What number is the current element we are iterating over?
2356    */
2357   unsigned int current;
2358 };
2359
2360 /**
2361  * Iterator for choosing random peers to connect.
2362  *
2363  * @param cls closure, a RandomContext
2364  * @param key the key the second Daemon was stored under
2365  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2366  *
2367  * @return GNUNET_YES to continue iteration
2368  */
2369 static int
2370 random_connect_iterator (void *cls,
2371                   const GNUNET_HashCode * key,
2372                   void *value)
2373 {
2374   struct RandomContext *random_ctx = cls;
2375   double random_number;
2376   uint32_t second_pos;
2377   GNUNET_HashCode first_hash;
2378   random_number = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
2379                                                      UINT64_MAX)) / ( (double) UINT64_MAX);
2380   if (random_number < random_ctx->percentage)
2381   {
2382     GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(random_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2383   }
2384   /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */
2385   uid_from_hash(key, &second_pos);
2386   hash_from_uid(random_ctx->first_uid, &first_hash);
2387   GNUNET_assert(random_ctx->pg->total > second_pos);
2388   GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(random_ctx->pg->peers[second_pos].connect_peers, &first_hash, random_ctx->first->daemon));
2389
2390   return GNUNET_YES;
2391 }
2392
2393 /**
2394  * Iterator for adding at least X peers to a peers connection set.
2395  *
2396  * @param cls closure, MinimumContext
2397  * @param key the key the second Daemon was stored under
2398  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2399  *
2400  * @return GNUNET_YES to continue iteration
2401  */
2402 static int
2403 minimum_connect_iterator (void *cls,
2404                   const GNUNET_HashCode * key,
2405                   void *value)
2406 {
2407   struct MinimumContext *min_ctx = cls;
2408   uint32_t second_pos;
2409   GNUNET_HashCode first_hash;
2410   unsigned int i;
2411
2412   if (GNUNET_CONTAINER_multihashmap_size(min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add)
2413   {
2414     for (i = 0; i < min_ctx->num_to_add; i++)
2415     {
2416       if (min_ctx->pg_array[i] == min_ctx->current)
2417       {
2418         GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(min_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2419         uid_from_hash(key, &second_pos);
2420         hash_from_uid(min_ctx->first_uid, &first_hash);
2421         GNUNET_assert(min_ctx->pg->total > second_pos);
2422         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));
2423         /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */
2424         GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(min_ctx->pg->peers[second_pos].connect_peers, &first_hash, min_ctx->first->daemon));
2425       }
2426     }
2427     min_ctx->current++;
2428     return GNUNET_YES;
2429   }
2430   else
2431     return GNUNET_NO; /* We can stop iterating, we have enough peers! */
2432
2433 }
2434
2435
2436 /**
2437  * Iterator for adding peers to a connection set based on a depth first search.
2438  *
2439  * @param cls closure, MinimumContext
2440  * @param key the key the second daemon was stored under
2441  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2442  *
2443  * @return GNUNET_YES to continue iteration
2444  */
2445 static int
2446 dfs_connect_iterator (void *cls,
2447                   const GNUNET_HashCode * key,
2448                   void *value)
2449 {
2450   struct DFSContext *dfs_ctx = cls;
2451   GNUNET_HashCode first_hash;
2452
2453   if (dfs_ctx->current == dfs_ctx->chosen)
2454     {
2455       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(dfs_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2456       uid_from_hash(key, &dfs_ctx->second_uid);
2457       hash_from_uid(dfs_ctx->first_uid, &first_hash);
2458       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));
2459       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(dfs_ctx->pg->peers[dfs_ctx->second_uid].connect_peers, &first_hash, dfs_ctx->first->daemon));
2460       /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */
2461       return GNUNET_NO; /* We have found our peer, don't iterate more */
2462     }
2463
2464   dfs_ctx->current++;
2465   return GNUNET_YES;
2466 }
2467
2468
2469 /**
2470  * From the set of connections possible, choose percentage percent of connections
2471  * to actually connect.
2472  *
2473  * @param pg the peergroup we are dealing with
2474  * @param percentage what percent of total connections to make
2475  */
2476 void
2477 choose_random_connections(struct GNUNET_TESTING_PeerGroup *pg, double percentage)
2478 {
2479   struct RandomContext random_ctx;
2480   uint32_t pg_iter;
2481
2482   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2483     {
2484       random_ctx.first_uid = pg_iter;
2485       random_ctx.first = &pg->peers[pg_iter];
2486       random_ctx.percentage = percentage;
2487       random_ctx.pg = pg;
2488       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(pg->total);
2489       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &random_connect_iterator, &random_ctx);
2490       /* Now remove the old connections */
2491       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2492       /* And replace with the random set */
2493       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2494     }
2495 }
2496
2497 /**
2498  * From the set of connections possible, choose at least num connections per
2499  * peer.
2500  *
2501  * @param pg the peergroup we are dealing with
2502  * @param num how many connections at least should each peer have (if possible)?
2503  */
2504 static void
2505 choose_minimum(struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2506 {
2507   struct MinimumContext minimum_ctx;
2508   uint32_t pg_iter;
2509
2510   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2511    {
2512      pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2513    }
2514
2515   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2516     {
2517       minimum_ctx.first_uid = pg_iter;
2518       minimum_ctx.pg_array = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, 
2519                                                           GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2520       minimum_ctx.first = &pg->peers[pg_iter];
2521       minimum_ctx.pg = pg;
2522       minimum_ctx.num_to_add = num;
2523       minimum_ctx.current = 0;
2524       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers,
2525                                             &minimum_connect_iterator, 
2526                                             &minimum_ctx);
2527     }
2528
2529   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2530     {
2531       /* Remove the "old" connections */
2532       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2533       /* And replace with the working set */
2534       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2535     }
2536
2537 }
2538
2539
2540 static unsigned int
2541 count_workingset_connections(struct GNUNET_TESTING_PeerGroup *pg)
2542 {
2543   unsigned int count;
2544   unsigned int pg_iter;
2545
2546   count = 0;
2547
2548   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2549     {
2550       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2551     }
2552
2553   return count;
2554 }
2555
2556
2557 static unsigned int count_allowed_connections(struct GNUNET_TESTING_PeerGroup *pg)
2558 {
2559   unsigned int count;
2560   unsigned int pg_iter;
2561
2562   count = 0;
2563
2564   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2565     {
2566       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers);
2567     }
2568
2569   return count;
2570 }
2571
2572 /**
2573  * From the set of connections possible, choose at least num connections per
2574  * peer based on depth first traversal of peer connections.  If DFS leaves
2575  * peers unconnected, ensure those peers get connections.
2576  *
2577  * @param pg the peergroup we are dealing with
2578  * @param num how many connections at least should each peer have (if possible)?
2579  */
2580 void
2581 perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2582 {
2583   struct DFSContext dfs_ctx;
2584   uint32_t pg_iter;
2585   uint32_t dfs_count;
2586   uint32_t starting_peer;
2587   uint32_t least_connections;
2588   GNUNET_HashCode second_hash;
2589
2590   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2591     {
2592       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2593     }
2594
2595   starting_peer = 0;
2596   dfs_count = 0;
2597   while ((count_workingset_connections(pg) < num * pg->total) && (count_allowed_connections(pg) > 0))
2598     {
2599       if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */
2600         {
2601           least_connections = -1; /* Set to very high number */
2602           for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2603             {
2604               if (GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set) < least_connections)
2605                 {
2606                   starting_peer = pg_iter;
2607                   least_connections = GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2608                 }
2609             }
2610         }
2611
2612       if (GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers) == 0)  /* Ensure there is at least one peer left to connect! */
2613         {
2614           dfs_count = 0;
2615           continue;
2616         }
2617
2618       /* Choose a random peer from the chosen peers set of connections to add */
2619       dfs_ctx.chosen = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers));
2620       dfs_ctx.first_uid = starting_peer;
2621       dfs_ctx.first = &pg->peers[starting_peer];
2622       dfs_ctx.pg = pg;
2623       dfs_ctx.current = 0;
2624
2625       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[starting_peer].connect_peers, &dfs_connect_iterator, &dfs_ctx);
2626       /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */
2627       hash_from_uid(dfs_ctx.second_uid, &second_hash);
2628       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[starting_peer].connect_peers, &second_hash, pg->peers[dfs_ctx.second_uid].daemon));
2629       starting_peer = dfs_ctx.second_uid;
2630     }
2631
2632   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2633     {
2634       /* Remove the "old" connections */
2635       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2636       /* And replace with the working set */
2637       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2638     }
2639 }
2640
2641 /**
2642  * There are many ways to connect peers that are supported by this function.
2643  * To connect peers in the same topology that was created via the
2644  * GNUNET_TESTING_create_topology, the topology variable must be set to
2645  * GNUNET_TESTING_TOPOLOGY_NONE.  If the topology variable is specified,
2646  * a new instance of that topology will be generated and attempted to be
2647  * connected.  This could result in some connections being impossible,
2648  * because some topologies are non-deterministic.
2649  *
2650  * @param pg the peer group struct representing the running peers
2651  * @param topology which topology to connect the peers in
2652  * @param options options for connecting the topology
2653  * @param option_modifier modifier for options that take a parameter
2654  * @return the number of connections that will be attempted, GNUNET_SYSERR on error
2655  */
2656 int
2657 GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
2658                                  enum GNUNET_TESTING_Topology topology,
2659                                  enum GNUNET_TESTING_TopologyOption options,
2660                                  double option_modifier)
2661 {
2662   switch (topology)
2663       {
2664       case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2665 #if VERBOSE_TOPOLOGY
2666       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2667                   _("Creating clique CONNECT topology\n"));
2668 #endif
2669         create_clique (pg, &add_actual_connections);
2670         break;
2671       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2672 #if VERBOSE_TOPOLOGY
2673       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2674                   _("Creating small world (ring) CONNECT topology\n"));
2675 #endif
2676         create_small_world_ring (pg, &add_actual_connections);
2677         break;
2678       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2679 #if VERBOSE_TOPOLOGY
2680       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2681                   _("Creating small world (2d-torus) CONNECT topology\n"));
2682 #endif
2683         create_small_world (pg, &add_actual_connections);
2684         break;
2685       case GNUNET_TESTING_TOPOLOGY_RING:
2686 #if VERBOSE_TOPOLOGY
2687       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2688                   _("Creating ring CONNECT topology\n"));
2689 #endif
2690         create_ring (pg, &add_actual_connections);
2691         break;
2692       case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2693 #if VERBOSE_TOPOLOGY
2694       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2695                   _("Creating 2d torus CONNECT topology\n"));
2696 #endif
2697         create_2d_torus (pg, &add_actual_connections);
2698         break;
2699       case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2700 #if VERBOSE_TOPOLOGY
2701       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2702                   _("Creating Erdos-Renyi CONNECT topology\n"));
2703 #endif
2704         create_erdos_renyi (pg, &add_actual_connections);
2705         break;
2706       case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2707 #if VERBOSE_TOPOLOGY
2708       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2709                   _("Creating InterNAT CONNECT topology\n"));
2710 #endif
2711         create_nated_internet (pg, &add_actual_connections);
2712         break;
2713       case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2714 #if VERBOSE_TOPOLOGY
2715       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2716                   _("Creating Scale Free CONNECT topology\n"));
2717 #endif
2718         create_scale_free (pg, &add_actual_connections);
2719         break;
2720       case GNUNET_TESTING_TOPOLOGY_LINE:
2721 #if VERBOSE_TOPOLOGY
2722       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2723                   _("Creating straight line CONNECT topology\n"));
2724 #endif
2725         create_line (pg, &add_actual_connections);
2726         break;
2727       case GNUNET_TESTING_TOPOLOGY_NONE:
2728 #if VERBOSE_TOPOLOGY
2729         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2730                   _("Creating no CONNECT topology\n"));
2731 #endif
2732         copy_allowed_topology(pg);
2733         break;
2734       default:
2735         GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
2736                    _("Unknown topology specification, can't connect peers!\n"));
2737         return GNUNET_SYSERR;
2738       }
2739
2740   switch (options)
2741     {
2742     case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM:
2743 #if VERBOSE_TOPOLOGY
2744       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2745                   _("Connecting random subset (%'.2f percent) of possible peers\n"), 100 * option_modifier);
2746 #endif
2747       choose_random_connections(pg, option_modifier);
2748       break;
2749     case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM:
2750 #if VERBOSE_TOPOLOGY
2751       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2752                   _("Connecting a minimum of %u peers each (if possible)\n"), (unsigned int)option_modifier);
2753 #endif
2754       choose_minimum(pg, (unsigned int)option_modifier);
2755       break;
2756     case GNUNET_TESTING_TOPOLOGY_OPTION_DFS:
2757 #if VERBOSE_TOPOLOGY
2758       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2759                   _("Using DFS to connect a minimum of %u peers each (if possible)\n"), (unsigned int)option_modifier);
2760 #endif
2761       perform_dfs(pg, (int)option_modifier);
2762       break;
2763     case GNUNET_TESTING_TOPOLOGY_OPTION_NONE:
2764       break;
2765     case GNUNET_TESTING_TOPOLOGY_OPTION_ALL:
2766       break;
2767     default:
2768       break;
2769     }
2770
2771   return connect_topology(pg);
2772 }
2773
2774 /**
2775  * Function which continues a peer group starting up
2776  * after successfully generating hostkeys for each peer.
2777  *
2778  * @param pg the peer group to continue starting
2779  *
2780  */
2781 void
2782 GNUNET_TESTING_daemons_continue_startup(struct GNUNET_TESTING_PeerGroup *pg)
2783 {
2784   unsigned int i;
2785
2786   for (i = 0; i < pg->total; i++)
2787     {
2788       GNUNET_TESTING_daemon_continue_startup(pg->peers[i].daemon);
2789     }
2790 }
2791
2792 /**
2793  * Start count gnunetd processes with the same set of transports and
2794  * applications.  The port numbers (any option called "PORT") will be
2795  * adjusted to ensure that no two peers running on the same system
2796  * have the same port(s) in their respective configurations.
2797  *
2798  * @param sched scheduler to use
2799  * @param cfg configuration template to use
2800  * @param total number of daemons to start
2801  * @param timeout total time allowed for peers to start
2802  * @param hostkey_callback function to call on each peers hostkey generation
2803  *        if NULL, peers will be started by this call, if non-null,
2804  *        GNUNET_TESTING_daemons_continue_startup must be called after
2805  *        successful hostkey generation
2806  * @param hostkey_cls closure for hostkey callback
2807  * @param cb function to call on each daemon that was started
2808  * @param cb_cls closure for cb
2809  * @param connect_callback function to call each time two hosts are connected
2810  * @param connect_callback_cls closure for connect_callback
2811  * @param hostnames space-separated list of hostnames to use; can be NULL (to run
2812  *        everything on localhost).
2813  * @return NULL on error, otherwise handle to control peer group
2814  */
2815 struct GNUNET_TESTING_PeerGroup *
2816 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
2817                               const struct GNUNET_CONFIGURATION_Handle *cfg,
2818                               unsigned int total,
2819                               struct GNUNET_TIME_Relative timeout,
2820                               GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback,
2821                               void *hostkey_cls,
2822                               GNUNET_TESTING_NotifyDaemonRunning cb,
2823                               void *cb_cls,
2824                               GNUNET_TESTING_NotifyConnection
2825                               connect_callback, void *connect_callback_cls,
2826                               const char *hostnames)
2827 {
2828   struct GNUNET_TESTING_PeerGroup *pg;
2829   const char *rpos;
2830   char *pos;
2831   char *start;
2832   const char *hostname;
2833   char *baseservicehome;
2834   char *newservicehome;
2835   char *tmpdir;
2836   struct GNUNET_CONFIGURATION_Handle *pcfg;
2837   unsigned int off;
2838   unsigned int hostcnt;
2839   uint16_t minport;
2840   uint32_t upnum;
2841
2842   if (0 == total)
2843     {
2844       GNUNET_break (0);
2845       return NULL;
2846     }
2847   upnum = 0;
2848   pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
2849   pg->sched = sched;
2850   pg->cfg = cfg;
2851   pg->cb = cb;
2852   pg->cb_cls = cb_cls;
2853   pg->notify_connection = connect_callback;
2854   pg->notify_connection_cls = connect_callback_cls;
2855   pg->total = total;
2856   pg->max_timeout = GNUNET_TIME_relative_to_absolute(timeout);
2857   pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
2858   if (NULL != hostnames)
2859     {
2860       off = 2;
2861       /* skip leading spaces */
2862       while ((0 != *hostnames) && (isspace ( (unsigned char) *hostnames)))
2863         hostnames++;
2864       rpos = hostnames;
2865       while ('\0' != *rpos)
2866         {
2867           if (isspace ( (unsigned char) *rpos))
2868             off++;
2869           rpos++;
2870         }
2871       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
2872       off = 0;
2873       start = GNUNET_strdup (hostnames);
2874       pos = start;
2875       while ('\0' != *pos)
2876         {
2877           if (isspace ( (unsigned char) *pos))
2878             {
2879               *pos = '\0';
2880               if (strlen (start) > 0)
2881                 {
2882                   pg->hosts[off].minport = LOW_PORT;
2883                   pg->hosts[off++].hostname = start;
2884                 }
2885               start = pos + 1;
2886             }
2887           pos++;
2888         }
2889       if (strlen (start) > 0)
2890         {
2891           pg->hosts[off].minport = LOW_PORT;
2892           pg->hosts[off++].hostname = start;
2893         }
2894       if (off == 0)
2895         {
2896           GNUNET_free (start);
2897           GNUNET_free (pg->hosts);
2898           pg->hosts = NULL;
2899         }
2900       hostcnt = off;
2901       minport = 0;              /* make gcc happy */
2902     }
2903   else
2904     {
2905       hostcnt = 0;
2906       minport = LOW_PORT;
2907     }
2908   for (off = 0; off < total; off++)
2909     {
2910       if (hostcnt > 0)
2911         {
2912           hostname = pg->hosts[off % hostcnt].hostname;
2913           pcfg = make_config (cfg, 
2914                               &pg->hosts[off % hostcnt].minport,
2915                               &upnum,
2916                               hostname);
2917         }
2918       else
2919         {
2920           hostname = NULL;
2921           pcfg = make_config (cfg,
2922                               &minport,
2923                               &upnum,
2924                               hostname);
2925         }
2926
2927       if (NULL == pcfg)
2928         {
2929           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2930                       _
2931                       ("Could not create configuration for peer number %u on `%s'!\n"),
2932                       off, hostname == NULL ? "localhost" : hostname);
2933           continue;
2934         }
2935
2936       if (GNUNET_YES ==
2937           GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
2938                                                  &baseservicehome))
2939         {
2940           GNUNET_asprintf (&newservicehome,
2941                            "%s/%d/", baseservicehome, off);
2942           GNUNET_free (baseservicehome);
2943         }
2944       else
2945         {
2946           tmpdir = getenv ("TMPDIR");
2947           tmpdir = tmpdir ? tmpdir : "/tmp";
2948           GNUNET_asprintf (&newservicehome,
2949                            "%s/%s/%d/",
2950                            tmpdir,
2951                            "gnunet-testing-test-test", off);
2952         }
2953       GNUNET_CONFIGURATION_set_value_string (pcfg,
2954                                              "PATHS",
2955                                              "SERVICEHOME", newservicehome);
2956       GNUNET_free (newservicehome);
2957       pg->peers[off].cfg = pcfg;
2958       pg->peers[off].allowed_peers = GNUNET_CONTAINER_multihashmap_create(total);
2959       pg->peers[off].connect_peers = GNUNET_CONTAINER_multihashmap_create(total);
2960       pg->peers[off].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create(total);
2961       pg->peers[off].pg = pg;
2962       pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
2963                                                            pcfg,
2964                                                            timeout,
2965                                                            hostname,
2966                                                            hostkey_callback,
2967                                                            hostkey_cls,
2968                                                            cb, cb_cls);
2969       if (NULL == pg->peers[off].daemon)
2970         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2971                     _("Could not start peer number %u!\n"), off);
2972
2973     }
2974   return pg;
2975 }
2976
2977 /*
2978  * Get a daemon by number, so callers don't have to do nasty
2979  * offsetting operation.
2980  */
2981 struct GNUNET_TESTING_Daemon *
2982 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
2983 {
2984   if (position < pg->total)
2985     return pg->peers[position].daemon;
2986   else
2987     return NULL;
2988 }
2989
2990 /**
2991  * Prototype of a function that will be called when a
2992  * particular operation was completed the testing library.
2993  *
2994  * @param cls closure (a struct RestartContext)
2995  * @param id id of the peer that was restarted
2996  * @param cfg handle to the configuration of the peer
2997  * @param d handle to the daemon that was restarted
2998  * @param emsg NULL on success
2999  */
3000 void restart_callback (void *cls,
3001                        const struct GNUNET_PeerIdentity *id,
3002                        const struct GNUNET_CONFIGURATION_Handle *cfg,
3003                        struct GNUNET_TESTING_Daemon *d,
3004                        const char *emsg)
3005 {
3006   struct RestartContext *restart_context = cls;
3007
3008   if (emsg == NULL)
3009     {
3010       restart_context->peers_restarted++;
3011     }
3012   else
3013     {
3014       restart_context->peers_restart_failed++;
3015     }
3016
3017   if (restart_context->peers_restarted == restart_context->peer_group->total)
3018     {
3019       restart_context->callback(restart_context->callback_cls, NULL);
3020       GNUNET_free(restart_context);
3021     }
3022   else if (restart_context->peers_restart_failed + restart_context->peers_restarted == restart_context->peer_group->total)
3023     {
3024       restart_context->callback(restart_context->callback_cls, "Failed to restart peers!");
3025       GNUNET_free(restart_context);
3026     }
3027
3028 }
3029
3030 /**
3031  * Callback for informing us about a successful
3032  * or unsuccessful churn stop call.
3033  *
3034  * @param cls a ChurnContext
3035  * @param emsg NULL on success, non-NULL on failure
3036  *
3037  */
3038 void
3039 churn_stop_callback (void *cls, const char *emsg)
3040 {
3041   struct ChurnContext *churn_ctx = cls;
3042   unsigned int total_left;
3043   char *error_message;
3044
3045   error_message = NULL;
3046   if (emsg != NULL)
3047     {
3048       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
3049                  "Churn stop callback failed with error `%s'\n", emsg);
3050       churn_ctx->num_failed_stop++;
3051     }
3052   else
3053     {
3054       churn_ctx->num_to_stop--;
3055     }
3056
3057 #if DEBUG_CHURN
3058   GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
3059              "Stopped peer, %d left.\n", 
3060              churn_ctx->num_to_stop);
3061 #endif
3062   total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
3063
3064   if (total_left == 0)
3065   {
3066     if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
3067       {
3068         GNUNET_asprintf(&error_message, 
3069                         "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", 
3070                         churn_ctx->num_failed_start, 
3071                         churn_ctx->num_failed_stop);
3072       }
3073     churn_ctx->cb(churn_ctx->cb_cls, error_message);
3074     GNUNET_free_non_null(error_message);
3075     GNUNET_free(churn_ctx);
3076   }
3077 }
3078
3079 /**
3080  * Callback for informing us about a successful
3081  * or unsuccessful churn start call.
3082  *
3083  * @param cls a ChurnContext
3084  * @param id the peer identity of the started peer
3085  * @param cfg the handle to the configuration of the peer
3086  * @param d handle to the daemon for the peer
3087  * @param emsg NULL on success, non-NULL on failure
3088  *
3089  */
3090 void
3091 churn_start_callback (void *cls,
3092                       const struct GNUNET_PeerIdentity *id,
3093                       const struct GNUNET_CONFIGURATION_Handle *cfg,
3094                       struct GNUNET_TESTING_Daemon *d,
3095                       const char *emsg)
3096 {
3097   struct ChurnContext *churn_ctx = cls;
3098   unsigned int total_left;
3099   char *error_message;
3100
3101   error_message = NULL;
3102   if (emsg != NULL)
3103     {
3104       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 
3105                   "Churn stop callback failed with error `%s'\n",
3106                   emsg);
3107       churn_ctx->num_failed_start++;
3108     }
3109   else
3110     {
3111       churn_ctx->num_to_start--;
3112     }
3113   
3114 #if DEBUG_CHURN
3115   GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
3116              "Started peer, %d left.\n", 
3117              churn_ctx->num_to_start);
3118 #endif
3119
3120   total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
3121
3122   if (total_left == 0)
3123   {
3124     if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
3125       GNUNET_asprintf(&error_message, 
3126                       "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", 
3127                       churn_ctx->num_failed_start,
3128                       churn_ctx->num_failed_stop);
3129     churn_ctx->cb(churn_ctx->cb_cls, error_message);
3130     GNUNET_free_non_null(error_message);
3131     GNUNET_free(churn_ctx);
3132   }
3133 }
3134
3135
3136 /**
3137  * Simulate churn by stopping some peers (and possibly
3138  * re-starting others if churn is called multiple times).  This
3139  * function can only be used to create leave-join churn (peers "never"
3140  * leave for good).  First "voff" random peers that are currently
3141  * online will be taken offline; then "von" random peers that are then
3142  * offline will be put back online.  No notifications will be
3143  * generated for any of these operations except for the callback upon
3144  * completion.
3145  *
3146  * @param pg handle for the peer group
3147  * @param voff number of peers that should go offline
3148  * @param von number of peers that should come back online;
3149  *            must be zero on first call (since "testbed_start"
3150  *            always starts all of the peers)
3151  * @param timeout how long to wait for operations to finish before
3152  *        giving up
3153  * @param cb function to call at the end
3154  * @param cb_cls closure for cb
3155  */
3156 void
3157 GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg,
3158                               unsigned int voff,
3159                               unsigned int von,
3160                               struct GNUNET_TIME_Relative timeout,
3161                               GNUNET_TESTING_NotifyCompletion cb,
3162                               void *cb_cls)
3163 {
3164   struct ChurnContext *churn_ctx;
3165   unsigned int running;
3166   unsigned int stopped;
3167   unsigned int i;
3168   unsigned int *running_arr;
3169   unsigned int *stopped_arr;
3170   unsigned int *running_permute;
3171   unsigned int *stopped_permute;
3172
3173   running = 0;
3174   stopped = 0;
3175
3176   if ((von == 0) && (voff == 0)) /* No peers at all? */
3177     {
3178       cb(cb_cls, NULL);
3179       return;
3180     }
3181
3182   for (i = 0; i < pg->total; i++)
3183   {
3184     if (pg->peers[i].daemon->running == GNUNET_YES)
3185     {
3186       GNUNET_assert(running != -1);
3187       running++;
3188     }
3189     else
3190     {
3191       GNUNET_assert(stopped != -1);
3192       stopped++;
3193     }
3194   }
3195
3196   if (voff > running)
3197   {
3198     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to stop more peers than are currently running!\n");
3199     cb(cb_cls, "Trying to stop more peers than are currently running!");
3200     return;
3201   }
3202
3203   if (von > stopped)
3204   {
3205     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to start more peers than are currently stopped!\n");
3206     cb(cb_cls, "Trying to start more peers than are currently stopped!");
3207     return;
3208   }
3209
3210   churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
3211   running_arr = GNUNET_malloc(running * sizeof(unsigned int));
3212   stopped_arr = GNUNET_malloc(stopped * sizeof(unsigned int));
3213
3214   running_permute = NULL;
3215   stopped_permute = NULL;
3216
3217   if (running > 0)
3218     running_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, running);
3219   if (stopped > 0)
3220     stopped_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, stopped);
3221
3222   running = 0;
3223   stopped = 0;
3224
3225   churn_ctx->num_to_start = von;
3226   churn_ctx->num_to_stop = voff;
3227   churn_ctx->cb = cb;
3228   churn_ctx->cb_cls = cb_cls;  
3229
3230   for (i = 0; i < pg->total; i++)
3231   {
3232     if (pg->peers[i].daemon->running == GNUNET_YES)
3233     {
3234       running_arr[running] = i;
3235       running++;
3236     }
3237     else
3238     {
3239       stopped_arr[stopped] = i;
3240       stopped++;
3241     }
3242   }
3243
3244   for (i = 0; i < voff; i++)
3245   {
3246 #if DEBUG_CHURN
3247     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Stopping peer %d!\n", running_permute[i]);
3248 #endif
3249     GNUNET_TESTING_daemon_stop (pg->peers[running_arr[running_permute[i]]].daemon,
3250                                 timeout, 
3251                                 &churn_stop_callback, churn_ctx, 
3252                                 GNUNET_NO, GNUNET_YES);
3253   }
3254
3255   for (i = 0; i < von; i++)
3256     {
3257 #if DEBUG_CHURN
3258       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Starting up peer %d!\n", stopped_permute[i]);
3259 #endif
3260       GNUNET_TESTING_daemon_start_stopped(pg->peers[stopped_arr[stopped_permute[i]]].daemon, 
3261                                           timeout, &churn_start_callback, churn_ctx);
3262   }
3263
3264   GNUNET_free(running_arr);
3265   GNUNET_free(stopped_arr);
3266   GNUNET_free_non_null(running_permute);
3267   GNUNET_free_non_null(stopped_permute);
3268 }
3269
3270
3271 /**
3272  * Restart all peers in the given group.
3273  *
3274  * @param pg the handle to the peer group
3275  * @param callback function to call on completion (or failure)
3276  * @param callback_cls closure for the callback function
3277  */
3278 void
3279 GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyCompletion callback, void *callback_cls)
3280 {
3281   struct RestartContext *restart_context;
3282   unsigned int off;
3283
3284   if (pg->total > 0)
3285     {
3286       restart_context = GNUNET_malloc(sizeof(struct RestartContext));
3287       restart_context->peer_group = pg;
3288       restart_context->peers_restarted = 0;
3289       restart_context->callback = callback;
3290       restart_context->callback_cls = callback_cls;
3291
3292       for (off = 0; off < pg->total; off++)
3293         {
3294           GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, restart_context);
3295         }
3296     }
3297 }
3298
3299 /**
3300  * Start or stop an individual peer from the given group.
3301  *
3302  * @param pg handle to the peer group
3303  * @param offset which peer to start or stop
3304  * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it
3305  * @param timeout how long to wait for shutdown
3306  * @param cb function to call at the end
3307  * @param cb_cls closure for cb
3308  */
3309 void
3310 GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, 
3311                              unsigned int offset,
3312                              int desired_status,
3313                              struct GNUNET_TIME_Relative timeout,
3314                              GNUNET_TESTING_NotifyCompletion cb,
3315                              void *cb_cls)
3316 {
3317   struct ChurnContext *churn_ctx;
3318
3319   if (GNUNET_NO == desired_status)
3320     {
3321       if (NULL != pg->peers[offset].daemon)
3322         {
3323           churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
3324           churn_ctx->num_to_start = 0;
3325           churn_ctx->num_to_stop = 1;
3326           churn_ctx->cb = cb;
3327           churn_ctx->cb_cls = cb_cls;  
3328           GNUNET_TESTING_daemon_stop(pg->peers[offset].daemon, 
3329                                      timeout, &churn_stop_callback, churn_ctx, 
3330                                      GNUNET_NO, GNUNET_YES);     
3331         }
3332     }
3333   else if (GNUNET_YES == desired_status)
3334     {
3335       if (NULL == pg->peers[offset].daemon)
3336         {
3337           churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
3338           churn_ctx->num_to_start = 1;
3339           churn_ctx->num_to_stop = 0;
3340           churn_ctx->cb = cb;
3341           churn_ctx->cb_cls = cb_cls;  
3342           GNUNET_TESTING_daemon_start_stopped(pg->peers[offset].daemon, 
3343                                               timeout, &churn_start_callback, churn_ctx);
3344         }
3345     }
3346   else
3347     GNUNET_break (0);
3348 }
3349
3350
3351 /**
3352  * Shutdown all peers started in the given group.
3353  *
3354  * @param pg handle to the peer group
3355  * @param timeout how long to wait for shutdown
3356  */
3357 void
3358 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, 
3359                              struct GNUNET_TIME_Relative timeout)
3360 {
3361   unsigned int off;
3362
3363   for (off = 0; off < pg->total; off++)
3364     {
3365       /* FIXME: should we wait for our continuations to be called
3366          here? This would require us to take a continuation as
3367          well... */
3368
3369       if (NULL != pg->peers[off].daemon)
3370         GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, timeout, NULL, NULL, GNUNET_YES, GNUNET_NO);
3371       if (NULL != pg->peers[off].cfg)
3372         GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
3373       if (pg->peers[off].allowed_peers != NULL)
3374         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].allowed_peers);
3375       if (pg->peers[off].connect_peers != NULL)
3376         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].connect_peers);
3377       if (pg->peers[off].blacklisted_peers != NULL)
3378         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].blacklisted_peers);
3379     }
3380   GNUNET_free (pg->peers);
3381   if (NULL != pg->hosts)
3382     {
3383       GNUNET_free (pg->hosts[0].hostname);
3384       GNUNET_free (pg->hosts);
3385     }
3386   GNUNET_free (pg);
3387 }
3388
3389
3390 /* end of testing_group.c */