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