Have you ever worked in any protocol development? I have been part of some protocol development; here I am sharing object oriented design strategy I followed. You can use this design as a Skeleton when you develop a new protocol.
For a protocol stack, data (packet) is flowing from top to bottom in Senders side and opposite in receiver’s side as shown below.

We can use the layered approach when designing a protocol stack class; following class diagram shows the players involved in the design.

Following table shows a short description about the classes involved in this design.

Code is shared below.
Layer.h
#pragma once
#include <iostream>
#include "Packet.h"
#include <vector>
class CPacket;
using namespace std;
class ILayer
{
public:
virtual void Send(CPacket&) = 0;
virtual void Recv(CPacket&) = 0;
virtual void Process(CPacket&) = 0;
virtual PROTOCOL_LAYER GetLayer() = 0;
virtual void GetHeader(vector<BYTE>& m_Data) = 0;
virtual void GetBody(vector<BYTE>& m_Data) = 0;
virtual void GetTrailer(vector<BYTE>& m_Data) = 0;
};
class ILayerHandler
{
public:
virtual ILayer* GetLowerLayer(PROTOCOL_LAYER layer) = 0;
virtual ILayer* GetUpperLayer(PROTOCOL_LAYER layer) = 0;
};
LayerImpl.h
#pragma once
#include "Layer.h"
#include <cstring>
#include <iterator>
#include "ProtocolStack.h"
#include <iostream>
#include <string>
class AbstractLayer: public ILayer
{
public:
AbstractLayer(ILayerHandler* pLayerhanler):m_pLayerhanler(pLayerhanler)
{
}
virtual void Send(CPacket& packet)
{
vector<BYTE> data;
GetHeader(data);
packet.AddHeader(data);
data.clear();
GetBody(data);
packet.AddBody(data);
data.clear();
GetTrailer(data);
packet.AddTrailer(data);
Process(packet);
if(m_pLayerhanler->GetLowerLayer(GetLayer()))
m_pLayerhanler->GetLowerLayer(GetLayer())->Send(packet);
}
virtual void Recv(CPacket& packet){
std::cout<<"\n "<< CProtocolStack::GetLayerName(GetLayer())<<" data is:";
vector<BYTE> header;
packet.ExtractHeader(header, GetLayer());
packet.Print(header);
vector<BYTE> body;
packet.ExtractBody(body, GetLayer());
packet.Print(body);
vector<BYTE> trailer;
packet.ExtractTrailer(trailer, GetLayer());
packet.Print(trailer);
if(m_pLayerhanler->GetUpperLayer(GetLayer()))
m_pLayerhanler->GetUpperLayer(GetLayer())->Recv(packet);
}
virtual void Process(CPacket&) = 0;
virtual PROTOCOL_LAYER GetLayer() = 0;
virtual void GetHeader(vector<BYTE>& m_Data) = 0;
virtual void GetBody(vector<BYTE>& m_Data) = 0;
virtual void GetTrailer(vector<BYTE>& m_Data) = 0;
private:
ILayerHandler* m_pLayerhanler;
};
class CApplicatioLayer : public AbstractLayer
{
public:
CApplicatioLayer(ILayerHandler* pLayerhanler):AbstractLayer(pLayerhanler)
{
}
virtual void Process(CPacket& packet) override
{
cout<<"nProcessing packet";
}
virtual PROTOCOL_LAYER GetLayer() override
{
return APPLICATION_LAYER;
}
virtual void GetHeader(vector<BYTE>& m_Data) override
{
std::string str = "APPLICATION-LAYER-HEADER";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
virtual void GetBody(vector<BYTE>& m_Data) override
{
std::string str = "APPLICATION-LAYER-BODY";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
virtual void GetTrailer(vector<BYTE>& m_Data) override
{
std::string str = "APPLICATION-LAYER-TRAILER";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
};
class CTransportLayer : public AbstractLayer
{
public:
CTransportLayer(ILayerHandler* pLayerhanler):AbstractLayer(pLayerhanler)
{
}
virtual void Process(CPacket& packet) override
{
cout<<"\nProcessing packet";
}
virtual PROTOCOL_LAYER GetLayer() override
{
return TRANSPORT_LAYER;
}
virtual void GetHeader(vector<BYTE>& m_Data) override
{
std::string str = "TRANSPORT-LAYER-HEADER";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
virtual void GetBody(vector<BYTE>& m_Data) override
{
std::string str = "TRANSPORT-LAYER-BODY";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
virtual void GetTrailer(vector<BYTE>& m_Data) override
{
std::string str = "TRANSPORT-LAYER-TRAILER";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
};
class CNetworkLayer : public AbstractLayer
{
public:
CNetworkLayer(ILayerHandler* pLayerhanler):AbstractLayer(pLayerhanler)
{
}
virtual void Process(CPacket& packet) override
{
cout<<"\nProcessing packet";
}
virtual PROTOCOL_LAYER GetLayer() override
{
return NETWORK_LAYER;
}
virtual void GetHeader(vector<BYTE>& m_Data) override
{
std::string str = "NETWORK-LAYER-HEADER";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
virtual void GetBody(vector<BYTE>& m_Data) override
{
std::string str = "NETWORK-LAYER-BODY";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
virtual void GetTrailer(vector<BYTE>& m_Data) override
{
std::string str = "NETWORK-LAYER-TRAILER";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
};
class CLinkLayer : public AbstractLayer
{
public:
CLinkLayer(ILayerHandler* pLayerhanler):AbstractLayer(pLayerhanler)
{
}
virtual void Process(CPacket& packet) override
{
cout<<"\nProcessing packet";
}
virtual PROTOCOL_LAYER GetLayer() override
{
return LINK_LAYER;
}
virtual void GetHeader(vector<BYTE>& m_Data) override
{
std::string str = "LINK-LAYER-HEADER";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
virtual void GetBody(vector<BYTE>& m_Data) override
{
std::string str = "LINK-LAYER-BODY";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
virtual void GetTrailer(vector<BYTE>& m_Data) override
{
std::string str = "LINK-LAYER-TRAILER";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
};
class CPhysicalLayer : public AbstractLayer
{
public:
CPhysicalLayer(ILayerHandler* pLayerhanler):AbstractLayer(pLayerhanler)
{
}
virtual void Process(CPacket& packet) override
{
cout<<"nProcessing packet";
}
virtual PROTOCOL_LAYER GetLayer() override
{
return PHYSICAL_LAYER;
}
virtual void GetHeader(vector<BYTE>& m_Data) override
{
std::string str = "PHYSICAL-LAYER-HEADER";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
virtual void GetBody(vector<BYTE>& m_Data) override
{
std::string str = "PHYSICAL-LAYER-BODY";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
virtual void GetTrailer(vector<BYTE>& m_Data) override
{
std::string str = "PHYSICAL-LAYER-TRAILER";
std::copy(str.begin(), str.end(), std::back_inserter(m_Data));
}
};
Packet.h
#pragma once
#include <vector>
using namespace std;
//#include "Layer.h"
enum PROTOCOL_LAYER;
//[ <Header_Information> ! <Body_Information> ! <Trailer_information> ]
class CPacket
{
public:
CPacket();
static char LAYER_EXTRACTOR;
static char LAYER_DATA_EXTRACTOR;
static size_t MAX_PACKET_LENGTH;
enum SECTION
{
HEADER =0,
BODY,
TRAILER
};
void AddHeader(vector<BYTE>& m_Data);
void AddBody(vector<BYTE>& m_Data);
void AddTrailer(vector<BYTE>& m_Data);
void ExtractHeader(vector<BYTE>& m_Data, PROTOCOL_LAYER layer);
void ExtractBody(vector<BYTE>& m_Data, PROTOCOL_LAYER layer);
void ExtractTrailer(vector<BYTE>& m_Data, PROTOCOL_LAYER layer);
size_t GetLength() { return m_nOffset; }
void Split( vector<BYTE>& result, PROTOCOL_LAYER& layer, SECTION section );
static void Print(vector<BYTE>& data);
void Display();
private:
vector<BYTE> m_Data;
size_t m_nOffset;
};
Packet.cpp
#include "stdafx.h"
#include "Packet.h"
#include <algorithm>
#include <iostream>
char CPacket::LAYER_EXTRACTOR = '>';
char CPacket::LAYER_DATA_EXTRACTOR = '|';
size_t CPacket::MAX_PACKET_LENGTH = 1024;
void CPacket::Print( vector<BYTE>& data )
{
std::cout<<"\n";
for(int nIndex = 0; nIndex < data.size(); nIndex++)
{
std::cout<<data[nIndex];
}
}
CPacket::CPacket():m_nOffset(0)
{
m_Data.reserve(MAX_PACKET_LENGTH);
}
void CPacket::AddHeader( vector<BYTE>& Data )
{
size_t index = m_nOffset, nDataIndex = 0;
for (index = m_nOffset, nDataIndex = 0; nDataIndex < Data.size(); index++)
{
m_Data.push_back(Data[nDataIndex++]);
}
m_Data.push_back(LAYER_DATA_EXTRACTOR);
m_nOffset = index+1;
}
void CPacket::AddBody( vector<BYTE>& Data )
{
size_t index = m_nOffset, nDataIndex = 0;
for (index = m_nOffset, nDataIndex = 0; nDataIndex < Data.size(); index++)
{
m_Data.push_back(Data[nDataIndex++]);
}
m_Data.push_back(LAYER_DATA_EXTRACTOR);
m_nOffset = index+1;
}
void CPacket::AddTrailer( vector<BYTE>& Data )
{
size_t index = m_nOffset, nDataIndex = 0;
for (index = m_nOffset, nDataIndex = 0; nDataIndex < Data.size(); index++)
{
m_Data.push_back(Data[nDataIndex++]);
}
m_Data.push_back(LAYER_DATA_EXTRACTOR);
m_nOffset = index+1;
}
void CPacket::ExtractHeader( vector<BYTE>& m_Data, PROTOCOL_LAYER layer )
{
Split(m_Data, layer, HEADER);
}
void CPacket::ExtractBody( vector<BYTE>& m_Data, PROTOCOL_LAYER layer )
{
Split(m_Data, layer, BODY);
}
void CPacket::ExtractTrailer( vector<BYTE>& m_Data, PROTOCOL_LAYER layer )
{
Split(m_Data, layer, TRAILER);
}
void CPacket::Split( vector<BYTE>& result, PROTOCOL_LAYER& layer, SECTION section )
{
std::vector<std::vector<BYTE>> m_SplitteData;
std::vector<BYTE>::iterator iter = m_Data.begin();
std::vector<BYTE>::iterator statInex = iter;
int ncount =0;
int nDiv = (APPLICATION_LAYER - layer)*3+(section+1);
while ((iter = std::find(iter,m_Data.end(), LAYER_DATA_EXTRACTOR)) != m_Data.end())
{
// Do something with iter
ncount++;
if(ncount%nDiv == 0){
std::vector<BYTE> temp(statInex, iter);
result =temp;
break;
}
iter++;
statInex = iter;
}
}
void CPacket::Display()
{
size_t nCount =0;
std::cout<<"\n---------------------------------------------------------------\n";
for (size_t nDataIndex = 0; nDataIndex < m_Data.size(); nDataIndex++)
{
if(m_Data[nDataIndex] == '|'){
nCount++;
if(nCount % 3 == 0)
std::cout<<"\n";
}
std::cout<<m_Data[nDataIndex];
}
std::cout<<"\n---------------------------------------------------------------\n";
}
ProtocolStack.h
#pragma once
#include <vector>
#include "Layer.h"
class CProtocolStack: public ILayerHandler
{
public:
CProtocolStack();
~CProtocolStack();
void Send (CPacket& packet);
void Recv(CPacket& packet);
ILayer* GetLowerLayer(PROTOCOL_LAYER layer);
ILayer* GetUpperLayer(PROTOCOL_LAYER layer);
ILayer* GetLayer(PROTOCOL_LAYER layer);
void Display(CPacket& packet);
static string GetLayerName(PROTOCOL_LAYER layer);
private:
void CreateStack();
std::vector<ILayer*> m_Layers;
};
ProtocolStack.cpp
#include "stdafx.h"
#include "ProtocolStack.h"
#include "LayerImpl.h"
CProtocolStack::CProtocolStack()
{
CreateStack();
}
CProtocolStack::~CProtocolStack()
{
for(auto it =m_Layers.begin(); it != m_Layers.end(); ++it)
{
ILayer* pLayer = *it;
delete pLayer;
}
m_Layers.clear();
}
void CProtocolStack::CreateStack()
{
ILayer* pLayer = new CPhysicalLayer(this);
m_Layers.push_back(pLayer);
pLayer = new CLinkLayer(this);
m_Layers.push_back(pLayer);
pLayer = new CNetworkLayer(this);
m_Layers.push_back(pLayer);
pLayer = new CTransportLayer(this);
m_Layers.push_back(pLayer);
pLayer = new CApplicatioLayer(this);
m_Layers.push_back(pLayer);
}
void CProtocolStack::Send( CPacket& packet )
{
GetLayer(APPLICATION_LAYER)->Send(packet);
}
void CProtocolStack::Recv( CPacket& packet )
{
GetLayer(PHYSICAL_LAYER)->Recv(packet);
}
ILayer* CProtocolStack::GetLowerLayer( PROTOCOL_LAYER layer )
{
ILayer* pLayer = NULL;
switch(layer)
{
case PHYSICAL_LAYER:
break;
default:
pLayer = m_Layers[layer-1];
break;
}
return pLayer;
}
ILayer* CProtocolStack::GetUpperLayer( PROTOCOL_LAYER layer )
{
ILayer* pLayer = NULL;
switch(layer)
{
case APPLICATION_LAYER:
break;
default:
pLayer = m_Layers[layer+1];
break;
}
return pLayer;
}
ILayer* CProtocolStack::GetLayer( PROTOCOL_LAYER layer )
{
return m_Layers[layer];
}
std::string CProtocolStack::GetLayerName( PROTOCOL_LAYER layer )
{
string sLayer;
switch(layer)
{
case PHYSICAL_LAYER:
sLayer ="Physical Layer";
break;
case LINK_LAYER:
sLayer ="Link Layer";
break;
case NETWORK_LAYER:
sLayer ="Network Layer";
break;
case TRANSPORT_LAYER:
sLayer ="Transport Layer";
break;
case APPLICATION_LAYER:
sLayer ="Application Layer";
break;
}
return sLayer;
}
void CProtocolStack::Display( CPacket& packet )
{
packet.Display();
}
Source code using VS 2010 is available to download at:https://drive.google.com/open?id=0B9PG5yLW1qG4ZEdQUzRiUENiY1E