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