peer linking
[oweals/gnunet.git] / src / testbed / testbed_api_topology.c
1 /*
2       This file is part of GNUnet
3       (C) 2008--2012 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 3, 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 testbed/testbed_api_topology.c
23  * @brief topology-generation functions
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_testbed_service.h"
28 #include "testbed_api.h"
29 #include "testbed_api_peers.h"
30 #include "testbed_api_operations.h"
31
32
33 /**
34  * Representation of an overlay link
35  */
36 struct OverlayLink
37 {
38   /**
39    * position of peer A's handle in peers array
40    */
41   uint32_t A;
42
43   /**
44    * position of peer B's handle in peers array
45    */
46   uint32_t B;
47
48 };
49
50
51 /**
52  * Context information for topology operations
53  */
54 struct TopologyContext
55 {
56   /**
57    * The array of peers
58    */
59   struct GNUNET_TESTBED_Peer **peers;
60
61   /**
62    * An array of links; this array is of size link_array_size
63    */
64   struct OverlayLink *link_array;
65
66   /**
67    * An array of operations resulting from the links we try to establish; the
68    * number of operations in this array is equal to link_array_size (1 link = 1
69    * operation)
70    */
71   struct GNUNET_TESTBED_Operation **link_ops;
72
73   /**
74    * The operation closure
75    */
76   void *op_cls;
77
78   /**
79    * The size of the link array
80    */
81   unsigned int link_array_size;  
82   
83 };
84
85
86 /**
87  * Callback to be called when an overlay_link operation complete
88  *
89  * @param cls element of the link_op array which points to the corresponding operation
90  * @param op the operation that has been finished
91  * @param emsg error message in case the operation has failed; will be NULL if
92  *          operation has executed successfully.
93  */
94 static void 
95 overlay_link_completed (void *cls,
96                         struct GNUNET_TESTBED_Operation *op, 
97                         const char *emsg)
98 {
99   struct GNUNET_TESTBED_Operation **link_op = cls;
100
101   GNUNET_assert (*link_op == op);
102   GNUNET_TESTBED_operation_done (op);
103   *link_op = NULL;
104   if (NULL != emsg)
105   {
106     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
107                 "Error while establishing a link: %s\n", emsg);
108     return;
109   }
110 }
111
112
113
114 /**
115  * Function called when a overlay connect operation is ready
116  *
117  * @param cls the Topology context
118  */
119 static void
120 opstart_overlay_configure_topology (void *cls)
121 {
122   struct TopologyContext *tc = cls;
123   unsigned int p;
124   
125   tc->link_ops = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Operations *)
126                                 * tc->link_array_size);
127   for (p = 0; p < tc->link_array_size; p++)
128   {
129     tc->link_ops[p] =
130         GNUNET_TESTBED_overlay_connect (tc->op_cls, &overlay_link_completed,
131                                         &tc->link_ops[p],
132                                         tc->peers[tc->link_array[p].A],
133                                         tc->peers[tc->link_array[p].B]);                                                  
134   }
135 }
136
137
138 /**
139  * Callback which will be called when overlay connect operation is released
140  *
141  * @param cls the Topology context
142  */
143 static void
144 oprelease_overlay_configure_topology (void *cls)
145 {
146   struct TopologyContext *tc = cls;
147   unsigned int p;
148   
149   if (NULL != tc->link_ops)
150   {
151     for (p = 0; p < tc->link_array_size; p++)
152       if (NULL != tc->link_ops[p])
153         GNUNET_TESTBED_operation_cancel (tc->link_ops[p]);      
154     GNUNET_free (tc->link_ops);    
155   }
156   GNUNET_free_non_null (tc->link_array);
157   GNUNET_free (tc);
158 }
159
160
161 /**
162  * Configure overall network topology to have a particular shape.
163  *
164  * @param op_cls closure argument to give with the operation event
165  * @param num_peers number of peers in 'peers'
166  * @param peers array of 'num_peers' with the peers to configure
167  * @param topo desired underlay topology to use
168  * @param ap topology-specific options
169  * @return handle to the operation, NULL if configuring the topology
170  *         is not allowed at this time
171  */
172 struct GNUNET_TESTBED_Operation *
173 GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls,
174                                                unsigned int num_peers,
175                                                struct GNUNET_TESTBED_Peer
176                                                **peers,
177                                                enum
178                                                GNUNET_TESTBED_TopologyOption
179                                                topo, va_list ap)
180 {
181   GNUNET_break (0);
182   return NULL;
183 }
184
185
186 /**
187  * Configure overall network topology to have a particular shape.
188  *
189  * @param op_cls closure argument to give with the operation event
190  * @param num_peers number of peers in 'peers'
191  * @param peers array of 'num_peers' with the peers to configure
192  * @param topo desired underlay topology to use
193  * @param ... topology-specific options
194  * @return handle to the operation, NULL if configuring the topology
195  *         is not allowed at this time
196  */
197 struct GNUNET_TESTBED_Operation *
198 GNUNET_TESTBED_underlay_configure_topology (void *op_cls,
199                                             unsigned int num_peers,
200                                             struct GNUNET_TESTBED_Peer **peers,
201                                             enum GNUNET_TESTBED_TopologyOption
202                                             topo, ...)
203 {
204   GNUNET_break (0);
205   return NULL;
206 }
207
208
209 /**
210  * All peers must have been started before calling this function.
211  * This function then connects the given peers in the P2P overlay
212  * using the given topology.
213  *
214  * @param op_cls closure argument to give with the operation event
215  * @param num_peers number of peers in 'peers'
216  * @param peers array of 'num_peers' with the peers to configure
217  * @param topo desired underlay topology to use
218  * @param va topology-specific options
219  * @return handle to the operation, NULL if connecting these
220  *         peers is fundamentally not possible at this time (peers
221  *         not running or underlay disallows) or if num_peers is less than 2
222  */
223 struct GNUNET_TESTBED_Operation *
224 GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls,
225                                               unsigned int num_peers,
226                                               struct GNUNET_TESTBED_Peer **peers,
227                                               enum GNUNET_TESTBED_TopologyOption
228                                               topo, va_list va)
229 {
230   struct TopologyContext *tc;
231   struct GNUNET_TESTBED_Operation *op;
232   struct GNUNET_TESTBED_Controller *c;
233   unsigned int cnt;
234
235   if (num_peers < 2)
236     return NULL;
237   c = peers[0]->controller;
238   tc = GNUNET_malloc (sizeof (struct TopologyContext));
239   tc->peers = peers;
240   tc->op_cls = tc->op_cls;
241   switch (topo)
242   {
243   case GNUNET_TESTBED_TOPOLOGY_LINE:
244     tc->link_array_size = num_peers - 1;
245     tc->link_array = GNUNET_malloc (sizeof (struct OverlayLink) *
246                                     tc->link_array_size);
247     for (cnt=1; cnt < num_peers; cnt++)
248     {
249       tc->link_array[cnt-1].A = cnt-1;
250       tc->link_array[cnt-1].B = cnt;
251     }
252     break;
253   case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
254     tc->link_array_size = va_arg (va, unsigned int);
255     tc->link_array = GNUNET_malloc (sizeof (struct OverlayLink) *
256                                     tc->link_array_size);
257     for (cnt = 0; cnt < tc->link_array_size; cnt++)
258     {
259       uint32_t A_rand;
260       uint32_t B_rand;
261       
262       do {
263         A_rand = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
264                                            num_peers);
265         B_rand = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
266                                            num_peers);
267       } while (A_rand == B_rand);      
268       tc->link_array[cnt].A = A_rand;
269       tc->link_array[cnt].B = B_rand;
270     }
271     break;
272   default:
273     GNUNET_break (0);
274     return NULL;
275   }
276   op = GNUNET_TESTBED_operation_create_ (tc,
277                                          &opstart_overlay_configure_topology,
278                                          &oprelease_overlay_configure_topology);
279   GNUNET_TESTBED_operation_queue_insert_
280       (c->opq_parallel_topology_config_operations, op);
281   return op;
282 }
283
284
285 /**
286  * All peers must have been started before calling this function.
287  * This function then connects the given peers in the P2P overlay
288  * using the given topology.
289  *
290  * @param op_cls closure argument to give with the operation event
291  * @param num_peers number of peers in 'peers'
292  * @param peers array of 'num_peers' with the peers to configure
293  * @param topo desired underlay topology to use
294  * @param ... topology-specific options
295  * @return handle to the operation, NULL if connecting these
296  *         peers is fundamentally not possible at this time (peers
297  *         not running or underlay disallows) or if num_peers is less than 2
298  */
299 struct GNUNET_TESTBED_Operation *
300 GNUNET_TESTBED_overlay_configure_topology (void *op_cls, unsigned int num_peers,
301                                            struct GNUNET_TESTBED_Peer **peers,
302                                            enum GNUNET_TESTBED_TopologyOption
303                                            topo, ...)
304 {
305   struct GNUNET_TESTBED_Operation *op;
306   va_list vargs;
307
308   va_start (vargs, topo);
309   op = GNUNET_TESTBED_overlay_configure_topology_va (op_cls, num_peers, peers,
310                                                      topo, vargs);
311   va_end (vargs);
312   return op;
313 }
314
315 /* end of testbed_api_topology.c */