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