]> git.stg.codes - stg.git/blob - projects/stargazer/user.cpp
Змімено спосіб зберігання TRAFF_STATS після невдалого запису
[stg.git] / projects / stargazer / user.cpp
1 /*
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.
6  *
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.
11  *
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
15  */
16
17 /*
18  *    Date: 27.10.2002
19  */
20
21 /*
22  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
23  */
24
25 /*
26  $Revision: 1.101 $
27  $Date: 2010/11/03 10:50:03 $
28  $Author: faust $
29  */
30
31 #ifndef _GNU_SOURCE
32 #define _GNU_SOURCE
33 #endif
34
35 #include <pthread.h>
36 #include <unistd.h> // access
37
38 #include <cassert>
39
40 #include "user.h"
41 #include "common.h"
42 #include "settings.h"
43 #include "script_executer.h"
44 #include "tariff.h"
45 #include "tariffs.h"
46 #include "admin.h"
47
48 USER::USER(const SETTINGS * s,
49            const BASE_STORE * st,
50            const TARIFFS * t,
51            const ADMIN & a,
52            const map<uint32_t, user_iter> * ipIdx)
53     : property(s),
54       WriteServLog(GetStgLogger()),
55       login(),
56       id(0),
57       __connected(0),
58       connected(__connected),
59       userIDGenerator(),
60       __currIP(0),
61       currIP(__currIP),
62       lastIPForDisconnect(0),
63       pingTime(0),
64       sysAdmin(a),
65       store(st),
66       tariffs(t),
67       tariff(tariffs->GetNoTariff()),
68       cash(property.cash),
69       up(property.up),
70       down(property.down),
71       lastCashAdd(property.lastCashAdd),
72       passiveTime(property.passiveTime),
73       lastCashAddTime(property.lastCashAddTime),
74       freeMb(property.freeMb),
75       lastActivityTime(property.lastActivityTime),
76       password(property.password),
77       passive(property.passive),
78       disabled(property.disabled),
79       disabledDetailStat(property.disabledDetailStat),
80       alwaysOnline(property.alwaysOnline),
81       tariffName(property.tariffName),
82       nextTariff(property.nextTariff),
83       address(property.address),
84       note(property.note),
85       group(property.group),
86       email(property.email),
87       phone(property.phone),
88       realName(property.realName),
89       credit(property.credit),
90       creditExpire(property.creditExpire),
91       ips(property.ips),
92       userdata0(property.userdata0),
93       userdata1(property.userdata1),
94       userdata2(property.userdata2),
95       userdata3(property.userdata3),
96       userdata4(property.userdata4),
97       userdata5(property.userdata5),
98       userdata6(property.userdata6),
99       userdata7(property.userdata7),
100       userdata8(property.userdata8),
101       userdata9(property.userdata9),
102       passiveNotifier(this),
103       tariffNotifier(this),
104       cashNotifier(this),
105       ipNotifier(this)
106 {
107 settings = s;
108 ipIndex = ipIdx;
109
110 password = "*_EMPTY_PASSWORD_*";
111 tariffName = NO_TARIFF_NAME;
112 connected = 0;
113 tariff = tariffs->GetNoTariff();
114 ips = StrToIPS("*");
115 deleted = false;
116 lastWriteStat = stgTime + random() % settings->GetStatWritePeriod();
117 lastWriteDeatiledStat = stgTime;
118 lastSwapDeatiledStat = stgTime;
119
120 property.tariffName.AddBeforeNotifier(&tariffNotifier);
121 property.passive.AddBeforeNotifier(&passiveNotifier);
122 property.cash.AddBeforeNotifier(&cashNotifier);
123 currIP.AddAfterNotifier(&ipNotifier);
124
125 lastScanMessages = 0;
126
127 writeFreeMbTraffCost = settings->GetWriteFreeMbTraffCost();
128
129 pthread_mutexattr_t attr;
130 pthread_mutexattr_init(&attr);
131 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
132 pthread_mutex_init(&mutex, &attr);
133 }
134 //-----------------------------------------------------------------------------
135 USER::USER(const USER & u)
136     : property(u.settings),
137       WriteServLog(GetStgLogger()),
138       login(u.login),
139       id(u.id),
140       __connected(u.__connected),
141       connected(__connected),
142       __currIP(u.__currIP),
143       currIP(__currIP),
144       lastIPForDisconnect(0),
145       pingTime(u.pingTime),
146       sysAdmin(u.sysAdmin),
147       store(u.store),
148       tariffs(u.tariffs),
149       tariff(u.tariff),
150       cash(property.cash),
151       up(property.up),
152       down(property.down),
153       lastCashAdd(property.lastCashAdd),
154       passiveTime(property.passiveTime),
155       lastCashAddTime(property.lastCashAddTime),
156       freeMb(property.freeMb),
157       lastActivityTime(property.lastActivityTime),
158       password(property.password),
159       passive(property.passive),
160       disabled(property.disabled),
161       disabledDetailStat(property.disabledDetailStat),
162       alwaysOnline(property.alwaysOnline),
163       tariffName(property.tariffName),
164       nextTariff(property.nextTariff),
165       address(property.address),
166       note(property.note),
167       group(property.group),
168       email(property.email),
169       phone(property.phone),
170       realName(property.realName),
171       credit(property.credit),
172       creditExpire(property.creditExpire),
173       ips(property.ips),
174       userdata0(property.userdata0),
175       userdata1(property.userdata1),
176       userdata2(property.userdata2),
177       userdata3(property.userdata3),
178       userdata4(property.userdata4),
179       userdata5(property.userdata5),
180       userdata6(property.userdata6),
181       userdata7(property.userdata7),
182       userdata8(property.userdata8),
183       userdata9(property.userdata9),
184       passiveNotifier(this),
185       tariffNotifier(this),
186       cashNotifier(this),
187       ipNotifier(this)
188 {
189 if (&u == this)
190     return;
191
192 connected = 0;
193
194 ipIndex = u.ipIndex;
195
196 deleted = u.deleted;
197
198 lastWriteStat = u.lastWriteStat;
199 lastWriteDeatiledStat = u.lastWriteDeatiledStat;
200 lastSwapDeatiledStat = u.lastSwapDeatiledStat;
201
202 settings = u.settings;
203
204 property.tariffName.AddBeforeNotifier(&tariffNotifier);
205 property.passive.AddBeforeNotifier(&passiveNotifier);
206 property.cash.AddBeforeNotifier(&cashNotifier);
207 currIP.AddAfterNotifier(&ipNotifier);
208
209 lastScanMessages = 0;
210
211 writeFreeMbTraffCost = settings->GetWriteFreeMbTraffCost();
212
213 property.SetProperties(u.property);
214
215 pthread_mutexattr_t attr;
216 pthread_mutexattr_init(&attr);
217 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
218 pthread_mutex_init(&mutex, &attr);
219 }
220 //-----------------------------------------------------------------------------
221 USER::~USER()
222 {
223 property.passive.DelBeforeNotifier(&passiveNotifier);
224 property.tariffName.DelBeforeNotifier(&tariffNotifier);
225 pthread_mutex_destroy(&mutex);
226 }
227 //-----------------------------------------------------------------------------
228 void USER::SetLogin(string const & l)
229 {
230 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
231 assert(login.empty() && "Login is already set");
232 login = l;
233 id = userIDGenerator.GetNextID();
234 }
235 //-----------------------------------------------------------------------------
236 int USER::ReadConf()
237 {
238 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
239 USER_CONF conf;
240
241 if (store->RestoreUserConf(&conf, login))
242     {
243     WriteServLog("Cannot read conf for user %s.", login.c_str());
244     WriteServLog("%s", store->GetStrError().c_str());
245     printfd(__FILE__, "Cannot read conf for user %s.\n", login.c_str());
246     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
247     return -1;
248     }
249
250 property.SetConf(conf);
251
252 tariff = tariffs->FindByName(tariffName);
253 if (tariff == NULL)
254     {
255     WriteServLog("Cannot read user %s. Tariff %s not exist.",
256                  login.c_str(), property.tariffName.Get().c_str());
257     return -1;
258     }
259
260 return 0;
261 }
262 //-----------------------------------------------------------------------------
263 int USER::ReadStat()
264 {
265 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
266 USER_STAT stat;
267
268 if (store->RestoreUserStat(&stat, login))
269     {
270     WriteServLog("Cannot read stat for user %s.", login.c_str());
271     WriteServLog("%s", store->GetStrError().c_str());
272     printfd(__FILE__, "Cannot read stat for user %s.\n", login.c_str());
273     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
274     return -1;
275     }
276
277 property.SetStat(stat);
278
279 return 0;
280 }
281 //-----------------------------------------------------------------------------
282 int USER::WriteConf()
283 {
284 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
285 USER_CONF conf(property.GetConf());
286
287 printfd(__FILE__, "USER::WriteConf()\n");
288
289 if (store->SaveUserConf(conf, login))
290     {
291     WriteServLog("Cannot write conf for user %s.", login.c_str());
292     WriteServLog("%s", store->GetStrError().c_str());
293     printfd(__FILE__, "Cannot write conf for user %s.\n", login.c_str());
294     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
295     return -1;
296     }
297
298 return 0;
299 }
300 //-----------------------------------------------------------------------------
301 int USER::WriteStat()
302 {
303 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
304 USER_STAT stat(property.GetStat());
305
306 printfd(__FILE__, "USER::WriteStat()\n");
307
308 if (store->SaveUserStat(stat, login))
309     {
310     WriteServLog("Cannot write stat for user %s.", login.c_str());
311     WriteServLog("%s", store->GetStrError().c_str());
312     printfd(__FILE__, "Cannot write stat for user %s.\n", login.c_str());
313     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
314     return -1;
315     }
316
317 lastWriteStat = stgTime;
318
319 return 0;
320 }
321 //-----------------------------------------------------------------------------
322 int USER::WriteMonthStat()
323 {
324 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
325 time_t tt = stgTime - 3600;
326 struct tm * t1 = localtime(&tt);
327
328 USER_STAT stat(property.GetStat());
329 if (store->SaveMonthStat(stat, t1->tm_mon, t1->tm_year, login))
330     {
331     WriteServLog("Cannot write month stat for user %s.", login.c_str());
332     WriteServLog("%s", store->GetStrError().c_str());
333     printfd(__FILE__, "Cannot write month stat for user %s.\n", login.c_str());
334     printfd(__FILE__, "%s\n", store->GetStrError().c_str());
335     return -1;
336     }
337
338 return 0;
339 }
340 //-----------------------------------------------------------------------------
341 int USER::Authorize(uint32_t ip, const string &, uint32_t dirs, const BASE_AUTH * auth)
342 {
343 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
344 /*
345  *  Authorize user. It only means that user will be authorized. Nothing more.
346  *  User can be connected or disconnected while authorized.
347  *  Example: user is authorized but disconnected due to 0 money or blocking
348  */
349
350 /*
351  * Prevent double authorization by identical authorizers
352  */
353 if (authorizedBy.find(auth) != authorizedBy.end())
354     return 0;
355
356 if (!ip)
357     return -1;
358
359 for (int i = 0; i < DIR_NUM; i++)
360     {
361     enabledDirs[i] = dirs & (1 << i);
362     }
363
364 if (authorizedBy.size())
365     {
366     if (currIP != ip)
367         {
368         //  We are already authorized, but with different IP address
369         errorStr = "User " + login + " alredy authorized with IP address " + inet_ntostring(ip);
370         return -1;
371         }
372
373     map<uint32_t, user_iter>::const_iterator ci = ipIndex->find(ip);
374     if (ci != ipIndex->end())
375         {
376         //  Address is already present in IP-index
377         //  If it's not our IP - throw an error
378         if (&(*ci->second) != this)
379             {
380             errorStr = "IP address " + inet_ntostring(ip) + " alredy in use";
381             return -1;
382             }
383         }
384     }
385 else
386     {
387     if (ipIndex->find(ip) != ipIndex->end())
388         {
389         //  Address is already present in IP-index
390         errorStr = "IP address " + inet_ntostring(ip) + " alredy in use";
391         return -1;
392         }
393
394     if (ips.ConstData().IsIPInIPS(ip))
395         {
396         currIP = ip;
397         lastIPForDisconnect = currIP;
398         }
399     else
400         {
401         printfd(__FILE__, " user %s: ips = %s\n", login.c_str(), ips.ConstData().GetIpStr().c_str());
402         errorStr = "IP address " + inet_ntostring(ip) + " not belong user " + login;
403         return -1;
404         }
405     }
406
407 authorizedBy.insert(auth);
408
409 ScanMessage();
410
411 return 0;
412 }
413 //-----------------------------------------------------------------------------
414 void USER::Unauthorize(const BASE_AUTH * auth)
415 {
416 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
417 /*
418  *  Authorizer tries to unauthorize user, that was not authorized by it
419  */
420 if (!authorizedBy.erase(auth))
421     return;
422
423 if (authorizedBy.empty())
424     {
425     lastIPForDisconnect = currIP;
426     currIP = 0; // DelUser in traffcounter
427     return;
428     }
429 }
430 //-----------------------------------------------------------------------------
431 bool USER::IsAuthorizedBy(const BASE_AUTH * auth) const
432 {
433 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
434 //  Is this user authorized by specified authorizer?
435 return authorizedBy.find(auth) != authorizedBy.end();
436 }
437 //-----------------------------------------------------------------------------
438 void USER::Connect(bool fakeConnect)
439 {
440 /*
441  *  Connect user to Internet. This function is differ from Authorize() !!!
442  */
443
444 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
445
446 if (!fakeConnect)
447     {
448     string scriptOnConnect = settings->GetScriptDir() + "/OnConnect";
449
450     if (access(scriptOnConnect.c_str(), X_OK) == 0)
451         {
452         char dirsStr[DIR_NUM + 1];
453         dirsStr[DIR_NUM] = 0;
454         for (int i = 0; i < DIR_NUM; i++)
455             {
456             dirsStr[i] = enabledDirs[i] ? '1' : '0';
457             }
458
459         string scriptOnConnectParams;
460         strprintf(&scriptOnConnectParams,
461                 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
462                 scriptOnConnect.c_str(),
463                 login.c_str(),
464                 inet_ntostring(currIP).c_str(),
465                 (double)cash,
466                 id,
467                 dirsStr);
468
469         ScriptExec(scriptOnConnectParams);
470         }
471     else
472         {
473         WriteServLog("Script %s cannot be executed. File not found.", scriptOnConnect.c_str());
474         }
475
476     connected = true;
477     }
478
479 if (store->WriteUserConnect(login, currIP))
480     {
481     WriteServLog("Cannot write connect for user %s.", login.c_str());
482     WriteServLog("%s", store->GetStrError().c_str());
483     }
484
485 if (!fakeConnect)
486     lastIPForDisconnect = currIP;
487 }
488 //-----------------------------------------------------------------------------
489 void USER::Disconnect(bool fakeDisconnect, const std::string & reason)
490 {
491 /*
492  *  Disconnect user from Internet. This function is differ from UnAuthorize() !!!
493  */
494
495 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
496
497 if (!lastIPForDisconnect)
498     {
499     printfd(__FILE__, "lastIPForDisconnect\n");
500     return;
501     }
502
503 if (!fakeDisconnect)
504     {
505     string scriptOnDisonnect = settings->GetScriptDir() + "/OnDisconnect";
506
507     if (access(scriptOnDisonnect.c_str(), X_OK) == 0)
508         {
509         char dirsStr[DIR_NUM + 1];
510         dirsStr[DIR_NUM] = 0;
511         for (int i = 0; i < DIR_NUM; i++)
512             {
513             dirsStr[i] = enabledDirs[i] ? '1' : '0';
514             }
515
516         string scriptOnDisonnectParams;
517         strprintf(&scriptOnDisonnectParams,
518                 "%s \"%s\" \"%s\" \"%f\" \"%d\" \"%s\"",
519                 scriptOnDisonnect.c_str(),
520                 login.c_str(),
521                 inet_ntostring(lastIPForDisconnect).c_str(),
522                 (double)cash,
523                 id,
524                 dirsStr);
525
526         ScriptExec(scriptOnDisonnectParams);
527         }
528     else
529         {
530         WriteServLog("Script OnDisconnect cannot be executed. File not found.");
531         }
532
533     connected = false;
534     }
535
536 if (store->WriteUserDisconnect(login, up, down, sessionUpload, sessionDownload, cash, freeMb, reason))
537     {
538     WriteServLog("Cannot write disconnect for user %s.", login.c_str());
539     WriteServLog("%s", store->GetStrError().c_str());
540     }
541
542 if (!fakeDisconnect)
543     lastIPForDisconnect = 0;
544
545 DIR_TRAFF zeroSesssion;
546
547 sessionUpload = zeroSesssion;
548 sessionDownload = zeroSesssion;
549 }
550 //-----------------------------------------------------------------------------
551 void USER::PrintUser() const
552 {
553 //return;
554 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
555 cout << "============================================================" << endl;
556 cout << "id=" << id << endl;
557 cout << "login=" << login << endl;
558 cout << "password=" << password << endl;
559 cout << "passive=" << passive << endl;
560 cout << "disabled=" << disabled << endl;
561 cout << "disabledDetailStat=" << disabledDetailStat << endl;
562 cout << "alwaysOnline=" << alwaysOnline << endl;
563 cout << "tariffName=" << tariffName << endl;
564 cout << "address=" << address << endl;
565 cout << "phone=" << phone << endl;
566 cout << "email=" << email << endl;
567 cout << "note=" << note << endl;
568 cout << "realName=" <<realName << endl;
569 cout << "group=" << group << endl;
570 cout << "credit=" << credit << endl;
571 cout << "nextTariff=" << nextTariff << endl;
572 cout << "userdata0" << userdata0 << endl;
573 cout << "userdata1" << userdata1 << endl;
574 cout << "creditExpire=" << creditExpire << endl;
575 cout << "ips=" << ips << endl;
576 cout << "------------------------" << endl;
577 cout << "up=" << up << endl;
578 cout << "down=" << down << endl;
579 cout << "cash=" << cash << endl;
580 cout << "freeMb=" << freeMb << endl;
581 cout << "lastCashAdd=" << lastCashAdd << endl;
582 cout << "lastCashAddTime=" << lastCashAddTime << endl;
583 cout << "passiveTime=" << passiveTime << endl;
584 cout << "lastActivityTime=" << lastActivityTime << endl;
585 cout << "============================================================" << endl;
586 }
587 //-----------------------------------------------------------------------------
588 void USER::Run()
589 {
590 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
591
592 if (stgTime - lastWriteStat > settings->GetStatWritePeriod())
593     {
594     printfd(__FILE__, "USER::WriteStat user=%s\n", GetLogin().c_str());
595     WriteStat();
596     }
597 if (creditExpire.ConstData() && creditExpire.ConstData() < stgTime)
598     {
599     WriteServLog("User: %s. Credit expired.", login.c_str());
600     credit = 0;
601     creditExpire = 0;
602     WriteConf();
603     }
604
605 if (passive.ConstData()
606     && (stgTime % 30 == 0)
607     && (passiveTime.ModificationTime() != stgTime))
608     {
609     passiveTime = passiveTime + (stgTime - passiveTime.ModificationTime());
610     printfd(__FILE__, "===== %s: passiveTime=%d =====\n", login.c_str(), passiveTime.ConstData());
611     }
612
613 if (!authorizedBy.empty())
614     {
615     if (connected)
616         {
617         lastActivityTime = *const_cast<time_t *>(&stgTime);
618         }
619     if (!connected && IsInetable())
620         {
621         Connect();
622         }
623     if (connected && !IsInetable())
624         {
625         if (disabled)
626             Disconnect(false, "disabled");
627         else if (passive)
628             Disconnect(false, "passive");
629         else
630             Disconnect(false, "no cash");
631         }
632
633     if (stgTime - lastScanMessages > 10)
634         {
635         ScanMessage();
636         lastScanMessages = stgTime;
637         }
638     }
639 else
640     {
641     if (connected)
642         {
643         Disconnect(false, "not authorized");
644         }
645     }
646
647 }
648 //-----------------------------------------------------------------------------
649 void USER::UpdatePingTime(time_t t)
650 {
651 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
652 //printfd(__FILE__, "UpdatePingTime(%d) %s\n", t, login.c_str());
653 if (t)
654     pingTime = t;
655 else
656     pingTime = stgTime;
657 }
658 //-----------------------------------------------------------------------------
659 bool USER::IsInetable()
660 {
661 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
662
663 if (disabled || passive)
664     return false;
665
666 if (settings->GetFreeMbAllowInet())
667     {
668     if (freeMb >= 0)
669         return true;
670     }
671
672 if (settings->GetShowFeeInCash())
673     {
674     return (cash >= -credit);
675     }
676
677 return (cash - tariff->GetFee() >= -credit);
678 }
679 //-----------------------------------------------------------------------------
680 string USER::GetEnabledDirs()
681 {
682 //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
683
684 string dirs = "";
685 for(int i = 0; i < DIR_NUM; i++)
686     dirs += enabledDirs[i] ? "1" : "0";
687 return dirs;
688 }
689 //-----------------------------------------------------------------------------
690 #ifdef TRAFF_STAT_WITH_PORTS
691 void USER::AddTraffStatU(int dir, uint32_t ip, uint16_t port, uint32_t len)
692 #else
693 void USER::AddTraffStatU(int dir, uint32_t ip, uint32_t len)
694 #endif
695 {
696 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
697
698 if (!connected)
699     return;
700
701 double cost = 0;
702 DIR_TRAFF dt(up);
703
704 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
705 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
706
707 dt[dir] += len;
708
709 int tt = tariff->GetTraffType();
710 if (tt == TRAFF_UP ||
711     tt == TRAFF_UP_DOWN ||
712     // Check NEW traff data
713     (tt == TRAFF_MAX && dt[dir] > down.ConstData()[dir]))
714     {
715     double dc = 0;
716     if (traff < threshold &&
717         traff + len >= threshold)
718         {
719         // cash = partBeforeThreshold * priceBeforeThreshold +
720         //        partAfterThreshold * priceAfterThreshold
721         int64_t before = threshold - traff; // Chunk part before threshold
722         int64_t after = len - before; // Chunk part after threshold
723         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir], // Traff before chunk
724                                            down.ConstData()[dir],
725                                            dir,
726                                            stgTime) * before +
727              tariff->GetPriceWithTraffType(dt[dir], // Traff after chunk
728                                            down.ConstData()[dir],
729                                            dir,
730                                            stgTime) * after;
731         }
732     else
733         {
734         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
735                                            down.ConstData()[dir],
736                                            dir,
737                                            stgTime) * len;
738         }
739
740     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
741         cost = dc;
742     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
743         cost = dc - freeMb.ConstData();
744
745     // Direct access to internal data structures via friend-specifier
746     property.stat.freeMb -= dc;
747     property.stat.cash -= cost;
748     cash.ModifyTime();
749     freeMb.ModifyTime();
750     }
751
752 up = dt;
753 sessionUpload[dir] += len;
754
755 //Add detailed stat
756
757 if (!writeFreeMbTraffCost && freeMb.ConstData() >= 0)
758     cost = 0;
759
760 #ifdef TRAFF_STAT_WITH_PORTS
761 IP_DIR_PAIR idp(ip, dir, port);
762 #else
763 IP_DIR_PAIR idp(ip, dir);
764 #endif
765
766 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
767 lb = traffStat.lower_bound(idp);
768 if (lb == traffStat.end() || lb->first != idp)
769     {
770     traffStat.insert(lb,
771                      pair<IP_DIR_PAIR, STAT_NODE>(idp,
772                                                   STAT_NODE(len, 0, cost)));
773     }
774 else
775     {
776     lb->second.cash += cost;
777     lb->second.up += len;
778     }
779 }
780 //-----------------------------------------------------------------------------
781 #ifdef TRAFF_STAT_WITH_PORTS
782 void USER::AddTraffStatD(int dir, uint32_t ip, uint16_t port, uint32_t len)
783 #else
784 void USER::AddTraffStatD(int dir, uint32_t ip, uint32_t len)
785 #endif
786 {
787 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
788
789 if (!connected)
790     return;
791
792 double cost = 0;
793 DIR_TRAFF dt(down);
794
795 int64_t traff = tariff->GetTraffByType(up.ConstData()[dir], down.ConstData()[dir]);
796 int64_t threshold = tariff->GetThreshold(dir) * 1024 * 1024;
797
798 dt[dir] += len;
799
800 int tt = tariff->GetTraffType();
801 if (tt == TRAFF_DOWN ||
802     tt == TRAFF_UP_DOWN ||
803     // Check NEW traff data
804     (tt == TRAFF_MAX && up.ConstData()[dir] <= dt[dir]))
805     {
806     double dc = 0;
807     if (traff < threshold &&
808         traff + len >= threshold)
809         {
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
816                                            dir,
817                                            stgTime) * before +
818              tariff->GetPriceWithTraffType(up.ConstData()[dir],
819                                            dt[dir], // Traff after chunk
820                                            dir,
821                                            stgTime) * after;
822         }
823     else
824         {
825         dc = tariff->GetPriceWithTraffType(up.ConstData()[dir],
826                                            down.ConstData()[dir],
827                                            dir,
828                                            stgTime) * len;
829         }
830
831     if (freeMb.ConstData() <= 0) // FreeMb is exhausted
832         cost = dc;
833     else if (freeMb.ConstData() < dc) // FreeMb is partially exhausted
834         cost = dc - freeMb.ConstData();
835
836     property.stat.freeMb -= dc;
837     property.stat.cash -= cost;
838     cash.ModifyTime();
839     freeMb.ModifyTime();
840     }
841
842 down = dt;
843 sessionDownload[dir] += len;
844
845 //Add detailed stat
846
847 if (!writeFreeMbTraffCost && freeMb.ConstData() >= 0)
848     cost = 0;
849
850 #ifdef TRAFF_STAT_WITH_PORTS
851 IP_DIR_PAIR idp(ip, dir, port);
852 #else
853 IP_DIR_PAIR idp(ip, dir);
854 #endif
855
856 map<IP_DIR_PAIR, STAT_NODE>::iterator lb;
857 lb = traffStat.lower_bound(idp);
858 if (lb == traffStat.end() || lb->first != idp)
859     {
860     traffStat.insert(lb,
861                      pair<IP_DIR_PAIR, STAT_NODE>(idp,
862                                                   STAT_NODE(0, len, cost)));
863     }
864 else
865     {
866     lb->second.cash += cost;
867     lb->second.down += len;
868     }
869 }
870 //-----------------------------------------------------------------------------
871 void USER::AddCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
872 {
873 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
874 currIP.AddBeforeNotifier(n);
875 }
876 //-----------------------------------------------------------------------------
877 void USER::DelCurrIPBeforeNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
878 {
879 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
880 currIP.DelBeforeNotifier(n);
881 }
882 //-----------------------------------------------------------------------------
883 void USER::AddCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
884 {
885 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
886 currIP.AddAfterNotifier(n);
887 }
888 //-----------------------------------------------------------------------------
889 void USER::DelCurrIPAfterNotifier(PROPERTY_NOTIFIER_BASE<uint32_t> * n)
890 {
891 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
892 currIP.DelAfterNotifier(n);
893 }
894 //-----------------------------------------------------------------------------
895 void USER::OnAdd()
896 {
897 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
898
899 string scriptOnAdd = settings->GetScriptDir() + "/OnUserAdd";
900
901 if (access(scriptOnAdd.c_str(), X_OK) == 0)
902     {
903     string scriptOnAddParams;
904     strprintf(&scriptOnAddParams,
905             "%s \"%s\"",
906             scriptOnAdd.c_str(),
907             login.c_str());
908
909     ScriptExec(scriptOnAddParams);
910     }
911 else
912     {
913     WriteServLog("Script %s cannot be executed. File not found.", scriptOnAdd.c_str());
914     }
915 }
916 //-----------------------------------------------------------------------------
917 void USER::OnDelete()
918 {
919 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
920
921 string scriptOnDel = settings->GetScriptDir() + "/OnUserDel";
922
923 if (access(scriptOnDel.c_str(), X_OK) == 0)
924     {
925     string scriptOnDelParams;
926     strprintf(&scriptOnDelParams,
927             "%s \"%s\"",
928             scriptOnDel.c_str(),
929             login.c_str());
930
931     ScriptExec(scriptOnDelParams);
932     }
933 else
934     {
935     WriteServLog("Script %s cannot be executed. File not found.", scriptOnDel.c_str());
936     }
937
938 Run();
939 }
940 //-----------------------------------------------------------------------------
941 int USER::WriteDetailStat(bool hard)
942 {
943 printfd(__FILE__, "USER::WriteDetailedStat() - saved size = %d\n", traffStatSaved.second.size());
944
945 if (!traffStatSaved.second.empty())
946     {
947     if (store->WriteDetailedStat(traffStatSaved.second, traffStatSaved.first, login))
948         {
949         printfd(__FILE__, "USER::WriteDetailStat() - failed to write detail stat from queue\n");
950         WriteServLog("Cannot write detail stat from queue (of size %d recs) for user %s.", traffStatSaved.second.size(), login.c_str());
951         WriteServLog("%s", store->GetStrError().c_str());
952         return -1;
953         }
954     traffStatSaved.second.erase(traffStatSaved.second.begin(), traffStatSaved.second.end());
955     }
956
957 TRAFF_STAT ts;
958
959     {
960     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
961     ts.swap(traffStat);
962     }
963
964 printfd(__FILE__, "USER::WriteDetailedStat() - size = %d\n", ts.size());
965
966 if (ts.size() && !disabledDetailStat)
967     {
968     if (store->WriteDetailedStat(ts, lastWriteDeatiledStat, login))
969         {
970         printfd(__FILE__, "USER::WriteDetailStat() - failed to write current detail stat\n");
971         WriteServLog("Cannot write detail stat for user %s.", login.c_str());
972         WriteServLog("%s", store->GetStrError().c_str());
973         if (!hard)
974             {
975             printfd(__FILE__, "USER::WriteDetailStat() - pushing detail stat to queue\n");
976             STG_LOCKER lock(&mutex, __FILE__, __LINE__);
977             traffStatSaved.second.swap(ts);
978             traffStatSaved.first = lastWriteDeatiledStat;
979             }
980         return -1;
981         }
982     }
983 lastWriteDeatiledStat = stgTime;
984 return 0;
985 }
986 //-----------------------------------------------------------------------------
987 double USER::GetPassiveTimePart() const
988 {
989 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
990
991 static int daysInMonth[12] =
992 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
993
994 struct tm * tms;
995 time_t t = stgTime;
996 tms = localtime(&t);
997
998 time_t secMonth = daysInMonth[(tms->tm_mon + 11) % 12] * 24 * 3600; // Previous month
999
1000 if (tms->tm_year % 4 == 0 && tms->tm_mon == 1)
1001     {
1002     // Leap year
1003     secMonth += 24 * 3600;
1004     }
1005
1006 int dt = secMonth - passiveTime;
1007
1008 if (dt < 0)
1009     dt = 0;
1010
1011 return double(dt) / (secMonth);
1012 }
1013 //-----------------------------------------------------------------------------
1014 void USER::SetPassiveTimeAsNewUser()
1015 {
1016 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1017
1018 time_t t;
1019 struct tm * tm;
1020 t = stgTime;
1021 tm = localtime(&t);
1022 int daysCurrMon = DaysInCurrentMonth();
1023 double pt = (tm->tm_mday - 1) / (double)daysCurrMon;
1024
1025 passiveTime = (time_t)(pt * 24 * 3600 * daysCurrMon);
1026 }
1027 //-----------------------------------------------------------------------------
1028 void USER::MidnightResetSessionStat()
1029 {
1030 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1031
1032 if (connected)
1033     {
1034     Disconnect(true, "fake");
1035     Connect(true);
1036     }
1037 }
1038 //-----------------------------------------------------------------------------
1039 void USER::ProcessNewMonth()
1040 {
1041 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1042 //  Reset traff
1043 if (connected)
1044     {
1045     Disconnect(true, "fake");
1046     }
1047 DIR_TRAFF zeroTarff;
1048
1049 WriteMonthStat();
1050
1051 up = zeroTarff;
1052 down = zeroTarff;
1053
1054 if (connected)
1055     {
1056     Connect(true);
1057     }
1058
1059 //  Set new tariff
1060 if (nextTariff.ConstData() != "")
1061     {
1062     const TARIFF * nt;
1063     nt = tariffs->FindByName(nextTariff);
1064     if (nt == NULL)
1065         {
1066         WriteServLog("Cannot change tariff for user %s. Tariff %s not exist.",
1067                      login.c_str(), property.tariffName.Get().c_str());
1068         }
1069     else
1070         {
1071         property.tariffName.Set(nextTariff, sysAdmin, login, store);
1072         tariff = nt;
1073         }
1074     ResetNextTariff();
1075     WriteConf();
1076     }
1077 }
1078 //-----------------------------------------------------------------------------
1079 void USER::ProcessDayFeeSpread()
1080 {
1081 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1082
1083 if (passive.ConstData())
1084     return;
1085
1086 double f = tariff->GetFee() / DaysInCurrentMonth();
1087
1088 if (f == 0.0)
1089     return;
1090
1091 double c = cash;
1092 property.cash.Set(c - f, sysAdmin, login, store, "Subscriber fee charge");
1093 ResetPassiveTime();
1094 }
1095 //-----------------------------------------------------------------------------
1096 void USER::ProcessDayFee()
1097 {
1098 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1099
1100 double passiveTimePart = 1.0;
1101 if (!settings->GetFullFee())
1102     {
1103     passiveTimePart = GetPassiveTimePart();
1104     }
1105 else
1106     {
1107     if (passive.ConstData())
1108         {
1109         printfd(__FILE__, "Don't charge fee `cause we are passive\n");
1110         return;
1111         }
1112     }
1113 double f = tariff->GetFee() * passiveTimePart;
1114
1115 ResetPassiveTime();
1116
1117 if (f == 0.0)
1118     return;
1119
1120 double c = cash;
1121 printfd(__FILE__, "login: %8s   Fee=%f PassiveTimePart=%f fee=%f\n",
1122         login.c_str(),
1123         tariff->GetFee(),
1124         passiveTimePart,
1125         f);
1126 property.cash.Set(c - f, sysAdmin, login, store, "Subscriber fee charge");
1127 }
1128 //-----------------------------------------------------------------------------
1129 void USER::SetPrepaidTraff()
1130 {
1131 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1132
1133 property.freeMb.Set(tariff->GetFree(), sysAdmin, login, store, "Prepaid traffic");
1134 }
1135 //-----------------------------------------------------------------------------
1136 int USER::AddMessage(STG_MSG * msg)
1137 {
1138 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1139
1140 if (SendMessage(*msg) == 0)
1141     {
1142     if (msg->header.repeat > 0)
1143         {
1144         msg->header.repeat--;
1145         #ifndef DEBUG
1146         //TODO: gcc v. 4.x generate ICE on x86_64
1147         msg->header.lastSendTime = time(NULL);
1148         #else
1149         msg->header.lastSendTime = stgTime;
1150         #endif
1151         if (store->AddMessage(msg, login))
1152             {
1153             errorStr = store->GetStrError();
1154             STG_LOGGER & WriteServLog = GetStgLogger();
1155             WriteServLog("Error adding message %s", errorStr.c_str());
1156             WriteServLog("%s", store->GetStrError().c_str());
1157             return -1;
1158             }
1159         }
1160     }
1161 else
1162     {
1163     if (store->AddMessage(msg, login))
1164         {
1165         errorStr = store->GetStrError();
1166         STG_LOGGER & WriteServLog = GetStgLogger();
1167         WriteServLog("Error adding message %s", errorStr.c_str());
1168         WriteServLog("%s", store->GetStrError().c_str());
1169         return -1;
1170         }
1171     }
1172 return 0;
1173 }
1174 //-----------------------------------------------------------------------------
1175 int USER::SendMessage(const STG_MSG & msg)
1176 {
1177 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1178
1179 if (authorizedBy.empty())
1180     {
1181     return -1;
1182     }
1183
1184 int ret = -1;
1185 set<const BASE_AUTH*>::iterator it;
1186
1187 it = authorizedBy.begin();
1188 while (it != authorizedBy.end())
1189     {
1190     if ((*it)->SendMessage(msg, currIP) == 0)
1191         ret = 0;
1192     ++it;
1193     }
1194 return ret;
1195 }
1196 //-----------------------------------------------------------------------------
1197 int USER::ScanMessage()
1198 {
1199 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
1200
1201 vector<STG_MSG_HDR> hdrsList;
1202
1203 if (store->GetMessageHdrs(&hdrsList, login))
1204     {
1205     printfd(__FILE__, "Error GetMessageHdrs %s\n", store->GetStrError().c_str());
1206     return -1;
1207     }
1208
1209 for (unsigned i = 0; i < hdrsList.size(); i++)
1210     {
1211
1212     if (hdrsList[i].lastSendTime + hdrsList[i].repeatPeriod * 60 < (unsigned)stgTime)
1213         {
1214         STG_MSG msg;
1215         if (store->GetMessage(hdrsList[i].id, &msg, login) == 0)
1216             {
1217             if (SendMessage(msg) == 0)
1218                 {
1219                 msg.header.repeat--;
1220                 if (msg.header.repeat < 0)
1221                     {
1222                     printfd(__FILE__, "DelMessage\n");
1223                     store->DelMessage(hdrsList[i].id, login);
1224                     }
1225                 else
1226                     {
1227                     #ifndef DEBUG
1228                     //TODO: gcc v. 4.x generate ICE on x86_64
1229                     msg.header.lastSendTime = time(NULL);
1230                     #else
1231                     msg.header.lastSendTime = stgTime;
1232                     #endif
1233                     if (store->EditMessage(msg, login))
1234                         {
1235                         printfd(__FILE__, "EditMessage Error %s\n", store->GetStrError().c_str());
1236                         }
1237                     }
1238                 }
1239             }
1240         else
1241             {
1242             WriteServLog("Cannot get message for user %s.", login.c_str());
1243             WriteServLog("%s", store->GetStrError().c_str());
1244             }
1245         }
1246     }
1247 return 0;
1248 }
1249 //-----------------------------------------------------------------------------
1250 //-----------------------------------------------------------------------------
1251 //-----------------------------------------------------------------------------
1252 void CHG_PASSIVE_NOTIFIER::Notify(const int & oldPassive, const int & newPassive)
1253 {
1254 if (newPassive && !oldPassive)
1255     user->property.cash.Set(user->cash - user->tariff->GetPassiveCost(),
1256                             user->sysAdmin,
1257                             user->login,
1258                             user->store,
1259                             "Freeze");
1260 }
1261 //-----------------------------------------------------------------------------
1262 void CHG_TARIFF_NOTIFIER::Notify(const string &, const string & newTariff)
1263 {
1264 user->tariff = user->tariffs->FindByName(newTariff);
1265 }
1266 //-----------------------------------------------------------------------------
1267 void CHG_CASH_NOTIFIER::Notify(const double & oldCash, const double & newCash)
1268 {
1269 user->lastCashAddTime = *const_cast<time_t *>(&stgTime);
1270 user->lastCashAdd = newCash - oldCash;
1271 }
1272 //-----------------------------------------------------------------------------
1273 void CHG_IP_NOTIFIER::Notify(const uint32_t & from, const uint32_t & to)
1274 {
1275     printfd(__FILE__, "Change IP from %s to %s\n", inet_ntostring(from).c_str(), inet_ntostring(to).c_str());
1276     if (from != 0)
1277         if (user->connected)
1278             user->Disconnect(false, "Change IP");
1279     if (to != 0)
1280         if (user->IsInetable())
1281             user->Connect(false);
1282 }
1283 //-----------------------------------------------------------------------------