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