User Manual, Developers Guide and API Documentation

How to implement a Layer

Introduction

Layer development is often the fundamental step of developing a wns module. Layers in the wns correspond to ISO OSI Layers and are divided into functionalUnits. There is a simple machanism to connect functionalUnits together. These functionalUnits connected in a specific way and assembled in the Layer class represent the layer of the wns module.

Usage

To define a wns layer it is necessary to derive a class from wns::ldk::Layer and implement three virtual methods.

class SimpleTestLayer :
    public wns::ldk::Layer
{
public:
    // Method to process outgoing compounds.
    virtual void doSendData(osi::PDUPtr pdu);
    // Method to process incoming compounds.
    virtual void doOnData(osi::PDUPtr pdu);

    virtual std::string getName() const { return "SimpleTestLayer"; }
};

The two methods doSendData and doOnData are called whenever the layer is asked to process outgoing compounds (sendData) and incoming compounds (onData). Typically the function of a layer is quite complex hence a split of the layer is necessary. The wns library provides a mechanism to easily build up a layer split into functionalUnits. For this several functionalUnits are already defined (FunctionalUnit reference).

If a custom functionalUnit is defined there are minimum requirements to be met:

The functionalUnit has to be derived from

Further the methods CompoundHandlerInterface::isAccepting(), CompoundHandlerInterface::sendData(), CompoundHandlerInterface::onData() and CompoundHandlerInterface::wakeup() need to be implemented which are derived from the FunctionalUnit which is again derived from the CompoundHandlerInterface. The class declaration may look like this:

class ExampleFunctionalUnit :
    virtual public wns::ldk::FunctionalUnit,
    public wns::ldk::CommandTypeSpecifier<wns::ldk::EmptyCommand>,
    public wns::ldk::HasReceptor<>,
    public wns::ldk::HasConnector<>,
    public wns::ldk::HasDeliverer<>,
    public wns::Cloneable<ExampleFunctionalUnit>
{
public:
    ExampleFunctionalUnit( wns::ldk::fun::FUN* fuNet );


    // Handles compounds from higher functional units
    virtual void doSendData(const wns::ldk::CompoundPtr& sdu);

    // Handles compounds from lower functional units
    virtual void doOnData(const wns::ldk::CompoundPtr& compound);

private:
    // CompoundHandlerInterface
    // Returns true if the FunctionalUnit is able to accept Compounds from higher FunctionalUnit.
    virtual bool doIsAccepting( const wns::ldk::CompoundPtr& compound ) const;

    // Wakes the FunctionalUnit and is called from lower FunctionalUnit whenever they accept compounds again.
    virtual void doWakeup();
};

For further details how to implement a functionalUnit see How to implement a FunctionalUnit.

Deriving from the FunctionalUnit the method FunctionalUnit::connect() gives access to the connection mechanism of functionalUnits. Higher functionalUnits may be connected with lower level functionalUnits. The internal structure of the layer is set up in the constructor of the layer. Here the functionalUnits are created and connected.

TestLayer::TestLayer(const wns::pyconfig::View& _config)    :
    wns::ldk::Layer(),
    config( _config )
{
    pyconfig::Parser emptyConfig;

    // create a fuNet
    fuNet = new wns::ldk::fun::Main(this);

    // create functionalUnits
    topStub = new wns::ldk::tools::Stub(fuNet, emptyConfig);

    // create and configure drop tail buffer
    wns::pyconfig::View droptailConfig(config, "Dropping");
    buffer = new wns::ldk::buffer::Dropping(fuNet, droptailConfig);

    // create the example functionalUnit
    exampleFunctionalUnit = new ExampleFunctionalUnit(fuNet);
    bottomStub = new wns::ldk::tools::Stub(fuNet, emptyConfig );

    // connect functionalUnits
    topStub
        ->connect(buffer)
        ->connect(exampleFunctionalUnit)
        ->connect(bottomStub);
}

In this example there are four functionalUnits declared. Two stubs are set up as upper and lower endpoint of the layer. A buffer is part of the functionalUnit chain to store incoming packets. Note that the buffer needs to be initialized with a pyconfig::View which tells the buffer the bufferlength. Last but not least the ExampleFunctionalUnit is part of the layer.

All four functionalUnits need to be connected. This is done by calling the connect() method of the highest functionalUnit. The next lower functionalUnit is given as parameter to the connect() method which returns a pointer of the lower functionalUnit. This makes connecting functionalUnits easy by calling connect() from the highest functionalUnit to the lowest.

Finally the Layer has to direct doSendData() calls to the highest functionalUnit and doOnData() calls to the lowest functionalUnit in the functionalUnit chain.

void TestLayer::doSendData(osi::PDUPtr sdu)
{
    // create a PDU that can be handled by the functionalUnits
    wns::ldk::CompoundPtr compound(fuNet->createCompound(sdu));
    // let the topStub handle the PDU
    topStub->sendData(compound);
}

void TestLayer::doOnData(osi::PDUPtr pdu)
{
    // this is a Compound
    wns::ldk::CompoundPtr command = dynamicCast<wns::ldk::Compound>(pdu);
    // let the lowest functionalUnit handle this pdu
    bottomStub->onData(command);
}

Now the layer is ready to use.


Generated on Wed Feb 8 03:32:25 2012 for openWNS by  doxygen 1.5.5