xaizek / tos (License: GPLv3 only) (since 2018-12-07)
This is an alternative version of sources presented as part of Write Your Own OS video tutorial by Viktor Engelmann.
<root> / src / net / udp.cpp (2b8d5a642a817b9754f2377846f96881cf5e7495) (3,405B) (mode 100644) [raw]
#include "net/udp.hpp"

#include <cstdint>

#include <memory>
#include <utility>

using namespace net;

UDPSocket::UDPSocket(UDPProvider &backend)
    : backend(backend), handler(nullptr), listening(false)
{
}

void
UDPSocket::handleUDPMessage(span<std::uint8_t> msg)
{
    if (handler != nullptr) {
        handler->handleUDPMessage(*this, msg);
    }
}

void
UDPSocket::send(span<const std::uint8_t> buf)
{
    backend.send(*this, buf);
}

void
UDPSocket::disconnect()
{
    backend.disconnect(*this);
}

UDPProvider::UDPProvider(IPProvider &backend)
    : IPHandler(backend, 0x11), numSockets(0), freePort(1024)
{
}

bool
UDPProvider::onIPReceived(NetOrder<std::uint32_t> srcIP,
                          NetOrder<std::uint32_t> dstIP,
                          span<std::uint8_t> msg)
{
    if (msg.size() < UDPHeader::size()) {
        return false;
    }

    UDPHeader udpHdr(msg.data());

    UDPSocket *socket = nullptr;
    for (std::uint16_t i = 0U; i < numSockets && socket == nullptr; ++i) {
        if (sockets[i]->localPort == udpHdr.dstPort &&
            sockets[i]->localIP == dstIP &&
            sockets[i]->listening) {
            socket = sockets[i].get();
            socket->listening = false;
            socket->remotePort = udpHdr.srcPort;
            socket->remoteIP = srcIP;
        } else if (sockets[i]->localPort == udpHdr.dstPort &&
                   sockets[i]->localIP == dstIP &&
                   sockets[i]->remotePort == udpHdr.srcPort &&
                   sockets[i]->remoteIP == srcIP) {
            socket = sockets[i].get();
        }
    }

    if (socket != nullptr) {
        socket->handleUDPMessage(msg.after(udpHdr.size()));
    }

    return false;
}

UDPSocket &
UDPProvider::connect(NetOrder<std::uint32_t> ip, std::uint16_t port)
{
    std::unique_ptr<UDPSocket> socket(new UDPSocket(*this));

    socket->remotePort = toNetOrder(port);
    socket->remoteIP = ip;
    socket->localPort = toNetOrder(freePort++);
    socket->localIP = backend.getIPAddress();

    sockets[numSockets++] = std::move(socket);
    return *sockets[numSockets - 1U];
}

UDPSocket &
UDPProvider::listen(std::uint16_t port)
{
    std::unique_ptr<UDPSocket> socket(new UDPSocket(*this));

    socket->listening = true;
    socket->localPort = toNetOrder(port);
    socket->localIP = backend.getIPAddress();

    sockets[numSockets++] = std::move(socket);
    return *sockets[numSockets - 1U];
}

void
UDPProvider::disconnect(UDPSocket &socket)
{
    for (std::uint16_t i = 0; i < numSockets; ++i) {
        if (sockets[i].get() == &socket) {
            sockets[i] = std::move(sockets[--numSockets]);
            break;
        }
    }
}

void
UDPProvider::send(UDPSocket &socket, span<const std::uint8_t> buf)
{
    std::uint16_t totalLength = buf.size() + UDPHeader::size();
    std::unique_ptr<std::uint8_t[]> buffer(new std::uint8_t[totalLength]);

    UDPHeader msg(buffer.get());

    msg.srcPort = socket.localPort;
    msg.dstPort = socket.remotePort;
    msg.length = toNetOrder(totalLength);

    std::uint8_t *payload = buffer.get() + UDPHeader::size();
    for (std::uint16_t i = 0U; i < buf.size(); ++i) {
        payload[i] = buf[i];
    }

    msg.checksum = toNetOrder<std::uint16_t>(0);
    IPHandler::send(socket.remoteIP, { buffer.get(), totalLength });
}

void
UDPProvider::bind(UDPSocket &socket, UDPHandler *handler)
{
    socket.handler = handler;
}
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/tos

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/tos

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master