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