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