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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.