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