Buffering object

A

Andrea Crotti

I have to design something to approach one of the (I think) classical
problems in network.

I need to send out packets (which are objects), but I need to take care
of possible retransmissions.

Suppose I can retransmit 3 times before giving up, I need to
- store the packet somewhere until I'm sure it reached destination
- setup a timer from the first time I send it
- at every timer increase a counter

But the problem is that the timer could be different for all the
packets, so I need "n" different timers (it's an event driven simulation
model) for n different packets.


So well I thought to manage all this externally, in a PacketHandler
class.

This class should in my idea take care of:
- create the object dynamically (using new)
- setup the timers and raise the right events
- clear the memory as soon as possible (that's the most important thing)

What I don't understand is how to implement it.
I mean, every packet type has its constructor with some parameters.

So, or I have a function "makePacketX" for every type of packet OR I
have to pass the pointer already initialized into the PacketHandler.

And also to make sure that the return type is correct I thought to use a
template class, and then I need to have a PacketHandler for every Data
type, which is again a bit annoying.

So the questions would be:
1. is that bad to allocate with new something outside PacketHandler and pass
the pointer inside to be eventually freed?

2. are there other better options to accomplish what I would like to do?


// this is a sketch of a possible class
// every packet stored it's fetched by its sequential number
template<class T>
class PacketHandler
{
private:
std::map<serial_t, T *> factory;
serial_t counter;

public:
PacketHandler()
: counter(0)
{}

serial_t getCounter() { return counter; }

T *getPacket(serial_t);


};
 
J

Jeremy

I have to design something to approach one of the (I think) classical
problems in network.

I need to send out packets (which are objects), but I need to take care
of possible retransmissions.

Just a suggestion, but I would create a packet structure to hold the
packet data to be sent, then instead of creating individual timers for
each packet I would maintain a timer wheel. Or basically one timer
mechanism and a bucket for every scheduled packet. Once the packet is
sent out the interface, place the packet data in the timer wheel as
per your re-transmission timeout values, or if the number of re-
transmits has been exceeded, don't. Once the timeout event happens, it
should just be resent. Once a response comes in, simply cancel the
timer which removes the timer from the wheel. The timer and packet
should be cleaned up together. Your main process may do something like
listen asynchronously on an interface for incoming packets, process
packets as they arrive (or for a certain amount of time) by canceling
the associated timer, then service the timer wheel which may include
sending out the re-transmissions. If your doing high throughput and
need high resolution timers you may want to explore running the timer
wheel and receive interface listener in different threads to reduce
problems with granularity on sending the re-transmissions. But I've
seen this single-threaded approach handle a very high throughput
without too much of a problem.
 
A

Andrea Crotti

Jeremy said:
Just a suggestion, but I would create a packet structure to hold the
packet data to be sent, then instead of creating individual timers for
each packet I would maintain a timer wheel. Or basically one timer
mechanism and a bucket for every scheduled packet. Once the packet is
sent out the interface, place the packet data in the timer wheel as
per your re-transmission timeout values, or if the number of re-
transmits has been exceeded, don't. Once the timeout event happens, it
should just be resent. Once a response comes in, simply cancel the
timer which removes the timer from the wheel. The timer and packet
should be cleaned up together. Your main process may do something like
listen asynchronously on an interface for incoming packets, process
packets as they arrive (or for a certain amount of time) by canceling
the associated timer, then service the timer wheel which may include
sending out the re-transmissions. If your doing high throughput and
need high resolution timers you may want to explore running the timer
wheel and receive interface listener in different threads to reduce
problems with granularity on sending the re-transmissions. But I've
seen this single-threaded approach handle a very high throughput
without too much of a problem.

Hi Jeremy thanks for your answer.

Well I have further challenges, since I'm using an event driven
simulator (omnet++)...

So basically all I can do when I send a packet is
"addEvent(PACKET_TIMEOUT_INTERVAL, PACKET_TIMEOUT_EVENT)"

But then the event is catched in the top level class, and from that
class I have to fetch the right packet.

The function in the main class is

handleEvent(int event)

so I guess I need some function to take the event int and map it to the
right packet.
 
J

Jeremy

Hi Jeremy thanks for your answer.

Well I have further challenges, since I'm using an event driven
simulator (omnet++)...

So basically all I can do when I send a packet is
"addEvent(PACKET_TIMEOUT_INTERVAL, PACKET_TIMEOUT_EVENT)"

But then the event is catched in the top level class, and from that
class I have to fetch the right packet.

The function in the main class is

handleEvent(int event)

so I guess I need some function to take the event int and map it to the
right packet.

It would seem you have three events:
1. Send new packet
2. receive packet
3. timer expiry

When each of those happen I gather you place an event on the queue.
The Event structure must hold the ip packet structure and ancillary
information (i.e. timeout, number of re-transmits etc). I wouldn't
think you would take an event and map it to the right packet, you
probably need to take information from the packet structure itself.
Not sure if the packets you are sending/receiving are your own
proprietary protocol or not, but if these packets aren't running on a
connection-oriented transport layer (i.e. TCP, SCTP) I would expect
the application layer to contain some sort of transaction id in order
to map the requests/responses. You could probably match packets that
way.

But, even though I understand what you are doing, I sure you know your
own restrictions more than I.
 
A

Andrea Crotti

It would seem you have three events:
1. Send new packet
2. receive packet
3. timer expiry

When each of those happen I gather you place an event on the queue.
The Event structure must hold the ip packet structure and ancillary
information (i.e. timeout, number of re-transmits etc). I wouldn't
think you would take an event and map it to the right packet, you
probably need to take information from the packet structure itself.
Not sure if the packets you are sending/receiving are your own
proprietary protocol or not, but if these packets aren't running on a
connection-oriented transport layer (i.e. TCP, SCTP) I would expect
the application layer to contain some sort of transaction id in order
to map the requests/responses. You could probably match packets that
way.

But, even though I understand what you are doing, I sure you know your
own restrictions more than I.


Well no it's not so simple, I don't even even IP addresses.
So now the idea is to have a general factory with an increasing
counter for all the type of packets.
At that factory I have unfortunately to pass the object already
instantiated, otherwise it's really a pain.

Then every time I send out a packet I generate an event with a number
that can be converted again to the packet sequential number.

In this way at every event like that I can check directly what packet
is referring to and so on.

Well is rather complicated and I have to make sure I don't overwrite
(because of overflows) positions that are still busy, but it should
work..
 
J

Jorgen Grahn

I have to design something to approach one of the (I think) classical
problems in network.

I need to send out packets (which are objects), but I need to take care
of possible retransmissions.

Suppose I can retransmit 3 times before giving up, I need to
- store the packet somewhere until I'm sure it reached destination

To be pedantic, you don't have to store the /packet/, just enough
information so you can create the same packet again. That information
may be much more space-efficient and easier to handle than a
std::vector<uint8_t> or whatever type you use for packets.

/Jorgen
 
A

Andrea Crotti

To be pedantic, you don't have to store the /packet/, just enough
information so you can create the same packet again.  That information
may be much more space-efficient and easier to handle than a
std::vector<uint8_t> or whatever type you use for packets.

/Jorgen

Sure that's true.
In my case it's not a big deal since I'm only sending headers, so I
don't know how much I could really gain having another representation
of the data.

Anyway I definitely need to free that memory as soon as possible.

A maybe easier possibility (keeping my code as it is more or less)
would be to do

InnerData *data = new InnerData(..);
// it takes a reference
Container *cont = new Container(*data);

delete data;
...
// when possible delete cont too

Supposing that the constructor of Container copies everything instead
of just taking the pointer it might also work, or not?
 
J

Jorgen Grahn

Sure that's true.
In my case it's not a big deal since I'm only sending headers, so I
don't know how much I could really gain having another representation
of the data.

Yes, it depends on the application. (I haven't kept track of your
recent postings.)
Anyway I definitely need to free that memory as soon as possible.

"Free" it in some sense, yes. It doesn't have to mean operator delete;
you might keep your packets in some standard container which does the
memory management more efficiently.
A maybe easier possibility (keeping my code as it is more or less)
would be to do

InnerData *data = new InnerData(..);
// it takes a reference
Container *cont = new Container(*data);

delete data;
..
// when possible delete cont too

Supposing that the constructor of Container copies everything instead
of just taking the pointer it might also work, or not?

I don't see the relation between the code above and the problem of
implementing retransmission, but I would want to write it as:

Container cont(Innerdata(..));

/Jorgen
 
J

James Kanze

I have to design something to approach one of the (I think) classical
problems in network.
I need to send out packets (which are objects), but I need to take care
of possible retransmissions.
Suppose I can retransmit 3 times before giving up, I need to
- store the packet somewhere until I'm sure it reached destination
- setup a timer from the first time I send it
- at every timer increase a counter
But the problem is that the timer could be different for all the
packets, so I need "n" different timers (it's an event driven simulation
model) for n different packets.

Not really. Or it depends on what you mean by "timer".
So well I thought to manage all this externally, in a PacketHandler
class.
This class should in my idea take care of:
- create the object dynamically (using new)
- setup the timers and raise the right events
- clear the memory as soon as possible (that's the most important thing)

I wonder if you aren't mixing issues. I suspect that the
packets should be created elsewhere; the PacketHandler should be
private to the logic which is responsible for sending them.

[...]
And also to make sure that the return type is correct

Huh? Classes don't have return types.
I thought to use a
template class, and then I need to have a PacketHandler for every Data
type, which is again a bit annoying.

Packets are likely represented by a class hierarchy. All your
"consumer" needs to do is to deal with the public interface,
however. (Alternatively: a Packet is nothing more than an
So the questions would be:
1. is that bad to allocate with new something outside PacketHandler and pass
the pointer inside to be eventually freed?

No. It's a very frequent pattern, and it's directly supported
in the standard with std::auto_ptr.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,738
Latest member
JinaMacvit

Latest Threads

Top