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