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