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