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