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