winix/winixd/core/ipbancontainer.cpp

254 lines
5.4 KiB
C++

/*
* This file is a part of Winix
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2012-2014, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <algorithm>
#include "ipbancontainer.h"
#include "log.h"
#include "date/date.h"
namespace Winix
{
IPBanContainer::IPBanContainer()
{
is_ipban_tab_sorted = true; // an empty list is sorted
soft_max_size = 100;
max_size = 110;
}
void IPBanContainer::SetMaxSize(size_t soft_size, size_t size)
{
soft_max_size = soft_size;
max_size = size;
if( max_size < soft_max_size )
max_size = soft_max_size + 1;
ipban_tab.reserve(max_size);
sort_helper_tab.reserve(max_size);
}
// returning a reference to the added (or existed) record
IPBan & IPBanContainer::AddIP(int ip)
{
IPBan * old_ip_ban = FindIP(ip);
if( !old_ip_ban )
{
IPBan ip_ban;
ip_ban.ip = ip;
if( ipban_tab.size() >= max_size )
RemoveOldRecords();
ipban_tab.push_back(ip_ban);
is_ipban_tab_sorted = false;
return ipban_tab.back();
}
else
{
return *old_ip_ban;
}
}
void IPBanContainer::RemoveIP(int ip)
{
IPBan * ipban = FindIP(ip);
if( ipban )
{
size_t index = ipban - &ipban_tab[0];
ipban_tab.erase(ipban_tab.begin() + index);
}
}
bool IPBanContainer::IsSorted()
{
return is_ipban_tab_sorted;
}
void IPBanContainer::Clear()
{
ipban_tab.clear();
is_ipban_tab_sorted = true;
}
// we need to remove some old records for the size of the container
// to be less or equal to soft_max_size
void IPBanContainer::RemoveOldRecords()
{
size_t to_remove = 0;
if( ipban_tab.size() >= soft_max_size )
to_remove = ipban_tab.size() - soft_max_size;
if( to_remove > 0 )
{
sort_helper_tab.resize(ipban_tab.size());
for(size_t i=0 ; i<ipban_tab.size() ; ++i)
sort_helper_tab[i] = i;
std::sort(sort_helper_tab.begin(), sort_helper_tab.end(), SortByLastUsedHelper(this));
sort_helper_tab.resize(to_remove);
std::sort(sort_helper_tab.begin(), sort_helper_tab.end());
while( to_remove-- > 0 )
ipban_tab.erase(ipban_tab.begin() + sort_helper_tab[to_remove]);
}
}
// for debug purposes
void IPBanContainer::PrintTab()
{
log << log4 << "ipban_tab (size: " << ipban_tab.size() << ")" << logend;
for(size_t i=0 ; i<ipban_tab.size() ; ++i)
{
log << log4 << i << ": ip: " << ipban_tab[i].ip << ", flags: " << ipban_tab[i].flags << ", last_used: ";
pt::Date date(ipban_tab[i].last_used);
log << date << ", expires: ";
date = ipban_tab[i].expires;
log << date << logend;
}
}
// for debug purposes
void IPBanContainer::PrintTab2()
{
log << log4 << "sort_helper_tab (size: " << sort_helper_tab.size() << ")" << logend;
for(size_t i=0 ; i<sort_helper_tab.size() ; ++i)
{
IPBan & ipban = ipban_tab[sort_helper_tab[i]];
log << log4 << i << ": ip: " << ipban.ip << ", flags: " << ipban.flags << ", last_used: ";
pt::Date date(ipban.last_used);
log << date << ", expires: ";
date = ipban.expires;
log << date << logend;
}
}
bool IPBanContainer::SortByLastUsedHelper::operator()(size_t index1, size_t index2)
{
if( index1 < container->ipban_tab.size() &&
index2 < container->ipban_tab.size() )
{
IPBan & ip1 = container->ipban_tab[index1];
IPBan & ip2 = container->ipban_tab[index2];
// prefer to select records which do not have WINIX_IPBAN_FLAG_ACTIVE
if( ip1.HasFlag(WINIX_IPBAN_FLAG_ACTIVE) !=
ip2.HasFlag(WINIX_IPBAN_FLAG_ACTIVE) )
{
return ip2.HasFlag(WINIX_IPBAN_FLAG_ACTIVE);
}
return ip1.last_used < ip2.last_used;
}
return false;
}
IPBan * IPBanContainer::FindIP(int ip)
{
// !! IMPROVE ME add binary search if is_ipban_tab_sorted is true
for(size_t i=0 ; i<ipban_tab.size() ; ++i)
{
if( ipban_tab[i].ip == ip )
{
return &ipban_tab[i];
}
}
return 0;
}
IPBan & IPBanContainer::GetIPBan(size_t index)
{
return ipban_tab[index];
}
void IPBanContainer::Sort()
{
std::sort(ipban_tab.begin(), ipban_tab.end(), SortIPBansFunction);
is_ipban_tab_sorted = true;
}
size_t IPBanContainer::Size()
{
return ipban_tab.size();
}
bool IPBanContainer::SortIPBansFunction(const IPBan & ip1, const IPBan & ip2)
{
return ip1.ip < ip2.ip;
}
} // namespace Winix