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