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