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