fixes
[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    * should the automatic retry be disabled
101    */
102   int disable_retry;
103   
104 };
105
106
107 /**
108  * Callback to be called when an overlay_link operation complete
109  *
110  * @param cls element of the link_op array which points to the corresponding operation
111  * @param op the operation that has been finished
112  * @param emsg error message in case the operation has failed; will be NULL if
113  *          operation has executed successfully.
114  */
115 static void 
116 overlay_link_completed (void *cls,
117                         struct GNUNET_TESTBED_Operation *op, 
118                         const char *emsg)
119 {
120   struct OverlayLink *link = cls;
121   struct TopologyContext *tc;
122
123   GNUNET_assert (op == link->op);
124   GNUNET_TESTBED_operation_done (op);
125   link->op = NULL;
126   tc = link->tc;
127   if ((NULL != emsg) && (GNUNET_NO == tc->disable_retry))
128   {
129     LOG (GNUNET_ERROR_TYPE_WARNING,
130          "Error while establishing a link: %s -- Retrying\n", emsg);
131     link->op =
132         GNUNET_TESTBED_overlay_connect (tc->op_cls,
133                                         &overlay_link_completed,
134                                         link,
135                                         tc->peers[link->A],
136                                         tc->peers[link->B]);
137     return;
138   }
139 }
140
141
142
143 /**
144  * Function called when a overlay connect operation is ready
145  *
146  * @param cls the Topology context
147  */
148 static void
149 opstart_overlay_configure_topology (void *cls)
150 {
151   struct TopologyContext *tc = cls;
152   unsigned int p;
153   
154   for (p = 0; p < tc->link_array_size; p++)
155   {
156     tc->link_array[p].op =
157         GNUNET_TESTBED_overlay_connect (tc->op_cls, &overlay_link_completed,
158                                         &tc->link_array[p],
159                                         tc->peers[tc->link_array[p].A],
160                                         tc->peers[tc->link_array[p].B]);                                                  
161   }
162 }
163
164
165 /**
166  * Callback which will be called when overlay connect operation is released
167  *
168  * @param cls the Topology context
169  */
170 static void
171 oprelease_overlay_configure_topology (void *cls)
172 {
173   struct TopologyContext *tc = cls;
174   unsigned int p;
175   
176   if (NULL != tc->link_array)
177   {
178     for (p = 0; p < tc->link_array_size; p++)
179       if (NULL != tc->link_array[p].op)
180         GNUNET_TESTBED_operation_cancel (tc->link_array[p].op);
181     GNUNET_free (tc->link_array);
182   }
183   GNUNET_free (tc);
184 }
185
186
187 /**
188  * Configure overall network topology to have a particular shape.
189  *
190  * @param op_cls closure argument to give with the operation event
191  * @param num_peers number of peers in 'peers'
192  * @param peers array of 'num_peers' with the peers to configure
193  * @param topo desired underlay topology to use
194  * @param ap topology-specific options
195  * @return handle to the operation, NULL if configuring the topology
196  *         is not allowed at this time
197  */
198 struct GNUNET_TESTBED_Operation *
199 GNUNET_TESTBED_underlay_configure_topology_va (void *op_cls,
200                                                unsigned int num_peers,
201                                                struct GNUNET_TESTBED_Peer
202                                                **peers,
203                                                enum
204                                                GNUNET_TESTBED_TopologyOption
205                                                topo, va_list ap)
206 {
207   GNUNET_break (0);
208   return NULL;
209 }
210
211
212 /**
213  * Configure overall network topology to have a particular shape.
214  *
215  * @param op_cls closure argument to give with the operation event
216  * @param num_peers number of peers in 'peers'
217  * @param peers array of 'num_peers' with the peers to configure
218  * @param topo desired underlay topology to use
219  * @param ... topology-specific options
220  * @return handle to the operation, NULL if configuring the topology
221  *         is not allowed at this time
222  */
223 struct GNUNET_TESTBED_Operation *
224 GNUNET_TESTBED_underlay_configure_topology (void *op_cls,
225                                             unsigned int num_peers,
226                                             struct GNUNET_TESTBED_Peer **peers,
227                                             enum GNUNET_TESTBED_TopologyOption
228                                             topo, ...)
229 {
230   GNUNET_break (0);
231   return NULL;
232 }
233
234
235 /**
236  * All peers must have been started before calling this function.
237  * This function then connects the given peers in the P2P overlay
238  * using the given topology.
239  *
240  * @param op_cls closure argument to give with the operation event
241  * @param num_peers number of peers in 'peers'
242  * @param peers array of 'num_peers' with the peers to configure
243  * @param topo desired underlay topology to use
244  * @param va topology-specific options
245  * @return handle to the operation, NULL if connecting these
246  *         peers is fundamentally not possible at this time (peers
247  *         not running or underlay disallows) or if num_peers is less than 2
248  */
249 struct GNUNET_TESTBED_Operation *
250 GNUNET_TESTBED_overlay_configure_topology_va (void *op_cls,
251                                               unsigned int num_peers,
252                                               struct GNUNET_TESTBED_Peer **peers,
253                                               enum GNUNET_TESTBED_TopologyOption
254                                               topo, va_list va)
255 {
256   struct TopologyContext *tc;
257   struct GNUNET_TESTBED_Operation *op;
258   struct GNUNET_TESTBED_Controller *c;
259   enum GNUNET_TESTBED_TopologyOption secondary_option;
260   unsigned int cnt;
261
262   if (num_peers < 2)
263     return NULL;
264   c = peers[0]->controller;
265   tc = GNUNET_malloc (sizeof (struct TopologyContext));
266   tc->peers = peers;
267   tc->op_cls = op_cls;
268   switch (topo)
269   {
270   case GNUNET_TESTBED_TOPOLOGY_LINE:
271     tc->link_array_size = num_peers - 1;
272     tc->link_array = GNUNET_malloc (sizeof (struct OverlayLink) *
273                                     tc->link_array_size);
274     for (cnt=1; cnt < num_peers; cnt++)
275     {
276       tc->link_array[cnt-1].A = cnt-1;
277       tc->link_array[cnt-1].B = cnt;
278       tc->link_array[cnt-1].tc = tc;
279     }
280     break;
281   case GNUNET_TESTBED_TOPOLOGY_ERDOS_RENYI:
282     tc->link_array_size = va_arg (va, unsigned int);
283     tc->link_array = GNUNET_malloc (sizeof (struct OverlayLink) *
284                                     tc->link_array_size);
285     for (cnt = 0; cnt < tc->link_array_size; cnt++)
286     {
287       uint32_t A_rand;
288       uint32_t B_rand;
289       
290       do {
291         A_rand = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
292                                            num_peers);
293         B_rand = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
294                                            num_peers);
295       } while (A_rand == B_rand);      
296       tc->link_array[cnt].A = A_rand;
297       tc->link_array[cnt].B = B_rand;
298       tc->link_array[cnt].tc = tc;
299     }
300     break;
301   case GNUNET_TESTBED_TOPOLOGY_CLIQUE:
302     tc->link_array_size = num_peers * (num_peers - 1);
303     tc->link_array = GNUNET_malloc (sizeof (struct OverlayLink) *
304                                     tc->link_array_size);
305     {
306       unsigned int offset;
307       
308       offset = 0;
309       for (cnt=0; cnt < num_peers; cnt++)
310       {
311         unsigned int neighbour;
312         
313         for (neighbour=0; neighbour < num_peers; neighbour++)
314         {
315           if (neighbour == cnt)
316             continue;
317           tc->link_array[offset].A = cnt;
318           tc->link_array[offset].B = neighbour;
319           tc->link_array[offset].tc = tc;
320           offset++;
321         }
322       }
323     }
324     break;
325   default:
326     GNUNET_break (0);
327     return NULL;
328   }
329   do
330   {
331     secondary_option = va_arg (va, enum GNUNET_TESTBED_TopologyOption);
332     switch (secondary_option)
333     {
334     case GNUNET_TESTBED_TOPOLOGY_DISABLE_AUTO_RETRY:
335       tc->disable_retry = GNUNET_YES;
336       break;
337     case GNUNET_TESTBED_TOPOLOGY_OPTION_END:
338       break;
339     default:
340       GNUNET_break (0);         /* Should not use any other option apart from
341                                    the ones handled here */
342       GNUNET_free_non_null (tc->link_array);
343       GNUNET_free (tc);
344       return NULL;
345     }
346   } while (GNUNET_TESTBED_TOPOLOGY_OPTION_END != secondary_option);
347   op = GNUNET_TESTBED_operation_create_ (tc,
348                                          &opstart_overlay_configure_topology,
349                                          &oprelease_overlay_configure_topology);
350   GNUNET_TESTBED_operation_queue_insert_
351       (c->opq_parallel_topology_config_operations, op);
352   return op;
353 }
354
355
356 /**
357  * All peers must have been started before calling this function.
358  * This function then connects the given peers in the P2P overlay
359  * using the given topology.
360  *
361  * @param op_cls closure argument to give with the operation event
362  * @param num_peers number of peers in 'peers'
363  * @param peers array of 'num_peers' with the peers to configure
364  * @param topo desired underlay topology to use
365  * @param ... topology-specific options
366  * @return handle to the operation, NULL if connecting these
367  *         peers is fundamentally not possible at this time (peers
368  *         not running or underlay disallows) or if num_peers is less than 2
369  */
370 struct GNUNET_TESTBED_Operation *
371 GNUNET_TESTBED_overlay_configure_topology (void *op_cls, unsigned int num_peers,
372                                            struct GNUNET_TESTBED_Peer **peers,
373                                            enum GNUNET_TESTBED_TopologyOption
374                                            topo, ...)
375 {
376   struct GNUNET_TESTBED_Operation *op;
377   va_list vargs;
378
379   GNUNET_assert (topo < GNUNET_TESTBED_TOPOLOGY_OPTION_END);
380   va_start (vargs, topo);
381   op = GNUNET_TESTBED_overlay_configure_topology_va (op_cls, num_peers, peers,
382                                                      topo, vargs);
383   va_end (vargs);
384   return op;
385 }
386
387 /* end of testbed_api_topology.c */