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/admin.h"
54 #include <unistd.h> // access
56 #ifdef USE_ABSTRACT_SETTINGS
57 USER_IMPL::USER_IMPL(const SETTINGS * s,
64 property(s->GetScriptsDir()),
65 WriteServLog(GetStgLogger()),
69 connected(__connected),
72 lastIPForDisconnect(0),
79 authorizedModificationTime(0),
82 lastWriteDetailedStat(0),
86 lastCashAdd(property.lastCashAdd),
87 passiveTime(property.passiveTime),
88 lastCashAddTime(property.lastCashAddTime),
89 freeMb(property.freeMb),
90 lastActivityTime(property.lastActivityTime),
91 password(property.password),
92 passive(property.passive),
93 disabled(property.disabled),
94 disabledDetailStat(property.disabledDetailStat),
95 alwaysOnline(property.alwaysOnline),
96 tariffName(property.tariffName),
97 nextTariff(property.nextTariff),
98 address(property.address),
100 group(property.group),
101 email(property.email),
102 phone(property.phone),
103 realName(property.realName),
104 credit(property.credit),
105 creditExpire(property.creditExpire),
107 userdata0(property.userdata0),
108 userdata1(property.userdata1),
109 userdata2(property.userdata2),
110 userdata3(property.userdata3),
111 userdata4(property.userdata4),
112 userdata5(property.userdata5),
113 userdata6(property.userdata6),
114 userdata7(property.userdata7),
115 userdata8(property.userdata8),
116 userdata9(property.userdata9),
117 passiveNotifier(this),
118 tariffNotifier(this),
122 password = "*_EMPTY_PASSWORD_*";
123 tariffName = NO_TARIFF_NAME;
125 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
126 lastWriteDetailedStat = stgTime;
128 property.tariffName.AddBeforeNotifier(&tariffNotifier);
129 property.passive.AddBeforeNotifier(&passiveNotifier);
130 property.disabled.AddAfterNotifier(&disabledNotifier);
131 property.cash.AddBeforeNotifier(&cashNotifier);
132 ips.AddAfterNotifier(&ipNotifier);
134 pthread_mutexattr_t attr;
135 pthread_mutexattr_init(&attr);
136 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
137 pthread_mutex_init(&mutex, &attr);
140 USER_IMPL::USER_IMPL(const SETTINGS_IMPL * s,
147 property(s->GetScriptsDir()),
148 WriteServLog(GetStgLogger()),
152 connected(__connected),
155 lastIPForDisconnect(0),
162 authorizedModificationTime(0),
165 lastWriteDetailedStat(0),
169 lastCashAdd(property.lastCashAdd),
170 passiveTime(property.passiveTime),
171 lastCashAddTime(property.lastCashAddTime),
172 freeMb(property.freeMb),
173 lastActivityTime(property.lastActivityTime),
174 password(property.password),
175 passive(property.passive),
176 disabled(property.disabled),
177 disabledDetailStat(property.disabledDetailStat),
178 alwaysOnline(property.alwaysOnline),
179 tariffName(property.tariffName),
180 nextTariff(property.nextTariff),
181 address(property.address),
183 group(property.group),
184 email(property.email),
185 phone(property.phone),
186 realName(property.realName),
187 credit(property.credit),
188 creditExpire(property.creditExpire),
190 userdata0(property.userdata0),
191 userdata1(property.userdata1),
192 userdata2(property.userdata2),
193 userdata3(property.userdata3),
194 userdata4(property.userdata4),
195 userdata5(property.userdata5),
196 userdata6(property.userdata6),
197 userdata7(property.userdata7),
198 userdata8(property.userdata8),
199 userdata9(property.userdata9),
200 passiveNotifier(this),
201 disabledNotifier(this),
202 tariffNotifier(this),
206 password = "*_EMPTY_PASSWORD_*";
207 tariffName = NO_TARIFF_NAME;
209 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
210 lastWriteDetailedStat = stgTime;
212 property.tariffName.AddBeforeNotifier(&tariffNotifier);
213 property.passive.AddBeforeNotifier(&passiveNotifier);
214 property.disabled.AddAfterNotifier(&disabledNotifier);
215 property.cash.AddBeforeNotifier(&cashNotifier);
216 ips.AddAfterNotifier(&ipNotifier);
218 pthread_mutexattr_t attr;
219 pthread_mutexattr_init(&attr);
220 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
221 pthread_mutex_init(&mutex, &attr);
224 //-----------------------------------------------------------------------------
225 USER_IMPL::USER_IMPL(const USER_IMPL & u)
228 property(u.settings->GetScriptsDir()),
229 WriteServLog(GetStgLogger()),
234 connected(__connected),
235 userIDGenerator(u.userIDGenerator),
236 __currIP(u.__currIP),
238 lastIPForDisconnect(0),
239 pingTime(u.pingTime),
240 sysAdmin(u.sysAdmin),
244 traffStat(u.traffStat),
245 traffStatSaved(u.traffStatSaved),
246 settings(u.settings),
247 authorizedModificationTime(u.authorizedModificationTime),
248 messages(u.messages),
250 lastWriteStat(u.lastWriteStat),
251 lastWriteDetailedStat(u.lastWriteDetailedStat),
255 lastCashAdd(property.lastCashAdd),
256 passiveTime(property.passiveTime),
257 lastCashAddTime(property.lastCashAddTime),
258 freeMb(property.freeMb),
259 lastActivityTime(property.lastActivityTime),
260 password(property.password),
261 passive(property.passive),
262 disabled(property.disabled),
263 disabledDetailStat(property.disabledDetailStat),
264 alwaysOnline(property.alwaysOnline),
265 tariffName(property.tariffName),
266 nextTariff(property.nextTariff),
267 address(property.address),
269 group(property.group),
270 email(property.email),
271 phone(property.phone),
272 realName(property.realName),
273 credit(property.credit),
274 creditExpire(property.creditExpire),
276 userdata0(property.userdata0),
277 userdata1(property.userdata1),
278 userdata2(property.userdata2),
279 userdata3(property.userdata3),
280 userdata4(property.userdata4),
281 userdata5(property.userdata5),
282 userdata6(property.userdata6),
283 userdata7(property.userdata7),
284 userdata8(property.userdata8),
285 userdata9(property.userdata9),
288 passiveNotifier(this),
289 disabledNotifier(this),
290 tariffNotifier(this),
297 property.tariffName.AddBeforeNotifier(&tariffNotifier);
298 property.passive.AddBeforeNotifier(&passiveNotifier);
299 property.disabled.AddAfterNotifier(&disabledNotifier);
300 property.cash.AddBeforeNotifier(&cashNotifier);
301 ips.AddAfterNotifier(&ipNotifier);
303 property.SetProperties(u.property);
305 pthread_mutexattr_t attr;
306 pthread_mutexattr_init(&attr);
307 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
308 pthread_mutex_init(&mutex, &attr);
310 //-----------------------------------------------------------------------------
311 USER_IMPL::~USER_IMPL()
313 property.tariffName.DelBeforeNotifier(&tariffNotifier);
314 property.passive.DelBeforeNotifier(&passiveNotifier);
315 property.disabled.DelAfterNotifier(&disabledNotifier);
316 property.cash.DelBeforeNotifier(&cashNotifier);
317 pthread_mutex_destroy(&mutex);
319 //-----------------------------------------------------------------------------
320 void USER_IMPL::SetLogin(const std::string & l)
322 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
323 assert(login.empty() && "Login is already set");
325 id = userIDGenerator.GetNextID();
327 //-----------------------------------------------------------------------------
328 int USER_IMPL::ReadConf()
330 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
333 if (store->RestoreUserConf(&conf, login))
335 WriteServLog("Cannot read conf for user %s.", login.c_str());
336 WriteServLog("%s", store->GetStrError().c_str());
337 printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
338 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
342 property.SetConf(conf);
344 tariff = tariffs->FindByName(tariffName);
347 WriteServLog("Cannot read user %s. Tariff %s not exist.",
348 login.c_str(), property.tariffName.Get().c_str());
352 std::vector<STG_MSG_HDR> hdrsList;
354 if (store->GetMessageHdrs(&hdrsList, login))
356 printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
357 WriteServLog("Cannot read user %s. Error reading message headers: %s.",
359 store->GetStrError().c_str());
363 std::vector<STG_MSG_HDR>::const_iterator it;
364 for (it = hdrsList.begin(); it != hdrsList.end(); ++it)
367 if (store->GetMessage(it->id, &msg, login) == 0)
369 messages.push_back(msg);
375 //-----------------------------------------------------------------------------
376 int USER_IMPL::ReadStat()
378 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
381 if (store->RestoreUserStat(&stat, login))
383 WriteServLog("Cannot read stat for user %s.", login.c_str());
384 WriteServLog("%s", store->GetStrError().c_str());
385 printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
386 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
390 property.SetStat(stat);
394 //-----------------------------------------------------------------------------
395 int USER_IMPL::WriteConf()
397 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
398 USER_CONF conf(property.GetConf());
400 printfd(__FILE__, "USER::WriteConf()\n");
402 if (store->SaveUserConf(conf, login))
404 WriteServLog("Cannot write conf for user %s.", login.c_str());
405 WriteServLog("%s", store->GetStrError().c_str());
406 printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
407 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
413 //-----------------------------------------------------------------------------
414 int USER_IMPL::WriteStat()
416 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
417 USER_STAT stat(property.GetStat());
419 if (store->SaveUserStat(stat, login))
421 WriteServLog("Cannot write stat for user %s.", login.c_str());
422 WriteServLog("%s", store->GetStrError().c_str());
423 printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
424 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
428 lastWriteStat = stgTime;
432 //-----------------------------------------------------------------------------
433 int USER_IMPL::WriteMonthStat()
435 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
436 time_t tt = stgTime - 3600;
438 localtime_r(&tt, &t1);
440 USER_STAT stat(property.GetStat());
441 if (store->SaveMonthStat(stat, t1.tm_mon, t1.tm_year, login))
443 WriteServLog("Cannot write month stat for user %s.", login.c_str());
444 WriteServLog("%s", store->GetStrError().c_str());
445 printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
446 printfd(__FILE__, "%s\n", store->GetStrError().c_str());
452 //-----------------------------------------------------------------------------
453 int USER_IMPL::Authorize(uint32_t ip, uint32_t dirs, const AUTH * auth)
455 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
457 * Authorize user. It only means that user will be authorized. Nothing more.
458 * User can be connected or disconnected while authorized.
459 * Example: user is authorized but disconnected due to 0 money or blocking
463 * Prevent double authorization by identical authorizers
465 if (authorizedBy.find(auth) != authorizedBy.end())
471 for (int i = 0; i < DIR_NUM; i++)
473 enabledDirs[i] = dirs & (1 << i);
476 if (!authorizedBy.empty())
480 // We are already authorized, but with different IP address
481 errorStr = "User " + login + " already authorized with IP address " + inet_ntostring(ip);
486 if (!users->FindByIPIdx(ip, &u))
488 // Address is already present in IP-index
489 // If it's not our IP - throw an error
492 errorStr = "IP address " + inet_ntostring(ip) + " already in use";
499 if (users->IsIPInIndex(ip))
501 // Address is already present in IP-index
502 errorStr = "IP address " + inet_ntostring(ip) + " already in use";
506 if (ips.ConstData().IsIPInIPS(ip))
509 lastIPForDisconnect = currIP;
513 printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().GetIpStr().c_str());
514 errorStr = "IP address " + inet_ntostring(ip) + " not belong user " + login;
519 if (authorizedBy.empty())
520 authorizedModificationTime = stgTime;
521 authorizedBy.insert(auth);
527 //-----------------------------------------------------------------------------
528 void USER_IMPL::Unauthorize(const AUTH * auth, const std::string & reason)
530 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
532 * Authorizer tries to unauthorize user, that was not authorized by it
534 if (!authorizedBy.erase(auth))
537 if (authorizedBy.empty())
539 authorizedModificationTime = stgTime;
540 lastDisconnectReason = reason;
541 lastIPForDisconnect = currIP;
542 currIP = 0; // DelUser in traffcounter
546 //-----------------------------------------------------------------------------
547 bool USER_IMPL::IsAuthorizedBy(const AUTH * auth) const
549 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
550 // Is this user authorized by specified authorizer?
551 return authorizedBy.find(auth) != authorizedBy.end();
553 //-----------------------------------------------------------------------------
554 std::vector<std::string> USER_IMPL::GetAuthorizers() const
556 std::vector<std::string> list;
557 std::transform(authorizedBy.begin(), authorizedBy.end(), std::back_inserter(list), std::mem_fun(&AUTH::GetVersion));
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 std::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 std::string scriptOnConnectParams;
584 strprintf(&scriptOnConnectParams,
585 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
586 scriptOnConnect.c_str(),
588 inet_ntostring(currIP).c_str(),
593 std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
594 while (it != settings->GetScriptParams().end())
596 scriptOnConnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
600 ScriptExec(scriptOnConnectParams.c_str());
604 WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
610 if (store->WriteUserConnect(login, currIP))
612 WriteServLog("Cannot write connect for user %s.", login.c_str());
613 WriteServLog("%s", store->GetStrError().c_str());
617 lastIPForDisconnect = currIP;
619 //-----------------------------------------------------------------------------
620 void USER_IMPL::Disconnect(bool fakeDisconnect, const std::string & reason)
623 * Disconnect user from Internet. This function is differ from UnAuthorize() !!!
626 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
628 if (!lastIPForDisconnect)
630 printfd(__FILE__, "lastIPForDisconnect\n");
636 lastDisconnectReason = reason;
637 std::string scriptOnDisonnect = settings->GetScriptsDir() + "/OnDisconnect";
639 if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
641 char dirsStr[DIR_NUM + 1];
642 dirsStr[DIR_NUM] = 0;
643 for (int i = 0; i < DIR_NUM; i++)
645 dirsStr[i] = enabledDirs[i] ? '1' : '0';
648 std::string scriptOnDisonnectParams;
649 strprintf(&scriptOnDisonnectParams,
650 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
651 scriptOnDisonnect.c_str(),
653 inet_ntostring(lastIPForDisconnect).c_str(),
658 std::vector<std::string>::const_iterator it(settings->GetScriptParams().begin());
659 while (it != settings->GetScriptParams().end())
661 scriptOnDisonnectParams += " \"" + GetParamValue(it->c_str()) + "\"";
665 ScriptExec(scriptOnDisonnectParams.c_str());
669 WriteServLog("Script OnDisconnect cannot be executed. File not found.");
675 std::string reasonMessage(reason);
676 if (!lastDisconnectReason.empty())
677 reasonMessage += ": " + lastDisconnectReason;
679 if (store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload,
680 cash, freeMb, reasonMessage))
682 WriteServLog("Cannot write disconnect for user %s.", login.c_str());
683 WriteServLog("%s", store->GetStrError().c_str());
687 lastIPForDisconnect = 0;
689 DIR_TRAFF zeroSesssion;
691 sessionUpload = zeroSesssion;
692 sessionDownload = zeroSesssion;
694 //-----------------------------------------------------------------------------
695 void USER_IMPL::PrintUser() const
698 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
699 std::cout << "============================================================" << std::endl;
700 std::cout << "id=" << id << std::endl;
701 std::cout << "login=" << login << std::endl;
702 std::cout << "password=" << password << std::endl;
703 std::cout << "passive=" << passive << std::endl;
704 std::cout << "disabled=" << disabled << std::endl;
705 std::cout << "disabledDetailStat=" << disabledDetailStat << std::endl;
706 std::cout << "alwaysOnline=" << alwaysOnline << std::endl;
707 std::cout << "tariffName=" << tariffName << std::endl;
708 std::cout << "address=" << address << std::endl;
709 std::cout << "phone=" << phone << std::endl;
710 std::cout << "email=" << email << std::endl;
711 std::cout << "note=" << note << std::endl;
712 std::cout << "realName=" <<realName << std::endl;
713 std::cout << "group=" << group << std::endl;
714 std::cout << "credit=" << credit << std::endl;
715 std::cout << "nextTariff=" << nextTariff << std::endl;
716 std::cout << "userdata0" << userdata0 << std::endl;
717 std::cout << "userdata1" << userdata1 << std::endl;
718 std::cout << "creditExpire=" << creditExpire << std::endl;
719 std::cout << "ips=" << ips << std::endl;
720 std::cout << "------------------------" << std::endl;
721 std::cout << "up=" << up << std::endl;
722 std::cout << "down=" << down << std::endl;
723 std::cout << "cash=" << cash << std::endl;
724 std::cout << "freeMb=" << freeMb << std::endl;
725 std::cout << "lastCashAdd=" << lastCashAdd << std::endl;
726 std::cout << "lastCashAddTime=" << lastCashAddTime << std::endl;
727 std::cout << "passiveTime=" << passiveTime << std::endl;
728 std::cout << "lastActivityTime=" << lastActivityTime << std::endl;
729 std::cout << "============================================================" << std::endl;
731 //-----------------------------------------------------------------------------
732 void USER_IMPL::Run()
734 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
736 if (stgTime > static_cast<time_t>(lastWriteStat + settings->GetStatWritePeriod()))
738 printfd(__FILE__, "USER::WriteStat user=%s\n", GetLogin().c_str());
741 if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
743 WriteServLog("User: %s. Credit expired.", login.c_str());
749 if (passive.ConstData()
750 && (stgTime % 30 == 0)
751 && (passiveTime.ModificationTime() != stgTime))
753 passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
754 printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
757 if (!authorizedBy.empty())
761 property.Stat().lastActivityTime = stgTime;
763 if (!connected && IsInetable())
767 if (connected && !IsInetable())
770 Disconnect(false, "disabled");
772 Disconnect(false, "passive");
774 Disconnect(false, "no cash");
777 if (stgTime - lastScanMessages > 10)
780 lastScanMessages = stgTime;
787 Disconnect(false, "not authorized");
792 //-----------------------------------------------------------------------------
793 void USER_IMPL::UpdatePingTime(time_t t)
795 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
796 //printfd(__FILE__, "UpdatePingTime(%d) %s\n", t, login.c_str());
802 //-----------------------------------------------------------------------------
803 bool USER_IMPL::IsInetable()
805 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
807 if (disabled || passive)
810 if (settings->GetFreeMbAllowInet())
816 if (settings->GetShowFeeInCash() || tariff == NULL)
818 return (cash >= -credit);
821 return (cash - tariff->GetFee() >= -credit);
823 //-----------------------------------------------------------------------------
824 std::string USER_IMPL::GetEnabledDirs() const
826 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
828 std::string dirs = "";
829 for(int i = 0; i < DIR_NUM; i++)
830 dirs += enabledDirs[i] ? "1" : "0";
833 //-----------------------------------------------------------------------------
834 #ifdef TRAFF_STAT_WITH_PORTS
835 void USER_IMPL::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
837 void USER_IMPL::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
840 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
842 if (!connected || tariff == NULL)
848 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
849 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
853 int tt = tariff->GetTraffType();
854 if (tt == TRAFF_UP ||
855 tt == TRAFF_UP_DOWN ||
856 // Check NEW traff data
857 (tt == TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
860 if (traff < threshold &&
861 traff + len >= threshold)
863 // cash = partBeforeThreshold * priceBeforeThreshold +
864 // partAfterThreshold * priceAfterThreshold
865 int64_t before = threshold - traff; // Chunk part before threshold
866 int64_t after = len - before; // Chunk part after threshold
867 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
868 down.ConstData()[dir],
871 tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
872 down.ConstData()[dir],
878 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
879 down.ConstData()[dir],
884 if (freeMb.ConstData() <= 0) // FreeMb is exhausted
886 else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
887 cost = dc - freeMb.ConstData();
889 // Direct access to internal data structures via friend-specifier
890 property.Stat().freeMb -= dc;
891 property.Stat().cash -= cost;
897 sessionUpload[dir] += len;
901 if (!settings->GetWriteFreeMbTraffCost() &&
902 freeMb.ConstData() >= 0)
905 #ifdef TRAFF_STAT_WITH_PORTS
906 IP_DIR_PAIR idp(ip, dir, port);
908 IP_DIR_PAIR idp(ip, dir);
911 std::map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
912 lb = traffStat.lower_bound(idp);
913 if (lb == traffStat.end() || lb->first != idp)
917 STAT_NODE(len, 0, cost)));
921 lb->second.cash += cost;
922 lb->second.up += len;
925 //-----------------------------------------------------------------------------
926 #ifdef TRAFF_STAT_WITH_PORTS
927 void USER_IMPL::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
929 void USER_IMPL::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
932 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
934 if (!connected || tariff == NULL)
940 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
941 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
945 int tt = tariff->GetTraffType();
946 if (tt == TRAFF_DOWN ||
947 tt == TRAFF_UP_DOWN ||
948 // Check NEW traff data
949 (tt == TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
952 if (traff < threshold &&
953 traff + len >= threshold)
955 // cash = partBeforeThreshold * priceBeforeThreshold +
956 // partAfterThreshold * priceAfterThreshold
957 int64_t before = threshold - traff; // Chunk part before threshold
958 int64_t after = len - before; // Chunk part after threshold
959 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
960 down.ConstData()[dir], // Traff before chunk
963 tariff->GetPriceWithTraffType(up.ConstData()[dir],
964 dt[dir], // Traff after chunk
970 dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
971 down.ConstData()[dir],
976 if (freeMb.ConstData() <= 0) // FreeMb is exhausted
978 else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
979 cost = dc - freeMb.ConstData();
981 property.Stat().freeMb -= dc;
982 property.Stat().cash -= cost;
988 sessionDownload[dir] += len;
992 if (!settings->GetWriteFreeMbTraffCost() &&
993 freeMb.ConstData() >= 0)
996 #ifdef TRAFF_STAT_WITH_PORTS
997 IP_DIR_PAIR idp(ip, dir, port);
999 IP_DIR_PAIR idp(ip, dir);
1002 std::map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
1003 lb = traffStat.lower_bound(idp);
1004 if (lb == traffStat.end() || lb->first != idp)
1006 traffStat.insert(lb,
1008 STAT_NODE(0, len, cost)));
1012 lb->second.cash += cost;
1013 lb->second.down += len;
1016 //-----------------------------------------------------------------------------
1017 void USER_IMPL::AddCurrIPBeforeNotifier(CURR_IP_NOTIFIER * notifier)
1019 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1020 currIP.AddBeforeNotifier(notifier);
1022 //-----------------------------------------------------------------------------
1023 void USER_IMPL::DelCurrIPBeforeNotifier(const CURR_IP_NOTIFIER * notifier)
1025 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1026 currIP.DelBeforeNotifier(notifier);
1028 //-----------------------------------------------------------------------------
1029 void USER_IMPL::AddCurrIPAfterNotifier(CURR_IP_NOTIFIER * notifier)
1031 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1032 currIP.AddAfterNotifier(notifier);
1034 //-----------------------------------------------------------------------------
1035 void USER_IMPL::DelCurrIPAfterNotifier(const CURR_IP_NOTIFIER * notifier)
1037 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1038 currIP.DelAfterNotifier(notifier);
1040 //-----------------------------------------------------------------------------
1041 void USER_IMPL::AddConnectedBeforeNotifier(CONNECTED_NOTIFIER * notifier)
1043 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1044 connected.AddBeforeNotifier(notifier);
1046 //-----------------------------------------------------------------------------
1047 void USER_IMPL::DelConnectedBeforeNotifier(const CONNECTED_NOTIFIER * notifier)
1049 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1050 connected.DelBeforeNotifier(notifier);
1052 //-----------------------------------------------------------------------------
1053 void USER_IMPL::AddConnectedAfterNotifier(CONNECTED_NOTIFIER * notifier)
1055 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1056 connected.AddAfterNotifier(notifier);
1058 //-----------------------------------------------------------------------------
1059 void USER_IMPL::DelConnectedAfterNotifier(const CONNECTED_NOTIFIER * notifier)
1061 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1062 connected.DelAfterNotifier(notifier);
1064 //-----------------------------------------------------------------------------
1065 void USER_IMPL::OnAdd()
1067 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1069 std::string scriptOnAdd = settings->GetScriptsDir() + "/OnUserAdd";
1071 if (access(scriptOnAdd.c_str(), X_OK) == 0)
1073 std::string scriptOnAddParams;
1074 strprintf(&scriptOnAddParams,
1076 scriptOnAdd.c_str(),
1079 ScriptExec(scriptOnAddParams.c_str());
1083 WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
1086 //-----------------------------------------------------------------------------
1087 void USER_IMPL::OnDelete()
1089 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1091 std::string scriptOnDel = settings->GetScriptsDir() + "/OnUserDel";
1093 if (access(scriptOnDel.c_str(), X_OK) == 0)
1095 std::string scriptOnDelParams;
1096 strprintf(&scriptOnDelParams,
1098 scriptOnDel.c_str(),
1101 ScriptExec(scriptOnDelParams.c_str());
1105 WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
1110 //-----------------------------------------------------------------------------
1111 int USER_IMPL::WriteDetailStat(bool hard)
1113 printfd(__FILE__, "USER::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
1115 if (!traffStatSaved.second.empty())
1117 if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
1119 printfd(__FILE__, "USER::WriteDetailStat() - failed to write detail stat from queue\n");
1120 WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
1121 WriteServLog("%s", store->GetStrError().c_str());
1124 traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
1130 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1134 printfd(__FILE__, "USER::WriteDetailedStat() - size = %d\n", ts.size());
1136 if (ts.size() && !disabledDetailStat)
1138 if (store->WriteDetailedStat(ts, lastWriteDetailedStat, login))
1140 printfd(__FILE__, "USER::WriteDetailStat() - failed to write current detail stat\n");
1141 WriteServLog("Cannot write detail stat for user %s.", login.c_str());
1142 WriteServLog("%s", store->GetStrError().c_str());
1145 printfd(__FILE__, "USER::WriteDetailStat() - pushing detail stat to queue\n");
1146 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1147 traffStatSaved.second.swap(ts);
1148 traffStatSaved.first = lastWriteDetailedStat;
1153 lastWriteDetailedStat = stgTime;
1156 //-----------------------------------------------------------------------------
1157 double USER_IMPL::GetPassiveTimePart() const
1159 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1161 static int daysInMonth[12] =
1162 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1166 localtime_r(&t, &tms);
1168 time_t secMonth = daysInMonth[(tms.tm_mon + 11) % 12] * 24 * 3600; // Previous month
1170 if (tms.tm_year % 4 == 0 && tms.tm_mon == 1)
1173 secMonth += 24 * 3600;
1176 time_t dt = secMonth - passiveTime;
1181 return static_cast<double>(dt) / secMonth;
1183 //-----------------------------------------------------------------------------
1184 void USER_IMPL::SetPassiveTimeAsNewUser()
1186 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1190 localtime_r(&t, &tm);
1191 int daysCurrMon = DaysInCurrentMonth();
1192 double pt = tm.tm_mday - 1;
1195 passiveTime = static_cast<time_t>(pt * 24 * 3600 * daysCurrMon);
1197 //-----------------------------------------------------------------------------
1198 void USER_IMPL::MidnightResetSessionStat()
1200 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1204 Disconnect(true, "fake");
1208 //-----------------------------------------------------------------------------
1209 void USER_IMPL::ProcessNewMonth()
1211 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1215 Disconnect(true, "fake");
1217 DIR_TRAFF zeroTarff;
1230 if (nextTariff.ConstData() != "")
1233 nt = tariffs->FindByName(nextTariff);
1236 WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
1237 login.c_str(), property.tariffName.Get().c_str());
1241 property.tariffName.Set(nextTariff, sysAdmin, login, store);
1248 //-----------------------------------------------------------------------------
1249 void USER_IMPL::ProcessDayFeeSpread()
1251 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1253 if (passive.ConstData() || tariff == NULL)
1256 if (tariff->GetPeriod() != TARIFF::MONTH)
1259 double fee = tariff->GetFee() / DaysInCurrentMonth();
1261 if (std::fabs(fee) < 1.0e-3)
1265 switch (settings->GetFeeChargeType())
1268 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1271 if (c + credit >= 0)
1272 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1275 if (c + credit >= fee)
1276 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1280 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1285 //-----------------------------------------------------------------------------
1286 void USER_IMPL::ProcessDayFee()
1288 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1293 if (tariff->GetPeriod() != TARIFF::MONTH)
1296 double passiveTimePart = 1.0;
1297 if (!settings->GetFullFee())
1299 passiveTimePart = GetPassiveTimePart();
1303 if (passive.ConstData())
1305 printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1309 double fee = tariff->GetFee() * passiveTimePart;
1313 if (std::fabs(fee) < 1.0e-3)
1320 printfd(__FILE__, "login: %8s Cash=%f Credit=%f Fee=%f PassiveTimePart=%f fee=%f\n",
1327 switch (settings->GetFeeChargeType())
1330 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1334 if (c + credit >= 0)
1336 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1341 if (c + credit >= fee)
1343 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1350 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1356 //-----------------------------------------------------------------------------
1357 void USER_IMPL::ProcessDailyFee()
1359 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1361 if (passive.ConstData() || tariff == NULL)
1364 if (tariff->GetPeriod() != TARIFF::DAY)
1367 double fee = tariff->GetFee();
1373 switch (settings->GetFeeChargeType())
1376 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1379 if (c + credit >= 0)
1380 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1383 if (c + credit >= fee)
1384 property.cash.Set(c - fee, sysAdmin, login, store, "Subscriber fee charge");
1389 //-----------------------------------------------------------------------------
1390 void USER_IMPL::SetPrepaidTraff()
1393 property.freeMb.Set(tariff->GetFree(), sysAdmin, login, store, "Prepaid traffic");
1395 //-----------------------------------------------------------------------------
1396 int USER_IMPL::AddMessage(STG_MSG * msg)
1398 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1400 if (SendMessage(*msg))
1402 if (store->AddMessage(msg, login))
1404 errorStr = store->GetStrError();
1405 WriteServLog("Error adding message: '%s'", errorStr.c_str());
1406 printfd(__FILE__, "Error adding message: '%s'\n", errorStr.c_str());
1409 messages.push_back(*msg);
1413 if (msg->header.repeat > 0)
1415 msg->header.repeat--;
1417 //TODO: gcc v. 4.x generate ICE on x86_64
1418 msg->header.lastSendTime = static_cast<int>(time(NULL));
1420 msg->header.lastSendTime = static_cast<int>(stgTime);
1422 if (store->AddMessage(msg, login))
1424 errorStr = store->GetStrError();
1425 WriteServLog("Error adding repeatable message: '%s'", errorStr.c_str());
1426 printfd(__FILE__, "Error adding repeatable message: '%s'\n", errorStr.c_str());
1429 messages.push_back(*msg);
1434 //-----------------------------------------------------------------------------
1435 int USER_IMPL::SendMessage(STG_MSG & msg) const
1437 // No lock `cause we are already locked from caller
1439 std::set<const AUTH*>::iterator it(authorizedBy.begin());
1440 while (it != authorizedBy.end())
1442 if (!(*it++)->SendMessage(msg, currIP))
1448 //TODO: gcc v. 4.x generate ICE on x86_64
1449 msg.header.lastSendTime = static_cast<int>(time(NULL));
1451 msg.header.lastSendTime = static_cast<int>(stgTime);
1453 msg.header.repeat--;
1457 //-----------------------------------------------------------------------------
1458 void USER_IMPL::ScanMessage()
1460 // No lock `cause we are already locked from caller
1461 // We need not check for the authorizedBy `cause it has already checked by caller
1463 std::list<STG_MSG>::iterator it(messages.begin());
1464 while (it != messages.end())
1466 if (settings->GetMessageTimeout() > 0 &&
1467 difftime(stgTime, it->header.creationTime) > settings->GetMessageTimeout())
1470 if (store->DelMessage(it->header.id, login))
1472 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1473 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1475 messages.erase(it++);
1478 if (it->GetNextSendTime() <= stgTime)
1480 if (SendMessage(*it))
1482 // We need to check all messages in queue for timeout
1486 if (it->header.repeat < 0)
1488 if (store->DelMessage(it->header.id, login))
1490 WriteServLog("Error deleting message: '%s'", store->GetStrError().c_str());
1491 printfd(__FILE__, "Error deleting message: '%s'\n", store->GetStrError().c_str());
1493 messages.erase(it++);
1497 if (store->EditMessage(*it, login))
1499 WriteServLog("Error modifying message: '%s'", store->GetStrError().c_str());
1500 printfd(__FILE__, "Error modifying message: '%s'\n", store->GetStrError().c_str());
1511 //-----------------------------------------------------------------------------
1512 std::string USER_IMPL::GetParamValue(const std::string & name) const
1514 std::string lowerName = ToLower(name);
1515 if (lowerName == "id")
1517 std::ostringstream stream;
1519 return stream.str();
1521 if (lowerName == "login") return login;
1522 if (lowerName == "currip") return currIP.ToString();
1523 if (lowerName == "enableddirs") return GetEnabledDirs();
1524 if (lowerName == "tariff") return property.tariffName;
1525 if (property.Exists(lowerName))
1526 return property.GetPropertyValue(lowerName);
1529 WriteServLog("User’s parameter '%s' does not exist.", name.c_str());
1533 //-----------------------------------------------------------------------------
1534 //-----------------------------------------------------------------------------
1535 //-----------------------------------------------------------------------------
1536 void CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive)
1538 if (newPassive && !oldPassive && user->tariff != NULL)
1539 user->property.cash.Set(user->cash - user->tariff->GetPassiveCost(),
1545 //-----------------------------------------------------------------------------
1546 void CHG_DISABLED_NOTIFIER::Notify(const int & oldValue, const int & newValue)
1548 if (oldValue && !newValue && user->GetConnected())
1550 user->Disconnect(false, "disabled");
1552 else if (!oldValue && newValue && user->IsInetable())
1554 user->Connect(false);
1558 //-----------------------------------------------------------------------------
1559 void CHG_TARIFF_NOTIFIER::Notify(const std::string &, const std::string & newTariff)
1561 if (user->settings->GetReconnectOnTariffChange() && user->connected)
1562 user->Disconnect(false, "Change tariff");
1563 user->tariff = user->tariffs->FindByName(newTariff);
1564 if (user->settings->GetReconnectOnTariffChange() &&
1565 !user->authorizedBy.empty() &&
1567 user->Connect(false);
1569 //-----------------------------------------------------------------------------
1570 void CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash)
1572 user->lastCashAddTime = *const_cast<time_t *>(&stgTime);
1573 user->lastCashAdd = newCash - oldCash;
1575 //-----------------------------------------------------------------------------
1576 void CHG_IPS_NOTIFIER::Notify(const USER_IPS & from, const USER_IPS & to)
1578 printfd(__FILE__, "Change IP from '%s' to '%s'\n", from.GetIpStr().c_str(), to.GetIpStr().c_str());
1579 if (user->connected)
1580 user->Disconnect(false, "Change IP");
1581 if (!user->authorizedBy.empty() && user->IsInetable())
1582 user->Connect(false);
1584 //-----------------------------------------------------------------------------