add statistics iteration to testing_group, test case for same.
[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 DEBUG_CHURN GNUNET_NO
36
37 /**
38  * Lowest port used for GNUnet testing.  Should be high enough to not
39  * conflict with other applications running on the hosts but be low
40  * enough to not conflict with client-ports (typically starting around
41  * 32k).
42  */
43 #define LOW_PORT 10000
44
45 /**
46  * Highest port used for GNUnet testing.  Should be low enough to not
47  * conflict with the port range for "local" ports (client apps; see
48  * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
49  */
50 #define HIGH_PORT 56000
51
52 #define MAX_OUTSTANDING_CONNECTIONS 10
53
54 #define MAX_CONCURRENT_HOSTKEYS 16
55
56 #define MAX_CONCURRENT_STARTING 50
57
58 #define CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
59
60 #define CONNECT_ATTEMPTS 8
61
62 /**
63  * Prototype of a function called whenever two peers would be connected
64  * in a certain topology.
65  */
66 typedef int (*GNUNET_TESTING_ConnectionProcessor)(struct GNUNET_TESTING_PeerGroup *pg, 
67                                                   unsigned int first,
68                                                   unsigned int second);
69
70
71 /**
72  * Context for handling churning a peer group
73  */
74 struct ChurnContext
75 {
76   /**
77    * Callback used to notify of churning finished
78    */
79   GNUNET_TESTING_NotifyCompletion cb;
80
81   /**
82    * Closure for callback
83    */
84   void *cb_cls;
85
86   /**
87    * Number of peers that still need to be started
88    */
89   unsigned int num_to_start;
90
91   /**
92    * Number of peers that still need to be stopped
93    */
94   unsigned int num_to_stop;
95  
96   /**
97    * Number of peers that failed to start
98    */
99   unsigned int num_failed_start;
100
101   /**
102    * Number of peers that failed to stop
103    */
104   unsigned int num_failed_stop;
105 };
106
107 struct RestartContext
108 {
109   /**
110    * The group of peers being restarted
111    */
112   struct GNUNET_TESTING_PeerGroup *peer_group;
113
114   /**
115    * How many peers have been restarted thus far
116    */
117   unsigned int peers_restarted;
118
119   /**
120    * How many peers got an error when restarting
121    */
122   unsigned int peers_restart_failed;
123
124   /**
125    * The function to call once all peers have been restarted
126    */
127   GNUNET_TESTING_NotifyCompletion callback;
128
129   /**
130    * Closure for callback function
131    */
132   void *callback_cls;
133
134 };
135
136
137 struct ShutdownContext
138 {
139   /**
140    * Total peers to wait for
141    */
142   int total_peers;
143
144   /**
145    * Number of peers successfully shut down
146    */
147   int peers_down;
148
149   /**
150    * Number of peers failed to shut down
151    */
152   int peers_failed;
153
154   /**
155    * Callback to call when all peers either
156    * shutdown or failed to shutdown
157    */
158   GNUNET_TESTING_NotifyCompletion cb;
159
160   /**
161    * Closure for cb
162    */
163   void *cb_cls;
164 };
165
166 struct CreateTopologyContext
167 {
168
169   /**
170    * Function to call with number of connections
171    */
172   GNUNET_TESTING_NotifyConnections cont;
173
174   /**
175    * Closure for connection notification
176    */
177   void *cls;
178 };
179
180 #if OLD
181 struct PeerConnection
182 {
183   /*
184    * Linked list
185    */
186   struct PeerConnection *next;
187
188   /*
189    * Pointer to daemon handle
190    */
191   struct GNUNET_TESTING_Daemon *daemon;
192
193 };
194 #endif
195
196 struct InternalStartContext
197 {
198   /**
199    * Pointer to peerdata
200    */
201   struct PeerData *peer;
202
203   /**
204    * Timeout for peer startup
205    */
206   struct GNUNET_TIME_Relative timeout;
207
208   /**
209    * Client callback for hostkey notification
210    */
211   GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback;
212
213   /**
214    * Closure for hostkey_callback
215    */
216   void *hostkey_cls;
217
218   /**
219    * Client callback for peer start notification
220    */
221   GNUNET_TESTING_NotifyDaemonRunning start_cb;
222
223   /**
224    * Closure for cb
225    */
226   void *start_cb_cls;
227
228   /**
229    * Hostname, where to start the peer
230    */
231   const char *hostname;
232 };
233
234 /**
235  * Data we keep per peer.
236  */
237 struct PeerData
238 {
239   /**
240    * (Initial) configuration of the host.
241    * (initial because clients could change
242    *  it and we would not know about those
243    *  updates).
244    */
245   struct GNUNET_CONFIGURATION_Handle *cfg;
246
247   /**
248    * Handle for controlling the daemon.
249    */
250   struct GNUNET_TESTING_Daemon *daemon;
251
252   /**
253    * The peergroup this peer belongs to.
254    */
255   struct GNUNET_TESTING_PeerGroup *pg;
256
257   /**
258    * Hash map of allowed peer connections (F2F created topology)
259    */
260   struct GNUNET_CONTAINER_MultiHashMap *allowed_peers;
261
262   /**
263    * Hash map of blacklisted peers
264    */
265   struct GNUNET_CONTAINER_MultiHashMap *blacklisted_peers;
266
267   /**
268    * Hash map of peer connections
269    */
270   struct GNUNET_CONTAINER_MultiHashMap *connect_peers;
271
272   /**
273    * Temporary hash map of peer connections
274    */
275   struct GNUNET_CONTAINER_MultiHashMap *connect_peers_working_set;
276
277   /**
278    * Temporary variable for topology creation, should be reset before
279    * creating any topology so the count is valid once finished.
280    */
281   int num_connections;
282
283   /**
284    * Context to keep track of peers being started, to
285    * stagger hostkey generation and peer startup.
286    */
287   struct InternalStartContext internal_context;
288 };
289
290
291 /**
292  * Data we keep per host.
293  */
294 struct HostData
295 {
296   /**
297    * Name of the host.
298    */
299   char *hostname;
300
301   /**
302    * Lowest port that we have not yet used
303    * for GNUnet.
304    */
305   uint16_t minport;
306 };
307
308 struct TopologyIterateContext
309 {
310   /**
311    * Callback for notifying of two connected peers.
312    */
313   GNUNET_TESTING_NotifyTopology topology_cb;
314
315   /**
316    * Closure for topology_cb
317    */
318   void *cls;
319
320   /**
321    * Number of peers currently connected to.
322    */
323   unsigned int connected;
324
325   /**
326    * Number of peers we have finished iterating.
327    */
328   unsigned int completed;
329
330   /**
331    * Number of peers total.
332    */
333   unsigned int total;
334 };
335
336 struct StatsIterateContext
337 {
338   /**
339    * Handle to the statistics service.
340    */
341   struct GNUNET_STATISTICS_Handle *stats_handle;
342
343   /**
344    * Handle for getting statistics.
345    */
346   struct GNUNET_STATISTICS_GetHandle *stats_get_handle;
347
348   /**
349    * Continuation to call once all stats information has been retrieved.
350    */
351   GNUNET_STATISTICS_Callback cont;
352
353   /**
354    * Proc function to call on each value received.
355    */
356   GNUNET_TESTING_STATISTICS_Iterator proc;
357
358   /**
359    * Closure for topology_cb
360    */
361   void *cls;
362
363   /**
364    * Number of peers currently connected to.
365    */
366   unsigned int connected;
367
368   /**
369    * Number of peers we have finished iterating.
370    */
371   unsigned int completed;
372
373   /**
374    * Number of peers total.
375    */
376   unsigned int total;
377 };
378
379 struct CoreContext
380 {
381   void *iter_context;
382   struct GNUNET_TESTING_Daemon *daemon;
383 };
384
385 /**
386  * Handle to a group of GNUnet peers.
387  */
388 struct GNUNET_TESTING_PeerGroup
389 {
390   /**
391    * Our scheduler.
392    */
393   struct GNUNET_SCHEDULER_Handle *sched;
394
395   /**
396    * Configuration template.
397    */
398   const struct GNUNET_CONFIGURATION_Handle *cfg;
399
400   /**
401    * Function to call on each started daemon.
402    */
403   //GNUNET_TESTING_NotifyDaemonRunning cb;
404
405   /**
406    * Closure for cb.
407    */
408   //void *cb_cls;
409
410   /*
411    * Function to call on each topology connection created
412    */
413   GNUNET_TESTING_NotifyConnection notify_connection;
414
415   /*
416    * Callback for notify_connection
417    */
418   void *notify_connection_cls;
419
420   /**
421    * NULL-terminated array of information about
422    * hosts.
423    */
424   struct HostData *hosts;
425
426   /**
427    * Array of "total" peers.
428    */
429   struct PeerData *peers;
430
431   /**
432    * Number of peers in this group.
433    */
434   unsigned int total;
435
436   /**
437    * At what time should we fail the peer startup process?
438    */
439   struct GNUNET_TIME_Absolute max_timeout;
440
441   /**
442    * How many peers are being started right now?
443    */
444   unsigned int starting;
445
446   /**
447    * How many peers have already been started?
448    */
449   unsigned int started;
450 };
451
452 struct UpdateContext
453 {
454   struct GNUNET_CONFIGURATION_Handle *ret;
455   const char *hostname;
456   unsigned int nport;
457   unsigned int upnum;
458 };
459
460
461 struct ConnectContext
462 {
463   struct GNUNET_TESTING_Daemon *first;
464
465   struct GNUNET_TESTING_Daemon *second;
466
467   struct GNUNET_TESTING_PeerGroup *pg;
468 };
469
470 /**
471  * Convert unique ID to hash code.
472  *
473  * @param uid unique ID to convert
474  * @param hash set to uid (extended with zeros)
475  */
476 static void
477 hash_from_uid (uint32_t uid,
478                GNUNET_HashCode *hash)
479 {
480   memset (hash, 0, sizeof(GNUNET_HashCode));
481   *((uint32_t*)hash) = uid;
482 }
483
484 /**
485  * Convert hash code to unique ID.
486  *
487  * @param uid unique ID to convert
488  * @param hash set to uid (extended with zeros)
489  */
490 static void
491 uid_from_hash (const GNUNET_HashCode *hash, uint32_t *uid)
492 {
493   memcpy (uid, hash, sizeof(uint32_t));
494 }
495
496 /**
497  * Number of connects we are waiting on, allows us to rate limit
498  * connect attempts.
499  */
500 static int outstanding_connects;
501
502 /**
503  * Get a topology from a string input.
504  *
505  * @param topology where to write the retrieved topology
506  * @param topology_string The string to attempt to
507  *        get a configuration value from
508  * @return GNUNET_YES if topology string matched a
509  *         known topology, GNUNET_NO if not
510  */
511 int
512 GNUNET_TESTING_topology_get(enum GNUNET_TESTING_Topology *topology, char * topology_string)
513 {
514   /**
515    * Strings representing topologies in enum
516    */
517   static const char * topology_strings[] =
518     {
519       /**
520        * A clique (everyone connected to everyone else).
521        */
522       "CLIQUE",
523       
524       /**
525        * Small-world network (2d torus plus random links).
526        */
527       "SMALL_WORLD",
528       
529       /**
530        * Small-world network (ring plus random links).
531        */
532       "SMALL_WORLD_RING",
533       
534       /**
535        * Ring topology.
536        */
537       "RING",
538       
539       /**
540        * 2-d torus.
541        */
542       "2D_TORUS",
543       
544       /**
545        * Random graph.
546        */
547       "ERDOS_RENYI",
548       
549       /**
550        * Certain percentage of peers are unable to communicate directly
551        * replicating NAT conditions
552        */
553       "INTERNAT",
554       
555       /**
556        * Scale free topology.
557        */
558       "SCALE_FREE",
559       
560       /**
561        * Straight line topology.
562        */
563       "LINE",
564       
565       /**
566        * All peers are disconnected.
567        */
568       "NONE",
569
570       NULL
571     };
572
573   int curr = 0;
574   if (topology_string == NULL)
575     return GNUNET_NO;
576   while (topology_strings[curr] != NULL)
577     {
578       if (strcasecmp(topology_strings[curr], topology_string) == 0)
579         {
580           *topology = curr;
581           return GNUNET_YES;
582         }
583       curr++;
584     }
585   *topology = GNUNET_TESTING_TOPOLOGY_NONE;
586   return GNUNET_NO;
587 }
588
589
590 /**
591  * Get connect topology option from string input.
592  *
593  * @param topology_option where to write the retrieved topology
594  * @param topology_string The string to attempt to
595  *        get a configuration value from
596  * @return GNUNET_YES if string matched a known
597  *         topology option, GNUNET_NO if not
598  */
599 int
600 GNUNET_TESTING_topology_option_get (enum GNUNET_TESTING_TopologyOption *topology_option,
601                                     char * topology_string)
602 {
603   /**
604    * Options for connecting a topology as strings.
605    */
606   static const char * topology_option_strings[] =
607     {
608       /**
609        * Try to connect all peers specified in the topology.
610        */
611       "CONNECT_ALL",
612       
613       /**
614        * Choose a random subset of connections to create.
615        */
616       "CONNECT_RANDOM_SUBSET",
617       
618       /**
619        * Create at least X connections for each peer.
620        */
621       "CONNECT_MINIMUM",
622       
623       /**
624        * Using a depth first search, create one connection
625        * per peer.  If any are missed (graph disconnected)
626        * start over at those peers until all have at least one
627        * connection.
628        */
629       "CONNECT_DFS",
630       
631       /**
632        * No options specified.
633        */
634       "CONNECT_NONE",
635
636       NULL
637     };
638   int curr = 0;
639
640   if (topology_string == NULL)
641     return GNUNET_NO;
642   while (NULL != topology_option_strings[curr])
643     {
644       if (strcasecmp(topology_option_strings[curr], topology_string) == 0)
645         {
646           *topology_option = curr;
647           return GNUNET_YES;
648         }
649       curr++;
650     } 
651   *topology_option = GNUNET_TESTING_TOPOLOGY_OPTION_NONE;
652   return GNUNET_NO;
653 }
654
655 /**
656  * Function to iterate over options.  Copies
657  * the options to the target configuration,
658  * updating PORT values as needed.
659  *
660  * @param cls closure
661  * @param section name of the section
662  * @param option name of the option
663  * @param value value of the option
664  */
665 static void
666 update_config (void *cls,
667                const char *section, const char *option, const char *value)
668 {
669   struct UpdateContext *ctx = cls;
670   unsigned int ival;
671   char cval[12];
672   char uval[128];
673
674   if ((0 == strcmp (option, "PORT")) && (1 == sscanf (value, "%u", &ival)))
675     {
676       if (ival != 0)
677         {
678           GNUNET_snprintf (cval, sizeof (cval), "%u", ctx->nport++);
679           value = cval;
680         }
681     }
682
683   if (0 == strcmp (option, "UNIXPATH"))
684     {
685       GNUNET_snprintf (uval, 
686                        sizeof (uval),
687                        "/tmp/test-service-%s-%u", 
688                        section,
689                        ctx->upnum++);
690       value = uval;
691     }
692
693   if ((0 == strcmp (option, "HOSTNAME")) && (ctx->hostname != NULL))
694     {
695       value = ctx->hostname;
696     }
697
698   GNUNET_CONFIGURATION_set_value_string (ctx->ret, section, option, value);
699 }
700
701
702 /**
703  * Create a new configuration using the given configuration
704  * as a template; however, each PORT in the existing cfg
705  * must be renumbered by incrementing "*port".  If we run
706  * out of "*port" numbers, return NULL.
707  *
708  * @param cfg template configuration
709  * @param port port numbers to use, update to reflect
710  *             port numbers that were used
711  * @param upnum number to make unix domain socket names unique
712  * @param hostname hostname of the controlling host, to allow control connections from
713  *
714  * @return new configuration, NULL on error
715  */
716 static struct GNUNET_CONFIGURATION_Handle *
717 make_config (const struct GNUNET_CONFIGURATION_Handle *cfg, 
718              uint16_t * port,
719              uint32_t * upnum,
720              const char *hostname)
721 {
722   struct UpdateContext uc;
723   uint16_t orig;
724   char *control_host;
725   char *allowed_hosts;
726
727   orig = *port;
728   uc.nport = *port;
729   uc.upnum = *upnum;
730   uc.ret = GNUNET_CONFIGURATION_create ();
731   uc.hostname = hostname;
732
733   GNUNET_CONFIGURATION_iterate (cfg, &update_config, &uc);
734   if (uc.nport >= HIGH_PORT)
735     {
736       *port = orig;
737       GNUNET_CONFIGURATION_destroy (uc.ret);
738       return NULL;
739     }
740
741   if (GNUNET_CONFIGURATION_get_value_string(cfg, "testing", "control_host", &control_host) == GNUNET_OK)
742     {
743       GNUNET_asprintf(&allowed_hosts, "%s; 127.0.0.1;", control_host);
744       GNUNET_CONFIGURATION_set_value_string(uc.ret, "core", "ACCEPT_FROM", allowed_hosts);
745       GNUNET_CONFIGURATION_set_value_string(uc.ret, "transport", "ACCEPT_FROM", allowed_hosts);
746       GNUNET_free_non_null(control_host);
747       GNUNET_free(allowed_hosts);
748     }
749
750
751   /* arm needs to know to allow connections from the host on which it is running,
752    * otherwise gnunet-arm is unable to connect to it in some instances */
753   if (hostname != NULL)
754     {
755       GNUNET_asprintf(&allowed_hosts, "%s; 127.0.0.1;", hostname);
756       GNUNET_CONFIGURATION_set_value_string(uc.ret, "arm", "ACCEPT_FROM", allowed_hosts);
757       GNUNET_free(allowed_hosts);
758     }
759
760   *port = (uint16_t) uc.nport;
761   *upnum = uc.upnum;
762   return uc.ret;
763 }
764
765
766 /*
767  * Add entries to the peers connect list
768  *
769  * @param pg the peer group we are working with
770  * @param first index of the first peer
771  * @param second index of the second peer
772  *
773  * @return the number of connections added
774  *         technically should only be 0 or 2
775  *
776  */
777 static int
778 add_actual_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
779 {
780   int added;
781   int add_first;
782   int add_second;
783
784   GNUNET_HashCode hash_first;
785   GNUNET_HashCode hash_second;
786
787   hash_from_uid(first, &hash_first);
788   hash_from_uid(second, &hash_second);
789
790   add_first = GNUNET_NO;
791   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].connect_peers, &hash_second))
792     {
793       add_first = GNUNET_YES;
794     }
795
796   add_second = GNUNET_NO;
797   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].connect_peers, &hash_first))
798     {
799       add_second = GNUNET_YES;
800     }
801
802   added = 0;
803   if (add_first)
804     {
805       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[first].connect_peers, &hash_second, pg->peers[second].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
806       pg->peers[first].num_connections++;
807       added++;
808     }
809
810   if (add_second)
811     {
812       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[second].connect_peers, &hash_first, pg->peers[first].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
813       pg->peers[second].num_connections++;
814       added++;
815     }
816
817   return added;
818 }
819
820
821 /*
822  * Add entries to the peers allowed connections list
823  *
824  * @param pg the peer group we are working with
825  * @param first index of the first peer
826  * @param second index of the second peer
827  *
828  * @return the number of connections added (can be 0, 1 or 2)
829  *         technically should only be 0 or 2, but the small price
830  *         of iterating over the lists (hashmaps in the future)
831  *         for being sure doesn't bother me!
832  *
833  */
834 static int
835 add_allowed_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
836 {
837   int added;
838 #if OLD
839   struct PeerConnection *first_iter;
840   struct PeerConnection *second_iter;
841   struct PeerConnection *new_first;
842   struct PeerConnection *new_second;
843 #endif
844   int add_first;
845   int add_second;
846
847   GNUNET_HashCode hash_first;
848   GNUNET_HashCode hash_second;
849
850   hash_from_uid(first, &hash_first);
851   hash_from_uid(second, &hash_second);
852
853   add_first = GNUNET_NO;
854   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].allowed_peers, &hash_second))
855     {
856       add_first = GNUNET_YES;
857     }
858
859   add_second = GNUNET_NO;
860   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].allowed_peers, &hash_first))
861     {
862       add_second = GNUNET_YES;
863     }
864 #if OLD
865   first_iter = pg->peers[first].connected_peers;
866   while (first_iter != NULL)
867     {
868       if (first_iter->daemon == pg->peers[second].daemon)
869         add_first = GNUNET_NO;
870       first_iter = first_iter->next;
871     }
872
873   second_iter = pg->peers[second].connected_peers;
874   add_second = GNUNET_YES;
875   while (second_iter != NULL)
876     {
877       if (second_iter->daemon == pg->peers[first].daemon)
878         add_second = GNUNET_NO;
879       second_iter = second_iter->next;
880     }
881 #endif
882
883   added = 0;
884   if (add_first)
885     {
886       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[first].allowed_peers, &hash_second, pg->peers[second].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
887 #if OLD
888       new_first = GNUNET_malloc(sizeof(struct PeerConnection));
889       new_first->daemon = pg->peers[second].daemon;
890       new_first->next = pg->peers[first].connected_peers;
891       pg->peers[first].connected_peers = new_first;
892 #endif
893       pg->peers[first].num_connections++;
894       added++;
895     }
896
897   if (add_second)
898     {
899       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[second].allowed_peers, &hash_first, pg->peers[first].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
900 #if OLD
901       new_second = GNUNET_malloc(sizeof(struct PeerConnection));
902       new_second->daemon = pg->peers[first].daemon;
903       new_second->next = pg->peers[second].connected_peers;
904       pg->peers[second].connected_peers = new_second;
905       pg->peers[first].num_connections++;
906 #endif
907       pg->peers[second].num_connections++;
908       added++;
909     }
910
911   return added;
912 }
913
914 /*
915  * Add entries to the peers blacklisted list
916  *
917  * @param pg the peer group we are working with
918  * @param first index of the first peer
919  * @param second index of the second peer
920  *
921  * @return the number of connections added (can be 0, 1 or 2)
922  *
923  */
924 static int
925 blacklist_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
926 {
927   int added;
928   int add_first;
929   int add_second;
930   GNUNET_HashCode hash_first;
931   GNUNET_HashCode hash_second;
932
933   hash_from_uid(first, &hash_first);
934   hash_from_uid(second, &hash_second);
935
936   add_first = GNUNET_NO;
937   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].blacklisted_peers, &hash_second))
938     {
939       add_first = GNUNET_YES;
940     }
941
942   add_second = GNUNET_NO;
943   if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].blacklisted_peers, &hash_first))
944     {
945       add_second = GNUNET_YES;
946     }
947
948   added = 0;
949   if (add_first)
950     {
951       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[first].blacklisted_peers, &hash_second, pg->peers[second].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
952       pg->peers[first].num_connections++;
953       added++;
954     }
955
956   if (add_second)
957     {
958       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(pg->peers[second].blacklisted_peers, &hash_first, pg->peers[first].daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
959       pg->peers[second].num_connections++;
960       added++;
961     }
962
963   return added;
964 }
965
966 /*
967  * Remove entries from the peers blacklisted list
968  *
969  * @param pg the peer group we are working with
970  * @param first index of the first peer
971  * @param second index of the second peer
972  *
973  * @return the number of connections removed (can be 0, 1 or 2)
974  *
975  */
976 static int
977 unblacklist_connections(struct GNUNET_TESTING_PeerGroup *pg, unsigned int first, unsigned int second)
978 {
979   int removed;
980   int remove_first;
981   int remove_second;
982   GNUNET_HashCode hash_first;
983   GNUNET_HashCode hash_second;
984
985   hash_from_uid(first, &hash_first);
986   hash_from_uid(second, &hash_second);
987
988   remove_first = GNUNET_CONTAINER_multihashmap_contains(pg->peers[first].blacklisted_peers, &hash_second);
989   remove_second = GNUNET_CONTAINER_multihashmap_contains(pg->peers[second].blacklisted_peers, &hash_first);
990
991   removed = 0;
992   if (remove_first)
993     {
994       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[first].blacklisted_peers, &hash_second, pg->peers[second].daemon));
995       removed++;
996     }
997
998   if (remove_second)
999     {
1000       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[second].blacklisted_peers, &hash_first, pg->peers[first].daemon));
1001       removed++;
1002     }
1003
1004   return removed;
1005 }
1006
1007 /**
1008  * Scale free network construction as described in:
1009  *
1010  * "Emergence of Scaling in Random Networks." Science 286, 509-512, 1999.
1011  *
1012  * Start with a network of "one" peer, then progressively add
1013  * peers up to the total number.  At each step, iterate over
1014  * all possible peers and connect new peer based on number of
1015  * existing connections of the target peer.
1016  *
1017  * @param pg the peer group we are dealing with
1018  * @param proc the connection processor to use
1019  *
1020  * @return the number of connections created
1021  */
1022 static int
1023 create_scale_free (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1024 {
1025
1026   unsigned int total_connections;
1027   unsigned int outer_count;
1028   unsigned int i;
1029   unsigned int previous_total_connections;
1030   double random;
1031   double probability;
1032
1033   GNUNET_assert(pg->total > 1);
1034
1035   /* Add a connection between the first two nodes */
1036   total_connections = proc(pg, 0, 1);
1037
1038   for (outer_count = 1; outer_count < pg->total; outer_count++)
1039     {
1040       previous_total_connections = total_connections;
1041       for (i = 0; i < outer_count; i++)
1042         {
1043           probability = pg->peers[i].num_connections / (double)previous_total_connections;
1044           random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
1045                                                       UINT64_MAX)) / ( (double) UINT64_MAX);
1046 #if VERBOSE_TESTING
1047           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1048                       "Considering connecting peer %d to peer %d\n",
1049                       outer_count, i);
1050 #endif
1051           if (random < probability)
1052             {
1053 #if VERBOSE_TESTING
1054               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1055                           "Connecting peer %d to peer %d\n",
1056                           outer_count, i);
1057 #endif
1058               total_connections += proc(pg, outer_count, i);
1059             }
1060         }
1061     }
1062
1063   return total_connections;
1064 }
1065
1066 /**
1067  * Create a topology given a peer group (set of running peers)
1068  * and a connection processor.
1069  *
1070  * @param pg the peergroup to create the topology on
1071  * @param proc the connection processor to call to actually set
1072  *        up connections between two peers
1073  *
1074  * @return the number of connections that were set up
1075  *
1076  */
1077 int
1078 create_small_world_ring(struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1079 {
1080   unsigned int i, j;
1081   int nodeToConnect;
1082   unsigned int natLog;
1083   unsigned int randomPeer;
1084   double random, logNModifier, percentage;
1085   unsigned int smallWorldConnections;
1086   int connsPerPeer;
1087   char *p_string;
1088   int max;
1089   int min;
1090   unsigned int useAnd;
1091   int connect_attempts;
1092
1093   logNModifier = 0.5; /* FIXME: default value? */
1094   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
1095                                                          "TESTING",
1096                                                          "LOGNMODIFIER",
1097                                                          &p_string))
1098     {
1099       if (sscanf(p_string, "%lf", &logNModifier) != 1)
1100         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1101                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1102                     p_string,
1103                     "LOGNMODIFIER",
1104                     "TESTING");
1105       GNUNET_free (p_string);
1106     }
1107   percentage = 0.5; /* FIXME: default percentage? */
1108   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
1109                                                          "TESTING",
1110                                                          "PERCENTAGE",
1111                                                          &p_string))
1112     {
1113       if (sscanf(p_string, "%lf", &percentage) != 1)
1114         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1115                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1116                     p_string,
1117                     "PERCENTAGE",
1118                     "TESTING");
1119       GNUNET_free (p_string);
1120     }
1121   natLog = log (pg->total);
1122   connsPerPeer = ceil (natLog * logNModifier);
1123
1124   if (connsPerPeer % 2 == 1)
1125     connsPerPeer += 1;
1126
1127   smallWorldConnections = 0;
1128   connect_attempts = 0;
1129   for (i = 0; i < pg->total; i++)
1130     {
1131       useAnd = 0;
1132       max = i + connsPerPeer / 2;
1133       min = i - connsPerPeer / 2;
1134
1135       if (max > pg->total - 1)
1136         {
1137           max = max - pg->total;
1138           useAnd = 1;
1139         }
1140
1141       if (min < 0)
1142         {
1143           min = pg->total - 1 + min;
1144           useAnd = 1;
1145         }
1146
1147       for (j = 0; j < connsPerPeer / 2; j++)
1148         {
1149           random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
1150                                                       UINT64_MAX) / ( (double) UINT64_MAX));
1151           if (random < percentage)
1152             {
1153               /* Connect to uniformly selected random peer */
1154               randomPeer =
1155                 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1156                                    pg->total);
1157               while ((((randomPeer < max) && (randomPeer > min))
1158                       && (useAnd == 0)) || (((randomPeer > min)
1159                                              || (randomPeer < max))
1160                                             && (useAnd == 1)))
1161                 {
1162                   randomPeer =
1163                       GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1164                                                          pg->total);
1165                 }
1166               smallWorldConnections +=
1167                 proc (pg, i, randomPeer);
1168             }
1169           else
1170             {
1171               nodeToConnect = i + j + 1;
1172               if (nodeToConnect > pg->total - 1)
1173                 {
1174                   nodeToConnect = nodeToConnect - pg->total;
1175                 }
1176               connect_attempts +=
1177                 proc (pg, i, nodeToConnect);
1178             }
1179         }
1180
1181     }
1182
1183   connect_attempts += smallWorldConnections;
1184
1185   return connect_attempts;
1186 }
1187
1188 /**
1189  * Create a topology given a peer group (set of running peers)
1190  * and a connection processor.
1191  *
1192  * @param pg the peergroup to create the topology on
1193  * @param proc the connection processor to call to actually set
1194  *        up connections between two peers
1195  *
1196  * @return the number of connections that were set up
1197  *
1198  */
1199 static int
1200 create_nated_internet (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1201 {
1202   unsigned int outer_count, inner_count;
1203   unsigned int cutoff;
1204   int connect_attempts;
1205   double nat_percentage;
1206   char *p_string;
1207
1208   nat_percentage = 0.6; /* FIXME: default percentage? */
1209   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
1210                                                          "TESTING",
1211                                                          "NATPERCENTAGE",
1212                                                          &p_string))
1213     {
1214       if (sscanf(p_string, "%lf", &nat_percentage) != 1)
1215         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1216                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1217                     p_string,
1218                     "NATPERCENTAGE",
1219                     "TESTING");
1220       GNUNET_free (p_string);
1221     }
1222
1223
1224
1225   cutoff = (unsigned int) (nat_percentage * pg->total);
1226
1227   connect_attempts = 0;
1228
1229   for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
1230     {
1231       for (inner_count = outer_count + 1; inner_count < pg->total;
1232            inner_count++)
1233         {
1234           if ((outer_count > cutoff) || (inner_count > cutoff))
1235             {
1236 #if VERBOSE_TESTING
1237               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1238                           "Connecting peer %d to peer %d\n",
1239                           outer_count, inner_count);
1240 #endif
1241               connect_attempts += proc(pg, outer_count, inner_count);
1242             }
1243         }
1244     }
1245
1246   return connect_attempts;
1247
1248 }
1249
1250 /**
1251  * Create a topology given a peer group (set of running peers)
1252  * and a connection processor.
1253  *
1254  * @param pg the peergroup to create the topology on
1255  * @param proc the connection processor to call to actually set
1256  *        up connections between two peers
1257  *
1258  * @return the number of connections that were set up
1259  *
1260  */
1261 static int
1262 create_small_world (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1263 {
1264   unsigned int i, j, k;
1265   unsigned int square;
1266   unsigned int rows;
1267   unsigned int cols;
1268   unsigned int toggle = 1;
1269   unsigned int nodeToConnect;
1270   unsigned int natLog;
1271   unsigned int node1Row;
1272   unsigned int node1Col;
1273   unsigned int node2Row;
1274   unsigned int node2Col;
1275   unsigned int distance;
1276   double probability, random, percentage;
1277   unsigned int smallWorldConnections;
1278   char *p_string;
1279   int connect_attempts;
1280   square = floor (sqrt (pg->total));
1281   rows = square;
1282   cols = square;
1283
1284   percentage = 0.5; /* FIXME: default percentage? */
1285   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
1286                                                          "TESTING",
1287                                                          "PERCENTAGE",
1288                                                          &p_string))
1289     {
1290       if (sscanf(p_string, "%lf", &percentage) != 1)
1291         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1292                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1293                     p_string,
1294                     "PERCENTAGE",
1295                     "TESTING");
1296       GNUNET_free (p_string);
1297     }
1298   probability = 0.5; /* FIXME: default percentage? */
1299   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
1300                                                          "TESTING",
1301                                                          "PROBABILITY",
1302                                                          &p_string))
1303     {
1304       if (sscanf(p_string, "%lf", &probability) != 1)
1305         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1306                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1307                     p_string,
1308                     "PROBABILITY",
1309                     "TESTING");
1310       GNUNET_free (p_string);
1311     }
1312   if (square * square != pg->total)
1313     {
1314       while (rows * cols < pg->total)
1315         {
1316           if (toggle % 2 == 0)
1317             rows++;
1318           else
1319             cols++;
1320
1321           toggle++;
1322         }
1323     }
1324 #if VERBOSE_TESTING
1325       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1326                   _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
1327                   rows, cols);
1328 #endif
1329
1330   connect_attempts = 0;
1331   /* Rows and columns are all sorted out, now iterate over all nodes and connect each
1332    * to the node to its right and above.  Once this is over, we'll have our torus!
1333    * Special case for the last node (if the rows and columns are not equal), connect
1334    * to the first in the row to maintain topology.
1335    */
1336   for (i = 0; i < pg->total; i++)
1337     {
1338       /* First connect to the node to the right */
1339       if (((i + 1) % cols != 0) && (i + 1 != pg->total))
1340         nodeToConnect = i + 1;
1341       else if (i + 1 == pg->total)
1342         nodeToConnect = rows * cols - cols;
1343       else
1344         nodeToConnect = i - cols + 1;
1345
1346       connect_attempts += proc (pg, i, nodeToConnect);
1347
1348       if (i < cols)
1349         nodeToConnect = (rows * cols) - cols + i;
1350       else
1351         nodeToConnect = i - cols;
1352
1353       if (nodeToConnect < pg->total)
1354         connect_attempts += proc (pg, i, nodeToConnect);
1355     }
1356   natLog = log (pg->total);
1357 #if VERBOSE_TESTING > 2
1358   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1359               _("natural log of %d is %d, will run %d iterations\n"),
1360              pg->total, natLog, (int) (natLog * percentage));
1361   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Total connections added thus far: %u!\n"), connect_attempts);
1362 #endif
1363   smallWorldConnections = 0;
1364   for (i = 0; i < (int) (natLog * percentage); i++)
1365     {
1366       for (j = 0; j < pg->total; j++)
1367         {
1368           /* Determine the row and column of node at position j on the 2d torus */
1369           node1Row = j / cols;
1370           node1Col = j - (node1Row * cols);
1371           for (k = 0; k < pg->total; k++)
1372             {
1373               /* Determine the row and column of node at position k on the 2d torus */
1374               node2Row = k / cols;
1375               node2Col = k - (node2Row * cols);
1376               /* Simple Cartesian distance */
1377               distance = abs (node1Row - node2Row) + abs (node1Col - node2Col);
1378               if (distance > 1)
1379                 {
1380                   /* Calculate probability as 1 over the square of the distance */
1381                   probability = 1.0 / (distance * distance);
1382                   /* Choose a random value between 0 and 1 */
1383                   random = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
1384                                                               UINT64_MAX)) / ( (double) UINT64_MAX);
1385                   /* If random < probability, then connect the two nodes */
1386                   if (random < probability)
1387                     smallWorldConnections += proc (pg, j, k);
1388
1389                 }
1390             }
1391         }
1392     }
1393   connect_attempts += smallWorldConnections;
1394 #if VERBOSE_TESTING > 2
1395           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1396                       _("Total connections added for small world: %d!\n"),
1397                       smallWorldConnections);
1398 #endif
1399   return connect_attempts;
1400 }
1401
1402 /**
1403  * Create a topology given a peer group (set of running peers)
1404  * and a connection processor.
1405  *
1406  * @param pg the peergroup to create the topology on
1407  * @param proc the connection processor to call to actually set
1408  *        up connections between two peers
1409  *
1410  * @return the number of connections that were set up
1411  *
1412  */
1413 static int
1414 create_erdos_renyi (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1415 {
1416   double temp_rand;
1417   unsigned int outer_count;
1418   unsigned int inner_count;
1419   int connect_attempts;
1420   double probability;
1421   char *p_string;
1422
1423   probability = 0.5; /* FIXME: default percentage? */
1424   if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string(pg->cfg,
1425                                                          "TESTING",
1426                                                          "PROBABILITY",
1427                                                          &p_string))
1428     {
1429       if (sscanf(p_string, "%lf", &probability) != 1)
1430         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1431                     _("Invalid value `%s' for option `%s' in section `%s': expected float\n"),
1432                     p_string,
1433                     "PROBABILITY",
1434                     "TESTING");
1435       GNUNET_free (p_string);
1436     }
1437   connect_attempts = 0;
1438   for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
1439     {
1440       for (inner_count = outer_count + 1; inner_count < pg->total;
1441            inner_count++)
1442         {
1443           temp_rand = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
1444                                                          UINT64_MAX)) / ( (double) UINT64_MAX);
1445 #if VERBOSE_TESTING
1446           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1447                       _("rand is %f probability is %f\n"), temp_rand,
1448                       probability);
1449 #endif
1450           if (temp_rand < probability)
1451             {
1452               connect_attempts += proc (pg, outer_count, inner_count);
1453             }
1454         }
1455     }
1456
1457   return connect_attempts;
1458 }
1459
1460 /**
1461  * Create a topology given a peer group (set of running peers)
1462  * and a connection processor.
1463  *
1464  * @param pg the peergroup to create the topology on
1465  * @param proc the connection processor to call to actually set
1466  *        up connections between two peers
1467  *
1468  * @return the number of connections that were set up
1469  *
1470  */
1471 static int
1472 create_2d_torus (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1473 {
1474   unsigned int i;
1475   unsigned int square;
1476   unsigned int rows;
1477   unsigned int cols;
1478   unsigned int toggle = 1;
1479   unsigned int nodeToConnect;
1480   int connect_attempts;
1481
1482   connect_attempts = 0;
1483
1484   square = floor (sqrt (pg->total));
1485   rows = square;
1486   cols = square;
1487
1488   if (square * square != pg->total)
1489     {
1490       while (rows * cols < pg->total)
1491         {
1492           if (toggle % 2 == 0)
1493             rows++;
1494           else
1495             cols++;
1496
1497           toggle++;
1498         }
1499     }
1500 #if VERBOSE_TESTING
1501       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1502                   _("Connecting nodes in 2d torus topology: %u rows %u columns\n"),
1503                   rows, cols);
1504 #endif
1505   /* Rows and columns are all sorted out, now iterate over all nodes and connect each
1506    * to the node to its right and above.  Once this is over, we'll have our torus!
1507    * Special case for the last node (if the rows and columns are not equal), connect
1508    * to the first in the row to maintain topology.
1509    */
1510   for (i = 0; i < pg->total; i++)
1511     {
1512       /* First connect to the node to the right */
1513       if (((i + 1) % cols != 0) && (i + 1 != pg->total))
1514         nodeToConnect = i + 1;
1515       else if (i + 1 == pg->total)
1516         nodeToConnect = rows * cols - cols;
1517       else
1518         nodeToConnect = i - cols + 1;
1519 #if VERBOSE_TESTING
1520           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1521                       "Connecting peer %d to peer %d\n",
1522                       i, nodeToConnect);
1523 #endif
1524       connect_attempts += proc(pg, i, nodeToConnect);
1525
1526       /* Second connect to the node immediately above */
1527       if (i < cols)
1528         nodeToConnect = (rows * cols) - cols + i;
1529       else
1530         nodeToConnect = i - cols;
1531
1532       if (nodeToConnect < pg->total)
1533         {
1534 #if VERBOSE_TESTING
1535           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1536                       "Connecting peer %d to peer %d\n",
1537                       i, nodeToConnect);
1538 #endif
1539           connect_attempts += proc(pg, i, nodeToConnect);
1540         }
1541
1542     }
1543
1544   return connect_attempts;
1545 }
1546
1547
1548 /**
1549  * Create a topology given a peer group (set of running peers)
1550  * and a connection processor.
1551  *
1552  * @param pg the peergroup to create the topology on
1553  * @param proc the connection processor to call to actually set
1554  *        up connections between two peers
1555  *
1556  * @return the number of connections that were set up
1557  *
1558  */
1559 static int
1560 create_clique (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1561 {
1562   unsigned int outer_count;
1563   unsigned int inner_count;
1564   int connect_attempts;
1565
1566   connect_attempts = 0;
1567
1568   for (outer_count = 0; outer_count < pg->total - 1; outer_count++)
1569     {
1570       for (inner_count = outer_count + 1; inner_count < pg->total;
1571            inner_count++)
1572         {
1573 #if VERBOSE_TESTING
1574           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1575                       "Connecting peer %d to peer %d\n",
1576                       outer_count, inner_count);
1577 #endif
1578           connect_attempts += proc(pg, outer_count, inner_count);
1579         }
1580     }
1581
1582   return connect_attempts;
1583 }
1584
1585 /**
1586  * Create a topology given a peer group (set of running peers)
1587  * and a connection processor.
1588  *
1589  * @param pg the peergroup to create the topology on
1590  * @param proc the connection processor to call to actually set
1591  *        up connections between two peers
1592  *
1593  * @return the number of connections that were set up
1594  *
1595  */
1596 static int
1597 create_line (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1598 {
1599   unsigned int count;
1600   int connect_attempts;
1601
1602   connect_attempts = 0;
1603
1604   /* Connect each peer to the next highest numbered peer */
1605   for (count = 0; count < pg->total - 1; count++)
1606     {
1607 #if VERBOSE_TESTING
1608           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1609                       "Connecting peer %d to peer %d\n",
1610                       count, count + 1);
1611 #endif
1612       connect_attempts += proc(pg, count, count + 1);
1613     }
1614
1615   return connect_attempts;
1616 }
1617
1618 /**
1619  * Create a topology given a peer group (set of running peers)
1620  * and a connection processor.
1621  *
1622  * @param pg the peergroup to create the topology on
1623  * @param proc the connection processor to call to actually set
1624  *        up connections between two peers
1625  *
1626  * @return the number of connections that were set up
1627  *
1628  */
1629 static int
1630 create_ring (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_ConnectionProcessor proc)
1631 {
1632   unsigned int count;
1633   int connect_attempts;
1634
1635   connect_attempts = 0;
1636
1637   /* Connect each peer to the next highest numbered peer */
1638   for (count = 0; count < pg->total - 1; count++)
1639     {
1640 #if VERBOSE_TESTING
1641           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1642                       "Connecting peer %d to peer %d\n",
1643                       count, count + 1);
1644 #endif
1645       connect_attempts += proc(pg, count, count + 1);
1646     }
1647
1648   /* Connect the last peer to the first peer */
1649   connect_attempts += proc(pg, pg->total - 1, 0);
1650
1651   return connect_attempts;
1652 }
1653
1654
1655 /**
1656  * Iterator for writing friends of a peer to a file.
1657  *
1658  * @param cls closure, an open writable file handle
1659  * @param key the key the daemon was stored under
1660  * @param value the GNUNET_TESTING_Daemon that needs to be written.
1661  *
1662  * @return GNUNET_YES to continue iteration
1663  *
1664  * TODO: Could replace friend_file_iterator and blacklist_file_iterator
1665  *       with a single file_iterator that takes a closure which contains
1666  *       the prefix to write before the peer.  Then this could be used
1667  *       for blacklisting multiple transports and writing the friend
1668  *       file.  I'm sure *someone* will complain loudly about other
1669  *       things that negate these functions even existing so no point in
1670  *       "fixing" now.
1671  */
1672 static int
1673 friend_file_iterator (void *cls,
1674                   const GNUNET_HashCode * key,
1675                   void *value)
1676 {
1677   FILE *temp_friend_handle = cls;
1678   struct GNUNET_TESTING_Daemon *peer = value;
1679   struct GNUNET_PeerIdentity *temppeer;
1680   struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
1681
1682   temppeer = &peer->id;
1683   GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
1684   fprintf(temp_friend_handle, "%s\n", (char *)&peer_enc);
1685
1686   return GNUNET_YES;
1687 }
1688
1689 struct BlacklistContext
1690 {
1691   /*
1692    * The (open) file handle to write to
1693    */
1694   FILE *temp_file_handle;
1695
1696   /*
1697    * The transport that this peer will be blacklisted on.
1698    */
1699   char *transport;
1700 };
1701
1702 /**
1703  * Iterator for writing blacklist data to appropriate files.
1704  *
1705  * @param cls closure, an open writable file handle
1706  * @param key the key the daemon was stored under
1707  * @param value the GNUNET_TESTING_Daemon that needs to be written.
1708  *
1709  * @return GNUNET_YES to continue iteration
1710  */
1711 static int
1712 blacklist_file_iterator (void *cls,
1713                          const GNUNET_HashCode * key,
1714                          void *value)
1715 {
1716   struct BlacklistContext *blacklist_ctx = cls;
1717   //FILE *temp_blacklist_handle = cls;
1718   struct GNUNET_TESTING_Daemon *peer = value;
1719   struct GNUNET_PeerIdentity *temppeer;
1720   struct GNUNET_CRYPTO_HashAsciiEncoded peer_enc;
1721
1722   temppeer = &peer->id;
1723   GNUNET_CRYPTO_hash_to_enc(&temppeer->hashPubKey, &peer_enc);
1724   fprintf(blacklist_ctx->temp_file_handle, "%s:%s\n", blacklist_ctx->transport, (char *)&peer_enc);
1725
1726   return GNUNET_YES;
1727 }
1728
1729 /*
1730  * Create the friend files based on the PeerConnection's
1731  * of each peer in the peer group, and copy the files
1732  * to the appropriate place
1733  *
1734  * @param pg the peer group we are dealing with
1735  */
1736 static int
1737 create_and_copy_friend_files (struct GNUNET_TESTING_PeerGroup *pg)
1738 {
1739   FILE *temp_friend_handle;
1740   unsigned int pg_iter;
1741   char *temp_service_path;
1742   pid_t *pidarr;
1743   char *arg;
1744   char * mytemp;
1745   enum GNUNET_OS_ProcessStatusType type;
1746   unsigned long return_code;
1747   int count;
1748   int ret;
1749   int max_wait = 10;
1750
1751   pidarr = GNUNET_malloc(sizeof(pid_t) * pg->total);
1752   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1753     {
1754       mytemp = GNUNET_DISK_mktemp("friends");
1755       GNUNET_assert(mytemp != NULL);
1756       temp_friend_handle = fopen (mytemp, "wt");
1757       GNUNET_assert(temp_friend_handle != NULL);
1758       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].allowed_peers, &friend_file_iterator, temp_friend_handle);
1759       fclose(temp_friend_handle);
1760
1761       if (GNUNET_OK !=
1762           GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
1763         {
1764           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1765                       _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
1766                       "SERVICEHOME",
1767                       "PATHS");
1768           if (UNLINK (mytemp) != 0)
1769             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
1770           GNUNET_free (mytemp);
1771           break;
1772         }
1773
1774       if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
1775         {
1776           GNUNET_asprintf (&arg, "%s/friends", temp_service_path);
1777           pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
1778                                          "mv", mytemp, arg, NULL);
1779 #if VERBOSE_TESTING
1780           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1781                       _("Copying file with command cp %s %s\n"), mytemp, arg);
1782 #endif
1783
1784           GNUNET_free(arg);
1785         }
1786       else /* Remote, scp the file to the correct place */
1787         {
1788           if (NULL != pg->peers[pg_iter].daemon->username)
1789             GNUNET_asprintf (&arg, "%s@%s:%s/friends", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
1790           else
1791             GNUNET_asprintf (&arg, "%s:%s/friends", pg->peers[pg_iter].daemon->hostname, temp_service_path);
1792           pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
1793                                          "scp", mytemp, arg, NULL);
1794
1795 #if VERBOSE_TESTING
1796           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1797                       _("Copying file with command scp %s %s\n"), mytemp, arg);
1798 #endif
1799           GNUNET_free(arg);
1800         }
1801       GNUNET_free (temp_service_path);
1802       GNUNET_free (mytemp);
1803     }
1804
1805   count = 0;
1806   ret = GNUNET_SYSERR;
1807   while ((count < max_wait) && (ret != GNUNET_OK))
1808     {
1809       ret = GNUNET_OK;
1810       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1811         {
1812 #if VERBOSE_TESTING
1813           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1814                       _("Checking copy status of file %d\n"), pg_iter);
1815 #endif
1816           if (pidarr[pg_iter] != 0) /* Check for already completed! */
1817             {
1818               if (GNUNET_OS_process_status(pidarr[pg_iter], &type, &return_code) != GNUNET_OK)
1819                 {
1820                   ret = GNUNET_SYSERR;
1821                 }
1822               else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
1823                 {
1824                   ret = GNUNET_SYSERR;
1825                 }
1826               else
1827                 {
1828                   pidarr[pg_iter] = 0;
1829 #if VERBOSE_TESTING
1830             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1831                       _("File %d copied\n"), pg_iter);
1832 #endif
1833                 }
1834             }
1835         }
1836       count++;
1837       if (ret == GNUNET_SYSERR)
1838         {
1839           /* FIXME: why sleep here? -CG */
1840           sleep(1);
1841         }
1842     }
1843
1844 #if VERBOSE_TESTING
1845     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1846                 _("Finished copying all friend files!\n"));
1847 #endif
1848   GNUNET_free(pidarr);
1849   return ret;
1850 }
1851
1852
1853 /*
1854  * Create the blacklist files based on the PeerConnection's
1855  * of each peer in the peer group, and copy the files
1856  * to the appropriate place.
1857  *
1858  * @param pg the peer group we are dealing with
1859  * @param transports space delimited list of transports to blacklist
1860  */
1861 static int
1862 create_and_copy_blacklist_files (struct GNUNET_TESTING_PeerGroup *pg, char *transports)
1863 {
1864   FILE *temp_file_handle;
1865   static struct BlacklistContext blacklist_ctx;
1866   unsigned int pg_iter;
1867   char *temp_service_path;
1868   pid_t *pidarr;
1869   char *arg;
1870   char *mytemp;
1871   enum GNUNET_OS_ProcessStatusType type;
1872   unsigned long return_code;
1873   int count;
1874   int ret;
1875   int max_wait = 10;
1876   int transport_len;
1877   unsigned int i;
1878   char *pos;
1879   char *temp_transports;
1880
1881   pidarr = GNUNET_malloc(sizeof(pid_t) * pg->total);
1882   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1883     {
1884       mytemp = GNUNET_DISK_mktemp("blacklist");
1885       GNUNET_assert(mytemp != NULL);
1886       temp_file_handle = fopen (mytemp, "wt");
1887       GNUNET_assert(temp_file_handle != NULL);
1888       temp_transports = GNUNET_strdup(transports);
1889       blacklist_ctx.temp_file_handle = temp_file_handle;
1890       transport_len = strlen(temp_transports) + 1;
1891       pos = NULL;
1892
1893       for (i = 0; i < transport_len; i++)
1894       {
1895         if ((temp_transports[i] == ' ') && (pos == NULL))
1896           continue; /* At start of string (whitespace) */
1897         else if ((temp_transports[i] == ' ') || (temp_transports[i] == '\0')) /* At end of string */
1898         {
1899           temp_transports[i] = '\0';
1900           blacklist_ctx.transport = pos;
1901           GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].blacklisted_peers, &blacklist_file_iterator, &blacklist_ctx);
1902           pos = NULL;
1903         } /* At beginning of actual string */
1904         else if (pos == NULL)
1905         {
1906           pos = &temp_transports[i];
1907         }
1908       }
1909
1910       GNUNET_free (temp_transports);
1911       fclose(temp_file_handle);
1912
1913       if (GNUNET_OK !=
1914           GNUNET_CONFIGURATION_get_value_string(pg->peers[pg_iter].daemon->cfg, "PATHS", "SERVICEHOME", &temp_service_path))
1915         {
1916           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1917                       _("No `%s' specified in peer configuration in section `%s', cannot copy friends file!\n"),
1918                       "SERVICEHOME",
1919                       "PATHS");
1920           if (UNLINK (mytemp) != 0)
1921             GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, "unlink", mytemp);
1922           GNUNET_free (mytemp);
1923           break;
1924         }
1925
1926       if (pg->peers[pg_iter].daemon->hostname == NULL) /* Local, just copy the file */
1927         {
1928           GNUNET_asprintf (&arg, "%s/blacklist", temp_service_path);
1929           pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "mv",
1930                                          "mv", mytemp, arg, NULL);
1931 #if VERBOSE_TESTING
1932           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1933                       _("Copying file with command cp %s %s\n"), mytemp, arg);
1934 #endif
1935
1936           GNUNET_free(arg);
1937         }
1938       else /* Remote, scp the file to the correct place */
1939         {
1940           if (NULL != pg->peers[pg_iter].daemon->username)
1941             GNUNET_asprintf (&arg, "%s@%s:%s/blacklist", pg->peers[pg_iter].daemon->username, pg->peers[pg_iter].daemon->hostname, temp_service_path);
1942           else
1943             GNUNET_asprintf (&arg, "%s:%s/blacklist", pg->peers[pg_iter].daemon->hostname, temp_service_path);
1944           pidarr[pg_iter] = GNUNET_OS_start_process (NULL, NULL, "scp",
1945                                          "scp", mytemp, arg, NULL);
1946
1947 #if VERBOSE_TESTING
1948           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1949                       _("Copying file with command scp %s %s\n"), mytemp, arg);
1950 #endif
1951           GNUNET_free(arg);
1952         }
1953       GNUNET_free (temp_service_path);
1954       GNUNET_free (mytemp);
1955     }
1956
1957   count = 0;
1958   ret = GNUNET_SYSERR;
1959   while ((count < max_wait) && (ret != GNUNET_OK))
1960     {
1961       ret = GNUNET_OK;
1962       for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1963         {
1964 #if VERBOSE_TESTING
1965           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1966                       _("Checking copy status of file %d\n"), pg_iter);
1967 #endif
1968           if (pidarr[pg_iter] != 0) /* Check for already completed! */
1969             {
1970               if (GNUNET_OS_process_status(pidarr[pg_iter], &type, &return_code) != GNUNET_OK)
1971                 {
1972                   ret = GNUNET_SYSERR;
1973                 }
1974               else if ((type != GNUNET_OS_PROCESS_EXITED) || (return_code != 0))
1975                 {
1976                   ret = GNUNET_SYSERR;
1977                 }
1978               else
1979                 {
1980                   pidarr[pg_iter] = 0;
1981 #if VERBOSE_TESTING
1982             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1983                       _("File %d copied\n"), pg_iter);
1984 #endif
1985                 }
1986             }
1987         }
1988       count++;
1989       if (ret == GNUNET_SYSERR)
1990         {
1991           /* FIXME: why sleep here? -CG */
1992           sleep(1);
1993         }
1994     }
1995
1996 #if VERBOSE_TESTING
1997     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1998                 _("Finished copying all blacklist files!\n"));
1999 #endif
2000   GNUNET_free(pidarr);
2001   return ret;
2002 }
2003
2004
2005 /**
2006  * Internal notification of a connection, kept so that we can ensure some connections
2007  * happen instead of flooding all testing daemons with requests to connect.
2008  */
2009 static void internal_connect_notify (void *cls,
2010                                      const struct GNUNET_PeerIdentity *first,
2011                                      const struct GNUNET_PeerIdentity *second,
2012                                      uint32_t distance,
2013                                      const struct GNUNET_CONFIGURATION_Handle *first_cfg,
2014                                      const struct GNUNET_CONFIGURATION_Handle *second_cfg,
2015                                      struct GNUNET_TESTING_Daemon *first_daemon,
2016                                      struct GNUNET_TESTING_Daemon *second_daemon,
2017                                      const char *emsg)
2018 {
2019   struct GNUNET_TESTING_PeerGroup *pg = cls;
2020   outstanding_connects--;
2021
2022   pg->notify_connection(pg->notify_connection_cls, first, second, distance, first_cfg, second_cfg, first_daemon, second_daemon, emsg);
2023 }
2024
2025
2026 /**
2027  * Either delay a connection (because there are too many outstanding)
2028  * or schedule it for right now.
2029  *
2030  * @param cls a connection context
2031  * @param tc the task runtime context
2032  */
2033 static void schedule_connect(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2034 {
2035   struct ConnectContext *connect_context = cls;
2036
2037   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2038     return;
2039
2040   if (outstanding_connects > MAX_OUTSTANDING_CONNECTIONS)
2041     {
2042 #if VERBOSE_TESTING > 2
2043           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2044                       _("Delaying connect, we have too many outstanding connections!\n"));
2045 #endif
2046       GNUNET_SCHEDULER_add_delayed(connect_context->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_connect, connect_context);
2047     }
2048   else
2049     {
2050 #if VERBOSE_TESTING > 2
2051           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2052                       _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
2053 #endif
2054       outstanding_connects++;
2055       GNUNET_TESTING_daemons_connect (connect_context->first,
2056                                       connect_context->second,
2057                                       CONNECT_TIMEOUT,
2058                                       CONNECT_ATTEMPTS,
2059                                       &internal_connect_notify,
2060                                       connect_context->pg);
2061       GNUNET_free(connect_context);
2062     }
2063 }
2064
2065
2066 /**
2067  * Iterator for actually scheduling connections to be created
2068  * between two peers.
2069  *
2070  * @param cls closure, a GNUNET_TESTING_Daemon
2071  * @param key the key the second Daemon was stored under
2072  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2073  *
2074  * @return GNUNET_YES to continue iteration
2075  */
2076 static int
2077 connect_iterator (void *cls,
2078                   const GNUNET_HashCode * key,
2079                   void *value)
2080 {
2081   struct PeerData *first = cls;
2082   struct GNUNET_TESTING_Daemon *second = value;
2083   struct ConnectContext *connect_context;
2084
2085   connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
2086   connect_context->pg = first->pg;
2087   connect_context->first = first->daemon;
2088   connect_context->second = second;
2089   GNUNET_SCHEDULER_add_now(first->pg->sched, &schedule_connect, connect_context);
2090
2091   return GNUNET_YES;
2092 }
2093
2094
2095 /**
2096  * Iterator for copying all entries in the allowed hashmap to the
2097  * connect hashmap.
2098  *
2099  * @param cls closure, a GNUNET_TESTING_Daemon
2100  * @param key the key the second Daemon was stored under
2101  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2102  *
2103  * @return GNUNET_YES to continue iteration
2104  */
2105 static int
2106 copy_topology_iterator (void *cls,
2107                   const GNUNET_HashCode * key,
2108                   void *value)
2109 {
2110   struct PeerData *first = cls;
2111
2112   GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(first->connect_peers, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2113
2114   return GNUNET_YES;
2115 }
2116
2117 /**
2118  * Make the peers to connect the same as those that are allowed to be
2119  * connected.
2120  *
2121  * @param pg the peer group
2122  */
2123 static int
2124 copy_allowed_topology (struct GNUNET_TESTING_PeerGroup *pg)
2125 {
2126   unsigned int pg_iter;
2127   int ret;
2128   int total;
2129
2130   total = 0;
2131   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2132     {
2133       ret = GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].allowed_peers, &copy_topology_iterator, &pg->peers[pg_iter]);
2134       if (GNUNET_SYSERR == ret)
2135         return GNUNET_SYSERR;
2136
2137       total = total + ret;
2138     }
2139
2140   return total;
2141 }
2142
2143
2144 /**
2145  * Connect the topology as specified by the PeerConnection's
2146  * of each peer in the peer group
2147  *
2148  * @param pg the peer group we are dealing with
2149  * @return the number of connections that will be attempted
2150  */
2151 static int
2152 connect_topology (struct GNUNET_TESTING_PeerGroup *pg)
2153 {
2154   unsigned int pg_iter;
2155   int ret;
2156   int total;
2157 #if OLD
2158   struct PeerConnection *connection_iter;
2159   struct ConnectContext *connect_context;
2160 #endif
2161
2162   total = 0;
2163   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2164     {
2165       ret = GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &connect_iterator, &pg->peers[pg_iter]);
2166       if (GNUNET_SYSERR == ret)
2167         return GNUNET_SYSERR;
2168
2169       total = total + ret;
2170
2171 #if OLD
2172       connection_iter = ;
2173       while (connection_iter != NULL)
2174         {
2175           connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
2176           connect_context->pg = pg;
2177           connect_context->first = ;
2178           connect_context->second = connection_iter->daemon;
2179           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_connect, connect_context);
2180           connection_iter = connection_iter->next;
2181         }
2182 #endif
2183     }
2184   return total;
2185 }
2186
2187
2188 /**
2189  * Takes a peer group and creates a topology based on the
2190  * one specified.  Creates a topology means generates friend
2191  * files for the peers so they can only connect to those allowed
2192  * by the topology.  This will only have an effect once peers
2193  * are started if the FRIENDS_ONLY option is set in the base
2194  * config.  Also takes an optional restrict topology which
2195  * disallows connections based on a particular transport
2196  * UNLESS they are specified in the restricted topology.
2197  *
2198  * @param pg the peer group struct representing the running peers
2199  * @param topology which topology to connect the peers in
2200  * @param restrict_topology allow only direct TCP connections in this topology
2201  *                          use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions
2202  * @param restrict_transports space delimited list of transports to blacklist
2203  *                            to create restricted topology
2204  *
2205  * @return the maximum number of connections were all allowed peers
2206  *         connected to each other
2207  */
2208 int
2209 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg,
2210                                 enum GNUNET_TESTING_Topology topology,
2211                                 enum GNUNET_TESTING_Topology restrict_topology,
2212                                 char *restrict_transports)
2213 {
2214   int ret;
2215   int num_connections;
2216   int unblacklisted_connections;
2217
2218   GNUNET_assert (pg->notify_connection != NULL);
2219   ret = GNUNET_OK;
2220
2221   switch (topology)
2222     {
2223     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2224 #if VERBOSE_TESTING
2225       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2226                   _("Creating clique topology\n"));
2227 #endif
2228       num_connections = create_clique (pg, &add_allowed_connections);
2229       break;
2230     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2231 #if VERBOSE_TESTING
2232       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2233                   _("Creating small world (ring) topology\n"));
2234 #endif
2235       num_connections = create_small_world_ring (pg, &add_allowed_connections);
2236       break;
2237     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2238 #if VERBOSE_TESTING
2239       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2240                   _("Creating small world (2d-torus) topology\n"));
2241 #endif
2242       num_connections = create_small_world (pg, &add_allowed_connections);
2243       break;
2244     case GNUNET_TESTING_TOPOLOGY_RING:
2245 #if VERBOSE_TESTING
2246       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2247                   _("Creating ring topology\n"));
2248 #endif
2249       num_connections = create_ring (pg, &add_allowed_connections);
2250       break;
2251     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2252 #if VERBOSE_TESTING
2253       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2254                   _("Creating 2d torus topology\n"));
2255 #endif
2256       num_connections = create_2d_torus (pg, &add_allowed_connections);
2257       break;
2258     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2259 #if VERBOSE_TESTING
2260       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2261                   _("Creating Erdos-Renyi topology\n"));
2262 #endif
2263       num_connections = create_erdos_renyi (pg, &add_allowed_connections);
2264       break;
2265     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2266 #if VERBOSE_TESTING
2267       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2268                   _("Creating InterNAT topology\n"));
2269 #endif
2270       num_connections = create_nated_internet (pg, &add_allowed_connections);
2271       break;
2272     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2273 #if VERBOSE_TESTING
2274       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2275                   _("Creating Scale Free topology\n"));
2276 #endif
2277       num_connections = create_scale_free (pg, &add_allowed_connections);
2278       break;
2279     case GNUNET_TESTING_TOPOLOGY_LINE:
2280 #if VERBOSE_TESTING
2281       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2282                   _("Creating straight line topology\n"));
2283 #endif
2284       num_connections = create_line (pg, &add_allowed_connections);
2285       break;
2286     case GNUNET_TESTING_TOPOLOGY_NONE:
2287 #if VERBOSE_TESTING
2288       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2289                   _("Creating no allowed topology (all peers can connect at core level)\n"));
2290 #endif
2291       num_connections = 0;
2292       break;
2293     default:
2294       num_connections = 0;
2295       break;
2296     }
2297
2298   if (num_connections < 0)
2299     return GNUNET_SYSERR;
2300
2301   if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
2302     {
2303       ret = create_and_copy_friend_files(pg);
2304       if (ret != GNUNET_OK)
2305         {
2306 #if VERBOSE_TESTING
2307           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2308                       _("Failed during friend file copying!\n"));
2309 #endif
2310           return GNUNET_SYSERR;
2311         }
2312       else
2313         {
2314 #if VERBOSE_TESTING
2315               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2316                           _("Friend files created/copied successfully!\n"));
2317 #endif
2318         }
2319     }
2320
2321   /* Use the create clique method to initially set all connections as blacklisted. */
2322   if (restrict_topology != GNUNET_TESTING_TOPOLOGY_NONE)
2323     create_clique (pg, &blacklist_connections);
2324   unblacklisted_connections = 0;
2325   /* Un-blacklist connections as per the topology specified */
2326   switch (restrict_topology)
2327     {
2328     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2329 #if VERBOSE_TESTING
2330       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2331                   _("Blacklisting all but clique topology\n"));
2332 #endif
2333       unblacklisted_connections = create_clique (pg, &unblacklist_connections);
2334       break;
2335     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2336 #if VERBOSE_TESTING
2337       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2338                   _("Blacklisting all but small world (ring) topology\n"));
2339 #endif
2340       unblacklisted_connections = create_small_world_ring (pg, &unblacklist_connections);
2341       break;
2342     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2343 #if VERBOSE_TESTING
2344       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2345                   _("Blacklisting all but small world (2d-torus) topology\n"));
2346 #endif
2347       unblacklisted_connections = create_small_world (pg, &unblacklist_connections);
2348       break;
2349     case GNUNET_TESTING_TOPOLOGY_RING:
2350 #if VERBOSE_TESTING
2351       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2352                   _("Blacklisting all but ring topology\n"));
2353 #endif
2354       unblacklisted_connections = create_ring (pg, &unblacklist_connections);
2355       break;
2356     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2357 #if VERBOSE_TESTING
2358       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2359                   _("Blacklisting all but 2d torus topology\n"));
2360 #endif
2361       unblacklisted_connections = create_2d_torus (pg, &unblacklist_connections);
2362       break;
2363     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2364 #if VERBOSE_TESTING
2365       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2366                   _("Blacklisting all but Erdos-Renyi topology\n"));
2367 #endif
2368       unblacklisted_connections = create_erdos_renyi (pg, &unblacklist_connections);
2369       break;
2370     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2371 #if VERBOSE_TESTING
2372       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2373                   _("Blacklisting all but InterNAT topology\n"));
2374 #endif
2375       unblacklisted_connections = create_nated_internet (pg, &unblacklist_connections);
2376       break;
2377     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2378 #if VERBOSE_TESTING
2379       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2380                   _("Blacklisting all but Scale Free topology\n"));
2381 #endif
2382       unblacklisted_connections = create_scale_free (pg, &unblacklist_connections);
2383       break;
2384     case GNUNET_TESTING_TOPOLOGY_LINE:
2385 #if VERBOSE_TESTING
2386       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2387                   _("Blacklisting all but straight line topology\n"));
2388 #endif
2389       unblacklisted_connections = create_line (pg, &unblacklist_connections);
2390       break;
2391     case GNUNET_TESTING_TOPOLOGY_NONE:
2392 #if VERBOSE_TESTING
2393       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2394                   _("Creating no blacklist topology (all peers can connect at transport level)\n"));
2395 #endif
2396     default:
2397       break;
2398     }
2399
2400   if ((unblacklisted_connections > 0) && (restrict_transports != NULL))
2401   {
2402     ret = create_and_copy_blacklist_files(pg, restrict_transports);
2403     if (ret != GNUNET_OK)
2404       {
2405 #if VERBOSE_TESTING
2406         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2407                     _("Failed during blacklist file copying!\n"));
2408 #endif
2409         return GNUNET_SYSERR;
2410       }
2411     else
2412       {
2413 #if VERBOSE_TESTING
2414         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2415                     _("Blacklist files created/copied successfully!\n"));
2416 #endif
2417       }
2418   }
2419   return num_connections;
2420 }
2421
2422 struct RandomContext
2423 {
2424   /**
2425    * The peergroup
2426    */
2427   struct GNUNET_TESTING_PeerGroup *pg;
2428
2429   /**
2430    * uid of the first peer
2431    */
2432   uint32_t first_uid;
2433
2434   /**
2435    * Peer data for first peer.
2436    */
2437   struct PeerData *first;
2438
2439   /**
2440    * Random percentage to use
2441    */
2442   double percentage;
2443 };
2444
2445 struct MinimumContext
2446 {
2447   /**
2448    * The peergroup
2449    */
2450   struct GNUNET_TESTING_PeerGroup *pg;
2451
2452   /**
2453    * uid of the first peer
2454    */
2455   uint32_t first_uid;
2456
2457   /**
2458    * Peer data for first peer.
2459    */
2460   struct PeerData *first;
2461
2462   /**
2463    * Number of conns per peer
2464    */
2465   unsigned int num_to_add;
2466
2467   /**
2468    * Permuted array of all possible connections.  Only add the Nth
2469    * peer if it's in the Nth position.
2470    */
2471   unsigned int *pg_array;
2472
2473   /**
2474    * What number is the current element we are iterating over?
2475    */
2476   unsigned int current;
2477 };
2478
2479 struct DFSContext
2480 {
2481   /**
2482    * The peergroup
2483    */
2484   struct GNUNET_TESTING_PeerGroup *pg;
2485
2486   /**
2487    * uid of the first peer
2488    */
2489   uint32_t first_uid;
2490
2491   /**
2492    * uid of the second peer
2493    */
2494   uint32_t second_uid;
2495
2496   /**
2497    * Peer data for first peer.
2498    */
2499   struct PeerData *first;
2500
2501   /**
2502    * Which peer has been chosen as the one to add?
2503    */
2504   unsigned int chosen;
2505
2506   /**
2507    * What number is the current element we are iterating over?
2508    */
2509   unsigned int current;
2510 };
2511
2512 /**
2513  * Iterator for choosing random peers to connect.
2514  *
2515  * @param cls closure, a RandomContext
2516  * @param key the key the second Daemon was stored under
2517  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2518  *
2519  * @return GNUNET_YES to continue iteration
2520  */
2521 static int
2522 random_connect_iterator (void *cls,
2523                   const GNUNET_HashCode * key,
2524                   void *value)
2525 {
2526   struct RandomContext *random_ctx = cls;
2527   double random_number;
2528   uint32_t second_pos;
2529   GNUNET_HashCode first_hash;
2530   random_number = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
2531                                                      UINT64_MAX)) / ( (double) UINT64_MAX);
2532   if (random_number < random_ctx->percentage)
2533   {
2534     GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(random_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2535   }
2536   /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */
2537   uid_from_hash(key, &second_pos);
2538   hash_from_uid(random_ctx->first_uid, &first_hash);
2539   GNUNET_assert(random_ctx->pg->total > second_pos);
2540   GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(random_ctx->pg->peers[second_pos].connect_peers, &first_hash, random_ctx->first->daemon));
2541
2542   return GNUNET_YES;
2543 }
2544
2545 /**
2546  * Iterator for adding at least X peers to a peers connection set.
2547  *
2548  * @param cls closure, MinimumContext
2549  * @param key the key the second Daemon was stored under
2550  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2551  *
2552  * @return GNUNET_YES to continue iteration
2553  */
2554 static int
2555 minimum_connect_iterator (void *cls,
2556                   const GNUNET_HashCode * key,
2557                   void *value)
2558 {
2559   struct MinimumContext *min_ctx = cls;
2560   uint32_t second_pos;
2561   GNUNET_HashCode first_hash;
2562   unsigned int i;
2563
2564   if (GNUNET_CONTAINER_multihashmap_size(min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add)
2565   {
2566     for (i = 0; i < min_ctx->num_to_add; i++)
2567     {
2568       if (min_ctx->pg_array[i] == min_ctx->current)
2569       {
2570         GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(min_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2571         uid_from_hash(key, &second_pos);
2572         hash_from_uid(min_ctx->first_uid, &first_hash);
2573         GNUNET_assert(min_ctx->pg->total > second_pos);
2574         GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(min_ctx->pg->peers[second_pos].connect_peers_working_set, &first_hash, min_ctx->first->daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2575         /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */
2576         GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(min_ctx->pg->peers[second_pos].connect_peers, &first_hash, min_ctx->first->daemon));
2577       }
2578     }
2579     min_ctx->current++;
2580     return GNUNET_YES;
2581   }
2582   else
2583     return GNUNET_NO; /* We can stop iterating, we have enough peers! */
2584
2585 }
2586
2587
2588 /**
2589  * Iterator for adding peers to a connection set based on a depth first search.
2590  *
2591  * @param cls closure, MinimumContext
2592  * @param key the key the second daemon was stored under
2593  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2594  *
2595  * @return GNUNET_YES to continue iteration
2596  */
2597 static int
2598 dfs_connect_iterator (void *cls,
2599                   const GNUNET_HashCode * key,
2600                   void *value)
2601 {
2602   struct DFSContext *dfs_ctx = cls;
2603   GNUNET_HashCode first_hash;
2604
2605   if (dfs_ctx->current == dfs_ctx->chosen)
2606     {
2607       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(dfs_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2608       uid_from_hash(key, &dfs_ctx->second_uid);
2609       hash_from_uid(dfs_ctx->first_uid, &first_hash);
2610       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(dfs_ctx->pg->peers[dfs_ctx->second_uid].connect_peers_working_set, &first_hash, dfs_ctx->first->daemon, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2611       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(dfs_ctx->pg->peers[dfs_ctx->second_uid].connect_peers, &first_hash, dfs_ctx->first->daemon));
2612       /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */
2613       return GNUNET_NO; /* We have found our peer, don't iterate more */
2614     }
2615
2616   dfs_ctx->current++;
2617   return GNUNET_YES;
2618 }
2619
2620
2621 /**
2622  * From the set of connections possible, choose percentage percent of connections
2623  * to actually connect.
2624  *
2625  * @param pg the peergroup we are dealing with
2626  * @param percentage what percent of total connections to make
2627  */
2628 void
2629 choose_random_connections(struct GNUNET_TESTING_PeerGroup *pg, double percentage)
2630 {
2631   struct RandomContext random_ctx;
2632   uint32_t pg_iter;
2633
2634   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2635     {
2636       random_ctx.first_uid = pg_iter;
2637       random_ctx.first = &pg->peers[pg_iter];
2638       random_ctx.percentage = percentage;
2639       random_ctx.pg = pg;
2640       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(pg->total);
2641       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &random_connect_iterator, &random_ctx);
2642       /* Now remove the old connections */
2643       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2644       /* And replace with the random set */
2645       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2646     }
2647 }
2648
2649 /**
2650  * From the set of connections possible, choose at least num connections per
2651  * peer.
2652  *
2653  * @param pg the peergroup we are dealing with
2654  * @param num how many connections at least should each peer have (if possible)?
2655  */
2656 static void
2657 choose_minimum(struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2658 {
2659   struct MinimumContext minimum_ctx;
2660   uint32_t pg_iter;
2661
2662   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2663    {
2664      pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2665    }
2666
2667   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2668     {
2669       minimum_ctx.first_uid = pg_iter;
2670       minimum_ctx.pg_array = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, 
2671                                                           GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2672       minimum_ctx.first = &pg->peers[pg_iter];
2673       minimum_ctx.pg = pg;
2674       minimum_ctx.num_to_add = num;
2675       minimum_ctx.current = 0;
2676       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers,
2677                                             &minimum_connect_iterator, 
2678                                             &minimum_ctx);
2679     }
2680
2681   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2682     {
2683       /* Remove the "old" connections */
2684       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2685       /* And replace with the working set */
2686       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2687     }
2688
2689 }
2690
2691
2692 static unsigned int
2693 count_workingset_connections(struct GNUNET_TESTING_PeerGroup *pg)
2694 {
2695   unsigned int count;
2696   unsigned int pg_iter;
2697
2698   count = 0;
2699
2700   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2701     {
2702       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2703     }
2704
2705   return count;
2706 }
2707
2708
2709 static unsigned int count_allowed_connections(struct GNUNET_TESTING_PeerGroup *pg)
2710 {
2711   unsigned int count;
2712   unsigned int pg_iter;
2713
2714   count = 0;
2715
2716   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2717     {
2718       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers);
2719     }
2720
2721   return count;
2722 }
2723
2724 /**
2725  * From the set of connections possible, choose at least num connections per
2726  * peer based on depth first traversal of peer connections.  If DFS leaves
2727  * peers unconnected, ensure those peers get connections.
2728  *
2729  * @param pg the peergroup we are dealing with
2730  * @param num how many connections at least should each peer have (if possible)?
2731  */
2732 void
2733 perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2734 {
2735   struct DFSContext dfs_ctx;
2736   uint32_t pg_iter;
2737   uint32_t dfs_count;
2738   uint32_t starting_peer;
2739   uint32_t least_connections;
2740   GNUNET_HashCode second_hash;
2741
2742   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2743     {
2744       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2745     }
2746
2747   starting_peer = 0;
2748   dfs_count = 0;
2749   while ((count_workingset_connections(pg) < num * pg->total) && (count_allowed_connections(pg) > 0))
2750     {
2751       if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */
2752         {
2753           least_connections = -1; /* Set to very high number */
2754           for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2755             {
2756               if (GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set) < least_connections)
2757                 {
2758                   starting_peer = pg_iter;
2759                   least_connections = GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2760                 }
2761             }
2762         }
2763
2764       if (GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers) == 0)  /* Ensure there is at least one peer left to connect! */
2765         {
2766           dfs_count = 0;
2767           continue;
2768         }
2769
2770       /* Choose a random peer from the chosen peers set of connections to add */
2771       dfs_ctx.chosen = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers));
2772       dfs_ctx.first_uid = starting_peer;
2773       dfs_ctx.first = &pg->peers[starting_peer];
2774       dfs_ctx.pg = pg;
2775       dfs_ctx.current = 0;
2776
2777       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[starting_peer].connect_peers, &dfs_connect_iterator, &dfs_ctx);
2778       /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */
2779       hash_from_uid(dfs_ctx.second_uid, &second_hash);
2780       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[starting_peer].connect_peers, &second_hash, pg->peers[dfs_ctx.second_uid].daemon));
2781       starting_peer = dfs_ctx.second_uid;
2782     }
2783
2784   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2785     {
2786       /* Remove the "old" connections */
2787       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2788       /* And replace with the working set */
2789       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2790     }
2791 }
2792
2793 /**
2794  * Internal callback for topology information for a particular peer.
2795  */
2796 static void
2797 internal_topology_callback(void *cls,
2798                            const struct GNUNET_PeerIdentity *peer,
2799                            struct GNUNET_TIME_Relative latency, uint32_t distance)
2800 {
2801   struct CoreContext *core_ctx = cls;
2802   struct TopologyIterateContext *iter_ctx = core_ctx->iter_context;
2803
2804   if (peer == NULL) /* Either finished, or something went wrong */
2805     {
2806       iter_ctx->completed++;
2807       iter_ctx->connected--;
2808       /* One core context allocated per iteration, must free! */
2809       GNUNET_free(core_ctx);
2810     }
2811   else
2812     {
2813       iter_ctx->topology_cb(iter_ctx->cls, &core_ctx->daemon->id, peer, latency, distance, NULL);
2814     }
2815
2816   if (iter_ctx->completed == iter_ctx->total)
2817     {
2818       iter_ctx->topology_cb(iter_ctx->cls, NULL, NULL, GNUNET_TIME_relative_get_zero(), 0, NULL);
2819       /* Once all are done, free the iteration context */
2820       GNUNET_free(iter_ctx);
2821     }
2822 }
2823
2824
2825 /**
2826  * Check running topology iteration tasks, if below max start a new one, otherwise
2827  * schedule for some time in the future.
2828  */
2829 static void
2830 schedule_get_topology(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2831 {
2832   struct CoreContext *core_context = cls;
2833   struct TopologyIterateContext *topology_context = (struct TopologyIterateContext *)core_context->iter_context;
2834   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2835     return;
2836
2837   if (topology_context->connected > MAX_OUTSTANDING_CONNECTIONS)
2838     {
2839 #if VERBOSE_TESTING > 2
2840           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2841                       _("Delaying connect, we have too many outstanding connections!\n"));
2842 #endif
2843       GNUNET_SCHEDULER_add_delayed(core_context->daemon->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_get_topology, core_context);
2844     }
2845   else
2846     {
2847 #if VERBOSE_TESTING > 2
2848           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2849                       _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
2850 #endif
2851       topology_context->connected++;
2852       if (GNUNET_OK != GNUNET_CORE_iterate_peers (core_context->daemon->sched, core_context->daemon->cfg, &internal_topology_callback, core_context))
2853         internal_topology_callback(core_context, NULL, GNUNET_TIME_relative_get_zero(), 0);
2854
2855     }
2856 }
2857
2858 /**
2859  * Iterate over all (running) peers in the peer group, retrieve
2860  * all connections that each currently has.
2861  */
2862 void
2863 GNUNET_TESTING_get_topology (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyTopology cb, void *cls)
2864 {
2865   struct TopologyIterateContext *topology_context;
2866   struct CoreContext *core_ctx;
2867   unsigned int i;
2868   unsigned int total_count;
2869
2870   /* Allocate a single topology iteration context */
2871   topology_context = GNUNET_malloc(sizeof(struct TopologyIterateContext));
2872   topology_context->topology_cb = cb;
2873   topology_context->cls = cls;
2874   total_count = 0;
2875   for (i = 0; i < pg->total; i++)
2876     {
2877       if (pg->peers[i].daemon->running == GNUNET_YES)
2878         {
2879           /* Allocate one core context per core we need to connect to */
2880           core_ctx = GNUNET_malloc(sizeof(struct CoreContext));
2881           core_ctx->daemon = pg->peers[i].daemon;
2882           /* Set back pointer to topology iteration context */
2883           core_ctx->iter_context = topology_context;
2884           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_get_topology, core_ctx);
2885           total_count++;
2886         }
2887     }
2888   topology_context->total = total_count;
2889   return;
2890 }
2891
2892 /**
2893  * Callback function to process statistic values.
2894  * This handler is here only really to insert a peer
2895  * identity (or daemon) so the statistics can be uniquely
2896  * tied to a single running peer.
2897  *
2898  * @param cls closure
2899  * @param subsystem name of subsystem that created the statistic
2900  * @param name the name of the datum
2901  * @param value the current value
2902  * @param is_persistent GNUNET_YES if the value is persistent, GNUNET_NO if not
2903  * @return GNUNET_OK to continue, GNUNET_SYSERR to abort iteration
2904  */
2905 static int internal_stats_callback (void *cls,
2906                                     const char *subsystem,
2907                                     const char *name,
2908                                     uint64_t value,
2909                                     int is_persistent)
2910 {
2911   struct CoreContext *core_context = cls;
2912   struct StatsIterateContext *stats_context = (struct StatsIterateContext *)core_context->iter_context;
2913
2914   return stats_context->proc(stats_context->cls, &core_context->daemon->id, subsystem, name, value, is_persistent);
2915 }
2916
2917 /**
2918  * Internal continuation call for statistics iteration.
2919  *
2920  * @param cls closure, the CoreContext for this iteration
2921  * @param success whether or not the statistics iterations
2922  *        was canceled or not (we don't care)
2923  */
2924 static void internal_stats_cont (void *cls, int success)
2925 {
2926   struct CoreContext *core_context = cls;
2927   struct StatsIterateContext *stats_context = (struct StatsIterateContext *)core_context->iter_context;
2928
2929   stats_context->connected--;
2930   stats_context->completed++;
2931
2932   if (stats_context->completed == stats_context->total)
2933     {
2934       stats_context->cont(stats_context->cls, GNUNET_YES);
2935       if (stats_context->stats_handle != NULL)
2936         GNUNET_STATISTICS_destroy(stats_context->stats_handle, GNUNET_NO);
2937       GNUNET_free(stats_context);
2938     }
2939   GNUNET_free(core_context);
2940 }
2941
2942 /**
2943  * Check running topology iteration tasks, if below max start a new one, otherwise
2944  * schedule for some time in the future.
2945  */
2946 static void
2947 schedule_get_statistics(void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2948 {
2949   struct CoreContext *core_context = cls;
2950   struct StatsIterateContext *stats_context = (struct StatsIterateContext *)core_context->iter_context;
2951
2952   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2953     return;
2954
2955   if (stats_context->connected > MAX_OUTSTANDING_CONNECTIONS)
2956     {
2957 #if VERBOSE_TESTING > 2
2958           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2959                       _("Delaying connect, we have too many outstanding connections!\n"));
2960 #endif
2961       GNUNET_SCHEDULER_add_delayed(core_context->daemon->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &schedule_get_statistics, core_context);
2962     }
2963   else
2964     {
2965 #if VERBOSE_TESTING > 2
2966           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2967                       _("Creating connection, outstanding_connections is %d\n"), outstanding_connects);
2968 #endif
2969
2970       stats_context->connected++;
2971       stats_context->stats_handle = GNUNET_STATISTICS_create(core_context->daemon->sched, "testing", core_context->daemon->cfg);
2972       if (stats_context->stats_handle == NULL)
2973         {
2974           internal_stats_cont (core_context, GNUNET_NO);
2975           return;
2976         }
2977
2978       stats_context->stats_get_handle = GNUNET_STATISTICS_get(stats_context->stats_handle, NULL, NULL, GNUNET_TIME_relative_get_forever(), &internal_stats_cont, &internal_stats_callback, core_context);
2979       if (stats_context->stats_get_handle == NULL)
2980          internal_stats_cont (core_context, GNUNET_NO);
2981
2982     }
2983 }
2984
2985
2986 /**
2987  * Iterate over all (running) peers in the peer group, retrieve
2988  * all statistics from each.
2989  */
2990 void
2991 GNUNET_TESTING_get_statistics (struct GNUNET_TESTING_PeerGroup *pg,
2992                                GNUNET_STATISTICS_Callback cont,
2993                                GNUNET_TESTING_STATISTICS_Iterator proc, void *cls)
2994 {
2995   struct StatsIterateContext *stats_context;
2996   struct CoreContext *core_ctx;
2997   unsigned int i;
2998   unsigned int total_count;
2999
3000   /* Allocate a single stats iteration context */
3001   stats_context = GNUNET_malloc(sizeof(struct StatsIterateContext));
3002   stats_context->cont = cont;
3003   stats_context->proc = proc;
3004   stats_context->cls = cls;
3005   total_count = 0;
3006   for (i = 0; i < pg->total; i++)
3007     {
3008       if (pg->peers[i].daemon->running == GNUNET_YES)
3009         {
3010           /* Allocate one core context per core we need to connect to */
3011           core_ctx = GNUNET_malloc(sizeof(struct CoreContext));
3012           core_ctx->daemon = pg->peers[i].daemon;
3013           /* Set back pointer to topology iteration context */
3014           core_ctx->iter_context = stats_context;
3015           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_get_statistics, core_ctx);
3016           total_count++;
3017         }
3018     }
3019   stats_context->total = total_count;
3020   return;
3021 }
3022
3023 /**
3024  * There are many ways to connect peers that are supported by this function.
3025  * To connect peers in the same topology that was created via the
3026  * GNUNET_TESTING_create_topology, the topology variable must be set to
3027  * GNUNET_TESTING_TOPOLOGY_NONE.  If the topology variable is specified,
3028  * a new instance of that topology will be generated and attempted to be
3029  * connected.  This could result in some connections being impossible,
3030  * because some topologies are non-deterministic.
3031  *
3032  * @param pg the peer group struct representing the running peers
3033  * @param topology which topology to connect the peers in
3034  * @param options options for connecting the topology
3035  * @param option_modifier modifier for options that take a parameter
3036  * @return the number of connections that will be attempted, GNUNET_SYSERR on error
3037  */
3038 int
3039 GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
3040                                  enum GNUNET_TESTING_Topology topology,
3041                                  enum GNUNET_TESTING_TopologyOption options,
3042                                  double option_modifier)
3043 {
3044   switch (topology)
3045       {
3046       case GNUNET_TESTING_TOPOLOGY_CLIQUE:
3047 #if VERBOSE_TOPOLOGY
3048       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3049                   _("Creating clique CONNECT topology\n"));
3050 #endif
3051         create_clique (pg, &add_actual_connections);
3052         break;
3053       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
3054 #if VERBOSE_TOPOLOGY
3055       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3056                   _("Creating small world (ring) CONNECT topology\n"));
3057 #endif
3058         create_small_world_ring (pg, &add_actual_connections);
3059         break;
3060       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
3061 #if VERBOSE_TOPOLOGY
3062       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3063                   _("Creating small world (2d-torus) CONNECT topology\n"));
3064 #endif
3065         create_small_world (pg, &add_actual_connections);
3066         break;
3067       case GNUNET_TESTING_TOPOLOGY_RING:
3068 #if VERBOSE_TOPOLOGY
3069       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3070                   _("Creating ring CONNECT topology\n"));
3071 #endif
3072         create_ring (pg, &add_actual_connections);
3073         break;
3074       case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
3075 #if VERBOSE_TOPOLOGY
3076       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3077                   _("Creating 2d torus CONNECT topology\n"));
3078 #endif
3079         create_2d_torus (pg, &add_actual_connections);
3080         break;
3081       case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
3082 #if VERBOSE_TOPOLOGY
3083       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3084                   _("Creating Erdos-Renyi CONNECT topology\n"));
3085 #endif
3086         create_erdos_renyi (pg, &add_actual_connections);
3087         break;
3088       case GNUNET_TESTING_TOPOLOGY_INTERNAT:
3089 #if VERBOSE_TOPOLOGY
3090       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3091                   _("Creating InterNAT CONNECT topology\n"));
3092 #endif
3093         create_nated_internet (pg, &add_actual_connections);
3094         break;
3095       case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
3096 #if VERBOSE_TOPOLOGY
3097       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3098                   _("Creating Scale Free CONNECT topology\n"));
3099 #endif
3100         create_scale_free (pg, &add_actual_connections);
3101         break;
3102       case GNUNET_TESTING_TOPOLOGY_LINE:
3103 #if VERBOSE_TOPOLOGY
3104       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3105                   _("Creating straight line CONNECT topology\n"));
3106 #endif
3107         create_line (pg, &add_actual_connections);
3108         break;
3109       case GNUNET_TESTING_TOPOLOGY_NONE:
3110 #if VERBOSE_TOPOLOGY
3111         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3112                   _("Creating no CONNECT topology\n"));
3113 #endif
3114         copy_allowed_topology(pg);
3115         break;
3116       default:
3117         GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
3118                    _("Unknown topology specification, can't connect peers!\n"));
3119         return GNUNET_SYSERR;
3120       }
3121
3122   switch (options)
3123     {
3124     case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM:
3125 #if VERBOSE_TOPOLOGY
3126       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3127                   _("Connecting random subset (%'.2f percent) of possible peers\n"), 100 * option_modifier);
3128 #endif
3129       choose_random_connections(pg, option_modifier);
3130       break;
3131     case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM:
3132 #if VERBOSE_TOPOLOGY
3133       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3134                   _("Connecting a minimum of %u peers each (if possible)\n"), (unsigned int)option_modifier);
3135 #endif
3136       choose_minimum(pg, (unsigned int)option_modifier);
3137       break;
3138     case GNUNET_TESTING_TOPOLOGY_OPTION_DFS:
3139 #if VERBOSE_TOPOLOGY
3140       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3141                   _("Using DFS to connect a minimum of %u peers each (if possible)\n"), (unsigned int)option_modifier);
3142 #endif
3143       perform_dfs(pg, (int)option_modifier);
3144       break;
3145     case GNUNET_TESTING_TOPOLOGY_OPTION_NONE:
3146       break;
3147     case GNUNET_TESTING_TOPOLOGY_OPTION_ALL:
3148       break;
3149     default:
3150       break;
3151     }
3152
3153   return connect_topology(pg);
3154 }
3155
3156 /**
3157  * Callback that is called whenever a hostkey is generated
3158  * for a peer.  Call the real callback and decrement the
3159  * starting counter for the peergroup.
3160  *
3161  * @param cls closure
3162  * @param id identifier for the daemon, NULL on error
3163  * @param d handle for the daemon
3164  * @param emsg error message (NULL on success)
3165  */
3166 static void internal_hostkey_callback (void *cls,
3167                                        const struct GNUNET_PeerIdentity *id,
3168                                        struct GNUNET_TESTING_Daemon *d,
3169                                        const char *emsg)
3170 {
3171   struct InternalStartContext *internal_context = cls;
3172   internal_context->peer->pg->starting--;
3173   internal_context->peer->pg->started++;
3174   if (internal_context->hostkey_callback != NULL)
3175     internal_context->hostkey_callback(internal_context->hostkey_cls, id, d, emsg);
3176   else if (internal_context->peer->pg->started == internal_context->peer->pg->total)
3177     {
3178       internal_context->peer->pg->started = 0; /* Internal startup may use this counter! */
3179       GNUNET_TESTING_daemons_continue_startup(internal_context->peer->pg);
3180     }
3181 }
3182
3183 /**
3184  * Callback that is called whenever a peer has finished starting.
3185  * Call the real callback and decrement the starting counter
3186  * for the peergroup.
3187  *
3188  * @param cls closure
3189  * @param id identifier for the daemon, NULL on error
3190  * @param d handle for the daemon
3191  * @param emsg error message (NULL on success)
3192  */
3193 static void internal_startup_callback (void *cls,
3194                                        const struct GNUNET_PeerIdentity *id,
3195                                        const struct GNUNET_CONFIGURATION_Handle *cfg,
3196                                        struct GNUNET_TESTING_Daemon *d,
3197                                        const char *emsg)
3198 {
3199   struct InternalStartContext *internal_context = cls;
3200   internal_context->peer->pg->starting--;
3201   if (internal_context->start_cb != NULL)
3202     internal_context->start_cb(internal_context->start_cb_cls, id, cfg, d, emsg);
3203 }
3204
3205 static void
3206 internal_continue_startup (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
3207 {
3208   struct InternalStartContext *internal_context = cls;
3209
3210   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3211     {
3212       return;
3213     }
3214
3215   if (internal_context->peer->pg->starting < MAX_CONCURRENT_STARTING)
3216     {
3217       internal_context->peer->pg->starting++;
3218       GNUNET_TESTING_daemon_continue_startup (internal_context->peer->daemon);
3219     }
3220   else
3221     {
3222       GNUNET_SCHEDULER_add_delayed(internal_context->peer->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &internal_continue_startup, internal_context);
3223     }
3224 }
3225
3226 static void
3227 internal_start (void *cls, const struct GNUNET_SCHEDULER_TaskContext * tc)
3228 {
3229   struct InternalStartContext *internal_context = cls;
3230
3231   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3232     {
3233       return;
3234     }
3235
3236   if (internal_context->peer->pg->starting < MAX_CONCURRENT_HOSTKEYS)
3237     {
3238       internal_context->peer->pg->starting++;
3239       internal_context->peer->daemon = GNUNET_TESTING_daemon_start (internal_context->peer->pg->sched,
3240                                                                     internal_context->peer->cfg,
3241                                                                     internal_context->timeout,
3242                                                                     internal_context->hostname,
3243                                                                     &internal_hostkey_callback,
3244                                                                     internal_context,
3245                                                                     &internal_startup_callback,
3246                                                                     internal_context);
3247     }
3248   else
3249     {
3250       GNUNET_SCHEDULER_add_delayed(internal_context->peer->pg->sched, GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_MILLISECONDS, 100), &internal_start, internal_context);
3251     }
3252 }
3253
3254 /**
3255  * Function which continues a peer group starting up
3256  * after successfully generating hostkeys for each peer.
3257  *
3258  * @param pg the peer group to continue starting
3259  *
3260  */
3261 void
3262 GNUNET_TESTING_daemons_continue_startup(struct GNUNET_TESTING_PeerGroup *pg)
3263 {
3264   unsigned int i;
3265
3266   pg->starting = 0;
3267   for (i = 0; i < pg->total; i++)
3268     {
3269       GNUNET_SCHEDULER_add_now (pg->sched, &internal_continue_startup, &pg->peers[i].internal_context);
3270       //GNUNET_TESTING_daemon_continue_startup(pg->peers[i].daemon);
3271     }
3272 }
3273
3274 /**
3275  * Start count gnunet instances with the same set of transports and
3276  * applications.  The port numbers (any option called "PORT") will be
3277  * adjusted to ensure that no two peers running on the same system
3278  * have the same port(s) in their respective configurations.
3279  *
3280  * @param sched scheduler to use
3281  * @param cfg configuration template to use
3282  * @param total number of daemons to start
3283  * @param timeout total time allowed for peers to start
3284  * @param hostkey_callback function to call on each peers hostkey generation
3285  *        if NULL, peers will be started by this call, if non-null,
3286  *        GNUNET_TESTING_daemons_continue_startup must be called after
3287  *        successful hostkey generation
3288  * @param hostkey_cls closure for hostkey callback
3289  * @param cb function to call on each daemon that was started
3290  * @param cb_cls closure for cb
3291  * @param connect_callback function to call each time two hosts are connected
3292  * @param connect_callback_cls closure for connect_callback
3293  * @param hostnames linked list of hosts to use to start peers on (NULL to run on localhost only)
3294  *
3295  * @return NULL on error, otherwise handle to control peer group
3296  */
3297 struct GNUNET_TESTING_PeerGroup *
3298 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
3299                               const struct GNUNET_CONFIGURATION_Handle *cfg,
3300                               unsigned int total,
3301                               struct GNUNET_TIME_Relative timeout,
3302                               GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback,
3303                               void *hostkey_cls,
3304                               GNUNET_TESTING_NotifyDaemonRunning cb,
3305                               void *cb_cls,
3306                               GNUNET_TESTING_NotifyConnection
3307                               connect_callback, void *connect_callback_cls,
3308                               const struct GNUNET_TESTING_Host *hostnames)
3309 {
3310   struct GNUNET_TESTING_PeerGroup *pg;
3311   const struct GNUNET_TESTING_Host *hostpos;
3312 #if 0
3313   char *pos;
3314   const char *rpos;
3315   char *start;
3316 #endif
3317   const char *hostname;
3318   char *baseservicehome;
3319   char *newservicehome;
3320   char *tmpdir;
3321   struct GNUNET_CONFIGURATION_Handle *pcfg;
3322   unsigned int off;
3323   unsigned int hostcnt;
3324   uint16_t minport;
3325   uint32_t upnum;
3326
3327   if (0 == total)
3328     {
3329       GNUNET_break (0);
3330       return NULL;
3331     }
3332   upnum = 0;
3333   pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
3334   pg->sched = sched;
3335   pg->cfg = cfg;
3336   pg->notify_connection = connect_callback;
3337   pg->notify_connection_cls = connect_callback_cls;
3338   pg->total = total;
3339   pg->max_timeout = GNUNET_TIME_relative_to_absolute(timeout);
3340   pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
3341   if (NULL != hostnames)
3342     {
3343       off = 2;
3344       hostpos = hostnames;
3345       while (hostpos != NULL)
3346         {
3347           hostpos = hostpos->next;
3348           off++;
3349         }
3350       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
3351       off = 0;
3352
3353       hostpos = hostnames;
3354       while (hostpos != NULL)
3355         {
3356           pg->hosts[off].minport = LOW_PORT;
3357           pg->hosts[off++].hostname = GNUNET_strdup(hostpos->hostname);
3358           hostpos = hostpos->next;
3359         }
3360
3361       if (off == 0)
3362         {
3363           GNUNET_free (pg->hosts);
3364           pg->hosts = NULL;
3365         }
3366       hostcnt = off;
3367       minport = 0;
3368
3369 #if NO_LL
3370       off = 2;
3371       /* skip leading spaces */
3372       while ((0 != *hostnames) && (isspace ( (unsigned char) *hostnames)))
3373         hostnames++;
3374       rpos = hostnames;
3375       while ('\0' != *rpos)
3376         {
3377           if (isspace ( (unsigned char) *rpos))
3378             off++;
3379           rpos++;
3380         }
3381       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
3382       off = 0;
3383       start = GNUNET_strdup (hostnames);
3384       pos = start;
3385       while ('\0' != *pos)
3386         {
3387           if (isspace ( (unsigned char) *pos))
3388             {
3389               *pos = '\0';
3390               if (strlen (start) > 0)
3391                 {
3392                   pg->hosts[off].minport = LOW_PORT;
3393                   pg->hosts[off++].hostname = start;
3394                 }
3395               start = pos + 1;
3396             }
3397           pos++;
3398         }
3399       if (strlen (start) > 0)
3400         {
3401           pg->hosts[off].minport = LOW_PORT;
3402           pg->hosts[off++].hostname = start;
3403         }
3404       if (off == 0)
3405         {
3406           GNUNET_free (start);
3407           GNUNET_free (pg->hosts);
3408           pg->hosts = NULL;
3409         }
3410       hostcnt = off;
3411       minport = 0;              /* make gcc happy */
3412 #endif
3413     }
3414   else
3415     {
3416       hostcnt = 0;
3417       minport = LOW_PORT;
3418     }
3419   for (off = 0; off < total; off++)
3420     {
3421       if (hostcnt > 0)
3422         {
3423           hostname = pg->hosts[off % hostcnt].hostname;
3424           pcfg = make_config (cfg, 
3425                               &pg->hosts[off % hostcnt].minport,
3426                               &upnum,
3427                               hostname);
3428         }
3429       else
3430         {
3431           hostname = NULL;
3432           pcfg = make_config (cfg,
3433                               &minport,
3434                               &upnum,
3435                               hostname);
3436         }
3437
3438       if (NULL == pcfg)
3439         {
3440           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3441                       _
3442                       ("Could not create configuration for peer number %u on `%s'!\n"),
3443                       off, hostname == NULL ? "localhost" : hostname);
3444           continue;
3445         }
3446
3447       if (GNUNET_YES ==
3448           GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
3449                                                  &baseservicehome))
3450         {
3451           GNUNET_asprintf (&newservicehome,
3452                            "%s/%d/", baseservicehome, off);
3453           GNUNET_free (baseservicehome);
3454         }
3455       else
3456         {
3457           tmpdir = getenv ("TMPDIR");
3458           tmpdir = tmpdir ? tmpdir : "/tmp";
3459           GNUNET_asprintf (&newservicehome,
3460                            "%s/%s/%d/",
3461                            tmpdir,
3462                            "gnunet-testing-test-test", off);
3463         }
3464       GNUNET_CONFIGURATION_set_value_string (pcfg,
3465                                              "PATHS",
3466                                              "SERVICEHOME", newservicehome);
3467       GNUNET_free (newservicehome);
3468       pg->peers[off].cfg = pcfg;
3469       pg->peers[off].allowed_peers = GNUNET_CONTAINER_multihashmap_create(total);
3470       pg->peers[off].connect_peers = GNUNET_CONTAINER_multihashmap_create(total);
3471       pg->peers[off].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create(total);
3472       pg->peers[off].pg = pg;
3473
3474       pg->peers[off].internal_context.peer = &pg->peers[off];
3475       pg->peers[off].internal_context.timeout = timeout;
3476       pg->peers[off].internal_context.hostname = hostname;
3477       pg->peers[off].internal_context.hostkey_callback = hostkey_callback;
3478       pg->peers[off].internal_context.hostkey_cls = hostkey_cls;
3479       pg->peers[off].internal_context.start_cb = cb;
3480       pg->peers[off].internal_context.start_cb_cls = cb_cls;
3481
3482       GNUNET_SCHEDULER_add_now (sched, &internal_start, &pg->peers[off].internal_context);
3483
3484     }
3485   return pg;
3486 }
3487
3488 /*
3489  * Get a daemon by number, so callers don't have to do nasty
3490  * offsetting operation.
3491  */
3492 struct GNUNET_TESTING_Daemon *
3493 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
3494 {
3495   if (position < pg->total)
3496     return pg->peers[position].daemon;
3497   else
3498     return NULL;
3499 }
3500
3501 /**
3502  * Prototype of a function that will be called when a
3503  * particular operation was completed the testing library.
3504  *
3505  * @param cls closure (a struct RestartContext)
3506  * @param id id of the peer that was restarted
3507  * @param cfg handle to the configuration of the peer
3508  * @param d handle to the daemon that was restarted
3509  * @param emsg NULL on success
3510  */
3511 void restart_callback (void *cls,
3512                        const struct GNUNET_PeerIdentity *id,
3513                        const struct GNUNET_CONFIGURATION_Handle *cfg,
3514                        struct GNUNET_TESTING_Daemon *d,
3515                        const char *emsg)
3516 {
3517   struct RestartContext *restart_context = cls;
3518
3519   if (emsg == NULL)
3520     {
3521       restart_context->peers_restarted++;
3522     }
3523   else
3524     {
3525       restart_context->peers_restart_failed++;
3526     }
3527
3528   if (restart_context->peers_restarted == restart_context->peer_group->total)
3529     {
3530       restart_context->callback(restart_context->callback_cls, NULL);
3531       GNUNET_free(restart_context);
3532     }
3533   else if (restart_context->peers_restart_failed + restart_context->peers_restarted == restart_context->peer_group->total)
3534     {
3535       restart_context->callback(restart_context->callback_cls, "Failed to restart peers!");
3536       GNUNET_free(restart_context);
3537     }
3538
3539 }
3540
3541 /**
3542  * Callback for informing us about a successful
3543  * or unsuccessful churn stop call.
3544  *
3545  * @param cls a ChurnContext
3546  * @param emsg NULL on success, non-NULL on failure
3547  *
3548  */
3549 void
3550 churn_stop_callback (void *cls, const char *emsg)
3551 {
3552   struct ChurnContext *churn_ctx = cls;
3553   unsigned int total_left;
3554   char *error_message;
3555
3556   error_message = NULL;
3557   if (emsg != NULL)
3558     {
3559       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
3560                  "Churn stop callback failed with error `%s'\n", emsg);
3561       churn_ctx->num_failed_stop++;
3562     }
3563   else
3564     {
3565       churn_ctx->num_to_stop--;
3566     }
3567
3568 #if DEBUG_CHURN
3569   GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
3570              "Stopped peer, %d left.\n", 
3571              churn_ctx->num_to_stop);
3572 #endif
3573   total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
3574
3575   if (total_left == 0)
3576   {
3577     if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
3578       {
3579         GNUNET_asprintf(&error_message, 
3580                         "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", 
3581                         churn_ctx->num_failed_start, 
3582                         churn_ctx->num_failed_stop);
3583       }
3584     churn_ctx->cb(churn_ctx->cb_cls, error_message);
3585     GNUNET_free_non_null(error_message);
3586     GNUNET_free(churn_ctx);
3587   }
3588 }
3589
3590 /**
3591  * Callback for informing us about a successful
3592  * or unsuccessful churn start call.
3593  *
3594  * @param cls a ChurnContext
3595  * @param id the peer identity of the started peer
3596  * @param cfg the handle to the configuration of the peer
3597  * @param d handle to the daemon for the peer
3598  * @param emsg NULL on success, non-NULL on failure
3599  *
3600  */
3601 void
3602 churn_start_callback (void *cls,
3603                       const struct GNUNET_PeerIdentity *id,
3604                       const struct GNUNET_CONFIGURATION_Handle *cfg,
3605                       struct GNUNET_TESTING_Daemon *d,
3606                       const char *emsg)
3607 {
3608   struct ChurnContext *churn_ctx = cls;
3609   unsigned int total_left;
3610   char *error_message;
3611
3612   error_message = NULL;
3613   if (emsg != NULL)
3614     {
3615       GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 
3616                   "Churn stop callback failed with error `%s'\n",
3617                   emsg);
3618       churn_ctx->num_failed_start++;
3619     }
3620   else
3621     {
3622       churn_ctx->num_to_start--;
3623     }
3624   
3625 #if DEBUG_CHURN
3626   GNUNET_log(GNUNET_ERROR_TYPE_WARNING,
3627              "Started peer, %d left.\n", 
3628              churn_ctx->num_to_start);
3629 #endif
3630
3631   total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
3632
3633   if (total_left == 0)
3634   {
3635     if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
3636       GNUNET_asprintf(&error_message, 
3637                       "Churn didn't complete successfully, %u peers failed to start %u peers failed to be stopped!", 
3638                       churn_ctx->num_failed_start,
3639                       churn_ctx->num_failed_stop);
3640     churn_ctx->cb(churn_ctx->cb_cls, error_message);
3641     GNUNET_free_non_null(error_message);
3642     GNUNET_free(churn_ctx);
3643   }
3644 }
3645
3646
3647 /**
3648  * Simulate churn by stopping some peers (and possibly
3649  * re-starting others if churn is called multiple times).  This
3650  * function can only be used to create leave-join churn (peers "never"
3651  * leave for good).  First "voff" random peers that are currently
3652  * online will be taken offline; then "von" random peers that are then
3653  * offline will be put back online.  No notifications will be
3654  * generated for any of these operations except for the callback upon
3655  * completion.
3656  *
3657  * @param pg handle for the peer group
3658  * @param voff number of peers that should go offline
3659  * @param von number of peers that should come back online;
3660  *            must be zero on first call (since "testbed_start"
3661  *            always starts all of the peers)
3662  * @param timeout how long to wait for operations to finish before
3663  *        giving up
3664  * @param cb function to call at the end
3665  * @param cb_cls closure for cb
3666  */
3667 void
3668 GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg,
3669                               unsigned int voff,
3670                               unsigned int von,
3671                               struct GNUNET_TIME_Relative timeout,
3672                               GNUNET_TESTING_NotifyCompletion cb,
3673                               void *cb_cls)
3674 {
3675   struct ChurnContext *churn_ctx;
3676   unsigned int running;
3677   unsigned int stopped;
3678   unsigned int total_running;
3679   unsigned int total_stopped;
3680   unsigned int i;
3681   unsigned int *running_arr;
3682   unsigned int *stopped_arr;
3683   unsigned int *running_permute;
3684   unsigned int *stopped_permute;
3685
3686   running = 0;
3687   stopped = 0;
3688
3689   if ((von == 0) && (voff == 0)) /* No peers at all? */
3690     {
3691       cb(cb_cls, NULL);
3692       return;
3693     }
3694
3695   for (i = 0; i < pg->total; i++)
3696   {
3697     if (pg->peers[i].daemon->running == GNUNET_YES)
3698     {
3699       GNUNET_assert(running != -1);
3700       running++;
3701     }
3702     else
3703     {
3704       GNUNET_assert(stopped != -1);
3705       stopped++;
3706     }
3707   }
3708
3709   if (voff > running)
3710   {
3711     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to stop more peers than are currently running!\n");
3712     cb(cb_cls, "Trying to stop more peers than are currently running!");
3713     return;
3714   }
3715
3716   if (von > stopped)
3717   {
3718     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to start more peers than are currently stopped!\n");
3719     cb(cb_cls, "Trying to start more peers than are currently stopped!");
3720     return;
3721   }
3722
3723   churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
3724
3725   running_arr = NULL;
3726   if (running > 0)
3727     running_arr = GNUNET_malloc(running * sizeof(unsigned int));
3728
3729   stopped_arr = NULL;
3730   if (stopped > 0)
3731     stopped_arr = GNUNET_malloc(stopped * sizeof(unsigned int));
3732
3733   running_permute = NULL;
3734   stopped_permute = NULL;
3735
3736   if (running > 0)
3737     running_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, running);
3738   if (stopped > 0)
3739     stopped_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, stopped);
3740
3741   total_running = running;
3742   total_stopped = stopped;
3743   running = 0;
3744   stopped = 0;
3745
3746   churn_ctx->num_to_start = von;
3747   churn_ctx->num_to_stop = voff;
3748   churn_ctx->cb = cb;
3749   churn_ctx->cb_cls = cb_cls;  
3750
3751   for (i = 0; i < pg->total; i++)
3752   {
3753     if (pg->peers[i].daemon->running == GNUNET_YES)
3754     {
3755       GNUNET_assert((running_arr != NULL) && (total_running > running));
3756       running_arr[running] = i;
3757       running++;
3758     }
3759     else
3760     {
3761       GNUNET_assert((stopped_arr != NULL) && (total_stopped > stopped));
3762       stopped_arr[stopped] = i;
3763       stopped++;
3764     }
3765   }
3766
3767   for (i = 0; i < voff; i++)
3768   {
3769 #if DEBUG_CHURN
3770     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Stopping peer %d!\n", running_permute[i]);
3771 #endif
3772     GNUNET_TESTING_daemon_stop (pg->peers[running_arr[running_permute[i]]].daemon,
3773                                 timeout, 
3774                                 &churn_stop_callback, churn_ctx, 
3775                                 GNUNET_NO, GNUNET_YES);
3776   }
3777
3778   for (i = 0; i < von; i++)
3779     {
3780 #if DEBUG_CHURN
3781       GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Starting up peer %d!\n", stopped_permute[i]);
3782 #endif
3783       GNUNET_TESTING_daemon_start_stopped(pg->peers[stopped_arr[stopped_permute[i]]].daemon, 
3784                                           timeout, &churn_start_callback, churn_ctx);
3785   }
3786
3787   GNUNET_free_non_null(running_arr);
3788   GNUNET_free_non_null(stopped_arr);
3789   GNUNET_free_non_null(running_permute);
3790   GNUNET_free_non_null(stopped_permute);
3791 }
3792
3793
3794 /**
3795  * Restart all peers in the given group.
3796  *
3797  * @param pg the handle to the peer group
3798  * @param callback function to call on completion (or failure)
3799  * @param callback_cls closure for the callback function
3800  */
3801 void
3802 GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyCompletion callback, void *callback_cls)
3803 {
3804   struct RestartContext *restart_context;
3805   unsigned int off;
3806
3807   if (pg->total > 0)
3808     {
3809       restart_context = GNUNET_malloc(sizeof(struct RestartContext));
3810       restart_context->peer_group = pg;
3811       restart_context->peers_restarted = 0;
3812       restart_context->callback = callback;
3813       restart_context->callback_cls = callback_cls;
3814
3815       for (off = 0; off < pg->total; off++)
3816         {
3817           GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, restart_context);
3818         }
3819     }
3820 }
3821
3822 /**
3823  * Start or stop an individual peer from the given group.
3824  *
3825  * @param pg handle to the peer group
3826  * @param offset which peer to start or stop
3827  * @param desired_status GNUNET_YES to have it running, GNUNET_NO to stop it
3828  * @param timeout how long to wait for shutdown
3829  * @param cb function to call at the end
3830  * @param cb_cls closure for cb
3831  */
3832 void
3833 GNUNET_TESTING_daemons_vary (struct GNUNET_TESTING_PeerGroup *pg, 
3834                              unsigned int offset,
3835                              int desired_status,
3836                              struct GNUNET_TIME_Relative timeout,
3837                              GNUNET_TESTING_NotifyCompletion cb,
3838                              void *cb_cls)
3839 {
3840   struct ChurnContext *churn_ctx;
3841
3842   if (GNUNET_NO == desired_status)
3843     {
3844       if (NULL != pg->peers[offset].daemon)
3845         {
3846           churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
3847           churn_ctx->num_to_start = 0;
3848           churn_ctx->num_to_stop = 1;
3849           churn_ctx->cb = cb;
3850           churn_ctx->cb_cls = cb_cls;  
3851           GNUNET_TESTING_daemon_stop(pg->peers[offset].daemon, 
3852                                      timeout, &churn_stop_callback, churn_ctx, 
3853                                      GNUNET_NO, GNUNET_YES);     
3854         }
3855     }
3856   else if (GNUNET_YES == desired_status)
3857     {
3858       if (NULL == pg->peers[offset].daemon)
3859         {
3860           churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
3861           churn_ctx->num_to_start = 1;
3862           churn_ctx->num_to_stop = 0;
3863           churn_ctx->cb = cb;
3864           churn_ctx->cb_cls = cb_cls;  
3865           GNUNET_TESTING_daemon_start_stopped(pg->peers[offset].daemon, 
3866                                               timeout, &churn_start_callback, churn_ctx);
3867         }
3868     }
3869   else
3870     GNUNET_break (0);
3871 }
3872
3873
3874 /**
3875  * Callback for shutting down peers in a peer group.
3876  *
3877  * @param cls closure (struct ShutdownContext)
3878  * @param emsg NULL on success
3879  */
3880 void internal_shutdown_callback (void *cls,
3881                         const char *emsg)
3882 {
3883   struct ShutdownContext *shutdown_ctx = cls;
3884
3885   if (emsg == NULL)
3886     {
3887       shutdown_ctx->peers_down++;
3888     }
3889   else
3890     {
3891       shutdown_ctx->peers_failed++;
3892     }
3893
3894   if ((shutdown_ctx->cb != NULL) && (shutdown_ctx->peers_down + shutdown_ctx->peers_failed == shutdown_ctx->total_peers))
3895     {
3896       if (shutdown_ctx->peers_failed > 0)
3897         shutdown_ctx->cb(shutdown_ctx->cb_cls, "Not all peers successfully shut down!");
3898       else
3899         shutdown_ctx->cb(shutdown_ctx->cb_cls, NULL);
3900       GNUNET_free(shutdown_ctx);
3901     }
3902 }
3903
3904 /**
3905  * Shutdown all peers started in the given group.
3906  *
3907  * @param pg handle to the peer group
3908  * @param timeout how long to wait for shutdown
3909  * @param cb callback to notify upon success or failure
3910  * @param cb_cls closure for cb
3911  */
3912 void
3913 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, 
3914                              struct GNUNET_TIME_Relative timeout,
3915                              GNUNET_TESTING_NotifyCompletion cb,
3916                              void *cb_cls)
3917 {
3918   unsigned int off;
3919   struct ShutdownContext *shutdown_ctx;
3920   GNUNET_TESTING_NotifyCompletion shutdown_cb;
3921   void *shutdown_cb_cls;
3922
3923   GNUNET_assert(pg->total > 0);
3924
3925   shutdown_cb = NULL;
3926   shutdown_ctx = NULL;
3927
3928   if (cb != NULL)
3929     {
3930       shutdown_ctx = GNUNET_malloc(sizeof(struct ShutdownContext));
3931       shutdown_ctx->cb = cb;
3932       shutdown_ctx->cb_cls = cb_cls;
3933       shutdown_ctx->total_peers = pg->total;
3934       shutdown_cb = &internal_shutdown_callback;
3935       shutdown_cb_cls = cb_cls;
3936     }
3937
3938   for (off = 0; off < pg->total; off++)
3939     {
3940       GNUNET_assert(NULL != pg->peers[off].daemon);
3941       GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, timeout, shutdown_cb, shutdown_ctx, GNUNET_YES, GNUNET_NO);
3942       if (NULL != pg->peers[off].cfg)
3943         GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
3944       if (pg->peers[off].allowed_peers != NULL)
3945         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].allowed_peers);
3946       if (pg->peers[off].connect_peers != NULL)
3947         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].connect_peers);
3948       if (pg->peers[off].blacklisted_peers != NULL)
3949         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].blacklisted_peers);
3950     }
3951   GNUNET_free (pg->peers);
3952   if (NULL != pg->hosts)
3953     {
3954       GNUNET_free (pg->hosts[0].hostname);
3955       GNUNET_free (pg->hosts);
3956     }
3957   GNUNET_free (pg);
3958 }
3959
3960
3961 /* end of testing_group.c */