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