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