|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include "RateLimit.h"
|
|
Packit |
8f70b4 |
#include "ResMgr.h"
|
|
Packit |
8f70b4 |
#include "SMTask.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xmap_p<RateLimit> *RateLimit::total;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void RateLimit::AddXfer(int add)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xfer_number+=add;
|
|
Packit |
8f70b4 |
assert(xfer_number>=0);
|
|
Packit |
8f70b4 |
if(parent)
|
|
Packit |
8f70b4 |
parent->AddXfer(add);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void RateLimit::init(level_e lvl,const char *c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
level=lvl;
|
|
Packit |
8f70b4 |
xfer_number=(level==PER_CONN?1:0);
|
|
Packit |
8f70b4 |
parent=0;
|
|
Packit |
8f70b4 |
Reconfig(0,c);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(level==TOTAL) // has no parent
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
level_e parent_level=level_e(level+1);
|
|
Packit |
8f70b4 |
if(parent_level==TOTAL)
|
|
Packit |
8f70b4 |
c=""; // no closure on top level
|
|
Packit |
8f70b4 |
xstring parent_key(c);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!total)
|
|
Packit |
8f70b4 |
total=new xmap_p<RateLimit>();
|
|
Packit |
8f70b4 |
if(total->exists(parent_key)) {
|
|
Packit |
8f70b4 |
parent=total->lookup(parent_key);
|
|
Packit |
8f70b4 |
if(parent->xfer_number==0)
|
|
Packit |
8f70b4 |
parent->Reconfig(0,c); // it was not used for a white, refresh config
|
|
Packit |
8f70b4 |
} else {
|
|
Packit |
8f70b4 |
parent=new RateLimit(parent_level,c);
|
|
Packit |
8f70b4 |
total->add(parent_key,parent);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
parent->AddXfer(xfer_number);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
RateLimit::~RateLimit()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(parent && xfer_number)
|
|
Packit |
8f70b4 |
parent->AddXfer(-xfer_number);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#define LARGE 0x10000000
|
|
Packit |
8f70b4 |
#define DEFAULT_MAX_COEFF 2
|
|
Packit |
8f70b4 |
void RateLimit::BytesPool::AdjustTime()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
double dif=TimeDiff(SMTask::now,t);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(dif>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
// prevent overflow
|
|
Packit |
8f70b4 |
if((LARGE-pool)/dif < rate)
|
|
Packit |
8f70b4 |
pool = pool_max;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
pool += int(dif*rate+0.5);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(pool>pool_max)
|
|
Packit |
8f70b4 |
pool=pool_max;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
t=SMTask::now;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int RateLimit::BytesAllowed(dir_t dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int parent_allowed = parent?parent->BytesAllowed(dir):LARGE;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(pool[dir].rate==0) // unlimited
|
|
Packit |
8f70b4 |
return parent_allowed;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pool[dir].AdjustTime();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int allowed = pool[dir].pool/xfer_number;
|
|
Packit |
8f70b4 |
if(allowed>parent_allowed)
|
|
Packit |
8f70b4 |
allowed=parent_allowed;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
return allowed;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool RateLimit::Relaxed(dir_t dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
bool parent_relaxed = parent?parent->Relaxed(dir):true;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(pool[dir].rate==0) // unlimited
|
|
Packit |
8f70b4 |
return parent_relaxed;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
pool[dir].AdjustTime();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(pool[dir].rate>0 && pool[dir].pool < pool[dir].pool_max/2)
|
|
Packit |
8f70b4 |
return false;
|
|
Packit |
8f70b4 |
return parent_relaxed;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void RateLimit::BytesPool::Used(int bytes)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(pool
|
|
Packit |
8f70b4 |
pool=0;
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
pool-=bytes;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void RateLimit::BytesUsed(int bytes,dir_t dir)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(parent)
|
|
Packit |
8f70b4 |
parent->BytesUsed(bytes,dir);
|
|
Packit |
8f70b4 |
pool[dir].Used(bytes);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void RateLimit::Reset()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pool[GET].Reset();
|
|
Packit |
8f70b4 |
pool[PUT].Reset();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void RateLimit::BytesPool::Reset()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
pool=rate;
|
|
Packit |
8f70b4 |
t=SMTask::now;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void RateLimit::Reconfig(const char *name,const char *c)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(name && strncmp(name,"net:limit-",10))
|
|
Packit |
8f70b4 |
return; // not relevant
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
bool config_total=(!name || !strncmp(name,"net:limit-total-",16));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *setting_rate="net:limit-rate";
|
|
Packit |
8f70b4 |
const char *setting_max="net:limit-max";
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(level>PER_CONN)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!config_total)
|
|
Packit |
8f70b4 |
return; // not relevant
|
|
Packit |
8f70b4 |
if(level==TOTAL)
|
|
Packit |
8f70b4 |
c=0; // aggregates everything
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
setting_rate="net:limit-total-rate";
|
|
Packit |
8f70b4 |
setting_max="net:limit-total-max";
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ResMgr::Query(setting_rate,c).ToNumberPair(pool[GET].rate,pool[PUT].rate);
|
|
Packit |
8f70b4 |
ResMgr::Query(setting_max,c).ToNumberPair(pool[GET].pool_max,pool[PUT].pool_max);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(pool[GET].pool_max==0)
|
|
Packit |
8f70b4 |
pool[GET].pool_max=pool[GET].rate*DEFAULT_MAX_COEFF;
|
|
Packit |
8f70b4 |
if(pool[PUT].pool_max==0)
|
|
Packit |
8f70b4 |
pool[PUT].pool_max=pool[PUT].rate*DEFAULT_MAX_COEFF;
|
|
Packit |
8f70b4 |
Reset();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(config_total && parent)
|
|
Packit |
8f70b4 |
parent->Reconfig(name,c);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int RateLimit::LimitBufferSize(int size,dir_t d) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(pool[d].rate!=0 && size>pool[d].pool_max)
|
|
Packit |
8f70b4 |
size=pool[d].pool_max;
|
|
Packit |
8f70b4 |
return size;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
void RateLimit::SetBufferSize(IOBuffer *buf,int size) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
dir_t d = (buf->GetDirection()==buf->GET ? GET : PUT);
|
|
Packit |
8f70b4 |
buf->SetMaxBuffered(LimitBufferSize(size,d));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void RateLimit::ClassCleanup()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!total)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
for(RateLimit *t=total->each_begin(); t; t=total->each_next())
|
|
Packit |
8f70b4 |
t->parent=0;
|
|
Packit |
8f70b4 |
delete total; total=0;
|
|
Packit |
8f70b4 |
}
|