diff options
Diffstat (limited to 'src/testbed/gnunet-service-testbed_peers.c')
-rw-r--r-- | src/testbed/gnunet-service-testbed_peers.c | 1552 |
1 files changed, 0 insertions, 1552 deletions
diff --git a/src/testbed/gnunet-service-testbed_peers.c b/src/testbed/gnunet-service-testbed_peers.c deleted file mode 100644 index 05410c26a..000000000 --- a/src/testbed/gnunet-service-testbed_peers.c +++ /dev/null | |||
@@ -1,1552 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2008--2013, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your 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 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
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 "platform.h" | ||
29 | #include "gnunet-service-testbed.h" | ||
30 | #include "gnunet_arm_service.h" | ||
31 | #include <zlib.h> | ||
32 | |||
33 | |||
34 | /** | ||
35 | * A list of peers we know about | ||
36 | */ | ||
37 | struct Peer **GST_peer_list; | ||
38 | |||
39 | /** | ||
40 | * The current number of peers running locally under this controller | ||
41 | */ | ||
42 | unsigned int GST_num_local_peers; | ||
43 | |||
44 | |||
45 | /** | ||
46 | * Context information to manage peers' services | ||
47 | */ | ||
48 | struct ManageServiceContext | ||
49 | { | ||
50 | /** | ||
51 | * DLL next ptr | ||
52 | */ | ||
53 | struct ManageServiceContext *next; | ||
54 | |||
55 | /** | ||
56 | * DLL prev ptr | ||
57 | */ | ||
58 | struct ManageServiceContext *prev; | ||
59 | |||
60 | /** | ||
61 | * The ARM handle of the peer | ||
62 | */ | ||
63 | struct GNUNET_ARM_Handle *ah; | ||
64 | |||
65 | /** | ||
66 | * peer whose service has to be managed | ||
67 | */ | ||
68 | struct Peer *peer; | ||
69 | |||
70 | /** | ||
71 | * The client which requested to manage the peer's service | ||
72 | */ | ||
73 | struct GNUNET_SERVICE_Client *client; | ||
74 | |||
75 | /** | ||
76 | * Name of the service. | ||
77 | */ | ||
78 | char *service; | ||
79 | |||
80 | /** | ||
81 | * The operation id of the associated request | ||
82 | */ | ||
83 | uint64_t op_id; | ||
84 | |||
85 | /** | ||
86 | * 1 if the service at the peer has to be started; 0 if it has to be stopped | ||
87 | */ | ||
88 | uint8_t start; | ||
89 | |||
90 | /** | ||
91 | * Is this context expired? Do not work on this context if it is set to | ||
92 | * GNUNET_YES | ||
93 | */ | ||
94 | uint8_t expired; | ||
95 | }; | ||
96 | |||
97 | |||
98 | /** | ||
99 | * Context information for peer re-configure operations | ||
100 | */ | ||
101 | struct PeerReconfigureContext | ||
102 | { | ||
103 | /** | ||
104 | * DLL next for inclusoin in peer reconfigure operations list | ||
105 | */ | ||
106 | struct PeerReconfigureContext *next; | ||
107 | |||
108 | /** | ||
109 | * DLL prev | ||
110 | */ | ||
111 | struct PeerReconfigureContext *prev; | ||
112 | |||
113 | /** | ||
114 | * The client which gave this operation to us | ||
115 | */ | ||
116 | struct GNUNET_SERVICE_Client *client; | ||
117 | |||
118 | /** | ||
119 | * The configuration handle to use as the new template | ||
120 | */ | ||
121 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
122 | |||
123 | /** | ||
124 | * The id of the operation | ||
125 | */ | ||
126 | uint64_t op_id; | ||
127 | |||
128 | /** | ||
129 | * The id of the peer which has to be reconfigured | ||
130 | */ | ||
131 | uint32_t peer_id; | ||
132 | |||
133 | /** | ||
134 | * The the peer stopped? Used while cleaning up this context to decide | ||
135 | * whether the asynchronous stop request through Testing/ARM API has to be | ||
136 | * cancelled | ||
137 | */ | ||
138 | uint8_t stopped; | ||
139 | }; | ||
140 | |||
141 | /** | ||
142 | * The DLL head for the peer reconfigure list | ||
143 | */ | ||
144 | static struct PeerReconfigureContext *prc_head; | ||
145 | |||
146 | /** | ||
147 | * The DLL tail for the peer reconfigure list | ||
148 | */ | ||
149 | static struct PeerReconfigureContext *prc_tail; | ||
150 | |||
151 | |||
152 | /** | ||
153 | * DLL head for queue of manage service requests | ||
154 | */ | ||
155 | static struct ManageServiceContext *mctx_head; | ||
156 | |||
157 | /** | ||
158 | * DLL tail for queue of manage service requests | ||
159 | */ | ||
160 | static struct ManageServiceContext *mctx_tail; | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Adds a peer to the peer array | ||
165 | * | ||
166 | * @param peer the peer to add | ||
167 | */ | ||
168 | static void | ||
169 | peer_list_add (struct Peer *peer) | ||
170 | { | ||
171 | if (peer->id >= GST_peer_list_size) | ||
172 | GST_array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id); | ||
173 | GNUNET_assert (NULL == GST_peer_list[peer->id]); | ||
174 | GST_peer_list[peer->id] = peer; | ||
175 | if (GNUNET_NO == peer->is_remote) | ||
176 | GST_num_local_peers++; | ||
177 | } | ||
178 | |||
179 | |||
180 | /** | ||
181 | * Removes a the give peer from the peer array | ||
182 | * | ||
183 | * @param peer the peer to be removed | ||
184 | */ | ||
185 | static void | ||
186 | peer_list_remove (struct Peer *peer) | ||
187 | { | ||
188 | unsigned int orig_size; | ||
189 | uint32_t id; | ||
190 | |||
191 | if (GNUNET_NO == peer->is_remote) | ||
192 | GST_num_local_peers--; | ||
193 | GST_peer_list[peer->id] = NULL; | ||
194 | orig_size = GST_peer_list_size; | ||
195 | while (GST_peer_list_size >= LIST_GROW_STEP) | ||
196 | { | ||
197 | for (id = GST_peer_list_size - 1; | ||
198 | (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX); | ||
199 | id--) | ||
200 | if (NULL != GST_peer_list[id]) | ||
201 | break; | ||
202 | if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1)) | ||
203 | break; | ||
204 | GST_peer_list_size -= LIST_GROW_STEP; | ||
205 | } | ||
206 | if (orig_size == GST_peer_list_size) | ||
207 | return; | ||
208 | GST_peer_list = | ||
209 | GNUNET_realloc (GST_peer_list, | ||
210 | sizeof(struct Peer *) * GST_peer_list_size); | ||
211 | } | ||
212 | |||
213 | |||
214 | /** | ||
215 | * The task to be executed if the forwarded peer create operation has been | ||
216 | * timed out | ||
217 | * | ||
218 | * @param cls the FowardedOperationContext | ||
219 | */ | ||
220 | static void | ||
221 | peer_create_forward_timeout (void *cls) | ||
222 | { | ||
223 | struct ForwardedOperationContext *fopc = cls; | ||
224 | |||
225 | GNUNET_free (fopc->cls); | ||
226 | GST_forwarded_operation_timeout (fopc); | ||
227 | } | ||
228 | |||
229 | |||
230 | /** | ||
231 | * Callback to be called when forwarded peer create operation is successful. We | ||
232 | * have to relay the reply msg back to the client | ||
233 | * | ||
234 | * @param cls ForwardedOperationContext | ||
235 | * @param msg the peer create success message | ||
236 | */ | ||
237 | static void | ||
238 | peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg) | ||
239 | { | ||
240 | struct ForwardedOperationContext *fopc = cls; | ||
241 | struct Peer *remote_peer; | ||
242 | |||
243 | if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS) | ||
244 | { | ||
245 | GNUNET_assert (NULL != fopc->cls); | ||
246 | remote_peer = fopc->cls; | ||
247 | peer_list_add (remote_peer); | ||
248 | } | ||
249 | GST_forwarded_operation_reply_relay (fopc, | ||
250 | msg); | ||
251 | } | ||
252 | |||
253 | |||
254 | /** | ||
255 | * Function to destroy a peer | ||
256 | * | ||
257 | * @param peer the peer structure to destroy | ||
258 | */ | ||
259 | void | ||
260 | GST_destroy_peer (struct Peer *peer) | ||
261 | { | ||
262 | GNUNET_break (0 == peer->reference_cnt); | ||
263 | if (GNUNET_YES == peer->is_remote) | ||
264 | { | ||
265 | peer_list_remove (peer); | ||
266 | GNUNET_free (peer); | ||
267 | return; | ||
268 | } | ||
269 | if (GNUNET_YES == peer->details.local.is_running) | ||
270 | { | ||
271 | GNUNET_TESTING_peer_stop (peer->details.local.peer); | ||
272 | peer->details.local.is_running = GNUNET_NO; | ||
273 | } | ||
274 | GNUNET_TESTING_peer_destroy (peer->details.local.peer); | ||
275 | GNUNET_CONFIGURATION_destroy (peer->details.local.cfg); | ||
276 | peer_list_remove (peer); | ||
277 | GNUNET_free (peer); | ||
278 | } | ||
279 | |||
280 | |||
281 | /** | ||
282 | * Cleanup the context information created for managing a peer's service | ||
283 | * | ||
284 | * @param mctx the ManageServiceContext | ||
285 | */ | ||
286 | static void | ||
287 | cleanup_mctx (struct ManageServiceContext *mctx) | ||
288 | { | ||
289 | mctx->expired = GNUNET_YES; | ||
290 | GNUNET_CONTAINER_DLL_remove (mctx_head, | ||
291 | mctx_tail, | ||
292 | mctx); | ||
293 | GNUNET_ARM_disconnect (mctx->ah); | ||
294 | GNUNET_assert (0 < mctx->peer->reference_cnt); | ||
295 | mctx->peer->reference_cnt--; | ||
296 | if ((GNUNET_YES == mctx->peer->destroy_flag) && | ||
297 | (0 == mctx->peer->reference_cnt)) | ||
298 | GST_destroy_peer (mctx->peer); | ||
299 | GNUNET_free (mctx->service); | ||
300 | GNUNET_free (mctx); | ||
301 | } | ||
302 | |||
303 | |||
304 | /** | ||
305 | * Stops a peer | ||
306 | * | ||
307 | * @param peer the peer to stop | ||
308 | * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure | ||
309 | */ | ||
310 | static int | ||
311 | stop_peer (struct Peer *peer) | ||
312 | { | ||
313 | GNUNET_assert (GNUNET_NO == peer->is_remote); | ||
314 | if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer)) | ||
315 | return GNUNET_SYSERR; | ||
316 | peer->details.local.is_running = GNUNET_NO; | ||
317 | return GNUNET_OK; | ||
318 | } | ||
319 | |||
320 | |||
321 | /** | ||
322 | * Cleans up the given PeerReconfigureContext | ||
323 | * | ||
324 | * @param prc the PeerReconfigureContext | ||
325 | */ | ||
326 | static void | ||
327 | cleanup_prc (struct PeerReconfigureContext *prc) | ||
328 | { | ||
329 | struct Peer *peer; | ||
330 | |||
331 | if (VALID_PEER_ID (prc->peer_id)) | ||
332 | { | ||
333 | peer = GST_peer_list [prc->peer_id]; | ||
334 | if (1 != prc->stopped) | ||
335 | { | ||
336 | GNUNET_TESTING_peer_stop_async_cancel (peer->details.local.peer); | ||
337 | stop_peer (peer); /* Stop the peer synchronously */ | ||
338 | } | ||
339 | } | ||
340 | if (NULL != prc->cfg) | ||
341 | GNUNET_CONFIGURATION_destroy (prc->cfg); | ||
342 | GNUNET_CONTAINER_DLL_remove (prc_head, | ||
343 | prc_tail, | ||
344 | prc); | ||
345 | GNUNET_free (prc); | ||
346 | } | ||
347 | |||
348 | |||
349 | /** | ||
350 | * Notify peers subsystem that @a client disconnected. | ||
351 | * | ||
352 | * @param client the client that disconnected | ||
353 | */ | ||
354 | void | ||
355 | GST_notify_client_disconnect_peers (struct GNUNET_SERVICE_Client *client) | ||
356 | { | ||
357 | struct ForwardedOperationContext *fopc; | ||
358 | struct ForwardedOperationContext *fopcn; | ||
359 | struct ManageServiceContext *mctx; | ||
360 | struct ManageServiceContext *mctxn; | ||
361 | struct PeerReconfigureContext *prc; | ||
362 | struct PeerReconfigureContext *prcn; | ||
363 | |||
364 | for (fopc = fopcq_head; NULL != fopc; fopc = fopcn) | ||
365 | { | ||
366 | fopcn = fopc->next; | ||
367 | if (client == fopc->client) | ||
368 | { | ||
369 | if (OP_PEER_CREATE == fopc->type) | ||
370 | GNUNET_free (fopc->cls); | ||
371 | GNUNET_SCHEDULER_cancel (fopc->timeout_task); | ||
372 | GST_forwarded_operation_timeout (fopc); | ||
373 | } | ||
374 | } | ||
375 | for (mctx = mctx_head; NULL != mctx; mctx = mctxn) | ||
376 | { | ||
377 | mctxn = mctx->next; | ||
378 | if (client == mctx->client) | ||
379 | cleanup_mctx (mctx); | ||
380 | } | ||
381 | for (prc = prc_head; NULL != prc; prc = prcn) | ||
382 | { | ||
383 | prcn = prc->next; | ||
384 | if (client == prc->client) | ||
385 | cleanup_prc (prc); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | |||
390 | /** | ||
391 | * Callback to be called when forwarded peer destroy operation is successful. We | ||
392 | * have to relay the reply msg back to the client | ||
393 | * | ||
394 | * @param cls ForwardedOperationContext | ||
395 | * @param msg the peer create success message | ||
396 | */ | ||
397 | static void | ||
398 | peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg) | ||
399 | { | ||
400 | struct ForwardedOperationContext *fopc = cls; | ||
401 | struct Peer *remote_peer; | ||
402 | |||
403 | if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS == | ||
404 | ntohs (msg->type)) | ||
405 | { | ||
406 | remote_peer = fopc->cls; | ||
407 | GNUNET_assert (NULL != remote_peer); | ||
408 | remote_peer->destroy_flag = GNUNET_YES; | ||
409 | if (0 == remote_peer->reference_cnt) | ||
410 | GST_destroy_peer (remote_peer); | ||
411 | } | ||
412 | GST_forwarded_operation_reply_relay (fopc, | ||
413 | msg); | ||
414 | } | ||
415 | |||
416 | |||
417 | /** | ||
418 | * Check #GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages | ||
419 | * | ||
420 | * @param cls identification of the client | ||
421 | * @param msg the actual message | ||
422 | * @return #GNUNET_OK if @a msg is well-formed | ||
423 | */ | ||
424 | int | ||
425 | check_peer_create (void *cls, | ||
426 | const struct GNUNET_TESTBED_PeerCreateMessage *msg) | ||
427 | { | ||
428 | return GNUNET_OK; /* checked later */ | ||
429 | } | ||
430 | |||
431 | |||
432 | void | ||
433 | handle_peer_create (void *cls, | ||
434 | const struct GNUNET_TESTBED_PeerCreateMessage *msg) | ||
435 | { | ||
436 | struct GNUNET_SERVICE_Client *client = cls; | ||
437 | struct GNUNET_MQ_Envelope *env; | ||
438 | struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply; | ||
439 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
440 | struct ForwardedOperationContext *fo_ctxt; | ||
441 | struct Route *route; | ||
442 | struct Peer *peer; | ||
443 | char *emsg; | ||
444 | uint32_t host_id; | ||
445 | uint32_t peer_id; | ||
446 | |||
447 | host_id = ntohl (msg->host_id); | ||
448 | peer_id = ntohl (msg->peer_id); | ||
449 | if (VALID_PEER_ID (peer_id)) | ||
450 | { | ||
451 | (void) GNUNET_asprintf (&emsg, | ||
452 | "Peer with ID %u already exists", | ||
453 | peer_id); | ||
454 | GST_send_operation_fail_msg (client, | ||
455 | GNUNET_ntohll (msg->operation_id), | ||
456 | emsg); | ||
457 | GNUNET_free (emsg); | ||
458 | GNUNET_SERVICE_client_continue (client); | ||
459 | return; | ||
460 | } | ||
461 | if (UINT32_MAX == peer_id) | ||
462 | { | ||
463 | GST_send_operation_fail_msg (client, | ||
464 | GNUNET_ntohll (msg->operation_id), | ||
465 | "Cannot create peer with given ID"); | ||
466 | GNUNET_SERVICE_client_continue (client); | ||
467 | return; | ||
468 | } | ||
469 | if (host_id == GST_context->host_id) | ||
470 | { | ||
471 | /* We are responsible for this peer */ | ||
472 | cfg = GNUNET_TESTBED_extract_config_ (&msg->header); | ||
473 | if (NULL == cfg) | ||
474 | { | ||
475 | GNUNET_break (0); | ||
476 | GNUNET_SERVICE_client_drop (client); | ||
477 | return; | ||
478 | } | ||
479 | GNUNET_CONFIGURATION_set_value_number (cfg, | ||
480 | "TESTBED", | ||
481 | "PEERID", | ||
482 | (unsigned long long) peer_id); | ||
483 | |||
484 | GNUNET_CONFIGURATION_set_value_number (cfg, | ||
485 | "PATHS", | ||
486 | "PEERID", | ||
487 | (unsigned long long) peer_id); | ||
488 | peer = GNUNET_new (struct Peer); | ||
489 | peer->is_remote = GNUNET_NO; | ||
490 | peer->details.local.cfg = cfg; | ||
491 | peer->id = peer_id; | ||
492 | LOG_DEBUG ("Creating peer with id: %u\n", | ||
493 | (unsigned int) peer->id); | ||
494 | peer->details.local.peer = | ||
495 | GNUNET_TESTING_peer_configure (GST_context->system, | ||
496 | peer->details.local.cfg, peer->id, | ||
497 | NULL /* Peer id */, | ||
498 | &emsg); | ||
499 | if (NULL == peer->details.local.peer) | ||
500 | { | ||
501 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
502 | "Configuring peer failed: %s\n", | ||
503 | emsg); | ||
504 | GNUNET_free (emsg); | ||
505 | GNUNET_free (peer); | ||
506 | GNUNET_break (0); | ||
507 | GNUNET_SERVICE_client_drop (client); | ||
508 | return; | ||
509 | } | ||
510 | peer->details.local.is_running = GNUNET_NO; | ||
511 | peer_list_add (peer); | ||
512 | env = GNUNET_MQ_msg (reply, | ||
513 | GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS); | ||
514 | reply->peer_id = msg->peer_id; | ||
515 | reply->operation_id = msg->operation_id; | ||
516 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
517 | env); | ||
518 | GNUNET_SERVICE_client_continue (client); | ||
519 | return; | ||
520 | } | ||
521 | |||
522 | /* Forward peer create request */ | ||
523 | route = GST_find_dest_route (host_id); | ||
524 | if (NULL == route) | ||
525 | { | ||
526 | GNUNET_break (0); | ||
527 | GNUNET_SERVICE_client_continue (client); // ? | ||
528 | return; | ||
529 | } | ||
530 | peer = GNUNET_new (struct Peer); | ||
531 | peer->is_remote = GNUNET_YES; | ||
532 | peer->id = peer_id; | ||
533 | peer->details.remote.slave = GST_slave_list[route->dest]; | ||
534 | peer->details.remote.remote_host_id = host_id; | ||
535 | fo_ctxt = GNUNET_new (struct ForwardedOperationContext); | ||
536 | fo_ctxt->client = client; | ||
537 | fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id); | ||
538 | fo_ctxt->cls = peer; | ||
539 | fo_ctxt->type = OP_PEER_CREATE; | ||
540 | fo_ctxt->opc = | ||
541 | GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list | ||
542 | [route->dest]->controller, | ||
543 | fo_ctxt->operation_id, | ||
544 | &msg->header, | ||
545 | &peer_create_success_cb, | ||
546 | fo_ctxt); | ||
547 | fo_ctxt->timeout_task = | ||
548 | GNUNET_SCHEDULER_add_delayed (GST_timeout, | ||
549 | &peer_create_forward_timeout, | ||
550 | fo_ctxt); | ||
551 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, | ||
552 | fopcq_tail, | ||
553 | fo_ctxt); | ||
554 | GNUNET_SERVICE_client_continue (client); | ||
555 | } | ||
556 | |||
557 | |||
558 | /** | ||
559 | * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages | ||
560 | * | ||
561 | * @param cls identification of the client | ||
562 | * @param msg the actual message | ||
563 | */ | ||
564 | void | ||
565 | handle_peer_destroy (void *cls, | ||
566 | const struct GNUNET_TESTBED_PeerDestroyMessage *msg) | ||
567 | { | ||
568 | struct GNUNET_SERVICE_Client *client = cls; | ||
569 | struct ForwardedOperationContext *fopc; | ||
570 | struct Peer *peer; | ||
571 | uint32_t peer_id; | ||
572 | |||
573 | peer_id = ntohl (msg->peer_id); | ||
574 | LOG_DEBUG ("Received peer destroy on peer: %u and operation id: %llu\n", | ||
575 | (unsigned int) peer_id, | ||
576 | (unsigned long long) GNUNET_ntohll (msg->operation_id)); | ||
577 | if (! VALID_PEER_ID (peer_id)) | ||
578 | { | ||
579 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
580 | "Asked to destroy a non existent peer with id: %u\n", peer_id); | ||
581 | GST_send_operation_fail_msg (client, | ||
582 | GNUNET_ntohll (msg->operation_id), | ||
583 | "Peer doesn't exist"); | ||
584 | GNUNET_SERVICE_client_continue (client); | ||
585 | return; | ||
586 | } | ||
587 | peer = GST_peer_list[peer_id]; | ||
588 | if (GNUNET_YES == peer->is_remote) | ||
589 | { | ||
590 | /* Forward the destroy message to sub controller */ | ||
591 | fopc = GNUNET_new (struct ForwardedOperationContext); | ||
592 | fopc->client = client; | ||
593 | fopc->cls = peer; | ||
594 | fopc->type = OP_PEER_DESTROY; | ||
595 | fopc->operation_id = GNUNET_ntohll (msg->operation_id); | ||
596 | fopc->opc = | ||
597 | GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote. | ||
598 | slave->controller, | ||
599 | fopc->operation_id, | ||
600 | &msg->header, | ||
601 | &peer_destroy_success_cb, | ||
602 | fopc); | ||
603 | fopc->timeout_task = | ||
604 | GNUNET_SCHEDULER_add_delayed (GST_timeout, | ||
605 | &GST_forwarded_operation_timeout, | ||
606 | fopc); | ||
607 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, | ||
608 | fopcq_tail, | ||
609 | fopc); | ||
610 | GNUNET_SERVICE_client_continue (client); | ||
611 | return; | ||
612 | } | ||
613 | peer->destroy_flag = GNUNET_YES; | ||
614 | if (0 == peer->reference_cnt) | ||
615 | GST_destroy_peer (peer); | ||
616 | else | ||
617 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
618 | "Delaying peer destroy as peer is currently in use\n"); | ||
619 | GST_send_operation_success_msg (client, | ||
620 | GNUNET_ntohll (msg->operation_id)); | ||
621 | GNUNET_SERVICE_client_continue (client); | ||
622 | } | ||
623 | |||
624 | |||
625 | /** | ||
626 | * Stats a peer | ||
627 | * | ||
628 | * @param peer the peer to start | ||
629 | * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure | ||
630 | */ | ||
631 | static int | ||
632 | start_peer (struct Peer *peer) | ||
633 | { | ||
634 | GNUNET_assert (GNUNET_NO == peer->is_remote); | ||
635 | if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer)) | ||
636 | return GNUNET_SYSERR; | ||
637 | peer->details.local.is_running = GNUNET_YES; | ||
638 | return GNUNET_OK; | ||
639 | } | ||
640 | |||
641 | |||
642 | void | ||
643 | handle_peer_start (void *cls, | ||
644 | const struct GNUNET_TESTBED_PeerStartMessage *msg) | ||
645 | { | ||
646 | struct GNUNET_SERVICE_Client *client = cls; | ||
647 | struct GNUNET_MQ_Envelope *env; | ||
648 | struct GNUNET_TESTBED_PeerEventMessage *reply; | ||
649 | struct ForwardedOperationContext *fopc; | ||
650 | struct Peer *peer; | ||
651 | uint32_t peer_id; | ||
652 | |||
653 | peer_id = ntohl (msg->peer_id); | ||
654 | if (! VALID_PEER_ID (peer_id)) | ||
655 | { | ||
656 | GNUNET_break (0); | ||
657 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
658 | "Asked to start a non existent peer with id: %u\n", | ||
659 | peer_id); | ||
660 | GNUNET_SERVICE_client_continue (client); | ||
661 | return; | ||
662 | } | ||
663 | peer = GST_peer_list[peer_id]; | ||
664 | if (GNUNET_YES == peer->is_remote) | ||
665 | { | ||
666 | fopc = GNUNET_new (struct ForwardedOperationContext); | ||
667 | fopc->client = client; | ||
668 | fopc->operation_id = GNUNET_ntohll (msg->operation_id); | ||
669 | fopc->type = OP_PEER_START; | ||
670 | fopc->opc = | ||
671 | GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote. | ||
672 | slave->controller, | ||
673 | fopc->operation_id, &msg->header, | ||
674 | & | ||
675 | GST_forwarded_operation_reply_relay, | ||
676 | fopc); | ||
677 | fopc->timeout_task = | ||
678 | GNUNET_SCHEDULER_add_delayed (GST_timeout, | ||
679 | &GST_forwarded_operation_timeout, | ||
680 | fopc); | ||
681 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, | ||
682 | fopcq_tail, | ||
683 | fopc); | ||
684 | GNUNET_SERVICE_client_continue (client); | ||
685 | return; | ||
686 | } | ||
687 | if (GNUNET_OK != start_peer (peer)) | ||
688 | { | ||
689 | GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id), | ||
690 | "Failed to start"); | ||
691 | GNUNET_SERVICE_client_continue (client); | ||
692 | return; | ||
693 | } | ||
694 | env = GNUNET_MQ_msg (reply, | ||
695 | GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT); | ||
696 | reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START); | ||
697 | reply->host_id = htonl (GST_context->host_id); | ||
698 | reply->peer_id = msg->peer_id; | ||
699 | reply->operation_id = msg->operation_id; | ||
700 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
701 | env); | ||
702 | GNUNET_SERVICE_client_continue (client); | ||
703 | } | ||
704 | |||
705 | |||
706 | /** | ||
707 | * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER messages | ||
708 | * | ||
709 | * @param cls identification of the client | ||
710 | * @param msg the actual message | ||
711 | */ | ||
712 | void | ||
713 | handle_peer_stop (void *cls, | ||
714 | const struct GNUNET_TESTBED_PeerStopMessage *msg) | ||
715 | { | ||
716 | struct GNUNET_SERVICE_Client *client = cls; | ||
717 | struct GNUNET_MQ_Envelope *env; | ||
718 | struct GNUNET_TESTBED_PeerEventMessage *reply; | ||
719 | struct ForwardedOperationContext *fopc; | ||
720 | struct Peer *peer; | ||
721 | uint32_t peer_id; | ||
722 | |||
723 | peer_id = ntohl (msg->peer_id); | ||
724 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
725 | "Received PEER_STOP for peer %u\n", | ||
726 | (unsigned int) peer_id); | ||
727 | if (! VALID_PEER_ID (peer_id)) | ||
728 | { | ||
729 | GST_send_operation_fail_msg (client, | ||
730 | GNUNET_ntohll (msg->operation_id), | ||
731 | "Peer not found"); | ||
732 | GNUNET_SERVICE_client_continue (client); | ||
733 | return; | ||
734 | } | ||
735 | peer = GST_peer_list[peer_id]; | ||
736 | if (GNUNET_YES == peer->is_remote) | ||
737 | { | ||
738 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
739 | "Forwarding PEER_STOP for peer %u\n", | ||
740 | (unsigned int) peer_id); | ||
741 | fopc = GNUNET_new (struct ForwardedOperationContext); | ||
742 | fopc->client = client; | ||
743 | fopc->operation_id = GNUNET_ntohll (msg->operation_id); | ||
744 | fopc->type = OP_PEER_STOP; | ||
745 | fopc->opc = | ||
746 | GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote. | ||
747 | slave->controller, | ||
748 | fopc->operation_id, | ||
749 | &msg->header, | ||
750 | & | ||
751 | GST_forwarded_operation_reply_relay, | ||
752 | fopc); | ||
753 | fopc->timeout_task = | ||
754 | GNUNET_SCHEDULER_add_delayed (GST_timeout, | ||
755 | &GST_forwarded_operation_timeout, | ||
756 | fopc); | ||
757 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, | ||
758 | fopcq_tail, | ||
759 | fopc); | ||
760 | GNUNET_SERVICE_client_continue (client); | ||
761 | return; | ||
762 | } | ||
763 | if (GNUNET_OK != stop_peer (peer)) | ||
764 | { | ||
765 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
766 | "Stopping peer %u failed\n", | ||
767 | (unsigned int) peer_id); | ||
768 | GST_send_operation_fail_msg (client, | ||
769 | GNUNET_ntohll (msg->operation_id), | ||
770 | "Peer not running"); | ||
771 | GNUNET_SERVICE_client_continue (client); | ||
772 | return; | ||
773 | } | ||
774 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
775 | "Peer %u successfully stopped\n", | ||
776 | (unsigned int) peer_id); | ||
777 | env = GNUNET_MQ_msg (reply, | ||
778 | GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT); | ||
779 | reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP); | ||
780 | reply->host_id = htonl (GST_context->host_id); | ||
781 | reply->peer_id = msg->peer_id; | ||
782 | reply->operation_id = msg->operation_id; | ||
783 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
784 | env); | ||
785 | GNUNET_SERVICE_client_continue (client); | ||
786 | GNUNET_TESTING_peer_wait (peer->details.local.peer); | ||
787 | } | ||
788 | |||
789 | |||
790 | /** | ||
791 | * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION messages | ||
792 | * | ||
793 | * @param cls identification of the client | ||
794 | * @param msg the actual message | ||
795 | */ | ||
796 | void | ||
797 | handle_peer_get_config (void *cls, | ||
798 | const struct | ||
799 | GNUNET_TESTBED_PeerGetConfigurationMessage *msg) | ||
800 | { | ||
801 | struct GNUNET_SERVICE_Client *client = cls; | ||
802 | struct GNUNET_MQ_Envelope *env; | ||
803 | struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply; | ||
804 | struct ForwardedOperationContext *fopc; | ||
805 | struct Peer *peer; | ||
806 | char *config; | ||
807 | char *xconfig; | ||
808 | size_t c_size; | ||
809 | size_t xc_size; | ||
810 | uint32_t peer_id; | ||
811 | |||
812 | peer_id = ntohl (msg->peer_id); | ||
813 | LOG_DEBUG ("Received GET_CONFIG for peer %u\n", | ||
814 | (unsigned int) peer_id); | ||
815 | if (! VALID_PEER_ID (peer_id)) | ||
816 | { | ||
817 | GST_send_operation_fail_msg (client, | ||
818 | GNUNET_ntohll (msg->operation_id), | ||
819 | "Peer not found"); | ||
820 | GNUNET_SERVICE_client_continue (client); | ||
821 | return; | ||
822 | } | ||
823 | peer = GST_peer_list[peer_id]; | ||
824 | if (GNUNET_YES == peer->is_remote) | ||
825 | { | ||
826 | LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", | ||
827 | (unsigned int) peer_id); | ||
828 | fopc = GNUNET_new (struct ForwardedOperationContext); | ||
829 | fopc->client = client; | ||
830 | fopc->operation_id = GNUNET_ntohll (msg->operation_id); | ||
831 | fopc->type = OP_PEER_INFO; | ||
832 | fopc->opc = | ||
833 | GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote. | ||
834 | slave->controller, | ||
835 | fopc->operation_id, | ||
836 | &msg->header, | ||
837 | & | ||
838 | GST_forwarded_operation_reply_relay, | ||
839 | fopc); | ||
840 | fopc->timeout_task = | ||
841 | GNUNET_SCHEDULER_add_delayed (GST_timeout, | ||
842 | &GST_forwarded_operation_timeout, | ||
843 | fopc); | ||
844 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, | ||
845 | fopcq_tail, | ||
846 | fopc); | ||
847 | GNUNET_SERVICE_client_continue (client); | ||
848 | return; | ||
849 | } | ||
850 | LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", | ||
851 | peer_id); | ||
852 | config = | ||
853 | GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg, | ||
854 | &c_size); | ||
855 | xc_size = GNUNET_TESTBED_compress_config_ (config, | ||
856 | c_size, | ||
857 | &xconfig); | ||
858 | GNUNET_free (config); | ||
859 | env = GNUNET_MQ_msg_extra (reply, | ||
860 | xc_size, | ||
861 | GNUNET_MESSAGE_TYPE_TESTBED_PEER_INFORMATION); | ||
862 | reply->peer_id = msg->peer_id; | ||
863 | reply->operation_id = msg->operation_id; | ||
864 | GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer, | ||
865 | &reply->peer_identity); | ||
866 | reply->config_size = htons ((uint16_t) c_size); | ||
867 | GNUNET_memcpy (&reply[1], | ||
868 | xconfig, | ||
869 | xc_size); | ||
870 | GNUNET_free (xconfig); | ||
871 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
872 | env); | ||
873 | GNUNET_SERVICE_client_continue (client); | ||
874 | } | ||
875 | |||
876 | |||
877 | /** | ||
878 | * Cleans up the Peer reconfigure context list | ||
879 | */ | ||
880 | void | ||
881 | GST_free_prcq () | ||
882 | { | ||
883 | while (NULL != prc_head) | ||
884 | cleanup_prc (prc_head); | ||
885 | } | ||
886 | |||
887 | |||
888 | /** | ||
889 | * Update peer configuration | ||
890 | * | ||
891 | * @param peer the peer to update | ||
892 | * @param cfg the new configuration | ||
893 | * @return error message (freshly allocated); NULL upon success | ||
894 | */ | ||
895 | static char * | ||
896 | update_peer_config (struct Peer *peer, | ||
897 | struct GNUNET_CONFIGURATION_Handle *cfg) | ||
898 | { | ||
899 | char *emsg; | ||
900 | |||
901 | GNUNET_TESTING_peer_destroy (peer->details.local.peer); | ||
902 | GNUNET_CONFIGURATION_destroy (peer->details.local.cfg); | ||
903 | peer->details.local.cfg = cfg; | ||
904 | emsg = NULL; | ||
905 | peer->details.local.peer | ||
906 | = GNUNET_TESTING_peer_configure (GST_context->system, | ||
907 | peer->details.local.cfg, | ||
908 | peer->id, | ||
909 | NULL /* Peer id */, | ||
910 | &emsg); | ||
911 | return emsg; | ||
912 | } | ||
913 | |||
914 | |||
915 | /** | ||
916 | * Callback to inform whether the peer is running or stopped. | ||
917 | * | ||
918 | * @param cls the closure given to GNUNET_TESTING_peer_stop_async() | ||
919 | * @param p the respective peer whose status is being reported | ||
920 | * @param success #GNUNET_YES if the peer is stopped; #GNUNET_SYSERR upon any | ||
921 | * error | ||
922 | */ | ||
923 | static void | ||
924 | prc_stop_cb (void *cls, | ||
925 | struct GNUNET_TESTING_Peer *p, | ||
926 | int success) | ||
927 | { | ||
928 | struct PeerReconfigureContext *prc = cls; | ||
929 | struct Peer *peer; | ||
930 | char *emsg; | ||
931 | |||
932 | GNUNET_assert (VALID_PEER_ID (prc->peer_id)); | ||
933 | peer = GST_peer_list [prc->peer_id]; | ||
934 | GNUNET_assert (GNUNET_NO == peer->is_remote); | ||
935 | emsg = update_peer_config (peer, prc->cfg); | ||
936 | prc->cfg = NULL; | ||
937 | prc->stopped = 1; | ||
938 | if (NULL != emsg) | ||
939 | { | ||
940 | GST_send_operation_fail_msg (prc->client, | ||
941 | prc->op_id, | ||
942 | emsg); | ||
943 | goto cleanup; | ||
944 | } | ||
945 | if (GNUNET_OK != start_peer (peer)) | ||
946 | { | ||
947 | GST_send_operation_fail_msg (prc->client, | ||
948 | prc->op_id, | ||
949 | "Failed to start reconfigured peer"); | ||
950 | goto cleanup; | ||
951 | } | ||
952 | GST_send_operation_success_msg (prc->client, | ||
953 | prc->op_id); | ||
954 | |||
955 | cleanup: | ||
956 | cleanup_prc (prc); | ||
957 | return; | ||
958 | } | ||
959 | |||
960 | |||
961 | /** | ||
962 | * Check #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages. | ||
963 | * | ||
964 | * @param cls identification of the client | ||
965 | * @param msg the actual message | ||
966 | * @return #GNUNET_OK if @a msg is well-formed | ||
967 | */ | ||
968 | int | ||
969 | check_peer_reconfigure (void *cls, | ||
970 | const struct GNUNET_TESTBED_PeerReconfigureMessage *msg) | ||
971 | { | ||
972 | return GNUNET_OK; /* checked later */ | ||
973 | } | ||
974 | |||
975 | |||
976 | /** | ||
977 | * Handler for #GNUNET_MESSAGE_TYPDE_TESTBED_RECONFIGURE_PEER type messages. | ||
978 | * Should stop the peer asynchronously, destroy it and create it again with the | ||
979 | * new configuration. | ||
980 | * | ||
981 | * @param cls identification of the client | ||
982 | * @param msg the actual message | ||
983 | */ | ||
984 | void | ||
985 | handle_peer_reconfigure (void *cls, | ||
986 | const struct | ||
987 | GNUNET_TESTBED_PeerReconfigureMessage *msg) | ||
988 | { | ||
989 | struct GNUNET_SERVICE_Client *client = cls; | ||
990 | struct Peer *peer; | ||
991 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
992 | struct ForwardedOperationContext *fopc; | ||
993 | struct PeerReconfigureContext *prc; | ||
994 | char *emsg; | ||
995 | uint64_t op_id; | ||
996 | uint32_t peer_id; | ||
997 | |||
998 | peer_id = ntohl (msg->peer_id); | ||
999 | op_id = GNUNET_ntohll (msg->operation_id); | ||
1000 | if (! VALID_PEER_ID (peer_id)) | ||
1001 | { | ||
1002 | GNUNET_break (0); | ||
1003 | GST_send_operation_fail_msg (client, | ||
1004 | op_id, | ||
1005 | "Peer not found"); | ||
1006 | GNUNET_SERVICE_client_continue (client); | ||
1007 | return; | ||
1008 | } | ||
1009 | peer = GST_peer_list[peer_id]; | ||
1010 | if (GNUNET_YES == peer->is_remote) | ||
1011 | { | ||
1012 | LOG_DEBUG ("Forwarding PEER_RECONFIGURE for peer: %u\n", peer_id); | ||
1013 | fopc = GNUNET_new (struct ForwardedOperationContext); | ||
1014 | fopc->client = client; | ||
1015 | fopc->operation_id = op_id; | ||
1016 | fopc->type = OP_PEER_RECONFIGURE; | ||
1017 | fopc->opc = | ||
1018 | GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote. | ||
1019 | slave->controller, | ||
1020 | fopc->operation_id, | ||
1021 | &msg->header, | ||
1022 | & | ||
1023 | GST_forwarded_operation_reply_relay, | ||
1024 | fopc); | ||
1025 | fopc->timeout_task = | ||
1026 | GNUNET_SCHEDULER_add_delayed (GST_timeout, | ||
1027 | &GST_forwarded_operation_timeout, | ||
1028 | fopc); | ||
1029 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, | ||
1030 | fopcq_tail, | ||
1031 | fopc); | ||
1032 | GNUNET_SERVICE_client_continue (client); | ||
1033 | return; | ||
1034 | } | ||
1035 | LOG_DEBUG ("Received PEER_RECONFIGURE for peer %u\n", | ||
1036 | (unsigned int) peer_id); | ||
1037 | if (0 < peer->reference_cnt) | ||
1038 | { | ||
1039 | GNUNET_break (0); | ||
1040 | GST_send_operation_fail_msg (client, | ||
1041 | op_id, | ||
1042 | "Peer in use"); | ||
1043 | GNUNET_SERVICE_client_continue (client); | ||
1044 | return; | ||
1045 | } | ||
1046 | if (GNUNET_YES == peer->destroy_flag) | ||
1047 | { | ||
1048 | GNUNET_break (0); | ||
1049 | GST_send_operation_fail_msg (client, | ||
1050 | op_id, | ||
1051 | "Peer is being destroyed"); | ||
1052 | GNUNET_SERVICE_client_continue (client); | ||
1053 | return; | ||
1054 | } | ||
1055 | cfg = GNUNET_TESTBED_extract_config_ (&msg->header); | ||
1056 | if (NULL == cfg) | ||
1057 | { | ||
1058 | GNUNET_break (0); | ||
1059 | GST_send_operation_fail_msg (client, | ||
1060 | op_id, | ||
1061 | "Compression error"); | ||
1062 | GNUNET_SERVICE_client_continue (client); | ||
1063 | return; | ||
1064 | } | ||
1065 | if (GNUNET_NO == peer->details.local.is_running) | ||
1066 | { | ||
1067 | emsg = update_peer_config (peer, | ||
1068 | cfg); | ||
1069 | if (NULL != emsg) | ||
1070 | GST_send_operation_fail_msg (client, | ||
1071 | op_id, | ||
1072 | emsg); | ||
1073 | GST_send_operation_success_msg (client, | ||
1074 | op_id); | ||
1075 | GNUNET_SERVICE_client_continue (client); | ||
1076 | GNUNET_free (emsg); | ||
1077 | return; | ||
1078 | } | ||
1079 | prc = GNUNET_new (struct PeerReconfigureContext); | ||
1080 | if (GNUNET_OK != | ||
1081 | GNUNET_TESTING_peer_stop_async (peer->details.local.peer, | ||
1082 | &prc_stop_cb, | ||
1083 | prc)) | ||
1084 | { | ||
1085 | GNUNET_assert (0 < GNUNET_asprintf (&emsg, | ||
1086 | "Error trying to stop peer %u asynchronously\n", | ||
1087 | peer_id)); | ||
1088 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1089 | "%s\n", | ||
1090 | emsg); | ||
1091 | GST_send_operation_fail_msg (client, | ||
1092 | op_id, | ||
1093 | emsg); | ||
1094 | GNUNET_SERVICE_client_continue (client); | ||
1095 | GNUNET_free (prc); | ||
1096 | GNUNET_free (emsg); | ||
1097 | return; | ||
1098 | } | ||
1099 | prc->cfg = cfg; | ||
1100 | prc->peer_id = peer_id; | ||
1101 | prc->op_id = op_id; | ||
1102 | prc->client = client; | ||
1103 | GNUNET_CONTAINER_DLL_insert_tail (prc_head, | ||
1104 | prc_tail, | ||
1105 | prc); | ||
1106 | GNUNET_SERVICE_client_continue (client); | ||
1107 | } | ||
1108 | |||
1109 | |||
1110 | /** | ||
1111 | * Frees the ManageServiceContext queue | ||
1112 | */ | ||
1113 | void | ||
1114 | GST_free_mctxq () | ||
1115 | { | ||
1116 | while (NULL != mctx_head) | ||
1117 | cleanup_mctx (mctx_head); | ||
1118 | } | ||
1119 | |||
1120 | |||
1121 | /** | ||
1122 | * Returns a string interpretation of @a rs. | ||
1123 | * | ||
1124 | * @param rs the request status from ARM | ||
1125 | * @return a string interpretation of the request status | ||
1126 | */ | ||
1127 | static const char * | ||
1128 | arm_req_string (enum GNUNET_ARM_RequestStatus rs) | ||
1129 | { | ||
1130 | switch (rs) | ||
1131 | { | ||
1132 | case GNUNET_ARM_REQUEST_SENT_OK: | ||
1133 | return _ ("Message was sent successfully"); | ||
1134 | |||
1135 | case GNUNET_ARM_REQUEST_DISCONNECTED: | ||
1136 | return _ ("We disconnected from ARM before we could send a request"); | ||
1137 | } | ||
1138 | return _ ("Unknown request status"); | ||
1139 | } | ||
1140 | |||
1141 | |||
1142 | /** | ||
1143 | * Returns a string interpretation of the @a result. | ||
1144 | * | ||
1145 | * @param result the arm result | ||
1146 | * @return a string interpretation | ||
1147 | */ | ||
1148 | static const char * | ||
1149 | arm_ret_string (enum GNUNET_ARM_Result result) | ||
1150 | { | ||
1151 | switch (result) | ||
1152 | { | ||
1153 | case GNUNET_ARM_RESULT_STOPPED: | ||
1154 | return _ ("%s is stopped"); | ||
1155 | |||
1156 | case GNUNET_ARM_RESULT_STARTING: | ||
1157 | return _ ("%s is starting"); | ||
1158 | |||
1159 | case GNUNET_ARM_RESULT_STOPPING: | ||
1160 | return _ ("%s is stopping"); | ||
1161 | |||
1162 | case GNUNET_ARM_RESULT_IS_STARTING_ALREADY: | ||
1163 | return _ ("%s is starting already"); | ||
1164 | |||
1165 | case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY: | ||
1166 | return _ ("%s is stopping already"); | ||
1167 | |||
1168 | case GNUNET_ARM_RESULT_IS_STARTED_ALREADY: | ||
1169 | return _ ("%s is started already"); | ||
1170 | |||
1171 | case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY: | ||
1172 | return _ ("%s is stopped already"); | ||
1173 | |||
1174 | case GNUNET_ARM_RESULT_IS_NOT_KNOWN: | ||
1175 | return _ ("%s service is not known to ARM"); | ||
1176 | |||
1177 | case GNUNET_ARM_RESULT_START_FAILED: | ||
1178 | return _ ("%s service failed to start"); | ||
1179 | |||
1180 | case GNUNET_ARM_RESULT_IN_SHUTDOWN: | ||
1181 | return _ ("%s service can't be started because ARM is shutting down"); | ||
1182 | } | ||
1183 | return _ ("%.s Unknown result code."); | ||
1184 | } | ||
1185 | |||
1186 | |||
1187 | /** | ||
1188 | * Function called in response to a start/stop request. | ||
1189 | * Will be called when request was not sent successfully, | ||
1190 | * or when a reply comes. If the request was not sent successfully, | ||
1191 | * @a rs will indicate that, and @a result will be undefined. | ||
1192 | * | ||
1193 | * @param cls ManageServiceContext | ||
1194 | * @param rs status of the request | ||
1195 | * @param result result of the operation | ||
1196 | */ | ||
1197 | static void | ||
1198 | service_manage_result_cb (void *cls, | ||
1199 | enum GNUNET_ARM_RequestStatus rs, | ||
1200 | enum GNUNET_ARM_Result result) | ||
1201 | { | ||
1202 | struct ManageServiceContext *mctx = cls; | ||
1203 | char *emsg; | ||
1204 | |||
1205 | emsg = NULL; | ||
1206 | if (GNUNET_YES == mctx->expired) | ||
1207 | return; | ||
1208 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) | ||
1209 | { | ||
1210 | GNUNET_asprintf (&emsg, | ||
1211 | "Error communicating with Peer %u's ARM: %s", | ||
1212 | mctx->peer->id, | ||
1213 | arm_req_string (rs)); | ||
1214 | goto ret; | ||
1215 | } | ||
1216 | if (1 == mctx->start) | ||
1217 | goto service_start_check; | ||
1218 | if (! ((GNUNET_ARM_RESULT_STOPPED == result) | ||
1219 | || (GNUNET_ARM_RESULT_STOPPING == result) | ||
1220 | || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result) | ||
1221 | || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result))) | ||
1222 | { | ||
1223 | /* stopping a service failed */ | ||
1224 | GNUNET_asprintf (&emsg, | ||
1225 | arm_ret_string (result), | ||
1226 | mctx->service); | ||
1227 | goto ret; | ||
1228 | } | ||
1229 | /* service stopped successfully */ | ||
1230 | goto ret; | ||
1231 | |||
1232 | service_start_check: | ||
1233 | if (! ((GNUNET_ARM_RESULT_STARTING == result) | ||
1234 | || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result) | ||
1235 | || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result))) | ||
1236 | { | ||
1237 | /* starting a service failed */ | ||
1238 | GNUNET_asprintf (&emsg, | ||
1239 | arm_ret_string (result), | ||
1240 | mctx->service); | ||
1241 | goto ret; | ||
1242 | } | ||
1243 | /* service started successfully */ | ||
1244 | |||
1245 | ret: | ||
1246 | if (NULL != emsg) | ||
1247 | { | ||
1248 | LOG_DEBUG ("%s\n", emsg); | ||
1249 | GST_send_operation_fail_msg (mctx->client, | ||
1250 | mctx->op_id, | ||
1251 | emsg); | ||
1252 | } | ||
1253 | else | ||
1254 | GST_send_operation_success_msg (mctx->client, | ||
1255 | mctx->op_id); | ||
1256 | GNUNET_free (emsg); | ||
1257 | cleanup_mctx (mctx); | ||
1258 | } | ||
1259 | |||
1260 | |||
1261 | /** | ||
1262 | * Check #GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE message | ||
1263 | * | ||
1264 | * @param cls identification of client | ||
1265 | * @param msg the actual message | ||
1266 | * @return #GNUNET_OK if @a msg is well-formed | ||
1267 | */ | ||
1268 | int | ||
1269 | check_manage_peer_service (void *cls, | ||
1270 | const struct | ||
1271 | GNUNET_TESTBED_ManagePeerServiceMessage *msg) | ||
1272 | { | ||
1273 | uint16_t msize; | ||
1274 | const char*service; | ||
1275 | |||
1276 | msize = ntohs (msg->header.size); | ||
1277 | service = (const char *) &msg[1]; | ||
1278 | if ('\0' != service[msize - sizeof | ||
1279 | (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1]) | ||
1280 | { | ||
1281 | GNUNET_break_op (0); | ||
1282 | return GNUNET_SYSERR; | ||
1283 | } | ||
1284 | if (1 < msg->start) | ||
1285 | { | ||
1286 | GNUNET_break_op (0); | ||
1287 | return GNUNET_SYSERR; | ||
1288 | } | ||
1289 | return GNUNET_OK; | ||
1290 | } | ||
1291 | |||
1292 | |||
1293 | void | ||
1294 | handle_manage_peer_service (void *cls, | ||
1295 | const struct | ||
1296 | GNUNET_TESTBED_ManagePeerServiceMessage *msg) | ||
1297 | { | ||
1298 | struct GNUNET_SERVICE_Client *client = cls; | ||
1299 | const char*service; | ||
1300 | struct Peer *peer; | ||
1301 | char *emsg; | ||
1302 | struct GNUNET_ARM_Handle *ah; | ||
1303 | struct ManageServiceContext *mctx; | ||
1304 | struct ForwardedOperationContext *fopc; | ||
1305 | uint64_t op_id; | ||
1306 | uint32_t peer_id; | ||
1307 | |||
1308 | service = (const char *) &msg[1]; | ||
1309 | peer_id = ntohl (msg->peer_id); | ||
1310 | op_id = GNUNET_ntohll (msg->operation_id); | ||
1311 | LOG_DEBUG ("Received request to manage service %s on peer %u\n", | ||
1312 | service, (unsigned int) peer_id); | ||
1313 | if ((GST_peer_list_size <= peer_id) | ||
1314 | || (NULL == (peer = GST_peer_list[peer_id]))) | ||
1315 | { | ||
1316 | GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer " | ||
1317 | "with id: %u", peer_id); | ||
1318 | goto err_ret; | ||
1319 | } | ||
1320 | if (0 == strcasecmp ("arm", service)) | ||
1321 | { | ||
1322 | emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. " | ||
1323 | "Use peer start/stop for that"); | ||
1324 | goto err_ret; | ||
1325 | } | ||
1326 | if (GNUNET_YES == peer->is_remote) | ||
1327 | { | ||
1328 | /* Forward the destroy message to sub controller */ | ||
1329 | fopc = GNUNET_new (struct ForwardedOperationContext); | ||
1330 | fopc->client = client; | ||
1331 | fopc->cls = peer; | ||
1332 | fopc->type = OP_MANAGE_SERVICE; | ||
1333 | fopc->operation_id = op_id; | ||
1334 | fopc->opc = | ||
1335 | GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote. | ||
1336 | slave->controller, | ||
1337 | fopc->operation_id, | ||
1338 | &msg->header, | ||
1339 | & | ||
1340 | GST_forwarded_operation_reply_relay, | ||
1341 | fopc); | ||
1342 | fopc->timeout_task = | ||
1343 | GNUNET_SCHEDULER_add_delayed (GST_timeout, | ||
1344 | &GST_forwarded_operation_timeout, | ||
1345 | fopc); | ||
1346 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, | ||
1347 | fopcq_tail, | ||
1348 | fopc); | ||
1349 | GNUNET_SERVICE_client_continue (client); | ||
1350 | return; | ||
1351 | } | ||
1352 | if (GNUNET_NO == peer->details.local.is_running) | ||
1353 | { | ||
1354 | emsg = GNUNET_strdup ("Peer not running\n"); | ||
1355 | goto err_ret; | ||
1356 | } | ||
1357 | if ((0 != peer->reference_cnt) | ||
1358 | && ((0 == strcasecmp ("core", service)) | ||
1359 | || (0 == strcasecmp ("transport", service)))) | ||
1360 | { | ||
1361 | GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u " | ||
1362 | "since it is required by existing operations", | ||
1363 | service, peer_id); | ||
1364 | goto err_ret; | ||
1365 | } | ||
1366 | ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL); | ||
1367 | if (NULL == ah) | ||
1368 | { | ||
1369 | GNUNET_asprintf (&emsg, | ||
1370 | "Cannot connect to ARM service of peer with id: %u", | ||
1371 | peer_id); | ||
1372 | goto err_ret; | ||
1373 | } | ||
1374 | mctx = GNUNET_new (struct ManageServiceContext); | ||
1375 | mctx->peer = peer; | ||
1376 | peer->reference_cnt++; | ||
1377 | mctx->op_id = op_id; | ||
1378 | mctx->ah = ah; | ||
1379 | mctx->client = client; | ||
1380 | mctx->start = msg->start; | ||
1381 | mctx->service = GNUNET_strdup (service); | ||
1382 | GNUNET_CONTAINER_DLL_insert_tail (mctx_head, | ||
1383 | mctx_tail, | ||
1384 | mctx); | ||
1385 | if (1 == mctx->start) | ||
1386 | GNUNET_ARM_request_service_start (mctx->ah, | ||
1387 | service, | ||
1388 | GNUNET_OS_INHERIT_STD_ERR, | ||
1389 | &service_manage_result_cb, | ||
1390 | mctx); | ||
1391 | else | ||
1392 | GNUNET_ARM_request_service_stop (mctx->ah, service, | ||
1393 | &service_manage_result_cb, | ||
1394 | mctx); | ||
1395 | GNUNET_SERVICE_client_continue (client); | ||
1396 | return; | ||
1397 | |||
1398 | err_ret: | ||
1399 | LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg); | ||
1400 | GST_send_operation_fail_msg (client, op_id, emsg); | ||
1401 | GNUNET_free (emsg); | ||
1402 | GNUNET_SERVICE_client_continue (client); | ||
1403 | } | ||
1404 | |||
1405 | |||
1406 | /** | ||
1407 | * Stops and destroys all peers | ||
1408 | */ | ||
1409 | void | ||
1410 | GST_destroy_peers () | ||
1411 | { | ||
1412 | struct Peer *peer; | ||
1413 | unsigned int id; | ||
1414 | |||
1415 | if (NULL == GST_peer_list) | ||
1416 | return; | ||
1417 | for (id = 0; id < GST_peer_list_size; id++) | ||
1418 | { | ||
1419 | peer = GST_peer_list[id]; | ||
1420 | if (NULL == peer) | ||
1421 | continue; | ||
1422 | /* If destroy flag is set it means that this peer should have been | ||
1423 | * destroyed by a context which we destroy before */ | ||
1424 | GNUNET_break (GNUNET_NO == peer->destroy_flag); | ||
1425 | /* counter should be zero as we free all contexts before */ | ||
1426 | GNUNET_break (0 == peer->reference_cnt); | ||
1427 | if ((GNUNET_NO == peer->is_remote) && | ||
1428 | (GNUNET_YES == peer->details.local.is_running)) | ||
1429 | GNUNET_TESTING_peer_kill (peer->details.local.peer); | ||
1430 | } | ||
1431 | for (id = 0; id < GST_peer_list_size; id++) | ||
1432 | { | ||
1433 | peer = GST_peer_list[id]; | ||
1434 | if (NULL == peer) | ||
1435 | continue; | ||
1436 | if (GNUNET_NO == peer->is_remote) | ||
1437 | { | ||
1438 | if (GNUNET_YES == peer->details.local.is_running) | ||
1439 | GNUNET_TESTING_peer_wait (peer->details.local.peer); | ||
1440 | GNUNET_TESTING_peer_destroy (peer->details.local.peer); | ||
1441 | GNUNET_CONFIGURATION_destroy (peer->details.local.cfg); | ||
1442 | } | ||
1443 | GNUNET_free (peer); | ||
1444 | } | ||
1445 | GNUNET_free (GST_peer_list); | ||
1446 | GST_peer_list = NULL; | ||
1447 | GST_peer_list_size = 0; | ||
1448 | } | ||
1449 | |||
1450 | |||
1451 | /** | ||
1452 | * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a | ||
1453 | * success reply is received from all clients and then sends the success message | ||
1454 | * to the client | ||
1455 | * | ||
1456 | * @param cls ForwardedOperationContext | ||
1457 | * @param msg the message to relay | ||
1458 | */ | ||
1459 | static void | ||
1460 | shutdown_peers_reply_cb (void *cls, | ||
1461 | const struct GNUNET_MessageHeader *msg) | ||
1462 | { | ||
1463 | struct ForwardedOperationContext *fo_ctxt = cls; | ||
1464 | struct HandlerContext_ShutdownPeers *hc; | ||
1465 | |||
1466 | hc = fo_ctxt->cls; | ||
1467 | GNUNET_assert (0 < hc->nslaves); | ||
1468 | hc->nslaves--; | ||
1469 | if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS != | ||
1470 | ntohs (msg->type)) | ||
1471 | hc->timeout = GNUNET_YES; | ||
1472 | if (0 == hc->nslaves) | ||
1473 | { | ||
1474 | if (GNUNET_YES == hc->timeout) | ||
1475 | GST_send_operation_fail_msg (fo_ctxt->client, | ||
1476 | fo_ctxt->operation_id, | ||
1477 | "Timeout at a slave controller"); | ||
1478 | else | ||
1479 | GST_send_operation_success_msg (fo_ctxt->client, | ||
1480 | fo_ctxt->operation_id); | ||
1481 | GNUNET_free (hc); | ||
1482 | hc = NULL; | ||
1483 | } | ||
1484 | GNUNET_CONTAINER_DLL_remove (fopcq_head, | ||
1485 | fopcq_tail, | ||
1486 | fo_ctxt); | ||
1487 | GNUNET_free (fo_ctxt); | ||
1488 | } | ||
1489 | |||
1490 | |||
1491 | /** | ||
1492 | * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages | ||
1493 | * | ||
1494 | * @param cls identification of the client | ||
1495 | * @param msg the actual message | ||
1496 | */ | ||
1497 | void | ||
1498 | handle_shutdown_peers (void *cls, | ||
1499 | const struct GNUNET_TESTBED_ShutdownPeersMessage *msg) | ||
1500 | { | ||
1501 | struct GNUNET_SERVICE_Client *client = cls; | ||
1502 | struct HandlerContext_ShutdownPeers *hc; | ||
1503 | struct Slave *slave; | ||
1504 | struct ForwardedOperationContext *fo_ctxt; | ||
1505 | uint64_t op_id; | ||
1506 | unsigned int cnt; | ||
1507 | |||
1508 | LOG_DEBUG ("Received SHUTDOWN_PEERS\n"); | ||
1509 | /* Stop and destroy all peers */ | ||
1510 | GST_free_mctxq (); | ||
1511 | GST_free_occq (); | ||
1512 | GST_free_roccq (); | ||
1513 | GST_clear_fopcq (); | ||
1514 | /* Forward to all slaves which we have started */ | ||
1515 | op_id = GNUNET_ntohll (msg->operation_id); | ||
1516 | hc = GNUNET_new (struct HandlerContext_ShutdownPeers); | ||
1517 | /* FIXME: have a better implementation where we track which slaves are | ||
1518 | started by this controller */ | ||
1519 | for (cnt = 0; cnt < GST_slave_list_size; cnt++) | ||
1520 | { | ||
1521 | slave = GST_slave_list[cnt]; | ||
1522 | if (NULL == slave) | ||
1523 | continue; | ||
1524 | if (NULL == slave->controller_proc) /* We didn't start the slave */ | ||
1525 | continue; | ||
1526 | LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n"); | ||
1527 | hc->nslaves++; | ||
1528 | fo_ctxt = GNUNET_new (struct ForwardedOperationContext); | ||
1529 | fo_ctxt->client = client; | ||
1530 | fo_ctxt->operation_id = op_id; | ||
1531 | fo_ctxt->cls = hc; | ||
1532 | fo_ctxt->type = OP_SHUTDOWN_PEERS; | ||
1533 | fo_ctxt->opc = | ||
1534 | GNUNET_TESTBED_forward_operation_msg_ (slave->controller, | ||
1535 | fo_ctxt->operation_id, | ||
1536 | &msg->header, | ||
1537 | shutdown_peers_reply_cb, | ||
1538 | fo_ctxt); | ||
1539 | GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, | ||
1540 | fopcq_tail, | ||
1541 | fo_ctxt); | ||
1542 | } | ||
1543 | LOG_DEBUG ("Shutting down peers\n"); | ||
1544 | GST_destroy_peers (); | ||
1545 | if (0 == hc->nslaves) | ||
1546 | { | ||
1547 | GST_send_operation_success_msg (client, | ||
1548 | op_id); | ||
1549 | GNUNET_free (hc); | ||
1550 | } | ||
1551 | GNUNET_SERVICE_client_continue (client); | ||
1552 | } | ||