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