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