aboutsummaryrefslogtreecommitdiff
path: root/src
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
parentf2257ba6dd452dddb4a425689a1c137433b5f578 (diff)
downloadgnunet-6f3ff8ff3db35d2a5c02e8cc88a912e9e0106d7c.tar.gz
gnunet-6f3ff8ff3db35d2a5c02e8cc88a912e9e0106d7c.zip
- restructure
Diffstat (limited to 'src')
-rw-r--r--src/testbed/Makefile.am3
-rw-r--r--src/testbed/gnunet-service-testbed.c1112
-rw-r--r--src/testbed/gnunet-service-testbed.h159
-rw-r--r--src/testbed/gnunet-service-testbed_oc.c9
-rw-r--r--src/testbed/gnunet-service-testbed_peers.c1138
5 files changed, 1322 insertions, 1099 deletions
diff --git a/src/testbed/Makefile.am b/src/testbed/Makefile.am
index d980e8b6e..97e304ff3 100644
--- a/src/testbed/Makefile.am
+++ b/src/testbed/Makefile.am
@@ -30,8 +30,9 @@ bin_PROGRAMS = \
30 gnunet-testbed-profiler 30 gnunet-testbed-profiler
31 31
32gnunet_service_testbed_SOURCES = \ 32gnunet_service_testbed_SOURCES = \
33 gnunet-service-testbed.c \
34 gnunet-service-testbed.h \ 33 gnunet-service-testbed.h \
34 gnunet-service-testbed.c \
35 gnunet-service-testbed_peers.c \
35 gnunet-service-testbed_cache.c \ 36 gnunet-service-testbed_cache.c \
36 gnunet-service-testbed_oc.c \ 37 gnunet-service-testbed_oc.c \
37 gnunet-service-testbed_cpustatus.c 38 gnunet-service-testbed_cpustatus.c
diff --git a/src/testbed/gnunet-service-testbed.c b/src/testbed/gnunet-service-testbed.c
index a1c7f02be..05668284b 100644
--- a/src/testbed/gnunet-service-testbed.c
+++ b/src/testbed/gnunet-service-testbed.c
@@ -25,28 +25,6 @@
25 */ 25 */
26 26
27#include "gnunet-service-testbed.h" 27#include "gnunet-service-testbed.h"
28#include "gnunet_arm_service.h"
29
30#include <zlib.h>
31
32
33/**
34 * Context data for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS handler
35 */
36struct HandlerContext_ShutdownPeers
37{
38 /**
39 * The number of slave we expect to hear from since we forwarded the
40 * GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS message to them
41 */
42 unsigned int nslaves;
43
44 /**
45 * Did we observe a timeout with respect to this operation at any of the
46 * slaves
47 */
48 int timeout;
49};
50 28
51 29
52/***********/ 30/***********/
@@ -69,11 +47,6 @@ struct Context *GST_context;
69struct Slave **GST_slave_list; 47struct Slave **GST_slave_list;
70 48
71/** 49/**
72 * A list of peers we know about
73 */
74struct Peer **GST_peer_list;
75
76/**
77 * Array of hosts 50 * Array of hosts
78 */ 51 */
79struct GNUNET_TESTBED_Host **GST_host_list; 52struct GNUNET_TESTBED_Host **GST_host_list;
@@ -277,30 +250,6 @@ GST_queue_message (struct GNUNET_SERVER_Client *client,
277 250
278 251
279/** 252/**
280 * Similar to GNUNET_array_grow(); however instead of calling GNUNET_array_grow()
281 * several times we call it only once. The array is also made to grow in steps
282 * of LIST_GROW_STEP.
283 *
284 * @param ptr the array pointer to grow
285 * @param size the size of array
286 * @param accommodate_size the size which the array has to accommdate; after
287 * this call the array will be big enough to accommdate sizes upto
288 * accommodate_size
289 */
290#define array_grow_large_enough(ptr, size, accommodate_size) \
291 do \
292 { \
293 unsigned int growth_size; \
294 GNUNET_assert (size <= accommodate_size); \
295 growth_size = size; \
296 while (growth_size <= accommodate_size) \
297 growth_size += LIST_GROW_STEP; \
298 GNUNET_array_grow (ptr, size, growth_size); \
299 GNUNET_assert (size > accommodate_size); \
300 } while (0)
301
302
303/**
304 * Function to add a host to the current list of known hosts 253 * Function to add a host to the current list of known hosts
305 * 254 *
306 * @param host the host to add 255 * @param host the host to add
@@ -314,7 +263,7 @@ host_list_add (struct GNUNET_TESTBED_Host *host)
314 263
315 host_id = GNUNET_TESTBED_host_get_id_ (host); 264 host_id = GNUNET_TESTBED_host_get_id_ (host);
316 if (GST_host_list_size <= host_id) 265 if (GST_host_list_size <= host_id)
317 array_grow_large_enough (GST_host_list, GST_host_list_size, host_id); 266 GST_array_grow_large_enough (GST_host_list, GST_host_list_size, host_id);
318 if (NULL != GST_host_list[host_id]) 267 if (NULL != GST_host_list[host_id])
319 { 268 {
320 LOG_DEBUG ("A host with id: %u already exists\n", host_id); 269 LOG_DEBUG ("A host with id: %u already exists\n", host_id);
@@ -334,7 +283,7 @@ static void
334route_list_add (struct Route *route) 283route_list_add (struct Route *route)
335{ 284{
336 if (route->dest >= route_list_size) 285 if (route->dest >= route_list_size)
337 array_grow_large_enough (route_list, route_list_size, route->dest); 286 GST_array_grow_large_enough (route_list, route_list_size, route->dest);
338 GNUNET_assert (NULL == route_list[route->dest]); 287 GNUNET_assert (NULL == route_list[route->dest]);
339 route_list[route->dest] = route; 288 route_list[route->dest] = route;
340} 289}
@@ -349,61 +298,14 @@ static void
349slave_list_add (struct Slave *slave) 298slave_list_add (struct Slave *slave)
350{ 299{
351 if (slave->host_id >= GST_slave_list_size) 300 if (slave->host_id >= GST_slave_list_size)
352 array_grow_large_enough (GST_slave_list, GST_slave_list_size, 301 GST_array_grow_large_enough (GST_slave_list, GST_slave_list_size,
353 slave->host_id); 302 slave->host_id);
354 GNUNET_assert (NULL == GST_slave_list[slave->host_id]); 303 GNUNET_assert (NULL == GST_slave_list[slave->host_id]);
355 GST_slave_list[slave->host_id] = slave; 304 GST_slave_list[slave->host_id] = slave;
356} 305}
357 306
358 307
359/** 308/**
360 * Adds a peer to the peer array
361 *
362 * @param peer the peer to add
363 */
364static void
365peer_list_add (struct Peer *peer)
366{
367 if (peer->id >= GST_peer_list_size)
368 array_grow_large_enough (GST_peer_list, GST_peer_list_size, peer->id);
369 GNUNET_assert (NULL == GST_peer_list[peer->id]);
370 GST_peer_list[peer->id] = peer;
371}
372
373
374/**
375 * Removes a the give peer from the peer array
376 *
377 * @param peer the peer to be removed
378 */
379static void
380peer_list_remove (struct Peer *peer)
381{
382 unsigned int orig_size;
383 uint32_t id;
384
385 GST_peer_list[peer->id] = NULL;
386 orig_size = GST_peer_list_size;
387 while (GST_peer_list_size >= LIST_GROW_STEP)
388 {
389 for (id = GST_peer_list_size - 1;
390 (id >= GST_peer_list_size - LIST_GROW_STEP) && (id != UINT32_MAX);
391 id--)
392 if (NULL != GST_peer_list[id])
393 break;
394 if (id != ((GST_peer_list_size - LIST_GROW_STEP) - 1))
395 break;
396 GST_peer_list_size -= LIST_GROW_STEP;
397 }
398 if (orig_size == GST_peer_list_size)
399 return;
400 GST_peer_list =
401 GNUNET_realloc (GST_peer_list,
402 sizeof (struct Peer *) * GST_peer_list_size);
403}
404
405
406/**
407 * Finds the route with directly connected host as destination through which 309 * Finds the route with directly connected host as destination through which
408 * the destination host can be reached 310 * the destination host can be reached
409 * 311 *
@@ -476,9 +378,9 @@ GST_send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
476 * @param client the client to send the message to 378 * @param client the client to send the message to
477 * @param operation_id the id of the operation which was successful 379 * @param operation_id the id of the operation which was successful
478 */ 380 */
479static void 381void
480send_operation_success_msg (struct GNUNET_SERVER_Client *client, 382GST_send_operation_success_msg (struct GNUNET_SERVER_Client *client,
481 uint64_t operation_id) 383 uint64_t operation_id)
482{ 384{
483 struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg; 385 struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
484 uint16_t msize; 386 uint16_t msize;
@@ -1415,530 +1317,6 @@ handle_link_controllers (void *cls, struct GNUNET_SERVER_Client *client,
1415 1317
1416 1318
1417/** 1319/**
1418 * The task to be executed if the forwarded peer create operation has been
1419 * timed out
1420 *
1421 * @param cls the FowardedOperationContext
1422 * @param tc the TaskContext from the scheduler
1423 */
1424static void
1425peer_create_forward_timeout (void *cls,
1426 const struct GNUNET_SCHEDULER_TaskContext *tc)
1427{
1428 struct ForwardedOperationContext *fopc = cls;
1429
1430 GNUNET_free (fopc->cls);
1431 GST_forwarded_operation_timeout (fopc, tc);
1432}
1433
1434
1435/**
1436 * Callback to be called when forwarded peer create operation is successfull. We
1437 * have to relay the reply msg back to the client
1438 *
1439 * @param cls ForwardedOperationContext
1440 * @param msg the peer create success message
1441 */
1442static void
1443peer_create_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1444{
1445 struct ForwardedOperationContext *fopc = cls;
1446 struct Peer *remote_peer;
1447
1448 if (ntohs (msg->type) == GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS)
1449 {
1450 GNUNET_assert (NULL != fopc->cls);
1451 remote_peer = fopc->cls;
1452 peer_list_add (remote_peer);
1453 }
1454 GST_forwarded_operation_reply_relay (fopc, msg);
1455}
1456
1457
1458/**
1459 * Function to destroy a peer
1460 *
1461 * @param peer the peer structure to destroy
1462 */
1463void
1464GST_destroy_peer (struct Peer *peer)
1465{
1466 GNUNET_break (0 == peer->reference_cnt);
1467 if (GNUNET_YES == peer->is_remote)
1468 {
1469 peer_list_remove (peer);
1470 GNUNET_free (peer);
1471 return;
1472 }
1473 if (GNUNET_YES == peer->details.local.is_running)
1474 {
1475 GNUNET_TESTING_peer_stop (peer->details.local.peer);
1476 peer->details.local.is_running = GNUNET_NO;
1477 }
1478 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
1479 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
1480 peer_list_remove (peer);
1481 GNUNET_free (peer);
1482}
1483
1484
1485/**
1486 * Callback to be called when forwarded peer destroy operation is successfull. We
1487 * have to relay the reply msg back to the client
1488 *
1489 * @param cls ForwardedOperationContext
1490 * @param msg the peer create success message
1491 */
1492static void
1493peer_destroy_success_cb (void *cls, const struct GNUNET_MessageHeader *msg)
1494{
1495 struct ForwardedOperationContext *fopc = cls;
1496 struct Peer *remote_peer;
1497
1498 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS ==
1499 ntohs (msg->type))
1500 {
1501 remote_peer = fopc->cls;
1502 GNUNET_assert (NULL != remote_peer);
1503 remote_peer->destroy_flag = GNUNET_YES;
1504 if (0 == remote_peer->reference_cnt)
1505 GST_destroy_peer (remote_peer);
1506 }
1507 GST_forwarded_operation_reply_relay (fopc, msg);
1508}
1509
1510
1511
1512/**
1513 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
1514 *
1515 * @param cls NULL
1516 * @param client identification of the client
1517 * @param message the actual message
1518 */
1519static void
1520handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
1521 const struct GNUNET_MessageHeader *message)
1522{
1523 const struct GNUNET_TESTBED_PeerCreateMessage *msg;
1524 struct GNUNET_TESTBED_PeerCreateSuccessEventMessage *reply;
1525 struct GNUNET_CONFIGURATION_Handle *cfg;
1526 struct ForwardedOperationContext *fo_ctxt;
1527 struct Route *route;
1528 struct Peer *peer;
1529 char *config;
1530 size_t dest_size;
1531 int ret;
1532 uint32_t config_size;
1533 uint32_t host_id;
1534 uint32_t peer_id;
1535 uint16_t msize;
1536
1537
1538 msize = ntohs (message->size);
1539 if (msize <= sizeof (struct GNUNET_TESTBED_PeerCreateMessage))
1540 {
1541 GNUNET_break (0); /* We need configuration */
1542 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1543 return;
1544 }
1545 msg = (const struct GNUNET_TESTBED_PeerCreateMessage *) message;
1546 host_id = ntohl (msg->host_id);
1547 peer_id = ntohl (msg->peer_id);
1548 if (UINT32_MAX == peer_id)
1549 {
1550 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1551 "Cannot create peer with given ID");
1552 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1553 return;
1554 }
1555 if (host_id == GST_context->host_id)
1556 {
1557 char *emsg;
1558
1559 /* We are responsible for this peer */
1560 msize -= sizeof (struct GNUNET_TESTBED_PeerCreateMessage);
1561 config_size = ntohl (msg->config_size);
1562 config = GNUNET_malloc (config_size);
1563 dest_size = config_size;
1564 if (Z_OK !=
1565 (ret =
1566 uncompress ((Bytef *) config, (uLongf *) & dest_size,
1567 (const Bytef *) &msg[1], (uLong) msize)))
1568 {
1569 GNUNET_break (0); /* uncompression error */
1570 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1571 return;
1572 }
1573 if (config_size != dest_size)
1574 {
1575 GNUNET_break (0); /* Uncompressed config size mismatch */
1576 GNUNET_free (config);
1577 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1578 return;
1579 }
1580 cfg = GNUNET_CONFIGURATION_create ();
1581 if (GNUNET_OK !=
1582 GNUNET_CONFIGURATION_deserialize (cfg, config, config_size, GNUNET_NO))
1583 {
1584 GNUNET_break (0); /* Configuration parsing error */
1585 GNUNET_free (config);
1586 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1587 return;
1588 }
1589 GNUNET_free (config);
1590 GNUNET_CONFIGURATION_set_value_number (cfg, "TESTBED", "PEERID",
1591 (unsigned long long) peer_id);
1592 peer = GNUNET_malloc (sizeof (struct Peer));
1593 peer->is_remote = GNUNET_NO;
1594 peer->details.local.cfg = cfg;
1595 peer->id = peer_id;
1596 LOG_DEBUG ("Creating peer with id: %u\n", (unsigned int) peer->id);
1597 peer->details.local.peer =
1598 GNUNET_TESTING_peer_configure (GST_context->system,
1599 peer->details.local.cfg, peer->id,
1600 NULL /* Peer id */ ,
1601 &emsg);
1602 if (NULL == peer->details.local.peer)
1603 {
1604 LOG (GNUNET_ERROR_TYPE_WARNING, "Configuring peer failed: %s\n", emsg);
1605 GNUNET_free (emsg);
1606 GNUNET_free (peer);
1607 GNUNET_break (0);
1608 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1609 return;
1610 }
1611 peer->details.local.is_running = GNUNET_NO;
1612 peer_list_add (peer);
1613 reply =
1614 GNUNET_malloc (sizeof
1615 (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1616 reply->header.size =
1617 htons (sizeof (struct GNUNET_TESTBED_PeerCreateSuccessEventMessage));
1618 reply->header.type =
1619 htons (GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER_SUCCESS);
1620 reply->peer_id = msg->peer_id;
1621 reply->operation_id = msg->operation_id;
1622 GST_queue_message (client, &reply->header);
1623 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1624 return;
1625 }
1626
1627 /* Forward peer create request */
1628 route = GST_find_dest_route (host_id);
1629 if (NULL == route)
1630 {
1631 GNUNET_break (0);
1632 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1633 return;
1634 }
1635
1636 peer = GNUNET_malloc (sizeof (struct Peer));
1637 peer->is_remote = GNUNET_YES;
1638 peer->id = peer_id;
1639 peer->details.remote.slave = GST_slave_list[route->dest];
1640 peer->details.remote.remote_host_id = host_id;
1641 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1642 GNUNET_SERVER_client_keep (client);
1643 fo_ctxt->client = client;
1644 fo_ctxt->operation_id = GNUNET_ntohll (msg->operation_id);
1645 fo_ctxt->cls = peer; //GST_slave_list[route->dest]->controller;
1646 fo_ctxt->type = OP_PEER_CREATE;
1647 fo_ctxt->opc =
1648 GNUNET_TESTBED_forward_operation_msg_ (GST_slave_list
1649 [route->dest]->controller,
1650 fo_ctxt->operation_id,
1651 &msg->header,
1652 peer_create_success_cb, fo_ctxt);
1653 fo_ctxt->timeout_task =
1654 GNUNET_SCHEDULER_add_delayed (GST_timeout, &peer_create_forward_timeout,
1655 fo_ctxt);
1656 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
1657 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1658}
1659
1660
1661/**
1662 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1663 *
1664 * @param cls NULL
1665 * @param client identification of the client
1666 * @param message the actual message
1667 */
1668static void
1669handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
1670 const struct GNUNET_MessageHeader *message)
1671{
1672 const struct GNUNET_TESTBED_PeerDestroyMessage *msg;
1673 struct ForwardedOperationContext *fopc;
1674 struct Peer *peer;
1675 uint32_t peer_id;
1676
1677 msg = (const struct GNUNET_TESTBED_PeerDestroyMessage *) message;
1678 peer_id = ntohl (msg->peer_id);
1679 LOG_DEBUG ("Received peer destory on peer: %u and operation id: %ul\n",
1680 peer_id, GNUNET_ntohll (msg->operation_id));
1681 if ((GST_peer_list_size <= peer_id) || (NULL == GST_peer_list[peer_id]))
1682 {
1683 LOG (GNUNET_ERROR_TYPE_ERROR,
1684 "Asked to destroy a non existent peer with id: %u\n", peer_id);
1685 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1686 "Peer doesn't exist");
1687 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1688 return;
1689 }
1690 peer = GST_peer_list[peer_id];
1691 if (GNUNET_YES == peer->is_remote)
1692 {
1693 /* Forward the destory message to sub controller */
1694 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1695 GNUNET_SERVER_client_keep (client);
1696 fopc->client = client;
1697 fopc->cls = peer;
1698 fopc->type = OP_PEER_DESTROY;
1699 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1700 fopc->opc =
1701 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1702 slave->controller,
1703 fopc->operation_id, &msg->header,
1704 &peer_destroy_success_cb, fopc);
1705 fopc->timeout_task =
1706 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1707 fopc);
1708 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1709 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1710 return;
1711 }
1712 peer->destroy_flag = GNUNET_YES;
1713 if (0 == peer->reference_cnt)
1714 GST_destroy_peer (peer);
1715 else
1716 LOG (GNUNET_ERROR_TYPE_DEBUG,
1717 "Delaying peer destroy as peer is currently in use\n");
1718 send_operation_success_msg (client, GNUNET_ntohll (msg->operation_id));
1719 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1720}
1721
1722
1723/**
1724 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1725 *
1726 * @param cls NULL
1727 * @param client identification of the client
1728 * @param message the actual message
1729 */
1730static void
1731handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
1732 const struct GNUNET_MessageHeader *message)
1733{
1734 const struct GNUNET_TESTBED_PeerStartMessage *msg;
1735 struct GNUNET_TESTBED_PeerEventMessage *reply;
1736 struct ForwardedOperationContext *fopc;
1737 struct Peer *peer;
1738 uint32_t peer_id;
1739
1740 msg = (const struct GNUNET_TESTBED_PeerStartMessage *) message;
1741 peer_id = ntohl (msg->peer_id);
1742 if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1743 {
1744 GNUNET_break (0);
1745 LOG (GNUNET_ERROR_TYPE_ERROR,
1746 "Asked to start a non existent peer with id: %u\n", peer_id);
1747 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1748 return;
1749 }
1750 peer = GST_peer_list[peer_id];
1751 if (GNUNET_YES == peer->is_remote)
1752 {
1753 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1754 GNUNET_SERVER_client_keep (client);
1755 fopc->client = client;
1756 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1757 fopc->type = OP_PEER_START;
1758 fopc->opc =
1759 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1760 slave->controller,
1761 fopc->operation_id, &msg->header,
1762 &GST_forwarded_operation_reply_relay,
1763 fopc);
1764 fopc->timeout_task =
1765 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1766 fopc);
1767 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1768 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1769 return;
1770 }
1771 if (GNUNET_OK != GNUNET_TESTING_peer_start (peer->details.local.peer))
1772 {
1773 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1774 "Failed to start");
1775 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1776 return;
1777 }
1778 peer->details.local.is_running = GNUNET_YES;
1779 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1780 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
1781 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1782 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_START);
1783 reply->host_id = htonl (GST_context->host_id);
1784 reply->peer_id = msg->peer_id;
1785 reply->operation_id = msg->operation_id;
1786 GST_queue_message (client, &reply->header);
1787 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1788}
1789
1790
1791/**
1792 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
1793 *
1794 * @param cls NULL
1795 * @param client identification of the client
1796 * @param message the actual message
1797 */
1798static void
1799handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
1800 const struct GNUNET_MessageHeader *message)
1801{
1802 const struct GNUNET_TESTBED_PeerStopMessage *msg;
1803 struct GNUNET_TESTBED_PeerEventMessage *reply;
1804 struct ForwardedOperationContext *fopc;
1805 struct Peer *peer;
1806 uint32_t peer_id;
1807
1808 msg = (const struct GNUNET_TESTBED_PeerStopMessage *) message;
1809 peer_id = ntohl (msg->peer_id);
1810 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received PEER_STOP for peer %u\n", peer_id);
1811 if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1812 {
1813 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1814 "Peer not found");
1815 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1816 return;
1817 }
1818 peer = GST_peer_list[peer_id];
1819 if (GNUNET_YES == peer->is_remote)
1820 {
1821 LOG (GNUNET_ERROR_TYPE_DEBUG, "Forwarding PEER_STOP for peer %u\n",
1822 peer_id);
1823 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1824 GNUNET_SERVER_client_keep (client);
1825 fopc->client = client;
1826 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1827 fopc->type = OP_PEER_STOP;
1828 fopc->opc =
1829 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1830 slave->controller,
1831 fopc->operation_id, &msg->header,
1832 &GST_forwarded_operation_reply_relay,
1833 fopc);
1834 fopc->timeout_task =
1835 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1836 fopc);
1837 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1838 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1839 return;
1840 }
1841 if (GNUNET_OK != GNUNET_TESTING_peer_kill (peer->details.local.peer))
1842 {
1843 LOG (GNUNET_ERROR_TYPE_WARNING, "Stopping peer %u failed\n", peer_id);
1844 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1845 "Peer not running");
1846 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1847 return;
1848 }
1849 LOG (GNUNET_ERROR_TYPE_DEBUG, "Peer %u successfully stopped\n", peer_id);
1850 peer->details.local.is_running = GNUNET_NO;
1851 reply = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1852 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_EVENT);
1853 reply->header.size = htons (sizeof (struct GNUNET_TESTBED_PeerEventMessage));
1854 reply->event_type = htonl (GNUNET_TESTBED_ET_PEER_STOP);
1855 reply->host_id = htonl (GST_context->host_id);
1856 reply->peer_id = msg->peer_id;
1857 reply->operation_id = msg->operation_id;
1858 GST_queue_message (client, &reply->header);
1859 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1860 GNUNET_TESTING_peer_wait (peer->details.local.peer);
1861}
1862
1863
1864/**
1865 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
1866 *
1867 * @param cls NULL
1868 * @param client identification of the client
1869 * @param message the actual message
1870 */
1871static void
1872handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1873 const struct GNUNET_MessageHeader *message)
1874{
1875 const struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
1876 struct GNUNET_TESTBED_PeerConfigurationInformationMessage *reply;
1877 struct Peer *peer;
1878 char *config;
1879 char *xconfig;
1880 size_t c_size;
1881 size_t xc_size;
1882 uint32_t peer_id;
1883 uint16_t msize;
1884
1885 msg = (const struct GNUNET_TESTBED_PeerGetConfigurationMessage *) message;
1886 peer_id = ntohl (msg->peer_id);
1887 if ((peer_id >= GST_peer_list_size) || (NULL == GST_peer_list[peer_id]))
1888 {
1889 GST_send_operation_fail_msg (client, GNUNET_ntohll (msg->operation_id),
1890 "Peer not found");
1891 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1892 return;
1893 }
1894 peer = GST_peer_list[peer_id];
1895 if (GNUNET_YES == peer->is_remote)
1896 {
1897 struct ForwardedOperationContext *fopc;
1898
1899 LOG_DEBUG ("Forwarding PEER_GET_CONFIG for peer: %u\n", peer_id);
1900 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
1901 GNUNET_SERVER_client_keep (client);
1902 fopc->client = client;
1903 fopc->operation_id = GNUNET_ntohll (msg->operation_id);
1904 fopc->type = OP_PEER_INFO;
1905 fopc->opc =
1906 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
1907 slave->controller,
1908 fopc->operation_id, &msg->header,
1909 &GST_forwarded_operation_reply_relay,
1910 fopc);
1911 fopc->timeout_task =
1912 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
1913 fopc);
1914 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
1915 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1916 return;
1917 }
1918 LOG_DEBUG ("Received PEER_GET_CONFIG for peer: %u\n", peer_id);
1919 config =
1920 GNUNET_CONFIGURATION_serialize (GST_peer_list[peer_id]->details.local.cfg,
1921 &c_size);
1922 xc_size = GNUNET_TESTBED_compress_config_ (config, c_size, &xconfig);
1923 GNUNET_free (config);
1924 msize =
1925 xc_size +
1926 sizeof (struct GNUNET_TESTBED_PeerConfigurationInformationMessage);
1927 reply = GNUNET_realloc (xconfig, msize);
1928 (void) memmove (&reply[1], reply, xc_size);
1929 reply->header.size = htons (msize);
1930 reply->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_PEER_CONFIGURATION);
1931 reply->peer_id = msg->peer_id;
1932 reply->operation_id = msg->operation_id;
1933 GNUNET_TESTING_peer_get_identity (GST_peer_list[peer_id]->details.local.peer,
1934 &reply->peer_identity);
1935 reply->config_size = htons ((uint16_t) c_size);
1936 GST_queue_message (client, &reply->header);
1937 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1938}
1939
1940
1941/**
1942 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages 1320 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
1943 * 1321 *
1944 * @param cls NULL 1322 * @param cls NULL
@@ -1991,286 +1369,12 @@ handle_slave_get_config (void *cls, struct GNUNET_SERVER_Client *client,
1991 GNUNET_SERVER_receive_done (client, GNUNET_OK); 1369 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1992} 1370}
1993 1371
1994struct ManageServiceContext
1995{
1996
1997 struct ManageServiceContext *next;
1998
1999 struct ManageServiceContext *prev;
2000
2001 struct GNUNET_ARM_Handle *ah;
2002
2003 struct Peer *peer;
2004
2005 struct GNUNET_SERVER_Client *client;
2006
2007 uint64_t op_id;
2008
2009 uint8_t start;
2010
2011 uint8_t expired;
2012
2013};
2014
2015static struct ManageServiceContext *mctx_head;
2016
2017static struct ManageServiceContext *mctx_tail;
2018
2019static void
2020cleanup_mctx (struct ManageServiceContext *mctx)
2021{
2022 mctx->expired = GNUNET_YES;
2023 GNUNET_CONTAINER_DLL_remove (mctx_head, mctx_tail, mctx);
2024 GNUNET_SERVER_client_drop (mctx->client);
2025 GNUNET_ARM_disconnect_and_free (mctx->ah);
2026 GNUNET_assert (0 < mctx->peer->reference_cnt);
2027 mctx->peer->reference_cnt--;
2028 if ( (GNUNET_YES == mctx->peer->destroy_flag)
2029 && (0 == mctx->peer->reference_cnt) )
2030 GST_destroy_peer (mctx->peer);
2031 GNUNET_free (mctx);
2032}
2033
2034static void
2035free_mctxq ()
2036{
2037 while (NULL != mctx_head)
2038 cleanup_mctx (mctx_head);
2039}
2040
2041static const char *
2042arm_req_string (enum GNUNET_ARM_RequestStatus rs)
2043{
2044 switch (rs)
2045 {
2046 case GNUNET_ARM_REQUEST_SENT_OK:
2047 return _("Message was sent successfully");
2048 case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR:
2049 return _("Misconfiguration (can't connect to the ARM service)");
2050 case GNUNET_ARM_REQUEST_DISCONNECTED:
2051 return _("We disconnected from ARM before we could send a request");
2052 case GNUNET_ARM_REQUEST_BUSY:
2053 return _("ARM API is busy");
2054 case GNUNET_ARM_REQUEST_TOO_LONG:
2055 return _("Request doesn't fit into a message");
2056 case GNUNET_ARM_REQUEST_TIMEOUT:
2057 return _("Request timed out");
2058 }
2059 return _("Unknown request status");
2060}
2061
2062static const char *
2063arm_ret_string (enum GNUNET_ARM_Result result)
2064{
2065 switch (result)
2066 {
2067 case GNUNET_ARM_RESULT_STOPPED:
2068 return _("%s is stopped");
2069 case GNUNET_ARM_RESULT_STARTING:
2070 return _("%s is starting");
2071 case GNUNET_ARM_RESULT_STOPPING:
2072 return _("%s is stopping");
2073 case GNUNET_ARM_RESULT_IS_STARTING_ALREADY:
2074 return _("%s is starting already");
2075 case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY:
2076 return _("%s is stopping already");
2077 case GNUNET_ARM_RESULT_IS_STARTED_ALREADY:
2078 return _("%s is started already");
2079 case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY:
2080 return _("%s is stopped already");
2081 case GNUNET_ARM_RESULT_IS_NOT_KNOWN:
2082 return _("%s service is not known to ARM");
2083 case GNUNET_ARM_RESULT_START_FAILED:
2084 return _("%s service failed to start");
2085 case GNUNET_ARM_RESULT_IN_SHUTDOWN:
2086 return _("%s service can't be started because ARM is shutting down");
2087 }
2088 return _("%.s Unknown result code.");
2089}
2090
2091static void
2092service_manage_result_cb (void *cls, struct GNUNET_ARM_Handle *arm,
2093 enum GNUNET_ARM_RequestStatus rs,
2094 const char *service, enum GNUNET_ARM_Result result)
2095{
2096 struct ManageServiceContext *mctx = cls;
2097 char *emsg;
2098
2099 emsg = NULL;
2100 if (GNUNET_YES == mctx->expired)
2101 return;
2102 if (GNUNET_ARM_REQUEST_SENT_OK != rs)
2103 {
2104 GNUNET_asprintf (&emsg, "Error communicating with Peer %u's ARM: %s",
2105 mctx->peer->id, arm_req_string (rs));
2106 goto ret;
2107 }
2108 if (1 == mctx->start)
2109 goto service_start_check;
2110 if (! ((GNUNET_ARM_RESULT_STOPPED == result)
2111 || (GNUNET_ARM_RESULT_STOPPING == result)
2112 || (GNUNET_ARM_RESULT_IS_STOPPING_ALREADY == result)
2113 || (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) )
2114 {
2115 /* stopping a service failed */
2116 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
2117 goto ret;
2118 }
2119 /* service stopped successfully */
2120 goto ret;
2121
2122 service_start_check:
2123 if (! ((GNUNET_ARM_RESULT_STARTING == result)
2124 || (GNUNET_ARM_RESULT_IS_STARTING_ALREADY == result)
2125 || (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) )
2126 {
2127 /* starting a service failed */
2128 GNUNET_asprintf (&emsg, arm_ret_string (result), service);
2129 goto ret;
2130 }
2131 /* service started successfully */
2132
2133 ret:
2134 if (NULL != emsg)
2135 {
2136 LOG_DEBUG ("%s\n", emsg);
2137 GST_send_operation_fail_msg (mctx->client, mctx->op_id, emsg);
2138 }
2139 else
2140 send_operation_success_msg (mctx->client, mctx->op_id);
2141 GNUNET_free_non_null (emsg);
2142 cleanup_mctx (mctx);
2143}
2144
2145static void
2146handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
2147 const struct GNUNET_MessageHeader *message)
2148{
2149 const struct GNUNET_TESTBED_ManagePeerServiceMessage *msg;
2150 const char* service;
2151 struct Peer *peer;
2152 char *emsg;
2153 struct GNUNET_ARM_Handle *ah;
2154 struct ManageServiceContext *mctx;
2155 struct ForwardedOperationContext *fopc;
2156 uint64_t op_id;
2157 uint32_t peer_id;
2158 uint16_t msize;
2159
2160
2161 msize = ntohs (message->size);
2162 if (msize <= sizeof (struct GNUNET_TESTBED_ManagePeerServiceMessage))
2163 {
2164 GNUNET_break_op (0);
2165 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2166 return;
2167 }
2168 msg = (const struct GNUNET_TESTBED_ManagePeerServiceMessage *) message;
2169 service = (const char *) &msg[1];
2170 if ('\0' != service[msize - sizeof
2171 (struct GNUNET_TESTBED_ManagePeerServiceMessage) - 1])
2172 {
2173 GNUNET_break_op (0);
2174 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2175 return;
2176 }
2177 if (1 < msg->start)
2178 {
2179 GNUNET_break_op (0);
2180 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2181 return;
2182 }
2183 peer_id = ntohl (msg->peer_id);
2184 op_id = GNUNET_ntohll (msg->operation_id);
2185 LOG_DEBUG ("Received request to manage service %s on peer %u\n",
2186 service, (unsigned int) peer_id);
2187 if ((GST_peer_list_size <= peer_id)
2188 || (NULL == (peer = GST_peer_list[peer_id])))
2189 {
2190 GNUNET_asprintf (&emsg, "Asked to manage service of a non existent peer "
2191 "with id: %u", peer_id);
2192 goto err_ret;
2193 }
2194 if (0 == strcasecmp ("arm", service))
2195 {
2196 emsg = GNUNET_strdup ("Cannot start/stop peer's ARM service. "
2197 "Use peer start/stop for that");
2198 goto err_ret;
2199 }
2200 if (GNUNET_YES == peer->is_remote)
2201 {
2202 /* Forward the destory message to sub controller */
2203 fopc = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2204 GNUNET_SERVER_client_keep (client);
2205 fopc->client = client;
2206 fopc->cls = peer;
2207 fopc->type = OP_MANAGE_SERVICE;
2208 fopc->operation_id = op_id;
2209 fopc->opc =
2210 GNUNET_TESTBED_forward_operation_msg_ (peer->details.remote.
2211 slave->controller,
2212 fopc->operation_id, &msg->header,
2213 &GST_forwarded_operation_reply_relay,
2214 fopc);
2215 fopc->timeout_task =
2216 GNUNET_SCHEDULER_add_delayed (GST_timeout, &GST_forwarded_operation_timeout,
2217 fopc);
2218 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fopc);
2219 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2220 return;
2221 }
2222 if ((0 != peer->reference_cnt)
2223 && ( (0 == strcasecmp ("core", service))
2224 || (0 == strcasecmp ("transport", service)) ) )
2225 {
2226 GNUNET_asprintf (&emsg, "Cannot stop %s service of peer with id: %u "
2227 "since it is required by existing operations",
2228 service, peer_id);
2229 goto err_ret;
2230 }
2231 ah = GNUNET_ARM_connect (peer->details.local.cfg, NULL, NULL);
2232 if (NULL == ah)
2233 {
2234 GNUNET_asprintf (&emsg,
2235 "Cannot connect to ARM service of peer with id: %u",
2236 peer_id);
2237 goto err_ret;
2238 }
2239 mctx = GNUNET_malloc (sizeof (struct ManageServiceContext));
2240 mctx->peer = peer;
2241 peer->reference_cnt++;
2242 mctx->op_id = op_id;
2243 mctx->ah = ah;
2244 GNUNET_SERVER_client_keep (client);
2245 mctx->client = client;
2246 mctx->start = msg->start;
2247 GNUNET_CONTAINER_DLL_insert_tail (mctx_head, mctx_tail, mctx);
2248 if (1 == mctx->start)
2249 GNUNET_ARM_request_service_start (mctx->ah, service,
2250 GNUNET_OS_INHERIT_STD_ERR,
2251 GST_timeout,
2252 service_manage_result_cb,
2253 mctx);
2254 else
2255 GNUNET_ARM_request_service_stop (mctx->ah, service,
2256 GST_timeout,
2257 service_manage_result_cb,
2258 mctx);
2259 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2260 return;
2261
2262 err_ret:
2263 LOG (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
2264 GST_send_operation_fail_msg (client, op_id, emsg);
2265 GNUNET_free (emsg);
2266 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2267}
2268 1372
2269/** 1373/**
2270 * Clears the forwarded operations queue 1374 * Clears the forwarded operations queue
2271 */ 1375 */
2272static void 1376void
2273clear_fopcq () 1377GST_clear_fopcq ()
2274{ 1378{
2275 struct ForwardedOperationContext *fopc; 1379 struct ForwardedOperationContext *fopc;
2276 1380
@@ -2314,184 +1418,6 @@ clear_fopcq ()
2314 1418
2315 1419
2316/** 1420/**
2317 * Task run upon timeout of forwarded SHUTDOWN_PEERS operation
2318 *
2319 * @param cls the ForwardedOperationContext
2320 * @param tc the scheduler task context
2321 */
2322static void
2323shutdown_peers_timeout_cb (void *cls,
2324 const struct GNUNET_SCHEDULER_TaskContext *tc)
2325{
2326 struct ForwardedOperationContext *fo_ctxt = cls;
2327 struct HandlerContext_ShutdownPeers *hc;
2328
2329 fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2330 hc = fo_ctxt->cls;
2331 hc->timeout = GNUNET_YES;
2332 GNUNET_assert (0 < hc->nslaves);
2333 hc->nslaves--;
2334 if (0 == hc->nslaves)
2335 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
2336 "Timeout at a slave controller");
2337 GNUNET_TESTBED_forward_operation_msg_cancel_ (fo_ctxt->opc);
2338 GNUNET_SERVER_client_drop (fo_ctxt->client);
2339 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
2340 GNUNET_free (fo_ctxt);
2341}
2342
2343
2344/**
2345 * The reply msg handler forwarded SHUTDOWN_PEERS operation. Checks if a
2346 * success reply is received from all clients and then sends the success message
2347 * to the client
2348 *
2349 * @param cls ForwardedOperationContext
2350 * @param msg the message to relay
2351 */
2352static void
2353shutdown_peers_reply_cb (void *cls,
2354 const struct GNUNET_MessageHeader *msg)
2355{
2356 struct ForwardedOperationContext *fo_ctxt = cls;
2357 struct HandlerContext_ShutdownPeers *hc;
2358
2359 hc = fo_ctxt->cls;
2360 GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != fo_ctxt->timeout_task);
2361 GNUNET_SCHEDULER_cancel (fo_ctxt->timeout_task);
2362 fo_ctxt->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2363 GNUNET_assert (0 < hc->nslaves);
2364 hc->nslaves--;
2365 if (GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS !=
2366 ntohs (msg->type))
2367 hc->timeout = GNUNET_YES;
2368 if (0 == hc->nslaves)
2369 {
2370 if (GNUNET_YES == hc->timeout)
2371 GST_send_operation_fail_msg (fo_ctxt->client, fo_ctxt->operation_id,
2372 "Timeout at a slave controller");
2373 else
2374 send_operation_success_msg (fo_ctxt->client, fo_ctxt->operation_id);
2375 }
2376 GNUNET_SERVER_client_drop (fo_ctxt->client);
2377 GNUNET_CONTAINER_DLL_remove (fopcq_head, fopcq_tail, fo_ctxt);
2378 GNUNET_free (fo_ctxt);
2379}
2380
2381
2382/**
2383 * Stops and destroys all peers
2384 */
2385static void
2386destroy_peers ()
2387{
2388 struct Peer *peer;
2389 unsigned int id;
2390
2391 if (NULL == GST_peer_list)
2392 return;
2393 for (id = 0; id < GST_peer_list_size; id++)
2394 {
2395 peer = GST_peer_list[id];
2396 if (NULL == peer)
2397 continue;
2398 /* If destroy flag is set it means that this peer should have been
2399 * destroyed by a context which we destroy before */
2400 GNUNET_break (GNUNET_NO == peer->destroy_flag);
2401 /* counter should be zero as we free all contexts before */
2402 GNUNET_break (0 == peer->reference_cnt);
2403 if ((GNUNET_NO == peer->is_remote) &&
2404 (GNUNET_YES == peer->details.local.is_running))
2405 GNUNET_TESTING_peer_kill (peer->details.local.peer);
2406 }
2407 for (id = 0; id < GST_peer_list_size; id++)
2408 {
2409 peer = GST_peer_list[id];
2410 if (NULL == peer)
2411 continue;
2412 if (GNUNET_NO == peer->is_remote)
2413 {
2414 if (GNUNET_YES == peer->details.local.is_running)
2415 GNUNET_TESTING_peer_wait (peer->details.local.peer);
2416 GNUNET_TESTING_peer_destroy (peer->details.local.peer);
2417 GNUNET_CONFIGURATION_destroy (peer->details.local.cfg);
2418 }
2419 GNUNET_free (peer);
2420 }
2421 GNUNET_free_non_null (GST_peer_list);
2422 GST_peer_list = NULL;
2423 GST_peer_list_size = 0;
2424}
2425
2426
2427/**
2428 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
2429 *
2430 * @param cls NULL
2431 * @param client identification of the client
2432 * @param message the actual message
2433 */
2434static void
2435handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
2436 const struct GNUNET_MessageHeader *message)
2437{
2438 const struct GNUNET_TESTBED_ShutdownPeersMessage *msg;
2439 struct HandlerContext_ShutdownPeers *hc;
2440 struct Slave *slave;
2441 struct ForwardedOperationContext *fo_ctxt;
2442 uint64_t op_id;
2443 unsigned int cnt;
2444
2445 msg = (const struct GNUNET_TESTBED_ShutdownPeersMessage *) message;
2446 LOG_DEBUG ("Received SHUTDOWN_PEERS\n");
2447 /* Stop and destroy all peers */
2448 free_mctxq ();
2449 GST_free_occq ();
2450 GST_free_roccq ();
2451 clear_fopcq ();
2452 /* Forward to all slaves which we have started */
2453 op_id = GNUNET_ntohll (msg->operation_id);
2454 hc = GNUNET_malloc (sizeof (struct HandlerContext_ShutdownPeers));
2455 /* FIXME: have a better implementation where we track which slaves are
2456 started by this controller */
2457 for (cnt = 0; cnt < GST_slave_list_size; cnt++)
2458 {
2459 slave = GST_slave_list[cnt];
2460 if (NULL == slave)
2461 continue;
2462 if (NULL == slave->controller_proc) /* We didn't start the slave */
2463 continue;
2464 LOG_DEBUG ("Forwarding SHUTDOWN_PEERS\n");
2465 hc->nslaves++;
2466 fo_ctxt = GNUNET_malloc (sizeof (struct ForwardedOperationContext));
2467 GNUNET_SERVER_client_keep (client);
2468 fo_ctxt->client = client;
2469 fo_ctxt->operation_id = op_id;
2470 fo_ctxt->cls = hc;
2471 fo_ctxt->type = OP_SHUTDOWN_PEERS;
2472 fo_ctxt->opc =
2473 GNUNET_TESTBED_forward_operation_msg_ (slave->controller,
2474 fo_ctxt->operation_id,
2475 &msg->header,
2476 shutdown_peers_reply_cb,
2477 fo_ctxt);
2478 fo_ctxt->timeout_task =
2479 GNUNET_SCHEDULER_add_delayed (GST_timeout, &shutdown_peers_timeout_cb,
2480 fo_ctxt);
2481 GNUNET_CONTAINER_DLL_insert_tail (fopcq_head, fopcq_tail, fo_ctxt);
2482 }
2483 LOG_DEBUG ("Shutting down peers\n");
2484 destroy_peers ();
2485 if (0 == hc->nslaves)
2486 {
2487 send_operation_success_msg (client, op_id);
2488 GNUNET_free (hc);
2489 }
2490 GNUNET_SERVER_receive_done (client, GNUNET_OK);
2491}
2492
2493
2494/**
2495 * Iterator over hash map entries. 1421 * Iterator over hash map entries.
2496 * 1422 *
2497 * @param cls closure 1423 * @param cls closure
@@ -2568,7 +1494,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2568 NULL); 1494 NULL);
2569 GNUNET_CONTAINER_multihashmap_destroy (ss_map); 1495 GNUNET_CONTAINER_multihashmap_destroy (ss_map);
2570 /* cleanup any remaining forwarded operations */ 1496 /* cleanup any remaining forwarded operations */
2571 clear_fopcq (); 1497 GST_clear_fopcq ();
2572 if (NULL != lcfq_head) 1498 if (NULL != lcfq_head)
2573 { 1499 {
2574 if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id) 1500 if (GNUNET_SCHEDULER_NO_TASK != lcf_proc_task_id)
@@ -2587,11 +1513,11 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2587 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq); 1513 GNUNET_CONTAINER_DLL_remove (lcfq_head, lcfq_tail, lcfq);
2588 GNUNET_free (lcfq); 1514 GNUNET_free (lcfq);
2589 } 1515 }
2590 free_mctxq (); 1516 GST_free_mctxq ();
2591 GST_free_occq (); 1517 GST_free_occq ();
2592 GST_free_roccq (); 1518 GST_free_roccq ();
2593 /* Clear peer list */ 1519 /* Clear peer list */
2594 destroy_peers (); 1520 GST_destroy_peers ();
2595 /* Clear host list */ 1521 /* Clear host list */
2596 for (id = 0; id < GST_host_list_size; id++) 1522 for (id = 0; id < GST_host_list_size; id++)
2597 if (NULL != GST_host_list[id]) 1523 if (NULL != GST_host_list[id])
@@ -2699,14 +1625,14 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
2699 GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0}, 1625 GNUNET_MESSAGE_TYPE_TESTBED_SHARE_SERVICE, 0},
2700 {&handle_link_controllers, NULL, 1626 {&handle_link_controllers, NULL,
2701 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0}, 1627 GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS, 0},
2702 {&handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0}, 1628 {&GST_handle_peer_create, NULL, GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER, 0},
2703 {&handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER, 1629 {&GST_handle_peer_destroy, NULL, GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
2704 sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)}, 1630 sizeof (struct GNUNET_TESTBED_PeerDestroyMessage)},
2705 {&handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_START_PEER, 1631 {&GST_handle_peer_start, NULL, GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
2706 sizeof (struct GNUNET_TESTBED_PeerStartMessage)}, 1632 sizeof (struct GNUNET_TESTBED_PeerStartMessage)},
2707 {&handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER, 1633 {&GST_handle_peer_stop, NULL, GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
2708 sizeof (struct GNUNET_TESTBED_PeerStopMessage)}, 1634 sizeof (struct GNUNET_TESTBED_PeerStopMessage)},
2709 {&handle_peer_get_config, NULL, 1635 {&GST_handle_peer_get_config, NULL,
2710 GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION, 1636 GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_CONFIGURATION,
2711 sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)}, 1637 sizeof (struct GNUNET_TESTBED_PeerGetConfigurationMessage)},
2712 {&GST_handle_overlay_connect, NULL, 1638 {&GST_handle_overlay_connect, NULL,
@@ -2714,12 +1640,12 @@ testbed_run (void *cls, struct GNUNET_SERVER_Handle *server,
2714 sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)}, 1640 sizeof (struct GNUNET_TESTBED_OverlayConnectMessage)},
2715 {&GST_handle_remote_overlay_connect, NULL, 1641 {&GST_handle_remote_overlay_connect, NULL,
2716 GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0}, 1642 GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT, 0},
2717 {&handle_manage_peer_service, NULL, 1643 {&GST_handle_manage_peer_service, NULL,
2718 GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE, 0}, 1644 GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE, 0},
2719 {&handle_slave_get_config, NULL, 1645 {&handle_slave_get_config, NULL,
2720 GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION, 1646 GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
2721 sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)}, 1647 sizeof (struct GNUNET_TESTBED_SlaveGetConfigurationMessage)},
2722 {&handle_shutdown_peers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS, 1648 {&GST_handle_shutdown_peers, NULL, GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
2723 sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage)}, 1649 sizeof (struct GNUNET_TESTBED_ShutdownPeersMessage)},
2724 {NULL} 1650 {NULL}
2725 }; 1651 };
diff --git a/src/testbed/gnunet-service-testbed.h b/src/testbed/gnunet-service-testbed.h
index 700bbfcd8..aa3ab0b83 100644
--- a/src/testbed/gnunet-service-testbed.h
+++ b/src/testbed/gnunet-service-testbed.h
@@ -600,6 +600,25 @@ struct LCFContextQueue
600 600
601 601
602/** 602/**
603 * Context data for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS handler
604 */
605struct HandlerContext_ShutdownPeers
606{
607 /**
608 * The number of slave we expect to hear from since we forwarded the
609 * GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS message to them
610 */
611 unsigned int nslaves;
612
613 /**
614 * Did we observe a timeout with respect to this operation at any of the
615 * slaves
616 */
617 int timeout;
618};
619
620
621/**
603 * Our configuration 622 * Our configuration
604 */ 623 */
605struct GNUNET_CONFIGURATION_Handle *our_config; 624struct GNUNET_CONFIGURATION_Handle *our_config;
@@ -666,6 +685,30 @@ extern char *GST_stats_dir;
666 685
667 686
668/** 687/**
688 * Similar to GNUNET_array_grow(); however instead of calling GNUNET_array_grow()
689 * several times we call it only once. The array is also made to grow in steps
690 * of LIST_GROW_STEP.
691 *
692 * @param ptr the array pointer to grow
693 * @param size the size of array
694 * @param accommodate_size the size which the array has to accommdate; after
695 * this call the array will be big enough to accommdate sizes upto
696 * accommodate_size
697 */
698#define GST_array_grow_large_enough(ptr, size, accommodate_size) \
699 do \
700 { \
701 unsigned int growth_size; \
702 GNUNET_assert (size <= accommodate_size); \
703 growth_size = size; \
704 while (growth_size <= accommodate_size) \
705 growth_size += LIST_GROW_STEP; \
706 GNUNET_array_grow (ptr, size, growth_size); \
707 GNUNET_assert (size > accommodate_size); \
708 } while (0)
709
710
711/**
669 * Queues a message in send queue for sending to the service 712 * Queues a message in send queue for sending to the service
670 * 713 *
671 * @param client the client to whom the queued message has to be sent 714 * @param client the client to whom the queued message has to be sent
@@ -686,6 +729,13 @@ GST_destroy_peer (struct Peer *peer);
686 729
687 730
688/** 731/**
732 * Stops and destroys all peers
733 */
734void
735GST_destroy_peers ();
736
737
738/**
689 * Finds the route with directly connected host as destination through which 739 * Finds the route with directly connected host as destination through which
690 * the destination host can be reached 740 * the destination host can be reached
691 * 741 *
@@ -747,6 +797,13 @@ GST_forwarded_operation_timeout (void *cls,
747 797
748 798
749/** 799/**
800 * Clears the forwarded operations queue
801 */
802void
803GST_clear_fopcq ();
804
805
806/**
750 * Send operation failure message to client 807 * Send operation failure message to client
751 * 808 *
752 * @param client the client to which the failure message has to be sent to 809 * @param client the client to which the failure message has to be sent to
@@ -759,6 +816,17 @@ GST_send_operation_fail_msg (struct GNUNET_SERVER_Client *client,
759 816
760 817
761/** 818/**
819 * Function to send generic operation success message to given client
820 *
821 * @param client the client to send the message to
822 * @param operation_id the id of the operation which was successful
823 */
824void
825GST_send_operation_success_msg (struct GNUNET_SERVER_Client *client,
826 uint64_t operation_id);
827
828
829/**
762 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT messages 830 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_REQUESTCONNECT messages
763 * 831 *
764 * @param cls NULL 832 * @param cls NULL
@@ -772,6 +840,97 @@ GST_handle_remote_overlay_connect (void *cls,
772 840
773 841
774/** 842/**
843 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_CREATEPEER messages
844 *
845 * @param cls NULL
846 * @param client identification of the client
847 * @param message the actual message
848 */
849void
850GST_handle_peer_create (void *cls, struct GNUNET_SERVER_Client *client,
851 const struct GNUNET_MessageHeader *message);
852
853
854/**
855 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
856 *
857 * @param cls NULL
858 * @param client identification of the client
859 * @param message the actual message
860 */
861void
862GST_handle_peer_destroy (void *cls, struct GNUNET_SERVER_Client *client,
863 const struct GNUNET_MessageHeader *message);
864
865
866/**
867 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
868 *
869 * @param cls NULL
870 * @param client identification of the client
871 * @param message the actual message
872 */
873void
874GST_handle_peer_start (void *cls, struct GNUNET_SERVER_Client *client,
875 const struct GNUNET_MessageHeader *message);
876
877
878/**
879 * Message handler for GNUNET_MESSAGE_TYPE_TESTBED_DESTROYPEER messages
880 *
881 * @param cls NULL
882 * @param client identification of the client
883 * @param message the actual message
884 */
885void
886GST_handle_peer_stop (void *cls, struct GNUNET_SERVER_Client *client,
887 const struct GNUNET_MessageHeader *message);
888
889
890/**
891 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_GETPEERCONFIG messages
892 *
893 * @param cls NULL
894 * @param client identification of the client
895 * @param message the actual message
896 */
897void
898GST_handle_peer_get_config (void *cls, struct GNUNET_SERVER_Client *client,
899 const struct GNUNET_MessageHeader *message);
900
901
902/**
903 * Handler for GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS messages
904 *
905 * @param cls NULL
906 * @param client identification of the client
907 * @param message the actual message
908 */
909void
910GST_handle_shutdown_peers (void *cls, struct GNUNET_SERVER_Client *client,
911 const struct GNUNET_MessageHeader *message);
912
913
914/**
915 * Handler for GNUNET_TESTBED_ManagePeerServiceMessage message
916 *
917 * @param cls NULL
918 * @param client identification of client
919 * @param message the actual message
920 */
921void
922GST_handle_manage_peer_service (void *cls, struct GNUNET_SERVER_Client *client,
923 const struct GNUNET_MessageHeader *message);
924
925
926/**
927 * Frees the ManageServiceContext queue
928 */
929void
930GST_free_mctxq ();
931
932
933/**
775 * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext 934 * Processes a forwarded overlay connect context in the queue of the given RegisteredHostContext
776 * 935 *
777 * @param rhc the RegisteredHostContext 936 * @param rhc the RegisteredHostContext
diff --git a/src/testbed/gnunet-service-testbed_oc.c b/src/testbed/gnunet-service-testbed_oc.c
index 7fdf14586..3199d71af 100644
--- a/src/testbed/gnunet-service-testbed_oc.c
+++ b/src/testbed/gnunet-service-testbed_oc.c
@@ -942,7 +942,6 @@ occ_cache_get_handle_core_cb (void *cls, struct GNUNET_CORE_Handle *ch,
942 occ->peer->details.local.cfg, 942 occ->peer->details.local.cfg,
943 p1_transport_connect_cache_callback, occ, 943 p1_transport_connect_cache_callback, occ,
944 NULL, NULL, NULL); 944 NULL, NULL, NULL);
945 return;
946} 945}
947 946
948 947
@@ -998,13 +997,12 @@ registeredhost_registration_completion (void *cls, const char *emsg)
998 const struct GNUNET_CONFIGURATION_Handle *cfg; 997 const struct GNUNET_CONFIGURATION_Handle *cfg;
999 uint32_t peer2_host_id; 998 uint32_t peer2_host_id;
1000 999
1001 /* if (NULL != rhc->focc_dll_head) */
1002 /* TESTBED_process_next_focc (rhc); */
1003 peer2_host_id = GNUNET_TESTBED_host_get_id_ (rhc->reg_host); 1000 peer2_host_id = GNUNET_TESTBED_host_get_id_ (rhc->reg_host);
1004 GNUNET_assert (RHC_INIT == rhc->state); 1001 GNUNET_assert (RHC_INIT == rhc->state);
1005 GNUNET_assert (NULL == rhc->sub_op); 1002 GNUNET_assert (NULL == rhc->sub_op);
1006 if ((NULL == rhc->gateway2) || ((peer2_host_id < GST_host_list_size) /* Check if we have the needed config */ 1003 if ((NULL == rhc->gateway2) ||
1007 && (NULL != GST_host_list[peer2_host_id]))) 1004 ( (peer2_host_id < GST_host_list_size) /* Check if we have the needed config */
1005 && (NULL != GST_host_list[peer2_host_id]) ) )
1008 { 1006 {
1009 rhc->state = RHC_LINK; 1007 rhc->state = RHC_LINK;
1010 cfg = 1008 cfg =
@@ -1233,6 +1231,7 @@ GST_handle_overlay_connect (void *cls, struct GNUNET_SERVER_Client *client,
1233 if ((peer2_host_id >= GST_slave_list_size) || 1231 if ((peer2_host_id >= GST_slave_list_size) ||
1234 (NULL == GST_slave_list[peer2_host_id])) 1232 (NULL == GST_slave_list[peer2_host_id]))
1235 { 1233 {
1234 GNUNET_break (0);
1236 LOG (GNUNET_ERROR_TYPE_WARNING, 1235 LOG (GNUNET_ERROR_TYPE_WARNING,
1237 "0x%llx: Configuration of peer2's controller missing for connecting peers" 1236 "0x%llx: Configuration of peer2's controller missing for connecting peers"
1238 "%u and %u\n", operation_id, p1, p2); 1237 "%u and %u\n", operation_id, p1, p2);
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}