3
\$\begingroup\$

Getting close to a release of generic server.

Nisse Server: Part 1 Helper Functions
Nisse Server: Part 2 Socket Layer
Nisse Server: Part 3 Stream Layer
Nisse Server: Part 4 Server

As I mentioned each connection is handled by a new handler object of specific type. These need to be derived from NisseHandler. But you only need to worry about this if you are creating a handler for a specific protocol (like HTTP, I have started the HTTP handler (still some work to do)).

But this also defines the standard handler that waits for the connection and created you port specific handler.

NisseHandler.h

#ifndef THORSANVIL_NISSE_NISSE_HANDLER_H
#define THORSANVIL_NISSE_NISSE_HANDLER_H

#include "NisseEventUtil.h"
#include "Socket.h"

extern "C" void eventCB(ThorsAnvil::Nisse::LibSocketId socketId, short eventType, void* event);

namespace ThorsAnvil
{
    namespace Nisse
    {

using EventDeleter  = decltype(&event_free);
using NisseEvent    = std::unique_ptr<LibEvent, EventDeleter>;

class NisseService;
class NisseHandler
{
    private:
        NisseService&                       parent;
        NisseEvent                          event;
    public:
        NisseHandler(NisseService& parent, LibEventBase* base, LibSocketId socketId, short eventType);
        virtual ~NisseHandler() {}
        virtual void eventActivate(LibSocketId sockId, short eventType);
    protected:
        void dropHandler();
        template<typename H, typename... Args>
        void addHandler(Args&&... args);
        template<typename H, typename... Args>
        void moveHandler(Args&&... args);
};

template<typename Handler, typename Param>
class ServerHandler: public NisseHandler
{
    private:
        ThorsAnvil::Socket::ServerSocket            socket;
        Param&                                      param;
    public:
        ServerHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::ServerSocket&& so, Param& param);
        virtual void eventActivate(LibSocketId sockId, short eventType) override;
};

template<typename Handler>
class ServerHandler<Handler, void>: public NisseHandler
{
    private:
        ThorsAnvil::Socket::ServerSocket            socket;
    public:
        ServerHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::ServerSocket&& so);
        virtual void eventActivate(LibSocketId sockId, short eventType) override;
};
    }
}

#ifndef COVERAGE_TEST
#include "NisseHandler.tpp"
#endif
#endif

NisseHandler.tpp

#ifndef THORSANVIL_NISSE_NISSE_HANDLER_TPP
#define THORSANVIL_NISSE_NISSE_HANDLER_TPP

#include "NisseService.h"

namespace ThorsAnvil
{
    namespace Nisse
    {

template<typename H, typename... Args>
inline void NisseHandler::addHandler(Args&&... args)
{
    parent.addHandler<H>(std::forward<Args>(args)...);
}

template<typename H, typename... Args>
inline void NisseHandler::moveHandler(Args&&... args)
{
    dropHandler();
    parent.addHandler<H>(std::forward<Args>(args)...);
}

template<typename Handler, typename Param>
inline ServerHandler<Handler, Param>::ServerHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::ServerSocket&& so, Param& param)
    : NisseHandler(parent, base, so.getSocketId(), EV_READ)
    , socket(std::move(so))
    , param(param)
{}

template<typename Handler, typename Param>
inline void ServerHandler<Handler, Param>::eventActivate(LibSocketId /*sockId*/, short /*eventType*/)
{
    ThorsAnvil::Socket::DataSocket accepted = socket.accept();
    addHandler<Handler>(std::move(accepted), param);
}

template<typename Handler>
inline ServerHandler<Handler, void>::ServerHandler(NisseService& parent, LibEventBase* base, ThorsAnvil::Socket::ServerSocket&& so)
    : NisseHandler(parent, base, so.getSocketId(), EV_READ)
    , socket(std::move(so))
{}

template<typename Handler>
inline void ServerHandler<Handler, void>::eventActivate(LibSocketId /*sockId*/, short /*eventType*/)
{
    ThorsAnvil::Socket::DataSocket accepted = socket.accept();
    addHandler<Handler>(std::move(accepted));
}

    }
}

#endif

NisseHandler.cpp

#include "NisseHandler.h"
#include "NisseService.h"
#include "Utility.h"

#include <iostream>

using namespace ThorsAnvil::Nisse;

void eventCB(LibSocketId socketId, short eventType, void* event)
{
    NisseHandler& handler = *reinterpret_cast<NisseHandler*>(event);
    handler.eventActivate(socketId, eventType);
}

NisseHandler::NisseHandler(NisseService& parent, LibEventBase* base, LibSocketId socketId, short eventType)
    : parent(parent)
    , event(event_new(base, socketId, eventType | EV_PERSIST, eventCB, this), event_free)
{
    if (event.get() == nullptr)
    {
        throw std::runtime_error(Socket::buildErrorMessage("ThorsAnvil::Nisse::NisseHandler::", __func__, ": event_new(): Failed"));
    }
    if (event_add(event.get(), nullptr) != 0)
    {
        throw std::runtime_error(Socket::buildErrorMessage("ThorsAnvil::Nisse::NisseHandler::", __func__, ": event_add(): Failed"));
    }
}

void NisseHandler::eventActivate(LibSocketId sockId, short eventType)
{
    std::cerr << "Callback made: " << sockId << " For " << eventType << "\n";
}

void NisseHandler::dropHandler()
{
    if (event_del(event.get()) != 0)
    {
        throw std::runtime_error(Socket::buildErrorMessage("ThorsAnvil::Nisse::NisseEvent::", __func__, ": event_del(): Failed"));
    }
    parent.delHandler(this);
}

#ifdef COVERAGE_TEST
/*
 * This code is only compiled into the unit tests for code coverage purposes
 * It is not part of the live code.
 */
#include "NisseHandler.tpp"
#endif
\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.