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