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