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;
+}