enable reading of hostkeys from a file for testing, also loading of topology from...
[oweals/gnunet.git] / src / testing / testing_group.c
1 /*
2       This file is part of GNUnet
3       (C) 2008, 2009 Christian Grothoff (and other contributing authors)
4
5       GNUnet is free software; you can redistribute it and/or modify
6       it under the terms of the GNU General Public License as published
7       by the Free Software Foundation; either version 3, or (at your
8       option) any later version.
9
10       GNUnet is distributed in the hope that it will be useful, but
11       WITHOUT ANY WARRANTY; without even the implied warranty of
12       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13       General Public License for more details.
14
15       You should have received a copy of the GNU General Public License
16       along with GNUnet; see the file COPYING.  If not, write to the
17       Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18       Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * @file testing/testing_group.c
23  * @brief convenience API for writing testcases for GNUnet
24  * @author Nathan Evans
25  * @author Christian Grothoff
26  *
27  */
28 #include "platform.h"
29 #include "gnunet_arm_service.h"
30 #include "gnunet_testing_lib.h"
31 #include "gnunet_core_service.h"
32
33 #define VERBOSE_TESTING GNUNET_NO
34
35 #define VERBOSE_TOPOLOGY GNUNET_YES
36
37 #define DEBUG_CHURN GNUNET_NO
38
39 /**
40  * Lowest port used for GNUnet testing.  Should be high enough to not
41  * conflict with other applications running on the hosts but be low
42  * enough to not conflict with client-ports (typically starting around
43  * 32k).
44  */
45 #define LOW_PORT 10000
46
47 /**
48  * Highest port used for GNUnet testing.  Should be low enough to not
49  * conflict with the port range for "local" ports (client apps; see
50  * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
51  */
52 #define HIGH_PORT 56000
53
54 #define MAX_OUTSTANDING_CONNECTIONS 40
55
56 #define MAX_CONCURRENT_HOSTKEYS 10
57
58 #define MAX_CONCURRENT_STARTING 10
59
60 #define MAX_CONCURRENT_SHUTDOWN 10
61
62 #define CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 200)
63
64 #define CONNECT_ATTEMPTS 21
65
66 /**
67  * Prototype of a function called whenever two peers would be connected
68  * in a certain topology.
69  */
70 typedef unsigned int (*GNUNET_TESTING_ConnectionProcessor) (struct
71                                                             GNUNET_TESTING_PeerGroup
72                                                             * pg,
73                                                             unsigned int
74                                                             first,
75                                                             unsigned int
76                                                             second);
77
78
79 /**
80  * Context for handling churning a peer group
81  */
82 struct ChurnContext
83 {
84   /**
85    * Callback used to notify of churning finished
86    */
87   GNUNET_TESTING_NotifyCompletion cb;
88
89   /**
90    * Closure for callback
91    */
92   void *cb_cls;
93
94   /**
95    * Number of peers that still need to be started
96    */
97   unsigned int num_to_start;
98
99   /**
100    * Number of peers that still need to be stopped
101    */
102   unsigned int num_to_stop;
103
104   /**
105    * Number of peers that failed to start
106    */
107   unsigned int num_failed_start;
108
109   /**
110    * Number of peers that failed to stop
111    */
112   unsigned int num_failed_stop;
113 };
114
115 struct RestartContext
116 {
117   /**
118    * The group of peers being restarted
119    */
120   struct GNUNET_TESTING_PeerGroup *peer_group;
121
122   /**
123    * How many peers have been restarted thus far
124    */
125   unsigned int peers_restarted;
126
127   /**
128    * How many peers got an error when restarting
129    */
130   unsigned int peers_restart_failed;
131
132   /**
133    * The function to call once all peers have been restarted
134    */
135   GNUNET_TESTING_NotifyCompletion callback;
136
137   /**
138    * Closure for callback function
139    */
140   void *callback_cls;
141
142 };
143
144
145 struct ShutdownContext
146 {
147   /**
148    * Total peers to wait for
149    */
150   unsigned int total_peers;
151
152   /**
153    * Number of peers successfully shut down
154    */
155   unsigned int peers_down;
156
157   /**
158    * Number of peers failed to shut down
159    */
160   unsigned int peers_failed;
161
162   /**
163    * Number of peers we have started shutting
164    * down.  If too many, wait on them.
165    */
166   unsigned int outstanding;
167
168   /**
169    * Timeout for shutdown.
170    */
171   struct GNUNET_TIME_Relative timeout;
172
173   /**
174    * Callback to call when all peers either
175    * shutdown or failed to shutdown
176    */
177   GNUNET_TESTING_NotifyCompletion cb;
178
179   /**
180    * Closure for cb
181    */
182   void *cb_cls;
183 };
184
185 /**
186  * Individual shutdown context for a particular peer.
187  */
188 struct PeerShutdownContext
189 {
190   /**
191    * Pointer to the high level shutdown context.
192    */
193   struct ShutdownContext *shutdown_ctx;
194
195   /**
196    * The daemon handle for the peer to shut down.
197    */
198   struct GNUNET_TESTING_Daemon *daemon;
199 };
200
201 /**
202  * Individual shutdown context for a particular peer.
203  */
204 struct PeerRestartContext
205 {
206   /**
207    * Pointer to the high level restart context.
208    */
209   struct ChurnRestartContext *churn_restart_ctx;
210
211   /**
212    * The daemon handle for the peer to shut down.
213    */
214   struct GNUNET_TESTING_Daemon *daemon;
215 };
216
217
218 struct CreateTopologyContext
219 {
220
221   /**
222    * Function to call with number of connections
223    */
224   GNUNET_TESTING_NotifyConnections cont;
225
226   /**
227    * Closure for connection notification
228    */
229   void *cls;
230 };
231
232 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         | GNUNET_DISK_PERM_USER_WRITE);
2156
2157   if ((0 != STAT (filename, &frstat)) || (frstat.st_size == 0))
2158     {
2159       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2160                   "Could not open file specified for topology!");
2161       return connect_attempts;
2162     }
2163
2164   data = GNUNET_malloc_large (frstat.st_size);
2165   GNUNET_assert(data != NULL);
2166   if (frstat.st_size !=
2167       GNUNET_DISK_fn_read (filename, data, frstat.st_size))
2168     {
2169       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2170                 "Could not read file %s specified for host list, ending test!", filename);
2171       GNUNET_free (data);
2172       return connect_attempts;
2173     }
2174
2175   buf = data;
2176   count = 0;
2177   /* First line should contain a single integer, specifying the number of peers */
2178   /* Each subsequent line should contain this format PEER_INDEX:OTHER_PEER_INDEX[,...] */
2179   curr_state = NUM_PEERS;
2180   while (count < frstat.st_size - 1)
2181     {
2182       if ((buf[count] == '\n') || (buf[count] == ' '))
2183       {
2184         count++;
2185         continue;
2186       }
2187
2188       switch (curr_state)
2189       {
2190         case NUM_PEERS:
2191           if (1 != sscanf(&buf[count], "%u", &total_peers))
2192             {
2193               GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to read number of peers from topology file!\n");
2194               GNUNET_free_non_null(data);
2195               return connect_attempts;
2196             }
2197           GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read %u total peers in topology\n", total_peers);
2198           GNUNET_assert(total_peers == pg->total);
2199           curr_state = PEER_INDEX;
2200           while((buf[count] != '\n') && (count < frstat.st_size - 1))
2201             count++;
2202           count++;
2203           break;
2204         case PEER_INDEX:
2205           if (1 != sscanf(&buf[count], "%u", &first_peer_index))
2206             {
2207               GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to read peer index from topology file!\n");
2208               GNUNET_free_non_null(data);
2209               return connect_attempts;
2210             }
2211           GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read next peer index %u\n", first_peer_index);
2212           while((buf[count] != ':') && (count < frstat.st_size - 1))
2213             count++;
2214           count++;
2215           curr_state = OTHER_PEER_INDEX;
2216           break;
2217         case COLON:
2218           if (1 == sscanf(&buf[count], ":"))
2219             curr_state = OTHER_PEER_INDEX;
2220           count++;
2221           break;
2222         case OTHER_PEER_INDEX:
2223           if (1 != sscanf(&buf[count], "%u", &second_peer_index))
2224             {
2225               GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Failed to peer index from topology file!\n");
2226               GNUNET_free_non_null(data);
2227               return connect_attempts;
2228             }
2229           GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Read second peer index %u\n", second_peer_index);
2230           /* Assume file is written with first peer 1, but array index is 0 */
2231           connect_attempts += proc (pg, first_peer_index - 1, second_peer_index - 1);
2232           while((buf[count] != '\n') && (buf[count] != ',') && (count < frstat.st_size - 1))
2233             count++;
2234           if (buf[count] == '\n')
2235           {
2236             curr_state = PEER_INDEX;
2237           }
2238           else if (buf[count] != ',')
2239           {
2240             curr_state = OTHER_PEER_INDEX;
2241           }
2242           count++;
2243           break;
2244         default:
2245           GNUNET_log(GNUNET_ERROR_TYPE_ERROR, "Found bad data in topology file while in state %d!\n", curr_state);
2246           GNUNET_break(0);
2247           return connect_attempts;
2248       }
2249
2250     }
2251 #if 0
2252   /* Connect each peer to the next highest numbered peer */
2253   for (count = 0; count < pg->total - 1; count++)
2254     {
2255 #if VERBOSE_TESTING
2256       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2257                   "Connecting peer %d to peer %d\n", first_peer_index, second_peer_index);
2258 #endif
2259       connect_attempts += proc (pg, first_peer_index, second_peer_index);
2260     }
2261 #endif
2262   return connect_attempts;
2263 }
2264
2265 /**
2266  * Create a topology given a peer group (set of running peers)
2267  * and a connection processor.
2268  *
2269  * @param pg the peergroup to create the topology on
2270  * @param proc the connection processor to call to actually set
2271  *        up connections between two peers
2272  *
2273  * @return the number of connections that were set up
2274  *
2275  */
2276 static unsigned int
2277 create_ring (struct GNUNET_TESTING_PeerGroup *pg,
2278              GNUNET_TESTING_ConnectionProcessor proc)
2279 {
2280   unsigned int count;
2281   int connect_attempts;
2282
2283   connect_attempts = 0;
2284
2285   /* Connect each peer to the next highest numbered peer */
2286   for (count = 0; count < pg->total - 1; count++)
2287     {
2288 #if VERBOSE_TESTING
2289       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2290                   "Connecting peer %d to peer %d\n", count, count + 1);
2291 #endif
2292       connect_attempts += proc (pg, count, count + 1);
2293     }
2294
2295   /* Connect the last peer to the first peer */
2296   connect_attempts += proc (pg, pg->total - 1, 0);
2297
2298   return connect_attempts;
2299 }
2300
2301
2302 /**
2303  * Iterator for writing friends of a peer to a file.
2304  *
2305  * @param cls closure, an open writable file handle
2306  * @param key the key the daemon was stored under
2307  * @param value the GNUNET_TESTING_Daemon that needs to be written.
2308  *
2309  * @return GNUNET_YES to continue iteration
2310  *
2311  * TODO: Could replace friend_file_iterator and blacklist_file_iterator
2312  *       with a single file_iterator that takes a closure which contains
2313  *       the prefix to write before the peer.  Then this could be used
2314  *       for blacklisting multiple transports and writing the friend
2315  *       file.  I'm sure *someone* will complain loudly about other
2316  *       things that negate these functions even existing so no point in
2317  *       "fixing" now.
2318  */
2319 static int
2320 friend_file_iterator (void *cls, const GNUNET_HashCode * key, void *value)
2321 {
2322   FILE *temp_friend_handle = cls;
2323   struct GNUNET_TESTING_Daemon *peer = value;
2324   struct GNUNET_PeerIdentity *temppeer;
2325   struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
2326
2327   temppeer = &peer->id;
2328   GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc);
2329   fprintf (temp_friend_handle, "%s\n", (char *) &peer_enc);
2330
2331   return GNUNET_YES;
2332 }
2333
2334 struct BlacklistContext
2335 {
2336   /*
2337    * The (open) file handle to write to
2338    */
2339   FILE *temp_file_handle;
2340
2341   /*
2342    * The transport that this peer will be blacklisted on.
2343    */
2344   char *transport;
2345 };
2346
2347 /**
2348  * Iterator for writing blacklist data to appropriate files.
2349  *
2350  * @param cls closure, an open writable file handle
2351  * @param key the key the daemon was stored under
2352  * @param value the GNUNET_TESTING_Daemon that needs to be written.
2353  *
2354  * @return GNUNET_YES to continue iteration
2355  */
2356 static int
2357 blacklist_file_iterator (void *cls, const GNUNET_HashCode * key, void *value)
2358 {
2359   struct BlacklistContext *blacklist_ctx = cls;
2360   struct GNUNET_TESTING_Daemon *peer = value;
2361   struct GNUNET_PeerIdentity *temppeer;
2362   struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
2363
2364   temppeer = &peer->id;
2365   GNUNET_CRYPTO_hash_to_enc (&temppeer->hashPubKey, &peer_enc);
2366   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Writing entry %s:%s to file\n", blacklist_ctx->transport, (char *) &peer_enc);
2367   fprintf (blacklist_ctx->temp_file_handle, "%s:%s\n",
2368            blacklist_ctx->transport, (char *) &peer_enc);
2369
2370   return GNUNET_YES;
2371 }
2372
2373 /*
2374  * Create the friend files based on the PeerConnection's
2375  * of each peer in the peer group, and copy the files
2376  * to the appropriate place
2377  *
2378  * @param pg the peer group we are dealing with
2379  */
2380 static int
2381 create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
2382 {
2383   FILE *temp_friend_handle;
2384   unsigned int pg_iter;
2385   char *temp_service_path;
2386   struct GNUNET_OS_Process **procarr;
2387   char *arg;
2388   char *mytemp;
2389   enum GNUNET_OS_ProcessStatusType type;
2390   unsigned long return_code;
2391   int count;
2392   int ret;
2393   int max_wait = 10;
2394
2395   procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total);
2396   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2397     {
2398       mytemp = GNUNET_DISK_mktemp ("friends");
2399       GNUNET_assert (mytemp != NULL);
2400       temp_friend_handle = fopen (mytemp, "wt");
2401       GNUNET_assert (temp_friend_handle != NULL);
2402       GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].allowed_peers,
2403                                              &friend_file_iterator,
2404                                              temp_friend_handle);
2405       fclose (temp_friend_handle);
2406
2407       if (GNUNET_OK !=
2408           GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].
2409                                                  daemon->cfg, "PATHS",
2410                                                  "SERVICEHOME",
2411                                                  &temp_service_path))
2412         {
2413           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2414                       _
2415                       ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
2416                       "SERVICEHOME", "PATHS");
2417           if (UNLINK (mytemp) != 0)
2418             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink",
2419                                       mytemp);
2420           GNUNET_free (mytemp);
2421           break;
2422         }
2423
2424       if (pg->peers[pg_iter].daemon->hostname == NULL)  /* Local, just copy the file */
2425         {
2426           GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
2427           procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
2428                                                       "mv", mytemp, arg,
2429                                                       NULL);
2430 #if VERBOSE_TESTING
2431           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2432                       _("Copying file with command cp %s %s\n"), mytemp, arg);
2433 #endif
2434
2435           GNUNET_free (arg);
2436         }
2437       else                      /* Remote, scp the file to the correct place */
2438         {
2439           if (NULL != pg->peers[pg_iter].daemon->username)
2440             GNUNET_asprintf (&arg, "%s@%s:%s/friends",
2441                              pg->peers[pg_iter].daemon->username,
2442                              pg->peers[pg_iter].daemon->hostname,
2443                              temp_service_path);
2444           else
2445             GNUNET_asprintf (&arg, "%s:%s/friends",
2446                              pg->peers[pg_iter].daemon->hostname,
2447                              temp_service_path);
2448           procarr[pg_iter] =
2449             GNUNET_OS_start_process (NULL, NULL, "scp", "scp", mytemp, arg,
2450                                      NULL);
2451
2452 #if VERBOSE_TESTING
2453           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2454                       _("Copying file with command scp %s %s\n"), mytemp,
2455                       arg);
2456 #endif
2457           GNUNET_free (arg);
2458         }
2459       GNUNET_free (temp_service_path);
2460       GNUNET_free (mytemp);
2461     }
2462
2463   count = 0;
2464   ret = GNUNET_SYSERR;
2465   while ((count < max_wait) && (ret != GNUNET_OK))
2466     {
2467       ret = GNUNET_OK;
2468       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2469         {
2470 #if VERBOSE_TESTING
2471           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2472                       _("Checking copy status of file %d\n"), pg_iter);
2473 #endif
2474           if (procarr[pg_iter] != NULL) /* Check for already completed! */
2475             {
2476               if (GNUNET_OS_process_status
2477                   (procarr[pg_iter], &type, &return_code) != GNUNET_OK)
2478                 {
2479                   ret = GNUNET_SYSERR;
2480                 }
2481               else if ((type != GNUNET_OS_PROCESS_EXITED)
2482                        || (return_code != 0))
2483                 {
2484                   ret = GNUNET_SYSERR;
2485                 }
2486               else
2487                 {
2488                   GNUNET_OS_process_close (procarr[pg_iter]);
2489                   procarr[pg_iter] = NULL;
2490 #if VERBOSE_TESTING
2491                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2492                               _("File %d copied\n"), pg_iter);
2493 #endif
2494                 }
2495             }
2496         }
2497       count++;
2498       if (ret == GNUNET_SYSERR)
2499         {
2500           /* FIXME: why sleep here? -CG */
2501           sleep (1);
2502         }
2503     }
2504
2505 #if VERBOSE_TESTING
2506   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2507               _("Finished copying all friend files!\n"));
2508 #endif
2509   GNUNET_free (procarr);
2510   return ret;
2511 }
2512
2513
2514 /*
2515  * Create the blacklist files based on the PeerConnection's
2516  * of each peer in the peer group, and copy the files
2517  * to the appropriate place.
2518  *
2519  * @param pg the peer group we are dealing with
2520  * @param transports space delimited list of transports to blacklist
2521  */
2522 static int
2523 create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg,
2524                                  const char *transports)
2525 {
2526   FILE *temp_file_handle;
2527   static struct BlacklistContext blacklist_ctx;
2528   unsigned int pg_iter;
2529   char *temp_service_path;
2530   struct GNUNET_OS_Process **procarr;
2531   char *arg;
2532   char *mytemp;
2533   enum GNUNET_OS_ProcessStatusType type;
2534   unsigned long return_code;
2535   int count;
2536   int ret;
2537   int max_wait = 10;
2538   int transport_len;
2539   unsigned int i;
2540   char *pos;
2541   char *temp_transports;
2542   int entry_count;
2543
2544   procarr = GNUNET_malloc (sizeof (struct GNUNET_OS_Process *) * pg->total);
2545   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2546     {
2547       mytemp = GNUNET_DISK_mktemp ("blacklist");
2548       GNUNET_assert (mytemp != NULL);
2549       temp_file_handle = fopen (mytemp, "wt");
2550       GNUNET_assert (temp_file_handle != NULL);
2551       temp_transports = GNUNET_strdup (transports);
2552       blacklist_ctx.temp_file_handle = temp_file_handle;
2553       transport_len = strlen (temp_transports) + 1;
2554       pos = NULL;
2555
2556       for (i = 0; i < transport_len; i++)
2557         {
2558           if ((temp_transports[i] == ' ') && (pos == NULL))
2559             continue;           /* At start of string (whitespace) */
2560           else if ((temp_transports[i] == ' ') || (temp_transports[i] == '\0')) /* At end of string */
2561             {
2562               temp_transports[i] = '\0';
2563               blacklist_ctx.transport = pos;
2564               entry_count = GNUNET_CONTAINER_multihashmap_iterate (pg->
2565                                                      peers
2566                                                      [pg_iter].blacklisted_peers,
2567                                                      &blacklist_file_iterator,
2568                                                      &blacklist_ctx);
2569               pos = NULL;
2570             }                   /* At beginning of actual string */
2571           else if (pos == NULL)
2572             {
2573               pos = &temp_transports[i];
2574             }
2575         }
2576
2577       GNUNET_free (temp_transports);
2578       fclose (temp_file_handle);
2579
2580       if (GNUNET_OK !=
2581           GNUNET_CONFIGURATION_get_value_string (pg->peers[pg_iter].
2582                                                  daemon->cfg, "PATHS",
2583                                                  "SERVICEHOME",
2584                                                  &temp_service_path))
2585         {
2586           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2587                       _
2588                       ("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
2589                       "SERVICEHOME", "PATHS");
2590           if (UNLINK (mytemp) != 0)
2591             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink",
2592                                       mytemp);
2593           GNUNET_free (mytemp);
2594           break;
2595         }
2596
2597       if (pg->peers[pg_iter].daemon->hostname == NULL)  /* Local, just copy the file */
2598         {
2599           GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path);
2600           procarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
2601                                                       "mv", mytemp, arg,
2602                                                       NULL);
2603 #if VERBOSE_TESTING
2604           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2605                       _("Copying file with command cp %s %s\n"), mytemp, arg);
2606 #endif
2607
2608           GNUNET_free (arg);
2609         }
2610       else                      /* Remote, scp the file to the correct place */
2611         {
2612           if (NULL != pg->peers[pg_iter].daemon->username)
2613             GNUNET_asprintf (&arg, "%s@%s:%s/blacklist",
2614                              pg->peers[pg_iter].daemon->username,
2615                              pg->peers[pg_iter].daemon->hostname,
2616                              temp_service_path);
2617           else
2618             GNUNET_asprintf (&arg, "%s:%s/blacklist",
2619                              pg->peers[pg_iter].daemon->hostname,
2620                              temp_service_path);
2621           procarr[pg_iter] =
2622             GNUNET_OS_start_process (NULL, NULL, "scp", "scp", mytemp, arg,
2623                                      NULL);
2624
2625 #if VERBOSE_TESTING
2626           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2627                       _("Copying file with command scp %s %s\n"), mytemp,
2628                       arg);
2629 #endif
2630           GNUNET_free (arg);
2631         }
2632       GNUNET_free (temp_service_path);
2633       GNUNET_free (mytemp);
2634     }
2635
2636   count = 0;
2637   ret = GNUNET_SYSERR;
2638   while ((count < max_wait) && (ret != GNUNET_OK))
2639     {
2640       ret = GNUNET_OK;
2641       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2642         {
2643 #if VERBOSE_TESTING
2644           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2645                       _("Checking copy status of file %d\n"), pg_iter);
2646 #endif
2647           if (procarr[pg_iter] != NULL) /* Check for already completed! */
2648             {
2649               if (GNUNET_OS_process_status
2650                   (procarr[pg_iter], &type, &return_code) != GNUNET_OK)
2651                 {
2652                   ret = GNUNET_SYSERR;
2653                 }
2654               else if ((type != GNUNET_OS_PROCESS_EXITED)
2655                        || (return_code != 0))
2656                 {
2657                   ret = GNUNET_SYSERR;
2658                 }
2659               else
2660                 {
2661                   GNUNET_OS_process_close (procarr[pg_iter]);
2662                   procarr[pg_iter] = NULL;
2663 #if VERBOSE_TESTING
2664                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2665                               _("File %d copied\n"), pg_iter);
2666 #endif
2667                 }
2668             }
2669         }
2670       count++;
2671       if (ret == GNUNET_SYSERR)
2672         {
2673           /* FIXME: why sleep here? -CG */
2674           sleep (1);
2675         }
2676     }
2677
2678 #if VERBOSE_TESTING
2679   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2680               _("Finished copying all blacklist files!\n"));
2681 #endif
2682   GNUNET_free (procarr);
2683   return ret;
2684 }
2685
2686
2687 /**
2688  * Internal notification of a connection, kept so that we can ensure some connections
2689  * happen instead of flooding all testing daemons with requests to connect.
2690  */
2691 static void
2692 internal_connect_notify (void *cls,
2693                          const struct GNUNET_PeerIdentity *first,
2694                          const struct GNUNET_PeerIdentity *second,
2695                          uint32_t distance,
2696                          const struct GNUNET_CONFIGURATION_Handle *first_cfg,
2697                          const struct GNUNET_CONFIGURATION_Handle *second_cfg,
2698                          struct GNUNET_TESTING_Daemon *first_daemon,
2699                          struct GNUNET_TESTING_Daemon *second_daemon,
2700                          const char *emsg)
2701 {
2702   struct ConnectTopologyContext *ct_ctx = cls;
2703   struct GNUNET_TESTING_PeerGroup *pg = ct_ctx->pg;
2704   outstanding_connects--;
2705   ct_ctx->remaining_connections--;
2706   if (ct_ctx->remaining_connections == 0)
2707     {
2708       if (ct_ctx->notify_connections_done != NULL)
2709         ct_ctx->notify_connections_done (ct_ctx->notify_cls, NULL);
2710       GNUNET_free (ct_ctx);
2711     }
2712
2713   if (pg->notify_connection != NULL)
2714     pg->notify_connection (pg->notify_connection_cls, first, second, distance,
2715                            first_cfg, second_cfg, first_daemon, second_daemon,
2716                            emsg);
2717 }
2718
2719
2720 /**
2721  * Either delay a connection (because there are too many outstanding)
2722  * or schedule it for right now.
2723  *
2724  * @param cls a connection context
2725  * @param tc the task runtime context
2726  */
2727 static void
2728 schedule_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2729 {
2730   struct ConnectContext *connect_context = cls;
2731
2732   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2733     return;
2734
2735   if (outstanding_connects > MAX_OUTSTANDING_CONNECTIONS)
2736     {
2737 #if VERBOSE_TESTING > 2
2738       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2739                   _
2740                   ("Delaying connect, we have too many outstanding connections!\n"));
2741 #endif
2742       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
2743                                     (GNUNET_TIME_UNIT_MILLISECONDS, 100),
2744                                     &schedule_connect, connect_context);
2745     }
2746   else
2747     {
2748 #if VERBOSE_TESTING > 2
2749       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2750                   _("Creating connection, outstanding_connections is %d\n"),
2751                   outstanding_connects);
2752 #endif
2753       outstanding_connects++;
2754       GNUNET_TESTING_daemons_connect (connect_context->first,
2755                                       connect_context->second,
2756                                       CONNECT_TIMEOUT,
2757                                       CONNECT_ATTEMPTS,
2758                                       &internal_connect_notify,
2759                                       connect_context->ct_ctx);
2760       GNUNET_free (connect_context);
2761     }
2762 }
2763
2764
2765 /**
2766  * Iterator for actually scheduling connections to be created
2767  * between two peers.
2768  *
2769  * @param cls closure, a GNUNET_TESTING_Daemon
2770  * @param key the key the second Daemon was stored under
2771  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2772  *
2773  * @return GNUNET_YES to continue iteration
2774  */
2775 static int
2776 connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
2777 {
2778   struct ConnectTopologyContext *ct_ctx = cls;
2779   struct PeerData *first = ct_ctx->first;
2780   struct GNUNET_TESTING_Daemon *second = value;
2781   struct ConnectContext *connect_context;
2782
2783   connect_context = GNUNET_malloc (sizeof (struct ConnectContext));
2784   connect_context->first = first->daemon;
2785   connect_context->second = second;
2786   connect_context->ct_ctx = ct_ctx;
2787   GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context);
2788
2789   return GNUNET_YES;
2790 }
2791
2792
2793 /**
2794  * Iterator for copying all entries in the allowed hashmap to the
2795  * connect hashmap.
2796  *
2797  * @param cls closure, a GNUNET_TESTING_Daemon
2798  * @param key the key the second Daemon was stored under
2799  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2800  *
2801  * @return GNUNET_YES to continue iteration
2802  */
2803 static int
2804 copy_topology_iterator (void *cls, const GNUNET_HashCode * key, void *value)
2805 {
2806   struct PeerData *first = cls;
2807
2808   GNUNET_assert (GNUNET_OK ==
2809                  GNUNET_CONTAINER_multihashmap_put (first->connect_peers, key,
2810                                                     value,
2811                                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2812
2813   return GNUNET_YES;
2814 }
2815
2816 /**
2817  * Make the peers to connect the same as those that are allowed to be
2818  * connected.
2819  *
2820  * @param pg the peer group
2821  */
2822 static int
2823 copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg)
2824 {
2825   unsigned int pg_iter;
2826   int ret;
2827   int total;
2828
2829   total = 0;
2830   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2831     {
2832       ret =
2833         GNUNET_CONTAINER_multihashmap_iterate (pg->
2834                                                peers[pg_iter].allowed_peers,
2835                                                &copy_topology_iterator,
2836                                                &pg->peers[pg_iter]);
2837       if (GNUNET_SYSERR == ret)
2838         return GNUNET_SYSERR;
2839
2840       total = total + ret;
2841     }
2842
2843   return total;
2844 }
2845
2846
2847 /**
2848  * Connect the topology as specified by the PeerConnection's
2849  * of each peer in the peer group
2850  *
2851  * @param pg the peer group we are dealing with
2852  * @param notify_callback callback to notify when finished
2853  * @param notify_cls closure for notify callback
2854  *
2855  * @return the number of connections that will be attempted
2856  */
2857 static int
2858 connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
2859                   GNUNET_TESTING_NotifyCompletion notify_callback,
2860                   void *notify_cls)
2861 {
2862   unsigned int pg_iter;
2863   int ret;
2864   unsigned int total;
2865   struct ConnectTopologyContext *ct_ctx;
2866 #if OLD
2867   struct PeerConnection *connection_iter;
2868   struct ConnectContext *connect_context;
2869 #endif
2870
2871   total = 0;
2872   ct_ctx = GNUNET_malloc (sizeof (struct ConnectTopologyContext));
2873   ct_ctx->notify_connections_done = notify_callback;
2874   ct_ctx->notify_cls = notify_cls;
2875   ct_ctx->pg = pg;
2876
2877   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2878     {
2879       total +=
2880         GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers);
2881     }
2882
2883   if (total == 0)
2884     {
2885       GNUNET_free (ct_ctx);
2886       return total;
2887     }
2888   ct_ctx->remaining_connections = total;
2889   total = 0;
2890
2891   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2892     {
2893       ct_ctx->first = &pg->peers[pg_iter];
2894       ret =
2895         GNUNET_CONTAINER_multihashmap_iterate (pg->
2896                                                peers[pg_iter].connect_peers,
2897                                                &connect_iterator, ct_ctx);
2898       GNUNET_assert (GNUNET_SYSERR != ret && ret >= 0);
2899       total = total + ret;
2900
2901 #if OLD
2902       connection_iter = FIXME;
2903       while (connection_iter != NULL)
2904         {
2905           connect_context = GNUNET_malloc (sizeof (struct ConnectContext));
2906           connect_context->pg = pg;
2907           connect_context->first = FIXME;
2908           connect_context->second = connection_iter->daemon;
2909           GNUNET_SCHEDULER_add_now (&schedule_connect, connect_context);
2910           connection_iter = connection_iter->next;
2911         }
2912 #endif
2913     }
2914   return total;
2915 }
2916
2917
2918 /**
2919  * Takes a peer group and creates a topology based on the
2920  * one specified.  Creates a topology means generates friend
2921  * files for the peers so they can only connect to those allowed
2922  * by the topology.  This will only have an effect once peers
2923  * are started if the FRIENDS_ONLY option is set in the base
2924  * config.  Also takes an optional restrict topology which
2925  * disallows connections based on particular transports
2926  * UNLESS they are specified in the restricted topology.
2927  *
2928  * @param pg the peer group struct representing the running peers
2929  * @param topology which topology to connect the peers in
2930  * @param restrict_topology disallow restrict_transports transport
2931  *                          connections to peers NOT in this topology
2932  *                          use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions
2933  * @param restrict_transports space delimited list of transports to blacklist
2934  *                            to create restricted topology
2935  *
2936  * @return the maximum number of connections were all allowed peers
2937  *         connected to each other
2938  */
2939 unsigned int
2940 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg,
2941                                 enum GNUNET_TESTING_Topology topology,
2942                                 enum GNUNET_TESTING_Topology
2943                                 restrict_topology,
2944                                 const char *restrict_transports)
2945 {
2946   int ret;
2947   unsigned int num_connections;
2948   int unblacklisted_connections;
2949   char *filename;
2950
2951   switch (topology)
2952     {
2953     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2954 #if VERBOSE_TESTING
2955       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating clique topology\n"));
2956 #endif
2957       num_connections = create_clique (pg, &add_allowed_connections);
2958       break;
2959     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2960 #if VERBOSE_TESTING
2961       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2962                   _("Creating small world (ring) topology\n"));
2963 #endif
2964       num_connections =
2965         create_small_world_ring (pg, &add_allowed_connections);
2966       break;
2967     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2968 #if VERBOSE_TESTING
2969       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2970                   _("Creating small world (2d-torus) topology\n"));
2971 #endif
2972       num_connections = create_small_world (pg, &add_allowed_connections);
2973       break;
2974     case GNUNET_TESTING_TOPOLOGY_RING:
2975 #if VERBOSE_TESTING
2976       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating ring topology\n"));
2977 #endif
2978       num_connections = create_ring (pg, &add_allowed_connections);
2979       break;
2980     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2981 #if VERBOSE_TESTING
2982       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating 2d torus topology\n"));
2983 #endif
2984       num_connections = create_2d_torus (pg, &add_allowed_connections);
2985       break;
2986     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2987 #if VERBOSE_TESTING
2988       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2989                   _("Creating Erdos-Renyi topology\n"));
2990 #endif
2991       num_connections = create_erdos_renyi (pg, &add_allowed_connections);
2992       break;
2993     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2994 #if VERBOSE_TESTING
2995       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Creating InterNAT topology\n"));
2996 #endif
2997       num_connections = create_nated_internet (pg, &add_allowed_connections);
2998       break;
2999     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
3000 #if VERBOSE_TESTING
3001       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3002                   _("Creating Scale Free topology\n"));
3003 #endif
3004       num_connections = create_scale_free (pg, &add_allowed_connections);
3005       break;
3006     case GNUNET_TESTING_TOPOLOGY_LINE:
3007 #if VERBOSE_TESTING
3008       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3009                   _("Creating straight line topology\n"));
3010 #endif
3011       num_connections = create_line (pg, &add_allowed_connections);
3012       break;
3013     case GNUNET_TESTING_TOPOLOGY_FROM_FILE:
3014 #if VERBOSE_TESTING
3015       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3016                   _("Creating topology from file!\n"));
3017 #endif
3018       if (GNUNET_OK ==
3019           GNUNET_CONFIGURATION_get_value_string (pg->cfg, "testing", "topology_file",
3020                                                  &filename))
3021         num_connections = create_from_file (pg, filename, &add_allowed_connections);
3022       else
3023       {
3024         GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Missing configuration option TESTING:TOPOLOGY_FILE for creating topology from file!");
3025         num_connections = 0;
3026       }
3027       break;
3028     case GNUNET_TESTING_TOPOLOGY_NONE:
3029 #if VERBOSE_TESTING
3030       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3031                   _
3032                   ("Creating no allowed topology (all peers can connect at core level)\n"));
3033 #endif
3034       num_connections = 0;
3035       break;
3036     default:
3037       num_connections = 0;
3038       break;
3039     }
3040
3041   if (GNUNET_YES ==
3042       GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
3043     {
3044       ret = create_and_copy_friend_files (pg);
3045       if (ret != GNUNET_OK)
3046         {
3047 #if VERBOSE_TESTING
3048           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3049                       _("Failed during friend file copying!\n"));
3050 #endif
3051           return GNUNET_SYSERR;
3052         }
3053       else
3054         {
3055 #if VERBOSE_TESTING
3056           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3057                       _("Friend files created/copied successfully!\n"));
3058 #endif
3059         }
3060     }
3061
3062   /* Use the create clique method to initially set all connections as blacklisted. */
3063   create_clique (pg, &blacklist_connections);
3064
3065   unblacklisted_connections = 0;
3066   /* Un-blacklist connections as per the topology specified */
3067   switch (restrict_topology)
3068     {
3069     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
3070 #if VERBOSE_TESTING
3071       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3072                   _("Blacklisting all but clique topology\n"));
3073 #endif
3074       unblacklisted_connections =
3075         create_clique (pg, &unblacklist_connections);
3076       break;
3077     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
3078 #if VERBOSE_TESTING
3079       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3080                   _("Blacklisting all but small world (ring) topology\n"));
3081 #endif
3082       unblacklisted_connections =
3083         create_small_world_ring (pg, &unblacklist_connections);
3084       break;
3085     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
3086 #if VERBOSE_TESTING
3087       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3088                   _
3089                   ("Blacklisting all but small world (2d-torus) topology\n"));
3090 #endif
3091       unblacklisted_connections =
3092         create_small_world (pg, &unblacklist_connections);
3093       break;
3094     case GNUNET_TESTING_TOPOLOGY_RING:
3095 #if VERBOSE_TESTING
3096       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3097                   _("Blacklisting all but ring topology\n"));
3098 #endif
3099       unblacklisted_connections = create_ring (pg, &unblacklist_connections);
3100       break;
3101     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
3102 #if VERBOSE_TESTING
3103       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3104                   _("Blacklisting all but 2d torus topology\n"));
3105 #endif
3106       unblacklisted_connections =
3107         create_2d_torus (pg, &unblacklist_connections);
3108       break;
3109     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
3110 #if VERBOSE_TESTING
3111       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3112                   _("Blacklisting all but Erdos-Renyi topology\n"));
3113 #endif
3114       unblacklisted_connections =
3115         create_erdos_renyi (pg, &unblacklist_connections);
3116       break;
3117     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
3118 #if VERBOSE_TESTING
3119       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3120                   _("Blacklisting all but InterNAT topology\n"));
3121 #endif
3122       unblacklisted_connections =
3123         create_nated_internet (pg, &unblacklist_connections);
3124       break;
3125     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
3126 #if VERBOSE_TESTING
3127       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3128                   _("Blacklisting all but Scale Free topology\n"));
3129 #endif
3130       unblacklisted_connections =
3131         create_scale_free (pg, &unblacklist_connections);
3132       break;
3133     case GNUNET_TESTING_TOPOLOGY_LINE:
3134 #if VERBOSE_TESTING
3135       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3136                   _("Blacklisting all but straight line topology\n"));
3137 #endif
3138       unblacklisted_connections = create_line (pg, &unblacklist_connections);
3139       break;
3140     case GNUNET_TESTING_TOPOLOGY_NONE:
3141     case GNUNET_TESTING_TOPOLOGY_FROM_FILE:
3142 #if VERBOSE_TESTING
3143       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3144                   _
3145                   ("Creating no blacklist topology (all peers can connect at transport level)\n"));
3146 #endif
3147     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3148                 _
3149                 ("Creating blacklist topology from allowed\n"));
3150     unblacklisted_connections = copy_allowed (pg, &unblacklist_connections);
3151     default:
3152       break;
3153     }
3154
3155   if ((unblacklisted_connections > 0) && (restrict_transports != NULL))
3156     {
3157       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Creating blacklist with `%s'", restrict_transports);
3158       ret = create_and_copy_blacklist_files (pg, restrict_transports);
3159       if (ret != GNUNET_OK)
3160         {
3161 #if VERBOSE_TESTING
3162           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3163                       _("Failed during blacklist file copying!\n"));
3164 #endif
3165           return 0;
3166         }
3167       else
3168         {
3169 #if VERBOSE_TESTING
3170           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3171                       _("Blacklist files created/copied successfully!\n"));
3172 #endif
3173         }
3174     }
3175   return num_connections;
3176 }
3177
3178
3179 /**
3180  * Iterator for choosing random peers to connect.
3181  *
3182  * @param cls closure, a RandomContext
3183  * @param key the key the second Daemon was stored under
3184  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
3185  *
3186  * @return GNUNET_YES to continue iteration
3187  */
3188 static int
3189 random_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
3190 {
3191   struct RandomContext *random_ctx = cls;
3192   double random_number;
3193   uint32_t second_pos;
3194   GNUNET_HashCode first_hash;
3195   random_number =
3196     ((double)
3197      GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
3198                                UINT64_MAX)) / ((double) UINT64_MAX);
3199   if (random_number < random_ctx->percentage)
3200     {
3201       GNUNET_assert (GNUNET_OK ==
3202                      GNUNET_CONTAINER_multihashmap_put (random_ctx->
3203                                                         first->connect_peers_working_set,
3204                                                         key, value,
3205                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3206     }
3207   /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */
3208   uid_from_hash (key, &second_pos);
3209   hash_from_uid (random_ctx->first_uid, &first_hash);
3210   GNUNET_assert (random_ctx->pg->total > second_pos);
3211   GNUNET_assert (GNUNET_YES ==
3212                  GNUNET_CONTAINER_multihashmap_remove (random_ctx->
3213                                                        pg->peers
3214                                                        [second_pos].connect_peers,
3215                                                        &first_hash,
3216                                                        random_ctx->
3217                                                        first->daemon));
3218
3219   return GNUNET_YES;
3220 }
3221
3222 /**
3223  * Iterator for adding at least X peers to a peers connection set.
3224  *
3225  * @param cls closure, MinimumContext
3226  * @param key the key the second Daemon was stored under
3227  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
3228  *
3229  * @return GNUNET_YES to continue iteration
3230  */
3231 static int
3232 minimum_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
3233 {
3234   struct MinimumContext *min_ctx = cls;
3235   uint32_t second_pos;
3236   GNUNET_HashCode first_hash;
3237   unsigned int i;
3238
3239   if (GNUNET_CONTAINER_multihashmap_size
3240       (min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add)
3241     {
3242       for (i = 0; i < min_ctx->num_to_add; i++)
3243         {
3244           if (min_ctx->pg_array[i] == min_ctx->current)
3245             {
3246               GNUNET_assert (GNUNET_OK ==
3247                              GNUNET_CONTAINER_multihashmap_put
3248                              (min_ctx->first->connect_peers_working_set, key,
3249                               value,
3250                               GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3251               uid_from_hash (key, &second_pos);
3252               hash_from_uid (min_ctx->first_uid, &first_hash);
3253               GNUNET_assert (min_ctx->pg->total > second_pos);
3254               GNUNET_assert (GNUNET_OK ==
3255                              GNUNET_CONTAINER_multihashmap_put (min_ctx->
3256                                                                 pg->peers
3257                                                                 [second_pos].connect_peers_working_set,
3258                                                                 &first_hash,
3259                                                                 min_ctx->first->
3260                                                                 daemon,
3261                                                                 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3262               /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */
3263               GNUNET_assert (GNUNET_YES ==
3264                              GNUNET_CONTAINER_multihashmap_remove
3265                              (min_ctx->pg->peers[second_pos].connect_peers,
3266                               &first_hash, min_ctx->first->daemon));
3267             }
3268         }
3269       min_ctx->current++;
3270       return GNUNET_YES;
3271     }
3272   else
3273     return GNUNET_NO;           /* We can stop iterating, we have enough peers! */
3274
3275 }
3276
3277
3278 /**
3279  * Iterator for adding peers to a connection set based on a depth first search.
3280  *
3281  * @param cls closure, MinimumContext
3282  * @param key the key the second daemon was stored under
3283  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
3284  *
3285  * @return GNUNET_YES to continue iteration
3286  */
3287 static int
3288 dfs_connect_iterator (void *cls, const GNUNET_HashCode * key, void *value)
3289 {
3290   struct DFSContext *dfs_ctx = cls;
3291   GNUNET_HashCode first_hash;
3292
3293   if (dfs_ctx->current == dfs_ctx->chosen)
3294     {
3295       GNUNET_assert (GNUNET_OK ==
3296                      GNUNET_CONTAINER_multihashmap_put (dfs_ctx->
3297                                                         first->connect_peers_working_set,
3298                                                         key, value,
3299                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3300       uid_from_hash (key, &dfs_ctx->second_uid);
3301       hash_from_uid (dfs_ctx->first_uid, &first_hash);
3302       GNUNET_assert (GNUNET_OK ==
3303                      GNUNET_CONTAINER_multihashmap_put (dfs_ctx->
3304                                                         pg->peers
3305                                                         [dfs_ctx->second_uid].connect_peers_working_set,
3306                                                         &first_hash,
3307                                                         dfs_ctx->
3308                                                         first->daemon,
3309                                                         GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3310       GNUNET_assert (GNUNET_YES ==
3311                      GNUNET_CONTAINER_multihashmap_remove (dfs_ctx->
3312                                                            pg->peers
3313                                                            [dfs_ctx->second_uid].connect_peers,
3314                                                            &first_hash,
3315                                                            dfs_ctx->
3316                                                            first->daemon));
3317       /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */
3318       return GNUNET_NO;         /* We have found our peer, don't iterate more */
3319     }
3320
3321   dfs_ctx->current++;
3322   return GNUNET_YES;
3323 }
3324
3325
3326 /**
3327  * From the set of connections possible, choose percentage percent of connections
3328  * to actually connect.
3329  *
3330  * @param pg the peergroup we are dealing with
3331  * @param percentage what percent of total connections to make
3332  */
3333 void
3334 choose_random_connections (struct GNUNET_TESTING_PeerGroup *pg,
3335                            double percentage)
3336 {
3337   struct RandomContext random_ctx;
3338   uint32_t pg_iter;
3339
3340   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3341     {
3342       random_ctx.first_uid = pg_iter;
3343       random_ctx.first = &pg->peers[pg_iter];
3344       random_ctx.percentage = percentage;
3345       random_ctx.pg = pg;
3346       pg->peers[pg_iter].connect_peers_working_set =
3347         GNUNET_CONTAINER_multihashmap_create (pg->total);
3348       GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers,
3349                                              &random_connect_iterator,
3350                                              &random_ctx);
3351       /* Now remove the old connections */
3352       GNUNET_CONTAINER_multihashmap_destroy (pg->
3353                                              peers[pg_iter].connect_peers);
3354       /* And replace with the random set */
3355       pg->peers[pg_iter].connect_peers =
3356         pg->peers[pg_iter].connect_peers_working_set;
3357     }
3358 }
3359
3360 /**
3361  * From the set of connections possible, choose at least num connections per
3362  * peer.
3363  *
3364  * @param pg the peergroup we are dealing with
3365  * @param num how many connections at least should each peer have (if possible)?
3366  */
3367 static void
3368 choose_minimum (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
3369 {
3370   struct MinimumContext minimum_ctx;
3371   uint32_t pg_iter;
3372
3373   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3374     {
3375       pg->peers[pg_iter].connect_peers_working_set =
3376         GNUNET_CONTAINER_multihashmap_create (num);
3377     }
3378
3379   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3380     {
3381       minimum_ctx.first_uid = pg_iter;
3382       minimum_ctx.pg_array =
3383         GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK,
3384                                       GNUNET_CONTAINER_multihashmap_size
3385                                       (pg->peers[pg_iter].connect_peers));
3386       minimum_ctx.first = &pg->peers[pg_iter];
3387       minimum_ctx.pg = pg;
3388       minimum_ctx.num_to_add = num;
3389       minimum_ctx.current = 0;
3390       GNUNET_CONTAINER_multihashmap_iterate (pg->peers[pg_iter].connect_peers,
3391                                              &minimum_connect_iterator,
3392                                              &minimum_ctx);
3393     }
3394
3395   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3396     {
3397       /* Remove the "old" connections */
3398       GNUNET_CONTAINER_multihashmap_destroy (pg->
3399                                              peers[pg_iter].connect_peers);
3400       /* And replace with the working set */
3401       pg->peers[pg_iter].connect_peers =
3402         pg->peers[pg_iter].connect_peers_working_set;
3403     }
3404
3405 }
3406
3407
3408 static unsigned int
3409 count_workingset_connections (struct GNUNET_TESTING_PeerGroup *pg)
3410 {
3411   unsigned int count;
3412   unsigned int pg_iter;
3413
3414   count = 0;
3415
3416   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3417     {
3418       count +=
3419         GNUNET_CONTAINER_multihashmap_size (pg->
3420                                             peers
3421                                             [pg_iter].connect_peers_working_set);
3422     }
3423
3424   return count;
3425 }
3426
3427
3428 static unsigned int
3429 count_allowed_connections (struct GNUNET_TESTING_PeerGroup *pg)
3430 {
3431   unsigned int count;
3432   unsigned int pg_iter;
3433
3434   count = 0;
3435
3436   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3437     {
3438       count +=
3439         GNUNET_CONTAINER_multihashmap_size (pg->peers[pg_iter].connect_peers);
3440     }
3441
3442   return count;
3443 }
3444
3445
3446 struct FindClosestContext
3447 {
3448   /**
3449    * The currently known closest peer.
3450    */
3451   struct GNUNET_TESTING_Daemon *closest;
3452
3453   /**
3454    * The info for the peer we are adding connections for.
3455    */
3456   struct PeerData *curr_peer;
3457
3458   /**
3459    * The distance (bits) between the current
3460    * peer and the currently known closest.
3461    */
3462   unsigned int closest_dist;
3463
3464   /**
3465    * The offset of the closest known peer in
3466    * the peer group.
3467    */
3468   unsigned int closest_num;
3469 };
3470
3471 /**
3472  * Iterator over hash map entries of the allowed
3473  * peer connections.  Find the closest, not already
3474  * connected peer and return it.
3475  *
3476  * @param cls closure (struct FindClosestContext)
3477  * @param key current key code (hash of offset in pg)
3478  * @param value value in the hash map - a GNUNET_TESTING_Daemon
3479  * @return GNUNET_YES if we should continue to
3480  *         iterate,
3481  *         GNUNET_NO if not.
3482  */
3483 static int
3484 find_closest_peers (void *cls, const GNUNET_HashCode * key, void *value)
3485 {
3486   struct FindClosestContext *closest_ctx = cls;
3487   struct GNUNET_TESTING_Daemon *daemon = value;
3488
3489   if (((closest_ctx->closest == NULL) ||
3490        (GNUNET_CRYPTO_hash_matching_bits
3491         (&daemon->id.hashPubKey,
3492          &closest_ctx->curr_peer->daemon->id.hashPubKey) >
3493         closest_ctx->closest_dist))
3494       && (GNUNET_YES !=
3495           GNUNET_CONTAINER_multihashmap_contains (closest_ctx->
3496                                                   curr_peer->connect_peers,
3497                                                   key)))
3498     {
3499       closest_ctx->closest_dist =
3500         GNUNET_CRYPTO_hash_matching_bits (&daemon->id.hashPubKey,
3501                                           &closest_ctx->curr_peer->daemon->
3502                                           id.hashPubKey);
3503       closest_ctx->closest = daemon;
3504       uid_from_hash (key, &closest_ctx->closest_num);
3505     }
3506   return GNUNET_YES;
3507 }
3508
3509 /**
3510  * From the set of connections possible, choose at num connections per
3511  * peer based on depth which are closest out of those allowed.  Guaranteed
3512  * to add num peers to connect to, provided there are that many peers
3513  * in the underlay topology to connect to.
3514  *
3515  * @param pg the peergroup we are dealing with
3516  * @param num how many connections at least should each peer have (if possible)?
3517  * @param proc processor to actually add the connections
3518  */
3519 void
3520 add_closest (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num,
3521              GNUNET_TESTING_ConnectionProcessor proc)
3522 {
3523   struct FindClosestContext closest_ctx;
3524   uint32_t pg_iter;
3525   uint32_t i;
3526
3527   for (i = 0; i < num; i++)     /* Each time find a closest peer (from those available) */
3528     {
3529       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3530         {
3531           closest_ctx.curr_peer = &pg->peers[pg_iter];
3532           closest_ctx.closest = NULL;
3533           closest_ctx.closest_dist = 0;
3534           closest_ctx.closest_num = 0;
3535           GNUNET_CONTAINER_multihashmap_iterate (pg->
3536                                                  peers[pg_iter].allowed_peers,
3537                                                  &find_closest_peers,
3538                                                  &closest_ctx);
3539           if (closest_ctx.closest != NULL)
3540             {
3541               GNUNET_assert (closest_ctx.closest_num < pg->total);
3542               proc (pg, pg_iter, closest_ctx.closest_num);
3543             }
3544         }
3545     }
3546 }
3547
3548 /**
3549  * From the set of connections possible, choose at least num connections per
3550  * peer based on depth first traversal of peer connections.  If DFS leaves
3551  * peers unconnected, ensure those peers get connections.
3552  *
3553  * @param pg the peergroup we are dealing with
3554  * @param num how many connections at least should each peer have (if possible)?
3555  */
3556 void
3557 perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
3558 {
3559   struct DFSContext dfs_ctx;
3560   uint32_t pg_iter;
3561   uint32_t dfs_count;
3562   uint32_t starting_peer;
3563   uint32_t least_connections;
3564   GNUNET_HashCode second_hash;
3565
3566   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3567     {
3568       pg->peers[pg_iter].connect_peers_working_set =
3569         GNUNET_CONTAINER_multihashmap_create (num);
3570     }
3571
3572   starting_peer = 0;
3573   dfs_count = 0;
3574   while ((count_workingset_connections (pg) < num * pg->total)
3575          && (count_allowed_connections (pg) > 0))
3576     {
3577       if (dfs_count % pg->total == 0)   /* Restart the DFS at some weakly connected peer */
3578         {
3579           least_connections = -1;       /* Set to very high number */
3580           for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3581             {
3582               if (GNUNET_CONTAINER_multihashmap_size
3583                   (pg->peers[pg_iter].connect_peers_working_set) <
3584                   least_connections)
3585                 {
3586                   starting_peer = pg_iter;
3587                   least_connections =
3588                     GNUNET_CONTAINER_multihashmap_size (pg->
3589                                                         peers
3590                                                         [pg_iter].connect_peers_working_set);
3591                 }
3592             }
3593         }
3594
3595       if (GNUNET_CONTAINER_multihashmap_size (pg->peers[starting_peer].connect_peers) == 0)     /* Ensure there is at least one peer left to connect! */
3596         {
3597           dfs_count = 0;
3598           continue;
3599         }
3600
3601       /* Choose a random peer from the chosen peers set of connections to add */
3602       dfs_ctx.chosen =
3603         GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
3604                                   GNUNET_CONTAINER_multihashmap_size
3605                                   (pg->peers[starting_peer].connect_peers));
3606       dfs_ctx.first_uid = starting_peer;
3607       dfs_ctx.first = &pg->peers[starting_peer];
3608       dfs_ctx.pg = pg;
3609       dfs_ctx.current = 0;
3610
3611       GNUNET_CONTAINER_multihashmap_iterate (pg->
3612                                              peers
3613                                              [starting_peer].connect_peers,
3614                                              &dfs_connect_iterator, &dfs_ctx);
3615       /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */
3616       hash_from_uid (dfs_ctx.second_uid, &second_hash);
3617       GNUNET_assert (GNUNET_YES ==
3618                      GNUNET_CONTAINER_multihashmap_remove (pg->peers
3619                                                            [starting_peer].connect_peers,
3620                                                            &second_hash,
3621                                                            pg->
3622                                                            peers
3623                                                            [dfs_ctx.second_uid].daemon));
3624       starting_peer = dfs_ctx.second_uid;
3625     }
3626
3627   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
3628     {
3629       /* Remove the "old" connections */
3630       GNUNET_CONTAINER_multihashmap_destroy (pg->
3631                                              peers[pg_iter].connect_peers);
3632       /* And replace with the working set */
3633       pg->peers[pg_iter].connect_peers =
3634         pg->peers[pg_iter].connect_peers_working_set;
3635     }
3636 }
3637
3638 /**
3639  * Internal callback for topology information for a particular peer.
3640  */
3641 static void
3642 internal_topology_callback (void *cls,
3643                             const struct GNUNET_PeerIdentity *peer,
3644                             const struct GNUNET_TRANSPORT_ATS_Information
3645                             *atsi)
3646 {
3647   struct CoreContext *core_ctx = cls;
3648   struct TopologyIterateContext *iter_ctx = core_ctx->iter_context;
3649
3650   if (peer == NULL)             /* Either finished, or something went wrong */
3651     {
3652       iter_ctx->completed++;
3653       iter_ctx->connected--;
3654       /* One core context allocated per iteration, must free! */
3655       GNUNET_free (core_ctx);
3656     }
3657   else
3658     {
3659       iter_ctx->topology_cb (iter_ctx->cls, &core_ctx->daemon->id,
3660                              peer, NULL);
3661     }
3662
3663   if (iter_ctx->completed == iter_ctx->total)
3664     {
3665       iter_ctx->topology_cb (iter_ctx->cls, NULL, NULL, NULL);
3666       /* Once all are done, free the iteration context */
3667       GNUNET_free (iter_ctx);
3668     }
3669 }
3670
3671
3672 /**
3673  * Check running topology iteration tasks, if below max start a new one, otherwise
3674  * schedule for some time in the future.
3675  */
3676 static void
3677 schedule_get_topology (void *cls,
3678                        const struct GNUNET_SCHEDULER_TaskContext *tc)
3679 {
3680   struct CoreContext *core_context = cls;
3681   struct TopologyIterateContext *topology_context =
3682     (struct TopologyIterateContext *) core_context->iter_context;
3683   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3684     return;
3685
3686   if (topology_context->connected > MAX_OUTSTANDING_CONNECTIONS)
3687     {
3688 #if VERBOSE_TESTING > 2
3689       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3690                   _
3691                   ("Delaying connect, we have too many outstanding connections!\n"));
3692 #endif
3693       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
3694                                     (GNUNET_TIME_UNIT_MILLISECONDS, 100),
3695                                     &schedule_get_topology, core_context);
3696     }
3697   else
3698     {
3699 #if VERBOSE_TESTING > 2
3700       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3701                   _("Creating connection, outstanding_connections is %d\n"),
3702                   outstanding_connects);
3703 #endif
3704       topology_context->connected++;
3705
3706       if (GNUNET_OK !=
3707           GNUNET_CORE_iterate_peers (core_context->daemon->cfg,
3708                                      &internal_topology_callback,
3709                                      core_context))
3710         {
3711           GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Topology iteration failed.\n");
3712           internal_topology_callback (core_context, NULL, NULL);
3713         }
3714     }
3715 }
3716
3717 /**
3718  * Iterate over all (running) peers in the peer group, retrieve
3719  * all connections that each currently has.
3720  */
3721 void
3722 GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg,
3723                              GNUNET_TESTING_NotifyTopology cb, void *cls)
3724 {
3725   struct TopologyIterateContext *topology_context;
3726   struct CoreContext *core_ctx;
3727   unsigned int i;
3728   unsigned int total_count;
3729
3730   /* Allocate a single topology iteration context */
3731   topology_context = GNUNET_malloc (sizeof (struct TopologyIterateContext));
3732   topology_context->topology_cb = cb;
3733   topology_context->cls = cls;
3734   total_count = 0;
3735   for (i = 0; i < pg->total; i++)
3736     {
3737       if (pg->peers[i].daemon->running == GNUNET_YES)
3738         {
3739           /* Allocate one core context per core we need to connect to */
3740           core_ctx = GNUNET_malloc (sizeof (struct CoreContext));
3741           core_ctx->daemon = pg->peers[i].daemon;
3742           /* Set back pointer to topology iteration context */
3743           core_ctx->iter_context = topology_context;
3744           GNUNET_SCHEDULER_add_now (&schedule_get_topology, core_ctx);
3745           total_count++;
3746         }
3747     }
3748   if (total_count == 0)
3749     {
3750       cb (cls, NULL, NULL, "Cannot iterate over topology, no running peers!");
3751       GNUNET_free (topology_context);
3752     }
3753   else
3754     topology_context->total = total_count;
3755   return;
3756 }
3757
3758 /**
3759  * Callback function to process statistic values.
3760  * This handler is here only really to insert a peer
3761  * identity (or daemon) so the statistics can be uniquely
3762  * tied to a single running peer.
3763  *
3764  * @param cls closure
3765  * @param subsystem name of subsystem that created the statistic
3766  * @param name the name of the datum
3767  * @param value the current value
3768  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
3769  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
3770  */
3771 static int
3772 internal_stats_callback (void *cls,
3773                          const char *subsystem,
3774                          const char *name, uint64_t value, int is_persistent)
3775 {
3776   struct StatsCoreContext *core_context = cls;
3777   struct StatsIterateContext *stats_context =
3778     (struct StatsIterateContext *) core_context->iter_context;
3779
3780   return stats_context->proc (stats_context->cls, &core_context->daemon->id,
3781                               subsystem, name, value, is_persistent);
3782 }
3783
3784 /**
3785  * Internal continuation call for statistics iteration.
3786  *
3787  * @param cls closure, the CoreContext for this iteration
3788  * @param success whether or not the statistics iterations
3789  *        was canceled or not (we don't care)
3790  */
3791 static void
3792 internal_stats_cont (void *cls, int success)
3793 {
3794   struct StatsCoreContext *core_context = cls;
3795   struct StatsIterateContext *stats_context =
3796     (struct StatsIterateContext *) core_context->iter_context;
3797
3798   stats_context->connected--;
3799   stats_context->completed++;
3800
3801   if (stats_context->completed == stats_context->total)
3802     {
3803       stats_context->cont (stats_context->cls, GNUNET_YES);
3804       GNUNET_free (stats_context);
3805     }
3806
3807   if (core_context->stats_handle != NULL)
3808     GNUNET_STATISTICS_destroy (core_context->stats_handle, GNUNET_NO);
3809
3810   GNUNET_free (core_context);
3811 }
3812
3813 /**
3814  * Check running topology iteration tasks, if below max start a new one, otherwise
3815  * schedule for some time in the future.
3816  */
3817 static void
3818 schedule_get_statistics (void *cls,
3819                          const struct GNUNET_SCHEDULER_TaskContext *tc)
3820 {
3821   struct StatsCoreContext *core_context = cls;
3822   struct StatsIterateContext *stats_context =
3823     (struct StatsIterateContext *) core_context->iter_context;
3824
3825   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3826     return;
3827
3828   if (stats_context->connected > MAX_OUTSTANDING_CONNECTIONS)
3829     {
3830 #if VERBOSE_TESTING > 2
3831       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3832                   _
3833                   ("Delaying connect, we have too many outstanding connections!\n"));
3834 #endif
3835       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
3836                                     (GNUNET_TIME_UNIT_MILLISECONDS, 100),
3837                                     &schedule_get_statistics, core_context);
3838     }
3839   else
3840     {
3841 #if VERBOSE_TESTING > 2
3842       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3843                   _("Creating connection, outstanding_connections is %d\n"),
3844                   outstanding_connects);
3845 #endif
3846
3847       stats_context->connected++;
3848       core_context->stats_handle =
3849         GNUNET_STATISTICS_create ("testing", core_context->daemon->cfg);
3850       if (core_context->stats_handle == NULL)
3851         {
3852           internal_stats_cont (core_context, GNUNET_NO);
3853           return;
3854         }
3855
3856       core_context->stats_get_handle =
3857         GNUNET_STATISTICS_get (core_context->stats_handle, NULL, NULL,
3858                                GNUNET_TIME_relative_get_forever (),
3859                                &internal_stats_cont, &internal_stats_callback,
3860                                core_context);
3861       if (core_context->stats_get_handle == NULL)
3862         internal_stats_cont (core_context, GNUNET_NO);
3863
3864     }
3865 }
3866
3867 struct DuplicateStats
3868 {
3869   /**
3870    * Next item in the list
3871    */
3872   struct DuplicateStats *next;
3873
3874   /**
3875    * Nasty string, concatenation of relevant information.
3876    */
3877   char *unique_string;
3878 };
3879
3880 /**
3881  * Check whether the combination of port/host/unix domain socket
3882  * already exists in the list of peers being checked for statistics.
3883  *
3884  * @param pg the peergroup in question
3885  * @param specific_peer the peer we're concerned with
3886  * @param stats_list the list to return to the caller
3887  *
3888  * @return GNUNET_YES if the statistics instance has been seen already,
3889  *         GNUNET_NO if not (and we may have added it to the list)
3890  */
3891 static int
3892 stats_check_existing (struct GNUNET_TESTING_PeerGroup *pg,
3893                       struct PeerData *specific_peer,
3894                       struct DuplicateStats **stats_list)
3895 {
3896   struct DuplicateStats *pos;
3897   char *unix_domain_socket;
3898   unsigned long long port;
3899   char *to_match;
3900   if (GNUNET_YES !=
3901       GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "testing",
3902                                             "single_statistics_per_host"))
3903     return GNUNET_NO;           /* Each peer has its own statistics instance, do nothing! */
3904
3905   pos = *stats_list;
3906   if (GNUNET_OK !=
3907       GNUNET_CONFIGURATION_get_value_string (specific_peer->cfg, "statistics",
3908                                              "unixpath", &unix_domain_socket))
3909     return GNUNET_NO;
3910
3911   if (GNUNET_OK !=
3912       GNUNET_CONFIGURATION_get_value_number (specific_peer->cfg, "statistics",
3913                                              "port", &port))
3914     {
3915       GNUNET_free(unix_domain_socket);
3916       return GNUNET_NO;
3917     }
3918
3919   if (specific_peer->daemon->hostname != NULL)
3920     GNUNET_asprintf (&to_match, "%s%s%llu", specific_peer->daemon->hostname,
3921                      unix_domain_socket, port);
3922   else
3923     GNUNET_asprintf (&to_match, "%s%llu", unix_domain_socket, port);
3924
3925   while (pos != NULL)
3926     {
3927       if (0 == strcmp (to_match, pos->unique_string))
3928         {
3929           GNUNET_free (unix_domain_socket);
3930           GNUNET_free (to_match);
3931           return GNUNET_YES;
3932         }
3933       pos = pos->next;
3934     }
3935   pos = GNUNET_malloc (sizeof (struct DuplicateStats));
3936   pos->unique_string = to_match;
3937   pos->next = *stats_list;
3938   *stats_list = pos;
3939   GNUNET_free (unix_domain_socket);
3940   return GNUNET_NO;
3941 }
3942
3943 /**
3944  * Iterate over all (running) peers in the peer group, retrieve
3945  * all statistics from each.
3946  */
3947 void
3948 GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg,
3949                                GNUNET_STATISTICS_Callback cont,
3950                                GNUNET_TESTING_STATISTICS_Iterator proc,
3951                                void *cls)
3952 {
3953   struct StatsIterateContext *stats_context;
3954   struct StatsCoreContext *core_ctx;
3955   unsigned int i;
3956   unsigned int total_count;
3957   struct DuplicateStats *stats_list;
3958   struct DuplicateStats *pos;
3959   stats_list = NULL;
3960
3961   /* Allocate a single stats iteration context */
3962   stats_context = GNUNET_malloc (sizeof (struct StatsIterateContext));
3963   stats_context->cont = cont;
3964   stats_context->proc = proc;
3965   stats_context->cls = cls;
3966   total_count = 0;
3967
3968   for (i = 0; i < pg->total; i++)
3969     {
3970       if ((pg->peers[i].daemon->running == GNUNET_YES)
3971           && (GNUNET_NO ==
3972               stats_check_existing (pg, &pg->peers[i], &stats_list)))
3973         {
3974           /* Allocate one core context per core we need to connect to */
3975           core_ctx = GNUNET_malloc (sizeof (struct StatsCoreContext));
3976           core_ctx->daemon = pg->peers[i].daemon;
3977           /* Set back pointer to topology iteration context */
3978           core_ctx->iter_context = stats_context;
3979           GNUNET_SCHEDULER_add_now (&schedule_get_statistics, core_ctx);
3980           total_count++;
3981         }
3982     }
3983
3984   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3985               "Retrieving stats from %u total instances.\n", total_count);
3986   stats_context->total = total_count;
3987   if (stats_list != NULL)
3988     {
3989       pos = stats_list;
3990       while (pos != NULL)
3991         {
3992           GNUNET_free (pos->unique_string);
3993           stats_list = pos->next;
3994           GNUNET_free (pos);
3995           pos = stats_list->next;
3996         }
3997     }
3998   return;
3999 }
4000
4001 /**
4002  * There are many ways to connect peers that are supported by this function.
4003  * To connect peers in the same topology that was created via the
4004  * GNUNET_TESTING_create_topology, the topology variable must be set to
4005  * GNUNET_TESTING_TOPOLOGY_NONE.  If the topology variable is specified,
4006  * a new instance of that topology will be generated and attempted to be
4007  * connected.  This could result in some connections being impossible,
4008  * because some topologies are non-deterministic.
4009  *
4010  * @param pg the peer group struct representing the running peers
4011  * @param topology which topology to connect the peers in
4012  * @param options options for connecting the topology
4013  * @param option_modifier modifier for options that take a parameter
4014  * @param notify_callback notification to be called once all connections completed
4015  * @param notify_cls closure for notification callback
4016  *
4017  * @return the number of connections that will be attempted, GNUNET_SYSERR on error
4018  */
4019 int
4020 GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
4021                                  enum GNUNET_TESTING_Topology topology,
4022                                  enum GNUNET_TESTING_TopologyOption options,
4023                                  double option_modifier,
4024                                  GNUNET_TESTING_NotifyCompletion
4025                                  notify_callback, void *notify_cls)
4026 {
4027   switch (topology)
4028     {
4029     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
4030 #if VERBOSE_TOPOLOGY
4031       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4032                   _("Creating clique CONNECT topology\n"));
4033 #endif
4034       create_clique (pg, &add_actual_connections);
4035       break;
4036     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
4037 #if VERBOSE_TOPOLOGY
4038       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4039                   _("Creating small world (ring) CONNECT topology\n"));
4040 #endif
4041       create_small_world_ring (pg, &add_actual_connections);
4042       break;
4043     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
4044 #if VERBOSE_TOPOLOGY
4045       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4046                   _("Creating small world (2d-torus) CONNECT topology\n"));
4047 #endif
4048       create_small_world (pg, &add_actual_connections);
4049       break;
4050     case GNUNET_TESTING_TOPOLOGY_RING:
4051 #if VERBOSE_TOPOLOGY
4052       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4053                   _("Creating ring CONNECT topology\n"));
4054 #endif
4055       create_ring (pg, &add_actual_connections);
4056       break;
4057     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
4058 #if VERBOSE_TOPOLOGY
4059       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4060                   _("Creating 2d torus CONNECT topology\n"));
4061 #endif
4062       create_2d_torus (pg, &add_actual_connections);
4063       break;
4064     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
4065 #if VERBOSE_TOPOLOGY
4066       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4067                   _("Creating Erdos-Renyi CONNECT topology\n"));
4068 #endif
4069       create_erdos_renyi (pg, &add_actual_connections);
4070       break;
4071     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
4072 #if VERBOSE_TOPOLOGY
4073       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4074                   _("Creating InterNAT CONNECT topology\n"));
4075 #endif
4076       create_nated_internet (pg, &add_actual_connections);
4077       break;
4078     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
4079 #if VERBOSE_TOPOLOGY
4080       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4081                   _("Creating Scale Free CONNECT topology\n"));
4082 #endif
4083       create_scale_free (pg, &add_actual_connections);
4084       break;
4085     case GNUNET_TESTING_TOPOLOGY_LINE:
4086 #if VERBOSE_TOPOLOGY
4087       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4088                   _("Creating straight line CONNECT topology\n"));
4089 #endif
4090       create_line (pg, &add_actual_connections);
4091       break;
4092     case GNUNET_TESTING_TOPOLOGY_NONE:
4093 #if VERBOSE_TOPOLOGY
4094       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4095                   _("Creating no CONNECT topology\n"));
4096 #endif
4097       copy_allowed_topology (pg);
4098       break;
4099     default:
4100       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4101                   _
4102                   ("Unknown topology specification, can't connect peers!\n"));
4103       return GNUNET_SYSERR;
4104     }
4105
4106   switch (options)
4107     {
4108     case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM:
4109 #if VERBOSE_TOPOLOGY
4110       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4111                   _
4112                   ("Connecting random subset (%'.2f percent) of possible peers\n"),
4113                   100 * option_modifier);
4114 #endif
4115       choose_random_connections (pg, option_modifier);
4116       break;
4117     case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM:
4118 #if VERBOSE_TOPOLOGY
4119       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4120                   _("Connecting a minimum of %u peers each (if possible)\n"),
4121                   (unsigned int) option_modifier);
4122 #endif
4123       choose_minimum (pg, (unsigned int) option_modifier);
4124       break;
4125     case GNUNET_TESTING_TOPOLOGY_OPTION_DFS:
4126 #if VERBOSE_TOPOLOGY
4127       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4128                   _
4129                   ("Using DFS to connect a minimum of %u peers each (if possible)\n"),
4130                   (unsigned int) option_modifier);
4131 #endif
4132       perform_dfs (pg, (int) option_modifier);
4133       break;
4134     case GNUNET_TESTING_TOPOLOGY_OPTION_ADD_CLOSEST:
4135 #if VERBOSE_TOPOLOGY
4136       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4137                   _
4138                   ("Finding additional %u closest peers each (if possible)\n"),
4139                   (unsigned int) option_modifier);
4140 #endif
4141       add_closest (pg, (unsigned int) option_modifier,
4142                    &add_actual_connections);
4143       break;
4144     case GNUNET_TESTING_TOPOLOGY_OPTION_NONE:
4145       break;
4146     case GNUNET_TESTING_TOPOLOGY_OPTION_ALL:
4147       break;
4148     default:
4149       break;
4150     }
4151
4152   return connect_topology (pg, notify_callback, notify_cls);
4153 }
4154
4155 /**
4156  * Callback that is called whenever a hostkey is generated
4157  * for a peer.  Call the real callback and decrement the
4158  * starting counter for the peergroup.
4159  *
4160  * @param cls closure
4161  * @param id identifier for the daemon, NULL on error
4162  * @param d handle for the daemon
4163  * @param emsg error message (NULL on success)
4164  */
4165 static void
4166 internal_hostkey_callback (void *cls,
4167                            const struct GNUNET_PeerIdentity *id,
4168                            struct GNUNET_TESTING_Daemon *d, const char *emsg)
4169 {
4170   struct InternalStartContext *internal_context = cls;
4171   internal_context->peer->pg->starting--;
4172   internal_context->peer->pg->started++;
4173   if (internal_context->hostkey_callback != NULL)
4174     internal_context->hostkey_callback (internal_context->hostkey_cls, id, d,
4175                                         emsg);
4176   else if (internal_context->peer->pg->started ==
4177            internal_context->peer->pg->total)
4178     {
4179       internal_context->peer->pg->started = 0;  /* Internal startup may use this counter! */
4180       GNUNET_TESTING_daemons_continue_startup (internal_context->peer->pg);
4181     }
4182 }
4183
4184 /**
4185  * Callback that is called whenever a peer has finished starting.
4186  * Call the real callback and decrement the starting counter
4187  * for the peergroup.
4188  *
4189  * @param cls closure
4190  * @param id identifier for the daemon, NULL on error
4191  * @param cfg config
4192  * @param d handle for the daemon
4193  * @param emsg error message (NULL on success)
4194  */
4195 static void
4196 internal_startup_callback (void *cls,
4197                            const struct GNUNET_PeerIdentity *id,
4198                            const struct GNUNET_CONFIGURATION_Handle *cfg,
4199                            struct GNUNET_TESTING_Daemon *d, const char *emsg)
4200 {
4201   struct InternalStartContext *internal_context = cls;
4202   internal_context->peer->pg->starting--;
4203   if (internal_context->start_cb != NULL)
4204     internal_context->start_cb (internal_context->start_cb_cls, id, cfg, d,
4205                                 emsg);
4206 }
4207
4208 static void
4209 internal_continue_startup (void *cls,
4210                            const struct GNUNET_SCHEDULER_TaskContext *tc)
4211 {
4212   struct InternalStartContext *internal_context = cls;
4213
4214   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
4215     {
4216       return;
4217     }
4218
4219   if (internal_context->peer->pg->starting < MAX_CONCURRENT_STARTING)
4220     {
4221       internal_context->peer->pg->starting++;
4222       GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon);
4223     }
4224   else
4225     {
4226       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
4227                                     (GNUNET_TIME_UNIT_MILLISECONDS, 100),
4228                                     &internal_continue_startup,
4229                                     internal_context);
4230     }
4231 }
4232
4233
4234 /**
4235  * Callback for informing us about a successful
4236  * or unsuccessful churn start call.
4237  *
4238  * @param cls a ChurnContext
4239  * @param id the peer identity of the started peer
4240  * @param cfg the handle to the configuration of the peer
4241  * @param d handle to the daemon for the peer
4242  * @param emsg NULL on success, non-NULL on failure
4243  *
4244  */
4245 void
4246 churn_start_callback (void *cls,
4247                       const struct GNUNET_PeerIdentity *id,
4248                       const struct GNUNET_CONFIGURATION_Handle *cfg,
4249                       struct GNUNET_TESTING_Daemon *d, const char *emsg)
4250 {
4251   struct ChurnRestartContext *startup_ctx = cls;
4252   struct ChurnContext *churn_ctx = startup_ctx->churn_ctx;
4253
4254   unsigned int total_left;
4255   char *error_message;
4256
4257   error_message = NULL;
4258   if (emsg != NULL)
4259     {
4260       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4261                   "Churn stop callback failed with error `%s'\n", emsg);
4262       churn_ctx->num_failed_start++;
4263     }
4264   else
4265     {
4266       churn_ctx->num_to_start--;
4267     }
4268
4269 #if DEBUG_CHURN
4270   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4271               "Started peer, %d left.\n", churn_ctx->num_to_start);
4272 #endif
4273
4274   total_left =
4275     (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) +
4276     (churn_ctx->num_to_start - churn_ctx->num_failed_start);
4277
4278   if (total_left == 0)
4279     {
4280       if ((churn_ctx->num_failed_stop > 0)
4281           || (churn_ctx->num_failed_start > 0))
4282         GNUNET_asprintf (&error_message,
4283                          "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!",
4284                          churn_ctx->num_failed_start,
4285                          churn_ctx->num_failed_stop);
4286       churn_ctx->cb (churn_ctx->cb_cls, error_message);
4287       GNUNET_free_non_null (error_message);
4288       GNUNET_free (churn_ctx);
4289       GNUNET_free (startup_ctx);
4290     }
4291 }
4292
4293
4294 static void
4295 schedule_churn_restart (void *cls,
4296                         const struct GNUNET_SCHEDULER_TaskContext *tc)
4297 {
4298   struct PeerRestartContext *peer_restart_ctx = cls;
4299   struct ChurnRestartContext *startup_ctx =
4300     peer_restart_ctx->churn_restart_ctx;
4301
4302   if (startup_ctx->outstanding > MAX_CONCURRENT_STARTING)
4303     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
4304                                   (GNUNET_TIME_UNIT_MILLISECONDS, 100),
4305                                   &schedule_churn_restart, peer_restart_ctx);
4306   else
4307     {
4308       GNUNET_TESTING_daemon_start_stopped (peer_restart_ctx->daemon,
4309                                            startup_ctx->timeout,
4310                                            &churn_start_callback,
4311                                            startup_ctx);
4312       GNUNET_free (peer_restart_ctx);
4313     }
4314 }
4315
4316 static void
4317 internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
4318 {
4319   struct InternalStartContext *internal_context = cls;
4320
4321   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
4322     {
4323       return;
4324     }
4325
4326   if (internal_context->peer->pg->starting < MAX_CONCURRENT_HOSTKEYS)
4327     {
4328       internal_context->peer->pg->starting++;
4329       internal_context->peer->daemon =
4330         GNUNET_TESTING_daemon_start (internal_context->peer->cfg,
4331                                      internal_context->timeout,
4332                                      internal_context->hostname,
4333                                      internal_context->username,
4334                                      internal_context->sshport,
4335                                      internal_context->hostkey,
4336                                      &internal_hostkey_callback,
4337                                      internal_context,
4338                                      &internal_startup_callback,
4339                                      internal_context);
4340     }
4341   else
4342     {
4343       GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
4344                                     (GNUNET_TIME_UNIT_MILLISECONDS, 100),
4345                                     &internal_start, internal_context);
4346     }
4347 }
4348
4349 /**
4350  * Function which continues a peer group starting up
4351  * after successfully generating hostkeys for each peer.
4352  *
4353  * @param pg the peer group to continue starting
4354  *
4355  */
4356 void
4357 GNUNET_TESTING_daemons_continue_startup (struct GNUNET_TESTING_PeerGroup *pg)
4358 {
4359   unsigned int i;
4360
4361   pg->starting = 0;
4362   for (i = 0; i < pg->total; i++)
4363     {
4364       GNUNET_SCHEDULER_add_now (&internal_continue_startup,
4365                                 &pg->peers[i].internal_context);
4366       //GNUNET_TESTING_daemon_continue_startup(pg->peers[i].daemon);
4367     }
4368 }
4369
4370 /**
4371  * Start count gnunet instances with the same set of transports and
4372  * applications.  The port numbers (any option called "PORT") will be
4373  * adjusted to ensure that no two peers running on the same system
4374  * have the same port(s) in their respective configurations.
4375  *
4376  * @param cfg configuration template to use
4377  * @param total number of daemons to start
4378  * @param timeout total time allowed for peers to start
4379  * @param hostkey_callback function to call on each peers hostkey generation
4380  *        if NULL, peers will be started by this call, if non-null,
4381  *        GNUNET_TESTING_daemons_continue_startup must be called after
4382  *        successful hostkey generation
4383  * @param hostkey_cls closure for hostkey callback
4384  * @param cb function to call on each daemon that was started
4385  * @param cb_cls closure for cb
4386  * @param connect_callback function to call each time two hosts are connected
4387  * @param connect_callback_cls closure for connect_callback
4388  * @param hostnames linked list of host structs to use to start peers on
4389  *                  (NULL to run on localhost only)
4390  *
4391  * @return NULL on error, otherwise handle to control peer group
4392  */
4393 struct GNUNET_TESTING_PeerGroup *
4394 GNUNET_TESTING_daemons_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
4395                               unsigned int total,
4396                               struct GNUNET_TIME_Relative timeout,
4397                               GNUNET_TESTING_NotifyHostkeyCreated
4398                               hostkey_callback, void *hostkey_cls,
4399                               GNUNET_TESTING_NotifyDaemonRunning cb,
4400                               void *cb_cls,
4401                               GNUNET_TESTING_NotifyConnection
4402                               connect_callback, void *connect_callback_cls,
4403                               const struct GNUNET_TESTING_Host *hostnames)
4404 {
4405   struct GNUNET_TESTING_PeerGroup *pg;
4406   const struct GNUNET_TESTING_Host *hostpos;
4407 #if 0
4408   char *pos;
4409   const char *rpos;
4410   char *start;
4411 #endif
4412   const char *hostname;
4413   const char *username;
4414   char *baseservicehome;
4415   char *newservicehome;
4416   char *tmpdir;
4417   char *hostkeys_file;
4418   char *hostkey_data;
4419   struct GNUNET_DISK_FileHandle *fd;
4420   struct GNUNET_CONFIGURATION_Handle *pcfg;
4421   unsigned int off;
4422   unsigned int hostcnt;
4423   uint16_t minport;
4424   uint16_t sshport;
4425   uint32_t upnum;
4426   uint32_t fdnum;
4427   uint64_t fs;
4428   uint64_t total_hostkeys;
4429
4430   if (0 == total)
4431     {
4432       GNUNET_break (0);
4433       return NULL;
4434     }
4435   hostkey_data = NULL;
4436   upnum = 0;
4437   fdnum = 0;
4438   pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
4439   pg->cfg = cfg;
4440   pg->notify_connection = connect_callback;
4441   pg->notify_connection_cls = connect_callback_cls;
4442   pg->total = total;
4443   pg->max_timeout = GNUNET_TIME_relative_to_absolute (timeout);
4444   pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
4445   if (NULL != hostnames)
4446     {
4447       off = 0;
4448       hostpos = hostnames;
4449       while (hostpos != NULL)
4450         {
4451           hostpos = hostpos->next;
4452           off++;
4453         }
4454       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
4455       off = 0;
4456
4457       hostpos = hostnames;
4458       while (hostpos != NULL)
4459         {
4460           pg->hosts[off].minport = LOW_PORT;
4461           pg->hosts[off].hostname = GNUNET_strdup (hostpos->hostname);
4462           if (hostpos->username != NULL)
4463             pg->hosts[off].username = GNUNET_strdup (hostpos->username);
4464           pg->hosts[off].sshport = hostpos->port;
4465           hostpos = hostpos->next;
4466           off++;
4467         }
4468
4469       if (off == 0)
4470         {
4471           pg->hosts = NULL;
4472         }
4473       hostcnt = off;
4474       minport = 0;
4475       pg->num_hosts = off;
4476
4477 #if NO_LL
4478       off = 2;
4479       /* skip leading spaces */
4480       while ((0 != *hostnames) && (isspace ((unsigned char) *hostnames)))
4481         hostnames++;
4482       rpos = hostnames;
4483       while ('\0' != *rpos)
4484         {
4485           if (isspace ((unsigned char) *rpos))
4486             off++;
4487           rpos++;
4488         }
4489       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
4490       off = 0;
4491       start = GNUNET_strdup (hostnames);
4492       pos = start;
4493       while ('\0' != *pos)
4494         {
4495           if (isspace ((unsigned char) *pos))
4496             {
4497               *pos = '\0';
4498               if (strlen (start) > 0)
4499                 {
4500                   pg->hosts[off].minport = LOW_PORT;
4501                   pg->hosts[off++].hostname = start;
4502                 }
4503               start = pos + 1;
4504             }
4505           pos++;
4506         }
4507       if (strlen (start) > 0)
4508         {
4509           pg->hosts[off].minport = LOW_PORT;
4510           pg->hosts[off++].hostname = start;
4511         }
4512       if (off == 0)
4513         {
4514           GNUNET_free (start);
4515           GNUNET_free (pg->hosts);
4516           pg->hosts = NULL;
4517         }
4518       hostcnt = off;
4519       minport = 0;              /* make gcc happy */
4520 #endif
4521     }
4522   else
4523     {
4524       hostcnt = 0;
4525       minport = LOW_PORT;
4526     }
4527
4528   if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "HOSTKEYSFILE",
4529                                                           &hostkeys_file))
4530     {
4531       if (GNUNET_YES != GNUNET_DISK_file_test (hostkeys_file))
4532         GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Couldn't read hostkeys file!");
4533       else
4534         {
4535           /* Check hostkey file size, read entire thing into memory */
4536           fd = GNUNET_DISK_file_open (hostkeys_file, GNUNET_DISK_OPEN_READ,
4537                                       GNUNET_DISK_PERM_NONE);
4538           if (NULL == fd)
4539             {
4540               GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", hostkeys_file);
4541               return NULL;
4542             }
4543
4544           if (GNUNET_YES != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES))
4545             fs = 0;
4546
4547           GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Found file size %llu for hostkeys, expect hostkeys to be size %d\n", fs, HOSTKEYFILESIZE);
4548
4549           if (fs % HOSTKEYFILESIZE != 0)
4550             {
4551               GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "File size %llu seems incorrect for hostkeys...\n", fs);
4552             }
4553           else
4554             {
4555               total_hostkeys = fs / HOSTKEYFILESIZE;
4556               GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Will read %llu hostkeys from file\n", total_hostkeys);
4557               hostkey_data = GNUNET_malloc_large (fs);
4558               GNUNET_assert (fs == GNUNET_DISK_file_read (fd, hostkey_data, fs));
4559             }
4560         }
4561     }
4562
4563   for (off = 0; off < total; off++)
4564     {
4565       if (hostcnt > 0)
4566         {
4567           hostname = pg->hosts[off % hostcnt].hostname;
4568           username = pg->hosts[off % hostcnt].username;
4569           sshport = pg->hosts[off % hostcnt].sshport;
4570           pcfg = make_config (cfg,
4571                               &pg->hosts[off % hostcnt].minport,
4572                               &upnum, hostname, &fdnum);
4573         }
4574       else
4575         {
4576           hostname = NULL;
4577           username = NULL;
4578           sshport = 0;
4579           pcfg = make_config (cfg, &minport, &upnum, hostname, &fdnum);
4580         }
4581
4582       if (NULL == pcfg)
4583         {
4584           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4585                       _
4586                       ("Could not create configuration for peer number %u on `%s'!\n"),
4587                       off, hostname == NULL ? "localhost" : hostname);
4588           continue;
4589         }
4590
4591       if (GNUNET_YES ==
4592           GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
4593                                                  &baseservicehome))
4594         {
4595           GNUNET_asprintf (&newservicehome, "%s/%d/", baseservicehome, off);
4596           GNUNET_free (baseservicehome);
4597         }
4598       else
4599         {
4600           tmpdir = getenv ("TMPDIR");
4601           tmpdir = tmpdir ? tmpdir : "/tmp";
4602           GNUNET_asprintf (&newservicehome,
4603                            "%s/%s/%d/",
4604                            tmpdir, "gnunet-testing-test-test", off);
4605         }
4606       GNUNET_CONFIGURATION_set_value_string (pcfg,
4607                                              "PATHS",
4608                                              "SERVICEHOME", newservicehome);
4609       GNUNET_free (newservicehome);
4610       pg->peers[off].cfg = pcfg;
4611       pg->peers[off].allowed_peers =
4612         GNUNET_CONTAINER_multihashmap_create (total);
4613       pg->peers[off].connect_peers =
4614         GNUNET_CONTAINER_multihashmap_create (total);
4615       pg->peers[off].blacklisted_peers =
4616         GNUNET_CONTAINER_multihashmap_create (total);
4617       pg->peers[off].pg = pg;
4618
4619       pg->peers[off].internal_context.peer = &pg->peers[off];
4620       pg->peers[off].internal_context.timeout = timeout;
4621       pg->peers[off].internal_context.hostname = hostname;
4622       pg->peers[off].internal_context.username = username;
4623       pg->peers[off].internal_context.sshport = sshport;
4624       if (hostkey_data != NULL)
4625         pg->peers[off].internal_context.hostkey = &hostkey_data[off * HOSTKEYFILESIZE];
4626       pg->peers[off].internal_context.hostkey_callback = hostkey_callback;
4627       pg->peers[off].internal_context.hostkey_cls = hostkey_cls;
4628       pg->peers[off].internal_context.start_cb = cb;
4629       pg->peers[off].internal_context.start_cb_cls = cb_cls;
4630
4631       GNUNET_SCHEDULER_add_now (&internal_start,
4632                                 &pg->peers[off].internal_context);
4633
4634     }
4635   return pg;
4636 }
4637
4638 /*
4639  * Get a daemon by number, so callers don't have to do nasty
4640  * offsetting operation.
4641  */
4642 struct GNUNET_TESTING_Daemon *
4643 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg,
4644                            unsigned int position)
4645 {
4646   if (position < pg->total)
4647     return pg->peers[position].daemon;
4648   else
4649     return NULL;
4650 }
4651
4652 /*
4653  * Get a daemon by peer identity, so callers can
4654  * retrieve the daemon without knowing it's offset.
4655  *
4656  * @param pg the peer group to retrieve the daemon from
4657  * @param peer_id the peer identity of the daemon to retrieve
4658  *
4659  * @return the daemon on success, or NULL if no such peer identity is found
4660  */
4661 struct GNUNET_TESTING_Daemon *
4662 GNUNET_TESTING_daemon_get_by_id (struct GNUNET_TESTING_PeerGroup *pg,
4663                                  struct GNUNET_PeerIdentity *peer_id)
4664 {
4665   unsigned int i;
4666
4667   for (i = 0; i < pg->total; i++)
4668     {
4669       if (0 ==
4670           memcmp (&pg->peers[i].daemon->id, peer_id,
4671                   sizeof (struct GNUNET_PeerIdentity)))
4672         return pg->peers[i].daemon;
4673     }
4674
4675   return NULL;
4676 }
4677
4678 /**
4679  * Prototype of a function that will be called when a
4680  * particular operation was completed the testing library.
4681  *
4682  * @param cls closure (a struct RestartContext)
4683  * @param id id of the peer that was restarted
4684  * @param cfg handle to the configuration of the peer
4685  * @param d handle to the daemon that was restarted
4686  * @param emsg NULL on success
4687  */
4688 void
4689 restart_callback (void *cls,
4690                   const struct GNUNET_PeerIdentity *id,
4691                   const struct GNUNET_CONFIGURATION_Handle *cfg,
4692                   struct GNUNET_TESTING_Daemon *d, const char *emsg)
4693 {
4694   struct RestartContext *restart_context = cls;
4695
4696   if (emsg == NULL)
4697     {
4698       restart_context->peers_restarted++;
4699     }
4700   else
4701     {
4702       restart_context->peers_restart_failed++;
4703     }
4704
4705   if (restart_context->peers_restarted == restart_context->peer_group->total)
4706     {
4707       restart_context->callback (restart_context->callback_cls, NULL);
4708       GNUNET_free (restart_context);
4709     }
4710   else if (restart_context->peers_restart_failed +
4711            restart_context->peers_restarted ==
4712            restart_context->peer_group->total)
4713     {
4714       restart_context->callback (restart_context->callback_cls,
4715                                  "Failed to restart peers!");
4716       GNUNET_free (restart_context);
4717     }
4718
4719 }
4720
4721 /**
4722  * Callback for informing us about a successful
4723  * or unsuccessful churn stop call.
4724  *
4725  * @param cls a ChurnContext
4726  * @param emsg NULL on success, non-NULL on failure
4727  *
4728  */
4729 void
4730 churn_stop_callback (void *cls, const char *emsg)
4731 {
4732   struct ShutdownContext *shutdown_ctx = cls;
4733   struct ChurnContext *churn_ctx = shutdown_ctx->cb_cls;
4734   unsigned int total_left;
4735   char *error_message;
4736
4737   error_message = NULL;
4738   shutdown_ctx->outstanding--;
4739
4740   if (emsg != NULL)
4741     {
4742       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4743                   "Churn stop callback failed with error `%s'\n", emsg);
4744       churn_ctx->num_failed_stop++;
4745     }
4746   else
4747     {
4748       churn_ctx->num_to_stop--;
4749     }
4750
4751 #if DEBUG_CHURN
4752   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4753               "Stopped peer, %d left.\n", churn_ctx->num_to_stop);
4754 #endif
4755   total_left =
4756     (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) +
4757     (churn_ctx->num_to_start - churn_ctx->num_failed_start);
4758
4759   if (total_left == 0)
4760     {
4761       if ((churn_ctx->num_failed_stop > 0)
4762           || (churn_ctx->num_failed_start > 0))
4763         {
4764           GNUNET_asprintf (&error_message,
4765                            "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!",
4766                            churn_ctx->num_failed_start,
4767                            churn_ctx->num_failed_stop);
4768         }
4769       churn_ctx->cb (churn_ctx->cb_cls, error_message);
4770       GNUNET_free_non_null (error_message);
4771       GNUNET_free (churn_ctx);
4772       GNUNET_free (shutdown_ctx);
4773     }
4774 }
4775
4776 /**
4777  * Count the number of running peers.
4778  *
4779  * @param pg handle for the peer group
4780  *
4781  * @return the number of currently running peers in the peer group
4782  */
4783 unsigned int
4784 GNUNET_TESTING_daemons_running (struct GNUNET_TESTING_PeerGroup *pg)
4785 {
4786   unsigned int i;
4787   unsigned int running = 0;
4788   for (i = 0; i < pg->total; i++)
4789     {
4790       if (pg->peers[i].daemon->running == GNUNET_YES)
4791         {
4792           GNUNET_assert (running != -1);
4793           running++;
4794         }
4795     }
4796   return running;
4797 }
4798
4799 /**
4800  * Task to rate limit the number of outstanding peer shutdown
4801  * requests.  This is necessary for making sure we don't do
4802  * too many ssh connections at once, but is generally nicer
4803  * to any system as well (graduated task starts, as opposed
4804  * to calling gnunet-arm N times all at once).
4805  */
4806 static void
4807 schedule_churn_shutdown_task (void *cls,
4808                               const struct GNUNET_SCHEDULER_TaskContext *tc)
4809 {
4810   struct PeerShutdownContext *peer_shutdown_ctx = cls;
4811   struct ShutdownContext *shutdown_ctx;
4812
4813   GNUNET_assert (peer_shutdown_ctx != NULL);
4814   shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
4815   GNUNET_assert (shutdown_ctx != NULL);
4816
4817   if (shutdown_ctx->outstanding > MAX_CONCURRENT_SHUTDOWN)
4818     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
4819                                   (GNUNET_TIME_UNIT_MILLISECONDS, 100),
4820                                   &schedule_churn_shutdown_task,
4821                                   peer_shutdown_ctx);
4822   else
4823     {
4824       shutdown_ctx->outstanding++;
4825       GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon,
4826                                   shutdown_ctx->timeout, shutdown_ctx->cb,
4827                                   shutdown_ctx, GNUNET_NO, GNUNET_YES);
4828       GNUNET_free (peer_shutdown_ctx);
4829     }
4830 }
4831
4832 /**
4833  * Simulate churn by stopping some peers (and possibly
4834  * re-starting others if churn is called multiple times).  This
4835  * function can only be used to create leave-join churn (peers "never"
4836  * leave for good).  First "voff" random peers that are currently
4837  * online will be taken offline; then "von" random peers that are then
4838  * offline will be put back online.  No notifications will be
4839  * generated for any of these operations except for the callback upon
4840  * completion.
4841  *
4842  * @param pg handle for the peer group
4843  * @param voff number of peers that should go offline
4844  * @param von number of peers that should come back online;
4845  *            must be zero on first call (since "testbed_start"
4846  *            always starts all of the peers)
4847  * @param timeout how long to wait for operations to finish before
4848  *        giving up
4849  * @param cb function to call at the end
4850  * @param cb_cls closure for cb
4851  */
4852 void
4853 GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg,
4854                               unsigned int voff,
4855                               unsigned int von,
4856                               struct GNUNET_TIME_Relative timeout,
4857                               GNUNET_TESTING_NotifyCompletion cb,
4858                               void *cb_cls)
4859 {
4860   struct ChurnContext *churn_ctx;
4861   struct ShutdownContext *shutdown_ctx;
4862   struct PeerShutdownContext *peer_shutdown_ctx;
4863   struct PeerRestartContext *peer_restart_ctx;
4864   struct ChurnRestartContext *churn_startup_ctx;
4865
4866   unsigned int running;
4867   unsigned int stopped;
4868   unsigned int total_running;
4869   unsigned int total_stopped;
4870   unsigned int i;
4871   unsigned int *running_arr;
4872   unsigned int *stopped_arr;
4873   unsigned int *running_permute;
4874   unsigned int *stopped_permute;
4875
4876   running = 0;
4877   stopped = 0;
4878
4879   if ((von == 0) && (voff == 0))        /* No peers at all? */
4880     {
4881       cb (cb_cls, NULL);
4882       return;
4883     }
4884
4885   for (i = 0; i < pg->total; i++)
4886     {
4887       if (pg->peers[i].daemon->running == GNUNET_YES)
4888         {
4889           GNUNET_assert (running != -1);
4890           running++;
4891         }
4892       else
4893         {
4894           GNUNET_assert (stopped != -1);
4895           stopped++;
4896         }
4897     }
4898
4899   if (voff > running)
4900     {
4901       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4902                   "Trying to stop more peers than are currently running!\n");
4903       cb (cb_cls, "Trying to stop more peers than are currently running!");
4904       return;
4905     }
4906
4907   if (von > stopped)
4908     {
4909       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4910                   "Trying to start more peers than are currently stopped!\n");
4911       cb (cb_cls, "Trying to start more peers than are currently stopped!");
4912       return;
4913     }
4914
4915   churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext));
4916
4917   running_arr = NULL;
4918   if (running > 0)
4919     running_arr = GNUNET_malloc (running * sizeof (unsigned int));
4920
4921   stopped_arr = NULL;
4922   if (stopped > 0)
4923     stopped_arr = GNUNET_malloc (stopped * sizeof (unsigned int));
4924
4925   running_permute = NULL;
4926   stopped_permute = NULL;
4927
4928   if (running > 0)
4929     running_permute =
4930       GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, running);
4931   if (stopped > 0)
4932     stopped_permute =
4933       GNUNET_CRYPTO_random_permute (GNUNET_CRYPTO_QUALITY_WEAK, stopped);
4934
4935   total_running = running;
4936   total_stopped = stopped;
4937   running = 0;
4938   stopped = 0;
4939
4940   churn_ctx->num_to_start = von;
4941   churn_ctx->num_to_stop = voff;
4942   churn_ctx->cb = cb;
4943   churn_ctx->cb_cls = cb_cls;
4944
4945   for (i = 0; i < pg->total; i++)
4946     {
4947       if (pg->peers[i].daemon->running == GNUNET_YES)
4948         {
4949           GNUNET_assert ((running_arr != NULL) && (total_running > running));
4950           running_arr[running] = i;
4951           running++;
4952         }
4953       else
4954         {
4955           GNUNET_assert ((stopped_arr != NULL) && (total_stopped > stopped));
4956           stopped_arr[stopped] = i;
4957           stopped++;
4958         }
4959     }
4960
4961   GNUNET_assert (running >= voff);
4962   if (voff > 0)
4963     {
4964       shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext));
4965       shutdown_ctx->cb = &churn_stop_callback;
4966       shutdown_ctx->cb_cls = churn_ctx;
4967       shutdown_ctx->total_peers = voff;
4968       shutdown_ctx->timeout = timeout;
4969     }
4970
4971   for (i = 0; i < voff; i++)
4972     {
4973 #if DEBUG_CHURN
4974       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %d!\n",
4975                   running_permute[i]);
4976 #endif
4977       GNUNET_assert (running_arr != NULL);
4978       peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext));
4979       peer_shutdown_ctx->daemon =
4980         pg->peers[running_arr[running_permute[i]]].daemon;
4981       peer_shutdown_ctx->shutdown_ctx = shutdown_ctx;
4982       GNUNET_SCHEDULER_add_now (&schedule_churn_shutdown_task,
4983                                 peer_shutdown_ctx);
4984
4985       /*
4986          GNUNET_TESTING_daemon_stop (pg->peers[running_arr[running_permute[i]]].daemon,
4987          timeout, 
4988          &churn_stop_callback, churn_ctx, 
4989          GNUNET_NO, GNUNET_YES); */
4990     }
4991
4992   GNUNET_assert (stopped >= von);
4993   if (von > 0)
4994     {
4995       churn_startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext));
4996       churn_startup_ctx->churn_ctx = churn_ctx;
4997       churn_startup_ctx->timeout = timeout;
4998     }
4999   for (i = 0; i < von; i++)
5000     {
5001 #if DEBUG_CHURN
5002       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Starting up peer %d!\n",
5003                   stopped_permute[i]);
5004 #endif
5005       GNUNET_assert (stopped_arr != NULL);
5006       peer_restart_ctx = GNUNET_malloc (sizeof (struct PeerRestartContext));
5007       peer_restart_ctx->churn_restart_ctx = churn_startup_ctx;
5008       peer_restart_ctx->daemon =
5009         pg->peers[stopped_arr[stopped_permute[i]]].daemon;
5010       GNUNET_SCHEDULER_add_now (&schedule_churn_restart, peer_restart_ctx);
5011       /*
5012          GNUNET_TESTING_daemon_start_stopped(pg->peers[stopped_arr[stopped_permute[i]]].daemon, 
5013          timeout, &churn_start_callback, churn_ctx); */
5014     }
5015
5016   GNUNET_free_non_null (running_arr);
5017   GNUNET_free_non_null (stopped_arr);
5018   GNUNET_free_non_null (running_permute);
5019   GNUNET_free_non_null (stopped_permute);
5020 }
5021
5022
5023 /**
5024  * Restart all peers in the given group.
5025  *
5026  * @param pg the handle to the peer group
5027  * @param callback function to call on completion (or failure)
5028  * @param callback_cls closure for the callback function
5029  */
5030 void
5031 GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg,
5032                                 GNUNET_TESTING_NotifyCompletion callback,
5033                                 void *callback_cls)
5034 {
5035   struct RestartContext *restart_context;
5036   unsigned int off;
5037
5038   if (pg->total > 0)
5039     {
5040       restart_context = GNUNET_malloc (sizeof (struct RestartContext));
5041       restart_context->peer_group = pg;
5042       restart_context->peers_restarted = 0;
5043       restart_context->callback = callback;
5044       restart_context->callback_cls = callback_cls;
5045
5046       for (off = 0; off < pg->total; off++)
5047         {
5048           GNUNET_TESTING_daemon_restart (pg->peers[off].daemon,
5049                                          &restart_callback, restart_context);
5050         }
5051     }
5052 }
5053
5054 /**
5055  * Start or stop an individual peer from the given group.
5056  *
5057  * @param pg handle to the peer group
5058  * @param offset which peer to start or stop
5059  * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it
5060  * @param timeout how long to wait for shutdown
5061  * @param cb function to call at the end
5062  * @param cb_cls closure for cb
5063  */
5064 void
5065 GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg,
5066                              unsigned int offset,
5067                              int desired_status,
5068                              struct GNUNET_TIME_Relative timeout,
5069                              GNUNET_TESTING_NotifyCompletion cb, void *cb_cls)
5070 {
5071   struct ShutdownContext *shutdown_ctx;
5072   struct ChurnRestartContext *startup_ctx;
5073   struct ChurnContext *churn_ctx;
5074
5075   if (GNUNET_NO == desired_status)
5076     {
5077       if (NULL != pg->peers[offset].daemon)
5078         {
5079           shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext));
5080           churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext));
5081           churn_ctx->num_to_start = 0;
5082           churn_ctx->num_to_stop = 1;
5083           churn_ctx->cb = cb;
5084           churn_ctx->cb_cls = cb_cls;
5085           shutdown_ctx->cb_cls = churn_ctx;
5086           GNUNET_TESTING_daemon_stop (pg->peers[offset].daemon,
5087                                       timeout, &churn_stop_callback,
5088                                       shutdown_ctx, GNUNET_NO, GNUNET_YES);
5089         }
5090     }
5091   else if (GNUNET_YES == desired_status)
5092     {
5093       if (NULL == pg->peers[offset].daemon)
5094         {
5095           startup_ctx = GNUNET_malloc (sizeof (struct ChurnRestartContext));
5096           churn_ctx = GNUNET_malloc (sizeof (struct ChurnContext));
5097           churn_ctx->num_to_start = 1;
5098           churn_ctx->num_to_stop = 0;
5099           churn_ctx->cb = cb;
5100           churn_ctx->cb_cls = cb_cls;
5101           startup_ctx->churn_ctx = churn_ctx;
5102           GNUNET_TESTING_daemon_start_stopped (pg->peers[offset].daemon,
5103                                                timeout, &churn_start_callback,
5104                                                startup_ctx);
5105         }
5106     }
5107   else
5108     GNUNET_break (0);
5109 }
5110
5111
5112 /**
5113  * Callback for shutting down peers in a peer group.
5114  *
5115  * @param cls closure (struct ShutdownContext)
5116  * @param emsg NULL on success
5117  */
5118 void
5119 internal_shutdown_callback (void *cls, const char *emsg)
5120 {
5121   struct ShutdownContext *shutdown_ctx = cls;
5122
5123   shutdown_ctx->outstanding--;
5124   if (emsg == NULL)
5125     {
5126       shutdown_ctx->peers_down++;
5127     }
5128   else
5129     {
5130       shutdown_ctx->peers_failed++;
5131     }
5132
5133   if ((shutdown_ctx->cb != NULL)
5134       && (shutdown_ctx->peers_down + shutdown_ctx->peers_failed ==
5135           shutdown_ctx->total_peers))
5136     {
5137       if (shutdown_ctx->peers_failed > 0)
5138         shutdown_ctx->cb (shutdown_ctx->cb_cls,
5139                           "Not all peers successfully shut down!");
5140       else
5141         shutdown_ctx->cb (shutdown_ctx->cb_cls, NULL);
5142       GNUNET_free (shutdown_ctx);
5143     }
5144 }
5145
5146
5147 /**
5148  * Task to rate limit the number of outstanding peer shutdown
5149  * requests.  This is necessary for making sure we don't do
5150  * too many ssh connections at once, but is generally nicer
5151  * to any system as well (graduated task starts, as opposed
5152  * to calling gnunet-arm N times all at once).
5153  */
5154 static void
5155 schedule_shutdown_task (void *cls,
5156                         const struct GNUNET_SCHEDULER_TaskContext *tc)
5157 {
5158   struct PeerShutdownContext *peer_shutdown_ctx = cls;
5159   struct ShutdownContext *shutdown_ctx;
5160
5161   GNUNET_assert (peer_shutdown_ctx != NULL);
5162   shutdown_ctx = peer_shutdown_ctx->shutdown_ctx;
5163   GNUNET_assert (shutdown_ctx != NULL);
5164
5165   if (shutdown_ctx->outstanding > MAX_CONCURRENT_SHUTDOWN)
5166     GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
5167                                   (GNUNET_TIME_UNIT_MILLISECONDS, 100),
5168                                   &schedule_shutdown_task, peer_shutdown_ctx);
5169   else
5170     {
5171       shutdown_ctx->outstanding++;
5172       GNUNET_TESTING_daemon_stop (peer_shutdown_ctx->daemon,
5173                                   shutdown_ctx->timeout,
5174                                   &internal_shutdown_callback, shutdown_ctx,
5175                                   GNUNET_YES, GNUNET_NO);
5176       GNUNET_free (peer_shutdown_ctx);
5177     }
5178 }
5179
5180 /**
5181  * Shutdown all peers started in the given group.
5182  *
5183  * @param pg handle to the peer group
5184  * @param timeout how long to wait for shutdown
5185  * @param cb callback to notify upon success or failure
5186  * @param cb_cls closure for cb
5187  */
5188 void
5189 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg,
5190                              struct GNUNET_TIME_Relative timeout,
5191                              GNUNET_TESTING_NotifyCompletion cb, void *cb_cls)
5192 {
5193   unsigned int off;
5194   struct ShutdownContext *shutdown_ctx;
5195   struct PeerShutdownContext *peer_shutdown_ctx;
5196
5197   GNUNET_assert (pg->total > 0);
5198
5199   shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext));
5200   shutdown_ctx->cb = cb;
5201   shutdown_ctx->cb_cls = cb_cls;
5202   shutdown_ctx->total_peers = pg->total;
5203   shutdown_ctx->timeout = timeout;
5204   /* shtudown_ctx->outstanding = 0; */
5205
5206   for (off = 0; off < pg->total; off++)
5207     {
5208       GNUNET_assert (NULL != pg->peers[off].daemon);
5209       peer_shutdown_ctx = GNUNET_malloc (sizeof (struct PeerShutdownContext));
5210       peer_shutdown_ctx->daemon = pg->peers[off].daemon;
5211       peer_shutdown_ctx->shutdown_ctx = shutdown_ctx;
5212       GNUNET_SCHEDULER_add_now (&schedule_shutdown_task, peer_shutdown_ctx);
5213       //GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, timeout, shutdown_cb, shutdown_ctx, GNUNET_YES, GNUNET_NO);
5214       if (NULL != pg->peers[off].cfg)
5215         GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
5216       if (pg->peers[off].allowed_peers != NULL)
5217         GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].allowed_peers);
5218       if (pg->peers[off].connect_peers != NULL)
5219         GNUNET_CONTAINER_multihashmap_destroy (pg->peers[off].connect_peers);
5220       if (pg->peers[off].blacklisted_peers != NULL)
5221         GNUNET_CONTAINER_multihashmap_destroy (pg->
5222                                                peers[off].blacklisted_peers);
5223     }
5224   GNUNET_free (pg->peers);
5225   for (off = 0; off < pg->num_hosts; off++)
5226     {
5227       GNUNET_free (pg->hosts[off].hostname);
5228       GNUNET_free_non_null (pg->hosts[off].username);
5229     }
5230   GNUNET_free_non_null (pg->hosts);
5231   GNUNET_free (pg);
5232 }
5233
5234
5235 /* end of testing_group.c */