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