[Xorp-hackers] Constructing packets

Pavlin Radoslavov pavlin at ICSI.Berkeley.EDU
Fri Feb 20 11:51:25 PST 2009


Victor Faion <vfaion at gmail.com> wrote:

> I was trying to construct a simple packet and send it over a socket. I
> defined the header like this:
> 
> typedef struct bpsfhdr {
>   uint8_t   type;
>   uint32_t  src;
> } bpsfhdr;
> 
> Then to construct it and send it I did this just as a test:
> 
> vector<uint8_t> data;
> data.reserve(sizeof(bpsfhdr));
> bpsfhdr hdr;
> hdr.type = 42;
> hdr.src = ip.addr();
> memcpy(&data[0], &hdr, sizeof(bpsfhdr));
> socketCl.send_send(dst, sockid, data,
>   callback(this, &Neighbour::send_cb));

You shouldn't be using method vector<>::reserve() because all it
does is helping avoiding re-allocation (e.g., if you call
vector<>::resize()).
E.g., if you print data.size() right resize(), you will get 0.

Instead, you should use data.resize(...) or even better just specify
the size when you declare the vector variable:

vector<uint8_t> data(sizeof(bpsfhdr));


> I didn't really know how to put the data inside the vector. For
> example if I use the copy_out() function of the IPv4 class I thought
> the IP address would overflow if I just had a uint8_t field in the
> struct. Is there a higher level way of adding data into the packets

You can use the above mechanism (write the data to a struct, and then
copying it to the buffer), but you have to be careful with the
host/network ordering of the values, and with the padding in the
structure.

Alternatively, you can use the embed_*() and extract_*() functions
in libproto/packet.hh which allow you to write directly to the
output buffer. By using this appropac you avoid the extra memory
copy, and you don't have the host/network ordering and padding
issues.

> passed into send_send, for example, adding a variable length string?
> Can I have for example a field of type string inside the struct? I
> think this is where I am going wrong, but I looked at a few examples
> in other XORP processes and it was done in a similar way.

You can't just use the C++ string and just copy it on the wire. You
must use C-style string (basically a variable length array with the
string value).
There are different ways to encode the string on the wire; one of
the simplest is to define a fixed max-length for the string itself
and reserve that space in your packet. Then have the string
zero-terminated as in C to avoid the extra encoding of the length
itself.

> To receive/umarshall the packet in socket4_user_0_1_recv_event I used
> the AlignData class:
> 
> AlignData<struct bpsfhdr> aligned(pdata);
> const struct bpsfhdr* pkt = aligned.payload();
> uint8_t type = pkt->type;
> IPv4 src(pkt->src);
> XLOG_INFO("type = %u src = %s", type, src.str().c_str());
> 
> But when I run this I get the following error:
> 
> xorp_fea: asyncio.cc:450: void AsyncFileWriter::add_data(const
> std::vector<uint8_t, std::allocator<uint8_t> >&, const
> ref_ptr<XorpCallback4<void, AsyncFileOperator::Event, const uint8_t*,
> size_t, size_t> >&): Assertion `data.size() != 0' failed.
> [ 2009/02/19 17:15:58  ERROR xorp_rtrmgr:30765 RTRMGR +754
> module_manager.cc done_cb ] Command
> "/root/project/xorp1.6/install/fea/xorp_fea": terminated with signal
> 6; aborted with a core dump.

You get the above assert because the original data size was zero
(because of the usage of reserve()).

Regards,
Pavlin



More information about the Xorp-hackers mailing list