暫無描述

Marek Küthe 4ab39a2e9e Add problem description 8 月之前
src 4c9140be55 Initial commit 8 月之前
.gitignore bde73fbba6 Initial commit 8 月之前
LICENSE bde73fbba6 Initial commit 8 月之前
README.md 4ab39a2e9e Add problem description 8 月之前

README.md

TAP device in C++

Problem

My program should simultaneously read packets from a generated TAP device and process them. For this I use the tuntap library from LaKabane together with Boost.Asio's posix::stream_descriptor. However, since I am acting as a client and not a server, there is no option to accept packets asynchronously. The proviorical solution I have chosen is to read asynchronously again and again. However, there are two major problems with this:

  1. There could be a stack overflow, as the same function is called "infinitely" often.
  2. The function does not accept the packets fast enough. I have tested this with sudo ping -f ff02::1%test.

The following is my code so far:

#include <iostream>
#include <cstdlib>
#include <boost/asio.hpp>
#include <unistd.h>
#include "tun_tap.hpp"

void handle_packet([[maybe_unused]] const boost::system::error_code& error, [[maybe_unused]] std::size_t bytes_transferred, [[maybe_unused]] const std::array<char, 1520>& buffer)
{
    if (error)
    {
        std::clog << "Error in handle_packet: " << error.message() << std::endl;
        return;
    }
    std::clog << "Received packet of size: " << bytes_transferred << std::endl;
    std::clog << std::flush;

    // To something with the packet
    sleep(5);
}

void start(boost::asio::posix::stream_descriptor& tap_device)
{
    std::array<char, 1520> buffer;

    tap_device.async_read_some(boost::asio::buffer(buffer),
                                  [&](const boost::system::error_code& error, std::size_t bytes_transferred) {
                                      start(tap_device);
                                      handle_packet(error, bytes_transferred, buffer);
                                  });
}

int main() {
    try {
        boost::asio::io_context io;
        const ::size_t mtu = 1500;
        std::clog << "Create TUN device." << std::endl;
        tun_tap dev = tun_tap("test", tun_tap_mode::tap);
        std::clog << "Set MTU to " << mtu << "." << std::endl;
        dev.set_mtu(1500);
        std::clog << "Set the TUN device up." << std::endl;
        dev.up();

        boost::asio::posix::stream_descriptor tap_device(io, ::dup(dev.native_handler()));
        start(tap_device);


        io.run();
    } catch (const std::exception &e) {
        std::cerr << "Error: " << e.what() << std::endl << "Exit program.";
        ::exit(EXIT_FAILURE);
    }
    return EXIT_SUCCESS;
}

My question now is, how can I read from the TAP device with Boost.Asio without losing packets?

Asked

Problem: stackoverflow: How can I read from a TAP device (via posix::stream_descriptor) simultaneously with Boost.Asio?

Building

$ meson setup src build
$ meson compile -C build

Running

# ./build/cpp_tap_device