0

I am working on a project for my job to encode/decode into buffers DNS Records objects in C++. Some records have the same infos, so I created a class Dns message with theses basic infos:

class CDnsMessage
{
public:
    CDnsMessage();
    virtual ~CDnsMessage();

    virtual int GetSize() = 0;
    uint32_t       m_ttl; 
    DnsClass       dclass; 
    DnsType        type; 
    std::string    m_domain;    
};

The DnsClass and DnsTypes are enum with the differents class/types I use. Then I have my sub-classes for each record, I will take A for the example:

class CDns_RR_A : public CDnsMessage
{
public:
    CDns_RR_A();

    virtual ~CDns_RR_A();
    virtual int GetSize(CDnsMessage const& msg);

    uint32_t        m_address;
};

Then I have my encode/decode function in another header, encoder.h and encoder.cpp.

I am receiving a DnsMessage (the object) and receiving buffer, and I encode or decode. So I used dynamic cast to know which type of record it is, and adapt the encode and decode to the variables the object has. here is my decode for example:

EncodeResult DecodeData(const char * buffer,CDnsMessage & msg,std::size_t size)
{
    EncodeResult res(ENCODE_OK);

    uint32 ttl = 0;
    eDnsClass dnsclass;
    eDnsType  dnstype;

    //decoding RR_A
    if(CDns_RR_A* RR_A_msg = dynamic_cast< CDns_RR_A* >( &msg ))
    {       
        uint32_t address;

        dnsclass = CLASS_IN;
        msg.dclass = dnsclass;
        dnstype = TYPE_A;
        msg.type = dnstype;

        res = DecodeInt32(&buffer,&size,&ttl);
        CHECK_DECODE_ERROR(res);
        msg.m_ttl = ttl;

        res = DecodeInt32(&buffer,&size,&address);
        CHECK_DECODE_ERROR(res);
        msg.m_address = address;
    }
}

The DecodeInt32 is a function made by people before long time ago, it takes a buffer (char**), a size_t* and a uint32.

I have two problems, first I can't access the members of my subclass, when I compile I got a problem with msg.dclass or msg.type and It says "request for member 'class' in 'RR_A_msg', which is of non-class type 'CDns_RR_A*' but I don't understand, if my dynamic cast works it mean that the msg received waiting to be fulfilled is of type A no?

And my second problem is: I am using uint32_t for the ttl (imposed by enterprise) and my decodeint32 takes uint32 so the compiler says invalid conversion from uint32_t* to uint32.

Is there away to convert one to another?

Edit: Updated my code following answers and advices, now i have

if(dynamic_cast< CDns_RR_A* >( &msg ) != nullptr)
                            {       
                                    CDns_RR_A* RR_A_msg = dynamic_cast< CDns_RR_A* >( &msg )

                                    uint32 address;

                                    dnsclass = CLASS_IN;
                                    RR_A_msg->dclass = dnsclass;
                                    dnstype = TYPE_A;
                                    RR_A_msg->type = dnstype;

                                    res = DecodeInt32(&buffer,&size,&ttl);
                                    CHECK_DECODE_ERROR(res);
                                    RR_A_msg->m_ttl = ttl;

                                    res = DecodeInt32(&buffer,&size,&address);
                                    CHECK_DECODE_ERROR(res);
                                    RR_A_msg->m_address = address;
                            }

Changing uint32_t to uint32 for decode worked, and having RR_A_msg-> instead of msg. worked too. But now i have undefined reference totypeinfo for CDns_RR_A'`

Raphael Lopes
  • 141
  • 2
  • 14
  • 1
    `if(CDns_RR_A* RR_A_msg = dynamic_cast< CDns_RR_A* >( &msg ))` looks unusual. Just write `if(dynamic_cast< CDns_RR_A* >( &msg ) != nullptr)`. – jww Jun 06 '19 at 06:59
  • I just changed thanks to your advice. But to do " RR_A_msg->m_address" i still have to initialize the way i did the RR_A_ – Raphael Lopes Jun 06 '19 at 07:45
  • `RR_A_msg` is not used in the code. You don't need a temporary for it. – jww Jun 06 '19 at 07:46

1 Answers1

1

For the "you cannot convert uint32_t* to uint32" the issue is that the former is a pointer and the later is not. You should take the & off the front and pass the value not a pointer to it.

I don't know why you can't get the class member (maybe related to using a reserved name as a variable?) but you shouldn't be able to access m_address in this way.

Instead of

msg.m_address

You need to be using

RR_A_msg->m_address
Henry
  • 54
  • 7
  • Thanks, just used it, it works perfectly for the uint. For the msg.m_address i used your solution (i got less errorrs) but i have this one now : "undefined reference to `typeinfo for CDns_RR_A'" – Raphael Lopes Jun 06 '19 at 07:39
  • This post has some possible solutions: https://stackoverflow.com/questions/307352/g-undefined-reference-to-typeinfo. Possibly you need the override specifier on your virtual functions in CDns_RR_A – Henry Jun 06 '19 at 08:03
  • It's the function signature of getSize on the derived class. It needs to be the same as that on the base. You also shouldn't need the instance of the base class passed in because the members of the base are available in the derived class – Henry Jun 06 '19 at 08:11
  • But when i call my function i don't know if i have an A record object or SRV so i have to pass a generic object : CDnsMessage no ? – Raphael Lopes Jun 06 '19 at 08:21
  • I tried to comment Getsize in the .h and .cpp to see if this remove the error but it still can't compile. – Raphael Lopes Jun 06 '19 at 08:39
  • You should read up about polymorphism in c++, you need to call that function against an object that either is or derives from your base. – Henry Jun 06 '19 at 17:52