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