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