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