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