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