Reputation: 315
Whilst doing refactoring I've somehow screwed up my code so the std::map I'm using stopped working properly.
I'm reassembling fragmented IPv4 packet.
Partially parsed Packet
comes and if it's fragment of packet it becomes Fragment
which has function for reassembling.
...
if(packet.isIPv4() && packet.isFragment()){
auto keyForMap = packet.key();
auto it = fragments.find(keyForMap);
auto fragmentNotFound = fragments.end();
std::cout << "-----------------------" << std::endl;
std::cout << "Fragments len: " << fragments.size() << std::endl;
keyForMap.print();
if(it == fragmentNotFound){
std::cout << "Not Found" << std::endl;
fragments[keyForMap] = Fragment(packet);
} else {
std::cout << "Found" << std::endl;
fragments[keyForMap].add(packet);
/* reassembling function call and some processing */
}
}
}
...
Data types used:
IPv4
is std::array<uchar_t, 4>
fragments
is fragments_t &
fragments_t
is std::map<FragmentCommon, Fragment>
struct FragmentCommon{
FragmentCommon(IPv4 ipsrc,
IPv4 ipdst,
uchar_t protocol,
uint16_t identification) : ip_src(ipsrc),
ip_dst(ipdst),
protocol(protocol),
identification(identification){};
void print(){
printf("key>%d.%d.%d.%d ", ip_src[0], ip_src[1], ip_src[2], ip_src[3]);
printf("%d.%d.%d.%d ", ip_dst[0], ip_dst[1], ip_dst[2], ip_dst[3]);
printf("%d %d\n", protocol, identification);
};
IPv4 ip_src;
IPv4 ip_dst;
uchar_t protocol;
uint16_t identification;
};
static bool operator<(const struct FragmentCommon &lhs, const struct FragmentCommon &rhs){
return lhs.ip_dst < rhs.ip_dst &&
lhs.ip_src < rhs.ip_src &&
lhs.protocol < rhs.protocol &&
lhs.identification < rhs.identification;
}
This is output my code gives me:
-----------------------
Fragments len: 0 // Correct (this is first fragment so nothing is in map)
key>192.168.1.3 192.168.1.4 6 1
Not Found // So it's added into map
-----------------------
Fragments len: 1 // Correct (1st fragment is in map)
key>192.168.1.5 192.168.1.6 6 1
Found // Not correct...keys are different
-----------------------
Fragments len: 1
key>192.168.1.5 192.168.1.6 6 1
Found
-----------------------
Fragments len: 1
key>192.168.1.5 192.168.1.6 6 1
Found
-----------------------
Upvotes: 0
Views: 104
Reputation: 35440
Given what you've posted and stated in the question, since IPv4
is a std::array<uchar_t,4>
(I'm assuming that uchar_t
is an alias for unsigned char
), you can define operator <
for FragmentCommon
using std::tie.
Using std::tie
is simpler and less-error prone for defining a strict-weak ordering (required for std::map
keys) when dealing with multiple values to test for in a "cascading" fashion.
#include <tuple>
//...
static bool operator < (const struct FragmentCommon &lhs, const struct FragmentCommon &rhs)
{
return std::tie(lhs.ip_dst, lhs.ip_src, lhs.protocol, lhs.identification) <
std::tie(rhs.ip_dst, rhs.ip_src, rhs.protocol, rhs.identification);
}
Since std::array has operator < defined, using std::tie
works correctly when using all 4 arguments in each std::tie
.
Upvotes: 2