diff options
Diffstat (limited to 'src/testbed/gnunet-service-testbed_peers.c')
-rw-r--r-- | src/testbed/gnunet-service-testbed_peers.c | 1138 |
1 files changed, 1138 insertions, 0 deletions
diff --git a/src/testbed/gnunet-service-testbed_peers.c b/src/testbed/gnunet-service-testbed_peers.c new file mode 100644 index 000000000..65cfe342c --- /dev/null +++ b/src/testbed/gnunet-service-testbed_peers.c | |||
@@ -0,0 +1,1138 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2008--2013 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 2, 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 | /** | ||
23 | * @file testbed/gnunet-service-testbed_peers.c | ||
24 | * @brief implementation of TESTBED service that deals with peer management | ||
25 | * @author Sree Harsha Totakura <sreeharsha@totakura.in> | ||
26 | */ | ||
27 | |||
28 | #include "gnunet-service-testbed.h" | ||
29 | #include "gnunet_arm_service.h" | ||
30 | #include <zlib.h> | ||
31 | |||
32 | |||
33 | /** | ||
34 | * A list of peers we know about | ||
35 | */ | ||
36 | struct Peer **GST_peer_list; | ||
37 | |||
38 | |||
39 | /** | ||
40 | * Context information to manage peers' services | ||
41 | */ | ||
42 | struct ManageServiceContext | ||
43 | { | ||
44 | /** | ||
45 | * DLL next ptr | ||
46 | */ | ||
47 | struct ManageServiceContext *next; | ||
48 | |||
49 | /** | ||
50 | * DLL prev ptr | ||
51 | */ | ||
52 | struct ManageServiceContext *prev; | ||
53 | |||
54 | /** | ||
55 | * The ARM handle of the peer | ||
56 | */ | ||
57 | struct GNUNET_ARM_Handle *ah; | ||
58 | |||
59 | /** | ||
60 | * peer whose service has to be managed | ||
61 | */ | ||
62 | struct Peer *peer; | ||
63 | |||
64 | /** | ||
65 | * The client which requested to manage the peer's service | ||
66 | */ | ||
67 | struct GNUNET_SERVER_Client *client; | ||
68 | |||
69 | /** | ||
70 | * The operation id of the associated request | ||
71 | */ | ||
72 | uint64_t op_id; | ||
73 | |||
74 | /** | ||
75 | * 1 if the service at the peer has to be started; 0 if it has to be stopped | ||
76 | */ | ||
77 | uint8_t start; | ||
78 | |||
79 | /** | ||
80 | * Is this context expired? Do not work on this context if it is set to | ||
81 | * GNUNET_YES | ||
82 | */ | ||
83 | uint8_t expired; | ||
84 | }; | ||
85 | |||
86 | |||
87 | /** | ||
88 | * DLL head for queue of manage service requests | ||
89 | */ | ||
90 | static struct ManageServiceContext *mctx_head; | ||
91 | |||
92 | /** | ||
93 | * DLL tail for queue of manage service requests | ||
94 | */ | ||
95 | static struct ManageServiceContext *mctx_tail; | ||
96 | |||
97 | |||
98 | /** | ||
99 | * Adds a peer to the peer array | ||
100 | * | ||
101 | * @param peer the peer to add | ||
102 | */ | ||
103 | static void | ||
104 | peer_list_add (struct Peer *peer) | ||
105 | { | ||
106 | if (peer->id >= GST_peer_list_size) | ||
107 | GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id); | ||
108 | GNUNET_assert (NULL == GST_peer_list[peer->id]); | ||
109 | GST_peer_list[peer->id] = peer; | ||
110 | } | ||
111 | |||
112 | |||
113 | /** | ||
114 | * Removes a the give peer from the peer array | ||
115 | * | ||
116 | * @param peer the peer to be removed | ||
117 | */ | ||
118 | static void | ||
119 | peer_list_remove (struct Peer *peer) | ||
120 | { | ||
121 | unsigned int orig_size; | ||
122 | uint32_t id; | ||
123 | |||
124 | GST_peer_list[peer->id] = NULL; | ||
125 | orig_size = GST_peer_list_size; | ||
126 | while (GST_peer_list_size >= LIST_GROW_STEP) | ||
127 | { | ||
128 | for (id = GST_peer_list_size - 1; | ||
129 | (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX); | ||
130 | id--) | ||
131 | if (NULL != GST_peer_list[id]) | ||
132 | break; | ||
133 | if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1)) | ||
134 | break; | ||
135 | GST_peer_list_size -= LIST_GROW_STEP; | ||
136 | } | ||
137 | if (orig_size == GST_peer_list_size) | ||
138 | return; | ||
139 | GST_peer_list = | ||
140 | GNUNET_realloc (GST_peer_list, | ||
141 | sizeof (struct Peer *) * GST_peer_list_size); | ||
142 | } | ||
143 | |||
144 | |||
145 | /** | ||
146 | * The task to be executed if the forwarded peer create operation has been | ||
147 | * timed out | ||
148 | * | ||
149 | * @param cls the FowardedOperationContext | ||
150 | * @param tc the TaskContext from the scheduler | ||
151 | */ | ||
152 | static void | ||
153 | peer_create_forward_timeout (void *cls, | ||
154 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
155 | { | ||
156 | struct ForwardedOperationContext *fopc = cls; | ||
157 | |||
158 | GNUNET_free (fopc->cls); | ||
159 | GST_forwarded_operation_timeout (fopc, tc); | ||
160 | } | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Callback to be called when forwarded peer create operation is successfull. We | ||
165 | * have to relay the reply msg back to the client | ||
166 | * | ||
167 | * @param cls ForwardedOperationContext | ||
168 | * @param msg the peer create success message | ||
169 | */ | ||
170 | static void | ||
171 | peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg) | ||
172 | { | ||
173 | struct ForwardedOperationContext *fopc = cls; | ||
174 | struct Peer *remote_peer; | ||
175 | |||
176 | if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS) | ||
177 | { | ||
178 | GNUNET_assert (NULL != fopc->cls); | ||
179 | remote_peer = fopc->cls; | ||
180 | peer_list_add (remote_peer); | ||
181 | } | ||
182 | GST_forwarded_operation_reply_relay (fopc, msg); | ||
183 | } | ||
184 | |||
185 | |||
186 | /** | ||
187 | * Function to destroy a peer | ||
188 | * | ||
189 | * @param peer the peer structure to destroy | ||
190 | */ | ||
191 | void | ||
192 | GST_destroy_peer (struct Peer *peer) | ||
193 | { | ||
194 | GNUNET_break (0 == peer->reference_cnt); | ||
195 | if (GNUNET_YES == peer->is_remote) | ||
196 | { | ||
197 | peer_list_remove (peer); | ||
198 | GNUNET_free (peer); | ||
199 | return; | ||
200 | } | ||
201 | if (GNUNET_YES == peer->details.local.is_running) | ||
202 | { | ||
203 | GNUNET_TESTING_peer_stop (peer->details.local.peer); | ||
204 | peer->details.local.is_running = GNUNET_NO; | ||
205 | } | ||
206 | GNUNET_TESTING_peer_destroy (peer->details.local.peer); | ||
207 | GNUNET_CONFIGURATION_destroy (peer->details.local.cfg); | ||
208 | peer_list_remove (peer); | ||
209 | GNUNET_free (peer); | ||
210 | } | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Callback to be called when forwarded peer destroy operation is successfull. We | ||
215 | * have to relay the reply msg back to the client | ||
216 | * | ||
217 | * @param cls ForwardedOperationContext | ||
218 | * @param msg the peer create success message | ||
219 | */ | ||
220 | static void | ||
221 | peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg) | ||
222 | { | ||
223 | struct ForwardedOperationContext *fopc = cls; | ||
224 | struct Peer *remote_peer; | ||
225 | |||
226 | if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS == | ||
227 | ntohs (msg->type)) | ||
228 | { | ||
229 | remote_peer = fopc->cls; | ||
230 | GNUNET_assert (NULL != remote_peer); | ||
231 | remote_peer->destroy_flag = GNUNET_YES; | ||
232 | if (0 == remote_peer->reference_cnt) | ||
233 | GST_destroy_peer (remote_peer); | ||
234 | } | ||
235 | GST_forwarded_operation_reply_relay (fopc, msg); | ||
236 | } | ||
237 | |||
238 | |||
239 | /** | ||
240 | * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages | ||
241 | * | ||
242 | * @param cls NULL | ||
243 | * @param client identification of the client | ||
244 | * @param message the actual message | ||
245 | */ | ||
246 | void | ||
247 | GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client, | ||
248 | const struct GNUNET_MessageHeader *message) | ||
249 | { | ||
250 | const struct GNUNET_TESTBED_PeerCreateMessage *msg; | ||
251 | struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply; | ||
252 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
253 | struct ForwardedOperationContext *fo_ctxt; | ||
254 | struct Route *route; | ||
255 | struct Peer *peer; | ||
256 | char *config; | ||
257 | size_t dest_size; | ||
258 | int ret; | ||
259 | uint32_t config_size; | ||
260 | uint32_t host_id; | ||
261 | uint32_t peer_id; | ||
262 | uint16_t msize; | ||
263 | |||
264 | |||
265 | msize = ntohs (message->size); | ||
266 | if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage)) | ||
267 | { | ||
268 | GNUNET_break (0); /* We need configuration */ | ||
269 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
270 | return; | ||
271 | } | ||
272 | msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message; | ||
273 | host_id = ntohl (msg->host_id); | ||
274 | peer_id = ntohl (msg->peer_id); | ||
275 | if (UINT32_MAX == peer_id) | ||
276 | { | ||
277 | GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id), | ||
278 | "Cannot create peer with given ID"); | ||
279 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
280 | return; | ||
281 | } | ||
282 | if (host_id == GST_context->host_id) | ||
283 | { | ||
284 | char *emsg; | ||
285 | |||
286 | /* We are responsible for this peer */ | ||
287 | msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage); | ||
288 | config_size = ntohl (msg->config_size); | ||
289 | config = GNUNET_malloc (config_size); | ||
290 | dest_size = config_size; | ||
291 | if (Z_OK != | ||
292 | (ret = | ||
293 | uncompress ((Bytef *) config, (uLongf *) & dest_size, | ||
294 | (const Bytef *) &msg[1], (uLong) msize))) | ||
295 | { | ||
296 | GNUNET_break (0); /* uncompression error */ | ||
297 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
298 | return; | ||
299 | } | ||
300 | if (config_size != dest_size) | ||
301 | { | ||
302 | GNUNET_break (0); /* Uncompressed config size mismatch */ | ||
303 | GNUNET_free (config); | ||
304 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
305 | return; | ||
306 | } | ||
307 | cfg = GNUNET_CONFIGURATION_create (); | ||
308 | if (GNUNET_OK != | ||
309 | GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO)) | ||
310 | { | ||
311 | GNUNET_break (0); /* Configuration parsing error */ | ||
312 | GNUNET_free (config); | ||
313 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
314 | return; | ||
315 | } | ||
316 | GNUNET_free (config); | ||
317 | GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID", | ||
318 | (unsigned long long) peer_id); | ||
319 | peer = GNUNET_malloc (sizeof (struct Peer)); | ||
320 | peer->is_remote = GNUNET_NO; | ||
321 | peer->details.local.cfg = cfg; | ||
322 | peer->id = peer_id; | ||
323 | LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id); | ||
324 | peer->details.local.peer = | ||
325 | GNUNET_TESTING_peer_configure (GST_context->system, | ||
326 | peer->details.local.cfg, peer->id, | ||
327 | NULL /* Peer id */ , | ||
328 | &emsg); | ||
329 | if (NULL == peer->details.local.peer) | ||
330 | { | ||
331 | LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg); | ||
332 | GNUNET_free (emsg); | ||
333 | GNUNET_free (peer); | ||
334 | GNUNET_break (0); | ||
335 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
336 | return; | ||
337 | } | ||
338 | peer->details.local.is_running = GNUNET_NO; | ||
339 | peer_list_add (peer); | ||
340 | reply = | ||
341 | GNUNET_malloc (sizeof | ||
342 | (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage)); | ||
343 | reply->header.size = | ||
344 | htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage)); | ||
345 | reply->header.type = | ||
346 | htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS); | ||
347 | reply->peer_id = msg->peer_id; | ||
348 | reply->operation_id = msg->operation_id; | ||
349 | GST_queue_message (client, &reply->header); | ||
350 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
351 | return; | ||
352 | } | ||
353 | |||
354 | /* Forward peer create request */ | ||
355 | route = GST_find_dest_route (host_id); | ||
356 | if (NULL == route) | ||
357 | { | ||
358 | GNUNET_break (0); | ||
359 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
360 | return; | ||
361 | } | ||
362 | |||
363 | peer = GNUNET_malloc (sizeof (struct Peer)); | ||
364 | peer->is_remote = GNUNET_YES; | ||
365 | peer->id = peer_id; | ||
366 | peer->details.remote.slave = GST_slave_list[route->dest]; | ||
367 | peer->details.remote.remote_host_id = host_id; | ||
368 | fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext)); | ||
369 | GNUNET_SERVER_client_keep (client); | ||
370 | fo_ctxt->client = client; | ||
371 | fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id); | ||
372 | fo_ctxt->cls = peer; //GST_slave_list[route->dest]->controller; | ||
373 | fo_ctxt->type = OP_PEER_CREATE; | ||
374 | fo_ctxt->opc = | ||
375 | GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list | ||
376 | [route->dest]->controller, | ||
377 | fo_ctxt->operation_id, | ||
378 | &msg->header, | ||
379 | peer_create_success_cb, fo_ctxt); | ||
380 | fo_ctxt->timeout_task = | ||
381 | GNUNET_SCHEDULER_add_delayed (GST_timeout, &peer_create_forward_timeout, | ||
382 | fo_ctxt); | ||
383 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt); | ||
384 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
385 | } | ||
386 | |||
387 | |||
388 | /** | ||
389 | * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages | ||
390 | * | ||
391 | * @param cls NULL | ||
392 | * @param client identification of the client | ||
393 | * @param message the actual message | ||
394 | */ | ||
395 | void | ||
396 | GST_handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client, | ||
397 | const struct GNUNET_MessageHeader *message) | ||
398 | { | ||
399 | const struct GNUNET_TESTBED_PeerDestroyMessage *msg; | ||
400 | struct ForwardedOperationContext *fopc; | ||
401 | struct Peer *peer; | ||
402 | uint32_t peer_id; | ||
403 | |||
404 | msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message; | ||
405 | peer_id = ntohl (msg->peer_id); | ||
406 | LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n", | ||
407 | peer_id, GNUNET_ntohll (msg->operation_id)); | ||
408 | if ((GST_peer_list_size <= peer_id) || (NULL == GST_peer_list[peer_id])) | ||
409 | { | ||
410 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
411 | "Asked to destroy a non existent peer with id: %u\n", peer_id); | ||
412 | GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id), | ||
413 | "Peer doesn't exist"); | ||
414 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
415 | return; | ||
416 | } | ||
417 | peer = GST_peer_list[peer_id]; | ||
418 | if (GNUNET_YES == peer->is_remote) | ||
419 | { | ||
420 | /* Forward the destory message to sub controller */ | ||
421 | fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext)); | ||
422 | GNUNET_SERVER_client_keep (client); | ||
423 | fopc->client = client; | ||
424 | fopc->cls = peer; | ||
425 | fopc->type = OP_PEER_DESTROY; | ||
426 | fopc->operation_id = GNUNET_ntohll (msg->operation_id); | ||
427 | fopc->opc = | ||
428 | GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote. | ||
429 | slave->controller, | ||
430 | fopc->operation_id, &msg->header, | ||
431 | &peer_destroy_success_cb, fopc); | ||
432 | fopc->timeout_task = | ||
433 | GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout, | ||
434 | fopc); | ||
435 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc); | ||
436 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
437 | return; | ||
438 | } | ||
439 | peer->destroy_flag = GNUNET_YES; | ||
440 | if (0 == peer->reference_cnt) | ||
441 | GST_destroy_peer (peer); | ||
442 | else | ||
443 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
444 | "Delaying peer destroy as peer is currently in use\n"); | ||
445 | GST_send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id)); | ||
446 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
447 | } | ||
448 | |||
449 | |||
450 | /** | ||
451 | * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages | ||
452 | * | ||
453 | * @param cls NULL | ||
454 | * @param client identification of the client | ||
455 | * @param message the actual message | ||
456 | */ | ||
457 | void | ||
458 | GST_handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client, | ||
459 | const struct GNUNET_MessageHeader *message) | ||
460 | { | ||
461 | const struct GNUNET_TESTBED_PeerStartMessage *msg; | ||
462 | struct GNUNET_TESTBED_PeerEventMessage *reply; | ||
463 | struct ForwardedOperationContext *fopc; | ||
464 | struct Peer *peer; | ||
465 | uint32_t peer_id; | ||
466 | |||
467 | msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message; | ||
468 | peer_id = ntohl (msg->peer_id); | ||
469 | if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id])) | ||
470 | { | ||
471 | GNUNET_break (0); | ||
472 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
473 | "Asked to start a non existent peer with id: %u\n", peer_id); | ||
474 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
475 | return; | ||
476 | } | ||
477 | peer = GST_peer_list[peer_id]; | ||
478 | if (GNUNET_YES == peer->is_remote) | ||
479 | { | ||
480 | fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext)); | ||
481 | GNUNET_SERVER_client_keep (client); | ||
482 | fopc->client = client; | ||
483 | fopc->operation_id = GNUNET_ntohll (msg->operation_id); | ||
484 | fopc->type = OP_PEER_START; | ||
485 | fopc->opc = | ||
486 | GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote. | ||
487 | slave->controller, | ||
488 | fopc->operation_id, &msg->header, | ||
489 | &GST_forwarded_operation_reply_relay, | ||
490 | fopc); | ||
491 | fopc->timeout_task = | ||
492 | GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout, | ||
493 | fopc); | ||
494 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc); | ||
495 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
496 | return; | ||
497 | } | ||
498 | if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer)) | ||
499 | { | ||
500 | GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id), | ||
501 | "Failed to start"); | ||
502 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
503 | return; | ||
504 | } | ||
505 | peer->details.local.is_running = GNUNET_YES; | ||
506 | reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage)); | ||
507 | reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT); | ||
508 | reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage)); | ||
509 | reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START); | ||
510 | reply->host_id = htonl (GST_context->host_id); | ||
511 | reply->peer_id = msg->peer_id; | ||
512 | reply->operation_id = msg->operation_id; | ||
513 | GST_queue_message (client, &reply->header); | ||
514 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
515 | } | ||
516 | |||
517 | |||
518 | /** | ||
519 | * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages | ||
520 | * | ||
521 | * @param cls NULL | ||
522 | * @param client identification of the client | ||
523 | * @param message the actual message | ||
524 | */ | ||
525 | void | ||
526 | GST_handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client, | ||
527 | const struct GNUNET_MessageHeader *message) | ||
528 | { | ||
529 | const struct GNUNET_TESTBED_PeerStopMessage *msg; | ||
530 | struct GNUNET_TESTBED_PeerEventMessage *reply; | ||
531 | struct ForwardedOperationContext *fopc; | ||
532 | struct Peer *peer; | ||
533 | uint32_t peer_id; | ||
534 | |||
535 | msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message; | ||
536 | peer_id = ntohl (msg->peer_id); | ||
537 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id); | ||
538 | if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id])) | ||
539 | { | ||
540 | GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id), | ||
541 | "Peer not found"); | ||
542 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
543 | return; | ||
544 | } | ||
545 | peer = GST_peer_list[peer_id]; | ||
546 | if (GNUNET_YES == peer->is_remote) | ||
547 | { | ||
548 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n", | ||
549 | peer_id); | ||
550 | fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext)); | ||
551 | GNUNET_SERVER_client_keep (client); | ||
552 | fopc->client = client; | ||
553 | fopc->operation_id = GNUNET_ntohll (msg->operation_id); | ||
554 | fopc->type = OP_PEER_STOP; | ||
555 | fopc->opc = | ||
556 | GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote. | ||
557 | slave->controller, | ||
558 | fopc->operation_id, &msg->header, | ||
559 | &GST_forwarded_operation_reply_relay, | ||
560 | fopc); | ||
561 | fopc->timeout_task = | ||
562 | GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout, | ||
563 | fopc); | ||
564 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc); | ||
565 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
566 | return; | ||
567 | } | ||
568 | if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer)) | ||
569 | { | ||
570 | LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id); | ||
571 | GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id), | ||
572 | "Peer not running"); | ||
573 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
574 | return; | ||
575 | } | ||
576 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id); | ||
577 | peer->details.local.is_running = GNUNET_NO; | ||
578 | reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage)); | ||
579 | reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT); | ||
580 | reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage)); | ||
581 | reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP); | ||
582 | reply->host_id = htonl (GST_context->host_id); | ||
583 | reply->peer_id = msg->peer_id; | ||
584 | reply->operation_id = msg->operation_id; | ||
585 | GST_queue_message (client, &reply->header); | ||
586 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
587 | GNUNET_TESTING_peer_wait (peer->details.local.peer); | ||
588 | } | ||
589 | |||
590 | |||
591 | /** | ||
592 | * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages | ||
593 | * | ||
594 | * @param cls NULL | ||
595 | * @param client identification of the client | ||
596 | * @param message the actual message | ||
597 | */ | ||
598 | void | ||
599 | GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client, | ||
600 | const struct GNUNET_MessageHeader *message) | ||
601 | { | ||
602 | const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg; | ||
603 | struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply; | ||
604 | struct Peer *peer; | ||
605 | char *config; | ||
606 | char *xconfig; | ||
607 | size_t c_size; | ||
608 | size_t xc_size; | ||
609 | uint32_t peer_id; | ||
610 | uint16_t msize; | ||
611 | |||
612 | msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message; | ||
613 | peer_id = ntohl (msg->peer_id); | ||
614 | if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id])) | ||
615 | { | ||
616 | GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id), | ||
617 | "Peer not found"); | ||
618 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
619 | return; | ||
620 | } | ||
621 | peer = GST_peer_list[peer_id]; | ||
622 | if (GNUNET_YES == peer->is_remote) | ||
623 | { | ||
624 | struct ForwardedOperationContext *fopc; | ||
625 | |||
626 | LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id); | ||
627 | fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext)); | ||
628 | GNUNET_SERVER_client_keep (client); | ||
629 | fopc->client = client; | ||
630 | fopc->operation_id = GNUNET_ntohll (msg->operation_id); | ||
631 | fopc->type = OP_PEER_INFO; | ||
632 | fopc->opc = | ||
633 | GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote. | ||
634 | slave->controller, | ||
635 | fopc->operation_id, &msg->header, | ||
636 | &GST_forwarded_operation_reply_relay, | ||
637 | fopc); | ||
638 | fopc->timeout_task = | ||
639 | GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout, | ||
640 | fopc); | ||
641 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc); | ||
642 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
643 | return; | ||
644 | } | ||
645 | LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id); | ||
646 | config = | ||
647 | GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg, | ||
648 | &c_size); | ||
649 | xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig); | ||
650 | GNUNET_free (config); | ||
651 | msize = | ||
652 | xc_size + | ||
653 | sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage); | ||
654 | reply = GNUNET_realloc (xconfig, msize); | ||
655 | (void) memmove (&reply[1], reply, xc_size); | ||
656 | reply->header.size = htons (msize); | ||
657 | reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION); | ||
658 | reply->peer_id = msg->peer_id; | ||
659 | reply->operation_id = msg->operation_id; | ||
660 | GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer, | ||
661 | &reply->peer_identity); | ||
662 | reply->config_size = htons ((uint16_t) c_size); | ||
663 | GST_queue_message (client, &reply->header); | ||
664 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
665 | } | ||
666 | |||
667 | |||
668 | /** | ||
669 | * Cleanup the context information created for managing a peer's service | ||
670 | * | ||
671 | * @param mctx the ManageServiceContext | ||
672 | */ | ||
673 | static void | ||
674 | cleanup_mctx (struct ManageServiceContext *mctx) | ||
675 | { | ||
676 | mctx->expired = GNUNET_YES; | ||
677 | GNUNET_CONTAINER_DLL_remove (mctx_head, mctx_tail, mctx); | ||
678 | GNUNET_SERVER_client_drop (mctx->client); | ||
679 | GNUNET_ARM_disconnect_and_free (mctx->ah); | ||
680 | GNUNET_assert (0 < mctx->peer->reference_cnt); | ||
681 | mctx->peer->reference_cnt--; | ||
682 | if ( (GNUNET_YES == mctx->peer->destroy_flag) | ||
683 | && (0 == mctx->peer->reference_cnt) ) | ||
684 | GST_destroy_peer (mctx->peer); | ||
685 | GNUNET_free (mctx); | ||
686 | } | ||
687 | |||
688 | |||
689 | /** | ||
690 | * Frees the ManageServiceContext queue | ||
691 | */ | ||
692 | void | ||
693 | GST_free_mctxq () | ||
694 | { | ||
695 | while (NULL != mctx_head) | ||
696 | cleanup_mctx (mctx_head); | ||
697 | } | ||
698 | |||
699 | |||
700 | /** | ||
701 | * Returns a string interpretation of 'rs' | ||
702 | * | ||
703 | * @param rs the request status from ARM | ||
704 | * @return a string interpretation of the request status | ||
705 | */ | ||
706 | static const char * | ||
707 | arm_req_string (enum GNUNET_ARM_RequestStatus rs) | ||
708 | { | ||
709 | switch (rs) | ||
710 | { | ||
711 | case GNUNET_ARM_REQUEST_SENT_OK: | ||
712 | return _("Message was sent successfully"); | ||
713 | case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR: | ||
714 | return _("Misconfiguration (can't connect to the ARM service)"); | ||
715 | case GNUNET_ARM_REQUEST_DISCONNECTED: | ||
716 | return _("We disconnected from ARM before we could send a request"); | ||
717 | case GNUNET_ARM_REQUEST_BUSY: | ||
718 | return _("ARM API is busy"); | ||
719 | case GNUNET_ARM_REQUEST_TOO_LONG: | ||
720 | return _("Request doesn't fit into a message"); | ||
721 | case GNUNET_ARM_REQUEST_TIMEOUT: | ||
722 | return _("Request timed out"); | ||
723 | } | ||
724 | return _("Unknown request status"); | ||
725 | } | ||
726 | |||
727 | |||
728 | /** | ||
729 | * Returns a string interpretation of the 'result' | ||
730 | * | ||
731 | * @param result the arm result | ||
732 | * @return a string interpretation | ||
733 | */ | ||
734 | static const char * | ||
735 | arm_ret_string (enum GNUNET_ARM_Result result) | ||
736 | { | ||
737 | switch (result) | ||
738 | { | ||
739 | case GNUNET_ARM_RESULT_STOPPED: | ||
740 | return _("%s is stopped"); | ||
741 | case GNUNET_ARM_RESULT_STARTING: | ||
742 | return _("%s is starting"); | ||
743 | case GNUNET_ARM_RESULT_STOPPING: | ||
744 | return _("%s is stopping"); | ||
745 | case GNUNET_ARM_RESULT_IS_STARTING_ALREADY: | ||
746 | return _("%s is starting already"); | ||
747 | case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY: | ||
748 | return _("%s is stopping already"); | ||
749 | case GNUNET_ARM_RESULT_IS_STARTED_ALREADY: | ||
750 | return _("%s is started already"); | ||
751 | case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY: | ||
752 | return _("%s is stopped already"); | ||
753 | case GNUNET_ARM_RESULT_IS_NOT_KNOWN: | ||
754 | return _("%s service is not known to ARM"); | ||
755 | case GNUNET_ARM_RESULT_START_FAILED: | ||
756 | return _("%s service failed to start"); | ||
757 | case GNUNET_ARM_RESULT_IN_SHUTDOWN: | ||
758 | return _("%s service can't be started because ARM is shutting down"); | ||
759 | } | ||
760 | return _("%.s Unknown result code."); | ||
761 | } | ||
762 | |||
763 | |||
764 | /** | ||
765 | * Function called in response to a start/stop request. | ||
766 | * Will be called when request was not sent successfully, | ||
767 | * or when a reply comes. If the request was not sent successfully, | ||
768 | * 'rs' will indicate that, and 'service' and 'result' will be undefined. | ||
769 | * | ||
770 | * @param cls ManageServiceContext | ||
771 | * @param arm handle to the arm connection | ||
772 | * @param rs status of the request | ||
773 | * @param service service name | ||
774 | * @param result result of the operation | ||
775 | */ | ||
776 | static void | ||
777 | service_manage_result_cb (void *cls, struct GNUNET_ARM_Handle *arm, | ||
778 | enum GNUNET_ARM_RequestStatus rs, | ||
779 | const char *service, enum GNUNET_ARM_Result result) | ||
780 | { | ||
781 | struct ManageServiceContext *mctx = cls; | ||
782 | char *emsg; | ||
783 | |||
784 | emsg = NULL; | ||
785 | if (GNUNET_YES == mctx->expired) | ||
786 | return; | ||
787 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) | ||
788 | { | ||
789 | GNUNET_asprintf (&emsg, "Error communicating with Peer %u's ARM: %s", | ||
790 | mctx->peer->id, arm_req_string (rs)); | ||
791 | goto ret; | ||
792 | } | ||
793 | if (1 == mctx->start) | ||
794 | goto service_start_check; | ||
795 | if (! ((GNUNET_ARM_RESULT_STOPPED == result) | ||
796 | || (GNUNET_ARM_RESULT_STOPPING == result) | ||
797 | || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result) | ||
798 | || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) ) | ||
799 | { | ||
800 | /* stopping a service failed */ | ||
801 | GNUNET_asprintf (&emsg, arm_ret_string (result), service); | ||
802 | goto ret; | ||
803 | } | ||
804 | /* service stopped successfully */ | ||
805 | goto ret; | ||
806 | |||
807 | service_start_check: | ||
808 | if (! ((GNUNET_ARM_RESULT_STARTING == result) | ||
809 | || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result) | ||
810 | || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) ) | ||
811 | { | ||
812 | /* starting a service failed */ | ||
813 | GNUNET_asprintf (&emsg, arm_ret_string (result), service); | ||
814 | goto ret; | ||
815 | } | ||
816 | /* service started successfully */ | ||
817 | |||
818 | ret: | ||
819 | if (NULL != emsg) | ||
820 | { | ||
821 | LOG_DEBUG ("%s\n", emsg); | ||
822 | GST_send_operation_fail_msg (mctx->client, mctx->op_id, emsg); | ||
823 | } | ||
824 | else | ||
825 | GST_send_operation_success_msg (mctx->client, mctx->op_id); | ||
826 | GNUNET_free_non_null (emsg); | ||
827 | cleanup_mctx (mctx); | ||
828 | } | ||
829 | |||
830 | |||
831 | /** | ||
832 | * Handler for GNUNET_TESTBED_ManagePeerServiceMessage message | ||
833 | * | ||
834 | * @param cls NULL | ||
835 | * @param client identification of client | ||
836 | * @param message the actual message | ||
837 | */ | ||
838 | void | ||
839 | GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client, | ||
840 | const struct GNUNET_MessageHeader *message) | ||
841 | { | ||
842 | const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg; | ||
843 | const char* service; | ||
844 | struct Peer *peer; | ||
845 | char *emsg; | ||
846 | struct GNUNET_ARM_Handle *ah; | ||
847 | struct ManageServiceContext *mctx; | ||
848 | struct ForwardedOperationContext *fopc; | ||
849 | uint64_t op_id; | ||
850 | uint32_t peer_id; | ||
851 | uint16_t msize; | ||
852 | |||
853 | |||
854 | msize = ntohs (message->size); | ||
855 | if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage)) | ||
856 | { | ||
857 | GNUNET_break_op (0); | ||
858 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
859 | return; | ||
860 | } | ||
861 | msg = (const struct GNUNET_TESTBED_ManagePeerServiceMessage *) message; | ||
862 | service = (const char *) &msg[1]; | ||
863 | if ('\0' != service[msize - sizeof | ||
864 | (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1]) | ||
865 | { | ||
866 | GNUNET_break_op (0); | ||
867 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
868 | return; | ||
869 | } | ||
870 | if (1 < msg->start) | ||
871 | { | ||
872 | GNUNET_break_op (0); | ||
873 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
874 | return; | ||
875 | } | ||
876 | peer_id = ntohl (msg->peer_id); | ||
877 | op_id = GNUNET_ntohll (msg->operation_id); | ||
878 | LOG_DEBUG ("Received request to manage service %s on peer %u\n", | ||
879 | service, (unsigned int) peer_id); | ||
880 | if ((GST_peer_list_size <= peer_id) | ||
881 | || (NULL == (peer = GST_peer_list[peer_id]))) | ||
882 | { | ||
883 | GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer " | ||
884 | "with id: %u", peer_id); | ||
885 | goto err_ret; | ||
886 | } | ||
887 | if (0 == strcasecmp ("arm", service)) | ||
888 | { | ||
889 | emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. " | ||
890 | "Use peer start/stop for that"); | ||
891 | goto err_ret; | ||
892 | } | ||
893 | if (GNUNET_YES == peer->is_remote) | ||
894 | { | ||
895 | /* Forward the destory message to sub controller */ | ||
896 | fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext)); | ||
897 | GNUNET_SERVER_client_keep (client); | ||
898 | fopc->client = client; | ||
899 | fopc->cls = peer; | ||
900 | fopc->type = OP_MANAGE_SERVICE; | ||
901 | fopc->operation_id = op_id; | ||
902 | fopc->opc = | ||
903 | GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote. | ||
904 | slave->controller, | ||
905 | fopc->operation_id, &msg->header, | ||
906 | &GST_forwarded_operation_reply_relay, | ||
907 | fopc); | ||
908 | fopc->timeout_task = | ||
909 | GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout, | ||
910 | fopc); | ||
911 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc); | ||
912 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
913 | return; | ||
914 | } | ||
915 | if ((0 != peer->reference_cnt) | ||
916 | && ( (0 == strcasecmp ("core", service)) | ||
917 | || (0 == strcasecmp ("transport", service)) ) ) | ||
918 | { | ||
919 | GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u " | ||
920 | "since it is required by existing operations", | ||
921 | service, peer_id); | ||
922 | goto err_ret; | ||
923 | } | ||
924 | ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL); | ||
925 | if (NULL == ah) | ||
926 | { | ||
927 | GNUNET_asprintf (&emsg, | ||
928 | "Cannot connect to ARM service of peer with id: %u", | ||
929 | peer_id); | ||
930 | goto err_ret; | ||
931 | } | ||
932 | mctx = GNUNET_malloc (sizeof (struct ManageServiceContext)); | ||
933 | mctx->peer = peer; | ||
934 | peer->reference_cnt++; | ||
935 | mctx->op_id = op_id; | ||
936 | mctx->ah = ah; | ||
937 | GNUNET_SERVER_client_keep (client); | ||
938 | mctx->client = client; | ||
939 | mctx->start = msg->start; | ||
940 | GNUNET_CONTAINER_DLL_insert_tail (mctx_head, mctx_tail, mctx); | ||
941 | if (1 == mctx->start) | ||
942 | GNUNET_ARM_request_service_start (mctx->ah, service, | ||
943 | GNUNET_OS_INHERIT_STD_ERR, | ||
944 | GST_timeout, | ||
945 | service_manage_result_cb, | ||
946 | mctx); | ||
947 | else | ||
948 | GNUNET_ARM_request_service_stop (mctx->ah, service, | ||
949 | GST_timeout, | ||
950 | service_manage_result_cb, | ||
951 | mctx); | ||
952 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
953 | return; | ||
954 | |||
955 | err_ret: | ||
956 | LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg); | ||
957 | GST_send_operation_fail_msg (client, op_id, emsg); | ||
958 | GNUNET_free (emsg); | ||
959 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
960 | } | ||
961 | |||
962 | |||
963 | /** | ||
964 | * Stops and destroys all peers | ||
965 | */ | ||
966 | void | ||
967 | GST_destroy_peers () | ||
968 | { | ||
969 | struct Peer *peer; | ||
970 | unsigned int id; | ||
971 | |||
972 | if (NULL == GST_peer_list) | ||
973 | return; | ||
974 | for (id = 0; id < GST_peer_list_size; id++) | ||
975 | { | ||
976 | peer = GST_peer_list[id]; | ||
977 | if (NULL == peer) | ||
978 | continue; | ||
979 | /* If destroy flag is set it means that this peer should have been | ||
980 | * destroyed by a context which we destroy before */ | ||
981 | GNUNET_break (GNUNET_NO == peer->destroy_flag); | ||
982 | /* counter should be zero as we free all contexts before */ | ||
983 | GNUNET_break (0 == peer->reference_cnt); | ||
984 | if ((GNUNET_NO == peer->is_remote) && | ||
985 | (GNUNET_YES == peer->details.local.is_running)) | ||
986 | GNUNET_TESTING_peer_kill (peer->details.local.peer); | ||
987 | } | ||
988 | for (id = 0; id < GST_peer_list_size; id++) | ||
989 | { | ||
990 | peer = GST_peer_list[id]; | ||
991 | if (NULL == peer) | ||
992 | continue; | ||
993 | if (GNUNET_NO == peer->is_remote) | ||
994 | { | ||
995 | if (GNUNET_YES == peer->details.local.is_running) | ||
996 | GNUNET_TESTING_peer_wait (peer->details.local.peer); | ||
997 | GNUNET_TESTING_peer_destroy (peer->details.local.peer); | ||
998 | GNUNET_CONFIGURATION_destroy (peer->details.local.cfg); | ||
999 | } | ||
1000 | GNUNET_free (peer); | ||
1001 | } | ||
1002 | GNUNET_free_non_null (GST_peer_list); | ||
1003 | GST_peer_list = NULL; | ||
1004 | GST_peer_list_size = 0; | ||
1005 | } | ||
1006 | |||
1007 | |||
1008 | /** | ||
1009 | * Task run upon timeout of forwarded SHUTDOWN_PEERS operation | ||
1010 | * | ||
1011 | * @param cls the ForwardedOperationContext | ||
1012 | * @param tc the scheduler task context | ||
1013 | */ | ||
1014 | static void | ||
1015 | shutdown_peers_timeout_cb (void *cls, | ||
1016 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1017 | { | ||
1018 | struct ForwardedOperationContext *fo_ctxt = cls; | ||
1019 | struct HandlerContext_ShutdownPeers *hc; | ||
1020 | |||
1021 | fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
1022 | hc = fo_ctxt->cls; | ||
1023 | hc->timeout = GNUNET_YES; | ||
1024 | GNUNET_assert (0 < hc->nslaves); | ||
1025 | hc->nslaves--; | ||
1026 | if (0 == hc->nslaves) | ||
1027 | GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id, | ||
1028 | "Timeout at a slave controller"); | ||
1029 | GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc); | ||
1030 | GNUNET_SERVER_client_drop (fo_ctxt->client); | ||
1031 | GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt); | ||
1032 | GNUNET_free (fo_ctxt); | ||
1033 | } | ||
1034 | |||
1035 | |||
1036 | /** | ||
1037 | * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a | ||
1038 | * success reply is received from all clients and then sends the success message | ||
1039 | * to the client | ||
1040 | * | ||
1041 | * @param cls ForwardedOperationContext | ||
1042 | * @param msg the message to relay | ||
1043 | */ | ||
1044 | static void | ||
1045 | shutdown_peers_reply_cb (void *cls, | ||
1046 | const struct GNUNET_MessageHeader *msg) | ||
1047 | { | ||
1048 | struct ForwardedOperationContext *fo_ctxt = cls; | ||
1049 | struct HandlerContext_ShutdownPeers *hc; | ||
1050 | |||
1051 | hc = fo_ctxt->cls; | ||
1052 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != fo_ctxt->timeout_task); | ||
1053 | GNUNET_SCHEDULER_cancel (fo_ctxt->timeout_task); | ||
1054 | fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK; | ||
1055 | GNUNET_assert (0 < hc->nslaves); | ||
1056 | hc->nslaves--; | ||
1057 | if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS != | ||
1058 | ntohs (msg->type)) | ||
1059 | hc->timeout = GNUNET_YES; | ||
1060 | if (0 == hc->nslaves) | ||
1061 | { | ||
1062 | if (GNUNET_YES == hc->timeout) | ||
1063 | GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id, | ||
1064 | "Timeout at a slave controller"); | ||
1065 | else | ||
1066 | GST_send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id); | ||
1067 | } | ||
1068 | GNUNET_SERVER_client_drop (fo_ctxt->client); | ||
1069 | GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt); | ||
1070 | GNUNET_free (fo_ctxt); | ||
1071 | } | ||
1072 | |||
1073 | |||
1074 | /** | ||
1075 | * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages | ||
1076 | * | ||
1077 | * @param cls NULL | ||
1078 | * @param client identification of the client | ||
1079 | * @param message the actual message | ||
1080 | */ | ||
1081 | void | ||
1082 | GST_handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client, | ||
1083 | const struct GNUNET_MessageHeader *message) | ||
1084 | { | ||
1085 | const struct GNUNET_TESTBED_ShutdownPeersMessage *msg; | ||
1086 | struct HandlerContext_ShutdownPeers *hc; | ||
1087 | struct Slave *slave; | ||
1088 | struct ForwardedOperationContext *fo_ctxt; | ||
1089 | uint64_t op_id; | ||
1090 | unsigned int cnt; | ||
1091 | |||
1092 | msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message; | ||
1093 | LOG_DEBUG ("Received SHUTDOWN_PEERS\n"); | ||
1094 | /* Stop and destroy all peers */ | ||
1095 | GST_free_mctxq (); | ||
1096 | GST_free_occq (); | ||
1097 | GST_free_roccq (); | ||
1098 | GST_clear_fopcq (); | ||
1099 | /* Forward to all slaves which we have started */ | ||
1100 | op_id = GNUNET_ntohll (msg->operation_id); | ||
1101 | hc = GNUNET_malloc (sizeof (struct HandlerContext_ShutdownPeers)); | ||
1102 | /* FIXME: have a better implementation where we track which slaves are | ||
1103 | started by this controller */ | ||
1104 | for (cnt = 0; cnt < GST_slave_list_size; cnt++) | ||
1105 | { | ||
1106 | slave = GST_slave_list[cnt]; | ||
1107 | if (NULL == slave) | ||
1108 | continue; | ||
1109 | if (NULL == slave->controller_proc) /* We didn't start the slave */ | ||
1110 | continue; | ||
1111 | LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n"); | ||
1112 | hc->nslaves++; | ||
1113 | fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext)); | ||
1114 | GNUNET_SERVER_client_keep (client); | ||
1115 | fo_ctxt->client = client; | ||
1116 | fo_ctxt->operation_id = op_id; | ||
1117 | fo_ctxt->cls = hc; | ||
1118 | fo_ctxt->type = OP_SHUTDOWN_PEERS; | ||
1119 | fo_ctxt->opc = | ||
1120 | GNUNET_TESTBED_forward_operation_msg_ (slave->controller, | ||
1121 | fo_ctxt->operation_id, | ||
1122 | &msg->header, | ||
1123 | shutdown_peers_reply_cb, | ||
1124 | fo_ctxt); | ||
1125 | fo_ctxt->timeout_task = | ||
1126 | GNUNET_SCHEDULER_add_delayed (GST_timeout, &shutdown_peers_timeout_cb, | ||
1127 | fo_ctxt); | ||
1128 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt); | ||
1129 | } | ||
1130 | LOG_DEBUG ("Shutting down peers\n"); | ||
1131 | GST_destroy_peers (); | ||
1132 | if (0 == hc->nslaves) | ||
1133 | { | ||
1134 | GST_send_operation_success_msg (client, op_id); | ||
1135 | GNUNET_free (hc); | ||
1136 | } | ||
1137 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
1138 | } | ||