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