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
asked Jul 9, 2017 at 19:44
\$\endgroup\$

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.