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