original patch from Mantis 1614
[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   if (small_world_it < 1)
1558     small_world_it = 1;
1559   GNUNET_assert(small_world_it > 0 && small_world_it < (unsigned int)-1);
1560   for (i = 0; i < small_world_it; i++)
1561     {
1562       for (j = 0; j < pg->total; j++)
1563         {
1564           /* Determine the row and column of node at position j on the 2d torus */
1565           node1Row = j / cols;
1566           node1Col = j - (node1Row * cols);
1567           for (k = 0; k < pg->total; k++)
1568             {
1569               /* Determine the row and column of node at position k on the 2d torus */
1570               node2Row = k / cols;
1571               node2Col = k - (node2Row * cols);
1572               /* Simple Cartesian distance */
1573               distance = abs (node1Row - node2Row) + abs (node1Col - node2Col);
1574               if (distance > 1)
1575                 {
1576                   /* Calculate probability as 1 over the square of the distance */
1577                   probability = 1.0 / (distance * distance);
1578                   /* Choose a random value between 0 and 1 */
1579                   random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
1580                                                               UINT64_MAX)) / ( (double) UINT64_MAX);
1581                   /* If random < probability, then connect the two nodes */
1582                   if (random < probability)
1583                     smallWorldConnections += proc (pg, j, k);
1584
1585                 }
1586             }
1587         }
1588     }
1589   connect_attempts += smallWorldConnections;
1590 #if VERBOSE_TESTING > 2
1591           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1592                       _("Total connections added for small world: %d!\n"),
1593                       smallWorldConnections);
1594 #endif
1595   return connect_attempts;
1596 }
1597
1598 /**
1599  * Create a topology given a peer group (set of running peers)
1600  * and a connection processor.
1601  *
1602  * @param pg the peergroup to create the topology on
1603  * @param proc the connection processor to call to actually set
1604  *        up connections between two peers
1605  *
1606  * @return the number of connections that were set up
1607  *
1608  */
1609 static unsigned int
1610 create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1611 {
1612   double temp_rand;
1613   unsigned int outer_count;
1614   unsigned int inner_count;
1615   int connect_attempts;
1616   double probability;
1617   char *p_string;
1618
1619   probability = 0.5; /* FIXME: default percentage? */
1620   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
1621                                                          "TESTING",
1622                                                          "PROBABILITY",
1623                                                          &p_string))
1624     {
1625       if (sscanf(p_string, "%lf", &probability) != 1)
1626         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1627                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1628                     p_string,
1629                     "PROBABILITY",
1630                     "TESTING");
1631       GNUNET_free (p_string);
1632     }
1633   connect_attempts = 0;
1634   for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
1635     {
1636       for (inner_count = outer_count + 1; inner_count < pg->total;
1637            inner_count++)
1638         {
1639           temp_rand = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
1640                                                          UINT64_MAX)) / ( (double) UINT64_MAX);
1641 #if VERBOSE_TESTING
1642           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1643                       _("rand is %f probability is %f\n"), temp_rand,
1644                       probability);
1645 #endif
1646           if (temp_rand < probability)
1647             {
1648               connect_attempts += proc (pg, outer_count, inner_count);
1649             }
1650         }
1651     }
1652
1653   return connect_attempts;
1654 }
1655
1656 /**
1657  * Create a topology given a peer group (set of running peers)
1658  * and a connection processor.  This particular function creates
1659  * the connections for a 2d-torus, plus additional "closest"
1660  * connections per peer.
1661  *
1662  * @param pg the peergroup to create the topology on
1663  * @param proc the connection processor to call to actually set
1664  *        up connections between two peers
1665  *
1666  * @return the number of connections that were set up
1667  *
1668  */
1669 static unsigned int
1670 create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1671 {
1672   unsigned int i;
1673   unsigned int square;
1674   unsigned int rows;
1675   unsigned int cols;
1676   unsigned int toggle = 1;
1677   unsigned int nodeToConnect;
1678   int connect_attempts;
1679
1680   connect_attempts = 0;
1681
1682   square = floor (sqrt (pg->total));
1683   rows = square;
1684   cols = square;
1685
1686   if (square * square != pg->total)
1687     {
1688       while (rows * cols < pg->total)
1689         {
1690           if (toggle % 2 == 0)
1691             rows++;
1692           else
1693             cols++;
1694
1695           toggle++;
1696         }
1697     }
1698 #if VERBOSE_TESTING
1699       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1700                   _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
1701                   rows, cols);
1702 #endif
1703   /* Rows and columns are all sorted out, now iterate over all nodes and connect each
1704    * to the node to its right and above.  Once this is over, we'll have our torus!
1705    * Special case for the last node (if the rows and columns are not equal), connect
1706    * to the first in the row to maintain topology.
1707    */
1708   for (i = 0; i < pg->total; i++)
1709     {
1710       /* First connect to the node to the right */
1711       if (((i + 1) % cols != 0) && (i + 1 != pg->total))
1712         nodeToConnect = i + 1;
1713       else if (i + 1 == pg->total)
1714         nodeToConnect = rows * cols - cols;
1715       else
1716         nodeToConnect = i - cols + 1;
1717 #if VERBOSE_TESTING
1718           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1719                       "Connecting peer %d to peer %d\n",
1720                       i, nodeToConnect);
1721 #endif
1722       connect_attempts += proc(pg, i, nodeToConnect);
1723
1724       /* Second connect to the node immediately above */
1725       if (i < cols)
1726         nodeToConnect = (rows * cols) - cols + i;
1727       else
1728         nodeToConnect = i - cols;
1729
1730       if (nodeToConnect < pg->total)
1731         {
1732 #if VERBOSE_TESTING
1733           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1734                       "Connecting peer %d to peer %d\n",
1735                       i, nodeToConnect);
1736 #endif
1737           connect_attempts += proc(pg, i, nodeToConnect);
1738         }
1739
1740     }
1741
1742   return connect_attempts;
1743 }
1744
1745
1746 /**
1747  * Create a topology given a peer group (set of running peers)
1748  * and a connection processor.
1749  *
1750  * @param pg the peergroup to create the topology on
1751  * @param proc the connection processor to call to actually set
1752  *        up connections between two peers
1753  *
1754  * @return the number of connections that were set up
1755  *
1756  */
1757 static unsigned int
1758 create_clique (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1759 {
1760   unsigned int outer_count;
1761   unsigned int inner_count;
1762   int connect_attempts;
1763
1764   connect_attempts = 0;
1765
1766   for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
1767     {
1768       for (inner_count = outer_count + 1; inner_count < pg->total;
1769            inner_count++)
1770         {
1771 #if VERBOSE_TESTING
1772           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1773                       "Connecting peer %d to peer %d\n",
1774                       outer_count, inner_count);
1775 #endif
1776           connect_attempts += proc(pg, outer_count, inner_count);
1777         }
1778     }
1779
1780   return connect_attempts;
1781 }
1782
1783 /**
1784  * Create a topology given a peer group (set of running peers)
1785  * and a connection processor.
1786  *
1787  * @param pg the peergroup to create the topology on
1788  * @param proc the connection processor to call to actually set
1789  *        up connections between two peers
1790  *
1791  * @return the number of connections that were set up
1792  *
1793  */
1794 static unsigned int
1795 create_line (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1796 {
1797   unsigned int count;
1798   int connect_attempts;
1799
1800   connect_attempts = 0;
1801
1802   /* Connect each peer to the next highest numbered peer */
1803   for (count = 0; count < pg->total - 1; count++)
1804     {
1805 #if VERBOSE_TESTING
1806           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1807                       "Connecting peer %d to peer %d\n",
1808                       count, count + 1);
1809 #endif
1810       connect_attempts += proc(pg, count, count + 1);
1811     }
1812
1813   return connect_attempts;
1814 }
1815
1816 /**
1817  * Create a topology given a peer group (set of running peers)
1818  * and a connection processor.
1819  *
1820  * @param pg the peergroup to create the topology on
1821  * @param proc the connection processor to call to actually set
1822  *        up connections between two peers
1823  *
1824  * @return the number of connections that were set up
1825  *
1826  */
1827 static unsigned int
1828 create_ring (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1829 {
1830   unsigned int count;
1831   int connect_attempts;
1832
1833   connect_attempts = 0;
1834
1835   /* Connect each peer to the next highest numbered peer */
1836   for (count = 0; count < pg->total - 1; count++)
1837     {
1838 #if VERBOSE_TESTING
1839           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1840                       "Connecting peer %d to peer %d\n",
1841                       count, count + 1);
1842 #endif
1843       connect_attempts += proc(pg, count, count + 1);
1844     }
1845
1846   /* Connect the last peer to the first peer */
1847   connect_attempts += proc(pg, pg->total - 1, 0);
1848
1849   return connect_attempts;
1850 }
1851
1852
1853 /**
1854  * Iterator for writing friends of a peer to a file.
1855  *
1856  * @param cls closure, an open writable file handle
1857  * @param key the key the daemon was stored under
1858  * @param value the GNUNET_TESTING_Daemon that needs to be written.
1859  *
1860  * @return GNUNET_YES to continue iteration
1861  *
1862  * TODO: Could replace friend_file_iterator and blacklist_file_iterator
1863  *       with a single file_iterator that takes a closure which contains
1864  *       the prefix to write before the peer.  Then this could be used
1865  *       for blacklisting multiple transports and writing the friend
1866  *       file.  I'm sure *someone* will complain loudly about other
1867  *       things that negate these functions even existing so no point in
1868  *       "fixing" now.
1869  */
1870 static int
1871 friend_file_iterator (void *cls,
1872                   const GNUNET_HashCode * key,
1873                   void *value)
1874 {
1875   FILE *temp_friend_handle = cls;
1876   struct GNUNET_TESTING_Daemon *peer = value;
1877   struct GNUNET_PeerIdentity *temppeer;
1878   struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
1879
1880   temppeer = &peer->id;
1881   GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
1882   fprintf(temp_friend_handle, "%s\n", (char *)&peer_enc);
1883
1884   return GNUNET_YES;
1885 }
1886
1887 struct BlacklistContext
1888 {
1889   /*
1890    * The (open) file handle to write to
1891    */
1892   FILE *temp_file_handle;
1893
1894   /*
1895    * The transport that this peer will be blacklisted on.
1896    */
1897   char *transport;
1898 };
1899
1900 /**
1901  * Iterator for writing blacklist data to appropriate files.
1902  *
1903  * @param cls closure, an open writable file handle
1904  * @param key the key the daemon was stored under
1905  * @param value the GNUNET_TESTING_Daemon that needs to be written.
1906  *
1907  * @return GNUNET_YES to continue iteration
1908  */
1909 static int
1910 blacklist_file_iterator (void *cls,
1911                          const GNUNET_HashCode * key,
1912                          void *value)
1913 {
1914   struct BlacklistContext *blacklist_ctx = cls;
1915   //FILE *temp_blacklist_handle = cls;
1916   struct GNUNET_TESTING_Daemon *peer = value;
1917   struct GNUNET_PeerIdentity *temppeer;
1918   struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
1919
1920   temppeer = &peer->id;
1921   GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
1922   fprintf(blacklist_ctx->temp_file_handle, "%s:%s\n", blacklist_ctx->transport, (char *)&peer_enc);
1923
1924   return GNUNET_YES;
1925 }
1926
1927 /*
1928  * Create the friend files based on the PeerConnection's
1929  * of each peer in the peer group, and copy the files
1930  * to the appropriate place
1931  *
1932  * @param pg the peer group we are dealing with
1933  */
1934 static int
1935 create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
1936 {
1937   FILE *temp_friend_handle;
1938   unsigned int pg_iter;
1939   char *temp_service_path;
1940   GNUNET_OS_Process **procarr;
1941   char *arg;
1942   char * mytemp;
1943   enum GNUNET_OS_ProcessStatusType type;
1944   unsigned long return_code;
1945   int count;
1946   int ret;
1947   int max_wait = 10;
1948
1949   procarr = GNUNET_malloc(sizeof(GNUNET_OS_Process *) * pg->total);
1950   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1951     {
1952       mytemp = GNUNET_DISK_mktemp("friends");
1953       GNUNET_assert(mytemp != NULL);
1954       temp_friend_handle = fopen (mytemp, "wt");
1955       GNUNET_assert(temp_friend_handle != NULL);
1956       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].allowed_peers, &friend_file_iterator, temp_friend_handle);
1957       fclose(temp_friend_handle);
1958
1959       if (GNUNET_OK !=
1960           GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
1961         {
1962           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1963                       _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
1964                       "SERVICEHOME",
1965                       "PATHS");
1966           if (UNLINK (mytemp) != 0)
1967             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
1968           GNUNET_free (mytemp);
1969           break;
1970         }
1971
1972       if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
1973         {
1974           GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
1975           procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
1976                                          "mv", mytemp, arg, NULL);
1977 #if VERBOSE_TESTING
1978           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1979                       _("Copying file with command cp %s %s\n"), mytemp, arg);
1980 #endif
1981
1982           GNUNET_free(arg);
1983         }
1984       else /* Remote, scp the file to the correct place */
1985         {
1986           if (NULL != pg->peers[pg_iter].daemon->username)
1987             GNUNET_asprintf (&arg, "%s@%s:%s/friends", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
1988           else
1989             GNUNET_asprintf (&arg, "%s:%s/friends", pg->peers[pg_iter].daemon->hostname, temp_service_path);
1990           procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
1991                                          "scp", mytemp, arg, NULL);
1992
1993 #if VERBOSE_TESTING
1994           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1995                       _("Copying file with command scp %s %s\n"), mytemp, arg);
1996 #endif
1997           GNUNET_free(arg);
1998         }
1999       GNUNET_free (temp_service_path);
2000       GNUNET_free (mytemp);
2001     }
2002
2003   count = 0;
2004   ret = GNUNET_SYSERR;
2005   while ((count < max_wait) && (ret != GNUNET_OK))
2006     {
2007       ret = GNUNET_OK;
2008       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2009         {
2010 #if VERBOSE_TESTING
2011           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2012                       _("Checking copy status of file %d\n"), pg_iter);
2013 #endif
2014           if (procarr[pg_iter] != NULL) /* Check for already completed! */
2015             {
2016               if (GNUNET_OS_process_status(procarr[pg_iter], &type, &return_code) != GNUNET_OK)
2017                 {
2018                   ret = GNUNET_SYSERR;
2019                 }
2020               else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
2021                 {
2022                   ret = GNUNET_SYSERR;
2023                 }
2024               else
2025                 {
2026                   GNUNET_OS_process_close (procarr[pg_iter]);
2027                   procarr[pg_iter] = NULL;
2028 #if VERBOSE_TESTING
2029             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2030                       _("File %d copied\n"), pg_iter);
2031 #endif
2032                 }
2033             }
2034         }
2035       count++;
2036       if (ret == GNUNET_SYSERR)
2037         {
2038           /* FIXME: why sleep here? -CG */
2039           sleep(1);
2040         }
2041     }
2042
2043 #if VERBOSE_TESTING
2044     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2045                 _("Finished copying all friend files!\n"));
2046 #endif
2047   GNUNET_free(procarr);
2048   return ret;
2049 }
2050
2051
2052 /*
2053  * Create the blacklist files based on the PeerConnection's
2054  * of each peer in the peer group, and copy the files
2055  * to the appropriate place.
2056  *
2057  * @param pg the peer group we are dealing with
2058  * @param transports space delimited list of transports to blacklist
2059  */
2060 static int
2061 create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg, const char *transports)
2062 {
2063   FILE *temp_file_handle;
2064   static struct BlacklistContext blacklist_ctx;
2065   unsigned int pg_iter;
2066   char *temp_service_path;
2067   GNUNET_OS_Process **procarr;
2068   char *arg;
2069   char *mytemp;
2070   enum GNUNET_OS_ProcessStatusType type;
2071   unsigned long return_code;
2072   int count;
2073   int ret;
2074   int max_wait = 10;
2075   int transport_len;
2076   unsigned int i;
2077   char *pos;
2078   char *temp_transports;
2079
2080   procarr = GNUNET_malloc(sizeof(GNUNET_OS_Process *) * pg->total);
2081   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2082     {
2083       mytemp = GNUNET_DISK_mktemp("blacklist");
2084       GNUNET_assert(mytemp != NULL);
2085       temp_file_handle = fopen (mytemp, "wt");
2086       GNUNET_assert(temp_file_handle != NULL);
2087       temp_transports = GNUNET_strdup(transports);
2088       blacklist_ctx.temp_file_handle = temp_file_handle;
2089       transport_len = strlen(temp_transports) + 1;
2090       pos = NULL;
2091
2092       for (i = 0; i < transport_len; i++)
2093       {
2094         if ((temp_transports[i] == ' ') && (pos == NULL))
2095           continue; /* At start of string (whitespace) */
2096         else if ((temp_transports[i] == ' ') || (temp_transports[i] == '\0')) /* At end of string */
2097         {
2098           temp_transports[i] = '\0';
2099           blacklist_ctx.transport = pos;
2100           GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].blacklisted_peers, &blacklist_file_iterator, &blacklist_ctx);
2101           pos = NULL;
2102         } /* At beginning of actual string */
2103         else if (pos == NULL)
2104         {
2105           pos = &temp_transports[i];
2106         }
2107       }
2108
2109       GNUNET_free (temp_transports);
2110       fclose(temp_file_handle);
2111
2112       if (GNUNET_OK !=
2113           GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
2114         {
2115           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2116                       _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
2117                       "SERVICEHOME",
2118                       "PATHS");
2119           if (UNLINK (mytemp) != 0)
2120             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
2121           GNUNET_free (mytemp);
2122           break;
2123         }
2124
2125       if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
2126         {
2127           GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path);
2128           procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
2129                                          "mv", mytemp, arg, NULL);
2130 #if VERBOSE_TESTING
2131           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2132                       _("Copying file with command cp %s %s\n"), mytemp, arg);
2133 #endif
2134
2135           GNUNET_free(arg);
2136         }
2137       else /* Remote, scp the file to the correct place */
2138         {
2139           if (NULL != pg->peers[pg_iter].daemon->username)
2140             GNUNET_asprintf (&arg, "%s@%s:%s/blacklist", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
2141           else
2142             GNUNET_asprintf (&arg, "%s:%s/blacklist", pg->peers[pg_iter].daemon->hostname, temp_service_path);
2143           procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
2144                                          "scp", mytemp, arg, NULL);
2145
2146 #if VERBOSE_TESTING
2147           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2148                       _("Copying file with command scp %s %s\n"), mytemp, arg);
2149 #endif
2150           GNUNET_free(arg);
2151         }
2152       GNUNET_free (temp_service_path);
2153       GNUNET_free (mytemp);
2154     }
2155
2156   count = 0;
2157   ret = GNUNET_SYSERR;
2158   while ((count < max_wait) && (ret != GNUNET_OK))
2159     {
2160       ret = GNUNET_OK;
2161       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2162         {
2163 #if VERBOSE_TESTING
2164           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2165                       _("Checking copy status of file %d\n"), pg_iter);
2166 #endif
2167           if (procarr[pg_iter] != NULL) /* Check for already completed! */
2168             {
2169               if (GNUNET_OS_process_status(procarr[pg_iter], &type, &return_code) != GNUNET_OK)
2170                 {
2171                   ret = GNUNET_SYSERR;
2172                 }
2173               else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
2174                 {
2175                   ret = GNUNET_SYSERR;
2176                 }
2177               else
2178                 {
2179                   GNUNET_OS_process_close (procarr[pg_iter]);
2180                   procarr[pg_iter] = NULL;
2181 #if VERBOSE_TESTING
2182             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2183                       _("File %d copied\n"), pg_iter);
2184 #endif
2185                 }
2186             }
2187         }
2188       count++;
2189       if (ret == GNUNET_SYSERR)
2190         {
2191           /* FIXME: why sleep here? -CG */
2192           sleep(1);
2193         }
2194     }
2195
2196 #if VERBOSE_TESTING
2197     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2198                 _("Finished copying all blacklist files!\n"));
2199 #endif
2200   GNUNET_free(procarr);
2201   return ret;
2202 }
2203
2204
2205 /**
2206  * Internal notification of a connection, kept so that we can ensure some connections
2207  * happen instead of flooding all testing daemons with requests to connect.
2208  */
2209 static void internal_connect_notify (void *cls,
2210                                      const struct GNUNET_PeerIdentity *first,
2211                                      const struct GNUNET_PeerIdentity *second,
2212                                      uint32_t distance,
2213                                      const struct GNUNET_CONFIGURATION_Handle *first_cfg,
2214                                      const struct GNUNET_CONFIGURATION_Handle *second_cfg,
2215                                      struct GNUNET_TESTING_Daemon *first_daemon,
2216                                      struct GNUNET_TESTING_Daemon *second_daemon,
2217                                      const char *emsg)
2218 {
2219   struct ConnectTopologyContext *ct_ctx = cls;
2220   struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg;
2221   outstanding_connects--;
2222   ct_ctx->remaining_connections--;
2223   if (ct_ctx->remaining_connections == 0)
2224     {
2225       if (ct_ctx->notify_connections_done != NULL)
2226         ct_ctx->notify_connections_done(ct_ctx->notify_cls, NULL);
2227       GNUNET_free(ct_ctx);
2228     }
2229
2230   if (pg->notify_connection != NULL)
2231     pg->notify_connection (pg->notify_connection_cls, first, second, distance, first_cfg, second_cfg, first_daemon, second_daemon, emsg);
2232 }
2233
2234
2235 /**
2236  * Either delay a connection (because there are too many outstanding)
2237  * or schedule it for right now.
2238  *
2239  * @param cls a connection context
2240  * @param tc the task runtime context
2241  */
2242 static void schedule_connect(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2243 {
2244   struct ConnectContext *connect_context = cls;
2245
2246   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2247     return;
2248
2249   if (outstanding_connects > MAX_OUTSTANDING_CONNECTIONS)
2250     {
2251 #if VERBOSE_TESTING > 2
2252           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2253                       _("Delaying connect, we have too many outstanding connections!\n"));
2254 #endif
2255       GNUNET_SCHEDULER_add_delayed(connect_context->ct_ctx->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_connect, connect_context);
2256     }
2257   else
2258     {
2259 #if VERBOSE_TESTING > 2
2260           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2261                       _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
2262 #endif
2263       outstanding_connects++;
2264       GNUNET_TESTING_daemons_connect (connect_context->first,
2265                                       connect_context->second,
2266                                       CONNECT_TIMEOUT,
2267                                       CONNECT_ATTEMPTS,
2268                                       &internal_connect_notify,
2269                                       connect_context->ct_ctx);
2270       GNUNET_free(connect_context);
2271     }
2272 }
2273
2274
2275 /**
2276  * Iterator for actually scheduling connections to be created
2277  * between two peers.
2278  *
2279  * @param cls closure, a GNUNET_TESTING_Daemon
2280  * @param key the key the second Daemon was stored under
2281  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2282  *
2283  * @return GNUNET_YES to continue iteration
2284  */
2285 static int
2286 connect_iterator (void *cls,
2287                   const GNUNET_HashCode * key,
2288                   void *value)
2289 {
2290   struct ConnectTopologyContext *ct_ctx = cls;
2291   struct PeerData *first = ct_ctx->first;
2292   struct GNUNET_TESTING_Daemon *second = value;
2293   struct ConnectContext *connect_context;
2294
2295   connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
2296   connect_context->first = first->daemon;
2297   connect_context->second = second;
2298   connect_context->ct_ctx = ct_ctx;
2299   GNUNET_SCHEDULER_add_now(first->pg->sched, &schedule_connect, connect_context);
2300
2301   return GNUNET_YES;
2302 }
2303
2304
2305 /**
2306  * Iterator for copying all entries in the allowed hashmap to the
2307  * connect hashmap.
2308  *
2309  * @param cls closure, a GNUNET_TESTING_Daemon
2310  * @param key the key the second Daemon was stored under
2311  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2312  *
2313  * @return GNUNET_YES to continue iteration
2314  */
2315 static int
2316 copy_topology_iterator (void *cls,
2317                   const GNUNET_HashCode * key,
2318                   void *value)
2319 {
2320   struct PeerData *first = cls;
2321
2322   GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(first->connect_peers, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2323
2324   return GNUNET_YES;
2325 }
2326
2327 /**
2328  * Make the peers to connect the same as those that are allowed to be
2329  * connected.
2330  *
2331  * @param pg the peer group
2332  */
2333 static int
2334 copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg)
2335 {
2336   unsigned int pg_iter;
2337   int ret;
2338   int total;
2339
2340   total = 0;
2341   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2342     {
2343       ret = GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].allowed_peers, &copy_topology_iterator, &pg->peers[pg_iter]);
2344       if (GNUNET_SYSERR == ret)
2345         return GNUNET_SYSERR;
2346
2347       total = total + ret;
2348     }
2349
2350   return total;
2351 }
2352
2353
2354 /**
2355  * Connect the topology as specified by the PeerConnection's
2356  * of each peer in the peer group
2357  *
2358  * @param pg the peer group we are dealing with
2359  * @return the number of connections that will be attempted
2360  */
2361 static int
2362 connect_topology (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyCompletion notify_callback, void *notify_cls)
2363 {
2364   unsigned int pg_iter;
2365   int ret;
2366   unsigned int total;
2367   struct ConnectTopologyContext *ct_ctx;
2368 #if OLD
2369   struct PeerConnection *connection_iter;
2370   struct ConnectContext *connect_context;
2371 #endif
2372
2373   total = 0;
2374   ct_ctx = GNUNET_malloc(sizeof(struct ConnectTopologyContext));
2375   ct_ctx->notify_connections_done = notify_callback;
2376   ct_ctx->notify_cls = notify_cls;
2377   ct_ctx->pg = pg;
2378
2379   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2380     {
2381       total += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers);
2382     }
2383
2384   if (total == 0)
2385     {
2386       GNUNET_free(ct_ctx);
2387       return total;
2388     }
2389   ct_ctx->remaining_connections = total;
2390   total = 0;
2391
2392   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2393     {
2394       ct_ctx->first = &pg->peers[pg_iter];
2395       ret = GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &connect_iterator, ct_ctx);
2396       GNUNET_assert(GNUNET_SYSERR != ret && ret >= 0);
2397       total = total + ret;
2398
2399 #if OLD
2400       connection_iter = FIXME;
2401       while (connection_iter != NULL)
2402         {
2403           connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
2404           connect_context->pg = pg;
2405           connect_context->first = FIXME;
2406           connect_context->second = connection_iter->daemon;
2407           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_connect, connect_context);
2408           connection_iter = connection_iter->next;
2409         }
2410 #endif
2411     }
2412   return total;
2413 }
2414
2415
2416 /**
2417  * Takes a peer group and creates a topology based on the
2418  * one specified.  Creates a topology means generates friend
2419  * files for the peers so they can only connect to those allowed
2420  * by the topology.  This will only have an effect once peers
2421  * are started if the FRIENDS_ONLY option is set in the base
2422  * config.  Also takes an optional restrict topology which
2423  * disallows connections based on a particular transport
2424  * UNLESS they are specified in the restricted topology.
2425  *
2426  * @param pg the peer group struct representing the running peers
2427  * @param topology which topology to connect the peers in
2428  * @param restrict_topology allow only direct TCP connections in this topology
2429  *                          use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions
2430  * @param restrict_transports space delimited list of transports to blacklist
2431  *                            to create restricted topology
2432  *
2433  * @return the maximum number of connections were all allowed peers
2434  *         connected to each other
2435  */
2436 unsigned int
2437 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg,
2438                                 enum GNUNET_TESTING_Topology topology,
2439                                 enum GNUNET_TESTING_Topology restrict_topology,
2440                                 const char *restrict_transports)
2441 {
2442   int ret;
2443   unsigned int num_connections;
2444   int unblacklisted_connections;
2445
2446   switch (topology)
2447     {
2448     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2449 #if VERBOSE_TESTING
2450       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2451                   _("Creating clique topology\n"));
2452 #endif
2453       num_connections = create_clique (pg, &add_allowed_connections);
2454       break;
2455     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2456 #if VERBOSE_TESTING
2457       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2458                   _("Creating small world (ring) topology\n"));
2459 #endif
2460       num_connections = create_small_world_ring (pg, &add_allowed_connections);
2461       break;
2462     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2463 #if VERBOSE_TESTING
2464       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2465                   _("Creating small world (2d-torus) topology\n"));
2466 #endif
2467       num_connections = create_small_world (pg, &add_allowed_connections);
2468       break;
2469     case GNUNET_TESTING_TOPOLOGY_RING:
2470 #if VERBOSE_TESTING
2471       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2472                   _("Creating ring topology\n"));
2473 #endif
2474       num_connections = create_ring (pg, &add_allowed_connections);
2475       break;
2476     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2477 #if VERBOSE_TESTING
2478       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2479                   _("Creating 2d torus topology\n"));
2480 #endif
2481       num_connections = create_2d_torus (pg, &add_allowed_connections);
2482       break;
2483     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2484 #if VERBOSE_TESTING
2485       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2486                   _("Creating Erdos-Renyi topology\n"));
2487 #endif
2488       num_connections = create_erdos_renyi (pg, &add_allowed_connections);
2489       break;
2490     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2491 #if VERBOSE_TESTING
2492       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2493                   _("Creating InterNAT topology\n"));
2494 #endif
2495       num_connections = create_nated_internet (pg, &add_allowed_connections);
2496       break;
2497     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2498 #if VERBOSE_TESTING
2499       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2500                   _("Creating Scale Free topology\n"));
2501 #endif
2502       num_connections = create_scale_free (pg, &add_allowed_connections);
2503       break;
2504     case GNUNET_TESTING_TOPOLOGY_LINE:
2505 #if VERBOSE_TESTING
2506       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2507                   _("Creating straight line topology\n"));
2508 #endif
2509       num_connections = create_line (pg, &add_allowed_connections);
2510       break;
2511     case GNUNET_TESTING_TOPOLOGY_NONE:
2512 #if VERBOSE_TESTING
2513       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2514                   _("Creating no allowed topology (all peers can connect at core level)\n"));
2515 #endif
2516       num_connections = 0;
2517       break;
2518     default:
2519       num_connections = 0;
2520       break;
2521     }
2522
2523   if (num_connections < 0)
2524     return GNUNET_SYSERR;
2525
2526   if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
2527     {
2528       ret = create_and_copy_friend_files(pg);
2529       if (ret != GNUNET_OK)
2530         {
2531 #if VERBOSE_TESTING
2532           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2533                       _("Failed during friend file copying!\n"));
2534 #endif
2535           return GNUNET_SYSERR;
2536         }
2537       else
2538         {
2539 #if VERBOSE_TESTING
2540               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2541                           _("Friend files created/copied successfully!\n"));
2542 #endif
2543         }
2544     }
2545
2546   /* Use the create clique method to initially set all connections as blacklisted. */
2547   if (restrict_topology != GNUNET_TESTING_TOPOLOGY_NONE)
2548     create_clique (pg, &blacklist_connections);
2549
2550   unblacklisted_connections = 0;
2551   /* Un-blacklist connections as per the topology specified */
2552   switch (restrict_topology)
2553     {
2554     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2555 #if VERBOSE_TESTING
2556       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2557                   _("Blacklisting all but clique topology\n"));
2558 #endif
2559       unblacklisted_connections = create_clique (pg, &unblacklist_connections);
2560       break;
2561     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2562 #if VERBOSE_TESTING
2563       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2564                   _("Blacklisting all but small world (ring) topology\n"));
2565 #endif
2566       unblacklisted_connections = create_small_world_ring (pg, &unblacklist_connections);
2567       break;
2568     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2569 #if VERBOSE_TESTING
2570       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2571                   _("Blacklisting all but small world (2d-torus) topology\n"));
2572 #endif
2573       unblacklisted_connections = create_small_world (pg, &unblacklist_connections);
2574       break;
2575     case GNUNET_TESTING_TOPOLOGY_RING:
2576 #if VERBOSE_TESTING
2577       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2578                   _("Blacklisting all but ring topology\n"));
2579 #endif
2580       unblacklisted_connections = create_ring (pg, &unblacklist_connections);
2581       break;
2582     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2583 #if VERBOSE_TESTING
2584       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2585                   _("Blacklisting all but 2d torus topology\n"));
2586 #endif
2587       unblacklisted_connections = create_2d_torus (pg, &unblacklist_connections);
2588       break;
2589     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2590 #if VERBOSE_TESTING
2591       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2592                   _("Blacklisting all but Erdos-Renyi topology\n"));
2593 #endif
2594       unblacklisted_connections = create_erdos_renyi (pg, &unblacklist_connections);
2595       break;
2596     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2597 #if VERBOSE_TESTING
2598       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2599                   _("Blacklisting all but InterNAT topology\n"));
2600 #endif
2601       unblacklisted_connections = create_nated_internet (pg, &unblacklist_connections);
2602       break;
2603     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2604 #if VERBOSE_TESTING
2605       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2606                   _("Blacklisting all but Scale Free topology\n"));
2607 #endif
2608       unblacklisted_connections = create_scale_free (pg, &unblacklist_connections);
2609       break;
2610     case GNUNET_TESTING_TOPOLOGY_LINE:
2611 #if VERBOSE_TESTING
2612       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2613                   _("Blacklisting all but straight line topology\n"));
2614 #endif
2615       unblacklisted_connections = create_line (pg, &unblacklist_connections);
2616       break;
2617     case GNUNET_TESTING_TOPOLOGY_NONE:
2618 #if VERBOSE_TESTING
2619       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2620                   _("Creating no blacklist topology (all peers can connect at transport level)\n"));
2621 #endif
2622     default:
2623       break;
2624     }
2625
2626   if ((unblacklisted_connections > 0) && (restrict_transports != NULL))
2627   {
2628     ret = create_and_copy_blacklist_files(pg, restrict_transports);
2629     if (ret != GNUNET_OK)
2630       {
2631 #if VERBOSE_TESTING
2632         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2633                     _("Failed during blacklist file copying!\n"));
2634 #endif
2635         return 0;
2636       }
2637     else
2638       {
2639 #if VERBOSE_TESTING
2640         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2641                     _("Blacklist files created/copied successfully!\n"));
2642 #endif
2643       }
2644   }
2645   return num_connections;
2646 }
2647
2648 struct RandomContext
2649 {
2650   /**
2651    * The peergroup
2652    */
2653   struct GNUNET_TESTING_PeerGroup *pg;
2654
2655   /**
2656    * uid of the first peer
2657    */
2658   uint32_t first_uid;
2659
2660   /**
2661    * Peer data for first peer.
2662    */
2663   struct PeerData *first;
2664
2665   /**
2666    * Random percentage to use
2667    */
2668   double percentage;
2669 };
2670
2671 struct MinimumContext
2672 {
2673   /**
2674    * The peergroup
2675    */
2676   struct GNUNET_TESTING_PeerGroup *pg;
2677
2678   /**
2679    * uid of the first peer
2680    */
2681   uint32_t first_uid;
2682
2683   /**
2684    * Peer data for first peer.
2685    */
2686   struct PeerData *first;
2687
2688   /**
2689    * Number of conns per peer
2690    */
2691   unsigned int num_to_add;
2692
2693   /**
2694    * Permuted array of all possible connections.  Only add the Nth
2695    * peer if it's in the Nth position.
2696    */
2697   unsigned int *pg_array;
2698
2699   /**
2700    * What number is the current element we are iterating over?
2701    */
2702   unsigned int current;
2703 };
2704
2705 struct DFSContext
2706 {
2707   /**
2708    * The peergroup
2709    */
2710   struct GNUNET_TESTING_PeerGroup *pg;
2711
2712   /**
2713    * uid of the first peer
2714    */
2715   uint32_t first_uid;
2716
2717   /**
2718    * uid of the second peer
2719    */
2720   uint32_t second_uid;
2721
2722   /**
2723    * Peer data for first peer.
2724    */
2725   struct PeerData *first;
2726
2727   /**
2728    * Which peer has been chosen as the one to add?
2729    */
2730   unsigned int chosen;
2731
2732   /**
2733    * What number is the current element we are iterating over?
2734    */
2735   unsigned int current;
2736 };
2737
2738 /**
2739  * Iterator for choosing random peers to connect.
2740  *
2741  * @param cls closure, a RandomContext
2742  * @param key the key the second Daemon was stored under
2743  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2744  *
2745  * @return GNUNET_YES to continue iteration
2746  */
2747 static int
2748 random_connect_iterator (void *cls,
2749                          const GNUNET_HashCode * key,
2750                          void *value)
2751 {
2752   struct RandomContext *random_ctx = cls;
2753   double random_number;
2754   uint32_t second_pos;
2755   GNUNET_HashCode first_hash;
2756   random_number = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
2757                                                      UINT64_MAX)) / ( (double) UINT64_MAX);
2758   if (random_number < random_ctx->percentage)
2759   {
2760     GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(random_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2761   }
2762   /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */
2763   uid_from_hash(key, &second_pos);
2764   hash_from_uid(random_ctx->first_uid, &first_hash);
2765   GNUNET_assert(random_ctx->pg->total > second_pos);
2766   GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(random_ctx->pg->peers[second_pos].connect_peers, &first_hash, random_ctx->first->daemon));
2767
2768   return GNUNET_YES;
2769 }
2770
2771 /**
2772  * Iterator for adding at least X peers to a peers connection set.
2773  *
2774  * @param cls closure, MinimumContext
2775  * @param key the key the second Daemon was stored under
2776  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2777  *
2778  * @return GNUNET_YES to continue iteration
2779  */
2780 static int
2781 minimum_connect_iterator (void *cls,
2782                   const GNUNET_HashCode * key,
2783                   void *value)
2784 {
2785   struct MinimumContext *min_ctx = cls;
2786   uint32_t second_pos;
2787   GNUNET_HashCode first_hash;
2788   unsigned int i;
2789
2790   if (GNUNET_CONTAINER_multihashmap_size(min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add)
2791   {
2792     for (i = 0; i < min_ctx->num_to_add; i++)
2793     {
2794       if (min_ctx->pg_array[i] == min_ctx->current)
2795       {
2796         GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(min_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2797         uid_from_hash(key, &second_pos);
2798         hash_from_uid(min_ctx->first_uid, &first_hash);
2799         GNUNET_assert(min_ctx->pg->total > second_pos);
2800         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));
2801         /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */
2802         GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(min_ctx->pg->peers[second_pos].connect_peers, &first_hash, min_ctx->first->daemon));
2803       }
2804     }
2805     min_ctx->current++;
2806     return GNUNET_YES;
2807   }
2808   else
2809     return GNUNET_NO; /* We can stop iterating, we have enough peers! */
2810
2811 }
2812
2813
2814 /**
2815  * Iterator for adding peers to a connection set based on a depth first search.
2816  *
2817  * @param cls closure, MinimumContext
2818  * @param key the key the second daemon was stored under
2819  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2820  *
2821  * @return GNUNET_YES to continue iteration
2822  */
2823 static int
2824 dfs_connect_iterator (void *cls,
2825                   const GNUNET_HashCode * key,
2826                   void *value)
2827 {
2828   struct DFSContext *dfs_ctx = cls;
2829   GNUNET_HashCode first_hash;
2830
2831   if (dfs_ctx->current == dfs_ctx->chosen)
2832     {
2833       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(dfs_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2834       uid_from_hash(key, &dfs_ctx->second_uid);
2835       hash_from_uid(dfs_ctx->first_uid, &first_hash);
2836       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));
2837       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(dfs_ctx->pg->peers[dfs_ctx->second_uid].connect_peers, &first_hash, dfs_ctx->first->daemon));
2838       /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */
2839       return GNUNET_NO; /* We have found our peer, don't iterate more */
2840     }
2841
2842   dfs_ctx->current++;
2843   return GNUNET_YES;
2844 }
2845
2846
2847 /**
2848  * From the set of connections possible, choose percentage percent of connections
2849  * to actually connect.
2850  *
2851  * @param pg the peergroup we are dealing with
2852  * @param percentage what percent of total connections to make
2853  */
2854 void
2855 choose_random_connections(struct GNUNET_TESTING_PeerGroup *pg, double percentage)
2856 {
2857   struct RandomContext random_ctx;
2858   uint32_t pg_iter;
2859
2860   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2861     {
2862       random_ctx.first_uid = pg_iter;
2863       random_ctx.first = &pg->peers[pg_iter];
2864       random_ctx.percentage = percentage;
2865       random_ctx.pg = pg;
2866       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(pg->total);
2867       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &random_connect_iterator, &random_ctx);
2868       /* Now remove the old connections */
2869       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2870       /* And replace with the random set */
2871       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2872     }
2873 }
2874
2875 /**
2876  * From the set of connections possible, choose at least num connections per
2877  * peer.
2878  *
2879  * @param pg the peergroup we are dealing with
2880  * @param num how many connections at least should each peer have (if possible)?
2881  */
2882 static void
2883 choose_minimum(struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2884 {
2885   struct MinimumContext minimum_ctx;
2886   uint32_t pg_iter;
2887
2888   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2889    {
2890      pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2891    }
2892
2893   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2894     {
2895       minimum_ctx.first_uid = pg_iter;
2896       minimum_ctx.pg_array = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, 
2897                                                           GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2898       minimum_ctx.first = &pg->peers[pg_iter];
2899       minimum_ctx.pg = pg;
2900       minimum_ctx.num_to_add = num;
2901       minimum_ctx.current = 0;
2902       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers,
2903                                             &minimum_connect_iterator, 
2904                                             &minimum_ctx);
2905     }
2906
2907   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2908     {
2909       /* Remove the "old" connections */
2910       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2911       /* And replace with the working set */
2912       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2913     }
2914
2915 }
2916
2917
2918 static unsigned int
2919 count_workingset_connections(struct GNUNET_TESTING_PeerGroup *pg)
2920 {
2921   unsigned int count;
2922   unsigned int pg_iter;
2923
2924   count = 0;
2925
2926   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2927     {
2928       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2929     }
2930
2931   return count;
2932 }
2933
2934
2935 static unsigned int count_allowed_connections(struct GNUNET_TESTING_PeerGroup *pg)
2936 {
2937   unsigned int count;
2938   unsigned int pg_iter;
2939
2940   count = 0;
2941
2942   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2943     {
2944       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers);
2945     }
2946
2947   return count;
2948 }
2949
2950
2951 struct FindClosestContext
2952 {
2953   /**
2954    * The currently known closest peer.
2955    */
2956   struct GNUNET_TESTING_Daemon *closest;
2957
2958   /**
2959    * The info for the peer we are adding connections for.
2960    */
2961   struct PeerData *curr_peer;
2962
2963   /**
2964    * The distance (bits) between the current
2965    * peer and the currently known closest.
2966    */
2967   unsigned int closest_dist;
2968
2969   /**
2970    * The offset of the closest known peer in
2971    * the peer group.
2972    */
2973   unsigned int closest_num;
2974 };
2975
2976 /**
2977  * Iterator over hash map entries of the allowed
2978  * peer connections.  Find the closest, not already
2979  * connected peer and return it.
2980  *
2981  * @param cls closure (struct FindClosestContext)
2982  * @param key current key code (hash of offset in pg)
2983  * @param value value in the hash map - a GNUNET_TESTING_Daemon
2984  * @return GNUNET_YES if we should continue to
2985  *         iterate,
2986  *         GNUNET_NO if not.
2987  */
2988 static
2989 int find_closest_peers (void *cls, const GNUNET_HashCode * key, void *value)
2990 {
2991   struct FindClosestContext *closest_ctx = cls;
2992   struct GNUNET_TESTING_Daemon *daemon = value;
2993
2994   if (((closest_ctx->closest == NULL) ||
2995        (GNUNET_CRYPTO_hash_matching_bits(&daemon->id.hashPubKey, &closest_ctx->curr_peer->daemon->id.hashPubKey) > closest_ctx->closest_dist))
2996       && (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains(closest_ctx->curr_peer->connect_peers, key)))
2997     {
2998       closest_ctx->closest_dist = GNUNET_CRYPTO_hash_matching_bits(&daemon->id.hashPubKey, &closest_ctx->curr_peer->daemon->id.hashPubKey);
2999       closest_ctx->closest = daemon;
3000       uid_from_hash(key, &closest_ctx->closest_num);
3001     }
3002   return GNUNET_YES;
3003 }
3004
3005 /**
3006  * From the set of connections possible, choose at num connections per
3007  * peer based on depth which are closest out of those allowed.  Guaranteed
3008  * to add num peers to connect to, provided there are that many peers
3009  * in the underlay topology to connect to.
3010  *
3011  * @param pg the peergroup we are dealing with
3012  * @param num how many connections at least should each peer have (if possible)?
3013  * @param proc processor to actually add the connections
3014  */
3015 void
3016 add_closest (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num, GNUNET_TESTING_ConnectionProcessor proc)
3017 {
3018   struct FindClosestContext closest_ctx;
3019   uint32_t pg_iter;
3020   uint32_t i;
3021
3022   for (i = 0; i < num; i++) /* Each time find a closest peer (from those available) */
3023     {
3024       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3025         {
3026           closest_ctx.curr_peer = &pg->peers[pg_iter];
3027           closest_ctx.closest = NULL;
3028           closest_ctx.closest_dist = 0;
3029           closest_ctx.closest_num = 0;
3030           GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].allowed_peers, &find_closest_peers, &closest_ctx);
3031           if (closest_ctx.closest != NULL)
3032             {
3033               GNUNET_assert((0 <= closest_ctx.closest_num) && (closest_ctx.closest_num < pg->total));
3034               proc(pg, pg_iter, closest_ctx.closest_num);
3035             }
3036         }
3037     }
3038 }
3039
3040 /**
3041  * From the set of connections possible, choose at least num connections per
3042  * peer based on depth first traversal of peer connections.  If DFS leaves
3043  * peers unconnected, ensure those peers get connections.
3044  *
3045  * @param pg the peergroup we are dealing with
3046  * @param num how many connections at least should each peer have (if possible)?
3047  */
3048 void
3049 perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
3050 {
3051   struct DFSContext dfs_ctx;
3052   uint32_t pg_iter;
3053   uint32_t dfs_count;
3054   uint32_t starting_peer;
3055   uint32_t least_connections;
3056   GNUNET_HashCode second_hash;
3057
3058   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3059     {
3060       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
3061     }
3062
3063   starting_peer = 0;
3064   dfs_count = 0;
3065   while ((count_workingset_connections(pg) < num * pg->total) && (count_allowed_connections(pg) > 0))
3066     {
3067       if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */
3068         {
3069           least_connections = -1; /* Set to very high number */
3070           for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3071             {
3072               if (GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set) < least_connections)
3073                 {
3074                   starting_peer = pg_iter;
3075                   least_connections = GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
3076                 }
3077             }
3078         }
3079
3080       if (GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers) == 0)  /* Ensure there is at least one peer left to connect! */
3081         {
3082           dfs_count = 0;
3083           continue;
3084         }
3085
3086       /* Choose a random peer from the chosen peers set of connections to add */
3087       dfs_ctx.chosen = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers));
3088       dfs_ctx.first_uid = starting_peer;
3089       dfs_ctx.first = &pg->peers[starting_peer];
3090       dfs_ctx.pg = pg;
3091       dfs_ctx.current = 0;
3092
3093       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[starting_peer].connect_peers, &dfs_connect_iterator, &dfs_ctx);
3094       /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */
3095       hash_from_uid(dfs_ctx.second_uid, &second_hash);
3096       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[starting_peer].connect_peers, &second_hash, pg->peers[dfs_ctx.second_uid].daemon));
3097       starting_peer = dfs_ctx.second_uid;
3098     }
3099
3100   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3101     {
3102       /* Remove the "old" connections */
3103       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
3104       /* And replace with the working set */
3105       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
3106     }
3107 }
3108
3109 /**
3110  * Internal callback for topology information for a particular peer.
3111  */
3112 static void
3113 internal_topology_callback(void *cls,
3114                            const struct GNUNET_PeerIdentity *peer,
3115                            struct GNUNET_TIME_Relative latency, uint32_t distance)
3116 {
3117   struct CoreContext *core_ctx = cls;
3118   struct TopologyIterateContext *iter_ctx = core_ctx->iter_context;
3119
3120   if (peer == NULL) /* Either finished, or something went wrong */
3121     {
3122       iter_ctx->completed++;
3123       iter_ctx->connected--;
3124       /* One core context allocated per iteration, must free! */
3125       GNUNET_free(core_ctx);
3126     }
3127   else
3128     {
3129       iter_ctx->topology_cb(iter_ctx->cls, &core_ctx->daemon->id, peer, latency, distance, NULL);
3130     }
3131
3132   if (iter_ctx->completed == iter_ctx->total)
3133     {
3134       iter_ctx->topology_cb(iter_ctx->cls, NULL, NULL, GNUNET_TIME_relative_get_zero(), 0, NULL);
3135       /* Once all are done, free the iteration context */
3136       GNUNET_free(iter_ctx);
3137     }
3138 }
3139
3140
3141 /**
3142  * Check running topology iteration tasks, if below max start a new one, otherwise
3143  * schedule for some time in the future.
3144  */
3145 static void
3146 schedule_get_topology(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3147 {
3148   struct CoreContext *core_context = cls;
3149   struct TopologyIterateContext *topology_context = (struct TopologyIterateContext *)core_context->iter_context;
3150   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3151     return;
3152
3153   if (topology_context->connected > MAX_OUTSTANDING_CONNECTIONS)
3154     {
3155 #if VERBOSE_TESTING > 2
3156           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3157                       _("Delaying connect, we have too many outstanding connections!\n"));
3158 #endif
3159       GNUNET_SCHEDULER_add_delayed(core_context->daemon->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_get_topology, core_context);
3160     }
3161   else
3162     {
3163 #if VERBOSE_TESTING > 2
3164           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3165                       _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
3166 #endif
3167       topology_context->connected++;
3168       if (GNUNET_OK != GNUNET_CORE_iterate_peers (core_context->daemon->sched, core_context->daemon->cfg, &internal_topology_callback, core_context))
3169         internal_topology_callback(core_context, NULL, GNUNET_TIME_relative_get_zero(), 0);
3170
3171     }
3172 }
3173
3174 /**
3175  * Iterate over all (running) peers in the peer group, retrieve
3176  * all connections that each currently has.
3177  */
3178 void
3179 GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyTopology cb, void *cls)
3180 {
3181   struct TopologyIterateContext *topology_context;
3182   struct CoreContext *core_ctx;
3183   unsigned int i;
3184   unsigned int total_count;
3185
3186   /* Allocate a single topology iteration context */
3187   topology_context = GNUNET_malloc(sizeof(struct TopologyIterateContext));
3188   topology_context->topology_cb = cb;
3189   topology_context->cls = cls;
3190   total_count = 0;
3191   for (i = 0; i < pg->total; i++)
3192     {
3193       if (pg->peers[i].daemon->running == GNUNET_YES)
3194         {
3195           /* Allocate one core context per core we need to connect to */
3196           core_ctx = GNUNET_malloc(sizeof(struct CoreContext));
3197           core_ctx->daemon = pg->peers[i].daemon;
3198           /* Set back pointer to topology iteration context */
3199           core_ctx->iter_context = topology_context;
3200           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_get_topology, core_ctx);
3201           total_count++;
3202         }
3203     }
3204   topology_context->total = total_count;
3205   return;
3206 }
3207
3208 /**
3209  * Callback function to process statistic values.
3210  * This handler is here only really to insert a peer
3211  * identity (or daemon) so the statistics can be uniquely
3212  * tied to a single running peer.
3213  *
3214  * @param cls closure
3215  * @param subsystem name of subsystem that created the statistic
3216  * @param name the name of the datum
3217  * @param value the current value
3218  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
3219  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
3220  */
3221 static int internal_stats_callback (void *cls,
3222                                     const char *subsystem,
3223                                     const char *name,
3224                                     uint64_t value,
3225                                     int is_persistent)
3226 {
3227   struct StatsCoreContext *core_context = cls;
3228   struct StatsIterateContext *stats_context = (struct StatsIterateContext *)core_context->iter_context;
3229
3230   return stats_context->proc(stats_context->cls, &core_context->daemon->id, subsystem, name, value, is_persistent);
3231 }
3232
3233 /**
3234  * Internal continuation call for statistics iteration.
3235  *
3236  * @param cls closure, the CoreContext for this iteration
3237  * @param success whether or not the statistics iterations
3238  *        was canceled or not (we don't care)
3239  */
3240 static void internal_stats_cont (void *cls, int success)
3241 {
3242   struct StatsCoreContext *core_context = cls;
3243   struct StatsIterateContext *stats_context = (struct StatsIterateContext *)core_context->iter_context;
3244
3245   stats_context->connected--;
3246   stats_context->completed++;
3247
3248   if (stats_context->completed == stats_context->total)
3249     {
3250       stats_context->cont(stats_context->cls, GNUNET_YES);
3251       GNUNET_free(stats_context);
3252     }
3253
3254   if (core_context->stats_handle != NULL)
3255     GNUNET_STATISTICS_destroy(core_context->stats_handle, GNUNET_NO);
3256
3257   GNUNET_free(core_context);
3258 }
3259
3260 /**
3261  * Check running topology iteration tasks, if below max start a new one, otherwise
3262  * schedule for some time in the future.
3263  */
3264 static void
3265 schedule_get_statistics(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3266 {
3267   struct StatsCoreContext *core_context = cls;
3268   struct StatsIterateContext *stats_context = (struct StatsIterateContext *)core_context->iter_context;
3269
3270   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3271     return;
3272
3273   if (stats_context->connected > MAX_OUTSTANDING_CONNECTIONS)
3274     {
3275 #if VERBOSE_TESTING > 2
3276           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3277                       _("Delaying connect, we have too many outstanding connections!\n"));
3278 #endif
3279       GNUNET_SCHEDULER_add_delayed(core_context->daemon->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_get_statistics, core_context);
3280     }
3281   else
3282     {
3283 #if VERBOSE_TESTING > 2
3284           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3285                       _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
3286 #endif
3287
3288       stats_context->connected++;
3289       core_context->stats_handle = GNUNET_STATISTICS_create(core_context->daemon->sched, "testing", core_context->daemon->cfg);
3290       if (core_context->stats_handle == NULL)
3291         {
3292           internal_stats_cont (core_context, GNUNET_NO);
3293           return;
3294         }
3295
3296       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);
3297       if (core_context->stats_get_handle == NULL)
3298         internal_stats_cont (core_context, GNUNET_NO);
3299
3300     }
3301 }
3302
3303 struct DuplicateStats
3304 {
3305   /**
3306    * Next item in the list
3307    */
3308   struct DuplicateStats *next;
3309
3310   /**
3311    * Nasty string, concatenation of relevant information.
3312    */
3313   char *unique_string;
3314 };
3315
3316 /**
3317  * Check whether the combination of port/host/unix domain socket
3318  * already exists in the list of peers being checked for statistics.
3319  *
3320  * @param pg the peergroup in question
3321  * @param specific_peer the peer we're concerned with
3322  * @param stats_list the list to return to the caller
3323  *
3324  * @return GNUNET_YES if the statistics instance has been seen already,
3325  *         GNUNET_NO if not (and we may have added it to the list)
3326  */
3327 static int
3328 stats_check_existing(struct GNUNET_TESTING_PeerGroup *pg, struct PeerData *specific_peer, struct DuplicateStats **stats_list)
3329 {
3330   struct DuplicateStats *pos;
3331   char *unix_domain_socket;
3332   unsigned long long port;
3333   char *to_match;
3334   if (GNUNET_YES != GNUNET_CONFIGURATION_get_value_yesno(pg->cfg, "testing", "single_statistics_per_host"))
3335     return GNUNET_NO; /* Each peer has its own statistics instance, do nothing! */
3336
3337   pos = *stats_list;
3338   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string(specific_peer->cfg, "statistics", "unixpath", &unix_domain_socket))
3339     return GNUNET_NO;
3340
3341   GNUNET_CONFIGURATION_get_value_number(specific_peer->cfg, "statistics", "port", &port);
3342
3343   if (specific_peer->daemon->hostname != NULL)
3344     GNUNET_asprintf(&to_match, "%s%s%llu", specific_peer->daemon->hostname, unix_domain_socket, port);
3345   else
3346     GNUNET_asprintf(&to_match, "%s%llu", unix_domain_socket, port);
3347
3348   while (pos != NULL)
3349     {
3350       if (0 == strcmp(to_match, pos->unique_string))
3351         {
3352           GNUNET_free(to_match);
3353           return GNUNET_YES;
3354         }
3355       pos = pos->next;
3356     }
3357   pos = GNUNET_malloc(sizeof(struct DuplicateStats));
3358   pos->unique_string = to_match;
3359   pos->next = *stats_list;
3360   *stats_list = pos;
3361   return GNUNET_NO;
3362 }
3363
3364 /**
3365  * Iterate over all (running) peers in the peer group, retrieve
3366  * all statistics from each.
3367  */
3368 void
3369 GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg,
3370                                GNUNET_STATISTICS_Callback cont,
3371                                GNUNET_TESTING_STATISTICS_Iterator proc, void *cls)
3372 {
3373   struct StatsIterateContext *stats_context;
3374   struct StatsCoreContext *core_ctx;
3375   unsigned int i;
3376   unsigned int total_count;
3377   struct DuplicateStats *stats_list;
3378   struct DuplicateStats *pos;
3379   stats_list = NULL;
3380
3381   /* Allocate a single stats iteration context */
3382   stats_context = GNUNET_malloc(sizeof(struct StatsIterateContext));
3383   stats_context->cont = cont;
3384   stats_context->proc = proc;
3385   stats_context->cls = cls;
3386   total_count = 0;
3387
3388   for (i = 0; i < pg->total; i++)
3389     {
3390       if ((pg->peers[i].daemon->running == GNUNET_YES) && (GNUNET_NO == stats_check_existing(pg, &pg->peers[i], &stats_list)))
3391         {
3392           /* Allocate one core context per core we need to connect to */
3393           core_ctx = GNUNET_malloc(sizeof(struct StatsCoreContext));
3394           core_ctx->daemon = pg->peers[i].daemon;
3395           /* Set back pointer to topology iteration context */
3396           core_ctx->iter_context = stats_context;
3397           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_get_statistics, core_ctx);
3398           total_count++;
3399         }
3400     }
3401
3402   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Retrieving stats from %u total instances.\n", total_count);
3403   stats_context->total = total_count;
3404   if (stats_list != NULL)
3405     {
3406       pos = stats_list;
3407       while(pos != NULL)
3408         {
3409           GNUNET_free(pos->unique_string);
3410           stats_list = pos->next;
3411           GNUNET_free(pos);
3412           pos = stats_list->next;
3413         }
3414     }
3415   return;
3416 }
3417
3418 /**
3419  * There are many ways to connect peers that are supported by this function.
3420  * To connect peers in the same topology that was created via the
3421  * GNUNET_TESTING_create_topology, the topology variable must be set to
3422  * GNUNET_TESTING_TOPOLOGY_NONE.  If the topology variable is specified,
3423  * a new instance of that topology will be generated and attempted to be
3424  * connected.  This could result in some connections being impossible,
3425  * because some topologies are non-deterministic.
3426  *
3427  * @param pg the peer group struct representing the running peers
3428  * @param topology which topology to connect the peers in
3429  * @param options options for connecting the topology
3430  * @param option_modifier modifier for options that take a parameter
3431  * @param notify_callback notification to be called once all connections completed
3432  * @param notify_cls closure for notification callback
3433  *
3434  * @return the number of connections that will be attempted, GNUNET_SYSERR on error
3435  */
3436 int
3437 GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
3438                                  enum GNUNET_TESTING_Topology topology,
3439                                  enum GNUNET_TESTING_TopologyOption options,
3440                                  double option_modifier,
3441                                  GNUNET_TESTING_NotifyCompletion notify_callback,
3442                                  void *notify_cls)
3443 {
3444   switch (topology)
3445       {
3446       case GNUNET_TESTING_TOPOLOGY_CLIQUE:
3447 #if VERBOSE_TOPOLOGY
3448       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3449                   _("Creating clique CONNECT topology\n"));
3450 #endif
3451         create_clique (pg, &add_actual_connections);
3452         break;
3453       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
3454 #if VERBOSE_TOPOLOGY
3455       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3456                   _("Creating small world (ring) CONNECT topology\n"));
3457 #endif
3458         create_small_world_ring (pg, &add_actual_connections);
3459         break;
3460       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
3461 #if VERBOSE_TOPOLOGY
3462       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3463                   _("Creating small world (2d-torus) CONNECT topology\n"));
3464 #endif
3465         create_small_world (pg, &add_actual_connections);
3466         break;
3467       case GNUNET_TESTING_TOPOLOGY_RING:
3468 #if VERBOSE_TOPOLOGY
3469       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3470                   _("Creating ring CONNECT topology\n"));
3471 #endif
3472         create_ring (pg, &add_actual_connections);
3473         break;
3474       case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
3475 #if VERBOSE_TOPOLOGY
3476       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3477                   _("Creating 2d torus CONNECT topology\n"));
3478 #endif
3479         create_2d_torus (pg, &add_actual_connections);
3480         break;
3481       case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
3482 #if VERBOSE_TOPOLOGY
3483       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3484                   _("Creating Erdos-Renyi CONNECT topology\n"));
3485 #endif
3486         create_erdos_renyi (pg, &add_actual_connections);
3487         break;
3488       case GNUNET_TESTING_TOPOLOGY_INTERNAT:
3489 #if VERBOSE_TOPOLOGY
3490       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3491                   _("Creating InterNAT CONNECT topology\n"));
3492 #endif
3493         create_nated_internet (pg, &add_actual_connections);
3494         break;
3495       case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
3496 #if VERBOSE_TOPOLOGY
3497       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3498                   _("Creating Scale Free CONNECT topology\n"));
3499 #endif
3500         create_scale_free (pg, &add_actual_connections);
3501         break;
3502       case GNUNET_TESTING_TOPOLOGY_LINE:
3503 #if VERBOSE_TOPOLOGY
3504       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3505                   _("Creating straight line CONNECT topology\n"));
3506 #endif
3507         create_line (pg, &add_actual_connections);
3508         break;
3509       case GNUNET_TESTING_TOPOLOGY_NONE:
3510 #if VERBOSE_TOPOLOGY
3511         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3512                   _("Creating no CONNECT topology\n"));
3513 #endif
3514         copy_allowed_topology(pg);
3515         break;
3516       default:
3517         GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
3518                    _("Unknown topology specification, can't connect peers!\n"));
3519         return GNUNET_SYSERR;
3520       }
3521
3522   switch (options)
3523     {
3524     case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM:
3525 #if VERBOSE_TOPOLOGY
3526       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3527                   _("Connecting random subset (%'.2f percent) of possible peers\n"), 100 * option_modifier);
3528 #endif
3529       choose_random_connections(pg, option_modifier);
3530       break;
3531     case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM:
3532 #if VERBOSE_TOPOLOGY
3533       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3534                   _("Connecting a minimum of %u peers each (if possible)\n"), (unsigned int)option_modifier);
3535 #endif
3536       choose_minimum(pg, (unsigned int)option_modifier);
3537       break;
3538     case GNUNET_TESTING_TOPOLOGY_OPTION_DFS:
3539 #if VERBOSE_TOPOLOGY
3540       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3541                   _("Using DFS to connect a minimum of %u peers each (if possible)\n"), (unsigned int)option_modifier);
3542 #endif
3543       perform_dfs(pg, (int)option_modifier);
3544       break;
3545     case GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST:
3546 #if VERBOSE_TOPOLOGY
3547       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3548                   _("Finding additional %u closest peers each (if possible)\n"), (unsigned int)option_modifier);
3549 #endif
3550       add_closest(pg, (unsigned int)option_modifier, &add_actual_connections);
3551       break;
3552     case GNUNET_TESTING_TOPOLOGY_OPTION_NONE:
3553       break;
3554     case GNUNET_TESTING_TOPOLOGY_OPTION_ALL:
3555       break;
3556     default:
3557       break;
3558     }
3559
3560   return connect_topology(pg, notify_callback, notify_cls);
3561 }
3562
3563 /**
3564  * Callback that is called whenever a hostkey is generated
3565  * for a peer.  Call the real callback and decrement the
3566  * starting counter for the peergroup.
3567  *
3568  * @param cls closure
3569  * @param id identifier for the daemon, NULL on error
3570  * @param d handle for the daemon
3571  * @param emsg error message (NULL on success)
3572  */
3573 static void internal_hostkey_callback (void *cls,
3574                                        const struct GNUNET_PeerIdentity *id,
3575                                        struct GNUNET_TESTING_Daemon *d,
3576                                        const char *emsg)
3577 {
3578   struct InternalStartContext *internal_context = cls;
3579   internal_context->peer->pg->starting--;
3580   internal_context->peer->pg->started++;
3581   if (internal_context->hostkey_callback != NULL)
3582     internal_context->hostkey_callback(internal_context->hostkey_cls, id, d, emsg);
3583   else if (internal_context->peer->pg->started == internal_context->peer->pg->total)
3584     {
3585       internal_context->peer->pg->started = 0; /* Internal startup may use this counter! */
3586       GNUNET_TESTING_daemons_continue_startup(internal_context->peer->pg);
3587     }
3588 }
3589
3590 /**
3591  * Callback that is called whenever a peer has finished starting.
3592  * Call the real callback and decrement the starting counter
3593  * for the peergroup.
3594  *
3595  * @param cls closure
3596  * @param id identifier for the daemon, NULL on error
3597  * @param d handle for the daemon
3598  * @param emsg error message (NULL on success)
3599  */
3600 static void internal_startup_callback (void *cls,
3601                                        const struct GNUNET_PeerIdentity *id,
3602                                        const struct GNUNET_CONFIGURATION_Handle *cfg,
3603                                        struct GNUNET_TESTING_Daemon *d,
3604                                        const char *emsg)
3605 {
3606   struct InternalStartContext *internal_context = cls;
3607   internal_context->peer->pg->starting--;
3608   if (internal_context->start_cb != NULL)
3609     internal_context->start_cb(internal_context->start_cb_cls, id, cfg, d, emsg);
3610 }
3611
3612 static void
3613 internal_continue_startup (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
3614 {
3615   struct InternalStartContext *internal_context = cls;
3616
3617   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3618     {
3619       return;
3620     }
3621
3622   if (internal_context->peer->pg->starting < MAX_CONCURRENT_STARTING)
3623     {
3624       internal_context->peer->pg->starting++;
3625       GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon);
3626     }
3627   else
3628     {
3629       GNUNET_SCHEDULER_add_delayed(internal_context->peer->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &internal_continue_startup, internal_context);
3630     }
3631 }
3632
3633
3634 /**
3635  * Callback for informing us about a successful
3636  * or unsuccessful churn start call.
3637  *
3638  * @param cls a ChurnContext
3639  * @param id the peer identity of the started peer
3640  * @param cfg the handle to the configuration of the peer
3641  * @param d handle to the daemon for the peer
3642  * @param emsg NULL on success, non-NULL on failure
3643  *
3644  */
3645 void
3646 churn_start_callback (void *cls,
3647                       const struct GNUNET_PeerIdentity *id,
3648                       const struct GNUNET_CONFIGURATION_Handle *cfg,
3649                       struct GNUNET_TESTING_Daemon *d,
3650                       const char *emsg)
3651 {
3652   struct ChurnRestartContext *startup_ctx = cls;
3653   struct ChurnContext *churn_ctx = startup_ctx->churn_ctx;
3654
3655   unsigned int total_left;
3656   char *error_message;
3657
3658   error_message = NULL;
3659   if (emsg != NULL)
3660     {
3661       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3662                   "Churn stop callback failed with error `%s'\n",
3663                   emsg);
3664       churn_ctx->num_failed_start++;
3665     }
3666   else
3667     {
3668       churn_ctx->num_to_start--;
3669     }
3670
3671 #if DEBUG_CHURN
3672   GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
3673              "Started peer, %d left.\n",
3674              churn_ctx->num_to_start);
3675 #endif
3676
3677   total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
3678
3679   if (total_left == 0)
3680   {
3681     if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
3682       GNUNET_asprintf(&error_message,
3683                       "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!",
3684                       churn_ctx->num_failed_start,
3685                       churn_ctx->num_failed_stop);
3686     churn_ctx->cb(churn_ctx->cb_cls, error_message);
3687     GNUNET_free_non_null(error_message);
3688     GNUNET_free(churn_ctx);
3689     GNUNET_free(startup_ctx);
3690   }
3691 }
3692
3693
3694 static void schedule_churn_restart(void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
3695 {
3696   struct PeerRestartContext *peer_restart_ctx = cls;
3697   struct ChurnRestartContext *startup_ctx = peer_restart_ctx->churn_restart_ctx;
3698
3699   if (startup_ctx->outstanding > MAX_CONCURRENT_STARTING)
3700     GNUNET_SCHEDULER_add_delayed(peer_restart_ctx->daemon->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_churn_restart, peer_restart_ctx);
3701   else
3702     {
3703       GNUNET_TESTING_daemon_start_stopped(peer_restart_ctx->daemon,
3704                                           startup_ctx->timeout,
3705                                           &churn_start_callback,
3706                                           startup_ctx);
3707       GNUNET_free(peer_restart_ctx);
3708     }
3709 }
3710
3711 static void
3712 internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
3713 {
3714   struct InternalStartContext *internal_context = cls;
3715
3716   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3717     {
3718       return;
3719     }
3720
3721   if (internal_context->peer->pg->starting < MAX_CONCURRENT_HOSTKEYS)
3722     {
3723       internal_context->peer->pg->starting++;
3724       internal_context->peer->daemon = GNUNET_TESTING_daemon_start (internal_context->peer->pg->sched,
3725                                                                     internal_context->peer->cfg,
3726                                                                     internal_context->timeout,
3727                                                                     internal_context->hostname,
3728                                                                     internal_context->username,
3729                                                                     internal_context->sshport,
3730                                                                     &internal_hostkey_callback,
3731                                                                     internal_context,
3732                                                                     &internal_startup_callback,
3733                                                                     internal_context);
3734     }
3735   else
3736     {
3737       GNUNET_SCHEDULER_add_delayed(internal_context->peer->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &internal_start, internal_context);
3738     }
3739 }
3740
3741 /**
3742  * Function which continues a peer group starting up
3743  * after successfully generating hostkeys for each peer.
3744  *
3745  * @param pg the peer group to continue starting
3746  *
3747  */
3748 void
3749 GNUNET_TESTING_daemons_continue_startup(struct GNUNET_TESTING_PeerGroup *pg)
3750 {
3751   unsigned int i;
3752
3753   pg->starting = 0;
3754   for (i = 0; i < pg->total; i++)
3755     {
3756       GNUNET_SCHEDULER_add_now (pg->sched, &internal_continue_startup, &pg->peers[i].internal_context);
3757       //GNUNET_TESTING_daemon_continue_startup(pg->peers[i].daemon);
3758     }
3759 }
3760
3761 /**
3762  * Start count gnunet instances with the same set of transports and
3763  * applications.  The port numbers (any option called "PORT") will be
3764  * adjusted to ensure that no two peers running on the same system
3765  * have the same port(s) in their respective configurations.
3766  *
3767  * @param sched scheduler to use
3768  * @param cfg configuration template to use
3769  * @param total number of daemons to start
3770  * @param timeout total time allowed for peers to start
3771  * @param hostkey_callback function to call on each peers hostkey generation
3772  *        if NULL, peers will be started by this call, if non-null,
3773  *        GNUNET_TESTING_daemons_continue_startup must be called after
3774  *        successful hostkey generation
3775  * @param hostkey_cls closure for hostkey callback
3776  * @param cb function to call on each daemon that was started
3777  * @param cb_cls closure for cb
3778  * @param connect_callback function to call each time two hosts are connected
3779  * @param connect_callback_cls closure for connect_callback
3780  * @param hostnames linked list of hosts to use to start peers on (NULL to run on localhost only)
3781  *
3782  * @return NULL on error, otherwise handle to control peer group
3783  */
3784 struct GNUNET_TESTING_PeerGroup *
3785 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
3786                               const struct GNUNET_CONFIGURATION_Handle *cfg,
3787                               unsigned int total,
3788                               struct GNUNET_TIME_Relative timeout,
3789                               GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback,
3790                               void *hostkey_cls,
3791                               GNUNET_TESTING_NotifyDaemonRunning cb,
3792                               void *cb_cls,
3793                               GNUNET_TESTING_NotifyConnection
3794                               connect_callback, void *connect_callback_cls,
3795                               const struct GNUNET_TESTING_Host *hostnames)
3796 {
3797   struct GNUNET_TESTING_PeerGroup *pg;
3798   const struct GNUNET_TESTING_Host *hostpos;
3799 #if 0
3800   char *pos;
3801   const char *rpos;
3802   char *start;
3803 #endif
3804   const char *hostname;
3805   const char *username;
3806   char *baseservicehome;
3807   char *newservicehome;
3808   char *tmpdir;
3809   struct GNUNET_CONFIGURATION_Handle *pcfg;
3810   unsigned int off;
3811   unsigned int hostcnt;
3812   uint16_t minport;
3813   uint16_t sshport;
3814   uint32_t upnum;
3815   uint32_t fdnum;
3816
3817   if (0 == total)
3818     {
3819       GNUNET_break (0);
3820       return NULL;
3821     }
3822   upnum = 0;
3823   fdnum = 0;
3824   pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
3825   pg->sched = sched;
3826   pg->cfg = cfg;
3827   pg->notify_connection = connect_callback;
3828   pg->notify_connection_cls = connect_callback_cls;
3829   pg->total = total;
3830   pg->max_timeout = GNUNET_TIME_relative_to_absolute(timeout);
3831   pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
3832   if (NULL != hostnames)
3833     {
3834       off = 0;
3835       hostpos = hostnames;
3836       while (hostpos != NULL)
3837         {
3838           hostpos = hostpos->next;
3839           off++;
3840         }
3841       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
3842       off = 0;
3843
3844       hostpos = hostnames;
3845       while (hostpos != NULL)
3846         {
3847           pg->hosts[off].minport = LOW_PORT;
3848           pg->hosts[off].hostname = GNUNET_strdup(hostpos->hostname);
3849           if (hostpos->username != NULL)
3850             pg->hosts[off].username = GNUNET_strdup(hostpos->username);
3851           pg->hosts[off].sshport = hostpos->port;
3852           hostpos = hostpos->next;
3853           off++;
3854         }
3855
3856       if (off == 0)
3857         {
3858           pg->hosts = NULL;
3859         }
3860       hostcnt = off;
3861       minport = 0;
3862       pg->num_hosts = off;
3863
3864 #if NO_LL
3865       off = 2;
3866       /* skip leading spaces */
3867       while ((0 != *hostnames) && (isspace ( (unsigned char) *hostnames)))
3868         hostnames++;
3869       rpos = hostnames;
3870       while ('\0' != *rpos)
3871         {
3872           if (isspace ( (unsigned char) *rpos))
3873             off++;
3874           rpos++;
3875         }
3876       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
3877       off = 0;
3878       start = GNUNET_strdup (hostnames);
3879       pos = start;
3880       while ('\0' != *pos)
3881         {
3882           if (isspace ( (unsigned char) *pos))
3883             {
3884               *pos = '\0';
3885               if (strlen (start) > 0)
3886                 {
3887                   pg->hosts[off].minport = LOW_PORT;
3888                   pg->hosts[off++].hostname = start;
3889                 }
3890               start = pos + 1;
3891             }
3892           pos++;
3893         }
3894       if (strlen (start) > 0)
3895         {
3896           pg->hosts[off].minport = LOW_PORT;
3897           pg->hosts[off++].hostname = start;
3898         }
3899       if (off == 0)
3900         {
3901           GNUNET_free (start);
3902           GNUNET_free (pg->hosts);
3903           pg->hosts = NULL;
3904         }
3905       hostcnt = off;
3906       minport = 0;              /* make gcc happy */
3907 #endif
3908     }
3909   else
3910     {
3911       hostcnt = 0;
3912       minport = LOW_PORT;
3913     }
3914   for (off = 0; off < total; off++)
3915     {
3916       if (hostcnt > 0)
3917         {
3918           hostname = pg->hosts[off % hostcnt].hostname;
3919           username = pg->hosts[off % hostcnt].username;
3920           sshport = pg->hosts[off % hostcnt].sshport;
3921           pcfg = make_config (cfg, 
3922                               &pg->hosts[off % hostcnt].minport,
3923                               &upnum,
3924                               hostname, &fdnum);
3925         }
3926       else
3927         {
3928           hostname = NULL;
3929           username = NULL;
3930           sshport = 0;
3931           pcfg = make_config (cfg,
3932                               &minport,
3933                               &upnum,
3934                               hostname, &fdnum);
3935         }
3936
3937       if (NULL == pcfg)
3938         {
3939           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3940                       _
3941                       ("Could not create configuration for peer number %u on `%s'!\n"),
3942                       off, hostname == NULL ? "localhost" : hostname);
3943           continue;
3944         }
3945
3946       if (GNUNET_YES ==
3947           GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
3948                                                  &baseservicehome))
3949         {
3950           GNUNET_asprintf (&newservicehome,
3951                            "%s/%d/", baseservicehome, off);
3952           GNUNET_free (baseservicehome);
3953         }
3954       else
3955         {
3956           tmpdir = getenv ("TMPDIR");
3957           tmpdir = tmpdir ? tmpdir : "/tmp";
3958           GNUNET_asprintf (&newservicehome,
3959                            "%s/%s/%d/",
3960                            tmpdir,
3961                            "gnunet-testing-test-test", off);
3962         }
3963       GNUNET_CONFIGURATION_set_value_string (pcfg,
3964                                              "PATHS",
3965                                              "SERVICEHOME", newservicehome);
3966       GNUNET_free (newservicehome);
3967       pg->peers[off].cfg = pcfg;
3968       pg->peers[off].allowed_peers = GNUNET_CONTAINER_multihashmap_create(total);
3969       pg->peers[off].connect_peers = GNUNET_CONTAINER_multihashmap_create(total);
3970       pg->peers[off].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create(total);
3971       pg->peers[off].pg = pg;
3972
3973       pg->peers[off].internal_context.peer = &pg->peers[off];
3974       pg->peers[off].internal_context.timeout = timeout;
3975       pg->peers[off].internal_context.hostname = hostname;
3976       pg->peers[off].internal_context.username = username;
3977       pg->peers[off].internal_context.sshport = sshport;
3978       pg->peers[off].internal_context.hostkey_callback = hostkey_callback;
3979       pg->peers[off].internal_context.hostkey_cls = hostkey_cls;
3980       pg->peers[off].internal_context.start_cb = cb;
3981       pg->peers[off].internal_context.start_cb_cls = cb_cls;
3982
3983       GNUNET_SCHEDULER_add_now (sched, &internal_start, &pg->peers[off].internal_context);
3984
3985     }
3986   return pg;
3987 }
3988
3989 /*
3990  * Get a daemon by number, so callers don't have to do nasty
3991  * offsetting operation.
3992  */
3993 struct GNUNET_TESTING_Daemon *
3994 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
3995 {
3996   if (position < pg->total)
3997     return pg->peers[position].daemon;
3998   else
3999     return NULL;
4000 }
4001
4002 /*
4003  * Get a daemon by peer identity, so callers can
4004  * retrieve the daemon without knowing it's offset.
4005  *
4006  * @param pg the peer group to retrieve the daemon from
4007  * @param peer_id the peer identity of the daemon to retrieve
4008  *
4009  * @return the daemon on success, or NULL if no such peer identity is found
4010  */
4011 struct GNUNET_TESTING_Daemon *
4012 GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg, struct GNUNET_PeerIdentity *peer_id)
4013 {
4014   unsigned int i;
4015
4016   for (i = 0; i < pg->total; i ++)
4017     {
4018       if (0 == memcmp(&pg->peers[i].daemon->id, peer_id, sizeof(struct GNUNET_PeerIdentity)))
4019         return pg->peers[i].daemon;
4020     }
4021
4022   return NULL;
4023 }
4024
4025 /**
4026  * Prototype of a function that will be called when a
4027  * particular operation was completed the testing library.
4028  *
4029  * @param cls closure (a struct RestartContext)
4030  * @param id id of the peer that was restarted
4031  * @param cfg handle to the configuration of the peer
4032  * @param d handle to the daemon that was restarted
4033  * @param emsg NULL on success
4034  */
4035 void restart_callback (void *cls,
4036                        const struct GNUNET_PeerIdentity *id,
4037                        const struct GNUNET_CONFIGURATION_Handle *cfg,
4038                        struct GNUNET_TESTING_Daemon *d,
4039                        const char *emsg)
4040 {
4041   struct RestartContext *restart_context = cls;
4042
4043   if (emsg == NULL)
4044     {
4045       restart_context->peers_restarted++;
4046     }
4047   else
4048     {
4049       restart_context->peers_restart_failed++;
4050     }
4051
4052   if (restart_context->peers_restarted == restart_context->peer_group->total)
4053     {
4054       restart_context->callback(restart_context->callback_cls, NULL);
4055       GNUNET_free(restart_context);
4056     }
4057   else if (restart_context->peers_restart_failed + restart_context->peers_restarted == restart_context->peer_group->total)
4058     {
4059       restart_context->callback(restart_context->callback_cls, "Failed to restart peers!");
4060       GNUNET_free(restart_context);
4061     }
4062
4063 }
4064
4065 /**
4066  * Callback for informing us about a successful
4067  * or unsuccessful churn stop call.
4068  *
4069  * @param cls a ChurnContext
4070  * @param emsg NULL on success, non-NULL on failure
4071  *
4072  */
4073 void
4074 churn_stop_callback (void *cls, const char *emsg)
4075 {
4076   struct ShutdownContext *shutdown_ctx = cls;
4077   struct ChurnContext *churn_ctx = shutdown_ctx->cb_cls;
4078   unsigned int total_left;
4079   char *error_message;
4080
4081   error_message = NULL;
4082   shutdown_ctx->outstanding--;
4083
4084   if (emsg != NULL)
4085     {
4086       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
4087                  "Churn stop callback failed with error `%s'\n", emsg);
4088       churn_ctx->num_failed_stop++;
4089     }
4090   else
4091     {
4092       churn_ctx->num_to_stop--;
4093     }
4094
4095 #if DEBUG_CHURN
4096   GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
4097              "Stopped peer, %d left.\n", 
4098              churn_ctx->num_to_stop);
4099 #endif
4100   total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
4101
4102   if (total_left == 0)
4103   {
4104     if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
4105       {
4106         GNUNET_asprintf(&error_message, 
4107                         "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", 
4108                         churn_ctx->num_failed_start, 
4109                         churn_ctx->num_failed_stop);
4110       }
4111     churn_ctx->cb(churn_ctx->cb_cls, error_message);
4112     GNUNET_free_non_null(error_message);
4113     GNUNET_free(churn_ctx);
4114     GNUNET_free(shutdown_ctx);
4115   }
4116 }
4117
4118 /**
4119  * Count the number of running peers.
4120  *
4121  * @param pg handle for the peer group
4122  *
4123  * @return the number of currently running peers in the peer group
4124  */
4125 unsigned int
4126 GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg)
4127 {
4128   unsigned int i;
4129   unsigned int running = 0;
4130   for (i = 0; i < pg->total; i++)
4131   {
4132     if (pg->peers[i].daemon->running == GNUNET_YES)
4133     {
4134       GNUNET_assert(running != -1);
4135       running++;
4136     }
4137   }
4138   return running;
4139 }
4140
4141 /**
4142  * Task to rate limit the number of outstanding peer shutdown
4143  * requests.  This is necessary for making sure we don't do
4144  * too many ssh connections at once, but is generally nicer
4145  * to any system as well (graduated task starts, as opposed
4146  * to calling gnunet-arm N times all at once).
4147  */
4148 static void
4149 schedule_churn_shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
4150 {
4151   struct PeerShutdownContext *peer_shutdown_ctx = cls;
4152   struct ShutdownContext *shutdown_ctx;
4153
4154   GNUNET_assert(peer_shutdown_ctx != NULL);
4155   shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
4156   GNUNET_assert(shutdown_ctx != NULL);
4157
4158   if (shutdown_ctx->outstanding > MAX_CONCURRENT_SHUTDOWN)
4159     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);
4160   else
4161     {
4162       shutdown_ctx->outstanding++;
4163       GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon, shutdown_ctx->timeout, shutdown_ctx->cb, shutdown_ctx, GNUNET_NO, GNUNET_YES);
4164       GNUNET_free(peer_shutdown_ctx);
4165     }
4166 }
4167
4168 /**
4169  * Simulate churn by stopping some peers (and possibly
4170  * re-starting others if churn is called multiple times).  This
4171  * function can only be used to create leave-join churn (peers "never"
4172  * leave for good).  First "voff" random peers that are currently
4173  * online will be taken offline; then "von" random peers that are then
4174  * offline will be put back online.  No notifications will be
4175  * generated for any of these operations except for the callback upon
4176  * completion.
4177  *
4178  * @param pg handle for the peer group
4179  * @param voff number of peers that should go offline
4180  * @param von number of peers that should come back online;
4181  *            must be zero on first call (since "testbed_start"
4182  *            always starts all of the peers)
4183  * @param timeout how long to wait for operations to finish before
4184  *        giving up
4185  * @param cb function to call at the end
4186  * @param cb_cls closure for cb
4187  */
4188 void
4189 GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg,
4190                               unsigned int voff,
4191                               unsigned int von,
4192                               struct GNUNET_TIME_Relative timeout,
4193                               GNUNET_TESTING_NotifyCompletion cb,
4194                               void *cb_cls)
4195 {
4196   struct ChurnContext *churn_ctx;
4197   struct ShutdownContext *shutdown_ctx;
4198   struct PeerShutdownContext *peer_shutdown_ctx;
4199   struct PeerRestartContext *peer_restart_ctx;
4200   struct ChurnRestartContext *churn_startup_ctx;
4201
4202   unsigned int running;
4203   unsigned int stopped;
4204   unsigned int total_running;
4205   unsigned int total_stopped;
4206   unsigned int i;
4207   unsigned int *running_arr;
4208   unsigned int *stopped_arr;
4209   unsigned int *running_permute;
4210   unsigned int *stopped_permute;
4211
4212   running = 0;
4213   stopped = 0;
4214
4215   if ((von == 0) && (voff == 0)) /* No peers at all? */
4216     {
4217       cb(cb_cls, NULL);
4218       return;
4219     }
4220
4221   for (i = 0; i < pg->total; i++)
4222   {
4223     if (pg->peers[i].daemon->running == GNUNET_YES)
4224     {
4225       GNUNET_assert(running != -1);
4226       running++;
4227     }
4228     else
4229     {
4230       GNUNET_assert(stopped != -1);
4231       stopped++;
4232     }
4233   }
4234
4235   if (voff > running)
4236   {
4237     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to stop more peers than are currently running!\n");
4238     cb(cb_cls, "Trying to stop more peers than are currently running!");
4239     return;
4240   }
4241
4242   if (von > stopped)
4243   {
4244     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to start more peers than are currently stopped!\n");
4245     cb(cb_cls, "Trying to start more peers than are currently stopped!");
4246     return;
4247   }
4248
4249   churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
4250
4251   running_arr = NULL;
4252   if (running > 0)
4253     running_arr = GNUNET_malloc(running * sizeof(unsigned int));
4254
4255   stopped_arr = NULL;
4256   if (stopped > 0)
4257     stopped_arr = GNUNET_malloc(stopped * sizeof(unsigned int));
4258
4259   running_permute = NULL;
4260   stopped_permute = NULL;
4261
4262   if (running > 0)
4263     running_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, running);
4264   if (stopped > 0)
4265     stopped_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, stopped);
4266
4267   total_running = running;
4268   total_stopped = stopped;
4269   running = 0;
4270   stopped = 0;
4271
4272   churn_ctx->num_to_start = von;
4273   churn_ctx->num_to_stop = voff;
4274   churn_ctx->cb = cb;
4275   churn_ctx->cb_cls = cb_cls;  
4276
4277   for (i = 0; i < pg->total; i++)
4278   {
4279     if (pg->peers[i].daemon->running == GNUNET_YES)
4280     {
4281       GNUNET_assert((running_arr != NULL) && (total_running > running));
4282       running_arr[running] = i;
4283       running++;
4284     }
4285     else
4286     {
4287       GNUNET_assert((stopped_arr != NULL) && (total_stopped > stopped));
4288       stopped_arr[stopped] = i;
4289       stopped++;
4290     }
4291   }
4292
4293   GNUNET_assert(running >= voff);
4294   if (voff > 0)
4295     {
4296       shutdown_ctx = GNUNET_malloc(sizeof(struct ShutdownContext));
4297       shutdown_ctx->cb = &churn_stop_callback;
4298       shutdown_ctx->cb_cls = churn_ctx;
4299       shutdown_ctx->total_peers = voff;
4300       shutdown_ctx->timeout = timeout;
4301     }
4302
4303   for (i = 0; i < voff; i++)
4304   {
4305 #if DEBUG_CHURN
4306     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Stopping peer %d!\n", running_permute[i]);
4307 #endif
4308     GNUNET_assert(running_arr != NULL);
4309     peer_shutdown_ctx = GNUNET_malloc(sizeof(struct PeerShutdownContext));
4310     peer_shutdown_ctx->daemon = pg->peers[running_arr[running_permute[i]]].daemon;
4311     peer_shutdown_ctx->shutdown_ctx = shutdown_ctx;
4312     GNUNET_SCHEDULER_add_now(peer_shutdown_ctx->daemon->sched, &schedule_churn_shutdown_task, peer_shutdown_ctx);
4313
4314     /*
4315     GNUNET_TESTING_daemon_stop (pg->peers[running_arr[running_permute[i]]].daemon,
4316                                 timeout, 
4317                                 &churn_stop_callback, churn_ctx, 
4318                                 GNUNET_NO, GNUNET_YES); */
4319   }
4320
4321   GNUNET_assert(stopped >= von);
4322   if (von > 0)
4323     {
4324       churn_startup_ctx = GNUNET_malloc(sizeof(struct ChurnRestartContext));
4325       churn_startup_ctx->churn_ctx = churn_ctx;
4326       churn_startup_ctx->timeout = timeout;
4327     }
4328   for (i = 0; i < von; i++)
4329     {
4330 #if DEBUG_CHURN
4331       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Starting up peer %d!\n", stopped_permute[i]);
4332 #endif
4333       GNUNET_assert(stopped_arr != NULL);
4334       peer_restart_ctx = GNUNET_malloc(sizeof(struct PeerRestartContext));
4335       peer_restart_ctx->churn_restart_ctx = churn_startup_ctx;
4336       peer_restart_ctx->daemon = pg->peers[stopped_arr[stopped_permute[i]]].daemon;
4337       GNUNET_SCHEDULER_add_now(peer_restart_ctx->daemon->sched, &schedule_churn_restart, peer_restart_ctx);
4338       /*
4339       GNUNET_TESTING_daemon_start_stopped(pg->peers[stopped_arr[stopped_permute[i]]].daemon, 
4340                                           timeout, &churn_start_callback, churn_ctx);*/
4341   }
4342
4343   GNUNET_free_non_null(running_arr);
4344   GNUNET_free_non_null(stopped_arr);
4345   GNUNET_free_non_null(running_permute);
4346   GNUNET_free_non_null(stopped_permute);
4347 }
4348
4349
4350 /**
4351  * Restart all peers in the given group.
4352  *
4353  * @param pg the handle to the peer group
4354  * @param callback function to call on completion (or failure)
4355  * @param callback_cls closure for the callback function
4356  */
4357 void
4358 GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg,
4359                                 GNUNET_TESTING_NotifyCompletion callback,
4360                                 void *callback_cls)
4361 {
4362   struct RestartContext *restart_context;
4363   unsigned int off;
4364
4365   if (pg->total > 0)
4366     {
4367       restart_context = GNUNET_malloc(sizeof(struct RestartContext));
4368       restart_context->peer_group = pg;
4369       restart_context->peers_restarted = 0;
4370       restart_context->callback = callback;
4371       restart_context->callback_cls = callback_cls;
4372
4373       for (off = 0; off < pg->total; off++)
4374         {
4375           GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, restart_context);
4376         }
4377     }
4378 }
4379
4380 /**
4381  * Start or stop an individual peer from the given group.
4382  *
4383  * @param pg handle to the peer group
4384  * @param offset which peer to start or stop
4385  * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it
4386  * @param timeout how long to wait for shutdown
4387  * @param cb function to call at the end
4388  * @param cb_cls closure for cb
4389  */
4390 void
4391 GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, 
4392                              unsigned int offset,
4393                              int desired_status,
4394                              struct GNUNET_TIME_Relative timeout,
4395                              GNUNET_TESTING_NotifyCompletion cb,
4396                              void *cb_cls)
4397 {
4398   struct ShutdownContext *shutdown_ctx;
4399   struct ChurnRestartContext *startup_ctx;
4400   struct ChurnContext *churn_ctx;
4401
4402   if (GNUNET_NO == desired_status)
4403     {
4404       if (NULL != pg->peers[offset].daemon)
4405         {
4406           shutdown_ctx = GNUNET_malloc(sizeof(struct ShutdownContext));
4407           churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
4408           churn_ctx->num_to_start = 0;
4409           churn_ctx->num_to_stop = 1;
4410           churn_ctx->cb = cb;
4411           churn_ctx->cb_cls = cb_cls;
4412           shutdown_ctx->cb_cls = churn_ctx;
4413           GNUNET_TESTING_daemon_stop(pg->peers[offset].daemon, 
4414                                      timeout, &churn_stop_callback, shutdown_ctx,
4415                                      GNUNET_NO, GNUNET_YES);     
4416         }
4417     }
4418   else if (GNUNET_YES == desired_status)
4419     {
4420       if (NULL == pg->peers[offset].daemon)
4421         {
4422           startup_ctx = GNUNET_malloc(sizeof(struct ChurnRestartContext));
4423           churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
4424           churn_ctx->num_to_start = 1;
4425           churn_ctx->num_to_stop = 0;
4426           churn_ctx->cb = cb;
4427           churn_ctx->cb_cls = cb_cls;  
4428           startup_ctx->churn_ctx = churn_ctx;
4429           GNUNET_TESTING_daemon_start_stopped(pg->peers[offset].daemon, 
4430                                               timeout, &churn_start_callback, startup_ctx);
4431         }
4432     }
4433   else
4434     GNUNET_break (0);
4435 }
4436
4437
4438 /**
4439  * Callback for shutting down peers in a peer group.
4440  *
4441  * @param cls closure (struct ShutdownContext)
4442  * @param emsg NULL on success
4443  */
4444 void internal_shutdown_callback (void *cls,
4445                                  const char *emsg)
4446 {
4447   struct ShutdownContext *shutdown_ctx = cls;
4448
4449   shutdown_ctx->outstanding--;
4450   if (emsg == NULL)
4451     {
4452       shutdown_ctx->peers_down++;
4453     }
4454   else
4455     {
4456       shutdown_ctx->peers_failed++;
4457     }
4458
4459   if ((shutdown_ctx->cb != NULL) && (shutdown_ctx->peers_down + shutdown_ctx->peers_failed == shutdown_ctx->total_peers))
4460     {
4461       if (shutdown_ctx->peers_failed > 0)
4462         shutdown_ctx->cb(shutdown_ctx->cb_cls, "Not all peers successfully shut down!");
4463       else
4464         shutdown_ctx->cb(shutdown_ctx->cb_cls, NULL);
4465       GNUNET_free(shutdown_ctx);
4466     }
4467 }
4468
4469
4470 /**
4471  * Task to rate limit the number of outstanding peer shutdown
4472  * requests.  This is necessary for making sure we don't do
4473  * too many ssh connections at once, but is generally nicer
4474  * to any system as well (graduated task starts, as opposed
4475  * to calling gnunet-arm N times all at once).
4476  */
4477 static void
4478 schedule_shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
4479 {
4480   struct PeerShutdownContext *peer_shutdown_ctx = cls;
4481   struct ShutdownContext *shutdown_ctx;
4482
4483   GNUNET_assert(peer_shutdown_ctx != NULL);
4484   shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
4485   GNUNET_assert(shutdown_ctx != NULL);
4486
4487   if (shutdown_ctx->outstanding > MAX_CONCURRENT_SHUTDOWN)
4488     GNUNET_SCHEDULER_add_delayed(peer_shutdown_ctx->daemon->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_shutdown_task, peer_shutdown_ctx);
4489   else
4490     {
4491       shutdown_ctx->outstanding++;
4492       GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon, shutdown_ctx->timeout, &internal_shutdown_callback, shutdown_ctx, GNUNET_YES, GNUNET_NO);
4493       GNUNET_free(peer_shutdown_ctx);
4494     }
4495 }
4496
4497 /**
4498  * Shutdown all peers started in the given group.
4499  *
4500  * @param pg handle to the peer group
4501  * @param timeout how long to wait for shutdown
4502  * @param cb callback to notify upon success or failure
4503  * @param cb_cls closure for cb
4504  */
4505 void
4506 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, 
4507                              struct GNUNET_TIME_Relative timeout,
4508                              GNUNET_TESTING_NotifyCompletion cb,
4509                              void *cb_cls)
4510 {
4511   unsigned int off;
4512   struct ShutdownContext *shutdown_ctx;
4513   struct PeerShutdownContext *peer_shutdown_ctx;
4514
4515   GNUNET_assert(pg->total > 0);
4516
4517   shutdown_ctx = GNUNET_malloc(sizeof(struct ShutdownContext));
4518   shutdown_ctx->cb = cb;
4519   shutdown_ctx->cb_cls = cb_cls;
4520   shutdown_ctx->total_peers = pg->total;
4521   shutdown_ctx->timeout = timeout;
4522   /* shtudown_ctx->outstanding = 0; */
4523
4524   for (off = 0; off < pg->total; off++)
4525     {
4526       GNUNET_assert(NULL != pg->peers[off].daemon);
4527       peer_shutdown_ctx = GNUNET_malloc(sizeof(struct PeerShutdownContext));
4528       peer_shutdown_ctx->daemon = pg->peers[off].daemon;
4529       peer_shutdown_ctx->shutdown_ctx = shutdown_ctx;
4530       GNUNET_SCHEDULER_add_now(pg->peers[off].daemon->sched, &schedule_shutdown_task, peer_shutdown_ctx);
4531       //GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, timeout, shutdown_cb, shutdown_ctx, GNUNET_YES, GNUNET_NO);
4532       if (NULL != pg->peers[off].cfg)
4533         GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
4534       if (pg->peers[off].allowed_peers != NULL)
4535         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].allowed_peers);
4536       if (pg->peers[off].connect_peers != NULL)
4537         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].connect_peers);
4538       if (pg->peers[off].blacklisted_peers != NULL)
4539         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].blacklisted_peers);
4540     }
4541   GNUNET_free (pg->peers);
4542   for (off = 0; off < pg->num_hosts; off++)
4543     {
4544       GNUNET_free (pg->hosts[off].hostname);
4545       GNUNET_free_non_null (pg->hosts[off].username);
4546     }
4547   GNUNET_free_non_null (pg->hosts);
4548   GNUNET_free (pg);
4549 }
4550
4551
4552 /* end of testing_group.c */