#include "host_port_app_cache.h"
#include <map>
+#include <cstring>
#include "log/messages.h"
#include "main/thread.h"
padding = 0;
}
- bool operator<(HostPortKey right) const
+ bool operator<(const HostPortKey& right) const
{
- if ( ip.less_than(right.ip) )
- return true;
- else if ( right.ip.less_than(ip) )
- return false;
- else
- {
- if ( port < right.port)
- return true;
- else if ( right.port < port )
- return false;
- else if ( proto < right.proto)
- return true;
- else
- return false;
- }
+ return memcmp((const uint8_t*) this, (const uint8_t*) &right, sizeof(*this)) < 0;
}
SfIp ip;
padding[0] = padding[1] = padding[2] = 0;
}
- bool operator<(AppIdServiceStateKey right) const
+ bool operator<(const AppIdServiceStateKey& right) const
{
- if ( ip.less_than(right.ip) )
- return true;
- else if ( right.ip.less_than(ip) )
- return false;
- else
- {
- if ( port < right.port )
- return true;
- else if ( right.port < port )
- return false;
- else if ( proto < right.proto )
- return true;
- else if ( right.proto < proto )
- return false;
- else if ( level < right.level )
- return true;
- else
- return false;
- }
+ return memcmp((const uint8_t*) this, (const uint8_t*) &right, sizeof(*this)) < 0;
}
private:
{
Val_t* ss = nullptr;
- Map_t::iterator it = m.find(k);
- if ( it == m.end() )
- {
- // Prune the map to make room for the new sds if memcap is hit
- if ( mem_used + sz > memcap )
- remove( q.front() );
-
- ss = new Val_t;
+ // Try to emplace k first, with a nullptr.
+ std::pair<Map_t::iterator, bool> sit = m.emplace( std::make_pair(k, ss) );
+ Map_t::iterator it = sit.first;
- std::pair<Map_t::iterator, bool> sit = m.emplace(std::make_pair(k,ss));
- q.emplace_back(sit.first);
+ if ( sit.second )
+ {
+ // emplace succeeded
+ ss = it->second = new Val_t;
+ q.emplace_back(it);
mem_used += sz;
ss->qptr = --q.end(); // remember our place in the queue
+
+ if ( mem_used > memcap )
+ remove( q.front() );
}
- else {
+ else
+ {
ss = it->second;
if ( do_touch )
- touch(ss->qptr);
+ touch( ss->qptr );
}
-
+
return ss;
}
CHECK_TRUE(sds.get_state() == SERVICE_ID_STATE::VALID);
}
+TEST(service_state_tests, appid_service_state_key_comparison_test)
+{
+ SfIp ip4, ip6;
+ ip4.set("1.2.3.4");
+ ip6.set("1111.2222.3333.4444.5555.6666.7777.8888");
+ IpProtocol proto = IpProtocol::TCP;
+ uint16_t port=3000;
+
+ Key_t A(&ip4, proto, port, 0);
+ Key_t B(&ip6, proto, port, 0);
+
+ // We must never be in a situation where !( A<B ) and !( B<A ),
+ // because then map will consider A=B.
+ CHECK_TRUE(A<B || B<A);
+}
+
TEST(service_state_tests, service_cache)
{
size_t num_entries = 10, max_entries = 3;
IpProtocol proto = IpProtocol::TCP;
uint16_t port = 3000;
- SfIp ip;
- ip.set("10.10.0.1");
+ SfIp ip4, ip6;
+ ip4.set("1.2.3.4");
+ ip6.set("1111.2222.3333.4444.5555.6666.7777.8888");
Val_t* ss = nullptr;
std::vector<Val_t*> ssvec;
-
- // Insert past the memcap, and check the memcap is not exceeded:
+
+
+ // Insert (ipv4 and ipv6) past the memcap, and check the memcap is not exceeded.
for( size_t i = 1; i <= num_entries; i++, port++ )
{
- ss = ServiceCache.add( Key_t(&ip, proto, port, 0) );
+ const SfIp* ip = ( i%2 == 1 ? &ip4 : &ip6 );
+ ss = ServiceCache.add( Key_t(ip, proto, port, 0) );
CHECK_TRUE(ServiceCache.size() == ( i <= max_entries ? i : max_entries));
ssvec.push_back(ss);
}
- // The cache should now be port 8, 9, 10
+ // The cache should now be ip6:3007, ip4:3008, ip6:3009.
+ // Check that the order in the cache is correct.
Queue_t::iterator it = ServiceCache.newest();
std::vector<Val_t*>::iterator vit = --ssvec.end();
for( size_t i=0; i<max_entries; i++, --it, --vit )
Map_t::iterator mit = *it;
CHECK_TRUE( mit->second == *vit );
}
-
- // Now get an entry in the cache and check that it got touched:
- port -= 1;
- ss = ServiceCache.get( Key_t(&ip, proto, port, 0) );
+
+ // Now get e.g. the oldest from the cache and check that it got touched:
+ it = ServiceCache.oldest();
+ ss = ServiceCache.get( (*it)->first, true );
CHECK_TRUE( ss != nullptr );
CHECK_TRUE( ss->qptr == ServiceCache.newest() );
}
return false;
}
+// FIXIT-L: when comparing ip4 vs ip6 we have !(ip4 < ip6) and !(ip6 < ip4).
+// This may be OK in some cases, but will not work e.g. on a binary tree
+// (stl::map) with SfIp as keys, whose implementation relies only on "<".
+// This affects SfIp::less_than() and SfIp::greater_than().
inline bool SfIp::_is_lesser(const SfIp& rhs) const
{
if (is_ip4())
SO_PUBLIC const char* snort_inet_ntop(int family, const void* ip_raw, char* buf, int bufsize);
} // namespace snort
#endif
-