diff options
Diffstat (limited to 'src/testing/testing_group.c')
-rw-r--r-- | src/testing/testing_group.c | 315 |
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 | */ | ||
48 | struct 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 | */ | ||
68 | struct 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 | ||
127 | struct 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 | */ |
92 | struct GNUNET_TESTING_PeerGroup * | 143 | static void |
93 | GNUNET_TESTING_daemons_start_va (struct GNUNET_SCHEDULER_Handle *sched, | 144 | update_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 | */ | ||
180 | static struct GNUNET_CONFIGURATION_Handle* | ||
181 | make_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 | */ |
127 | struct GNUNET_TESTING_PeerGroup * | 219 | struct GNUNET_TESTING_PeerGroup * |
128 | GNUNET_TESTING_daemons_start (struct GNUNET_SCHEDULER_Handle *sched, | 220 | GNUNET_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, | |||
154 | void | 340 | void |
155 | GNUNET_TESTING_daemons_stop (struct GNUNET_TESTING_PeerGroup *pg) | 341 | GNUNET_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 | ||