views:

63

answers:

3
              ------------                       ------------
              | TclObjct |                       |  Handler |
              ------------                       ------------
                   |__________________________________|
                                   |
                             --------------
                              | NsObject  |---> virtual void recv(Packet*,Handler* callback = 0) = 0;
                             --------------
                                   |
                             --------------
                              | Connector |
                             --------------
                                   |
                      ________________________________
                      |                              |
                      |                         -------------     
                      |                         |   Agent   |
                      |                         -------------
                      |                              |
                      |                         -------------
                      |                         |   OLSR    |
               -------------                    -------------
               |   Queue   |-----> virtual void recv(Packet*, Handler*);
               -------------                    
                      |
               -------------
                | DropTail |
               -------------
                      |
               -------------
                | PriQueue |-----> void recv(Packet* p, Handler* h);
               --------------

Dear all, I am using NS2 to implement a network coding protocol. But I have been stuck on a problem for days regarding to cross reference between classes and the way to pass the "this" pointer.

The class hierarchy is shown in the above figure (Please excuse me it looks like that, I am a new user of this site, and is not allowed to post images).

In the program I have to create a connection from the "PriQueue" class to the "OLSR" class, which I think cross reference might be a nice way (The connection from OLSR to PriQueue is automatically set in NS2 using the pointer 'target_', which is of type NsObject*).

Part of the code is giving below. But the problem is, the pointer "olsr_callback" is always NULL. As a result, when calling function add_rr_ack() from the PriQueue object, the line accessing the 'ra_addr_' variable will generates a segmentation error.

(The program works fine if the line "nsaddr_t addr = ra_addr(); " is blocked)

The cross reference mechanism is obtained from this page: cross reference as stated in post 4

I guess it is the problem of the way I tried to pass the "this" pointer in send_pkt(). But I can't figure out what is wrong. If you have any idea in mind, please help me.

Any help will be appreciated.

Shu.

//------OLSR.h--------//
class PriQueue;
class OLSR : public Agent {
    ......
    nsaddr_t ra_addr_;
    void send_pkt();
    ......
public:
    inline nsaddr_t& ra_addr()  { return ra_addr_; }
    Packet* add_rr_ack(Packet*,PriQueue*);
    ......
}

//------OLSR.cc------//
#include<olsr/OLSR.h>
#include<queue/priqueue.h>

void OLSR::send_pkt() {
    ......
    ......
    target_->recv(p,this);    // 'target_' points to the respective priqueue object 
                              // during the runtime
}

Packet* OLSR::add_rr_ack(Packet* p, PriQueue*) {
    ......
    nsaddr_t  addr = ra_addr();     // Generate a segmentation error!!!!!
    .......
    return p;
}
......

//------priqueue.h------//
class OLSR;

class PriQueue : public DropTail {
public:
    void recv(Packet* p, Handler* h);
    ......
    Packet* deque();
    OLSR* olsr_callback;
    ......
}

//------priqueue.cc------//
#include<olsr/OLSR.h>
#include "priqueue.h"

PriQueue::PriQueue() : DropTail(),olsr_callback(NULL) {......}

PriQueue::recv(Packet* p, Handler* h) {
    ......
    olsr_callback = dynamic_cast<OLSR*>(h);
    //Debug
    printf("Packet received through recv() in PriQueue. \n");
    ......
}

PriQueue::deque() {
   .....
   Packet* p = q_->deque();       

   if(olsr_callback == NULL)  printf("CALLBACK is NULL. \n");
   Packet* p1 = olsr_callback->add_rr_ack(p);
   .....
}

P.S: I also tried to change the recv() function in class PriQueue as follows:

//------priqueue.h------//
void recv(Packet* p, OLSR* h);

// ------priqueue.cc-----//
void PriQueue::recv(Packet* p, OLSR*h) {
   ......
   olsr_callback = h;
   ......
}

// However, in this case, when we call the recv() function from send_pkt(). It will actually invoke the recv() function of the base class Queue, not the recv() function of the PriQueue as expected.

+1  A: 
class OLSR : public Agent

You class OLSR is derived from some class 'Agent' (which I don't know what it is). I assume that is not one of those classes derived from 'Handle' (since it is not shown in the diagram).

Since 'OLSR' is not derived from 'Handle', dynamic_cast of 'Handle' to 'OLSR' fails. You can do dynamic_cast from polymorphic Base to Derived only and not to unrelated classes.

Chubsdad
I am sorry, my mistake. Class 'Agnet' has been added to the diagram. I will try to modify my program, thanks very much for your tip.
Edward
Thank you very much for you help and valuable advice. I have found where the problem is, please see my own posted-answer.
Edward
+1  A: 

The code below works with my compiler. It outputs "20", which was the value I gave to the member OLSR::ra_addr_. A few unstated assumptions I had to add to get things compiling:

  • OLSR or some parent defines recv() so that it's not abstract.
  • Class Handler has at least one virtual function (otherwise using Handler* with dynamic_cast would be ill-formed, and your compiler should complain).
  • You call OLSR::send_pkt at some point. I assume you have checked for its debug output line. (But maybe it's being called with a different PriQueue object?)
  • Ignore Packet::get(). That's just there to give me a pointer so I can call functions matching your signatures.

If you can't figure out why your code isn't working, always try this: Make a copy of all your code, and then remove things a bit at a time until you either pinpoint the problem or get a simple example that you can post in entirety and ask why it doesn't do what you expect.

#include <iostream>

class Packet {
public:
    static Packet* get() { return &dummy_; }
private:
    static Packet dummy_;
};
Packet Packet::dummy_;

class Handler {
public:
    virtual ~Handler() {}
};

class NsObject : public Handler {
public:
    virtual void recv(Packet*, Handler* callback = 0) = 0;
};

class Connector : public NsObject {};

class Queue : public Connector {
public:
    virtual void recv(Packet*, Handler*) {}
};

class DropTail : public Queue {};

class OLSR;

class PriQueue : public DropTail {
public:
    inline PriQueue() : DropTail(), olsr_callback(NULL) {}
    void recv(Packet* p, Handler* h);
    Packet* deque();
private:
    OLSR* olsr_callback;
};

class Agent : public Connector {};

class OLSR : public Agent {
public:
    explicit OLSR(int ra_addr) : Agent(), ra_addr_(ra_addr) {}
    inline int ra_addr() { return ra_addr_; }
    void send_pkt(PriQueue* q);
    Packet* add_rr_ack(Packet* p, PriQueue*);
    virtual void recv(Packet*, Handler*) {}
private:
    int ra_addr_;
};

void PriQueue::recv(Packet* p, Handler* h) {
    olsr_callback = dynamic_cast<OLSR*>(h);
}

Packet* PriQueue::deque() {
    return olsr_callback->add_rr_ack(Packet::get(), this);
}

void OLSR::send_pkt(PriQueue* q) {
    q->recv( Packet::get(), this );
}

Packet* OLSR::add_rr_ack(Packet* p, PriQueue*) {
    std::cout << ra_addr() << std::endl;
    return p;
}

int main() {
    PriQueue q;
    OLSR olsr(20);
    olsr.send_pkt(&q);
    q.deque();

    return 0;
}
aschepler
Thank you very much for your help and notable effort. I have found where the problem is, please see my own posted-answer.
Edward
A: 

Thank you all for your help, Chubsdad and aschepler. I have found where the problem is.

Normally, a packet is scheduled as an event on the simulation timeline using the following statement:

Scheduler::instance().schedule(target_,p,0.0);

where p is the packet which is casted to a event; '0.0' is the delay time of the event, in this case it is zero; and the key parameter, 'target_' is the handler which will process the event.

Here is part of the class NsObject and its implementation:

   //----------- object.h ----------//
    class NsObject : public TclObject, public Handler {
    public:
       NsObject();
       virtual ~NsObject();
       virtual void recv(Packet*, Handler* callback = 0) = 0;
    protected:
       void handle(Event*);
    }

   //------------ object.cc -----------//
    void NsObject::handle(Event* e)
   {
       recv((Packet*)e);   // In my case, this will call the recv(Packet*,Handler*) of PriQueue class.
   }

and here is the implementation of class Handler:

   class Handler {
   public:
       virtual ~Handler() {}
       virtual void Handler(Event* event) = 0;
   }

Based on my previous understanding about NS2, I tried to use

   target_->recv(p,h); 

to avoid event scheduling, and directly call the recv(Packet*, Handler*) function of PriQueue, which turned out to be wrong.

The control will still enter the NsObject::handle(),despite of using target_->recv(p,h), as the NsObject::handle() function takes only a Event* type parameter, the Handler* parameter will always be lost. That is how the olsr_callback variable turned out to be always NULL. (This has been verified in my debugging process.)

So the next step would be make a few adjustments to NsObject, even if I still don't fully understand how it ends up entering function NsObject::recv() when using target_->recv(p,h). :)

Thanks again for your help.

Shu

Edward