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