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