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 $
36 #include <unistd.h> // access
41 #include "stg/users.h"
42 #include "stg/common.h"
43 #include "stg/scriptexecuter.h"
44 #include "stg/tariff.h"
45 #include "stg/tariffs.h"
46 #include "stg/admin.h"
47 #include "user_impl.h"
48 #include "settings_impl.h"
49 #include "stg_timer.h"
51 #ifdef USE_ABSTRACT_SETTINGS
52 USER_IMPL::USER_IMPL(const SETTINGS * s,
59 property(s->GetScriptsDir()),
60 WriteServLog(GetStgLogger()),
65 connected(__connected),
70 lastIPForDisconnect(0),
83 lastWriteDetailedStat(0),
87 lastCashAdd(property.lastCashAdd),
88 passiveTime(property.passiveTime),
89 lastCashAddTime(property.lastCashAddTime),
90 freeMb(property.freeMb),
91 lastActivityTime(property.lastActivityTime),
92 password(property.password),
93 passive(property.passive),
94 disabled(property.disabled),
95 disabledDetailStat(property.disabledDetailStat),
96 alwaysOnline(property.alwaysOnline),
97 tariffName(property.tariffName),
98 nextTariff(property.nextTariff),
99 address(property.address),
101 group(property.group),
102 email(property.email),
103 phone(property.phone),
104 realName(property.realName),
105 credit(property.credit),
106 creditExpire(property.creditExpire),
108 userdata0(property.userdata0),
109 userdata1(property.userdata1),
110 userdata2(property.userdata2),
111 userdata3(property.userdata3),
112 userdata4(property.userdata4),
113 userdata5(property.userdata5),
114 userdata6(property.userdata6),
115 userdata7(property.userdata7),
116 userdata8(property.userdata8),
117 userdata9(property.userdata9),
120 passiveNotifier(this),
121 tariffNotifier(this),
127 password = "*_EMPTY_PASSWORD_*";
128 tariffName = NO_TARIFF_NAME;
130 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
131 lastWriteDetailedStat = stgTime;
133 property.tariffName.AddBeforeNotifier(&tariffNotifier);
134 property.passive.AddBeforeNotifier(&passiveNotifier);
135 property.cash.AddBeforeNotifier(&cashNotifier);
136 ips.AddAfterNotifier(&ipNotifier);
138 pthread_mutexattr_t attr;
139 pthread_mutexattr_init(&attr);
140 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
141 pthread_mutex_init(&mutex, &attr);
144 USER_IMPL::USER_IMPL(const SETTINGS_IMPL * s,
151 property(s->GetScriptsDir()),
152 WriteServLog(GetStgLogger()),
157 connected(__connected),
162 lastIPForDisconnect(0),
175 lastWriteDetailedStat(0),
179 lastCashAdd(property.lastCashAdd),
180 passiveTime(property.passiveTime),
181 lastCashAddTime(property.lastCashAddTime),
182 freeMb(property.freeMb),
183 lastActivityTime(property.lastActivityTime),
184 password(property.password),
185 passive(property.passive),
186 disabled(property.disabled),
187 disabledDetailStat(property.disabledDetailStat),
188 alwaysOnline(property.alwaysOnline),
189 tariffName(property.tariffName),
190 nextTariff(property.nextTariff),
191 address(property.address),
193 group(property.group),
194 email(property.email),
195 phone(property.phone),
196 realName(property.realName),
197 credit(property.credit),
198 creditExpire(property.creditExpire),
200 userdata0(property.userdata0),
201 userdata1(property.userdata1),
202 userdata2(property.userdata2),
203 userdata3(property.userdata3),
204 userdata4(property.userdata4),
205 userdata5(property.userdata5),
206 userdata6(property.userdata6),
207 userdata7(property.userdata7),
208 userdata8(property.userdata8),
209 userdata9(property.userdata9),
212 passiveNotifier(this),
213 tariffNotifier(this),
219 password = "*_EMPTY_PASSWORD_*";
220 tariffName = NO_TARIFF_NAME;
222 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
223 lastWriteDetailedStat = stgTime;
225 property.tariffName.AddBeforeNotifier(&tariffNotifier);
226 property.passive.AddBeforeNotifier(&passiveNotifier);
227 property.cash.AddBeforeNotifier(&cashNotifier);
228 ips.AddAfterNotifier(&ipNotifier);
230 pthread_mutexattr_t attr;
231 pthread_mutexattr_init(&attr);
232 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
233 pthread_mutex_init(&mutex, &attr);
236 //-----------------------------------------------------------------------------
237 USER_IMPL::USER_IMPL(const USER_IMPL & u)
240 property(u.settings->GetScriptsDir()),
241 WriteServLog(GetStgLogger()),
246 connected(__connected),
248 userIDGenerator(u.userIDGenerator),
249 __currIP(u.__currIP),
251 lastIPForDisconnect(0),
252 pingTime(u.pingTime),
253 sysAdmin(u.sysAdmin),
257 traffStat(u.traffStat),
258 traffStatSaved(u.traffStatSaved),
259 settings(u.settings),
261 messages(u.messages),
263 lastWriteStat(u.lastWriteStat),
264 lastWriteDetailedStat(u.lastWriteDetailedStat),
268 lastCashAdd(property.lastCashAdd),
269 passiveTime(property.passiveTime),
270 lastCashAddTime(property.lastCashAddTime),
271 freeMb(property.freeMb),
272 lastActivityTime(property.lastActivityTime),
273 password(property.password),
274 passive(property.passive),
275 disabled(property.disabled),
276 disabledDetailStat(property.disabledDetailStat),
277 alwaysOnline(property.alwaysOnline),
278 tariffName(property.tariffName),
279 nextTariff(property.nextTariff),
280 address(property.address),
282 group(property.group),
283 email(property.email),
284 phone(property.phone),
285 realName(property.realName),
286 credit(property.credit),
287 creditExpire(property.creditExpire),
289 userdata0(property.userdata0),
290 userdata1(property.userdata1),
291 userdata2(property.userdata2),
292 userdata3(property.userdata3),
293 userdata4(property.userdata4),
294 userdata5(property.userdata5),
295 userdata6(property.userdata6),
296 userdata7(property.userdata7),
297 userdata8(property.userdata8),
298 userdata9(property.userdata9),
301 passiveNotifier(this),
302 tariffNotifier(this),
311 property.tariffName.AddBeforeNotifier(&tariffNotifier);
312 property.passive.AddBeforeNotifier(&passiveNotifier);
313 property.cash.AddBeforeNotifier(&cashNotifier);
314 ips.AddAfterNotifier(&ipNotifier);
316 property.SetProperties(u.property);
318 pthread_mutexattr_t attr;
319 pthread_mutexattr_init(&attr);
320 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
321 pthread_mutex_init(&mutex, &attr);
323 //-----------------------------------------------------------------------------
324 USER_IMPL::~USER_IMPL()
326 property.passive.DelBeforeNotifier(&passiveNotifier);
327 property.tariffName.DelBeforeNotifier(&tariffNotifier);
328 pthread_mutex_destroy(&mutex);
330 //-----------------------------------------------------------------------------
331 void USER_IMPL::SetLogin(string const & l)
333 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
334 assert(login.empty() && "Login is already set");
336 id = userIDGenerator.GetNextID();
338 //-----------------------------------------------------------------------------
339 int USER_IMPL::ReadConf()
341 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
344 if (store->RestoreUserConf(&conf, login))
346 WriteServLog("Cannot read conf for user %s.", login.c_str());
347 WriteServLog("%s", store->GetStrError().c_str());
348 printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
349 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
353 property.SetConf(conf);
355 tariff = tariffs->FindByName(tariffName);
358 WriteServLog("Cannot read user %s. Tariff %s not exist.",
359 login.c_str(), property.tariffName.Get().c_str());
363 std::vector<STG_MSG_HDR> hdrsList;
365 if (store->GetMessageHdrs(&hdrsList, login))
367 printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
368 WriteServLog("Cannot read user %s. Error reading message headers: %s.",
370 store->GetStrError().c_str());
374 std::vector<STG_MSG_HDR>::const_iterator it;
375 for (it = hdrsList.begin(); it != hdrsList.end(); ++it)
378 if (store->GetMessage(it->id, &msg, login) == 0)
380 messages.push_back(msg);
386 //-----------------------------------------------------------------------------
387 int USER_IMPL::ReadStat()
389 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
392 if (store->RestoreUserStat(&stat, login))
394 WriteServLog("Cannot read stat for user %s.", login.c_str());
395 WriteServLog("%s", store->GetStrError().c_str());
396 printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
397 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
401 property.SetStat(stat);
405 //-----------------------------------------------------------------------------
406 int USER_IMPL::WriteConf()
408 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
409 USER_CONF conf(property.GetConf());
411 printfd(__FILE__, "USER::WriteConf()\n");
413 if (store->SaveUserConf(conf, login))
415 WriteServLog("Cannot write conf for user %s.", login.c_str());
416 WriteServLog("%s", store->GetStrError().c_str());
417 printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
418 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
424 //-----------------------------------------------------------------------------
425 int USER_IMPL::WriteStat()
427 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
428 USER_STAT stat(property.GetStat());
430 if (store->SaveUserStat(stat, login))
432 WriteServLog("Cannot write stat for user %s.", login.c_str());
433 WriteServLog("%s", store->GetStrError().c_str());
434 printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
435 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
439 lastWriteStat = stgTime;
443 //-----------------------------------------------------------------------------
444 int USER_IMPL::WriteMonthStat()
446 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
447 time_t tt = stgTime - 3600;
449 localtime_r(&tt, &t1);
451 USER_STAT stat(property.GetStat());
452 if (store->SaveMonthStat(stat, t1.tm_mon, t1.tm_year, login))
454 WriteServLog("Cannot write month stat for user %s.", login.c_str());
455 WriteServLog("%s", store->GetStrError().c_str());
456 printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
457 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
463 //-----------------------------------------------------------------------------
464 int USER_IMPL::Authorize(uint32_t ip, uint32_t dirs, const AUTH * auth)
466 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
468 * Authorize user. It only means that user will be authorized. Nothing more.
469 * User can be connected or disconnected while authorized.
470 * Example: user is authorized but disconnected due to 0 money or blocking
474 * Prevent double authorization by identical authorizers
476 if (authorizedBy.find(auth) != authorizedBy.end())
482 for (int i = 0; i < DIR_NUM; i++)
484 enabledDirs[i] = dirs & (1 << i);
487 if (!authorizedBy.empty())
491 // We are already authorized, but with different IP address
492 errorStr = "User " + login + " already authorized with IP address " + inet_ntostring(ip);
497 if (!users->FindByIPIdx(ip, &u))
499 // Address is already present in IP-index
500 // If it's not our IP - throw an error
503 errorStr = "IP address " + inet_ntostring(ip) + " already in use";
510 if (users->IsIPInIndex(ip))
512 // Address is already present in IP-index
513 errorStr = "IP address " + inet_ntostring(ip) + " already in use";
517 if (ips.ConstData().IsIPInIPS(ip))
520 lastIPForDisconnect = currIP;
524 printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().GetIpStr().c_str());
525 errorStr = "IP address " + inet_ntostring(ip) + " not belong user " + login;
530 authorizedBy.insert(auth);
536 //-----------------------------------------------------------------------------
537 void USER_IMPL::Unauthorize(const AUTH * auth)
539 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
541 * Authorizer tries to unauthorize user, that was not authorized by it
543 if (!authorizedBy.erase(auth))
546 if (authorizedBy.empty())
548 lastIPForDisconnect = currIP;
549 currIP = 0; // DelUser in traffcounter
553 //-----------------------------------------------------------------------------
554 bool USER_IMPL::IsAuthorizedBy(const AUTH * auth) const
556 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
557 // Is this user authorized by specified authorizer?
558 return authorizedBy.find(auth) != authorizedBy.end();
560 //-----------------------------------------------------------------------------
561 void USER_IMPL::Connect(bool fakeConnect)
564 * Connect user to Internet. This function is differ from Authorize() !!!
567 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
571 string scriptOnConnect = settings->GetScriptsDir() + "/OnConnect";
573 if (access(scriptOnConnect.c_str(), X_OK) == 0)
575 char dirsStr[DIR_NUM + 1];
576 dirsStr[DIR_NUM] = 0;
577 for (int i = 0; i < DIR_NUM; i++)
579 dirsStr[i] = enabledDirs[i] ? '1' : '0';
582 string scriptOnConnectParams;
583 strprintf(&scriptOnConnectParams,
584 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
585 scriptOnConnect.c_str(),
587 inet_ntostring(currIP).c_str(),
592 ScriptExec(scriptOnConnectParams.c_str());
596 WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
602 if (store->WriteUserConnect(login, currIP))
604 WriteServLog("Cannot write connect for user %s.", login.c_str());
605 WriteServLog("%s", store->GetStrError().c_str());
609 lastIPForDisconnect = currIP;
611 //-----------------------------------------------------------------------------
612 void USER_IMPL::Disconnect(bool fakeDisconnect, const std::string & reason)
615 * Disconnect user from Internet. This function is differ from UnAuthorize() !!!
618 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
620 if (!lastIPForDisconnect)
622 printfd(__FILE__, "lastIPForDisconnect\n");
628 string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect";
630 if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
632 char dirsStr[DIR_NUM + 1];
633 dirsStr[DIR_NUM] = 0;
634 for (int i = 0; i < DIR_NUM; i++)
636 dirsStr[i] = enabledDirs[i] ? '1' : '0';
639 string scriptOnDisonnectParams;
640 strprintf(&scriptOnDisonnectParams,
641 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
642 scriptOnDisonnect.c_str(),
644 inet_ntostring(lastIPForDisconnect).c_str(),
649 ScriptExec(scriptOnDisonnectParams.c_str());
653 WriteServLog("Script OnDisconnect cannot be executed. File not found.");
659 if (store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload, cash, freeMb, reason))
661 WriteServLog("Cannot write disconnect for user %s.", login.c_str());
662 WriteServLog("%s", store->GetStrError().c_str());
666 lastIPForDisconnect = 0;
668 DIR_TRAFF zeroSesssion;
670 sessionUpload = zeroSesssion;
671 sessionDownload = zeroSesssion;
673 //-----------------------------------------------------------------------------
674 void USER_IMPL::PrintUser() const
677 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
678 cout << "============================================================" << endl;
679 cout << "id=" << id << endl;
680 cout << "login=" << login << endl;
681 cout << "password=" << password << endl;
682 cout << "passive=" << passive << endl;
683 cout << "disabled=" << disabled << endl;
684 cout << "disabledDetailStat=" << disabledDetailStat << endl;
685 cout << "alwaysOnline=" << alwaysOnline << endl;
686 cout << "tariffName=" << tariffName << endl;
687 cout << "address=" << address << endl;
688 cout << "phone=" << phone << endl;
689 cout << "email=" << email << endl;
690 cout << "note=" << note << endl;
691 cout << "realName=" <<realName << endl;
692 cout << "group=" << group << endl;
693 cout << "credit=" << credit << endl;
694 cout << "nextTariff=" << nextTariff << endl;
695 cout << "userdata0" << userdata0 << endl;
696 cout << "userdata1" << userdata1 << endl;
697 cout << "creditExpire=" << creditExpire << endl;
698 cout << "ips=" << ips << endl;
699 cout << "------------------------" << endl;
700 cout << "up=" << up << endl;
701 cout << "down=" << down << endl;
702 cout << "cash=" << cash << endl;
703 cout << "freeMb=" << freeMb << endl;
704 cout << "lastCashAdd=" << lastCashAdd << endl;
705 cout << "lastCashAddTime=" << lastCashAddTime << endl;
706 cout << "passiveTime=" << passiveTime << endl;
707 cout << "lastActivityTime=" << lastActivityTime << endl;
708 cout << "============================================================" << endl;
710 //-----------------------------------------------------------------------------
711 void USER_IMPL::Run()
713 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
715 if (stgTime > static_cast<time_t>(lastWriteStat + settings->GetStatWritePeriod()))
717 printfd(__FILE__, "USER::WriteStat user=%s\n", GetLogin().c_str());
720 if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
722 WriteServLog("User: %s. Credit expired.", login.c_str());
728 if (passive.ConstData()
729 && (stgTime % 30 == 0)
730 && (passiveTime.ModificationTime() != stgTime))
732 passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
733 printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
736 if (!authorizedBy.empty())
740 property.Stat().lastActivityTime = stgTime;
742 if (!connected && IsInetable())
746 if (connected && !IsInetable())
749 Disconnect(false, "disabled");
751 Disconnect(false, "passive");
753 Disconnect(false, "no cash");
756 if (stgTime - lastScanMessages > 10)
759 lastScanMessages = stgTime;
766 Disconnect(false, "not authorized");
771 //-----------------------------------------------------------------------------
772 void USER_IMPL::UpdatePingTime(time_t t)
774 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
775 //printfd(__FILE__, "UpdatePingTime(%d) %s\n", t, login.c_str());
781 //-----------------------------------------------------------------------------
782 bool USER_IMPL::IsInetable()
784 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
786 if (disabled || passive)
789 if (settings->GetFreeMbAllowInet())
795 if (settings->GetShowFeeInCash() || tariff == NULL)
797 return (cash >= -credit);
800 return (cash - tariff->GetFee() >= -credit);
802 //-----------------------------------------------------------------------------
803 string USER_IMPL::GetEnabledDirs()
805 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
808 for(int i = 0; i < DIR_NUM; i++)
809 dirs += enabledDirs[i] ? "1" : "0";
812 //-----------------------------------------------------------------------------
813 #ifdef TRAFF_STAT_WITH_PORTS
814 void USER_IMPL::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
816 void USER_IMPL::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
819 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
821 if (!connected || tariff == NULL)
827 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
828 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
832 int tt = tariff->GetTraffType();
833 if (tt == TRAFF_UP ||
834 tt == TRAFF_UP_DOWN ||
835 // Check NEW traff data
836 (tt == TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
839 if (traff < threshold &&
840 traff + len >= threshold)
842 // cash = partBeforeThreshold * priceBeforeThreshold +
843 // partAfterThreshold * priceAfterThreshold
844 int64_t before = threshold - traff; // Chunk part before threshold
845 int64_t after = len - before; // Chunk part after threshold
846 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
847 down.ConstData()[dir],
850 tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
851 down.ConstData()[dir],
857 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
858 down.ConstData()[dir],
863 if (freeMb.ConstData() <= 0) // FreeMb is exhausted
865 else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
866 cost = dc - freeMb.ConstData();
868 // Direct access to internal data structures via friend-specifier
869 property.Stat().freeMb -= dc;
870 property.Stat().cash -= cost;
876 sessionUpload[dir] += len;
880 if (!settings->GetWriteFreeMbTraffCost() &&
881 freeMb.ConstData() >= 0)
884 #ifdef TRAFF_STAT_WITH_PORTS
885 IP_DIR_PAIR idp(ip, dir, port);
887 IP_DIR_PAIR idp(ip, dir);
890 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
891 lb = traffStat.lower_bound(idp);
892 if (lb == traffStat.end() || lb->first != idp)
895 pair<IP_DIR_PAIR, STAT_NODE>(idp,
896 STAT_NODE(len, 0, cost)));
900 lb->second.cash += cost;
901 lb->second.up += len;
904 //-----------------------------------------------------------------------------
905 #ifdef TRAFF_STAT_WITH_PORTS
906 void USER_IMPL::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
908 void USER_IMPL::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
911 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
913 if (!connected || tariff == NULL)
919 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
920 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
924 int tt = tariff->GetTraffType();
925 if (tt == TRAFF_DOWN ||
926 tt == TRAFF_UP_DOWN ||
927 // Check NEW traff data
928 (tt == TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
931 if (traff < threshold &&
932 traff + len >= threshold)
934 // cash = partBeforeThreshold * priceBeforeThreshold +
935 // partAfterThreshold * priceAfterThreshold
936 int64_t before = threshold - traff; // Chunk part before threshold
937 int64_t after = len - before; // Chunk part after threshold
938 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
939 down.ConstData()[dir], // Traff before chunk
942 tariff->GetPriceWithTraffType(up.ConstData()[dir],
943 dt[dir], // Traff after chunk
949 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
950 down.ConstData()[dir],
955 if (freeMb.ConstData() <= 0) // FreeMb is exhausted
957 else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
958 cost = dc - freeMb.ConstData();
960 property.Stat().freeMb -= dc;
961 property.Stat().cash -= cost;
967 sessionDownload[dir] += len;
971 if (!settings->GetWriteFreeMbTraffCost() &&
972 freeMb.ConstData() >= 0)
975 #ifdef TRAFF_STAT_WITH_PORTS
976 IP_DIR_PAIR idp(ip, dir, port);
978 IP_DIR_PAIR idp(ip, dir);
981 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
982 lb = traffStat.lower_bound(idp);
983 if (lb == traffStat.end() || lb->first != idp)
986 pair<IP_DIR_PAIR, STAT_NODE>(idp,
987 STAT_NODE(0, len, cost)));
991 lb->second.cash += cost;
992 lb->second.down += len;
995 //-----------------------------------------------------------------------------
996 void USER_IMPL::AddCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
998 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
999 currIP.AddBeforeNotifier(n);
1001 //-----------------------------------------------------------------------------
1002 void USER_IMPL::DelCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
1004 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1005 currIP.DelBeforeNotifier(n);
1007 //-----------------------------------------------------------------------------
1008 void USER_IMPL::AddCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
1010 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1011 currIP.AddAfterNotifier(n);
1013 //-----------------------------------------------------------------------------
1014 void USER_IMPL::DelCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
1016 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1017 currIP.DelAfterNotifier(n);
1019 //-----------------------------------------------------------------------------
1020 void USER_IMPL::AddConnectedBeforeNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
1022 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1023 connected.AddBeforeNotifier(n);
1025 //-----------------------------------------------------------------------------
1026 void USER_IMPL::DelConnectedBeforeNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
1028 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1029 connected.DelBeforeNotifier(n);
1031 //-----------------------------------------------------------------------------
1032 void USER_IMPL::AddConnectedAfterNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
1034 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1035 connected.AddAfterNotifier(n);
1037 //-----------------------------------------------------------------------------
1038 void USER_IMPL::DelConnectedAfterNotifier(PROPERTY_NOTIFIER_BASE<bool> * n)
1040 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1041 connected.DelAfterNotifier(n);
1043 //-----------------------------------------------------------------------------
1044 void USER_IMPL::OnAdd()
1046 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1048 string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd";
1050 if (access(scriptOnAdd.c_str(), X_OK) == 0)
1052 string scriptOnAddParams;
1053 strprintf(&scriptOnAddParams,
1055 scriptOnAdd.c_str(),
1058 ScriptExec(scriptOnAddParams.c_str());
1062 WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
1065 //-----------------------------------------------------------------------------
1066 void USER_IMPL::OnDelete()
1068 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1070 string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel";
1072 if (access(scriptOnDel.c_str(), X_OK) == 0)
1074 string scriptOnDelParams;
1075 strprintf(&scriptOnDelParams,
1077 scriptOnDel.c_str(),
1080 ScriptExec(scriptOnDelParams.c_str());
1084 WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
1089 //-----------------------------------------------------------------------------
1090 int USER_IMPL::WriteDetailStat(bool hard)
1092 printfd(__FILE__, "USER::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
1094 if (!traffStatSaved.second.empty())
1096 if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
1098 printfd(__FILE__, "USER::WriteDetailStat() - failed to write detail stat from queue\n");
1099 WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
1100 WriteServLog("%s", store->GetStrError().c_str());
1103 traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
1109 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1113 printfd(__FILE__, "USER::WriteDetailedStat() - size = %d\n", ts.size());
1115 if (ts.size() && !disabledDetailStat)
1117 if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login))
1119 printfd(__FILE__, "USER::WriteDetailStat() - failed to write current detail stat\n");
1120 WriteServLog("Cannot write detail stat for user %s.", login.c_str());
1121 WriteServLog("%s", store->GetStrError().c_str());
1124 printfd(__FILE__, "USER::WriteDetailStat() - pushing detail stat to queue\n");
1125 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1126 traffStatSaved.second.swap(ts);
1127 traffStatSaved.first = lastWriteDetailedStat;
1132 lastWriteDetailedStat = stgTime;
1135 //-----------------------------------------------------------------------------
1136 double USER_IMPL::GetPassiveTimePart() const
1138 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1140 static int daysInMonth[12] =
1141 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1145 localtime_r(&t, &tms);
1147 time_t secMonth = daysInMonth[(tms.tm_mon + 11) % 12] * 24 * 3600; // Previous month
1149 if (tms.tm_year % 4 == 0 && tms.tm_mon == 1)
1152 secMonth += 24 * 3600;
1155 int dt = secMonth - passiveTime;
1160 return double(dt) / (secMonth);
1162 //-----------------------------------------------------------------------------
1163 void USER_IMPL::SetPassiveTimeAsNewUser()
1165 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1169 localtime_r(&t, &tm);
1170 int daysCurrMon = DaysInCurrentMonth();
1171 double pt = (tm.tm_mday - 1) / (double)daysCurrMon;
1173 passiveTime = (time_t)(pt * 24 * 3600 * daysCurrMon);
1175 //-----------------------------------------------------------------------------
1176 void USER_IMPL::MidnightResetSessionStat()
1178 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1182 Disconnect(true, "fake");
1186 //-----------------------------------------------------------------------------
1187 void USER_IMPL::ProcessNewMonth()
1189 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1193 Disconnect(true, "fake");
1195 DIR_TRAFF zeroTarff;
1208 if (nextTariff.ConstData() != "")
1211 nt = tariffs->FindByName(nextTariff);
1214 WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
1215 login.c_str(), property.tariffName.Get().c_str());
1219 property.tariffName.Set(nextTariff, sysAdmin, login, store);
1226 //-----------------------------------------------------------------------------
1227 void USER_IMPL::ProcessDayFeeSpread()
1229 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1231 if (passive.ConstData() || tariff == NULL)
1234 double fee = tariff->GetFee() / DaysInCurrentMonth();
1240 switch (settings->GetFeeChargeType())
1243 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1246 if (c + credit >= 0)
1247 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1250 if (c + credit >= fee)
1251 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1256 //-----------------------------------------------------------------------------
1257 void USER_IMPL::ProcessDayFee()
1259 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1264 double passiveTimePart = 1.0;
1265 if (!settings->GetFullFee())
1267 passiveTimePart = GetPassiveTimePart();
1271 if (passive.ConstData())
1273 printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1277 double fee = tariff->GetFee() * passiveTimePart;
1288 printfd(__FILE__, "login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n",
1295 switch (settings->GetFeeChargeType())
1298 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1302 if (c + credit >= 0)
1304 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1309 if (c + credit >= fee)
1311 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1317 //-----------------------------------------------------------------------------
1318 void USER_IMPL::SetPrepaidTraff()
1321 property.freeMb.Set(tariff->GetFree(), sysAdmin, login, store, "Prepaid traffic");
1323 //-----------------------------------------------------------------------------
1324 int USER_IMPL::AddMessage(STG_MSG * msg)
1326 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1328 if (SendMessage(*msg))
1330 if (store->AddMessage(msg, login))
1332 errorStr = store->GetStrError();
1333 WriteServLog("Error adding message: '%s'", errorStr.c_str());
1334 printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
1337 messages.push_back(*msg);
1341 if (msg->header.repeat > 0)
1343 msg->header.repeat--;
1345 //TODO: gcc v. 4.x generate ICE on x86_64
1346 msg->header.lastSendTime = time(NULL);
1348 msg->header.lastSendTime = stgTime;
1350 if (store->AddMessage(msg, login))
1352 errorStr = store->GetStrError();
1353 WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str());
1354 printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str());
1357 messages.push_back(*msg);
1362 //-----------------------------------------------------------------------------
1363 int USER_IMPL::SendMessage(STG_MSG & msg) const
1365 // No lock `cause we are already locked from caller
1367 set<const AUTH*>::iterator it(authorizedBy.begin());
1368 while (it != authorizedBy.end())
1370 if (!(*it++)->SendMessage(msg, currIP))
1376 //TODO: gcc v. 4.x generate ICE on x86_64
1377 msg.header.lastSendTime = time(NULL);
1379 msg.header.lastSendTime = stgTime;
1381 msg.header.repeat--;
1385 //-----------------------------------------------------------------------------
1386 void USER_IMPL::ScanMessage()
1388 // No lock `cause we are already locked from caller
1389 // We need not check for the authorizedBy `cause it has already checked by caller
1391 std::list<STG_MSG>::iterator it(messages.begin());
1392 while (it != messages.end())
1394 if (settings->GetMessageTimeout() > 0 &&
1395 difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
1398 if (store->DelMessage(it->header.id, login))
1400 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1401 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1403 messages.erase(it++);
1406 if (it->GetNextSendTime() <= stgTime)
1408 if (SendMessage(*it))
1410 // We need to check all messages in queue for timeout
1414 if (it->header.repeat < 0)
1416 if (store->DelMessage(it->header.id, login))
1418 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1419 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1421 messages.erase(it++);
1425 if (store->EditMessage(*it, login))
1427 WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
1428 printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
1439 //-----------------------------------------------------------------------------
1440 //-----------------------------------------------------------------------------
1441 //-----------------------------------------------------------------------------
1442 void CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive)
1444 if (newPassive && !oldPassive && user->tariff != NULL)
1445 user->property.cash.Set(user->cash - user->tariff->GetPassiveCost(),
1451 //-----------------------------------------------------------------------------
1452 void CHG_TARIFF_NOTIFIER::Notify(const string &, const string & newTariff)
1454 if (user->settings->GetReconnectOnTariffChange() && user->connected)
1455 user->Disconnect(false, "Change tariff");
1456 user->tariff = user->tariffs->FindByName(newTariff);
1457 if (user->settings->GetReconnectOnTariffChange() &&
1458 !user->authorizedBy.empty() &&
1460 user->Connect(false);
1462 //-----------------------------------------------------------------------------
1463 void CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash)
1465 user->lastCashAddTime = *const_cast<time_t *>(&stgTime);
1466 user->lastCashAdd = newCash - oldCash;
1468 //-----------------------------------------------------------------------------
1469 void CHG_IPS_NOTIFIER::Notify(const USER_IPS & from, const USER_IPS & to)
1471 printfd(__FILE__, "Change IP from '%s' to '%s'\n", from.GetIpStr().c_str(), to.GetIpStr().c_str());
1472 if (user->connected)
1473 user->Disconnect(false, "Change IP");
1474 if (!user->authorizedBy.empty() && user->IsInetable())
1475 user->Connect(false);
1477 //-----------------------------------------------------------------------------