diff --git a/daisi/CMakeLists.txt b/daisi/CMakeLists.txt index c8861df8..84a96351 100644 --- a/daisi/CMakeLists.txt +++ b/daisi/CMakeLists.txt @@ -12,6 +12,7 @@ cmake_policy(VERSION 3.19) include(CMakeDependentOption) option(DAISI_DISABLE_NETWORK_SIMULATION "Disable ns-3 network simulation (use ns-3 as discrete event simulator only)" OFF) +option(DAISI_ENABLE_EXAMPLES "Enable DAISI ns-3 example applications" ON) option(DAISI_ENABLE_COMPILER_WARNINGS "Build with compiler warnings" ON) cmake_dependent_option(DAISI_HANDLE_COMPILER_WARNINGS_AS_ERRORS "Handle compiler warnings as error" OFF DAISI_ENABLE_COMPILER_WARNINGS OFF) @@ -59,6 +60,10 @@ add_subdirectory(../ ${CMAKE_CURRENT_BINARY_DIR}/sola_mono) add_subdirectory(src) +if(DAISI_ENABLE_EXAMPLES) + add_subdirectory(examples) +endif() + add_subdirectory(tests/unittests) add_subdirectory(third_party) diff --git a/daisi/examples/CMakeLists.txt b/daisi/examples/CMakeLists.txt new file mode 100644 index 00000000..c037cff4 --- /dev/null +++ b/daisi/examples/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(tcp) diff --git a/daisi/examples/tcp/CMakeLists.txt b/daisi/examples/tcp/CMakeLists.txt new file mode 100644 index 00000000..00eb54fd --- /dev/null +++ b/daisi/examples/tcp/CMakeLists.txt @@ -0,0 +1,14 @@ +add_executable(daisi_tcp_example tcp_example.cpp) +target_link_libraries(daisi_tcp_example + PRIVATE + ns3::libcore + daisi_network_tcp_server + daisi_network_tcp_client + daisi_utils + daisi_socket_manager + ns3::libcsma +) +target_include_directories(daisi_tcp_example + PRIVATE + ${DAISI_SOURCE_DIR}/src +) diff --git a/daisi/examples/tcp/tcp_example.cpp b/daisi/examples/tcp/tcp_example.cpp new file mode 100644 index 00000000..176fd2bc --- /dev/null +++ b/daisi/examples/tcp/tcp_example.cpp @@ -0,0 +1,157 @@ +// Copyright 2023 The SOLA authors +// +// This file is part of DAISI. +// +// DAISI is free software: you can redistribute it and/or modify it under the terms of the GNU +// General Public License as published by the Free Software Foundation; version 2. +// +// DAISI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +// Public License for more details. +// +// You should have received a copy of the GNU General Public License along with DAISI. If not, see +// . +// +// SPDX-License-Identifier: GPL-2.0-only + +#include +#include + +#include "network_tcp/client.h" +#include "network_tcp/server.h" +#include "ns3/applications-module.h" +#include "ns3/core-module.h" +#include "ns3/csma-module.h" +#include "ns3/internet-module.h" +#include "ns3/network-module.h" +#include "utils/socket_manager.h" +#include "utils/sola_utils.h" + +using namespace ns3; +using namespace daisi; + +/// TCP Pong server +class Server : public Application { +public: + static TypeId GetTypeId() { + static TypeId tid = TypeId("Server").SetParent().AddConstructor(); + return tid; + } + + Server() = default; + + ~Server() override = default; + + void StartApplication() override { + auto new_msg = [this](network_tcp::TcpSocketHandle handle, const std::string &msg) { + std::cout << "[SERVER] \"" << msg << "\" from handle " << handle << "\n"; + tcp_->send(handle, "PONG"); + }; + + auto connected = [](network_tcp::TcpSocketHandle handle, const std::string &ip, uint16_t port) { + std::cout << "[SERVER] New connection from " << ip << ":" << port << " WITH HANDLE " << handle + << "\n"; + }; + + auto disconnected = [](network_tcp::TcpSocketHandle /*handle*/) {}; + + tcp_ = std::make_unique( + network_tcp::ServerCallbacks{new_msg, connected, disconnected}); + std::cout << "[SERVER] Started on " << tcp_->getIP() << ":" << tcp_->getPort() << "\n"; + } + + void StopApplication() override { tcp_.reset(); } + +private: + std::unique_ptr tcp_; +}; + +/// TCP client +class Client : public Application { +public: + static TypeId GetTypeId() { + static TypeId tid = TypeId("Client").SetParent(); + return tid; + } + + explicit Client(network_tcp::Endpoint endpoint) : endpoint_(std::move(endpoint)) {} + + ~Client() override = default; + + void StartApplication() override { + auto new_msg = [](const std::string & /*msg*/) {}; + auto connected = []() {}; + auto disconnected = []() {}; + + tcp_ = std::make_unique( + network_tcp::ClientCallbacks{new_msg, connected, disconnected}, endpoint_); + } + + void StopApplication() override { tcp_.reset(); } + + void sendData(const std::string &msg) { tcp_->send(msg); } + +private: + network_tcp::Endpoint endpoint_; + + std::unique_ptr tcp_; +}; + +#define SCHEDULE(number, function, type, seconds) \ + ns3::Simulator::ScheduleWithContext( \ + node_container.Get(number)->GetId(), Seconds(seconds), &type::function, \ + node_container.Get(number)->GetApplication(0)->GetObject()); + +#define SCHEDULE_WITH_ARG(number, function, type, seconds, arg) \ + ns3::Simulator::ScheduleWithContext( \ + node_container.Get(number)->GetId(), Seconds(seconds), &type::function, \ + node_container.Get(number)->GetApplication(0)->GetObject(), arg); + +int main(int /*argc*/, char * /*argv*/[]) { + NodeContainer node_container; + node_container.Create(2); + + CsmaHelper csma; + csma.SetChannelAttribute("DataRate", StringValue("10Gbps")); + csma.SetChannelAttribute("Delay", StringValue("1ms")); + + NetDeviceContainer net_devices; + net_devices = csma.Install(node_container); + csma.EnablePcapAll("output"); + + InternetStackHelper stack; + stack.Install(node_container); + + Ipv4AddressHelper address; + address.SetBase("10.0.0.0", "255.255.255.0"); + Ipv4InterfaceContainer interfaces = address.Assign(net_devices); + + // Start one server and N-1 clients + for (auto i = 0; i < node_container.GetN(); i++) { + // Register node for automatic ns-3 socket creation + std::vector addresses = daisi::getAddressesForNode(node_container, i); + daisi::SocketManager::get().registerNode(addresses, node_container.Get(i), 2000); + + if (i == 0) { + Ptr app = CreateObject(); + app->SetStartTime(Seconds(i)); + app->SetStopTime(Seconds(9)); + + node_container.Get(i)->AddApplication(app); + } else { + network_tcp::Endpoint a{"10.0.0.1", 2000}; // Server endpoint + Ptr app = CreateObject(a); + app->SetStartTime(Seconds(i)); + app->SetStopTime(Seconds(10)); + node_container.Get(i)->AddApplication(app); + } + } + + SCHEDULE_WITH_ARG(1, sendData, Client, 2, "Hello"); + + Simulator::Stop(Seconds(20)); + Simulator::Run(); + Simulator::Destroy(); + + return 0; +}