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