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