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