X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/4271ab433cd55bbd2612292bcf39e4dc3d7274f1..0907aa4037b12b6b88ee24495d4577a064d4f8db:/stargazer/user_impl.cpp diff --git a/stargazer/user_impl.cpp b/stargazer/user_impl.cpp deleted file mode 100644 index 2b7cc3a9..00000000 --- a/stargazer/user_impl.cpp +++ /dev/null @@ -1,1543 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Date: 27.10.2002 - */ - -/* - * Author : Boris Mikhailenko - */ - -/* - $Revision: 1.101 $ - $Date: 2010/11/03 10:50:03 $ - $Author: faust $ - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include "user_impl.h" -#include "settings_impl.h" -#include "stg_timer.h" - -#include "stg/users.h" -#include "stg/common.h" -#include "stg/scriptexecuter.h" -#include "stg/tariff.h" -#include "stg/tariffs.h" -#include "stg/services.h" -#include "stg/service_conf.h" -#include "stg/admin.h" - -#include -#include - -#include -#include -#include - -#include -#include // access - -using STG::UserImpl; - -namespace -{ - -std::string dirsToString(const bool * dirs) -{ -std::string res; -for (size_t i = 0; i < DIR_NUM; i++) - res += dirs[i] ? '1' : '0'; -return res; -} - -void dirsFromBits(bool * dirs, uint32_t bits) -{ -for (size_t i = 0; i < DIR_NUM; i++) - dirs[i] = bits & (1 << i); -} - -} - -UserImpl::UserImpl(const Settings * s, - const Store * st, - const Tariffs * t, - const Admin * a, - const Users * u, - const Services & svcs) - : users(u), - properties(*s), - WriteServLog(Logger::get()), - lastScanMessages(0), - id(0), - __connected(0), - connected(__connected), - __currIP(0), - currIP(__currIP), - lastIPForDisconnect(0), - pingTime(0), - sysAdmin(a), - store(st), - tariffs(t), - tariff(NULL), - m_services(svcs), - settings(s), - authorizedModificationTime(0), - deleted(false), - lastWriteStat(0), - lastWriteDetailedStat(0), - cash(properties.cash), - up(properties.up), - down(properties.down), - lastCashAdd(properties.lastCashAdd), - passiveTime(properties.passiveTime), - lastCashAddTime(properties.lastCashAddTime), - freeMb(properties.freeMb), - lastActivityTime(properties.lastActivityTime), - password(properties.password), - passive(properties.passive), - disabled(properties.disabled), - disabledDetailStat(properties.disabledDetailStat), - alwaysOnline(properties.alwaysOnline), - tariffName(properties.tariffName), - nextTariff(properties.nextTariff), - address(properties.address), - note(properties.note), - group(properties.group), - email(properties.email), - phone(properties.phone), - realName(properties.realName), - credit(properties.credit), - creditExpire(properties.creditExpire), - ips(properties.ips), - userdata0(properties.userdata0), - userdata1(properties.userdata1), - userdata2(properties.userdata2), - userdata3(properties.userdata3), - userdata4(properties.userdata4), - userdata5(properties.userdata5), - userdata6(properties.userdata6), - userdata7(properties.userdata7), - userdata8(properties.userdata8), - userdata9(properties.userdata9), - sessionUploadModTime(stgTime), - sessionDownloadModTime(stgTime), - passiveNotifier(this), - disabledNotifier(this), - tariffNotifier(this), - cashNotifier(this), - ipNotifier(this) -{ -Init(); -} -//----------------------------------------------------------------------------- -void UserImpl::Init() -{ -password = "*_EMPTY_PASSWORD_*"; -tariffName = NO_TARIFF_NAME; -tariff = tariffs->FindByName(tariffName); -ips = UserIPs::parse("*"); -lastWriteStat = stgTime + random() % settings->GetStatWritePeriod(); -lastWriteDetailedStat = stgTime; - -properties.tariffName.AddBeforeNotifier(&tariffNotifier); -properties.passive.AddBeforeNotifier(&passiveNotifier); -properties.disabled.AddAfterNotifier(&disabledNotifier); -properties.cash.AddBeforeNotifier(&cashNotifier); -ips.AddAfterNotifier(&ipNotifier); - -pthread_mutexattr_t attr; -pthread_mutexattr_init(&attr); -pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); -pthread_mutex_init(&mutex, &attr); -} -//----------------------------------------------------------------------------- -UserImpl::UserImpl(const UserImpl & u) - : users(u.users), - properties(*u.settings), - WriteServLog(Logger::get()), - lastScanMessages(0), - login(u.login), - id(u.id), - __connected(0), - connected(__connected), - __currIP(u.__currIP), - currIP(__currIP), - lastIPForDisconnect(0), - pingTime(u.pingTime), - sysAdmin(u.sysAdmin), - store(u.store), - tariffs(u.tariffs), - tariff(u.tariff), - m_services(u.m_services), - traffStat(u.traffStat), - traffStatSaved(u.traffStatSaved), - settings(u.settings), - authorizedModificationTime(u.authorizedModificationTime), - messages(u.messages), - deleted(u.deleted), - lastWriteStat(u.lastWriteStat), - lastWriteDetailedStat(u.lastWriteDetailedStat), - cash(properties.cash), - up(properties.up), - down(properties.down), - lastCashAdd(properties.lastCashAdd), - passiveTime(properties.passiveTime), - lastCashAddTime(properties.lastCashAddTime), - freeMb(properties.freeMb), - lastActivityTime(properties.lastActivityTime), - password(properties.password), - passive(properties.passive), - disabled(properties.disabled), - disabledDetailStat(properties.disabledDetailStat), - alwaysOnline(properties.alwaysOnline), - tariffName(properties.tariffName), - nextTariff(properties.nextTariff), - address(properties.address), - note(properties.note), - group(properties.group), - email(properties.email), - phone(properties.phone), - realName(properties.realName), - credit(properties.credit), - creditExpire(properties.creditExpire), - ips(properties.ips), - userdata0(properties.userdata0), - userdata1(properties.userdata1), - userdata2(properties.userdata2), - userdata3(properties.userdata3), - userdata4(properties.userdata4), - userdata5(properties.userdata5), - userdata6(properties.userdata6), - userdata7(properties.userdata7), - userdata8(properties.userdata8), - userdata9(properties.userdata9), - sessionUpload(), - sessionDownload(), - sessionUploadModTime(stgTime), - sessionDownloadModTime(stgTime), - passiveNotifier(this), - disabledNotifier(this), - tariffNotifier(this), - cashNotifier(this), - ipNotifier(this) -{ -if (&u == this) - return; - -properties.tariffName.AddBeforeNotifier(&tariffNotifier); -properties.passive.AddBeforeNotifier(&passiveNotifier); -properties.disabled.AddAfterNotifier(&disabledNotifier); -properties.cash.AddBeforeNotifier(&cashNotifier); -ips.AddAfterNotifier(&ipNotifier); - -properties.SetProperties(u.properties); - -pthread_mutexattr_t attr; -pthread_mutexattr_init(&attr); -pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); -pthread_mutex_init(&mutex, &attr); -} -//----------------------------------------------------------------------------- -UserImpl::~UserImpl() -{ -properties.tariffName.DelBeforeNotifier(&tariffNotifier); -properties.passive.DelBeforeNotifier(&passiveNotifier); -properties.disabled.DelAfterNotifier(&disabledNotifier); -properties.cash.DelBeforeNotifier(&cashNotifier); -pthread_mutex_destroy(&mutex); -} -//----------------------------------------------------------------------------- -void UserImpl::SetLogin(const std::string & l) -{ -STG_LOCKER lock(&mutex); -static int idGen = 0; -assert(login.empty() && "Login is already set"); -login = l; -id = idGen++; -} -//----------------------------------------------------------------------------- -int UserImpl::ReadConf() -{ -STG_LOCKER lock(&mutex); -UserConf conf; - -if (store->RestoreUserConf(&conf, login)) - { - WriteServLog("Cannot read conf for user %s.", login.c_str()); - WriteServLog("%s", store->GetStrError().c_str()); - printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str()); - printfd(__FILE__, "%s\n", store->GetStrError().c_str()); - return -1; - } - -properties.SetConf(conf); - -tariff = tariffs->FindByName(tariffName); -if (tariff == NULL) - { - WriteServLog("Cannot read user %s. Tariff %s not exist.", - login.c_str(), properties.tariffName.Get().c_str()); - return -1; - } - -std::vector hdrsList; - -if (store->GetMessageHdrs(&hdrsList, login)) - { - printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str()); - WriteServLog("Cannot read user %s. Error reading message headers: %s.", - login.c_str(), - store->GetStrError().c_str()); - return -1; - } - -std::vector::const_iterator it; -for (it = hdrsList.begin(); it != hdrsList.end(); ++it) - { - Message msg; - if (store->GetMessage(it->id, &msg, login) == 0) - { - messages.push_back(msg); - } - } - -return 0; -} -//----------------------------------------------------------------------------- -int UserImpl::ReadStat() -{ -STG_LOCKER lock(&mutex); -UserStat stat; - -if (store->RestoreUserStat(&stat, login)) - { - WriteServLog("Cannot read stat for user %s.", login.c_str()); - WriteServLog("%s", store->GetStrError().c_str()); - printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str()); - printfd(__FILE__, "%s\n", store->GetStrError().c_str()); - return -1; - } - -properties.SetStat(stat); - -return 0; -} -//----------------------------------------------------------------------------- -int UserImpl::WriteConf() -{ -STG_LOCKER lock(&mutex); -UserConf conf(properties.GetConf()); - -printfd(__FILE__, "UserImpl::WriteConf()\n"); - -if (store->SaveUserConf(conf, login)) - { - WriteServLog("Cannot write conf for user %s.", login.c_str()); - WriteServLog("%s", store->GetStrError().c_str()); - printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str()); - printfd(__FILE__, "%s\n", store->GetStrError().c_str()); - return -1; - } - -return 0; -} -//----------------------------------------------------------------------------- -int UserImpl::WriteStat() -{ -STG_LOCKER lock(&mutex); -UserStat stat(properties.GetStat()); - -if (store->SaveUserStat(stat, login)) - { - WriteServLog("Cannot write stat for user %s.", login.c_str()); - WriteServLog("%s", store->GetStrError().c_str()); - printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str()); - printfd(__FILE__, "%s\n", store->GetStrError().c_str()); - return -1; - } - -lastWriteStat = stgTime; - -return 0; -} -//----------------------------------------------------------------------------- -int UserImpl::WriteMonthStat() -{ -STG_LOCKER lock(&mutex); -time_t tt = stgTime - 3600; -struct tm t1; -localtime_r(&tt, &t1); - -UserStat stat(properties.GetStat()); -if (store->SaveMonthStat(stat, t1.tm_mon, t1.tm_year, login)) - { - WriteServLog("Cannot write month stat for user %s.", login.c_str()); - WriteServLog("%s", store->GetStrError().c_str()); - printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str()); - printfd(__FILE__, "%s\n", store->GetStrError().c_str()); - return -1; - } - -return 0; -} -//----------------------------------------------------------------------------- -int UserImpl::Authorize(uint32_t ip, uint32_t dirs, const Auth * auth) -{ -STG_LOCKER lock(&mutex); -/* - * Authorize user. It only means that user will be authorized. Nothing more. - * User can be connected or disconnected while authorized. - * Example: user is authorized but disconnected due to 0 money or blocking - */ - -/* - * TODO: in fact "authorization" means allowing access to a service. What we - * call "authorization" here, int STG, is "authentication". So this should be - * fixed in future. - */ - -/* - * Prevent double authorization by identical authorizers - */ -if (authorizedBy.find(auth) != authorizedBy.end()) - return 0; - -if (!ip) - return -1; - -dirsFromBits(enabledDirs, dirs); - -if (!authorizedBy.empty()) - { - if (currIP != ip) - { - // We are already authorized, but with different IP address - errorStr = "User " + login + " already authorized with IP address " + inet_ntostring(ip); - return -1; - } - - User * u = NULL; - if (!users->FindByIPIdx(ip, &u)) - { - // Address presents in IP-index. - // If it's not our IP - report it. - if (u != this) - { - errorStr = "IP address " + inet_ntostring(ip) + " is already in use"; - return -1; - } - } - } -else - { - if (users->IsIPInIndex(ip)) - { - // Address is already present in IP-index. - errorStr = "IP address " + inet_ntostring(ip) + " is already in use"; - return -1; - } - - if (ips.ConstData().find(ip)) - { - currIP = ip; - lastIPForDisconnect = currIP; - } - else - { - printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().toString().c_str()); - errorStr = "IP address " + inet_ntostring(ip) + " does not belong to user " + login; - return -1; - } - } - -if (authorizedBy.empty()) - authorizedModificationTime = stgTime; -authorizedBy.insert(auth); - -ScanMessage(); - -return 0; -} -//----------------------------------------------------------------------------- -void UserImpl::Unauthorize(const Auth * auth, const std::string & reason) -{ -STG_LOCKER lock(&mutex); -/* - * Authorizer tries to unauthorize user, that was not authorized by it - */ -if (!authorizedBy.erase(auth)) - return; - -authorizedModificationTime = stgTime; - -if (authorizedBy.empty()) - { - lastDisconnectReason = reason; - lastIPForDisconnect = currIP; - currIP = 0; // DelUser in traffcounter - if (connected) - Disconnect(false, "not authorized"); - return; - } -} -//----------------------------------------------------------------------------- -bool UserImpl::IsAuthorizedBy(const Auth * auth) const -{ -STG_LOCKER lock(&mutex); -// Is this user authorized by specified authorizer? -return authorizedBy.find(auth) != authorizedBy.end(); -} -//----------------------------------------------------------------------------- -std::vector UserImpl::GetAuthorizers() const -{ - STG_LOCKER lock(&mutex); - std::vector list; - std::transform(authorizedBy.begin(), authorizedBy.end(), std::back_inserter(list), [](const auto auth){ return auth->GetVersion(); }); - return list; -} -//----------------------------------------------------------------------------- -void UserImpl::Connect(bool fakeConnect) -{ -/* - * Connect user to Internet. This function is differ from Authorize() !!! - */ - -STG_LOCKER lock(&mutex); - -if (!fakeConnect) - { - std::string scriptOnConnect = settings->GetScriptsDir() + "/OnConnect"; - - if (access(scriptOnConnect.c_str(), X_OK) == 0) - { - std::string dirs = dirsToString(enabledDirs); - - std::string scriptOnConnectParams; - strprintf(&scriptOnConnectParams, - "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"", - scriptOnConnect.c_str(), - login.c_str(), - inet_ntostring(currIP).c_str(), - cash.ConstData(), - id, - dirs.c_str()); - - std::vector::const_iterator it(settings->GetScriptParams().begin()); - while (it != settings->GetScriptParams().end()) - { - scriptOnConnectParams += " \"" + GetParamValue(it->c_str()) + "\""; - ++it; - } - - ScriptExec(scriptOnConnectParams.c_str()); - } - else - { - WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str()); - } - - connected = true; - } - -if (!settings->GetDisableSessionLog() && store->WriteUserConnect(login, currIP)) - { - WriteServLog("Cannot write connect for user %s.", login.c_str()); - WriteServLog("%s", store->GetStrError().c_str()); - } - -if (!fakeConnect) - lastIPForDisconnect = currIP; -} -//----------------------------------------------------------------------------- -void UserImpl::Disconnect(bool fakeDisconnect, const std::string & reason) -{ -/* - * Disconnect user from Internet. This function is differ from UnAuthorize() !!! - */ - -STG_LOCKER lock(&mutex); - -if (!lastIPForDisconnect) - { - printfd(__FILE__, "lastIPForDisconnect\n"); - return; - } - -if (!fakeDisconnect) - { - lastDisconnectReason = reason; - std::string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect"; - - if (access(scriptOnDisonnect.c_str(), X_OK) == 0) - { - std::string dirs = dirsToString(enabledDirs); - - std::string scriptOnDisonnectParams; - strprintf(&scriptOnDisonnectParams, - "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"", - scriptOnDisonnect.c_str(), - login.c_str(), - inet_ntostring(lastIPForDisconnect).c_str(), - cash.ConstData(), - id, - dirs.c_str()); - - std::vector::const_iterator it(settings->GetScriptParams().begin()); - while (it != settings->GetScriptParams().end()) - { - scriptOnDisonnectParams += " \"" + GetParamValue(it->c_str()) + "\""; - ++it; - } - - ScriptExec(scriptOnDisonnectParams.c_str()); - } - else - { - WriteServLog("Script OnDisconnect cannot be executed. File not found."); - } - - connected = false; - } - -std::string reasonMessage(reason); -if (!lastDisconnectReason.empty()) - reasonMessage += ": " + lastDisconnectReason; - -if (!settings->GetDisableSessionLog() && store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload, - cash, freeMb, reasonMessage)) - { - WriteServLog("Cannot write disconnect for user %s.", login.c_str()); - WriteServLog("%s", store->GetStrError().c_str()); - } - -if (!fakeDisconnect) - lastIPForDisconnect = 0; - -sessionUpload.reset(); -sessionDownload.reset(); -sessionUploadModTime = stgTime; -sessionDownloadModTime = stgTime; -} -//----------------------------------------------------------------------------- -void UserImpl::Run() -{ -STG_LOCKER lock(&mutex); - -if (stgTime > static_cast(lastWriteStat + settings->GetStatWritePeriod())) - { - printfd(__FILE__, "UserImpl::WriteStat user=%s\n", GetLogin().c_str()); - WriteStat(); - } -if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime) - { - WriteServLog("User: %s. Credit expired.", login.c_str()); - credit = 0; - creditExpire = 0; - WriteConf(); - } - -if (passive.ConstData() - && (stgTime % 30 == 0) - && (passiveTime.ModificationTime() != stgTime)) - { - passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime()); - printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData()); - } - -if (!authorizedBy.empty()) - { - if (connected) - properties.Stat().lastActivityTime = stgTime; - - if (!connected && IsInetable()) - Connect(); - - if (connected && !IsInetable()) - { - if (disabled) - Disconnect(false, "disabled"); - else if (passive) - Disconnect(false, "passive"); - else - Disconnect(false, "no cash"); - } - - if (stgTime - lastScanMessages > 10) - { - ScanMessage(); - lastScanMessages = stgTime; - } - } -else - { - if (connected) - Disconnect(false, "not authorized"); - } - -} -//----------------------------------------------------------------------------- -void UserImpl::UpdatePingTime(time_t t) -{ -STG_LOCKER lock(&mutex); -if (t) - pingTime = t; -else - pingTime = stgTime; -} -//----------------------------------------------------------------------------- -bool UserImpl::IsInetable() -{ -if (disabled || passive) - return false; - -if (settings->GetFreeMbAllowInet()) - { - if (freeMb >= 0) - return true; - } - -if (settings->GetShowFeeInCash() || tariff == NULL) - return (cash >= -credit); - -return (cash - tariff->GetFee() >= -credit); -} -//----------------------------------------------------------------------------- -std::string UserImpl::GetEnabledDirs() const -{ -return dirsToString(enabledDirs); -} -//----------------------------------------------------------------------------- -#ifdef TRAFF_STAT_WITH_PORTS -void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len) -#else -void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint32_t len) -#endif -{ -STG_LOCKER lock(&mutex); - -if (!connected || tariff == NULL) - return; - -double cost = 0; -DirTraff dt(up); - -int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]); -int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024; - -dt[dir] += len; - -int tt = tariff->GetTraffType(); -if (tt == Tariff::TRAFF_UP || - tt == Tariff::TRAFF_UP_DOWN || - // Check NEW traff data - (tt == Tariff::TRAFF_MAX && dt[dir] > down.ConstData()[dir])) - { - double dc = 0; - if (traff < threshold && - traff + len >= threshold) - { - // cash = partBeforeThreshold * priceBeforeThreshold + - // partAfterThreshold * priceAfterThreshold - int64_t before = threshold - traff; // Chunk part before threshold - int64_t after = len - before; // Chunk part after threshold - dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk - down.ConstData()[dir], - dir, - stgTime) * before + - tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk - down.ConstData()[dir], - dir, - stgTime) * after; - } - else - { - dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], - down.ConstData()[dir], - dir, - stgTime) * len; - } - - if (freeMb.ConstData() <= 0) // FreeMb is exhausted - cost = dc; - else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted - cost = dc - freeMb.ConstData(); - - // Direct access to internal data structures via friend-specifier - properties.Stat().freeMb -= dc; - properties.Stat().cash -= cost; - cash.ModifyTime(); - freeMb.ModifyTime(); - } - -up = dt; -sessionUpload[dir] += len; -sessionUploadModTime = stgTime; - -//Add detailed stat - -if (!settings->GetWriteFreeMbTraffCost() && - freeMb.ConstData() >= 0) - cost = 0; - -#ifdef TRAFF_STAT_WITH_PORTS -IPDirPair idp(ip, dir, port); -#else -IPDirPair idp(ip, dir); -#endif - -std::map::iterator lb; -lb = traffStat.lower_bound(idp); -if (lb == traffStat.end() || lb->first != idp) - { - traffStat.insert(lb, - std::make_pair(idp, - StatNode(len, 0, cost))); - } -else - { - lb->second.cash += cost; - lb->second.up += len; - } -} -//----------------------------------------------------------------------------- -#ifdef TRAFF_STAT_WITH_PORTS -void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len) -#else -void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint32_t len) -#endif -{ -STG_LOCKER lock(&mutex); - -if (!connected || tariff == NULL) - return; - -double cost = 0; -DirTraff dt(down); - -int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]); -int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024; - -dt[dir] += len; - -int tt = tariff->GetTraffType(); -if (tt == Tariff::TRAFF_DOWN || - tt == Tariff::TRAFF_UP_DOWN || - // Check NEW traff data - (tt == Tariff::TRAFF_MAX && up.ConstData()[dir] <= dt[dir])) - { - double dc = 0; - if (traff < threshold && - traff + len >= threshold) - { - // cash = partBeforeThreshold * priceBeforeThreshold + - // partAfterThreshold * priceAfterThreshold - int64_t before = threshold - traff; // Chunk part before threshold - int64_t after = len - before; // Chunk part after threshold - dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], - down.ConstData()[dir], // Traff before chunk - dir, - stgTime) * before + - tariff->GetPriceWithTraffType(up.ConstData()[dir], - dt[dir], // Traff after chunk - dir, - stgTime) * after; - } - else - { - dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], - down.ConstData()[dir], - dir, - stgTime) * len; - } - - if (freeMb.ConstData() <= 0) // FreeMb is exhausted - cost = dc; - else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted - cost = dc - freeMb.ConstData(); - - properties.Stat().freeMb -= dc; - properties.Stat().cash -= cost; - cash.ModifyTime(); - freeMb.ModifyTime(); - } - -down = dt; -sessionDownload[dir] += len; -sessionDownloadModTime = stgTime; - -//Add detailed stat - -if (!settings->GetWriteFreeMbTraffCost() && - freeMb.ConstData() >= 0) - cost = 0; - -#ifdef TRAFF_STAT_WITH_PORTS -IPDirPair idp(ip, dir, port); -#else -IPDirPair idp(ip, dir); -#endif - -std::map::iterator lb; -lb = traffStat.lower_bound(idp); -if (lb == traffStat.end() || lb->first != idp) - { - traffStat.insert(lb, - std::make_pair(idp, - StatNode(0, len, cost))); - } -else - { - lb->second.cash += cost; - lb->second.down += len; - } -} -//----------------------------------------------------------------------------- -void UserImpl::AddCurrIPBeforeNotifier(CURR_IP_NOTIFIER * notifier) -{ -STG_LOCKER lock(&mutex); -currIP.AddBeforeNotifier(notifier); -} -//----------------------------------------------------------------------------- -void UserImpl::DelCurrIPBeforeNotifier(const CURR_IP_NOTIFIER * notifier) -{ -STG_LOCKER lock(&mutex); -currIP.DelBeforeNotifier(notifier); -} -//----------------------------------------------------------------------------- -void UserImpl::AddCurrIPAfterNotifier(CURR_IP_NOTIFIER * notifier) -{ -STG_LOCKER lock(&mutex); -currIP.AddAfterNotifier(notifier); -} -//----------------------------------------------------------------------------- -void UserImpl::DelCurrIPAfterNotifier(const CURR_IP_NOTIFIER * notifier) -{ -STG_LOCKER lock(&mutex); -currIP.DelAfterNotifier(notifier); -} -//----------------------------------------------------------------------------- -void UserImpl::AddConnectedBeforeNotifier(CONNECTED_NOTIFIER * notifier) -{ -STG_LOCKER lock(&mutex); -connected.AddBeforeNotifier(notifier); -} -//----------------------------------------------------------------------------- -void UserImpl::DelConnectedBeforeNotifier(const CONNECTED_NOTIFIER * notifier) -{ -STG_LOCKER lock(&mutex); -connected.DelBeforeNotifier(notifier); -} -//----------------------------------------------------------------------------- -void UserImpl::AddConnectedAfterNotifier(CONNECTED_NOTIFIER * notifier) -{ -STG_LOCKER lock(&mutex); -connected.AddAfterNotifier(notifier); -} -//----------------------------------------------------------------------------- -void UserImpl::DelConnectedAfterNotifier(const CONNECTED_NOTIFIER * notifier) -{ -STG_LOCKER lock(&mutex); -connected.DelAfterNotifier(notifier); -} -//----------------------------------------------------------------------------- -void UserImpl::OnAdd() -{ -STG_LOCKER lock(&mutex); - -std::string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd"; - -if (access(scriptOnAdd.c_str(), X_OK) == 0) - { - std::string scriptOnAddParams = scriptOnAdd + " \"" + login + "\""; - - ScriptExec(scriptOnAddParams.c_str()); - } -else - { - WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str()); - } -} -//----------------------------------------------------------------------------- -void UserImpl::OnDelete() -{ -STG_LOCKER lock(&mutex); - -std::string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel"; - -if (access(scriptOnDel.c_str(), X_OK) == 0) - { - std::string scriptOnDelParams = scriptOnDel + " \"" + login + "\""; - - ScriptExec(scriptOnDelParams.c_str()); - } -else - { - WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str()); - } - -Run(); -} -//----------------------------------------------------------------------------- -int UserImpl::WriteDetailStat(bool hard) -{ -printfd(__FILE__, "UserImpl::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size()); - -if (!traffStatSaved.second.empty()) - { - if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login)) - { - printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write detail stat from queue\n"); - WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str()); - WriteServLog("%s", store->GetStrError().c_str()); - return -1; - } - traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end()); - } - -TraffStat ts; - - { - STG_LOCKER lock(&mutex); - ts.swap(traffStat); - } - -printfd(__FILE__, "UserImpl::WriteDetailedStat() - size = %d\n", ts.size()); - -if (ts.size() && !disabledDetailStat) - { - if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login)) - { - printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write current detail stat\n"); - WriteServLog("Cannot write detail stat for user %s.", login.c_str()); - WriteServLog("%s", store->GetStrError().c_str()); - if (!hard) - { - printfd(__FILE__, "UserImpl::WriteDetailStat() - pushing detail stat to queue\n"); - STG_LOCKER lock(&mutex); - traffStatSaved.second.swap(ts); - traffStatSaved.first = lastWriteDetailedStat; - } - return -1; - } - } -lastWriteDetailedStat = stgTime; -return 0; -} -//----------------------------------------------------------------------------- -double UserImpl::GetPassiveTimePart() const -{ -STG_LOCKER lock(&mutex); - -static int daysInMonth[12] = -{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; - -struct tm tms; -time_t t = stgTime; -localtime_r(&t, &tms); - -time_t secMonth = daysInMonth[(tms.tm_mon + 11) % 12] * 24 * 3600; // Previous month - -if (tms.tm_year % 4 == 0 && tms.tm_mon == 1) - { - // Leap year - secMonth += 24 * 3600; - } - -time_t dt = secMonth - passiveTime; - -if (dt < 0) - dt = 0; - -return static_cast(dt) / secMonth; -} -//----------------------------------------------------------------------------- -void UserImpl::SetPassiveTimeAsNewUser() -{ -STG_LOCKER lock(&mutex); - -time_t t = stgTime; -struct tm tm; -localtime_r(&t, &tm); -int daysCurrMon = DaysInCurrentMonth(); -double pt = tm.tm_mday - 1; -pt /= daysCurrMon; - -passiveTime = static_cast(pt * 24 * 3600 * daysCurrMon); -} -//----------------------------------------------------------------------------- -void UserImpl::MidnightResetSessionStat() -{ -STG_LOCKER lock(&mutex); - -if (connected) - { - Disconnect(true, "fake"); - Connect(true); - } -} -//----------------------------------------------------------------------------- -void UserImpl::ProcessNewMonth() -{ -STG_LOCKER lock(&mutex); -// Reset traff -if (connected) - Disconnect(true, "fake"); - -WriteMonthStat(); - -properties.Stat().monthUp.reset(); -properties.Stat().monthDown.reset(); - -if (connected) - Connect(true); - -// Set new tariff -if (nextTariff.ConstData() != "") - { - const Tariff * nt = tariffs->FindByName(nextTariff); - if (nt == NULL) - { - WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.", - login.c_str(), properties.tariffName.Get().c_str()); - } - else - { - std::string message = tariff->TariffChangeIsAllowed(*nt, stgTime); - if (message.empty()) - { - properties.tariffName.Set(nextTariff, *sysAdmin, login, *store); - } - else - { - WriteServLog("Tariff change is prohibited for user %s. %s", - login.c_str(), - message.c_str()); - } - } - ResetNextTariff(); - WriteConf(); - } -} -//----------------------------------------------------------------------------- -void UserImpl::ProcessDayFeeSpread() -{ -STG_LOCKER lock(&mutex); - -if (passive.ConstData() || tariff == NULL) - return; - -if (tariff->GetPeriod() != Tariff::MONTH) - return; - -double fee = tariff->GetFee() / DaysInCurrentMonth(); - -if (std::fabs(fee) < 1.0e-3) - return; - -double c = cash; -switch (settings->GetFeeChargeType()) - { - case 0: - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - break; - case 1: - if (c + credit >= 0) - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - break; - case 2: - if (c + credit >= fee) - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - break; - case 3: - if (c >= 0) - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - break; - } -ResetPassiveTime(); -} -//----------------------------------------------------------------------------- -void UserImpl::ProcessDayFee() -{ -STG_LOCKER lock(&mutex); - -if (tariff == NULL) - return; - -if (tariff->GetPeriod() != Tariff::MONTH) - return; - -double passiveTimePart = 1.0; -if (!settings->GetFullFee()) - { - passiveTimePart = GetPassiveTimePart(); - } -else - { - if (passive.ConstData()) - { - printfd(__FILE__, "Don't charge fee `cause we are passive\n"); - return; - } - } -double fee = tariff->GetFee() * passiveTimePart; - -ResetPassiveTime(); - -if (std::fabs(fee) < 1.0e-3) - { - SetPrepaidTraff(); - return; - } - -double c = cash; -printfd(__FILE__, "login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n", - login.c_str(), - cash.ConstData(), - credit.ConstData(), - tariff->GetFee(), - passiveTimePart, - fee); -switch (settings->GetFeeChargeType()) - { - case 0: - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - SetPrepaidTraff(); - break; - case 1: - if (c + credit >= 0) - { - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - SetPrepaidTraff(); - } - break; - case 2: - if (c + credit >= fee) - { - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - SetPrepaidTraff(); - } - break; - case 3: - if (c >= 0) - { - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - SetPrepaidTraff(); - } - break; - } -} -//----------------------------------------------------------------------------- -void UserImpl::ProcessDailyFee() -{ -STG_LOCKER lock(&mutex); - -if (passive.ConstData() || tariff == NULL) - return; - -if (tariff->GetPeriod() != Tariff::DAY) - return; - -double fee = tariff->GetFee(); - -if (fee == 0.0) - return; - -double c = cash; -switch (settings->GetFeeChargeType()) - { - case 0: - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - break; - case 1: - if (c + credit >= 0) - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - break; - case 2: - if (c + credit >= fee) - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - break; - } -ResetPassiveTime(); -} -//----------------------------------------------------------------------------- -void UserImpl::ProcessServices() -{ -struct tm tms; -time_t t = stgTime; -localtime_r(&t, &tms); - -double passiveTimePart = 1.0; -if (!settings->GetFullFee()) - { - passiveTimePart = GetPassiveTimePart(); - } -else - { - if (passive.ConstData()) - { - printfd(__FILE__, "Don't charge fee `cause we are passive\n"); - return; - } - } - -for (size_t i = 0; i < properties.Conf().services.size(); ++i) - { - ServiceConf conf; - if (m_services.Find(properties.Conf().services[i], &conf)) - continue; - if (conf.payDay == tms.tm_mday || - (conf.payDay == 0 && tms.tm_mday == DaysInCurrentMonth())) - { - double c = cash; - double fee = conf.cost * passiveTimePart; - printfd(__FILE__, "Service fee. login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n", - login.c_str(), - cash.ConstData(), - credit.ConstData(), - tariff->GetFee(), - passiveTimePart, - fee); - switch (settings->GetFeeChargeType()) - { - case 0: - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - SetPrepaidTraff(); - break; - case 1: - if (c + credit >= 0) - { - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - SetPrepaidTraff(); - } - break; - case 2: - if (c + credit >= fee) - { - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - SetPrepaidTraff(); - } - break; - case 3: - if (c >= 0) - { - properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge"); - SetPrepaidTraff(); - } - break; - } - } - } -} -//----------------------------------------------------------------------------- -void UserImpl::SetPrepaidTraff() -{ -if (tariff != NULL) - properties.freeMb.Set(tariff->GetFree(), *sysAdmin, login, *store, "Prepaid traffic"); -} -//----------------------------------------------------------------------------- -int UserImpl::AddMessage(Message * msg) -{ -STG_LOCKER lock(&mutex); - -if (SendMessage(*msg)) - { - if (store->AddMessage(msg, login)) - { - errorStr = store->GetStrError(); - WriteServLog("Error adding message: '%s'", errorStr.c_str()); - printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str()); - return -1; - } - messages.push_back(*msg); - } -else - { - if (msg->header.repeat > 0) - { - msg->header.repeat--; - #ifndef DEBUG - //TODO: gcc v. 4.x generate ICE on x86_64 - msg->header.lastSendTime = static_cast(time(NULL)); - #else - msg->header.lastSendTime = static_cast(stgTime); - #endif - if (store->AddMessage(msg, login)) - { - errorStr = store->GetStrError(); - WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str()); - printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str()); - return -1; - } - messages.push_back(*msg); - } - } -return 0; -} -//----------------------------------------------------------------------------- -int UserImpl::SendMessage(Message & msg) const -{ -// No lock `cause we are already locked from caller -int ret = -1; -std::set::iterator it(authorizedBy.begin()); -while (it != authorizedBy.end()) - { - if (!(*it++)->SendMessage(msg, currIP)) - ret = 0; - } -if (!ret) - { -#ifndef DEBUG - //TODO: gcc v. 4.x generate ICE on x86_64 - msg.header.lastSendTime = static_cast(time(NULL)); -#else - msg.header.lastSendTime = static_cast(stgTime); -#endif - msg.header.repeat--; - } -return ret; -} -//----------------------------------------------------------------------------- -void UserImpl::ScanMessage() -{ -// No lock `cause we are already locked from caller -// We need not check for the authorizedBy `cause it has already checked by caller - -auto it = messages.begin(); -while (it != messages.end()) - { - if (settings->GetMessageTimeout() > 0 && - difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout()) - { - // Timeout exceeded - if (store->DelMessage(it->header.id, login)) - { - WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str()); - printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str()); - } - messages.erase(it++); - continue; - } - if (it->GetNextSendTime() <= stgTime) - { - if (SendMessage(*it)) - { - // We need to check all messages in queue for timeout - ++it; - continue; - } - if (it->header.repeat < 0) - { - if (store->DelMessage(it->header.id, login)) - { - WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str()); - printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str()); - } - messages.erase(it++); - } - else - { - if (store->EditMessage(*it, login)) - { - WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str()); - printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str()); - } - ++it; - } - } - else - { - ++it; - } - } -} -//----------------------------------------------------------------------------- -std::string UserImpl::GetParamValue(const std::string & name) const -{ - std::string lowerName = ToLower(name); - if (lowerName == "id") - { - std::ostringstream stream; - stream << id; - return stream.str(); - } - if (lowerName == "login") return login; - if (lowerName == "currip") return currIP.ToString(); - if (lowerName == "enableddirs") return GetEnabledDirs(); - if (lowerName == "tariff") return properties.tariffName; - if (properties.Exists(lowerName)) - return properties.GetPropertyValue(lowerName); - else - { - WriteServLog("User’s parameter '%s' does not exist.", name.c_str()); - return ""; - } -} -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- -void STG::CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive) -{ -if (newPassive && !oldPassive && user->tariff != NULL) - user->properties.cash.Set(user->cash - user->tariff->GetPassiveCost(), - *user->sysAdmin, - user->login, - *user->store, - "Freeze"); -} -//----------------------------------------------------------------------------- -void STG::CHG_DISABLED_NOTIFIER::Notify(const int & oldValue, const int & newValue) -{ -if (oldValue && !newValue && user->GetConnected()) - user->Disconnect(false, "disabled"); -else if (!oldValue && newValue && user->IsInetable()) - user->Connect(false); -} -//----------------------------------------------------------------------------- -void STG::CHG_TARIFF_NOTIFIER::Notify(const std::string &, const std::string & newTariff) -{ -STG_LOCKER lock(&user->mutex); -if (user->settings->GetReconnectOnTariffChange() && user->connected) - user->Disconnect(false, "Change tariff"); -user->tariff = user->tariffs->FindByName(newTariff); -if (user->settings->GetReconnectOnTariffChange() && - !user->authorizedBy.empty() && - user->IsInetable()) - { - // This notifier gets called *before* changing the tariff, and in Connect we want to see new tariff name. - user->properties.Conf().tariffName = newTariff; - user->Connect(false); - } -} -//----------------------------------------------------------------------------- -void STG::CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash) -{ -user->lastCashAddTime = *const_cast(&stgTime); -user->lastCashAdd = newCash - oldCash; -} -//----------------------------------------------------------------------------- -void STG::CHG_IPS_NOTIFIER::Notify(const UserIPs & from, const UserIPs & to) -{ -printfd(__FILE__, "Change IP from '%s' to '%s'\n", from.toString().c_str(), to.toString().c_str()); -if (user->connected) - user->Disconnect(false, "Change IP"); -if (!user->authorizedBy.empty() && user->IsInetable()) - user->Connect(false); -}