change connect topology in testing_group.c to call callback on all peers connected...
[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   GNUNET_assert (pg->notify_connection != NULL);
2443
2444   switch (topology)
2445     {
2446     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2447 #if VERBOSE_TESTING
2448       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2449                   _("Creating clique topology\n"));
2450 #endif
2451       num_connections = create_clique (pg, &add_allowed_connections);
2452       break;
2453     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2454 #if VERBOSE_TESTING
2455       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2456                   _("Creating small world (ring) topology\n"));
2457 #endif
2458       num_connections = create_small_world_ring (pg, &add_allowed_connections);
2459       break;
2460     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2461 #if VERBOSE_TESTING
2462       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2463                   _("Creating small world (2d-torus) topology\n"));
2464 #endif
2465       num_connections = create_small_world (pg, &add_allowed_connections);
2466       break;
2467     case GNUNET_TESTING_TOPOLOGY_RING:
2468 #if VERBOSE_TESTING
2469       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2470                   _("Creating ring topology\n"));
2471 #endif
2472       num_connections = create_ring (pg, &add_allowed_connections);
2473       break;
2474     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2475 #if VERBOSE_TESTING
2476       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2477                   _("Creating 2d torus topology\n"));
2478 #endif
2479       num_connections = create_2d_torus (pg, &add_allowed_connections);
2480       break;
2481     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2482 #if VERBOSE_TESTING
2483       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2484                   _("Creating Erdos-Renyi topology\n"));
2485 #endif
2486       num_connections = create_erdos_renyi (pg, &add_allowed_connections);
2487       break;
2488     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2489 #if VERBOSE_TESTING
2490       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2491                   _("Creating InterNAT topology\n"));
2492 #endif
2493       num_connections = create_nated_internet (pg, &add_allowed_connections);
2494       break;
2495     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2496 #if VERBOSE_TESTING
2497       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2498                   _("Creating Scale Free topology\n"));
2499 #endif
2500       num_connections = create_scale_free (pg, &add_allowed_connections);
2501       break;
2502     case GNUNET_TESTING_TOPOLOGY_LINE:
2503 #if VERBOSE_TESTING
2504       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2505                   _("Creating straight line topology\n"));
2506 #endif
2507       num_connections = create_line (pg, &add_allowed_connections);
2508       break;
2509     case GNUNET_TESTING_TOPOLOGY_NONE:
2510 #if VERBOSE_TESTING
2511       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2512                   _("Creating no allowed topology (all peers can connect at core level)\n"));
2513 #endif
2514       num_connections = 0;
2515       break;
2516     default:
2517       num_connections = 0;
2518       break;
2519     }
2520
2521   if (num_connections < 0)
2522     return GNUNET_SYSERR;
2523
2524   if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
2525     {
2526       ret = create_and_copy_friend_files(pg);
2527       if (ret != GNUNET_OK)
2528         {
2529 #if VERBOSE_TESTING
2530           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2531                       _("Failed during friend file copying!\n"));
2532 #endif
2533           return GNUNET_SYSERR;
2534         }
2535       else
2536         {
2537 #if VERBOSE_TESTING
2538               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2539                           _("Friend files created/copied successfully!\n"));
2540 #endif
2541         }
2542     }
2543
2544   /* Use the create clique method to initially set all connections as blacklisted. */
2545   if (restrict_topology != GNUNET_TESTING_TOPOLOGY_NONE)
2546     create_clique (pg, &blacklist_connections);
2547
2548   unblacklisted_connections = 0;
2549   /* Un-blacklist connections as per the topology specified */
2550   switch (restrict_topology)
2551     {
2552     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2553 #if VERBOSE_TESTING
2554       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2555                   _("Blacklisting all but clique topology\n"));
2556 #endif
2557       unblacklisted_connections = create_clique (pg, &unblacklist_connections);
2558       break;
2559     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2560 #if VERBOSE_TESTING
2561       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2562                   _("Blacklisting all but small world (ring) topology\n"));
2563 #endif
2564       unblacklisted_connections = create_small_world_ring (pg, &unblacklist_connections);
2565       break;
2566     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2567 #if VERBOSE_TESTING
2568       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2569                   _("Blacklisting all but small world (2d-torus) topology\n"));
2570 #endif
2571       unblacklisted_connections = create_small_world (pg, &unblacklist_connections);
2572       break;
2573     case GNUNET_TESTING_TOPOLOGY_RING:
2574 #if VERBOSE_TESTING
2575       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2576                   _("Blacklisting all but ring topology\n"));
2577 #endif
2578       unblacklisted_connections = create_ring (pg, &unblacklist_connections);
2579       break;
2580     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2581 #if VERBOSE_TESTING
2582       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2583                   _("Blacklisting all but 2d torus topology\n"));
2584 #endif
2585       unblacklisted_connections = create_2d_torus (pg, &unblacklist_connections);
2586       break;
2587     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2588 #if VERBOSE_TESTING
2589       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2590                   _("Blacklisting all but Erdos-Renyi topology\n"));
2591 #endif
2592       unblacklisted_connections = create_erdos_renyi (pg, &unblacklist_connections);
2593       break;
2594     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2595 #if VERBOSE_TESTING
2596       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2597                   _("Blacklisting all but InterNAT topology\n"));
2598 #endif
2599       unblacklisted_connections = create_nated_internet (pg, &unblacklist_connections);
2600       break;
2601     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2602 #if VERBOSE_TESTING
2603       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2604                   _("Blacklisting all but Scale Free topology\n"));
2605 #endif
2606       unblacklisted_connections = create_scale_free (pg, &unblacklist_connections);
2607       break;
2608     case GNUNET_TESTING_TOPOLOGY_LINE:
2609 #if VERBOSE_TESTING
2610       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2611                   _("Blacklisting all but straight line topology\n"));
2612 #endif
2613       unblacklisted_connections = create_line (pg, &unblacklist_connections);
2614       break;
2615     case GNUNET_TESTING_TOPOLOGY_NONE:
2616 #if VERBOSE_TESTING
2617       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2618                   _("Creating no blacklist topology (all peers can connect at transport level)\n"));
2619 #endif
2620     default:
2621       break;
2622     }
2623
2624   if ((unblacklisted_connections > 0) && (restrict_transports != NULL))
2625   {
2626     ret = create_and_copy_blacklist_files(pg, restrict_transports);
2627     if (ret != GNUNET_OK)
2628       {
2629 #if VERBOSE_TESTING
2630         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2631                     _("Failed during blacklist file copying!\n"));
2632 #endif
2633         return 0;
2634       }
2635     else
2636       {
2637 #if VERBOSE_TESTING
2638         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2639                     _("Blacklist files created/copied successfully!\n"));
2640 #endif
2641       }
2642   }
2643   return num_connections;
2644 }
2645
2646 struct RandomContext
2647 {
2648   /**
2649    * The peergroup
2650    */
2651   struct GNUNET_TESTING_PeerGroup *pg;
2652
2653   /**
2654    * uid of the first peer
2655    */
2656   uint32_t first_uid;
2657
2658   /**
2659    * Peer data for first peer.
2660    */
2661   struct PeerData *first;
2662
2663   /**
2664    * Random percentage to use
2665    */
2666   double percentage;
2667 };
2668
2669 struct MinimumContext
2670 {
2671   /**
2672    * The peergroup
2673    */
2674   struct GNUNET_TESTING_PeerGroup *pg;
2675
2676   /**
2677    * uid of the first peer
2678    */
2679   uint32_t first_uid;
2680
2681   /**
2682    * Peer data for first peer.
2683    */
2684   struct PeerData *first;
2685
2686   /**
2687    * Number of conns per peer
2688    */
2689   unsigned int num_to_add;
2690
2691   /**
2692    * Permuted array of all possible connections.  Only add the Nth
2693    * peer if it's in the Nth position.
2694    */
2695   unsigned int *pg_array;
2696
2697   /**
2698    * What number is the current element we are iterating over?
2699    */
2700   unsigned int current;
2701 };
2702
2703 struct DFSContext
2704 {
2705   /**
2706    * The peergroup
2707    */
2708   struct GNUNET_TESTING_PeerGroup *pg;
2709
2710   /**
2711    * uid of the first peer
2712    */
2713   uint32_t first_uid;
2714
2715   /**
2716    * uid of the second peer
2717    */
2718   uint32_t second_uid;
2719
2720   /**
2721    * Peer data for first peer.
2722    */
2723   struct PeerData *first;
2724
2725   /**
2726    * Which peer has been chosen as the one to add?
2727    */
2728   unsigned int chosen;
2729
2730   /**
2731    * What number is the current element we are iterating over?
2732    */
2733   unsigned int current;
2734 };
2735
2736 /**
2737  * Iterator for choosing random peers to connect.
2738  *
2739  * @param cls closure, a RandomContext
2740  * @param key the key the second Daemon was stored under
2741  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2742  *
2743  * @return GNUNET_YES to continue iteration
2744  */
2745 static int
2746 random_connect_iterator (void *cls,
2747                          const GNUNET_HashCode * key,
2748                          void *value)
2749 {
2750   struct RandomContext *random_ctx = cls;
2751   double random_number;
2752   uint32_t second_pos;
2753   GNUNET_HashCode first_hash;
2754   random_number = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
2755                                                      UINT64_MAX)) / ( (double) UINT64_MAX);
2756   if (random_number < random_ctx->percentage)
2757   {
2758     GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(random_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2759   }
2760   /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */
2761   uid_from_hash(key, &second_pos);
2762   hash_from_uid(random_ctx->first_uid, &first_hash);
2763   GNUNET_assert(random_ctx->pg->total > second_pos);
2764   GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(random_ctx->pg->peers[second_pos].connect_peers, &first_hash, random_ctx->first->daemon));
2765
2766   return GNUNET_YES;
2767 }
2768
2769 /**
2770  * Iterator for adding at least X peers to a peers connection set.
2771  *
2772  * @param cls closure, MinimumContext
2773  * @param key the key the second Daemon was stored under
2774  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2775  *
2776  * @return GNUNET_YES to continue iteration
2777  */
2778 static int
2779 minimum_connect_iterator (void *cls,
2780                   const GNUNET_HashCode * key,
2781                   void *value)
2782 {
2783   struct MinimumContext *min_ctx = cls;
2784   uint32_t second_pos;
2785   GNUNET_HashCode first_hash;
2786   unsigned int i;
2787
2788   if (GNUNET_CONTAINER_multihashmap_size(min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add)
2789   {
2790     for (i = 0; i < min_ctx->num_to_add; i++)
2791     {
2792       if (min_ctx->pg_array[i] == min_ctx->current)
2793       {
2794         GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(min_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2795         uid_from_hash(key, &second_pos);
2796         hash_from_uid(min_ctx->first_uid, &first_hash);
2797         GNUNET_assert(min_ctx->pg->total > second_pos);
2798         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));
2799         /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */
2800         GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(min_ctx->pg->peers[second_pos].connect_peers, &first_hash, min_ctx->first->daemon));
2801       }
2802     }
2803     min_ctx->current++;
2804     return GNUNET_YES;
2805   }
2806   else
2807     return GNUNET_NO; /* We can stop iterating, we have enough peers! */
2808
2809 }
2810
2811
2812 /**
2813  * Iterator for adding peers to a connection set based on a depth first search.
2814  *
2815  * @param cls closure, MinimumContext
2816  * @param key the key the second daemon was stored under
2817  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2818  *
2819  * @return GNUNET_YES to continue iteration
2820  */
2821 static int
2822 dfs_connect_iterator (void *cls,
2823                   const GNUNET_HashCode * key,
2824                   void *value)
2825 {
2826   struct DFSContext *dfs_ctx = cls;
2827   GNUNET_HashCode first_hash;
2828
2829   if (dfs_ctx->current == dfs_ctx->chosen)
2830     {
2831       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(dfs_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2832       uid_from_hash(key, &dfs_ctx->second_uid);
2833       hash_from_uid(dfs_ctx->first_uid, &first_hash);
2834       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));
2835       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(dfs_ctx->pg->peers[dfs_ctx->second_uid].connect_peers, &first_hash, dfs_ctx->first->daemon));
2836       /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */
2837       return GNUNET_NO; /* We have found our peer, don't iterate more */
2838     }
2839
2840   dfs_ctx->current++;
2841   return GNUNET_YES;
2842 }
2843
2844
2845 /**
2846  * From the set of connections possible, choose percentage percent of connections
2847  * to actually connect.
2848  *
2849  * @param pg the peergroup we are dealing with
2850  * @param percentage what percent of total connections to make
2851  */
2852 void
2853 choose_random_connections(struct GNUNET_TESTING_PeerGroup *pg, double percentage)
2854 {
2855   struct RandomContext random_ctx;
2856   uint32_t pg_iter;
2857
2858   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2859     {
2860       random_ctx.first_uid = pg_iter;
2861       random_ctx.first = &pg->peers[pg_iter];
2862       random_ctx.percentage = percentage;
2863       random_ctx.pg = pg;
2864       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(pg->total);
2865       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &random_connect_iterator, &random_ctx);
2866       /* Now remove the old connections */
2867       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2868       /* And replace with the random set */
2869       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2870     }
2871 }
2872
2873 /**
2874  * From the set of connections possible, choose at least num connections per
2875  * peer.
2876  *
2877  * @param pg the peergroup we are dealing with
2878  * @param num how many connections at least should each peer have (if possible)?
2879  */
2880 static void
2881 choose_minimum(struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2882 {
2883   struct MinimumContext minimum_ctx;
2884   uint32_t pg_iter;
2885
2886   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2887    {
2888      pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2889    }
2890
2891   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2892     {
2893       minimum_ctx.first_uid = pg_iter;
2894       minimum_ctx.pg_array = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, 
2895                                                           GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2896       minimum_ctx.first = &pg->peers[pg_iter];
2897       minimum_ctx.pg = pg;
2898       minimum_ctx.num_to_add = num;
2899       minimum_ctx.current = 0;
2900       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers,
2901                                             &minimum_connect_iterator, 
2902                                             &minimum_ctx);
2903     }
2904
2905   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2906     {
2907       /* Remove the "old" connections */
2908       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2909       /* And replace with the working set */
2910       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2911     }
2912
2913 }
2914
2915
2916 static unsigned int
2917 count_workingset_connections(struct GNUNET_TESTING_PeerGroup *pg)
2918 {
2919   unsigned int count;
2920   unsigned int pg_iter;
2921
2922   count = 0;
2923
2924   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2925     {
2926       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2927     }
2928
2929   return count;
2930 }
2931
2932
2933 static unsigned int count_allowed_connections(struct GNUNET_TESTING_PeerGroup *pg)
2934 {
2935   unsigned int count;
2936   unsigned int pg_iter;
2937
2938   count = 0;
2939
2940   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2941     {
2942       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers);
2943     }
2944
2945   return count;
2946 }
2947
2948
2949 struct FindClosestContext
2950 {
2951   /**
2952    * The currently known closest peer.
2953    */
2954   struct GNUNET_TESTING_Daemon *closest;
2955
2956   /**
2957    * The info for the peer we are adding connections for.
2958    */
2959   struct PeerData *curr_peer;
2960
2961   /**
2962    * The distance (bits) between the current
2963    * peer and the currently known closest.
2964    */
2965   unsigned int closest_dist;
2966
2967   /**
2968    * The offset of the closest known peer in
2969    * the peer group.
2970    */
2971   unsigned int closest_num;
2972 };
2973
2974 /**
2975  * Iterator over hash map entries of the allowed
2976  * peer connections.  Find the closest, not already
2977  * connected peer and return it.
2978  *
2979  * @param cls closure (struct FindClosestContext)
2980  * @param key current key code (hash of offset in pg)
2981  * @param value value in the hash map - a GNUNET_TESTING_Daemon
2982  * @return GNUNET_YES if we should continue to
2983  *         iterate,
2984  *         GNUNET_NO if not.
2985  */
2986 static
2987 int find_closest_peers (void *cls, const GNUNET_HashCode * key, void *value)
2988 {
2989   struct FindClosestContext *closest_ctx = cls;
2990   struct GNUNET_TESTING_Daemon *daemon = value;
2991
2992   if (((closest_ctx->closest == NULL) ||
2993        (GNUNET_CRYPTO_hash_matching_bits(&daemon->id.hashPubKey, &closest_ctx->curr_peer->daemon->id.hashPubKey) > closest_ctx->closest_dist))
2994       && (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains(closest_ctx->curr_peer->connect_peers, key)))
2995     {
2996       closest_ctx->closest_dist = GNUNET_CRYPTO_hash_matching_bits(&daemon->id.hashPubKey, &closest_ctx->curr_peer->daemon->id.hashPubKey);
2997       closest_ctx->closest = daemon;
2998       uid_from_hash(key, &closest_ctx->closest_num);
2999     }
3000   return GNUNET_YES;
3001 }
3002
3003 /**
3004  * From the set of connections possible, choose at num connections per
3005  * peer based on depth which are closest out of those allowed.  Guaranteed
3006  * to add num peers to connect to, provided there are that many peers
3007  * in the underlay topology to connect to.
3008  *
3009  * @param pg the peergroup we are dealing with
3010  * @param num how many connections at least should each peer have (if possible)?
3011  * @param proc processor to actually add the connections
3012  */
3013 void
3014 add_closest (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num, GNUNET_TESTING_ConnectionProcessor proc)
3015 {
3016   struct FindClosestContext closest_ctx;
3017   uint32_t pg_iter;
3018   uint32_t i;
3019
3020   for (i = 0; i < num; i++) /* Each time find a closest peer (from those available) */
3021     {
3022       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3023         {
3024           closest_ctx.curr_peer = &pg->peers[pg_iter];
3025           closest_ctx.closest = NULL;
3026           closest_ctx.closest_dist = 0;
3027           closest_ctx.closest_num = 0;
3028           GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].allowed_peers, &find_closest_peers, &closest_ctx);
3029           if (closest_ctx.closest != NULL)
3030             {
3031               GNUNET_assert((0 <= closest_ctx.closest_num) && (closest_ctx.closest_num < pg->total));
3032               proc(pg, pg_iter, closest_ctx.closest_num);
3033             }
3034         }
3035     }
3036 }
3037
3038 /**
3039  * From the set of connections possible, choose at least num connections per
3040  * peer based on depth first traversal of peer connections.  If DFS leaves
3041  * peers unconnected, ensure those peers get connections.
3042  *
3043  * @param pg the peergroup we are dealing with
3044  * @param num how many connections at least should each peer have (if possible)?
3045  */
3046 void
3047 perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
3048 {
3049   struct DFSContext dfs_ctx;
3050   uint32_t pg_iter;
3051   uint32_t dfs_count;
3052   uint32_t starting_peer;
3053   uint32_t least_connections;
3054   GNUNET_HashCode second_hash;
3055
3056   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3057     {
3058       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
3059     }
3060
3061   starting_peer = 0;
3062   dfs_count = 0;
3063   while ((count_workingset_connections(pg) < num * pg->total) && (count_allowed_connections(pg) > 0))
3064     {
3065       if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */
3066         {
3067           least_connections = -1; /* Set to very high number */
3068           for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3069             {
3070               if (GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set) < least_connections)
3071                 {
3072                   starting_peer = pg_iter;
3073                   least_connections = GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
3074                 }
3075             }
3076         }
3077
3078       if (GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers) == 0)  /* Ensure there is at least one peer left to connect! */
3079         {
3080           dfs_count = 0;
3081           continue;
3082         }
3083
3084       /* Choose a random peer from the chosen peers set of connections to add */
3085       dfs_ctx.chosen = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers));
3086       dfs_ctx.first_uid = starting_peer;
3087       dfs_ctx.first = &pg->peers[starting_peer];
3088       dfs_ctx.pg = pg;
3089       dfs_ctx.current = 0;
3090
3091       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[starting_peer].connect_peers, &dfs_connect_iterator, &dfs_ctx);
3092       /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */
3093       hash_from_uid(dfs_ctx.second_uid, &second_hash);
3094       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[starting_peer].connect_peers, &second_hash, pg->peers[dfs_ctx.second_uid].daemon));
3095       starting_peer = dfs_ctx.second_uid;
3096     }
3097
3098   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3099     {
3100       /* Remove the "old" connections */
3101       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
3102       /* And replace with the working set */
3103       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
3104     }
3105 }
3106
3107 /**
3108  * Internal callback for topology information for a particular peer.
3109  */
3110 static void
3111 internal_topology_callback(void *cls,
3112                            const struct GNUNET_PeerIdentity *peer,
3113                            struct GNUNET_TIME_Relative latency, uint32_t distance)
3114 {
3115   struct CoreContext *core_ctx = cls;
3116   struct TopologyIterateContext *iter_ctx = core_ctx->iter_context;
3117
3118   if (peer == NULL) /* Either finished, or something went wrong */
3119     {
3120       iter_ctx->completed++;
3121       iter_ctx->connected--;
3122       /* One core context allocated per iteration, must free! */
3123       GNUNET_free(core_ctx);
3124     }
3125   else
3126     {
3127       iter_ctx->topology_cb(iter_ctx->cls, &core_ctx->daemon->id, peer, latency, distance, NULL);
3128     }
3129
3130   if (iter_ctx->completed == iter_ctx->total)
3131     {
3132       iter_ctx->topology_cb(iter_ctx->cls, NULL, NULL, GNUNET_TIME_relative_get_zero(), 0, NULL);
3133       /* Once all are done, free the iteration context */
3134       GNUNET_free(iter_ctx);
3135     }
3136 }
3137
3138
3139 /**
3140  * Check running topology iteration tasks, if below max start a new one, otherwise
3141  * schedule for some time in the future.
3142  */
3143 static void
3144 schedule_get_topology(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3145 {
3146   struct CoreContext *core_context = cls;
3147   struct TopologyIterateContext *topology_context = (struct TopologyIterateContext *)core_context->iter_context;
3148   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3149     return;
3150
3151   if (topology_context->connected > MAX_OUTSTANDING_CONNECTIONS)
3152     {
3153 #if VERBOSE_TESTING > 2
3154           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3155                       _("Delaying connect, we have too many outstanding connections!\n"));
3156 #endif
3157       GNUNET_SCHEDULER_add_delayed(core_context->daemon->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_get_topology, core_context);
3158     }
3159   else
3160     {
3161 #if VERBOSE_TESTING > 2
3162           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3163                       _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
3164 #endif
3165       topology_context->connected++;
3166       if (GNUNET_OK != GNUNET_CORE_iterate_peers (core_context->daemon->sched, core_context->daemon->cfg, &internal_topology_callback, core_context))
3167         internal_topology_callback(core_context, NULL, GNUNET_TIME_relative_get_zero(), 0);
3168
3169     }
3170 }
3171
3172 /**
3173  * Iterate over all (running) peers in the peer group, retrieve
3174  * all connections that each currently has.
3175  */
3176 void
3177 GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyTopology cb, void *cls)
3178 {
3179   struct TopologyIterateContext *topology_context;
3180   struct CoreContext *core_ctx;
3181   unsigned int i;
3182   unsigned int total_count;
3183
3184   /* Allocate a single topology iteration context */
3185   topology_context = GNUNET_malloc(sizeof(struct TopologyIterateContext));
3186   topology_context->topology_cb = cb;
3187   topology_context->cls = cls;
3188   total_count = 0;
3189   for (i = 0; i < pg->total; i++)
3190     {
3191       if (pg->peers[i].daemon->running == GNUNET_YES)
3192         {
3193           /* Allocate one core context per core we need to connect to */
3194           core_ctx = GNUNET_malloc(sizeof(struct CoreContext));
3195           core_ctx->daemon = pg->peers[i].daemon;
3196           /* Set back pointer to topology iteration context */
3197           core_ctx->iter_context = topology_context;
3198           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_get_topology, core_ctx);
3199           total_count++;
3200         }
3201     }
3202   topology_context->total = total_count;
3203   return;
3204 }
3205
3206 /**
3207  * Callback function to process statistic values.
3208  * This handler is here only really to insert a peer
3209  * identity (or daemon) so the statistics can be uniquely
3210  * tied to a single running peer.
3211  *
3212  * @param cls closure
3213  * @param subsystem name of subsystem that created the statistic
3214  * @param name the name of the datum
3215  * @param value the current value
3216  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
3217  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
3218  */
3219 static int internal_stats_callback (void *cls,
3220                                     const char *subsystem,
3221                                     const char *name,
3222                                     uint64_t value,
3223                                     int is_persistent)
3224 {
3225   struct StatsCoreContext *core_context = cls;
3226   struct StatsIterateContext *stats_context = (struct StatsIterateContext *)core_context->iter_context;
3227
3228   return stats_context->proc(stats_context->cls, &core_context->daemon->id, subsystem, name, value, is_persistent);
3229 }
3230
3231 /**
3232  * Internal continuation call for statistics iteration.
3233  *
3234  * @param cls closure, the CoreContext for this iteration
3235  * @param success whether or not the statistics iterations
3236  *        was canceled or not (we don't care)
3237  */
3238 static void internal_stats_cont (void *cls, int success)
3239 {
3240   struct StatsCoreContext *core_context = cls;
3241   struct StatsIterateContext *stats_context = (struct StatsIterateContext *)core_context->iter_context;
3242
3243   stats_context->connected--;
3244   stats_context->completed++;
3245
3246   if (stats_context->completed == stats_context->total)
3247     {
3248       stats_context->cont(stats_context->cls, GNUNET_YES);
3249       GNUNET_free(stats_context);
3250     }
3251
3252   if (core_context->stats_handle != NULL)
3253     GNUNET_STATISTICS_destroy(core_context->stats_handle, GNUNET_NO);
3254
3255   GNUNET_free(core_context);
3256 }
3257
3258 /**
3259  * Check running topology iteration tasks, if below max start a new one, otherwise
3260  * schedule for some time in the future.
3261  */
3262 static void
3263 schedule_get_statistics(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3264 {
3265   struct StatsCoreContext *core_context = cls;
3266   struct StatsIterateContext *stats_context = (struct StatsIterateContext *)core_context->iter_context;
3267
3268   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3269     return;
3270
3271   if (stats_context->connected > MAX_OUTSTANDING_CONNECTIONS)
3272     {
3273 #if VERBOSE_TESTING > 2
3274           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3275                       _("Delaying connect, we have too many outstanding connections!\n"));
3276 #endif
3277       GNUNET_SCHEDULER_add_delayed(core_context->daemon->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_get_statistics, core_context);
3278     }
3279   else
3280     {
3281 #if VERBOSE_TESTING > 2
3282           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3283                       _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
3284 #endif
3285
3286       stats_context->connected++;
3287       core_context->stats_handle = GNUNET_STATISTICS_create(core_context->daemon->sched, "testing", core_context->daemon->cfg);
3288       if (core_context->stats_handle == NULL)
3289         {
3290           internal_stats_cont (core_context, GNUNET_NO);
3291           return;
3292         }
3293
3294       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);
3295       if (core_context->stats_get_handle == NULL)
3296         internal_stats_cont (core_context, GNUNET_NO);
3297
3298     }
3299 }
3300
3301 struct DuplicateStats
3302 {
3303   /**
3304    * Next item in the list
3305    */
3306   struct DuplicateStats *next;
3307
3308   /**
3309    * Nasty string, concatenation of relevant information.
3310    */
3311   char *unique_string;
3312 };
3313
3314 /**
3315  * Check whether the combination of port/host/unix domain socket
3316  * already exists in the list of peers being checked for statistics.
3317  *
3318  * @param pg the peergroup in question
3319  * @param specific_peer the peer we're concerned with
3320  * @param stats_list the list to return to the caller
3321  *
3322  * @return GNUNET_YES if the statistics instance has been seen already,
3323  *         GNUNET_NO if not (and we may have added it to the list)
3324  */
3325 static int
3326 stats_check_existing(struct GNUNET_TESTING_PeerGroup *pg, struct PeerData *specific_peer, struct DuplicateStats **stats_list)
3327 {
3328   struct DuplicateStats *pos;
3329   char *unix_domain_socket;
3330   unsigned long long port;
3331   char *to_match;
3332   if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno(pg->cfg, "testing", "single_statistics_per_host"))
3333     return GNUNET_NO; /* Each peer has its own statistics instance, do nothing! */
3334
3335   pos = *stats_list;
3336   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(specific_peer->cfg, "statistics", "unixpath", &unix_domain_socket))
3337     return GNUNET_NO;
3338
3339   GNUNET_CONFIGURATION_get_value_number(specific_peer->cfg, "statistics", "port", &port);
3340
3341   if (specific_peer->daemon->hostname != NULL)
3342     GNUNET_asprintf(&to_match, "%s%s%llu", specific_peer->daemon->hostname, unix_domain_socket, port);
3343   else
3344     GNUNET_asprintf(&to_match, "%s%llu", unix_domain_socket, port);
3345
3346   while (pos != NULL)
3347     {
3348       if (0 == strcmp(to_match, pos->unique_string))
3349         {
3350           GNUNET_free(to_match);
3351           return GNUNET_YES;
3352         }
3353       pos = pos->next;
3354     }
3355   pos = GNUNET_malloc(sizeof(struct DuplicateStats));
3356   pos->unique_string = to_match;
3357   pos->next = *stats_list;
3358   *stats_list = pos;
3359   return GNUNET_NO;
3360 }
3361
3362 /**
3363  * Iterate over all (running) peers in the peer group, retrieve
3364  * all statistics from each.
3365  */
3366 void
3367 GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg,
3368                                GNUNET_STATISTICS_Callback cont,
3369                                GNUNET_TESTING_STATISTICS_Iterator proc, void *cls)
3370 {
3371   struct StatsIterateContext *stats_context;
3372   struct StatsCoreContext *core_ctx;
3373   unsigned int i;
3374   unsigned int total_count;
3375   struct DuplicateStats *stats_list;
3376   struct DuplicateStats *pos;
3377   stats_list = NULL;
3378
3379   /* Allocate a single stats iteration context */
3380   stats_context = GNUNET_malloc(sizeof(struct StatsIterateContext));
3381   stats_context->cont = cont;
3382   stats_context->proc = proc;
3383   stats_context->cls = cls;
3384   total_count = 0;
3385
3386   for (i = 0; i < pg->total; i++)
3387     {
3388       if ((pg->peers[i].daemon->running == GNUNET_YES) && (GNUNET_NO == stats_check_existing(pg, &pg->peers[i], &stats_list)))
3389         {
3390           /* Allocate one core context per core we need to connect to */
3391           core_ctx = GNUNET_malloc(sizeof(struct StatsCoreContext));
3392           core_ctx->daemon = pg->peers[i].daemon;
3393           /* Set back pointer to topology iteration context */
3394           core_ctx->iter_context = stats_context;
3395           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_get_statistics, core_ctx);
3396           total_count++;
3397         }
3398     }
3399
3400   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Retrieving stats from %u total instances.\n", total_count);
3401   stats_context->total = total_count;
3402   if (stats_list != NULL)
3403     {
3404       pos = stats_list;
3405       while(pos != NULL)
3406         {
3407           GNUNET_free(pos->unique_string);
3408           stats_list = pos->next;
3409           GNUNET_free(pos);
3410           pos = stats_list->next;
3411         }
3412     }
3413   return;
3414 }
3415
3416 /**
3417  * There are many ways to connect peers that are supported by this function.
3418  * To connect peers in the same topology that was created via the
3419  * GNUNET_TESTING_create_topology, the topology variable must be set to
3420  * GNUNET_TESTING_TOPOLOGY_NONE.  If the topology variable is specified,
3421  * a new instance of that topology will be generated and attempted to be
3422  * connected.  This could result in some connections being impossible,
3423  * because some topologies are non-deterministic.
3424  *
3425  * @param pg the peer group struct representing the running peers
3426  * @param topology which topology to connect the peers in
3427  * @param options options for connecting the topology
3428  * @param option_modifier modifier for options that take a parameter
3429  * @param notify_callback notification to be called once all connections completed
3430  * @param notify_cls closure for notification callback
3431  *
3432  * @return the number of connections that will be attempted, GNUNET_SYSERR on error
3433  */
3434 int
3435 GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
3436                                  enum GNUNET_TESTING_Topology topology,
3437                                  enum GNUNET_TESTING_TopologyOption options,
3438                                  double option_modifier,
3439                                  GNUNET_TESTING_NotifyCompletion notify_callback,
3440                                  void *notify_cls)
3441 {
3442   switch (topology)
3443       {
3444       case GNUNET_TESTING_TOPOLOGY_CLIQUE:
3445 #if VERBOSE_TOPOLOGY
3446       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3447                   _("Creating clique CONNECT topology\n"));
3448 #endif
3449         create_clique (pg, &add_actual_connections);
3450         break;
3451       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
3452 #if VERBOSE_TOPOLOGY
3453       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3454                   _("Creating small world (ring) CONNECT topology\n"));
3455 #endif
3456         create_small_world_ring (pg, &add_actual_connections);
3457         break;
3458       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
3459 #if VERBOSE_TOPOLOGY
3460       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3461                   _("Creating small world (2d-torus) CONNECT topology\n"));
3462 #endif
3463         create_small_world (pg, &add_actual_connections);
3464         break;
3465       case GNUNET_TESTING_TOPOLOGY_RING:
3466 #if VERBOSE_TOPOLOGY
3467       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3468                   _("Creating ring CONNECT topology\n"));
3469 #endif
3470         create_ring (pg, &add_actual_connections);
3471         break;
3472       case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
3473 #if VERBOSE_TOPOLOGY
3474       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3475                   _("Creating 2d torus CONNECT topology\n"));
3476 #endif
3477         create_2d_torus (pg, &add_actual_connections);
3478         break;
3479       case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
3480 #if VERBOSE_TOPOLOGY
3481       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3482                   _("Creating Erdos-Renyi CONNECT topology\n"));
3483 #endif
3484         create_erdos_renyi (pg, &add_actual_connections);
3485         break;
3486       case GNUNET_TESTING_TOPOLOGY_INTERNAT:
3487 #if VERBOSE_TOPOLOGY
3488       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3489                   _("Creating InterNAT CONNECT topology\n"));
3490 #endif
3491         create_nated_internet (pg, &add_actual_connections);
3492         break;
3493       case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
3494 #if VERBOSE_TOPOLOGY
3495       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3496                   _("Creating Scale Free CONNECT topology\n"));
3497 #endif
3498         create_scale_free (pg, &add_actual_connections);
3499         break;
3500       case GNUNET_TESTING_TOPOLOGY_LINE:
3501 #if VERBOSE_TOPOLOGY
3502       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3503                   _("Creating straight line CONNECT topology\n"));
3504 #endif
3505         create_line (pg, &add_actual_connections);
3506         break;
3507       case GNUNET_TESTING_TOPOLOGY_NONE:
3508 #if VERBOSE_TOPOLOGY
3509         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3510                   _("Creating no CONNECT topology\n"));
3511 #endif
3512         copy_allowed_topology(pg);
3513         break;
3514       default:
3515         GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
3516                    _("Unknown topology specification, can't connect peers!\n"));
3517         return GNUNET_SYSERR;
3518       }
3519
3520   switch (options)
3521     {
3522     case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM:
3523 #if VERBOSE_TOPOLOGY
3524       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3525                   _("Connecting random subset (%'.2f percent) of possible peers\n"), 100 * option_modifier);
3526 #endif
3527       choose_random_connections(pg, option_modifier);
3528       break;
3529     case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM:
3530 #if VERBOSE_TOPOLOGY
3531       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3532                   _("Connecting a minimum of %u peers each (if possible)\n"), (unsigned int)option_modifier);
3533 #endif
3534       choose_minimum(pg, (unsigned int)option_modifier);
3535       break;
3536     case GNUNET_TESTING_TOPOLOGY_OPTION_DFS:
3537 #if VERBOSE_TOPOLOGY
3538       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3539                   _("Using DFS to connect a minimum of %u peers each (if possible)\n"), (unsigned int)option_modifier);
3540 #endif
3541       perform_dfs(pg, (int)option_modifier);
3542       break;
3543     case GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST:
3544 #if VERBOSE_TOPOLOGY
3545       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3546                   _("Finding additional %u closest peers each (if possible)\n"), (unsigned int)option_modifier);
3547 #endif
3548       add_closest(pg, (unsigned int)option_modifier, &add_actual_connections);
3549       break;
3550     case GNUNET_TESTING_TOPOLOGY_OPTION_NONE:
3551       break;
3552     case GNUNET_TESTING_TOPOLOGY_OPTION_ALL:
3553       break;
3554     default:
3555       break;
3556     }
3557
3558   return connect_topology(pg, notify_callback, notify_cls);
3559 }
3560
3561 /**
3562  * Callback that is called whenever a hostkey is generated
3563  * for a peer.  Call the real callback and decrement the
3564  * starting counter for the peergroup.
3565  *
3566  * @param cls closure
3567  * @param id identifier for the daemon, NULL on error
3568  * @param d handle for the daemon
3569  * @param emsg error message (NULL on success)
3570  */
3571 static void internal_hostkey_callback (void *cls,
3572                                        const struct GNUNET_PeerIdentity *id,
3573                                        struct GNUNET_TESTING_Daemon *d,
3574                                        const char *emsg)
3575 {
3576   struct InternalStartContext *internal_context = cls;
3577   internal_context->peer->pg->starting--;
3578   internal_context->peer->pg->started++;
3579   if (internal_context->hostkey_callback != NULL)
3580     internal_context->hostkey_callback(internal_context->hostkey_cls, id, d, emsg);
3581   else if (internal_context->peer->pg->started == internal_context->peer->pg->total)
3582     {
3583       internal_context->peer->pg->started = 0; /* Internal startup may use this counter! */
3584       GNUNET_TESTING_daemons_continue_startup(internal_context->peer->pg);
3585     }
3586 }
3587
3588 /**
3589  * Callback that is called whenever a peer has finished starting.
3590  * Call the real callback and decrement the starting counter
3591  * for the peergroup.
3592  *
3593  * @param cls closure
3594  * @param id identifier for the daemon, NULL on error
3595  * @param d handle for the daemon
3596  * @param emsg error message (NULL on success)
3597  */
3598 static void internal_startup_callback (void *cls,
3599                                        const struct GNUNET_PeerIdentity *id,
3600                                        const struct GNUNET_CONFIGURATION_Handle *cfg,
3601                                        struct GNUNET_TESTING_Daemon *d,
3602                                        const char *emsg)
3603 {
3604   struct InternalStartContext *internal_context = cls;
3605   internal_context->peer->pg->starting--;
3606   if (internal_context->start_cb != NULL)
3607     internal_context->start_cb(internal_context->start_cb_cls, id, cfg, d, emsg);
3608 }
3609
3610 static void
3611 internal_continue_startup (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
3612 {
3613   struct InternalStartContext *internal_context = cls;
3614
3615   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3616     {
3617       return;
3618     }
3619
3620   if (internal_context->peer->pg->starting < MAX_CONCURRENT_STARTING)
3621     {
3622       internal_context->peer->pg->starting++;
3623       GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon);
3624     }
3625   else
3626     {
3627       GNUNET_SCHEDULER_add_delayed(internal_context->peer->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &internal_continue_startup, internal_context);
3628     }
3629 }
3630
3631
3632 /**
3633  * Callback for informing us about a successful
3634  * or unsuccessful churn start call.
3635  *
3636  * @param cls a ChurnContext
3637  * @param id the peer identity of the started peer
3638  * @param cfg the handle to the configuration of the peer
3639  * @param d handle to the daemon for the peer
3640  * @param emsg NULL on success, non-NULL on failure
3641  *
3642  */
3643 void
3644 churn_start_callback (void *cls,
3645                       const struct GNUNET_PeerIdentity *id,
3646                       const struct GNUNET_CONFIGURATION_Handle *cfg,
3647                       struct GNUNET_TESTING_Daemon *d,
3648                       const char *emsg)
3649 {
3650   struct ChurnRestartContext *startup_ctx = cls;
3651   struct ChurnContext *churn_ctx = startup_ctx->churn_ctx;
3652
3653   unsigned int total_left;
3654   char *error_message;
3655
3656   error_message = NULL;
3657   if (emsg != NULL)
3658     {
3659       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3660                   "Churn stop callback failed with error `%s'\n",
3661                   emsg);
3662       churn_ctx->num_failed_start++;
3663     }
3664   else
3665     {
3666       churn_ctx->num_to_start--;
3667     }
3668
3669 #if DEBUG_CHURN
3670   GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
3671              "Started peer, %d left.\n",
3672              churn_ctx->num_to_start);
3673 #endif
3674
3675   total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
3676
3677   if (total_left == 0)
3678   {
3679     if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
3680       GNUNET_asprintf(&error_message,
3681                       "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!",
3682                       churn_ctx->num_failed_start,
3683                       churn_ctx->num_failed_stop);
3684     churn_ctx->cb(churn_ctx->cb_cls, error_message);
3685     GNUNET_free_non_null(error_message);
3686     GNUNET_free(churn_ctx);
3687     GNUNET_free(startup_ctx);
3688   }
3689 }
3690
3691
3692 static void schedule_churn_restart(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
3693 {
3694   struct PeerRestartContext *peer_restart_ctx = cls;
3695   struct ChurnRestartContext *startup_ctx = peer_restart_ctx->churn_restart_ctx;
3696
3697   if (startup_ctx->outstanding > MAX_CONCURRENT_STARTING)
3698     GNUNET_SCHEDULER_add_delayed(peer_restart_ctx->daemon->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_churn_restart, peer_restart_ctx);
3699   else
3700     {
3701       GNUNET_TESTING_daemon_start_stopped(peer_restart_ctx->daemon,
3702                                           startup_ctx->timeout,
3703                                           &churn_start_callback,
3704                                           startup_ctx);
3705       GNUNET_free(peer_restart_ctx);
3706     }
3707 }
3708
3709 static void
3710 internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
3711 {
3712   struct InternalStartContext *internal_context = cls;
3713
3714   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3715     {
3716       return;
3717     }
3718
3719   if (internal_context->peer->pg->starting < MAX_CONCURRENT_HOSTKEYS)
3720     {
3721       internal_context->peer->pg->starting++;
3722       internal_context->peer->daemon = GNUNET_TESTING_daemon_start (internal_context->peer->pg->sched,
3723                                                                     internal_context->peer->cfg,
3724                                                                     internal_context->timeout,
3725                                                                     internal_context->hostname,
3726                                                                     internal_context->username,
3727                                                                     internal_context->sshport,
3728                                                                     &internal_hostkey_callback,
3729                                                                     internal_context,
3730                                                                     &internal_startup_callback,
3731                                                                     internal_context);
3732     }
3733   else
3734     {
3735       GNUNET_SCHEDULER_add_delayed(internal_context->peer->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &internal_start, internal_context);
3736     }
3737 }
3738
3739 /**
3740  * Function which continues a peer group starting up
3741  * after successfully generating hostkeys for each peer.
3742  *
3743  * @param pg the peer group to continue starting
3744  *
3745  */
3746 void
3747 GNUNET_TESTING_daemons_continue_startup(struct GNUNET_TESTING_PeerGroup *pg)
3748 {
3749   unsigned int i;
3750
3751   pg->starting = 0;
3752   for (i = 0; i < pg->total; i++)
3753     {
3754       GNUNET_SCHEDULER_add_now (pg->sched, &internal_continue_startup, &pg->peers[i].internal_context);
3755       //GNUNET_TESTING_daemon_continue_startup(pg->peers[i].daemon);
3756     }
3757 }
3758
3759 /**
3760  * Start count gnunet instances with the same set of transports and
3761  * applications.  The port numbers (any option called "PORT") will be
3762  * adjusted to ensure that no two peers running on the same system
3763  * have the same port(s) in their respective configurations.
3764  *
3765  * @param sched scheduler to use
3766  * @param cfg configuration template to use
3767  * @param total number of daemons to start
3768  * @param timeout total time allowed for peers to start
3769  * @param hostkey_callback function to call on each peers hostkey generation
3770  *        if NULL, peers will be started by this call, if non-null,
3771  *        GNUNET_TESTING_daemons_continue_startup must be called after
3772  *        successful hostkey generation
3773  * @param hostkey_cls closure for hostkey callback
3774  * @param cb function to call on each daemon that was started
3775  * @param cb_cls closure for cb
3776  * @param connect_callback function to call each time two hosts are connected
3777  * @param connect_callback_cls closure for connect_callback
3778  * @param hostnames linked list of hosts to use to start peers on (NULL to run on localhost only)
3779  *
3780  * @return NULL on error, otherwise handle to control peer group
3781  */
3782 struct GNUNET_TESTING_PeerGroup *
3783 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
3784                               const struct GNUNET_CONFIGURATION_Handle *cfg,
3785                               unsigned int total,
3786                               struct GNUNET_TIME_Relative timeout,
3787                               GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback,
3788                               void *hostkey_cls,
3789                               GNUNET_TESTING_NotifyDaemonRunning cb,
3790                               void *cb_cls,
3791                               GNUNET_TESTING_NotifyConnection
3792                               connect_callback, void *connect_callback_cls,
3793                               const struct GNUNET_TESTING_Host *hostnames)
3794 {
3795   struct GNUNET_TESTING_PeerGroup *pg;
3796   const struct GNUNET_TESTING_Host *hostpos;
3797 #if 0
3798   char *pos;
3799   const char *rpos;
3800   char *start;
3801 #endif
3802   const char *hostname;
3803   const char *username;
3804   char *baseservicehome;
3805   char *newservicehome;
3806   char *tmpdir;
3807   struct GNUNET_CONFIGURATION_Handle *pcfg;
3808   unsigned int off;
3809   unsigned int hostcnt;
3810   uint16_t minport;
3811   uint16_t sshport;
3812   uint32_t upnum;
3813   uint32_t fdnum;
3814
3815   if (0 == total)
3816     {
3817       GNUNET_break (0);
3818       return NULL;
3819     }
3820   upnum = 0;
3821   fdnum = 0;
3822   pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
3823   pg->sched = sched;
3824   pg->cfg = cfg;
3825   pg->notify_connection = connect_callback;
3826   pg->notify_connection_cls = connect_callback_cls;
3827   pg->total = total;
3828   pg->max_timeout = GNUNET_TIME_relative_to_absolute(timeout);
3829   pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
3830   if (NULL != hostnames)
3831     {
3832       off = 0;
3833       hostpos = hostnames;
3834       while (hostpos != NULL)
3835         {
3836           hostpos = hostpos->next;
3837           off++;
3838         }
3839       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
3840       off = 0;
3841
3842       hostpos = hostnames;
3843       while (hostpos != NULL)
3844         {
3845           pg->hosts[off].minport = LOW_PORT;
3846           pg->hosts[off].hostname = GNUNET_strdup(hostpos->hostname);
3847           if (hostpos->username != NULL)
3848             pg->hosts[off].username = GNUNET_strdup(hostpos->username);
3849           pg->hosts[off].sshport = hostpos->port;
3850           hostpos = hostpos->next;
3851           off++;
3852         }
3853
3854       if (off == 0)
3855         {
3856           pg->hosts = NULL;
3857         }
3858       hostcnt = off;
3859       minport = 0;
3860       pg->num_hosts = off;
3861
3862 #if NO_LL
3863       off = 2;
3864       /* skip leading spaces */
3865       while ((0 != *hostnames) && (isspace ( (unsigned char) *hostnames)))
3866         hostnames++;
3867       rpos = hostnames;
3868       while ('\0' != *rpos)
3869         {
3870           if (isspace ( (unsigned char) *rpos))
3871             off++;
3872           rpos++;
3873         }
3874       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
3875       off = 0;
3876       start = GNUNET_strdup (hostnames);
3877       pos = start;
3878       while ('\0' != *pos)
3879         {
3880           if (isspace ( (unsigned char) *pos))
3881             {
3882               *pos = '\0';
3883               if (strlen (start) > 0)
3884                 {
3885                   pg->hosts[off].minport = LOW_PORT;
3886                   pg->hosts[off++].hostname = start;
3887                 }
3888               start = pos + 1;
3889             }
3890           pos++;
3891         }
3892       if (strlen (start) > 0)
3893         {
3894           pg->hosts[off].minport = LOW_PORT;
3895           pg->hosts[off++].hostname = start;
3896         }
3897       if (off == 0)
3898         {
3899           GNUNET_free (start);
3900           GNUNET_free (pg->hosts);
3901           pg->hosts = NULL;
3902         }
3903       hostcnt = off;
3904       minport = 0;              /* make gcc happy */
3905 #endif
3906     }
3907   else
3908     {
3909       hostcnt = 0;
3910       minport = LOW_PORT;
3911     }
3912   for (off = 0; off < total; off++)
3913     {
3914       if (hostcnt > 0)
3915         {
3916           hostname = pg->hosts[off % hostcnt].hostname;
3917           username = pg->hosts[off % hostcnt].username;
3918           sshport = pg->hosts[off % hostcnt].sshport;
3919           pcfg = make_config (cfg, 
3920                               &pg->hosts[off % hostcnt].minport,
3921                               &upnum,
3922                               hostname, &fdnum);
3923         }
3924       else
3925         {
3926           hostname = NULL;
3927           username = NULL;
3928           sshport = 0;
3929           pcfg = make_config (cfg,
3930                               &minport,
3931                               &upnum,
3932                               hostname, &fdnum);
3933         }
3934
3935       if (NULL == pcfg)
3936         {
3937           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3938                       _
3939                       ("Could not create configuration for peer number %u on `%s'!\n"),
3940                       off, hostname == NULL ? "localhost" : hostname);
3941           continue;
3942         }
3943
3944       if (GNUNET_YES ==
3945           GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
3946                                                  &baseservicehome))
3947         {
3948           GNUNET_asprintf (&newservicehome,
3949                            "%s/%d/", baseservicehome, off);
3950           GNUNET_free (baseservicehome);
3951         }
3952       else
3953         {
3954           tmpdir = getenv ("TMPDIR");
3955           tmpdir = tmpdir ? tmpdir : "/tmp";
3956           GNUNET_asprintf (&newservicehome,
3957                            "%s/%s/%d/",
3958                            tmpdir,
3959                            "gnunet-testing-test-test", off);
3960         }
3961       GNUNET_CONFIGURATION_set_value_string (pcfg,
3962                                              "PATHS",
3963                                              "SERVICEHOME", newservicehome);
3964       GNUNET_free (newservicehome);
3965       pg->peers[off].cfg = pcfg;
3966       pg->peers[off].allowed_peers = GNUNET_CONTAINER_multihashmap_create(total);
3967       pg->peers[off].connect_peers = GNUNET_CONTAINER_multihashmap_create(total);
3968       pg->peers[off].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create(total);
3969       pg->peers[off].pg = pg;
3970
3971       pg->peers[off].internal_context.peer = &pg->peers[off];
3972       pg->peers[off].internal_context.timeout = timeout;
3973       pg->peers[off].internal_context.hostname = hostname;
3974       pg->peers[off].internal_context.username = username;
3975       pg->peers[off].internal_context.sshport = sshport;
3976       pg->peers[off].internal_context.hostkey_callback = hostkey_callback;
3977       pg->peers[off].internal_context.hostkey_cls = hostkey_cls;
3978       pg->peers[off].internal_context.start_cb = cb;
3979       pg->peers[off].internal_context.start_cb_cls = cb_cls;
3980
3981       GNUNET_SCHEDULER_add_now (sched, &internal_start, &pg->peers[off].internal_context);
3982
3983     }
3984   return pg;
3985 }
3986
3987 /*
3988  * Get a daemon by number, so callers don't have to do nasty
3989  * offsetting operation.
3990  */
3991 struct GNUNET_TESTING_Daemon *
3992 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
3993 {
3994   if (position < pg->total)
3995     return pg->peers[position].daemon;
3996   else
3997     return NULL;
3998 }
3999
4000 /*
4001  * Get a daemon by peer identity, so callers can
4002  * retrieve the daemon without knowing it's offset.
4003  *
4004  * @param pg the peer group to retrieve the daemon from
4005  * @param peer_id the peer identity of the daemon to retrieve
4006  *
4007  * @return the daemon on success, or NULL if no such peer identity is found
4008  */
4009 struct GNUNET_TESTING_Daemon *
4010 GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg, struct GNUNET_PeerIdentity *peer_id)
4011 {
4012   unsigned int i;
4013
4014   for (i = 0; i < pg->total; i ++)
4015     {
4016       if (0 == memcmp(&pg->peers[i].daemon->id, peer_id, sizeof(struct GNUNET_PeerIdentity)))
4017         return pg->peers[i].daemon;
4018     }
4019
4020   return NULL;
4021 }
4022
4023 /**
4024  * Prototype of a function that will be called when a
4025  * particular operation was completed the testing library.
4026  *
4027  * @param cls closure (a struct RestartContext)
4028  * @param id id of the peer that was restarted
4029  * @param cfg handle to the configuration of the peer
4030  * @param d handle to the daemon that was restarted
4031  * @param emsg NULL on success
4032  */
4033 void restart_callback (void *cls,
4034                        const struct GNUNET_PeerIdentity *id,
4035                        const struct GNUNET_CONFIGURATION_Handle *cfg,
4036                        struct GNUNET_TESTING_Daemon *d,
4037                        const char *emsg)
4038 {
4039   struct RestartContext *restart_context = cls;
4040
4041   if (emsg == NULL)
4042     {
4043       restart_context->peers_restarted++;
4044     }
4045   else
4046     {
4047       restart_context->peers_restart_failed++;
4048     }
4049
4050   if (restart_context->peers_restarted == restart_context->peer_group->total)
4051     {
4052       restart_context->callback(restart_context->callback_cls, NULL);
4053       GNUNET_free(restart_context);
4054     }
4055   else if (restart_context->peers_restart_failed + restart_context->peers_restarted == restart_context->peer_group->total)
4056     {
4057       restart_context->callback(restart_context->callback_cls, "Failed to restart peers!");
4058       GNUNET_free(restart_context);
4059     }
4060
4061 }
4062
4063 /**
4064  * Callback for informing us about a successful
4065  * or unsuccessful churn stop call.
4066  *
4067  * @param cls a ChurnContext
4068  * @param emsg NULL on success, non-NULL on failure
4069  *
4070  */
4071 void
4072 churn_stop_callback (void *cls, const char *emsg)
4073 {
4074   struct ShutdownContext *shutdown_ctx = cls;
4075   struct ChurnContext *churn_ctx = shutdown_ctx->cb_cls;
4076   unsigned int total_left;
4077   char *error_message;
4078
4079   error_message = NULL;
4080   shutdown_ctx->outstanding--;
4081
4082   if (emsg != NULL)
4083     {
4084       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
4085                  "Churn stop callback failed with error `%s'\n", emsg);
4086       churn_ctx->num_failed_stop++;
4087     }
4088   else
4089     {
4090       churn_ctx->num_to_stop--;
4091     }
4092
4093 #if DEBUG_CHURN
4094   GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
4095              "Stopped peer, %d left.\n", 
4096              churn_ctx->num_to_stop);
4097 #endif
4098   total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
4099
4100   if (total_left == 0)
4101   {
4102     if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
4103       {
4104         GNUNET_asprintf(&error_message, 
4105                         "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", 
4106                         churn_ctx->num_failed_start, 
4107                         churn_ctx->num_failed_stop);
4108       }
4109     churn_ctx->cb(churn_ctx->cb_cls, error_message);
4110     GNUNET_free_non_null(error_message);
4111     GNUNET_free(churn_ctx);
4112     GNUNET_free(shutdown_ctx);
4113   }
4114 }
4115
4116 /**
4117  * Count the number of running peers.
4118  *
4119  * @param pg handle for the peer group
4120  *
4121  * @return the number of currently running peers in the peer group
4122  */
4123 unsigned int
4124 GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg)
4125 {
4126   unsigned int i;
4127   unsigned int running = 0;
4128   for (i = 0; i < pg->total; i++)
4129   {
4130     if (pg->peers[i].daemon->running == GNUNET_YES)
4131     {
4132       GNUNET_assert(running != -1);
4133       running++;
4134     }
4135   }
4136   return running;
4137 }
4138
4139 /**
4140  * Task to rate limit the number of outstanding peer shutdown
4141  * requests.  This is necessary for making sure we don't do
4142  * too many ssh connections at once, but is generally nicer
4143  * to any system as well (graduated task starts, as opposed
4144  * to calling gnunet-arm N times all at once).
4145  */
4146 static void
4147 schedule_churn_shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
4148 {
4149   struct PeerShutdownContext *peer_shutdown_ctx = cls;
4150   struct ShutdownContext *shutdown_ctx;
4151
4152   GNUNET_assert(peer_shutdown_ctx != NULL);
4153   shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
4154   GNUNET_assert(shutdown_ctx != NULL);
4155
4156   if (shutdown_ctx->outstanding > MAX_CONCURRENT_SHUTDOWN)
4157     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);
4158   else
4159     {
4160       shutdown_ctx->outstanding++;
4161       GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon, shutdown_ctx->timeout, shutdown_ctx->cb, shutdown_ctx, GNUNET_NO, GNUNET_YES);
4162       GNUNET_free(peer_shutdown_ctx);
4163     }
4164 }
4165
4166 /**
4167  * Simulate churn by stopping some peers (and possibly
4168  * re-starting others if churn is called multiple times).  This
4169  * function can only be used to create leave-join churn (peers "never"
4170  * leave for good).  First "voff" random peers that are currently
4171  * online will be taken offline; then "von" random peers that are then
4172  * offline will be put back online.  No notifications will be
4173  * generated for any of these operations except for the callback upon
4174  * completion.
4175  *
4176  * @param pg handle for the peer group
4177  * @param voff number of peers that should go offline
4178  * @param von number of peers that should come back online;
4179  *            must be zero on first call (since "testbed_start"
4180  *            always starts all of the peers)
4181  * @param timeout how long to wait for operations to finish before
4182  *        giving up
4183  * @param cb function to call at the end
4184  * @param cb_cls closure for cb
4185  */
4186 void
4187 GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg,
4188                               unsigned int voff,
4189                               unsigned int von,
4190                               struct GNUNET_TIME_Relative timeout,
4191                               GNUNET_TESTING_NotifyCompletion cb,
4192                               void *cb_cls)
4193 {
4194   struct ChurnContext *churn_ctx;
4195   struct ShutdownContext *shutdown_ctx;
4196   struct PeerShutdownContext *peer_shutdown_ctx;
4197   struct PeerRestartContext *peer_restart_ctx;
4198   struct ChurnRestartContext *churn_startup_ctx;
4199
4200   unsigned int running;
4201   unsigned int stopped;
4202   unsigned int total_running;
4203   unsigned int total_stopped;
4204   unsigned int i;
4205   unsigned int *running_arr;
4206   unsigned int *stopped_arr;
4207   unsigned int *running_permute;
4208   unsigned int *stopped_permute;
4209
4210   running = 0;
4211   stopped = 0;
4212
4213   if ((von == 0) && (voff == 0)) /* No peers at all? */
4214     {
4215       cb(cb_cls, NULL);
4216       return;
4217     }
4218
4219   for (i = 0; i < pg->total; i++)
4220   {
4221     if (pg->peers[i].daemon->running == GNUNET_YES)
4222     {
4223       GNUNET_assert(running != -1);
4224       running++;
4225     }
4226     else
4227     {
4228       GNUNET_assert(stopped != -1);
4229       stopped++;
4230     }
4231   }
4232
4233   if (voff > running)
4234   {
4235     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to stop more peers than are currently running!\n");
4236     cb(cb_cls, "Trying to stop more peers than are currently running!");
4237     return;
4238   }
4239
4240   if (von > stopped)
4241   {
4242     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to start more peers than are currently stopped!\n");
4243     cb(cb_cls, "Trying to start more peers than are currently stopped!");
4244     return;
4245   }
4246
4247   churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
4248
4249   running_arr = NULL;
4250   if (running > 0)
4251     running_arr = GNUNET_malloc(running * sizeof(unsigned int));
4252
4253   stopped_arr = NULL;
4254   if (stopped > 0)
4255     stopped_arr = GNUNET_malloc(stopped * sizeof(unsigned int));
4256
4257   running_permute = NULL;
4258   stopped_permute = NULL;
4259
4260   if (running > 0)
4261     running_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, running);
4262   if (stopped > 0)
4263     stopped_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, stopped);
4264
4265   total_running = running;
4266   total_stopped = stopped;
4267   running = 0;
4268   stopped = 0;
4269
4270   churn_ctx->num_to_start = von;
4271   churn_ctx->num_to_stop = voff;
4272   churn_ctx->cb = cb;
4273   churn_ctx->cb_cls = cb_cls;  
4274
4275   for (i = 0; i < pg->total; i++)
4276   {
4277     if (pg->peers[i].daemon->running == GNUNET_YES)
4278     {
4279       GNUNET_assert((running_arr != NULL) && (total_running > running));
4280       running_arr[running] = i;
4281       running++;
4282     }
4283     else
4284     {
4285       GNUNET_assert((stopped_arr != NULL) && (total_stopped > stopped));
4286       stopped_arr[stopped] = i;
4287       stopped++;
4288     }
4289   }
4290
4291   GNUNET_assert(running >= voff);
4292   if (voff > 0)
4293     {
4294       shutdown_ctx = GNUNET_malloc(sizeof(struct ShutdownContext));
4295       shutdown_ctx->cb = &churn_stop_callback;
4296       shutdown_ctx->cb_cls = churn_ctx;
4297       shutdown_ctx->total_peers = voff;
4298       shutdown_ctx->timeout = timeout;
4299     }
4300
4301   for (i = 0; i < voff; i++)
4302   {
4303 #if DEBUG_CHURN
4304     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Stopping peer %d!\n", running_permute[i]);
4305 #endif
4306     GNUNET_assert(running_arr != NULL);
4307     peer_shutdown_ctx = GNUNET_malloc(sizeof(struct PeerShutdownContext));
4308     peer_shutdown_ctx->daemon = pg->peers[running_arr[running_permute[i]]].daemon;
4309     peer_shutdown_ctx->shutdown_ctx = shutdown_ctx;
4310     GNUNET_SCHEDULER_add_now(peer_shutdown_ctx->daemon->sched, &schedule_churn_shutdown_task, peer_shutdown_ctx);
4311
4312     /*
4313     GNUNET_TESTING_daemon_stop (pg->peers[running_arr[running_permute[i]]].daemon,
4314                                 timeout, 
4315                                 &churn_stop_callback, churn_ctx, 
4316                                 GNUNET_NO, GNUNET_YES); */
4317   }
4318
4319   GNUNET_assert(stopped >= von);
4320   if (von > 0)
4321     {
4322       churn_startup_ctx = GNUNET_malloc(sizeof(struct ChurnRestartContext));
4323       churn_startup_ctx->churn_ctx = churn_ctx;
4324       churn_startup_ctx->timeout = timeout;
4325     }
4326   for (i = 0; i < von; i++)
4327     {
4328 #if DEBUG_CHURN
4329       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Starting up peer %d!\n", stopped_permute[i]);
4330 #endif
4331       GNUNET_assert(stopped_arr != NULL);
4332       peer_restart_ctx = GNUNET_malloc(sizeof(struct PeerRestartContext));
4333       peer_restart_ctx->churn_restart_ctx = churn_startup_ctx;
4334       peer_restart_ctx->daemon = pg->peers[stopped_arr[stopped_permute[i]]].daemon;
4335       GNUNET_SCHEDULER_add_now(peer_restart_ctx->daemon->sched, &schedule_churn_restart, peer_restart_ctx);
4336       /*
4337       GNUNET_TESTING_daemon_start_stopped(pg->peers[stopped_arr[stopped_permute[i]]].daemon, 
4338                                           timeout, &churn_start_callback, churn_ctx);*/
4339   }
4340
4341   GNUNET_free_non_null(running_arr);
4342   GNUNET_free_non_null(stopped_arr);
4343   GNUNET_free_non_null(running_permute);
4344   GNUNET_free_non_null(stopped_permute);
4345 }
4346
4347
4348 /**
4349  * Restart all peers in the given group.
4350  *
4351  * @param pg the handle to the peer group
4352  * @param callback function to call on completion (or failure)
4353  * @param callback_cls closure for the callback function
4354  */
4355 void
4356 GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg,
4357                                 GNUNET_TESTING_NotifyCompletion callback,
4358                                 void *callback_cls)
4359 {
4360   struct RestartContext *restart_context;
4361   unsigned int off;
4362
4363   if (pg->total > 0)
4364     {
4365       restart_context = GNUNET_malloc(sizeof(struct RestartContext));
4366       restart_context->peer_group = pg;
4367       restart_context->peers_restarted = 0;
4368       restart_context->callback = callback;
4369       restart_context->callback_cls = callback_cls;
4370
4371       for (off = 0; off < pg->total; off++)
4372         {
4373           GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, restart_context);
4374         }
4375     }
4376 }
4377
4378 /**
4379  * Start or stop an individual peer from the given group.
4380  *
4381  * @param pg handle to the peer group
4382  * @param offset which peer to start or stop
4383  * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it
4384  * @param timeout how long to wait for shutdown
4385  * @param cb function to call at the end
4386  * @param cb_cls closure for cb
4387  */
4388 void
4389 GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, 
4390                              unsigned int offset,
4391                              int desired_status,
4392                              struct GNUNET_TIME_Relative timeout,
4393                              GNUNET_TESTING_NotifyCompletion cb,
4394                              void *cb_cls)
4395 {
4396   struct ShutdownContext *shutdown_ctx;
4397   struct ChurnRestartContext *startup_ctx;
4398   struct ChurnContext *churn_ctx;
4399
4400   if (GNUNET_NO == desired_status)
4401     {
4402       if (NULL != pg->peers[offset].daemon)
4403         {
4404           shutdown_ctx = GNUNET_malloc(sizeof(struct ShutdownContext));
4405           churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
4406           churn_ctx->num_to_start = 0;
4407           churn_ctx->num_to_stop = 1;
4408           churn_ctx->cb = cb;
4409           churn_ctx->cb_cls = cb_cls;
4410           shutdown_ctx->cb_cls = churn_ctx;
4411           GNUNET_TESTING_daemon_stop(pg->peers[offset].daemon, 
4412                                      timeout, &churn_stop_callback, shutdown_ctx,
4413                                      GNUNET_NO, GNUNET_YES);     
4414         }
4415     }
4416   else if (GNUNET_YES == desired_status)
4417     {
4418       if (NULL == pg->peers[offset].daemon)
4419         {
4420           startup_ctx = GNUNET_malloc(sizeof(struct ChurnRestartContext));
4421           churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
4422           churn_ctx->num_to_start = 1;
4423           churn_ctx->num_to_stop = 0;
4424           churn_ctx->cb = cb;
4425           churn_ctx->cb_cls = cb_cls;  
4426           startup_ctx->churn_ctx = churn_ctx;
4427           GNUNET_TESTING_daemon_start_stopped(pg->peers[offset].daemon, 
4428                                               timeout, &churn_start_callback, startup_ctx);
4429         }
4430     }
4431   else
4432     GNUNET_break (0);
4433 }
4434
4435
4436 /**
4437  * Callback for shutting down peers in a peer group.
4438  *
4439  * @param cls closure (struct ShutdownContext)
4440  * @param emsg NULL on success
4441  */
4442 void internal_shutdown_callback (void *cls,
4443                                  const char *emsg)
4444 {
4445   struct ShutdownContext *shutdown_ctx = cls;
4446
4447   shutdown_ctx->outstanding--;
4448   if (emsg == NULL)
4449     {
4450       shutdown_ctx->peers_down++;
4451     }
4452   else
4453     {
4454       shutdown_ctx->peers_failed++;
4455     }
4456
4457   if ((shutdown_ctx->cb != NULL) && (shutdown_ctx->peers_down + shutdown_ctx->peers_failed == shutdown_ctx->total_peers))
4458     {
4459       if (shutdown_ctx->peers_failed > 0)
4460         shutdown_ctx->cb(shutdown_ctx->cb_cls, "Not all peers successfully shut down!");
4461       else
4462         shutdown_ctx->cb(shutdown_ctx->cb_cls, NULL);
4463       GNUNET_free(shutdown_ctx);
4464     }
4465 }
4466
4467
4468 /**
4469  * Task to rate limit the number of outstanding peer shutdown
4470  * requests.  This is necessary for making sure we don't do
4471  * too many ssh connections at once, but is generally nicer
4472  * to any system as well (graduated task starts, as opposed
4473  * to calling gnunet-arm N times all at once).
4474  */
4475 static void
4476 schedule_shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
4477 {
4478   struct PeerShutdownContext *peer_shutdown_ctx = cls;
4479   struct ShutdownContext *shutdown_ctx;
4480
4481   GNUNET_assert(peer_shutdown_ctx != NULL);
4482   shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
4483   GNUNET_assert(shutdown_ctx != NULL);
4484
4485   if (shutdown_ctx->outstanding > MAX_CONCURRENT_SHUTDOWN)
4486     GNUNET_SCHEDULER_add_delayed(peer_shutdown_ctx->daemon->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_shutdown_task, peer_shutdown_ctx);
4487   else
4488     {
4489       shutdown_ctx->outstanding++;
4490       GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon, shutdown_ctx->timeout, &internal_shutdown_callback, shutdown_ctx, GNUNET_YES, GNUNET_NO);
4491       GNUNET_free(peer_shutdown_ctx);
4492     }
4493 }
4494
4495 /**
4496  * Shutdown all peers started in the given group.
4497  *
4498  * @param pg handle to the peer group
4499  * @param timeout how long to wait for shutdown
4500  * @param cb callback to notify upon success or failure
4501  * @param cb_cls closure for cb
4502  */
4503 void
4504 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, 
4505                              struct GNUNET_TIME_Relative timeout,
4506                              GNUNET_TESTING_NotifyCompletion cb,
4507                              void *cb_cls)
4508 {
4509   unsigned int off;
4510   struct ShutdownContext *shutdown_ctx;
4511   struct PeerShutdownContext *peer_shutdown_ctx;
4512
4513   GNUNET_assert(pg->total > 0);
4514
4515   shutdown_ctx = GNUNET_malloc(sizeof(struct ShutdownContext));
4516   shutdown_ctx->cb = cb;
4517   shutdown_ctx->cb_cls = cb_cls;
4518   shutdown_ctx->total_peers = pg->total;
4519   shutdown_ctx->timeout = timeout;
4520   /* shtudown_ctx->outstanding = 0; */
4521
4522   for (off = 0; off < pg->total; off++)
4523     {
4524       GNUNET_assert(NULL != pg->peers[off].daemon);
4525       peer_shutdown_ctx = GNUNET_malloc(sizeof(struct PeerShutdownContext));
4526       peer_shutdown_ctx->daemon = pg->peers[off].daemon;
4527       peer_shutdown_ctx->shutdown_ctx = shutdown_ctx;
4528       GNUNET_SCHEDULER_add_now(pg->peers[off].daemon->sched, &schedule_shutdown_task, peer_shutdown_ctx);
4529       //GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, timeout, shutdown_cb, shutdown_ctx, GNUNET_YES, GNUNET_NO);
4530       if (NULL != pg->peers[off].cfg)
4531         GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
4532       if (pg->peers[off].allowed_peers != NULL)
4533         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].allowed_peers);
4534       if (pg->peers[off].connect_peers != NULL)
4535         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].connect_peers);
4536       if (pg->peers[off].blacklisted_peers != NULL)
4537         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].blacklisted_peers);
4538     }
4539   GNUNET_free (pg->peers);
4540   for (off = 0; off < pg->num_hosts; off++)
4541     {
4542       GNUNET_free (pg->hosts[off].hostname);
4543       GNUNET_free_non_null (pg->hosts[off].username);
4544     }
4545   GNUNET_free_non_null (pg->hosts);
4546   GNUNET_free (pg);
4547 }
4548
4549
4550 /* end of testing_group.c */