aboutsummaryrefslogtreecommitdiff
path: root/src/testing/testing_group.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testing/testing_group.c')
-rw-r--r--src/testing/testing_group.c315
1 files changed, 260 insertions, 55 deletions
diff --git a/src/testing/testing_group.c b/src/testing/testing_group.c
index 917a524de..b87507364 100644
--- a/src/testing/testing_group.c
+++ b/src/testing/testing_group.c
@@ -27,6 +27,58 @@
27#include "gnunet_arm_service.h" 27#include "gnunet_arm_service.h"
28#include "gnunet_testing_lib.h" 28#include "gnunet_testing_lib.h"
29 29
30/**
31 * Lowest port used for GNUnet testing. Should be high enough to not
32 * conflict with other applications running on the hosts but be low
33 * enough to not conflict with client-ports (typically starting around
34 * 32k).
35 */
36#define LOW_PORT 10000
37
38/**
39 * Highest port used for GNUnet testing. Should be low enough to not
40 * conflict with the port range for "local" ports (client apps; see
41 * /proc/sys/net/ipv4/ip_local_port_range on Linux for example).
42 */
43#define HIGH_PORT 32000
44
45/**
46 * Data we keep per peer.
47 */
48struct PeerData
49{
50 /**
51 * (Initial) configuration of the host.
52 * (initial because clients could change
53 * it and we would not know about those
54 * updates).
55 */
56 struct GNUNET_CONFIGURATION_Handle *cfg;
57
58 /**
59 * Handle for controlling the daemon.
60 */
61 struct GNUNET_TESTING_Daemon *daemon;
62};
63
64
65/**
66 * Data we keep per host.
67 */
68struct HostData
69{
70 /**
71 * Name of the host.
72 */
73 char *hostname;
74
75 /**
76 * Lowest port that we have not yet used
77 * for GNUnet.
78 */
79 uint16_t minport;
80};
81
30 82
31/** 83/**
32 * Handle to a group of GNUnet peers. 84 * Handle to a group of GNUnet peers.
@@ -41,7 +93,7 @@ struct GNUNET_TESTING_PeerGroup
41 /** 93 /**
42 * Configuration template. 94 * Configuration template.
43 */ 95 */
44 struct GNUNET_CONFIGURATION_Handle *cfg; 96 const struct GNUNET_CONFIGURATION_Handle *cfg;
45 97
46 /** 98 /**
47 * Function to call on each started daemon. 99 * Function to call on each started daemon.
@@ -54,14 +106,15 @@ struct GNUNET_TESTING_PeerGroup
54 void *cb_cls; 106 void *cb_cls;
55 107
56 /** 108 /**
57 * NULL-terminated array of hostnames. 109 * NULL-terminated array of information about
110 * hosts.
58 */ 111 */
59 char **hostnames; 112 struct HostData *hosts;
60 113
61 /** 114 /**
62 * Array of "total" peers. 115 * Array of "total" peers.
63 */ 116 */
64 struct GNUNET_TESTING_Daemon **peers; 117 struct PeerData *peers;
65 118
66 /** 119 /**
67 * Number of peers in this group. 120 * Number of peers in this group.
@@ -71,79 +124,212 @@ struct GNUNET_TESTING_PeerGroup
71}; 124};
72 125
73 126
127struct UpdateContext
128{
129 struct GNUNET_CONFIGURATION_Handle *ret;
130 unsigned int nport;
131};
132
74/** 133/**
75 * Start count gnunetd processes with the same set of transports and 134 * Function to iterate over options. Copies
76 * applications. The port numbers (any option called "PORT") will be 135 * the options to the target configuration,
77 * adjusted to ensure that no two peers running on the same system 136 * updating PORT values as needed.
78 * have the same port(s) in their respective configurations.
79 * 137 *
80 * @param sched scheduler to use 138 * @param cls closure
81 * @param cfg configuration template to use 139 * @param section name of the section
82 * @param total number of daemons to start 140 * @param option name of the option
83 * @param cb function to call on each daemon that was started 141 * @param value value of the option
84 * @param cb_cls closure for cb
85 * @param hostname where to run the peers; can be NULL (to run
86 * everything on localhost).
87 * @param va Additional hosts can be specified using a NULL-terminated list of
88 * varargs, hosts will then be used round-robin from that
89 * list; va only contains anything if hostname != NULL.
90 * @return NULL on error, otherwise handle to control peer group
91 */ 142 */
92struct GNUNET_TESTING_PeerGroup * 143static void
93GNUNET_TESTING_daemons_start_va (struct GNUNET_SCHEDULER_Handle *sched, 144update_config(void *cls,
94 const struct GNUNET_CONFIGURATION_Handle *cfg, 145 const char *section,
95 unsigned int total, 146 const char *option,
96 GNUNET_TESTING_NotifyDaemonRunning cb, 147 const char *value)
97 void *cb_cls,
98 const char *hostname,
99 va_list va)
100{ 148{
101 struct GNUNET_TESTING_PeerGroup *pg; 149 struct UpdateContext *ctx = cls;
102 150 unsigned int ival;
103 pg = GNUNET_malloc (sizeof(struct GNUNET_TESTING_PeerGroup)); 151 char cval[12];
104 return pg; 152
153 if ( (0 == strcmp (option, "PORT")) &&
154 (1 == sscanf (value, "%u", &ival)) )
155 {
156 GNUNET_snprintf (cval,
157 sizeof(cval),
158 "%u",
159 ctx->nport++);
160 value = cval;
161 }
162 GNUNET_CONFIGURATION_set_value_string (ctx->ret,
163 section,
164 option,
165 value);
105} 166}
106 167
107 168
108/** 169/**
109 * Start count gnunetd processes with the same set of 170 * Create a new configuration using the given configuration
110 * transports and applications. The port numbers will 171 * as a template; however, each PORT in the existing cfg
111 * be computed by adding delta each time (zero 172 * must be renumbered by incrementing "*port". If we run
112 * times for the first peer). 173 * out of "*port" numbers, return NULL.
174 *
175 * @param cfg template configuration
176 * @param port port numbers to use, update to reflect
177 * port numbers that were used
178 * @return new configuration, NULL on error
179 */
180static struct GNUNET_CONFIGURATION_Handle*
181make_config (const struct GNUNET_CONFIGURATION_Handle*cfg,
182 uint16_t *port)
183{
184 struct UpdateContext uc;
185 uint16_t orig;
186
187 orig = *port;
188 uc.nport = *port;
189 uc.ret = GNUNET_CONFIGURATION_create ();
190 GNUNET_CONFIGURATION_iterate (cfg,
191 &update_config,
192 &uc);
193 if (uc.nport >= HIGH_PORT)
194 {
195 *port = orig;
196 GNUNET_CONFIGURATION_destroy (uc.ret);
197 return NULL;
198 }
199 *port = (uint16_t) uc.nport;
200 return uc.ret;
201}
202
203
204/**
205 * Start count gnunetd processes with the same set of transports and
206 * applications. The port numbers (any option called "PORT") will be
207 * adjusted to ensure that no two peers running on the same system
208 * have the same port(s) in their respective configurations.
113 * 209 *
114 * @param sched scheduler to use 210 * @param sched scheduler to use
115 * @param cfg configuration template to use 211 * @param cfg configuration template to use
116 * @param total number of daemons to start 212 * @param total number of daemons to start
117 * @param timeout how long is this allowed to take?
118 * @param cb function to call on each daemon that was started 213 * @param cb function to call on each daemon that was started
119 * @param cb_cls closure for cb 214 * @param cb_cls closure for cb
120 * @param hostname where to run the peers; can be NULL (to run 215 * @param hostnames space-separated list of hostnames to use; can be NULL (to run
121 * everything on localhost). Additional 216 * everything on localhost).
122 * hosts can be specified using a NULL-terminated list of
123 * varargs, hosts will then be used round-robin from that
124 * list.
125 * @return NULL on error, otherwise handle to control peer group 217 * @return NULL on error, otherwise handle to control peer group
126 */ 218 */
127struct GNUNET_TESTING_PeerGroup * 219struct GNUNET_TESTING_PeerGroup *
128GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched, 220GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
129 struct GNUNET_CONFIGURATION_Handle *cfg, 221 const struct GNUNET_CONFIGURATION_Handle *cfg,
130 unsigned int total, 222 unsigned int total,
131 GNUNET_TESTING_NotifyDaemonRunning cb, 223 GNUNET_TESTING_NotifyDaemonRunning cb,
132 void *cb_cls, 224 void *cb_cls,
133 const char *hostname, 225 const char *hostnames)
134 ...)
135{ 226{
136 struct GNUNET_TESTING_PeerGroup * ret; 227 struct GNUNET_TESTING_PeerGroup *pg;
137 va_list va; 228 const char *rpos;
138 229 char *pos;
139 va_start (va, hostname); 230 char *start;
140 ret = GNUNET_TESTING_daemons_start_va (sched, cfg, 231 const char *hostname;
141 total, cb, cb_cls, hostname, 232 struct GNUNET_CONFIGURATION_Handle *pcfg;
142 va); 233 unsigned int off;
143 va_end (va); 234 unsigned int hostcnt;
144 return ret; 235 uint16_t minport;
145}
146 236
237 if (0 == total)
238 {
239 GNUNET_break (0);
240 return NULL;
241 }
242 pg = GNUNET_malloc (sizeof(struct GNUNET_TESTING_PeerGroup));
243 pg->sched = sched;
244 pg->cfg = cfg;
245 pg->cb = cb;
246 pg->cb_cls = cb_cls;
247 pg->total = total;
248 pg->peers = GNUNET_malloc (total * sizeof(struct PeerData));
249 if (NULL != hostnames)
250 {
251 off = 2;
252 /* skip leading spaces */
253 while ( (0 != *hostnames) &&
254 (isspace(*hostnames)))
255 hostnames++;
256 rpos = hostnames;
257 while ('\0' != *rpos)
258 {
259 if (isspace (*rpos))
260 off++;
261 rpos++;
262 }
263 pg->hosts = GNUNET_malloc (off * sizeof (struct HostData));
264 off = 0;
265 start = GNUNET_strdup (hostnames);
266 pos = start;
267 while ('\0' != *pos)
268 {
269 if (isspace (*pos))
270 {
271 *pos = '\0';
272 if (strlen(start) > 0)
273 {
274 pg->hosts[off].minport = LOW_PORT;
275 pg->hosts[off++].hostname = start;
276 }
277 start = pos+1;
278 }
279 pos++;
280 }
281 if (strlen(start) > 0)
282 {
283 pg->hosts[off].minport = LOW_PORT;
284 pg->hosts[off++].hostname = start;
285 }
286 if (off == 0)
287 {
288 GNUNET_free (start);
289 GNUNET_free (pg->hosts);
290 pg->hosts = NULL;
291 }
292 hostcnt = off;
293 minport = 0; /* make gcc happy */
294 }
295 else
296 {
297 hostcnt = 0;
298 minport = LOW_PORT;
299 }
300 for (off = 0; off < total; off++)
301 {
302 if (hostcnt > 0)
303 {
304 hostname = pg->hosts[off % hostcnt].hostname;
305 pcfg = make_config (cfg, &pg->hosts[off % hostcnt].minport);
306 }
307 else
308 {
309 hostname = NULL;
310 pcfg = make_config (cfg, &minport);
311 }
312 if (NULL == pcfg)
313 {
314 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
315 _("Could not create configuration for peer number %u on `%s'!\n"),
316 off,
317 hostname == NULL ? "localhost" : hostname);
318 continue;
319 }
320 pg->peers[off].cfg = pcfg;
321 pg->peers[off].daemon = GNUNET_TESTING_daemon_start (sched,
322 pcfg,
323 hostname,
324 cb,
325 cb_cls);
326 if (NULL == pg->peers[off].daemon)
327 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
328 _("Could not start peer number %u!\n"),
329 off);
330 }
331 return pg;
332}
147 333
148 334
149/** 335/**
@@ -154,7 +340,26 @@ GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched,
154void 340void
155GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg) 341GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg)
156{ 342{
157 343 unsigned int off;
344
345 for (off = 0; off < pg->total; off++)
346 {
347 /* FIXME: should we wait for our
348 continuations to be called here? This
349 would require us to take a continuation
350 as well... */
351 if (NULL != pg->peers[off].daemon)
352 GNUNET_TESTING_daemon_stop (pg->peers[off].daemon,
353 NULL, NULL);
354 if (NULL != pg->peers[off].cfg)
355 GNUNET_CONFIGURATION_destroy (pg->peers[off].cfg);
356 }
357 GNUNET_free (pg->peers);
358 if (NULL != pg->hosts)
359 {
360 GNUNET_free (pg->hosts[0].hostname);
361 GNUNET_free (pg->hosts);
362 }
158 GNUNET_free (pg); 363 GNUNET_free (pg);
159} 364}
160 365