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