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