2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
27 $Date: 2010/11/03 10:50:03 $
35 #include "user_impl.h"
36 #include "settings_impl.h"
37 #include "stg_timer.h"
39 #include "stg/users.h"
40 #include "stg/common.h"
41 #include "stg/scriptexecuter.h"
42 #include "stg/tariff.h"
43 #include "stg/tariffs.h"
44 #include "stg/services.h"
45 #include "stg/service_conf.h"
46 #include "stg/admin.h"
57 #include <unistd.h> // access
64 std::string dirsToString(const bool * dirs)
67 for (size_t i = 0; i < DIR_NUM; i++)
68 res += dirs[i] ? '1' : '0';
72 void dirsFromBits(bool * dirs, uint32_t bits)
74 for (size_t i = 0; i < DIR_NUM; i++)
75 dirs[i] = bits & (1 << i);
80 UserImpl::UserImpl(const Settings * s,
85 const Services & svcs)
88 WriteServLog(Logger::get()),
91 lastIPForDisconnect(0),
99 authorizedModificationTime(0),
102 lastWriteDetailedStat(0),
103 cash(properties.cash),
105 down(properties.down),
106 lastCashAdd(properties.lastCashAdd),
107 passiveTime(properties.passiveTime),
108 lastCashAddTime(properties.lastCashAddTime),
109 freeMb(properties.freeMb),
110 lastActivityTime(properties.lastActivityTime),
111 password(properties.password),
112 passive(properties.passive),
113 disabled(properties.disabled),
114 disabledDetailStat(properties.disabledDetailStat),
115 alwaysOnline(properties.alwaysOnline),
116 tariffName(properties.tariffName),
117 nextTariff(properties.nextTariff),
118 address(properties.address),
119 note(properties.note),
120 group(properties.group),
121 email(properties.email),
122 phone(properties.phone),
123 realName(properties.realName),
124 credit(properties.credit),
125 creditExpire(properties.creditExpire),
127 userdata0(properties.userdata0),
128 userdata1(properties.userdata1),
129 userdata2(properties.userdata2),
130 userdata3(properties.userdata3),
131 userdata4(properties.userdata4),
132 userdata5(properties.userdata5),
133 userdata6(properties.userdata6),
134 userdata7(properties.userdata7),
135 userdata8(properties.userdata8),
136 userdata9(properties.userdata9),
137 sessionUploadModTime(stgTime),
138 sessionDownloadModTime(stgTime)
142 //-----------------------------------------------------------------------------
143 void UserImpl::Init()
145 password = "*_EMPTY_PASSWORD_*";
146 tariffName = NO_TARIFF_NAME;
147 tariff = tariffs->FindByName(tariffName);
148 ips = UserIPs::parse("*");
149 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
150 lastWriteDetailedStat = stgTime;
152 m_beforePassiveConn = properties.passive.beforeChange([this](auto oldVal, auto newVal){ onPassiveChange(oldVal, newVal); });
153 m_afterDisabledConn = properties.disabled.afterChange([this](auto oldVal, auto newVal){ onDisabledChange(oldVal, newVal); });
154 m_beforeTariffConn = properties.tariffName.beforeChange([this](const auto& oldVal, const auto& newVal){ onTariffChange(oldVal, newVal); });
155 m_beforeCashConn = properties.cash.beforeChange([this](auto oldVal, auto newVal){ onCashChange(oldVal, newVal); });
156 m_afterIPConn = ips.afterChange([this](const auto& oldVal, const auto& newVal){ onIPChange(oldVal, newVal); });
158 //-----------------------------------------------------------------------------
159 UserImpl::UserImpl(const UserImpl & u)
161 properties(*u.settings),
162 WriteServLog(Logger::get()),
166 lastIPForDisconnect(0),
167 pingTime(u.pingTime),
168 sysAdmin(u.sysAdmin),
172 m_services(u.m_services),
173 traffStat(u.traffStat),
174 traffStatSaved(u.traffStatSaved),
175 settings(u.settings),
176 authorizedModificationTime(u.authorizedModificationTime),
177 messages(u.messages),
179 lastWriteStat(u.lastWriteStat),
180 lastWriteDetailedStat(u.lastWriteDetailedStat),
181 cash(properties.cash),
183 down(properties.down),
184 lastCashAdd(properties.lastCashAdd),
185 passiveTime(properties.passiveTime),
186 lastCashAddTime(properties.lastCashAddTime),
187 freeMb(properties.freeMb),
188 lastActivityTime(properties.lastActivityTime),
189 password(properties.password),
190 passive(properties.passive),
191 disabled(properties.disabled),
192 disabledDetailStat(properties.disabledDetailStat),
193 alwaysOnline(properties.alwaysOnline),
194 tariffName(properties.tariffName),
195 nextTariff(properties.nextTariff),
196 address(properties.address),
197 note(properties.note),
198 group(properties.group),
199 email(properties.email),
200 phone(properties.phone),
201 realName(properties.realName),
202 credit(properties.credit),
203 creditExpire(properties.creditExpire),
205 userdata0(properties.userdata0),
206 userdata1(properties.userdata1),
207 userdata2(properties.userdata2),
208 userdata3(properties.userdata3),
209 userdata4(properties.userdata4),
210 userdata5(properties.userdata5),
211 userdata6(properties.userdata6),
212 userdata7(properties.userdata7),
213 userdata8(properties.userdata8),
214 userdata9(properties.userdata9),
217 sessionUploadModTime(stgTime),
218 sessionDownloadModTime(stgTime)
223 m_beforePassiveConn = properties.passive.beforeChange([this](auto oldVal, auto newVal){ onPassiveChange(oldVal, newVal); });
224 m_afterDisabledConn = properties.disabled.afterChange([this](auto oldVal, auto newVal){ onDisabledChange(oldVal, newVal); });
225 m_beforeTariffConn = properties.tariffName.beforeChange([this](const auto& oldVal, const auto& newVal){ onTariffChange(oldVal, newVal); });
226 m_beforeCashConn = properties.cash.beforeChange([this](auto oldVal, auto newVal){ onCashChange(oldVal, newVal); });
227 m_afterIPConn = ips.afterChange([this](const auto& oldVal, const auto& newVal){ onIPChange(oldVal, newVal); });
229 properties.SetProperties(u.properties);
231 //-----------------------------------------------------------------------------
232 void UserImpl::SetLogin(const std::string & l)
234 std::lock_guard lock(m_mutex);
235 static int idGen = 0;
236 assert(login.empty() && "Login is already set");
240 //-----------------------------------------------------------------------------
241 int UserImpl::ReadConf()
243 std::lock_guard lock(m_mutex);
246 if (store->RestoreUserConf(&conf, login))
248 WriteServLog("Cannot read conf for user %s.", login.c_str());
249 WriteServLog("%s", store->GetStrError().c_str());
250 printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
251 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
255 properties.SetConf(conf);
257 tariff = tariffs->FindByName(tariffName);
260 WriteServLog("Cannot read user %s. Tariff %s not exist.",
261 login.c_str(), properties.tariffName.Get().c_str());
265 std::vector<Message::Header> hdrsList;
267 if (store->GetMessageHdrs(&hdrsList, login))
269 printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
270 WriteServLog("Cannot read user %s. Error reading message headers: %s.",
272 store->GetStrError().c_str());
276 std::vector<Message::Header>::const_iterator it;
277 for (it = hdrsList.begin(); it != hdrsList.end(); ++it)
280 if (store->GetMessage(it->id, &msg, login) == 0)
282 messages.push_back(msg);
288 //-----------------------------------------------------------------------------
289 int UserImpl::ReadStat()
291 std::lock_guard lock(m_mutex);
294 if (store->RestoreUserStat(&stat, login))
296 WriteServLog("Cannot read stat for user %s.", login.c_str());
297 WriteServLog("%s", store->GetStrError().c_str());
298 printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
299 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
303 properties.SetStat(stat);
307 //-----------------------------------------------------------------------------
308 int UserImpl::WriteConf()
310 std::lock_guard lock(m_mutex);
311 UserConf conf(properties.GetConf());
313 printfd(__FILE__, "UserImpl::WriteConf()\n");
315 if (store->SaveUserConf(conf, login))
317 WriteServLog("Cannot write conf for user %s.", login.c_str());
318 WriteServLog("%s", store->GetStrError().c_str());
319 printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
320 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
326 //-----------------------------------------------------------------------------
327 int UserImpl::WriteStat()
329 std::lock_guard lock(m_mutex);
330 UserStat stat(properties.GetStat());
332 if (store->SaveUserStat(stat, login))
334 WriteServLog("Cannot write stat for user %s.", login.c_str());
335 WriteServLog("%s", store->GetStrError().c_str());
336 printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
337 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
341 lastWriteStat = stgTime;
345 //-----------------------------------------------------------------------------
346 int UserImpl::WriteMonthStat()
348 std::lock_guard lock(m_mutex);
349 time_t tt = stgTime - 3600;
351 localtime_r(&tt, &t1);
353 UserStat stat(properties.GetStat());
354 if (store->SaveMonthStat(stat, t1.tm_mon, t1.tm_year, login))
356 WriteServLog("Cannot write month stat for user %s.", login.c_str());
357 WriteServLog("%s", store->GetStrError().c_str());
358 printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
359 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
365 //-----------------------------------------------------------------------------
366 int UserImpl::Authorize(uint32_t ip, uint32_t dirs, const Auth * auth)
368 std::lock_guard lock(m_mutex);
370 * Authorize user. It only means that user will be authorized. Nothing more.
371 * User can be connected or disconnected while authorized.
372 * Example: user is authorized but disconnected due to 0 money or blocking
376 * TODO: in fact "authorization" means allowing access to a service. What we
377 * call "authorization" here, int STG, is "authentication". So this should be
382 * Prevent double authorization by identical authorizers
384 if (authorizedBy.find(auth) != authorizedBy.end())
390 dirsFromBits(enabledDirs, dirs);
392 if (!authorizedBy.empty())
396 // We are already authorized, but with different IP address
397 errorStr = "User " + login + " already authorized with IP address " + inet_ntostring(ip);
402 if (!users->FindByIPIdx(ip, &u))
404 // Address presents in IP-index.
405 // If it's not our IP - report it.
408 errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
415 if (users->IsIPInIndex(ip))
417 // Address is already present in IP-index.
418 errorStr = "IP address " + inet_ntostring(ip) + " is already in use";
422 if (ips.ConstData().find(ip))
425 lastIPForDisconnect = m_currIP;
429 printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().toString().c_str());
430 errorStr = "IP address " + inet_ntostring(ip) + " does not belong to user " + login;
435 if (authorizedBy.empty())
436 authorizedModificationTime = stgTime;
437 authorizedBy.insert(auth);
443 //-----------------------------------------------------------------------------
444 void UserImpl::Unauthorize(const Auth * auth, const std::string & reason)
446 std::lock_guard lock(m_mutex);
448 * Authorizer tries to unauthorize user, that was not authorized by it
450 if (!authorizedBy.erase(auth))
453 authorizedModificationTime = stgTime;
455 if (authorizedBy.empty())
457 lastDisconnectReason = reason;
458 lastIPForDisconnect = m_currIP;
459 m_currIP = 0; // DelUser in traffcounter
461 Disconnect(false, "not authorized");
465 //-----------------------------------------------------------------------------
466 bool UserImpl::IsAuthorizedBy(const Auth * auth) const
468 std::lock_guard lock(m_mutex);
469 // Is this user authorized by specified authorizer?
470 return authorizedBy.find(auth) != authorizedBy.end();
472 //-----------------------------------------------------------------------------
473 std::vector<std::string> UserImpl::GetAuthorizers() const
475 std::lock_guard lock(m_mutex);
476 std::vector<std::string> list;
477 std::transform(authorizedBy.begin(), authorizedBy.end(), std::back_inserter(list), [](const auto auth){ return auth->GetVersion(); });
480 //-----------------------------------------------------------------------------
481 void UserImpl::Connect(bool fakeConnect)
484 * Connect user to Internet. This function is differ from Authorize() !!!
489 std::string scriptOnConnect = settings->GetScriptsDir() + "/OnConnect";
491 if (access(scriptOnConnect.c_str(), X_OK) == 0)
493 std::string dirs = dirsToString(enabledDirs);
495 std::string scriptOnConnectParams;
496 strprintf(&scriptOnConnectParams,
497 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
498 scriptOnConnect.c_str(),
500 inet_ntostring(m_currIP).c_str(),
505 std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
506 while (it != settings->GetScriptParams().end())
508 scriptOnConnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
512 ScriptExec(scriptOnConnectParams.c_str());
516 WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
522 if (!settings->GetDisableSessionLog() && store->WriteUserConnect(login, m_currIP))
524 WriteServLog("Cannot write connect for user %s.", login.c_str());
525 WriteServLog("%s", store->GetStrError().c_str());
529 lastIPForDisconnect = m_currIP;
531 //-----------------------------------------------------------------------------
532 void UserImpl::Disconnect(bool fakeDisconnect, const std::string & reason)
535 * Disconnect user from Internet. This function is differ from UnAuthorize() !!!
538 if (!lastIPForDisconnect)
540 printfd(__FILE__, "lastIPForDisconnect\n");
546 lastDisconnectReason = reason;
547 std::string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect";
549 if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
551 std::string dirs = dirsToString(enabledDirs);
553 std::string scriptOnDisonnectParams;
554 strprintf(&scriptOnDisonnectParams,
555 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
556 scriptOnDisonnect.c_str(),
558 inet_ntostring(lastIPForDisconnect).c_str(),
563 std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
564 while (it != settings->GetScriptParams().end())
566 scriptOnDisonnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
570 ScriptExec(scriptOnDisonnectParams.c_str());
574 WriteServLog("Script OnDisconnect cannot be executed. File not found.");
580 std::string reasonMessage(reason);
581 if (!lastDisconnectReason.empty())
582 reasonMessage += ": " + lastDisconnectReason;
584 if (!settings->GetDisableSessionLog() && store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload,
585 cash, freeMb, reasonMessage))
587 WriteServLog("Cannot write disconnect for user %s.", login.c_str());
588 WriteServLog("%s", store->GetStrError().c_str());
592 lastIPForDisconnect = 0;
594 sessionUpload.reset();
595 sessionDownload.reset();
596 sessionUploadModTime = stgTime;
597 sessionDownloadModTime = stgTime;
599 //-----------------------------------------------------------------------------
602 std::lock_guard lock(m_mutex);
604 if (stgTime > lastWriteStat + settings->GetStatWritePeriod())
606 printfd(__FILE__, "UserImpl::WriteStat user=%s\n", GetLogin().c_str());
609 if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
611 WriteServLog("User: %s. Credit expired.", login.c_str());
617 if (passive.ConstData()
618 && (stgTime % 30 == 0)
619 && (passiveTime.ModificationTime() != stgTime))
621 passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
622 printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
625 if (!authorizedBy.empty())
628 properties.Stat().lastActivityTime = stgTime;
630 if (!m_connected && IsInetable())
633 if (m_connected && !IsInetable())
636 Disconnect(false, "disabled");
638 Disconnect(false, "passive");
640 Disconnect(false, "no cash");
643 if (stgTime - lastScanMessages > 10)
646 lastScanMessages = stgTime;
652 Disconnect(false, "not authorized");
656 //-----------------------------------------------------------------------------
657 void UserImpl::UpdatePingTime(time_t t)
659 std::lock_guard lock(m_mutex);
665 //-----------------------------------------------------------------------------
666 bool UserImpl::IsInetable()
668 if (disabled || passive)
671 if (settings->GetFreeMbAllowInet())
677 if (settings->GetShowFeeInCash() || tariff == NULL)
678 return (cash >= -credit);
680 return (cash - tariff->GetFee() >= -credit);
682 //-----------------------------------------------------------------------------
683 std::string UserImpl::GetEnabledDirs() const
685 return dirsToString(enabledDirs);
687 //-----------------------------------------------------------------------------
688 #ifdef TRAFF_STAT_WITH_PORTS
689 void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
691 void UserImpl::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
694 std::lock_guard lock(m_mutex);
696 if (!m_connected || tariff == NULL)
702 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
703 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
707 int tt = tariff->GetTraffType();
708 if (tt == Tariff::TRAFF_UP ||
709 tt == Tariff::TRAFF_UP_DOWN ||
710 // Check NEW traff data
711 (tt == Tariff::TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
714 if (traff < threshold &&
715 traff + len >= threshold)
717 // cash = partBeforeThreshold * priceBeforeThreshold +
718 // partAfterThreshold * priceAfterThreshold
719 int64_t before = threshold - traff; // Chunk part before threshold
720 int64_t after = len - before; // Chunk part after threshold
721 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
722 down.ConstData()[dir],
725 tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
726 down.ConstData()[dir],
732 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
733 down.ConstData()[dir],
738 if (freeMb.ConstData() <= 0) // FreeMb is exhausted
740 else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
741 cost = dc - freeMb.ConstData();
743 // Direct access to internal data structures via friend-specifier
744 properties.Stat().freeMb -= dc;
745 properties.Stat().cash -= cost;
751 sessionUpload[dir] += len;
752 sessionUploadModTime = stgTime;
756 if (!settings->GetWriteFreeMbTraffCost() &&
757 freeMb.ConstData() >= 0)
760 #ifdef TRAFF_STAT_WITH_PORTS
761 IPDirPair idp(ip, dir, port);
763 IPDirPair idp(ip, dir);
766 std::map<IPDirPair, StatNode>::iterator lb;
767 lb = traffStat.lower_bound(idp);
768 if (lb == traffStat.end() || lb->first != idp)
772 StatNode(len, 0, cost)));
776 lb->second.cash += cost;
777 lb->second.up += len;
780 //-----------------------------------------------------------------------------
781 #ifdef TRAFF_STAT_WITH_PORTS
782 void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
784 void UserImpl::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
787 std::lock_guard lock(m_mutex);
789 if (!m_connected || tariff == NULL)
795 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
796 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
800 int tt = tariff->GetTraffType();
801 if (tt == Tariff::TRAFF_DOWN ||
802 tt == Tariff::TRAFF_UP_DOWN ||
803 // Check NEW traff data
804 (tt == Tariff::TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
807 if (traff < threshold &&
808 traff + len >= threshold)
810 // cash = partBeforeThreshold * priceBeforeThreshold +
811 // partAfterThreshold * priceAfterThreshold
812 int64_t before = threshold - traff; // Chunk part before threshold
813 int64_t after = len - before; // Chunk part after threshold
814 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
815 down.ConstData()[dir], // Traff before chunk
818 tariff->GetPriceWithTraffType(up.ConstData()[dir],
819 dt[dir], // Traff after chunk
825 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
826 down.ConstData()[dir],
831 if (freeMb.ConstData() <= 0) // FreeMb is exhausted
833 else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
834 cost = dc - freeMb.ConstData();
836 properties.Stat().freeMb -= dc;
837 properties.Stat().cash -= cost;
843 sessionDownload[dir] += len;
844 sessionDownloadModTime = stgTime;
848 if (!settings->GetWriteFreeMbTraffCost() &&
849 freeMb.ConstData() >= 0)
852 #ifdef TRAFF_STAT_WITH_PORTS
853 IPDirPair idp(ip, dir, port);
855 IPDirPair idp(ip, dir);
858 std::map<IPDirPair, StatNode>::iterator lb;
859 lb = traffStat.lower_bound(idp);
860 if (lb == traffStat.end() || lb->first != idp)
864 StatNode(0, len, cost)));
868 lb->second.cash += cost;
869 lb->second.down += len;
872 //-----------------------------------------------------------------------------
873 void UserImpl::OnAdd()
875 std::lock_guard lock(m_mutex);
877 std::string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd";
879 if (access(scriptOnAdd.c_str(), X_OK) == 0)
881 std::string scriptOnAddParams = scriptOnAdd + " \"" + login + "\"";
883 ScriptExec(scriptOnAddParams.c_str());
887 WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
890 //-----------------------------------------------------------------------------
891 void UserImpl::OnDelete()
893 std::lock_guard lock(m_mutex);
895 std::string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel";
897 if (access(scriptOnDel.c_str(), X_OK) == 0)
899 std::string scriptOnDelParams = scriptOnDel + " \"" + login + "\"";
901 ScriptExec(scriptOnDelParams.c_str());
905 WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
910 //-----------------------------------------------------------------------------
911 int UserImpl::WriteDetailStat(bool hard)
913 printfd(__FILE__, "UserImpl::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
915 if (!traffStatSaved.second.empty())
917 if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
919 printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write detail stat from queue\n");
920 WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
921 WriteServLog("%s", store->GetStrError().c_str());
924 traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
930 std::lock_guard lock(m_mutex);
934 printfd(__FILE__, "UserImpl::WriteDetailedStat() - size = %d\n", ts.size());
936 if (ts.size() && !disabledDetailStat)
938 if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login))
940 printfd(__FILE__, "UserImpl::WriteDetailStat() - failed to write current detail stat\n");
941 WriteServLog("Cannot write detail stat for user %s.", login.c_str());
942 WriteServLog("%s", store->GetStrError().c_str());
945 printfd(__FILE__, "UserImpl::WriteDetailStat() - pushing detail stat to queue\n");
946 std::lock_guard lock(m_mutex);
947 traffStatSaved.second.swap(ts);
948 traffStatSaved.first = lastWriteDetailedStat;
953 lastWriteDetailedStat = stgTime;
956 //-----------------------------------------------------------------------------
957 double UserImpl::GetPassiveTimePart() const
959 std::lock_guard lock(m_mutex);
960 return getPassiveTimePart();
963 double UserImpl::getPassiveTimePart() const
965 static const std::array<unsigned, 12> daysInMonth{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
969 localtime_r(&t, &tms);
971 time_t secMonth = daysInMonth[(tms.tm_mon + 11) % 12] * 24 * 3600; // Previous month
973 if (tms.tm_year % 4 == 0 && tms.tm_mon == 1)
976 secMonth += 24 * 3600;
979 time_t dt = secMonth - passiveTime;
984 return static_cast<double>(dt) / secMonth;
986 //-----------------------------------------------------------------------------
987 void UserImpl::SetPassiveTimeAsNewUser()
989 std::lock_guard lock(m_mutex);
993 localtime_r(&t, &tm);
994 int daysCurrMon = DaysInCurrentMonth();
995 double pt = tm.tm_mday - 1;
998 passiveTime = static_cast<time_t>(pt * 24 * 3600 * daysCurrMon);
1000 //-----------------------------------------------------------------------------
1001 void UserImpl::MidnightResetSessionStat()
1003 std::lock_guard lock(m_mutex);
1007 Disconnect(true, "fake");
1011 //-----------------------------------------------------------------------------
1012 void UserImpl::ProcessNewMonth()
1014 std::lock_guard lock(m_mutex);
1017 Disconnect(true, "fake");
1021 properties.Stat().monthUp.reset();
1022 properties.Stat().monthDown.reset();
1028 if (nextTariff.ConstData() != "")
1030 const Tariff * nt = tariffs->FindByName(nextTariff);
1033 WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
1034 login.c_str(), properties.tariffName.Get().c_str());
1038 std::string message = tariff->TariffChangeIsAllowed(*nt, stgTime);
1039 if (message.empty())
1041 properties.tariffName.Set(nextTariff, *sysAdmin, login, *store);
1045 WriteServLog("Tariff change is prohibited for user %s. %s",
1054 //-----------------------------------------------------------------------------
1055 void UserImpl::ProcessDayFeeSpread()
1057 std::lock_guard lock(m_mutex);
1059 if (passive.ConstData() || tariff == NULL)
1062 if (tariff->GetPeriod() != Tariff::MONTH)
1065 double fee = tariff->GetFee() / DaysInCurrentMonth();
1067 if (std::fabs(fee) < 1.0e-3)
1071 switch (settings->GetFeeChargeType())
1074 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1077 if (c + credit >= 0)
1078 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1081 if (c + credit >= fee)
1082 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1086 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1091 //-----------------------------------------------------------------------------
1092 void UserImpl::ProcessDayFee()
1094 std::lock_guard lock(m_mutex);
1099 if (tariff->GetPeriod() != Tariff::MONTH)
1102 double passiveTimePart = 1.0;
1103 if (!settings->GetFullFee())
1105 passiveTimePart = getPassiveTimePart();
1109 if (passive.ConstData())
1111 printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1115 double fee = tariff->GetFee() * passiveTimePart;
1119 if (std::fabs(fee) < 1.0e-3)
1126 printfd(__FILE__, "login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n",
1133 switch (settings->GetFeeChargeType())
1136 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1140 if (c + credit >= 0)
1142 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1147 if (c + credit >= fee)
1149 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1156 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1162 //-----------------------------------------------------------------------------
1163 void UserImpl::ProcessDailyFee()
1165 std::lock_guard lock(m_mutex);
1167 if (passive.ConstData() || tariff == NULL)
1170 if (tariff->GetPeriod() != Tariff::DAY)
1173 double fee = tariff->GetFee();
1179 switch (settings->GetFeeChargeType())
1182 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1185 if (c + credit >= 0)
1186 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1189 if (c + credit >= fee)
1190 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1195 //-----------------------------------------------------------------------------
1196 void UserImpl::ProcessServices()
1200 localtime_r(&t, &tms);
1202 std::lock_guard lock(m_mutex);
1204 double passiveTimePart = 1.0;
1205 if (!settings->GetFullFee())
1207 passiveTimePart = getPassiveTimePart();
1211 if (passive.ConstData())
1213 printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1218 for (size_t i = 0; i < properties.Conf().services.size(); ++i)
1221 if (m_services.Find(properties.Conf().services[i], &conf))
1223 if (conf.payDay == tms.tm_mday ||
1224 (conf.payDay == 0 && tms.tm_mday == DaysInCurrentMonth()))
1227 double fee = conf.cost * passiveTimePart;
1228 printfd(__FILE__, "Service fee. login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n",
1235 switch (settings->GetFeeChargeType())
1238 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1242 if (c + credit >= 0)
1244 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1249 if (c + credit >= fee)
1251 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1258 properties.cash.Set(c - fee, *sysAdmin, login, *store, "Subscriber fee charge");
1266 //-----------------------------------------------------------------------------
1267 void UserImpl::SetPrepaidTraff()
1270 properties.freeMb.Set(tariff->GetFree(), *sysAdmin, login, *store, "Prepaid traffic");
1272 //-----------------------------------------------------------------------------
1273 int UserImpl::AddMessage(Message * msg)
1275 std::lock_guard lock(m_mutex);
1277 if (SendMessage(*msg))
1279 if (store->AddMessage(msg, login))
1281 errorStr = store->GetStrError();
1282 WriteServLog("Error adding message: '%s'", errorStr.c_str());
1283 printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
1286 messages.push_back(*msg);
1290 if (msg->header.repeat > 0)
1292 msg->header.repeat--;
1294 //TODO: gcc v. 4.x generate ICE on x86_64
1295 msg->header.lastSendTime = static_cast<int>(time(NULL));
1297 msg->header.lastSendTime = static_cast<int>(stgTime);
1299 if (store->AddMessage(msg, login))
1301 errorStr = store->GetStrError();
1302 WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str());
1303 printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str());
1306 messages.push_back(*msg);
1311 //-----------------------------------------------------------------------------
1312 int UserImpl::SendMessage(Message & msg) const
1314 // No lock `cause we are already locked from caller
1316 std::set<const Auth*>::iterator it(authorizedBy.begin());
1317 while (it != authorizedBy.end())
1319 if (!(*it++)->SendMessage(msg, m_currIP))
1325 //TODO: gcc v. 4.x generate ICE on x86_64
1326 msg.header.lastSendTime = static_cast<int>(time(NULL));
1328 msg.header.lastSendTime = static_cast<int>(stgTime);
1330 msg.header.repeat--;
1334 //-----------------------------------------------------------------------------
1335 void UserImpl::ScanMessage()
1337 // No lock `cause we are already locked from caller
1338 // We need not check for the authorizedBy `cause it has already checked by caller
1340 auto it = messages.begin();
1341 while (it != messages.end())
1343 if (settings->GetMessageTimeout() > 0 &&
1344 difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
1347 if (store->DelMessage(it->header.id, login))
1349 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1350 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1352 messages.erase(it++);
1355 if (it->GetNextSendTime() <= stgTime)
1357 if (SendMessage(*it))
1359 // We need to check all messages in queue for timeout
1363 if (it->header.repeat < 0)
1365 if (store->DelMessage(it->header.id, login))
1367 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1368 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1370 messages.erase(it++);
1374 if (store->EditMessage(*it, login))
1376 WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
1377 printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
1388 //-----------------------------------------------------------------------------
1389 std::string UserImpl::GetParamValue(const std::string & name) const
1391 std::string lowerName = ToLower(name);
1392 if (lowerName == "id")
1394 std::ostringstream stream;
1396 return stream.str();
1398 if (lowerName == "login") return login;
1399 if (lowerName == "currip") return m_currIP.ToString();
1400 if (lowerName == "enableddirs") return GetEnabledDirs();
1401 if (lowerName == "tariff") return properties.tariffName;
1402 if (properties.Exists(lowerName))
1403 return properties.GetPropertyValue(lowerName);
1406 WriteServLog("User’s parameter '%s' does not exist.", name.c_str());
1410 //-----------------------------------------------------------------------------
1411 //-----------------------------------------------------------------------------
1412 //-----------------------------------------------------------------------------
1413 void UserImpl::onPassiveChange(int oldVal, int newVal)
1415 std::lock_guard lock(m_mutex);
1416 if (newVal && !oldVal && tariff != NULL)
1417 properties.cash.Set(cash - tariff->GetPassiveCost(),
1423 //-----------------------------------------------------------------------------
1424 void UserImpl::onDisabledChange(int oldVal, int newVal)
1426 std::lock_guard lock(m_mutex);
1427 if (oldVal && !newVal && GetConnected())
1428 Disconnect(false, "disabled");
1429 else if (!oldVal && newVal && IsInetable())
1432 //-----------------------------------------------------------------------------
1433 void UserImpl::onTariffChange(const std::string& /*oldVal*/, const std::string& newVal)
1435 std::lock_guard lock(m_mutex);
1436 if (settings->GetReconnectOnTariffChange() && m_connected)
1437 Disconnect(false, "Change tariff");
1438 tariff = tariffs->FindByName(newVal);
1439 if (settings->GetReconnectOnTariffChange() &&
1440 !authorizedBy.empty() &&
1443 // This notifier gets called *before* changing the tariff, and in Connect we want to see new tariff name.
1444 properties.Conf().tariffName = newVal;
1448 //-----------------------------------------------------------------------------
1449 void UserImpl::onCashChange(double oldVal, double newVal)
1451 time_t now = stgTime;
1452 lastCashAddTime = now;
1453 lastCashAdd = newVal - oldVal;
1455 //-----------------------------------------------------------------------------
1456 void UserImpl::onIPChange(const UserIPs& oldVal, const UserIPs& newVal)
1458 std::lock_guard lock(m_mutex);
1459 printfd(__FILE__, "Change IP from '%s' to '%s'\n", oldVal.toString().c_str(), newVal.toString().c_str());
1461 Disconnect(false, "Change IP");
1462 if (!authorizedBy.empty() && IsInetable())