diff --git a/.ci/Dockerfile b/.ci/Dockerfile index 42c3740bf51dcf9a26bda5cf746bbd574a20f038..ab5aee47e1540dfacdb88cb49aabcf6012ef233b 100644 --- a/.ci/Dockerfile +++ b/.ci/Dockerfile @@ -1,2 +1,5 @@ FROM ubuntu:22.04 -RUN apt update && DEBIAN_FRONTEND=noninteractive apt -y install make cmake pkg-config libcoap3-dev build-essential gcovr libgtest-dev libglib2.0-dev +COPY run.sh /etc/init/ +RUN apt update && DEBIAN_FRONTEND=noninteractive apt -y install make cmake pkg-config libcoap3-dev build-essential gcovr libgtest-dev dbus-x11 libglib2.0-dev +RUN ["chmod", "+x", "/etc/init/run.sh"] +ENTRYPOINT ["/etc/init/run.sh"] \ No newline at end of file diff --git a/.ci/run.sh b/.ci/run.sh new file mode 100644 index 0000000000000000000000000000000000000000..e9305e6c9cc7c6abd37b7f86e9d280c506d9907a --- /dev/null +++ b/.ci/run.sh @@ -0,0 +1,3 @@ +#!/bin/bash +export $(dbus-launch) +/bin/bash \ No newline at end of file diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index a8c3bedd0748d4f99b6e853bc52adc79226aab73..68ee79f5750cd75b0c27912a23c61134e83cd1b7 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -41,6 +41,7 @@ install(TARGETS eddie-endpoint RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) # virtualization server add_executable(eddie-virt-server examples/virt_server.cpp ${SOURCES}) target_link_libraries(eddie-virt-server PkgConfig::GLIB ${CMAKE_THREAD_LIBS_INIT} eddie-communication eddie-virtualization) +target_include_directories(eddie-virt-server PUBLIC ${PROJECT_SOURCE_DIR}/include) set_property(TARGET eddie-virt-server PROPERTY C_STANDARD 11) install(TARGETS eddie-virt-server RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/linux/communication/include/CoapClient.h b/linux/communication/include/CoapClient.h index deb3af9f4829b1de7bd75efb12c956e6c43bfc9d..e6d987b3f32cffd995c49aeec103f5c1bd138c16 100644 --- a/linux/communication/include/CoapClient.h +++ b/linux/communication/include/CoapClient.h @@ -28,9 +28,11 @@ private: coap_session_t *open_session(const char *dst_host, const char *dst_port); - std::thread client_thread; - static ThreadSafeMap *messages; + + std::string last_token; + + std::thread client_thread; static std::mutex client_mutex; static std::condition_variable client_condition; diff --git a/linux/communication/src/CoapClient.cpp b/linux/communication/src/CoapClient.cpp index 95310b569e28259aae70bdd38c0a71cd6b2af003..71cd59f9cdd6fab95fea88e45745bb6a3bc0236e 100644 --- a/linux/communication/src/CoapClient.cpp +++ b/linux/communication/src/CoapClient.cpp @@ -118,24 +118,16 @@ void CoapClient::set_quit(bool value) { } std::string CoapClient::send_message(request_t request) { - coap_session_t *session; uint8_t buf[1024]; - size_t buflen; uint8_t *sbuf = buf; coap_pdu_t *pdu; int res; coap_optlist_t *optlist = nullptr; - uint8_t token_buf[1024]; - memset(token_buf, 0, sizeof(token_buf)); - size_t token_len; - uint8_t *token = token_buf; - // BEGIN CRITICAL CALLS TO CoAP APIs std::unique_lock lock(CoapClient::client_mutex); - session = open_session(request.dst_host, request.dst_port); - + coap_session_t * session = open_session(request.dst_host, request.dst_port); if (!session) { LOG_ERR("Error creating remote session"); coap_session_release(session); @@ -148,12 +140,20 @@ std::string CoapClient::send_message(request_t request) { coap_new_message_id(session), coap_session_max_pdu_size(session)); - // Add token to the request - coap_session_new_token(session, &token_len, token); - coap_add_token(pdu, token_len, token); + // initialize session token to last generated token so that new sessions does not reuse same token again + if (!last_token.empty()) + coap_session_init_token(session, last_token.length(), (const uint8_t *)last_token.c_str()); + + // generate new token and add to PDU + uint8_t token_buf[8]; + size_t token_len; + coap_session_new_token(session, &token_len, token_buf); + std::string token_str = std::string(reinterpret_cast(token_buf), token_len); + this->last_token = token_str; + coap_add_token(pdu, token_len, token_buf); if (request.path) { - buflen = sizeof(buf); + size_t buflen = sizeof(buf); res = coap_split_path((const uint8_t *) request.path, strlen(request.path), sbuf, @@ -175,7 +175,7 @@ std::string CoapClient::send_message(request_t request) { // Add query as option to the PDU if (request.query) { - buflen = sizeof(buf); + size_t buflen = sizeof(buf); res = coap_split_query((const uint8_t *) request.query, strlen(request.query), sbuf, &buflen); while (res--) { @@ -195,9 +195,6 @@ std::string CoapClient::send_message(request_t request) { coap_add_data(pdu, request.data_length, request.data); } - // add token string as valid token - std::string token_str = std::string(reinterpret_cast(token), token_len); - coap_send(session, pdu); // END OF CRITICAL LINES diff --git a/linux/communication/src/EddieEndpoint.cpp b/linux/communication/src/EddieEndpoint.cpp index 94857ea508fe5dcf32882e32afec26293a129e8c..edf6bcacc41d284a9f595668d13c05a4cd3450a7 100644 --- a/linux/communication/src/EddieEndpoint.cpp +++ b/linux/communication/src/EddieEndpoint.cpp @@ -92,6 +92,7 @@ int EddieEndpoint::add_resource(EddieResource *resource) { } int EddieEndpoint::start_server(bool blocking) { + LOG_DBG("starting server"); if (blocking) return get_server()->run(); else @@ -99,6 +100,7 @@ int EddieEndpoint::start_server(bool blocking) { } int EddieEndpoint::stop_server() { + LOG_DBG("stopping server"); return get_server()->stop_server(); } diff --git a/linux/examples/virt_client.cpp b/linux/examples/virt_client.cpp index def14f49c262dfc9ab82a23bc4d616b0d894c3aa..d37ca168ac137ffe786f928ac21650c54800b4cd 100644 --- a/linux/examples/virt_client.cpp +++ b/linux/examples/virt_client.cpp @@ -24,7 +24,7 @@ int main() { }); auto answer = send_message(parameters); - printf("%s\n", answer); + printf("%s\n", answer.c_str()); disconnect(watcher_id); diff --git a/linux/examples/virt_server.cpp b/linux/examples/virt_server.cpp index a2526c4889caac1b339c82349317d19661e97314..21bf35f0f0709cab9b3dbef22f330233f830702e 100644 --- a/linux/examples/virt_server.cpp +++ b/linux/examples/virt_server.cpp @@ -8,10 +8,60 @@ #include #include #include "VirtualizationReceiver.h" +#include "argparse.hpp" using namespace std; -int main() { - VirtualizationReceiver receiver = VirtualizationReceiver(); - receiver.run(vector(), vector(), 0); +void mock_comm_setup(std::vector &uris, std::vector &attributes) { + uris = { + "lamp", + "lamp/brightness", + "lamp/color_rgb" + }; + + attributes = { + "lt=90000&rt=eddie.lamp&ct=40", + "lt=90000&rt=eddie.lamp.brightness&range=0-1&ct=0", + "lt=90000&rt=eddie.lamp.color&ct=0" + }; +} + +int main(int argc, char *argv[]) { + argparse::ArgumentParser program("eddie-virt-server"); + + program.add_argument("--ip", "-a") + .help("Ip address") + .default_value(std::string{"auto"}); + + program.add_argument("--port", "-p") + .help("Port number") + .scan<'i', int>() + .default_value(5683); + + program.add_argument("--exampleres", "-e") + .help("Publish example lamp resources") + .default_value(false) + .implicit_value(true); + + try { + program.parse_args(argc, argv); + } + catch (const std::runtime_error& err) { + std::cerr << err.what() << std::endl; + std::cerr << program; + std::exit(1); + } + + auto port_number = program.get("port"); + auto ip = program.get("ip"); + if (ip == "auto") ip = ""; + + VirtualizationReceiver receiver = VirtualizationReceiver(ip, std::to_string(port_number)); + + vector uris; + vector attributes; + if (program["--exampleres"] == true) { + mock_comm_setup(uris, attributes); + } + receiver.run(uris, attributes); } diff --git a/linux/tests/CMakeLists.txt b/linux/tests/CMakeLists.txt index f2e63b3ec0b2600abe08d76fe09495b7d7d94f89..4e133f845224de16738e73b5c1fa89d2fd3155e3 100644 --- a/linux/tests/CMakeLists.txt +++ b/linux/tests/CMakeLists.txt @@ -2,6 +2,10 @@ add_executable( communication_tests communication_tests.cpp ) +add_executable( + virtualization_tests + virtualization_tests.cpp +) target_link_libraries( communication_tests gtest @@ -10,17 +14,25 @@ target_link_libraries( eddie-communication ) +target_link_libraries( + virtualization_tests + gtest + gtest_main + eddie-virtualization +) + include(GoogleTest) -gtest_discover_tests(communication_tests PROPERTIES FIXTURES_REQUIRED "resource-directory") +gtest_discover_tests(communication_tests PROPERTIES FIXTURES_REQUIRED "eddie-virt-server") +gtest_discover_tests(virtualization_tests PROPERTIES FIXTURES_REQUIRED "eddie-virt-server") add_test(NAME Fixture.Eddie_Server_Setup - COMMAND ${CMAKE_SOURCE_DIR}/tests/fixture-start.sh ./linux/resource-directory) + COMMAND ${CMAKE_SOURCE_DIR}/tests/fixture-start.sh "./linux/eddie-virt-server --exampleres --ip ::1") set_tests_properties(Fixture.Eddie_Server_Setup PROPERTIES WORKING_DIRECTORY . - FIXTURES_SETUP resource-directory) + FIXTURES_SETUP eddie-virt-server) add_test(NAME Fixture.Eddie_Server_Teardown - COMMAND ${CMAKE_SOURCE_DIR}/tests/fixture-stop.sh ./linux/resource-directory) + COMMAND ${CMAKE_SOURCE_DIR}/tests/fixture-stop.sh) set_tests_properties(Fixture.Eddie_Server_Teardown PROPERTIES WORKING_DIRECTORY . - FIXTURES_CLEANUP resource-directory) + FIXTURES_CLEANUP eddie-virt-server) diff --git a/linux/tests/communication_tests.cpp b/linux/tests/communication_tests.cpp index 4d333828cfb8366503bafcf6b516971475c6e0f5..8c97e62a03def19b8ff94364d6548c7d346f1616 100644 --- a/linux/tests/communication_tests.cpp +++ b/linux/tests/communication_tests.cpp @@ -133,7 +133,7 @@ TEST(Communication, Get_Resources_From_Rd) { EXPECT_EQ(endpoint.discover_rd(), 0); std::vector res = endpoint.get_resources_from_rd(); - EXPECT_EQ(res.size(), 0); + EXPECT_EQ(res.size(), 3); } TEST(Communication, Publish_And_Get_Resources) { @@ -175,4 +175,4 @@ TEST(Communication, Publish_And_Get_Resources) { EXPECT_EQ(response.data, "on"); EXPECT_EQ(endpoint.stop_server(), 0); -} \ No newline at end of file +} diff --git a/linux/tests/virtualization_tests.cpp b/linux/tests/virtualization_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3991cc1e430883d4611b023455b1c3ab1894e9d4 --- /dev/null +++ b/linux/tests/virtualization_tests.cpp @@ -0,0 +1,37 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * SPDX-FileCopyrightText: Huawei Inc. + * SPDX-FileCopyrightText: Politecnico Di Milano + */ +#include +#include +#include + +#include "VirtualizationSender.h" + +TEST(Communication, Virtualization_Sender) { + guint watcher_id = connect(); + + std::thread main([]() { + run(); + }); + + std::unordered_map parameters = { + {"method", "POST"}, + {"payload", "100"} + }; + auto answer = send_message(parameters); + EXPECT_EQ(answer, ""); + + parameters = { + {"method", "GET"}, + {"payload", ""} + }; + answer = send_message(parameters); + EXPECT_EQ(answer, "100"); + + disconnect(watcher_id); + + main.join(); +} \ No newline at end of file diff --git a/linux/virtualization/include/VirtualizationReceiver.h b/linux/virtualization/include/VirtualizationReceiver.h index fadf631fc237362e1f42148dff59ac4aa3a4de43..9e23eb9ab61d70e71d9264353b9f2c4c5cc6a25e 100644 --- a/linux/virtualization/include/VirtualizationReceiver.h +++ b/linux/virtualization/include/VirtualizationReceiver.h @@ -40,11 +40,11 @@ private: on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data); public: - VirtualizationReceiver(); + VirtualizationReceiver(const std::string& ip = "", const std::string& port = "5683"); static EddieEndpoint *communication_layer(); - int run(std::vector uris, std::vector attributes, int node); + int run(std::vector uris, std::vector attributes); static void update_resources(); }; diff --git a/linux/virtualization/include/VirtualizationSender.h b/linux/virtualization/include/VirtualizationSender.h index 18287f777c6ceda73704c50062fcd0e960dc9f85..34ca1df5eb2a1029451317a37d30327b246268c4 100644 --- a/linux/virtualization/include/VirtualizationSender.h +++ b/linux/virtualization/include/VirtualizationSender.h @@ -16,7 +16,7 @@ guint connect(); void disconnect(guint watcher_id); -const gchar *send_message(const std::unordered_map ¶meters); +std::string send_message(const std::unordered_map ¶meters); void run(); diff --git a/linux/virtualization/src/VirtualizationReceiver.cpp b/linux/virtualization/src/VirtualizationReceiver.cpp index dfa34080447bc56088ad69924987d5cbba8a6ef9..6b3a5080c6eb62a1e83b731f08a7706469782ddd 100644 --- a/linux/virtualization/src/VirtualizationReceiver.cpp +++ b/linux/virtualization/src/VirtualizationReceiver.cpp @@ -30,7 +30,7 @@ static const gchar *introspection_XML = " " ""; -EddieEndpoint* VirtualizationReceiver::eddie_endpoint = new EddieEndpoint(); +EddieEndpoint* VirtualizationReceiver::eddie_endpoint; std::vector VirtualizationReceiver::resources; GDBusNodeInfo *VirtualizationReceiver::introspection_data = g_dbus_node_info_new_for_xml(introspection_XML, nullptr); const GDBusInterfaceVTable VirtualizationReceiver::interface_vtable = {handle_method_call}; @@ -38,18 +38,6 @@ const GDBusInterfaceVTable VirtualizationReceiver::interface_vtable = {handle_me std::unordered_multimap resources_by_ip; std::unordered_map resources_by_resource_name; -std::vector split_virt(const std::string &s, char delimiter) { - std::vector tokens; - std::string token; - std::istringstream tokenStream(s); - - while (std::getline(tokenStream, token, delimiter)) { - tokens.push_back(token); - } - - return tokens; -} - method_t method_from_string(const std::string &input) { if (input == "GET") return GET; else if (input == "POST") return POST; @@ -61,39 +49,18 @@ int mock_ai_executor(const std::string &method, const std::unordered_mapsecond.host; - port = resource_it->second.port; - query = ""; - } else { - res = "lamp1/status"; - ip = resource_it->second.host; - port = resource_it->second.port; - query = ""; + if (resource_it == resources_by_resource_name.end()) { + LOG_ERR("lamp/brightness resource not found"); + return -1; } - return 0; -} -void mock_comm_setup(std::vector &uris, std::vector &attributes) { - uris = { - "lamp", - "lamp/brightness", - "lamp/color_rgb" - }; - - attributes = { - "lt=90000&rt=eddie.lamp&ct=40", - "lt=90000&rt=eddie.lamp.brightness&range=0-1&ct=0", - "lt=90000&rt=eddie.lamp.color&ct=0" - }; + ip = resource_it->second.host; + port = resource_it->second.port; + query = ""; + return 0; } class MockEddieResource : public EddieResource { @@ -126,6 +93,8 @@ public: token = strtok(nullptr, "&"); } split_attributes.push_back(nullptr); + + data = "uninitialized data"; } ~MockEddieResource() { @@ -182,12 +151,9 @@ void VirtualizationReceiver::handle_method_call(GDBusConnection *connection, con } std::string ip, port, resource, query; - std::basic_string token; update_resources(); - std::string comm_answer; - if (mock_ai_executor(method, query_parameters, ip, port, resource, query)) { g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", "ERROR forging the message")); LOG_ERR("ERROR forging the message"); @@ -205,10 +171,8 @@ void VirtualizationReceiver::handle_method_call(GDBusConnection *connection, con 0 }; message_t response = eddie_endpoint->get_client()->send_message_and_wait_response(request); - comm_answer = response.data; - LOG_DBG("return data: %s", comm_answer.c_str()); - g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", comm_answer.c_str())); + g_dbus_method_invocation_return_value(invocation, g_variant_new("(s)", response.data.c_str())); } } @@ -222,22 +186,20 @@ void VirtualizationReceiver::on_bus_acquired(GDBusConnection *connection, const nullptr, nullptr, nullptr); g_assert(registration_id > 0); + printf("Started virtualization layer"); } void VirtualizationReceiver::on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { - + LOG_DBG("[Virtualization Layer]: dbus name acquired -> %s", name); } void VirtualizationReceiver::on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data) { + LOG_ERR("[Virtualization Layer]: dbus name lost <- %s", name); exit(-1); } -VirtualizationReceiver::VirtualizationReceiver() { - if (eddie_endpoint == nullptr) { - LOG_ERR("[VirtualizationReceiver::VirtualizationReceiver]: error setting up the infrastructure\n"); - LOG_ERR("\teddie_endpoint is null\n"); - exit(-1); - } +VirtualizationReceiver::VirtualizationReceiver(const std::string& ip, const std::string& port) { + eddie_endpoint = new EddieEndpoint(port, ip); eddie_endpoint->discover_rd(); } @@ -259,12 +221,8 @@ EddieEndpoint *VirtualizationReceiver::communication_layer() { return eddie_endpoint; } -int VirtualizationReceiver::run(std::vector uris, std::vector attributes, int node) { - std::thread comm_runner([]() { - eddie_endpoint->start_server(); - }); - - if (uris.empty() || attributes.empty()) mock_comm_setup(uris, attributes); +int VirtualizationReceiver::run(std::vector uris, std::vector attributes) { + eddie_endpoint->start_server(); for (int i = 0; i < uris.size(); ++i) { EddieResource* new_resource = new MockEddieResource(uris[i], attributes[i]); diff --git a/linux/virtualization/src/VirtualizationSender.cpp b/linux/virtualization/src/VirtualizationSender.cpp index da170aa925450f4305fe7221f93dfcea35b02e49..0bd8531e10594d6ab385167c8de66adca579cefc 100644 --- a/linux/virtualization/src/VirtualizationSender.cpp +++ b/linux/virtualization/src/VirtualizationSender.cpp @@ -99,7 +99,7 @@ void disconnect(guint watcher_id) { g_main_loop_quit(global_loop); } -const gchar *send_message(const std::unordered_map ¶meters) { +std::string send_message(const std::unordered_map ¶meters) { int count = 0; while (global_connection == nullptr && count < MAX_RETRIES) { @@ -172,11 +172,12 @@ const gchar *send_message(const std::unordered_map &pa } const gchar *response = g_dbus_message_get_arg0(method_reply_message); + std::string response_str = std::string(response); g_object_unref(method_call_message); g_object_unref(method_reply_message); - return response; + return response_str; } void run() { diff --git a/tests/fixture-start.sh b/tests/fixture-start.sh index 2be3c64fe2117fdbad227f99ac97fc6412479dce..bb6870e27e14dfc93968762e4dec9be79d0b0869 100755 --- a/tests/fixture-start.sh +++ b/tests/fixture-start.sh @@ -3,5 +3,5 @@ $1 2>/dev/null 1>/dev/null 0 fixture.pid # Allow server to fully start before lauching clients with ctest -sleep 2 +sleep 5 exit 0