nitpicks
[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  * @return the number of connections that will be attempted
1700  */
1701 static int
1702 connect_topology (struct GNUNET_TESTING_PeerGroup *pg)
1703 {
1704   unsigned int pg_iter;
1705   int ret;
1706   int total;
1707 #if OLD
1708   struct PeerConnection *connection_iter;
1709   struct ConnectContext *connect_context;
1710 #endif
1711
1712   total = 0;
1713   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
1714     {
1715       ret = GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &connect_iterator, &pg->peers[pg_iter]);
1716       if (GNUNET_SYSERR == ret)
1717         return GNUNET_SYSERR;
1718
1719       total = total + ret;
1720
1721 #if OLD
1722       connection_iter = ;
1723       while (connection_iter != NULL)
1724         {
1725           connect_context = GNUNET_malloc(sizeof(struct ConnectContext));
1726           connect_context->pg = pg;
1727           connect_context->first = ;
1728           connect_context->second = connection_iter->daemon;
1729           GNUNET_SCHEDULER_add_now(pg->sched, &schedule_connect, connect_context);
1730           connection_iter = connection_iter->next;
1731         }
1732 #endif
1733     }
1734   return total;
1735 }
1736
1737
1738 /**
1739  * Takes a peer group and creates a topology based on the
1740  * one specified.  Creates a topology means generates friend
1741  * files for the peers so they can only connect to those allowed
1742  * by the topology.  This will only have an effect once peers
1743  * are started if the FRIENDS_ONLY option is set in the base
1744  * config.  Also takes an optional restrict topology which
1745  * disallows direct TCP connections UNLESS they are specified in
1746  * the restricted topology.
1747  *
1748  * @param pg the peer group struct representing the running peers
1749  * @param topology which topology to connect the peers in
1750  * @param restrict_topology allow only direct TCP connections in this topology
1751  *                          use GNUNET_TESTING_TOPOLOGY_NONE for no restrictions
1752  * @param restrict_transports space delimited list of transports to blacklist
1753  *                            to create restricted topology
1754  *
1755  * @return the maximum number of connections were all allowed peers
1756  *         connected to each other
1757  */
1758 int
1759 GNUNET_TESTING_create_topology (struct GNUNET_TESTING_PeerGroup *pg,
1760                                 enum GNUNET_TESTING_Topology topology,
1761                                 enum GNUNET_TESTING_Topology restrict_topology,
1762                                 char *restrict_transports)
1763 {
1764   int ret;
1765   int num_connections;
1766   int unblacklisted_connections;
1767
1768   GNUNET_assert (pg->notify_connection != NULL);
1769   ret = GNUNET_OK;
1770
1771   switch (topology)
1772     {
1773     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
1774 #if VERBOSE_TESTING
1775       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1776                   _("Creating clique topology\n"));
1777 #endif
1778       num_connections = create_clique (pg, &add_allowed_connections);
1779       break;
1780     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
1781 #if VERBOSE_TESTING
1782       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1783                   _("Creating small world (ring) topology\n"));
1784 #endif
1785       num_connections = create_small_world_ring (pg, &add_allowed_connections);
1786       break;
1787     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
1788 #if VERBOSE_TESTING
1789       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1790                   _("Creating small world (2d-torus) topology\n"));
1791 #endif
1792       num_connections = create_small_world (pg, &add_allowed_connections);
1793       break;
1794     case GNUNET_TESTING_TOPOLOGY_RING:
1795 #if VERBOSE_TESTING
1796       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1797                   _("Creating ring topology\n"));
1798 #endif
1799       num_connections = create_ring (pg, &add_allowed_connections);
1800       break;
1801     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
1802 #if VERBOSE_TESTING
1803       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1804                   _("Creating 2d torus topology\n"));
1805 #endif
1806       num_connections = create_2d_torus (pg, &add_allowed_connections);
1807       break;
1808     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
1809 #if VERBOSE_TESTING
1810       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1811                   _("Creating Erdos-Renyi topology\n"));
1812 #endif
1813       num_connections = create_erdos_renyi (pg, &add_allowed_connections);
1814       break;
1815     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
1816 #if VERBOSE_TESTING
1817       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1818                   _("Creating InterNAT topology\n"));
1819 #endif
1820       num_connections = create_nated_internet (pg, &add_allowed_connections);
1821       break;
1822     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
1823 #if VERBOSE_TESTING
1824       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1825                   _("Creating Scale Free topology\n"));
1826 #endif
1827       num_connections = create_scale_free (pg, &add_allowed_connections);
1828       break;
1829     case GNUNET_TESTING_TOPOLOGY_NONE:
1830       num_connections = 0;
1831       break;
1832     default:
1833       num_connections = 0;
1834       break;
1835     }
1836   if (num_connections < 1)
1837     return GNUNET_SYSERR;
1838
1839   if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pg->cfg, "TESTING", "F2F"))
1840     {
1841       ret = create_and_copy_friend_files(pg);
1842     }
1843
1844   if (ret != GNUNET_OK)
1845     {
1846 #if VERBOSE_TESTING
1847       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1848                   _("Failed during friend file copying!\n"));
1849 #endif
1850       return GNUNET_SYSERR;
1851     }
1852   else
1853     {
1854 #if VERBOSE_TESTING
1855           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1856                       _("Friend files created/copied successfully!\n"));
1857 #endif
1858     }
1859
1860   /* Use the create clique method to initially set all connections as blacklisted. */
1861   create_clique (pg, &blacklist_connections);
1862   unblacklisted_connections = 0;
1863   /* Un-blacklist connections as per the topology specified */
1864   switch (restrict_topology)
1865     {
1866     case GNUNET_TESTING_TOPOLOGY_CLIQUE:
1867 #if VERBOSE_TESTING
1868       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1869                   _("Blacklisting all but clique topology\n"));
1870 #endif
1871       unblacklisted_connections = create_clique (pg, &unblacklist_connections);
1872       break;
1873     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
1874 #if VERBOSE_TESTING
1875       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1876                   _("Blacklisting all but small world (ring) topology\n"));
1877 #endif
1878       unblacklisted_connections = create_small_world_ring (pg, &unblacklist_connections);
1879       break;
1880     case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
1881 #if VERBOSE_TESTING
1882       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1883                   _("Blacklisting all but small world (2d-torus) topology\n"));
1884 #endif
1885       unblacklisted_connections = create_small_world (pg, &unblacklist_connections);
1886       break;
1887     case GNUNET_TESTING_TOPOLOGY_RING:
1888 #if VERBOSE_TESTING
1889       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1890                   _("Blacklisting all but ring topology\n"));
1891 #endif
1892       unblacklisted_connections = create_ring (pg, &unblacklist_connections);
1893       break;
1894     case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
1895 #if VERBOSE_TESTING
1896       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1897                   _("Blacklisting all but 2d torus topology\n"));
1898 #endif
1899       unblacklisted_connections = create_2d_torus (pg, &unblacklist_connections);
1900       break;
1901     case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
1902 #if VERBOSE_TESTING
1903       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1904                   _("Blacklisting all but Erdos-Renyi topology\n"));
1905 #endif
1906       unblacklisted_connections = create_erdos_renyi (pg, &unblacklist_connections);
1907       break;
1908     case GNUNET_TESTING_TOPOLOGY_INTERNAT:
1909 #if VERBOSE_TESTING
1910       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1911                   _("Blacklisting all but InterNAT topology\n"));
1912 #endif
1913       unblacklisted_connections = create_nated_internet (pg, &unblacklist_connections);
1914       break;
1915     case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
1916 #if VERBOSE_TESTING
1917       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1918                   _("Blacklisting all but Scale Free topology\n"));
1919 #endif
1920       unblacklisted_connections = create_scale_free (pg, &unblacklist_connections);
1921       break;
1922     case GNUNET_TESTING_TOPOLOGY_NONE:
1923       /* Fall through */
1924     default:
1925       break;
1926     }
1927
1928   if ((unblacklisted_connections > 0) && (restrict_transports != NULL))
1929   {
1930     ret = create_and_copy_blacklist_files(pg, restrict_transports);
1931     if (ret != GNUNET_OK)
1932       {
1933 #if VERBOSE_TESTING
1934         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1935                     _("Failed during blacklist file copying!\n"));
1936 #endif
1937         return GNUNET_SYSERR;
1938       }
1939     else
1940       {
1941 #if VERBOSE_TESTING
1942         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1943                     _("Blacklist files created/copied successfully!\n"));
1944 #endif
1945       }
1946   }
1947   return num_connections;
1948 }
1949
1950 struct RandomContext
1951 {
1952   /**
1953    * The peergroup
1954    */
1955   struct GNUNET_TESTING_PeerGroup *pg;
1956
1957   /**
1958    * uid of the first peer
1959    */
1960   uint32_t first_uid;
1961
1962   /**
1963    * Peer data for first peer.
1964    */
1965   struct PeerData *first;
1966
1967   /**
1968    * Random percentage to use
1969    */
1970   double percentage;
1971 };
1972
1973 struct MinimumContext
1974 {
1975   /**
1976    * The peergroup
1977    */
1978   struct GNUNET_TESTING_PeerGroup *pg;
1979
1980   /**
1981    * uid of the first peer
1982    */
1983   uint32_t first_uid;
1984
1985   /**
1986    * Peer data for first peer.
1987    */
1988   struct PeerData *first;
1989
1990   /**
1991    * Number of conns per peer
1992    */
1993   unsigned int num_to_add;
1994
1995   /**
1996    * Permuted array of all possible connections.  Only add the Nth
1997    * peer if it's in the Nth position.
1998    */
1999   unsigned int *pg_array;
2000
2001   /**
2002    * What number is the current element we are iterating over?
2003    */
2004   unsigned int current;
2005 };
2006
2007 struct DFSContext
2008 {
2009   /**
2010    * The peergroup
2011    */
2012   struct GNUNET_TESTING_PeerGroup *pg;
2013
2014   /**
2015    * uid of the first peer
2016    */
2017   uint32_t first_uid;
2018
2019   /**
2020    * uid of the second peer
2021    */
2022   uint32_t second_uid;
2023
2024   /**
2025    * Peer data for first peer.
2026    */
2027   struct PeerData *first;
2028
2029   /**
2030    * Which peer has been chosen as the one to add?
2031    */
2032   unsigned int chosen;
2033
2034   /**
2035    * What number is the current element we are iterating over?
2036    */
2037   unsigned int current;
2038 };
2039
2040 /**
2041  * Iterator for choosing random peers to connect.
2042  *
2043  * @param cls closure, a RandomContext
2044  * @param key the key the second Daemon was stored under
2045  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2046  *
2047  * @return GNUNET_YES to continue iteration
2048  */
2049 static int
2050 random_connect_iterator (void *cls,
2051                   const GNUNET_HashCode * key,
2052                   void *value)
2053 {
2054   struct RandomContext *random_ctx = cls;
2055   double random_number;
2056   uint32_t second_pos;
2057   GNUNET_HashCode first_hash;
2058   random_number = ((double) GNUNET_CRYPTO_random_u64(GNUNET_CRYPTO_QUALITY_WEAK,
2059                    (uint64_t)-1LL)) / ( (double) (uint64_t) -1LL);
2060   if (random_number < random_ctx->percentage)
2061   {
2062     GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(random_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2063   }
2064   /* Now we have considered this particular connection, remove it from the second peer so it's not double counted */
2065   uid_from_hash(key, &second_pos);
2066   hash_from_uid(random_ctx->first_uid, &first_hash);
2067   GNUNET_assert(random_ctx->pg->total > second_pos);
2068   GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(random_ctx->pg->peers[second_pos].connect_peers, &first_hash, random_ctx->first->daemon));
2069
2070   return GNUNET_YES;
2071 }
2072
2073 /**
2074  * Iterator for adding at least X peers to a peers connection set.
2075  *
2076  * @param cls closure, MinimumContext
2077  * @param key the key the second Daemon was stored under
2078  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2079  *
2080  * @return GNUNET_YES to continue iteration
2081  */
2082 static int
2083 minimum_connect_iterator (void *cls,
2084                   const GNUNET_HashCode * key,
2085                   void *value)
2086 {
2087   struct MinimumContext *min_ctx = cls;
2088   uint32_t second_pos;
2089   GNUNET_HashCode first_hash;
2090   unsigned int i;
2091
2092   if (GNUNET_CONTAINER_multihashmap_size(min_ctx->first->connect_peers_working_set) < min_ctx->num_to_add)
2093   {
2094     for (i = 0; i < min_ctx->num_to_add; i++)
2095     {
2096       if (min_ctx->pg_array[i] == min_ctx->current)
2097       {
2098         GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(min_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2099         uid_from_hash(key, &second_pos);
2100         hash_from_uid(min_ctx->first_uid, &first_hash);
2101         GNUNET_assert(min_ctx->pg->total > second_pos);
2102         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));
2103         /* Now we have added this particular connection, remove it from the second peer's map so it's not double counted */
2104         GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(min_ctx->pg->peers[second_pos].connect_peers, &first_hash, min_ctx->first->daemon));
2105       }
2106     }
2107     min_ctx->current++;
2108     return GNUNET_YES;
2109   }
2110   else
2111     return GNUNET_NO; /* We can stop iterating, we have enough peers! */
2112
2113 }
2114
2115
2116 /**
2117  * Iterator for adding peers to a connection set based on a depth first search.
2118  *
2119  * @param cls closure, MinimumContext
2120  * @param key the key the second daemon was stored under
2121  * @param value the GNUNET_TESTING_Daemon that the first is to connect to
2122  *
2123  * @return GNUNET_YES to continue iteration
2124  */
2125 static int
2126 dfs_connect_iterator (void *cls,
2127                   const GNUNET_HashCode * key,
2128                   void *value)
2129 {
2130   struct DFSContext *dfs_ctx = cls;
2131   GNUNET_HashCode first_hash;
2132
2133   if (dfs_ctx->current == dfs_ctx->chosen)
2134     {
2135       GNUNET_assert(GNUNET_OK == GNUNET_CONTAINER_multihashmap_put(dfs_ctx->first->connect_peers_working_set, key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
2136       uid_from_hash(key, &dfs_ctx->second_uid);
2137       hash_from_uid(dfs_ctx->first_uid, &first_hash);
2138       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));
2139       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(dfs_ctx->pg->peers[dfs_ctx->second_uid].connect_peers, &first_hash, dfs_ctx->first->daemon));
2140       /* Can't remove second from first yet because we are currently iterating, hence the return value in the DFSContext! */
2141       return GNUNET_NO; /* We have found our peer, don't iterate more */
2142     }
2143
2144   dfs_ctx->current++;
2145   return GNUNET_YES;
2146 }
2147
2148
2149 /**
2150  * From the set of connections possible, choose percentage percent of connections
2151  * to actually connect.
2152  *
2153  * @param pg the peergroup we are dealing with
2154  * @param percentage what percent of total connections to make
2155  */
2156 void
2157 choose_random_connections(struct GNUNET_TESTING_PeerGroup *pg, double percentage)
2158 {
2159   struct RandomContext random_ctx;
2160   uint32_t pg_iter;
2161
2162   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2163     {
2164       random_ctx.first_uid = pg_iter;
2165       random_ctx.first = &pg->peers[pg_iter];
2166       random_ctx.percentage = percentage;
2167       random_ctx.pg = pg;
2168       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(pg->total);
2169       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &random_connect_iterator, &random_ctx);
2170       /* Now remove the old connections */
2171       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2172       /* And replace with the random set */
2173       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2174     }
2175 }
2176
2177 /**
2178  * From the set of connections possible, choose at least num connections per
2179  * peer.
2180  *
2181  * @param pg the peergroup we are dealing with
2182  * @param num how many connections at least should each peer have (if possible)?
2183  */
2184 void
2185 choose_minimum(struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2186 {
2187   struct MinimumContext minimum_ctx;
2188   uint32_t pg_iter;
2189
2190   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2191     {
2192       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2193     }
2194
2195   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2196     {
2197       minimum_ctx.first_uid = pg_iter;
2198       minimum_ctx.pg_array = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2199       minimum_ctx.first = &pg->peers[pg_iter];
2200       minimum_ctx.pg = pg;
2201       minimum_ctx.num_to_add = num;
2202       minimum_ctx.current = 0;
2203       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(pg->total);
2204       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[pg_iter].connect_peers, &minimum_connect_iterator, &minimum_ctx);
2205     }
2206
2207   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2208     {
2209       /* Remove the "old" connections */
2210       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2211       /* And replace with the working set */
2212       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2213       fprintf(stderr, "Finished! Hashmap size %u\n", GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2214     }
2215
2216 }
2217
2218
2219 static unsigned int count_workingset_connections(struct GNUNET_TESTING_PeerGroup *pg)
2220 {
2221   unsigned int count;
2222   unsigned int pg_iter;
2223
2224   count = 0;
2225
2226   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2227     {
2228       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2229     }
2230
2231   return count;
2232 }
2233
2234
2235 static unsigned int count_allowed_connections(struct GNUNET_TESTING_PeerGroup *pg)
2236 {
2237   unsigned int count;
2238   unsigned int pg_iter;
2239
2240   count = 0;
2241
2242   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2243     {
2244       count += GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers);
2245     }
2246
2247   return count;
2248 }
2249
2250 /**
2251  * From the set of connections possible, choose at least num connections per
2252  * peer based on depth first traversal of peer connections.  If DFS leaves
2253  * peers unconnected, ensure those peers get connections.
2254  *
2255  * @param pg the peergroup we are dealing with
2256  * @param num how many connections at least should each peer have (if possible)?
2257  */
2258 void
2259 perform_dfs (struct GNUNET_TESTING_PeerGroup *pg, unsigned int num)
2260 {
2261   struct DFSContext dfs_ctx;
2262   uint32_t pg_iter;
2263   uint32_t dfs_count;
2264   uint32_t starting_peer;
2265   uint32_t least_connections;
2266   GNUNET_HashCode second_hash;
2267
2268   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2269     {
2270       pg->peers[pg_iter].connect_peers_working_set = GNUNET_CONTAINER_multihashmap_create(num);
2271     }
2272
2273   starting_peer = 0;
2274   dfs_count = 0;
2275   while ((count_workingset_connections(pg) < num * pg->total) && (count_allowed_connections(pg) > 0))
2276     {
2277       if (dfs_count % pg->total == 0) /* Restart the DFS at some weakly connected peer */
2278         {
2279           least_connections = -1; /* Set to very high number */
2280           for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2281             {
2282               if (GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set) < least_connections)
2283                 {
2284                   starting_peer = pg_iter;
2285                   least_connections = GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers_working_set);
2286                 }
2287             }
2288         }
2289
2290       if (GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers) == 0)  /* Ensure there is at least one peer left to connect! */
2291         {
2292           dfs_count = 0;
2293           continue;
2294         }
2295
2296       /* Choose a random peer from the chosen peers set of connections to add */
2297       dfs_ctx.chosen = GNUNET_CRYPTO_random_u32(GNUNET_CRYPTO_QUALITY_WEAK, GNUNET_CONTAINER_multihashmap_size(pg->peers[starting_peer].connect_peers));
2298       dfs_ctx.first_uid = starting_peer;
2299       dfs_ctx.first = &pg->peers[starting_peer];
2300       dfs_ctx.pg = pg;
2301       dfs_ctx.current = 0;
2302
2303       GNUNET_CONTAINER_multihashmap_iterate(pg->peers[starting_peer].connect_peers, &dfs_connect_iterator, &dfs_ctx);
2304       /* Remove the second from the first, since we will be continuing the search and may encounter the first peer again! */
2305       hash_from_uid(dfs_ctx.second_uid, &second_hash);
2306       GNUNET_assert(GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(pg->peers[starting_peer].connect_peers, &second_hash, pg->peers[dfs_ctx.second_uid].daemon));
2307       starting_peer = dfs_ctx.second_uid;
2308     }
2309
2310   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2311     {
2312
2313     }
2314
2315   for (pg_iter = 0; pg_iter < pg->total; pg_iter++)
2316     {
2317       /* Remove the "old" connections */
2318       GNUNET_CONTAINER_multihashmap_destroy(pg->peers[pg_iter].connect_peers);
2319       /* And replace with the working set */
2320       pg->peers[pg_iter].connect_peers = pg->peers[pg_iter].connect_peers_working_set;
2321       fprintf(stderr, "Finished! Hashmap size %u\n", GNUNET_CONTAINER_multihashmap_size(pg->peers[pg_iter].connect_peers));
2322     }
2323
2324 }
2325
2326 /**
2327  * There are many ways to connect peers that are supported by this function.
2328  * To connect peers in the same topology that was created via the
2329  * GNUNET_TESTING_create_topology, the topology variable must be set to
2330  * GNUNET_TESTING_TOPOLOGY_NONE.  If the topology variable is specified,
2331  * a new instance of that topology will be generated and attempted to be
2332  * connected.  This could result in some connections being impossible,
2333  * because some topologies are non-deterministic.
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  * @return the number of connections that will be attempted, GNUNET_SYSERR on error
2340  */
2341 int
2342 GNUNET_TESTING_connect_topology (struct GNUNET_TESTING_PeerGroup *pg,
2343                                  enum GNUNET_TESTING_Topology topology,
2344                                  enum GNUNET_TESTING_TopologyOption options,
2345                                  double option_modifier)
2346 {
2347   switch (topology)
2348       {
2349       case GNUNET_TESTING_TOPOLOGY_CLIQUE:
2350   #if VERBOSE_TESTING
2351         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2352                     _("Creating clique topology\n"));
2353   #endif
2354         create_clique (pg, &add_actual_connections);
2355         break;
2356       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD_RING:
2357   #if VERBOSE_TESTING
2358         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2359                     _("Creating small world (ring) topology\n"));
2360   #endif
2361         create_small_world_ring (pg, &add_actual_connections);
2362         break;
2363       case GNUNET_TESTING_TOPOLOGY_SMALL_WORLD:
2364   #if VERBOSE_TESTING
2365         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2366                     _("Creating small world (2d-torus) topology\n"));
2367   #endif
2368         create_small_world (pg, &add_actual_connections);
2369         break;
2370       case GNUNET_TESTING_TOPOLOGY_RING:
2371   #if VERBOSE_TESTING
2372         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2373                     _("Creating ring topology\n"));
2374   #endif
2375         create_ring (pg, &add_actual_connections);
2376         break;
2377       case GNUNET_TESTING_TOPOLOGY_2D_TORUS:
2378   #if VERBOSE_TESTING
2379         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2380                     _("Creating 2d torus topology\n"));
2381   #endif
2382         create_2d_torus (pg, &add_actual_connections);
2383         break;
2384       case GNUNET_TESTING_TOPOLOGY_ERDOS_RENYI:
2385   #if VERBOSE_TESTING
2386         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2387                     _("Creating Erdos-Renyi topology\n"));
2388   #endif
2389         create_erdos_renyi (pg, &add_actual_connections);
2390         break;
2391       case GNUNET_TESTING_TOPOLOGY_INTERNAT:
2392   #if VERBOSE_TESTING
2393         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2394                     _("Creating InterNAT topology\n"));
2395   #endif
2396         create_nated_internet (pg, &add_actual_connections);
2397         break;
2398       case GNUNET_TESTING_TOPOLOGY_SCALE_FREE:
2399   #if VERBOSE_TESTING
2400         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2401                     _("Creating Scale Free topology\n"));
2402   #endif
2403         create_scale_free (pg, &add_actual_connections);
2404         break;
2405       case GNUNET_TESTING_TOPOLOGY_NONE:
2406         num_connections = copy_allowed_topology(pg);
2407         break;
2408       default:
2409         GNUNET_log(GNUNET_ERROR_TYPE_WARNING, 
2410                    _("Unknown topology specification, can't connect peers!\n"));
2411         return GNUNET_SYSERR;
2412       }
2413
2414   switch (options)
2415     {
2416     case GNUNET_TESTING_TOPOLOGY_OPTION_RANDOM: 
2417       choose_random_connections(pg, option_modifier);
2418       break;
2419     case GNUNET_TESTING_TOPOLOGY_OPTION_MINIMUM: 
2420       choose_minimum(pg, (unsigned int)option_modifier);
2421       break;
2422     case GNUNET_TESTING_TOPOLOGY_OPTION_DFS: 
2423       perform_dfs(pg, (int)option_modifier);
2424       break;
2425     case GNUNET_TESTING_TOPOLOGY_OPTION_NONE:
2426       break;
2427     case GNUNET_TESTING_TOPOLOGY_OPTION_ALL:
2428       break;
2429     default:
2430       break;
2431     }
2432
2433   return connect_topology(pg);
2434 }
2435
2436 /**
2437  * Function which continues a peer group starting up
2438  * after successfully generating hostkeys for each peer.
2439  *
2440  * @param pg the peer group to continue starting
2441  *
2442  */
2443 void
2444 GNUNET_TESTING_daemons_continue_startup(struct GNUNET_TESTING_PeerGroup *pg)
2445 {
2446   unsigned int i;
2447
2448   for (i = 0; i < pg->total; i++)
2449     {
2450       GNUNET_TESTING_daemon_continue_startup(pg->peers[i].daemon);
2451     }
2452 }
2453
2454 /**
2455  * Start count gnunetd processes with the same set of transports and
2456  * applications.  The port numbers (any option called "PORT") will be
2457  * adjusted to ensure that no two peers running on the same system
2458  * have the same port(s) in their respective configurations.
2459  *
2460  * @param sched scheduler to use
2461  * @param cfg configuration template to use
2462  * @param total number of daemons to start
2463  * @param timeout total time allowed for peers to start
2464  * @param hostkey_callback function to call on each peers hostkey generation
2465  *        if NULL, peers will be started by this call, if non-null,
2466  *        GNUNET_TESTING_daemons_continue_startup must be called after
2467  *        successful hostkey generation
2468  * @param hostkey_cls closure for hostkey callback
2469  * @param cb function to call on each daemon that was started
2470  * @param cb_cls closure for cb
2471  * @param connect_callback function to call each time two hosts are connected
2472  * @param connect_callback_cls closure for connect_callback
2473  * @param hostnames space-separated list of hostnames to use; can be NULL (to run
2474  *        everything on localhost).
2475  * @return NULL on error, otherwise handle to control peer group
2476  */
2477 struct GNUNET_TESTING_PeerGroup *
2478 GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
2479                               const struct GNUNET_CONFIGURATION_Handle *cfg,
2480                               unsigned int total,
2481                               struct GNUNET_TIME_Relative timeout,
2482                               GNUNET_TESTING_NotifyHostkeyCreated hostkey_callback,
2483                               void *hostkey_cls,
2484                               GNUNET_TESTING_NotifyDaemonRunning cb,
2485                               void *cb_cls,
2486                               GNUNET_TESTING_NotifyConnection
2487                               connect_callback, void *connect_callback_cls,
2488                               const char *hostnames)
2489 {
2490   struct GNUNET_TESTING_PeerGroup *pg;
2491   const char *rpos;
2492   char *pos;
2493   char *start;
2494   const char *hostname;
2495   char *baseservicehome;
2496   char *newservicehome;
2497   char *tmpdir;
2498   struct GNUNET_CONFIGURATION_Handle *pcfg;
2499   unsigned int off;
2500   unsigned int hostcnt;
2501   uint16_t minport;
2502
2503   if (0 == total)
2504     {
2505       GNUNET_break (0);
2506       return NULL;
2507     }
2508
2509   pg = GNUNET_malloc (sizeof (struct GNUNET_TESTING_PeerGroup));
2510   pg->sched = sched;
2511   pg->cfg = cfg;
2512   pg->cb = cb;
2513   pg->cb_cls = cb_cls;
2514   pg->notify_connection = connect_callback;
2515   pg->notify_connection_cls = connect_callback_cls;
2516   pg->total = total;
2517   pg->max_timeout = GNUNET_TIME_relative_to_absolute(timeout);
2518   pg->peers = GNUNET_malloc (total * sizeof (struct PeerData));
2519   if (NULL != hostnames)
2520     {
2521       off = 2;
2522       /* skip leading spaces */
2523       while ((0 != *hostnames) && (isspace (*hostnames)))
2524         hostnames++;
2525       rpos = hostnames;
2526       while ('\0' != *rpos)
2527         {
2528           if (isspace (*rpos))
2529             off++;
2530           rpos++;
2531         }
2532       pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
2533       off = 0;
2534       start = GNUNET_strdup (hostnames);
2535       pos = start;
2536       while ('\0' != *pos)
2537         {
2538           if (isspace (*pos))
2539             {
2540               *pos = '\0';
2541               if (strlen (start) > 0)
2542                 {
2543                   pg->hosts[off].minport = LOW_PORT;
2544                   pg->hosts[off++].hostname = start;
2545                 }
2546               start = pos + 1;
2547             }
2548           pos++;
2549         }
2550       if (strlen (start) > 0)
2551         {
2552           pg->hosts[off].minport = LOW_PORT;
2553           pg->hosts[off++].hostname = start;
2554         }
2555       if (off == 0)
2556         {
2557           GNUNET_free (start);
2558           GNUNET_free (pg->hosts);
2559           pg->hosts = NULL;
2560         }
2561       hostcnt = off;
2562       minport = 0;              /* make gcc happy */
2563     }
2564   else
2565     {
2566       hostcnt = 0;
2567       minport = LOW_PORT;
2568     }
2569   for (off = 0; off < total; off++)
2570     {
2571       if (hostcnt > 0)
2572         {
2573           hostname = pg->hosts[off % hostcnt].hostname;
2574           pcfg = make_config (cfg, &pg->hosts[off % hostcnt].minport, hostname);
2575         }
2576       else
2577         {
2578           hostname = NULL;
2579           pcfg = make_config (cfg, &minport, hostname);
2580         }
2581
2582       if (NULL == pcfg)
2583         {
2584           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2585                       _
2586                       ("Could not create configuration for peer number %u on `%s'!\n"),
2587                       off, hostname == NULL ? "localhost" : hostname);
2588           continue;
2589         }
2590
2591       if (GNUNET_YES ==
2592           GNUNET_CONFIGURATION_get_value_string (pcfg, "PATHS", "SERVICEHOME",
2593                                                  &baseservicehome))
2594         {
2595           GNUNET_asprintf (&newservicehome,
2596                            "%s/%d/", baseservicehome, off);
2597           GNUNET_free (baseservicehome);
2598         }
2599       else
2600         {
2601           tmpdir = getenv ("TMPDIR");
2602           tmpdir = tmpdir ? tmpdir : "/tmp";
2603           GNUNET_asprintf (&newservicehome,
2604                            "%s/%s/%d/",
2605                            tmpdir,
2606                            "gnunet-testing-test-test", off);
2607         }
2608       GNUNET_CONFIGURATION_set_value_string (pcfg,
2609                                              "PATHS",
2610                                              "SERVICEHOME", newservicehome);
2611       GNUNET_free (newservicehome);
2612       pg->peers[off].cfg = pcfg;
2613       pg->peers[off].allowed_peers = GNUNET_CONTAINER_multihashmap_create(total);
2614       pg->peers[off].connect_peers = GNUNET_CONTAINER_multihashmap_create(total);
2615       pg->peers[off].blacklisted_peers = GNUNET_CONTAINER_multihashmap_create(total);
2616       pg->peers[off].pg = pg;
2617       pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
2618                                                            pcfg,
2619                                                            timeout,
2620                                                            hostname,
2621                                                            hostkey_callback,
2622                                                            hostkey_cls,
2623                                                            cb, cb_cls);
2624       if (NULL == pg->peers[off].daemon)
2625         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2626                     _("Could not start peer number %u!\n"), off);
2627
2628     }
2629   return pg;
2630 }
2631
2632 /*
2633  * Get a daemon by number, so callers don't have to do nasty
2634  * offsetting operation.
2635  */
2636 struct GNUNET_TESTING_Daemon *
2637 GNUNET_TESTING_daemon_get (struct GNUNET_TESTING_PeerGroup *pg, unsigned int position)
2638 {
2639   if (position < pg->total)
2640     return pg->peers[position].daemon;
2641   else
2642     return NULL;
2643 }
2644
2645 /**
2646  * Prototype of a function that will be called when a
2647  * particular operation was completed the testing library.
2648  *
2649  * @param id id of the peer that was restarted
2650  * @param cfg handle to the configuration of the peer
2651  * @param d handle to the daemon that was restarted
2652  * @param emsg NULL on success
2653  */
2654 void restart_callback (void *cls,
2655                        const struct GNUNET_PeerIdentity *id,
2656                        const struct GNUNET_CONFIGURATION_Handle *cfg,
2657                        struct GNUNET_TESTING_Daemon *d,
2658                        const char *emsg)
2659 {
2660   struct RestartContext *restart_context = cls;
2661
2662   if (emsg == NULL)
2663     {
2664       restart_context->peers_restarted++;
2665     }
2666   else
2667     {
2668       restart_context->peers_restart_failed++;
2669     }
2670
2671   if (restart_context->peers_restarted == restart_context->peer_group->total)
2672     {
2673       restart_context->callback(restart_context->callback_cls, NULL);
2674       GNUNET_free(restart_context);
2675     }
2676   else if (restart_context->peers_restart_failed + restart_context->peers_restarted == restart_context->peer_group->total)
2677     {
2678       restart_context->callback(restart_context->callback_cls, "Failed to restart peers!");
2679       GNUNET_free(restart_context);
2680     }
2681
2682 }
2683
2684 /**
2685  * Callback for informing us about a successful
2686  * or unsuccessful churn stop call.
2687  *
2688  * @param cls a ChurnContext
2689  * @param emsg NULL on success, non-NULL on failure
2690  *
2691  */
2692 void
2693 churn_stop_callback (void *cls, const char *emsg)
2694 {
2695   struct ChurnContext *churn_ctx = cls;
2696   unsigned int total_left;
2697   char *error_message;
2698
2699   error_message = NULL;
2700   if (emsg != NULL)
2701   {
2702     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Churn stop callback failed with error `%s'\n", emsg);
2703     churn_ctx->num_failed_stop++;
2704   }
2705   else
2706   {
2707     churn_ctx->num_to_stop--;
2708   }
2709
2710 #if DEBUG_CHURN
2711     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Stopped peer, %d left.\n", churn_ctx->num_to_stop);
2712 #endif
2713   total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
2714
2715   if (total_left == 0)
2716   {
2717     if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
2718       {
2719         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);
2720       }
2721     churn_ctx->cb(churn_ctx->cb_cls, error_message);
2722     GNUNET_free_non_null(error_message);
2723     GNUNET_free(churn_ctx);
2724   }
2725 }
2726
2727 /**
2728  * Callback for informing us about a successful
2729  * or unsuccessful churn start call.
2730  *
2731  * @param cls a ChurnContext
2732  * @param id the peer identity of the started peer
2733  * @param cfg the handle to the configuration of the peer
2734  * @param d handle to the daemon for the peer
2735  * @param emsg NULL on success, non-NULL on failure
2736  *
2737  */
2738 void
2739 churn_start_callback (void *cls,
2740                       const struct GNUNET_PeerIdentity *id,
2741                       const struct GNUNET_CONFIGURATION_Handle *cfg,
2742                       struct GNUNET_TESTING_Daemon *d,
2743                       const char *emsg)
2744 {
2745   struct ChurnContext *churn_ctx = cls;
2746   unsigned int total_left;
2747   char *error_message;
2748
2749   error_message = NULL;
2750   if (emsg != NULL)
2751   {
2752     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Churn stop callback failed with error `%s'\n", emsg);
2753     churn_ctx->num_failed_start++;
2754   }
2755   else
2756   {
2757     churn_ctx->num_to_start--;
2758   }
2759
2760 #if DEBUG_CHURN
2761     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Started peer, %d left.\n", churn_ctx->num_to_start);
2762 #endif
2763
2764   total_left = (churn_ctx->num_to_stop - churn_ctx->num_failed_stop) + (churn_ctx->num_to_start - churn_ctx->num_failed_start);
2765
2766   if (total_left == 0)
2767   {
2768     if ((churn_ctx->num_failed_stop > 0) || (churn_ctx->num_failed_start > 0))
2769       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);
2770     churn_ctx->cb(churn_ctx->cb_cls, error_message);
2771     GNUNET_free_non_null(error_message);
2772     GNUNET_free(churn_ctx);
2773   }
2774
2775 }
2776
2777 /**
2778  * Simulate churn by stopping some peers (and possibly
2779  * re-starting others if churn is called multiple times).  This
2780  * function can only be used to create leave-join churn (peers "never"
2781  * leave for good).  First "voff" random peers that are currently
2782  * online will be taken offline; then "von" random peers that are then
2783  * offline will be put back online.  No notifications will be
2784  * generated for any of these operations except for the callback upon
2785  * completion.
2786  *
2787  * @param pg handle for the peer group
2788  * @param voff number of peers that should go offline
2789  * @param von number of peers that should come back online;
2790  *            must be zero on first call (since "testbed_start"
2791  *            always starts all of the peers)
2792  * @param timeout how long to wait for operations to finish before
2793  *        giving up
2794  * @param cb function to call at the end
2795  * @param cb_cls closure for cb
2796  */
2797 void
2798 GNUNET_TESTING_daemons_churn (struct GNUNET_TESTING_PeerGroup *pg,
2799                               unsigned int voff,
2800                               unsigned int von,
2801                               struct GNUNET_TIME_Relative timeout,
2802                               GNUNET_TESTING_NotifyCompletion cb,
2803                               void *cb_cls)
2804 {
2805   struct ChurnContext *churn_ctx;
2806   unsigned int running;
2807   unsigned int stopped;
2808   unsigned int i;
2809   unsigned int *running_arr;
2810   unsigned int *stopped_arr;
2811   unsigned int *running_permute;
2812   unsigned int *stopped_permute;
2813
2814   running = 0;
2815   stopped = 0;
2816
2817   if ((von == 0) && (voff == 0)) /* No peers at all? */
2818     {
2819       cb(cb_cls, NULL);
2820       return;
2821     }
2822
2823   for (i = 0; i < pg->total; i++)
2824   {
2825     if (pg->peers[i].daemon->running == GNUNET_YES)
2826     {
2827       running++;
2828     }
2829     else
2830     {
2831       stopped++;
2832     }
2833   }
2834
2835   if (voff > running)
2836   {
2837     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to stop more peers than are currently running!\n");
2838     cb(cb_cls, "Trying to stop more peers than are currently running!");
2839     return;
2840   }
2841
2842   if (von > stopped)
2843   {
2844     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Trying to start more peers than are currently stopped!\n");
2845     cb(cb_cls, "Trying to start more peers than are currently stopped!");
2846     return;
2847   }
2848
2849   churn_ctx = GNUNET_malloc(sizeof(struct ChurnContext));
2850   running_arr = GNUNET_malloc(running * sizeof(unsigned int));
2851   stopped_arr = GNUNET_malloc(stopped * sizeof(unsigned int));
2852
2853   running_permute = NULL;
2854   stopped_permute = NULL;
2855
2856   if (running > 0)
2857     running_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, running);
2858   if (stopped > 0)
2859     stopped_permute = GNUNET_CRYPTO_random_permute(GNUNET_CRYPTO_QUALITY_WEAK, stopped);
2860
2861   running = 0;
2862   stopped = 0;
2863
2864   churn_ctx->num_to_start = von;
2865   churn_ctx->num_to_stop = voff;
2866   churn_ctx->cb = cb;
2867   churn_ctx->cb_cls = cb_cls;  
2868
2869   for (i = 0; i < pg->total; i++)
2870   {
2871     if (pg->peers[i].daemon->running == GNUNET_YES)
2872     {
2873       running_arr[running] = i;
2874       running++;
2875     }
2876     else
2877     {
2878       stopped_arr[stopped] = i;
2879       stopped++;
2880     }
2881   }
2882
2883   for (i = 0; i < voff; i++)
2884   {
2885 #if DEBUG_CHURN
2886     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Stopping peer %d!\n", running_permute[i]);
2887 #endif
2888     GNUNET_TESTING_daemon_stop(pg->peers[running_arr[running_permute[i]]].daemon, timeout, &churn_stop_callback, churn_ctx, GNUNET_NO, GNUNET_YES);
2889   }
2890
2891   for (i = 0; i < von; i++)
2892   {
2893 #if DEBUG_CHURN
2894     GNUNET_log(GNUNET_ERROR_TYPE_WARNING, "Starting up peer %d!\n", stopped_permute[i]);
2895 #endif
2896     GNUNET_TESTING_daemon_start_stopped(pg->peers[stopped_arr[stopped_permute[i]]].daemon, timeout, &churn_start_callback, churn_ctx);
2897   }
2898
2899   GNUNET_free(running_arr);
2900   GNUNET_free(stopped_arr);
2901   GNUNET_free_non_null(running_permute);
2902   GNUNET_free_non_null(stopped_permute);
2903 }
2904
2905
2906 /**
2907  * Restart all peers in the given group.
2908  *
2909  * @param pg the handle to the peer group
2910  * @param callback function to call on completion (or failure)
2911  * @param callback_cls closure for the callback function
2912  */
2913 void
2914 GNUNET_TESTING_daemons_restart (struct GNUNET_TESTING_PeerGroup *pg, GNUNET_TESTING_NotifyCompletion callback, void *callback_cls)
2915 {
2916   struct RestartContext *restart_context;
2917   unsigned int off;
2918
2919   if (pg->total > 0)
2920     {
2921       restart_context = GNUNET_malloc(sizeof(struct RestartContext));
2922       restart_context->peer_group = pg;
2923       restart_context->peers_restarted = 0;
2924       restart_context->callback = callback;
2925       restart_context->callback_cls = callback_cls;
2926
2927       for (off = 0; off < pg->total; off++)
2928         {
2929           GNUNET_TESTING_daemon_restart (pg->peers[off].daemon, &restart_callback, restart_context);
2930         }
2931     }
2932 }
2933
2934 /**
2935  * Shutdown all peers started in the given group.
2936  *
2937  * @param pg handle to the peer group
2938  * @param timeout how long to wait for shutdown
2939  *
2940  */
2941 void
2942 GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg, struct GNUNET_TIME_Relative timeout)
2943 {
2944   unsigned int off;
2945
2946   for (off = 0; off < pg->total; off++)
2947     {
2948       /* FIXME: should we wait for our
2949          continuations to be called here? This
2950          would require us to take a continuation
2951          as well... */
2952
2953       if (NULL != pg->peers[off].daemon)
2954         GNUNET_TESTING_daemon_stop (pg->peers[off].daemon, timeout, NULL, NULL, GNUNET_YES, GNUNET_NO);
2955       if (NULL != pg->peers[off].cfg)
2956         GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
2957
2958       if (pg->peers[off].allowed_peers != NULL)
2959         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].allowed_peers);
2960       if (pg->peers[off].connect_peers != NULL)
2961         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].connect_peers);
2962       if (pg->peers[off].blacklisted_peers != NULL)
2963         GNUNET_CONTAINER_multihashmap_destroy(pg->peers[off].blacklisted_peers);
2964
2965     }
2966   GNUNET_free (pg->peers);
2967   if (NULL != pg->hosts)
2968     {
2969       GNUNET_free (pg->hosts[0].hostname);
2970       GNUNET_free (pg->hosts);
2971     }
2972   GNUNET_free (pg);
2973 }
2974
2975
2976 /* end of testing_group.c */