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