]> git.stg.codes - stg.git/blob - projects/stargazer/users_impl.cpp
Help book chapter 2 complete
[stg.git] / projects / stargazer / users_impl.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.61 $
27  $Date: 2010/09/13 05:56:42 $
28  $Author: faust $
29  */
30
31 #ifndef _GNU_SOURCE
32 #define _GNU_SOURCE
33 #endif
34
35 #include <pthread.h>
36 #include <csignal>
37 #include <cassert>
38 #include <algorithm>
39 #include <utility>
40 #include <string>
41 #include <vector>
42
43 #include "stg/settings.h"
44 #include "stg/common.h"
45 #include "users_impl.h"
46 #include "stg_timer.h"
47
48 using namespace std;
49
50 extern const volatile time_t stgTime;
51
52 //#define USERS_DEBUG 1
53
54 //-----------------------------------------------------------------------------
55 USERS_IMPL::USERS_IMPL(SETTINGS_IMPL * s, STORE * st, TARIFFS * t, const ADMIN * sa)
56     : users(),
57       usersToDelete(),
58       userIPNotifiersBefore(),
59       userIPNotifiersAfter(),
60       ipIndex(),
61       loginIndex(),
62       settings(s),
63       tariffs(t),
64       store(st),
65       sysAdmin(sa),
66       WriteServLog(GetStgLogger()),
67       nonstop(false),
68       isRunning(false),
69       mutex(),
70       thread(),
71       handle(0),
72       searchDescriptors(),
73       onAddNotifiers(),
74       onDelNotifiers(),
75       onAddNotifiersImpl(),
76       onDelNotifiersImpl()
77 {
78 pthread_mutexattr_t attr;
79 pthread_mutexattr_init(&attr);
80 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
81 pthread_mutex_init(&mutex, &attr);
82 }
83 //-----------------------------------------------------------------------------
84 USERS_IMPL::~USERS_IMPL()
85 {
86 pthread_mutex_destroy(&mutex);
87 }
88 //-----------------------------------------------------------------------------
89 int USERS_IMPL::FindByNameNonLock(const string & login, user_iter * user)
90 {
91 map<string, user_iter>::iterator iter;
92 iter = loginIndex.find(login);
93 if (iter != loginIndex.end())
94     {
95     if (user)
96         *user = iter->second;
97     return 0;
98     }
99 return -1;
100 }
101 //-----------------------------------------------------------------------------
102 int USERS_IMPL::FindByName(const string & login, USER_PTR * user)
103 {
104 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
105 user_iter u;
106 int res = FindByNameNonLock(login, &u);
107 if (res)
108     return -1;
109 *user = &(*u);
110 return 0;
111 }
112 //-----------------------------------------------------------------------------
113 bool USERS_IMPL::TariffInUse(const string & tariffName) const
114 {
115 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
116 list<USER_IMPL>::const_iterator iter;
117 iter = users.begin();
118 while (iter != users.end())
119     {
120     if (iter->GetProperty().tariffName.Get() == tariffName)
121         return true;
122     ++iter;
123     }
124 return false;
125 }
126 //-----------------------------------------------------------------------------
127 int USERS_IMPL::Add(const string & login, const ADMIN * admin)
128 {
129 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
130 const PRIV * priv = admin->GetPriv();
131
132 if (!priv->userAddDel)
133     {
134     WriteServLog("%s tried to add user \'%s\'. Access denied.",
135          admin->GetLogStr().c_str(), login.c_str());
136     /*errorStr = "Admin \'" + admin->GetLogin() +
137                "\': tried to add user \'" + ud->login + "\'. Access denied.";*/
138     return -1;
139     }
140
141 //////
142 if (store->AddUser(login))
143     {
144     //TODO
145     //WriteServLog("Admin \'%s\': tried to add user \'%s\'. Access denied.",
146     //     admin->GetLogin().c_str(), ud->login.c_str());
147     return -1;
148     }
149 //////
150
151 USER_IMPL u(settings, store, tariffs, sysAdmin, this);
152
153 /*struct tm * tms;
154 time_t t = stgTime;
155
156 tms = localtime(&t);
157
158 tms->tm_hour = 0;
159 tms->tm_min = 0;
160 tms->tm_sec = 0;
161
162 if (settings->GetDayResetTraff() > tms->tm_mday)
163     tms->tm_mon -= 1;
164
165 tms->tm_mday = settings->GetDayResetTraff();*/
166
167 u.SetLogin(login);
168
169 u.SetPassiveTimeAsNewUser();
170
171 u.WriteConf();
172 u.WriteStat();
173
174 WriteServLog("%s User \'%s\' added.",
175          admin->GetLogStr().c_str(), login.c_str());
176
177 u.OnAdd();
178
179 users.push_front(u);
180
181 AddUserIntoIndexes(users.begin());
182 SetUserNotifiers(users.begin());
183
184     {
185     // Fire all "on add" notifiers
186     set<NOTIFIER_BASE<USER_PTR> *>::iterator ni = onAddNotifiers.begin();
187     while (ni != onAddNotifiers.end())
188         {
189         (*ni)->Notify(&users.front());
190         ++ni;
191         }
192     }
193
194     {
195     // Fire all "on add" implementation notifiers
196     set<NOTIFIER_BASE<USER_IMPL_PTR> *>::iterator ni = onAddNotifiersImpl.begin();
197     while (ni != onAddNotifiersImpl.end())
198         {
199         (*ni)->Notify(&users.front());
200         ++ni;
201         }
202     }
203
204 return 0;
205 }
206 //-----------------------------------------------------------------------------
207 void USERS_IMPL::Del(const string & login, const ADMIN * admin)
208 {
209 const PRIV * priv = admin->GetPriv();
210 user_iter u;
211
212 if (!priv->userAddDel)
213     {
214     WriteServLog("%s tried to remove user \'%s\'. Access denied.",
215          admin->GetLogStr().c_str(), login.c_str());
216     return;
217     }
218
219
220     {
221     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
222
223     if (FindByNameNonLock(login, &u))
224         {
225         WriteServLog("%s tried to delete user \'%s\': not found.",
226                      admin->GetLogStr().c_str(),
227                      login.c_str());
228         return;
229         }
230     }
231
232     {
233     set<NOTIFIER_BASE<USER_PTR> *>::iterator ni = onDelNotifiers.begin();
234     while (ni != onDelNotifiers.end())
235         {
236         (*ni)->Notify(&(*u));
237         ++ni;
238         }
239     }
240
241     {
242     set<NOTIFIER_BASE<USER_IMPL_PTR> *>::iterator ni = onDelNotifiersImpl.begin();
243     while (ni != onDelNotifiersImpl.end())
244         {
245         (*ni)->Notify(&(*u));
246         ++ni;
247         }
248     }
249
250     {
251     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
252
253     u->OnDelete();
254     u->SetDeleted();
255
256     USER_TO_DEL utd;
257     utd.iter = u;
258     utd.delTime = stgTime;
259     usersToDelete.push_back(utd);
260
261     UnSetUserNotifiers(u);
262     DelUserFromIndexes(u);
263
264     WriteServLog("%s User \'%s\' deleted.",
265              admin->GetLogStr().c_str(), login.c_str());
266
267     }
268 }
269 //-----------------------------------------------------------------------------
270 int USERS_IMPL::ReadUsers()
271 {
272 vector<string> usersList;
273 usersList.clear();
274 if (store->GetUsersList(&usersList) < 0)
275     {
276     WriteServLog(store->GetStrError().c_str());
277     exit(1);
278     }
279
280 user_iter ui;
281
282 for (unsigned int i = 0; i < usersList.size(); i++)
283     {
284     USER_IMPL u(settings, store, tariffs, sysAdmin, this);
285
286     u.SetLogin(usersList[i]);
287     users.push_front(u);
288     ui = users.begin();
289
290     AddUserIntoIndexes(ui);
291     SetUserNotifiers(ui);
292
293     if (ui->ReadConf() < 0)
294         return -1;
295
296     if (ui->ReadStat() < 0)
297         return -1;
298     }
299
300 return 0;
301 }
302 //-----------------------------------------------------------------------------
303 void * USERS_IMPL::Run(void * d)
304 {
305 printfd(__FILE__, "=====================| pid: %d |===================== \n", getpid());
306 USERS_IMPL * us = (USERS_IMPL*) d;
307
308 struct tm t;
309 time_t tt = stgTime;
310 localtime_r(&tt, &t);
311
312 int min = t.tm_min;
313 int day = t.tm_mday;
314
315 printfd(__FILE__,"Day = %d Min = %d\n", day, min);
316
317 time_t touchTime = stgTime - MONITOR_TIME_DELAY_SEC;
318 string monFile = us->settings->GetMonitorDir() + "/users_r";
319 printfd(__FILE__, "Monitor=%d file USERS %s\n", us->settings->GetMonitoring(), monFile.c_str());
320
321 us->isRunning = true;
322 while (us->nonstop)
323     {
324     //printfd(__FILE__,"New Minute. old = %02d current = %02d\n", min, t->tm_min);
325     //printfd(__FILE__,"New Day.    old = %2d current = %2d\n", day, t->tm_mday);
326
327     for_each(us->users.begin(), us->users.end(), mem_fun_ref(&USER_IMPL::Run));
328
329     tt = stgTime;
330     localtime_r(&tt, &t);
331
332     if (min != t.tm_min)
333         {
334         printfd(__FILE__,"Sec = %d\n", stgTime);
335         printfd(__FILE__,"New Minute. old = %d current = %d\n", min, t.tm_min);
336         min = t.tm_min;
337
338         us->NewMinute(t);
339         }
340
341     if (day != t.tm_mday)
342         {
343         printfd(__FILE__,"Sec = %d\n", stgTime);
344         printfd(__FILE__,"New Day. old = %d current = %d\n", day, t.tm_mday);
345         day = t.tm_mday;
346         us->NewDay(t);
347         }
348
349     if (us->settings->GetMonitoring() && (touchTime + MONITOR_TIME_DELAY_SEC <= stgTime))
350         {
351         //printfd(__FILE__, "Monitor=%d file TRAFFCOUNTER %s\n", tc->monitoring, monFile.c_str());
352         touchTime = stgTime;
353         TouchFile(monFile.c_str());
354         }
355
356     stgUsleep(100000);
357     } //while (us->nonstop)
358
359 user_iter ui = us->users.begin();
360 while (ui != us->users.end())
361     {
362     us->UnSetUserNotifiers(ui);
363     us->DelUserFromIndexes(ui);
364     ++ui;
365     }
366
367 list<USER_TO_DEL>::iterator iter;
368 iter = us->usersToDelete.begin();
369 while (iter != us->usersToDelete.end())
370     {
371     iter->delTime -= 2 * userDeleteDelayTime;
372     ++iter;
373     }
374 us->RealDelUser();
375
376 us->isRunning = false;
377
378 return NULL;
379 }
380 //-----------------------------------------------------------------------------
381 void USERS_IMPL::NewMinute(const struct tm & t)
382 {
383 //Write traff, reset session traff. Fake disconnect-connect
384 if (t.tm_hour == 23 && t.tm_min == 59)
385     {
386     printfd(__FILE__,"MidnightResetSessionStat\n");
387     for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::MidnightResetSessionStat));
388     }
389
390 if (TimeToWriteDetailStat(t))
391     {
392     //printfd(__FILE__, "USER::WriteInetStat\n");
393     int usersCnt = 0;
394
395     // ðÉÛÅÍ ÀÚÅÒÏ× ÞÁÓÔÑÍÉ. ÷ ÐÅÒÅÒÙ×ÁÈ ×ÙÚÙ×ÁÅÍ USER::Run
396     list<USER_IMPL>::iterator usr = users.begin();
397     while (usr != users.end())
398         {
399         usersCnt++;
400         usr->WriteDetailStat();
401         ++usr;
402         if (usersCnt % 10 == 0)
403             for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::Run));
404         }
405     }
406
407 RealDelUser();
408 }
409 //-----------------------------------------------------------------------------
410 void USERS_IMPL::NewDay(const struct tm & t)
411 {
412 struct tm t1;
413 time_t tt = stgTime;
414 localtime_r(&tt, &t1);
415 int dayFee = settings->GetDayFee();
416
417 if (dayFee == 0)
418     dayFee = DaysInCurrentMonth();
419
420 printfd(__FILE__, "DayFee = %d\n", dayFee);
421 printfd(__FILE__, "Today = %d DayResetTraff = %d\n", t1.tm_mday, settings->GetDayResetTraff());
422 printfd(__FILE__, "DayFeeIsLastDay = %d\n", settings->GetDayFeeIsLastDay());
423
424 if (!settings->GetDayFeeIsLastDay())
425     {
426     printfd(__FILE__, "DayResetTraff - 1 -\n");
427     DayResetTraff(t1);
428     //printfd(__FILE__, "DayResetTraff - 1 - 1 -\n");
429     }
430
431 if (settings->GetSpreadFee())
432     {
433     printfd(__FILE__, "Spread DayFee\n");
434     for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::ProcessDayFeeSpread));
435     }
436 else
437     {
438     if (t.tm_mday == dayFee)
439         {
440         printfd(__FILE__, "DayFee\n");
441         for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::ProcessDayFee));
442         }
443     }
444
445 if (settings->GetDayFeeIsLastDay())
446     {
447     printfd(__FILE__, "DayResetTraff - 2 -\n");
448     DayResetTraff(t1);
449     }
450 }
451 //-----------------------------------------------------------------------------
452 void USERS_IMPL::DayResetTraff(const struct tm & t1)
453 {
454 int dayResetTraff = settings->GetDayResetTraff();
455 if (dayResetTraff == 0)
456     dayResetTraff = DaysInCurrentMonth();
457 if (t1.tm_mday == dayResetTraff)
458     {
459     printfd(__FILE__, "ResetTraff\n");
460     for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::ProcessNewMonth));
461     //for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::SetPrepaidTraff));
462     }
463 }
464 //-----------------------------------------------------------------------------
465 int USERS_IMPL::Start()
466 {
467 if (ReadUsers())
468     {
469     WriteServLog("USERS: Error: Cannot read users!");
470     return -1;
471     }
472
473 nonstop = true;
474 if (pthread_create(&thread, NULL, Run, this))
475     {
476     WriteServLog("USERS: Error: Cannot start thread!");
477     return -1;
478     }
479 return 0;
480 }
481 //-----------------------------------------------------------------------------
482 int USERS_IMPL::Stop()
483 {
484 printfd(__FILE__, "USERS::Stop()\n");
485
486 if (!isRunning)
487     {
488     //printfd(__FILE__, "Alredy stopped\n");
489     return 0;
490     }
491
492 nonstop = false;
493
494 //5 seconds to thread stops itself
495 struct timespec ts = {0, 200000000};
496 for (size_t i = 0; i < 25 * (users.size() / 50 + 1); i++)
497     {
498     if (!isRunning)
499         break;
500
501     nanosleep(&ts, NULL);
502     }
503
504 //after 5 seconds waiting thread still running. now kill it
505 if (isRunning)
506     {
507     printfd(__FILE__, "kill USERS thread.\n");
508     //TODO pthread_cancel()
509     if (pthread_kill(thread, SIGINT))
510         {
511         //errorStr = "Cannot kill USERS thread.";
512         //printfd(__FILE__, "Cannot kill USERS thread.\n");
513         //return 0;
514         }
515     printfd(__FILE__, "USERS killed\n");
516     }
517
518 printfd(__FILE__, "Before USERS::Run()\n");
519 for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::Run));
520
521 // 'cause bind2st accepts only constant first param
522 for (list<USER_IMPL>::iterator it = users.begin();
523      it != users.end();
524      ++it)
525     it->WriteDetailStat(true);
526
527 for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::WriteStat));
528 //for_each(users.begin(), users.end(), mem_fun_ref(&USER_IMPL::WriteConf));
529
530 printfd(__FILE__, "USERS::Stop()\n");
531 return 0;
532 }
533 //-----------------------------------------------------------------------------
534 void USERS_IMPL::RealDelUser()
535 {
536 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
537
538 printfd(__FILE__, "RealDelUser() users to del: %d\n", usersToDelete.size());
539
540 list<USER_TO_DEL>::iterator iter;
541 iter = usersToDelete.begin();
542 while (iter != usersToDelete.end())
543     {
544     printfd(__FILE__, "RealDelUser() user=%s\n", iter->iter->GetLogin().c_str());
545     if (iter->delTime + userDeleteDelayTime < stgTime)
546         {
547         printfd(__FILE__, "RealDelUser() user=%s removed from DB\n", iter->iter->GetLogin().c_str());
548         if (store->DelUser(iter->iter->GetLogin()))
549             {
550             WriteServLog("Error removing user \'%s\' from database.", iter->iter->GetLogin().c_str());
551             }
552         users.erase(iter->iter);
553         usersToDelete.erase(iter++);
554         }
555     else
556         {
557         ++iter;
558         }
559     }
560 return;
561 }
562 //-----------------------------------------------------------------------------
563 int USERS_IMPL::GetUserNum() const
564 {
565 return users.size();
566 }
567 //-----------------------------------------------------------------------------
568 void USERS_IMPL::AddToIPIdx(user_iter user)
569 {
570 printfd(__FILE__, "USERS: Add IP Idx\n");
571 uint32_t ip = user->GetCurrIP();
572 //assert(ip && "User has non-null ip");
573 if (!ip)
574     return; // User has disconnected
575
576 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
577
578 const map<uint32_t, user_iter>::iterator it(
579         ipIndex.lower_bound(ip)
580 );
581
582 assert((it == ipIndex.end() || it->first != ip) && "User is not in index");
583
584 ipIndex.insert(it, std::make_pair(ip, user));
585 }
586 //-----------------------------------------------------------------------------
587 void USERS_IMPL::DelFromIPIdx(uint32_t ip)
588 {
589 printfd(__FILE__, "USERS: Del IP Idx\n");
590 assert(ip && "User has non-null ip");
591
592 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
593
594 const map<uint32_t, user_iter>::iterator it(
595         ipIndex.find(ip)
596 );
597
598 //assert(it != ipIndex.end() && "User is in index");
599 if (it == ipIndex.end())
600     return; // User has not been added
601
602 ipIndex.erase(it);
603 }
604 //-----------------------------------------------------------------------------
605 int USERS_IMPL::FindByIPIdx(uint32_t ip, USER_PTR * usr) const
606 {
607     USER_IMPL * ptr = NULL;
608     if (FindByIPIdx(ip, &ptr))
609         return -1;
610     *usr = ptr;
611     return 0;
612 }
613 //-----------------------------------------------------------------------------
614 int USERS_IMPL::FindByIPIdx(uint32_t ip, USER_IMPL ** usr) const
615 {
616 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
617
618 map<uint32_t, user_iter>::const_iterator it;
619 it = ipIndex.find(ip);
620
621 if (it == ipIndex.end())
622     {
623     //printfd(__FILE__, "User NOT found in IP_Index!!!\n");
624     return -1;
625     }
626 *usr = &(*it->second);
627 //printfd(__FILE__, "User found in IP_Index\n");
628 return 0;
629 }
630 //-----------------------------------------------------------------------------
631 bool USERS_IMPL::IsIPInIndex(uint32_t ip) const
632 {
633 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
634
635 map<uint32_t, user_iter>::const_iterator it;
636 it = ipIndex.find(ip);
637
638 return it != ipIndex.end();
639 }
640 //-----------------------------------------------------------------------------
641 void USERS_IMPL::AddNotifierUserAdd(NOTIFIER_BASE<USER_PTR> * n)
642 {
643 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
644 onAddNotifiers.insert(n);
645 }
646 //-----------------------------------------------------------------------------
647 void USERS_IMPL::DelNotifierUserAdd(NOTIFIER_BASE<USER_PTR> * n)
648 {
649 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
650 onAddNotifiers.erase(n);
651 }
652 //-----------------------------------------------------------------------------
653 void USERS_IMPL::AddNotifierUserDel(NOTIFIER_BASE<USER_PTR> * n)
654 {
655 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
656 onDelNotifiers.insert(n);
657 }
658 //-----------------------------------------------------------------------------
659 void USERS_IMPL::DelNotifierUserDel(NOTIFIER_BASE<USER_PTR> * n)
660 {
661 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
662 onDelNotifiers.erase(n);
663 }
664 //-----------------------------------------------------------------------------
665 void USERS_IMPL::AddNotifierUserAdd(NOTIFIER_BASE<USER_IMPL_PTR> * n)
666 {
667 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
668 onAddNotifiersImpl.insert(n);
669 }
670 //-----------------------------------------------------------------------------
671 void USERS_IMPL::DelNotifierUserAdd(NOTIFIER_BASE<USER_IMPL_PTR> * n)
672 {
673 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
674 onAddNotifiersImpl.erase(n);
675 }
676 //-----------------------------------------------------------------------------
677 void USERS_IMPL::AddNotifierUserDel(NOTIFIER_BASE<USER_IMPL_PTR> * n)
678 {
679 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
680 onDelNotifiersImpl.insert(n);
681 }
682 //-----------------------------------------------------------------------------
683 void USERS_IMPL::DelNotifierUserDel(NOTIFIER_BASE<USER_IMPL_PTR> * n)
684 {
685 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
686 onDelNotifiersImpl.erase(n);
687 }
688 //-----------------------------------------------------------------------------
689 int USERS_IMPL::OpenSearch()
690 {
691 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
692 handle++;
693 searchDescriptors[handle] = users.begin();
694 return handle;
695 }
696 //-----------------------------------------------------------------------------
697 int USERS_IMPL::SearchNext(int h, USER_PTR * user)
698 {
699     USER_IMPL * ptr = NULL;
700     if (SearchNext(h, &ptr))
701         return -1;
702     *user = ptr;
703     return 0;
704 }
705 //-----------------------------------------------------------------------------
706 int USERS_IMPL::SearchNext(int h, USER_IMPL ** user)
707 {
708 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
709
710 if (searchDescriptors.find(h) == searchDescriptors.end())
711     {
712     WriteServLog("USERS. Incorrect search handle.");
713     return -1;
714     }
715
716 if (searchDescriptors[h] == users.end())
717     return -1;
718
719 while (searchDescriptors[h]->GetDeleted())
720     {
721     ++searchDescriptors[h];
722     if (searchDescriptors[h] == users.end())
723         {
724         return -1;
725         }
726     }
727
728 *user = &(*searchDescriptors[h]);
729
730 ++searchDescriptors[h];
731
732 return 0;
733 }
734 //-----------------------------------------------------------------------------
735 int USERS_IMPL::CloseSearch(int h)
736 {
737 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
738 if (searchDescriptors.find(h) != searchDescriptors.end())
739     {
740     searchDescriptors.erase(searchDescriptors.find(h));
741     return 0;
742     }
743
744 WriteServLog("USERS. Incorrect search handle.");
745 return -1;
746 }
747 //-----------------------------------------------------------------------------
748 void USERS_IMPL::SetUserNotifiers(user_iter user)
749 {
750 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
751
752 PROPERTY_NOTIFER_IP_BEFORE nb(*this, user);
753 PROPERTY_NOTIFER_IP_AFTER  na(*this, user);
754
755 userIPNotifiersBefore.push_front(nb);
756 userIPNotifiersAfter.push_front(na);
757
758 user->AddCurrIPBeforeNotifier(&(*userIPNotifiersBefore.begin()));
759 user->AddCurrIPAfterNotifier(&(*userIPNotifiersAfter.begin()));
760 }
761 //-----------------------------------------------------------------------------
762 void USERS_IMPL::UnSetUserNotifiers(user_iter user)
763 {
764 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
765
766 list<PROPERTY_NOTIFER_IP_BEFORE>::iterator  bi;
767 list<PROPERTY_NOTIFER_IP_AFTER>::iterator   ai;
768
769 bi = userIPNotifiersBefore.begin();
770 while (bi != userIPNotifiersBefore.end())
771     {
772     if (bi->GetUser() == user)
773         {
774         bi->GetUser()->DelCurrIPBeforeNotifier(&(*bi));
775         userIPNotifiersBefore.erase(bi);
776         //printfd(__FILE__, "Notifier Before removed. User %s\n", bi->GetUser()->GetLogin().c_str());
777         break;
778         }
779     ++bi;
780     }
781
782 ai = userIPNotifiersAfter.begin();
783 while (ai != userIPNotifiersAfter.end())
784     {
785     if (ai->GetUser() == user)
786         {
787         ai->GetUser()->DelCurrIPAfterNotifier(&(*ai));
788         userIPNotifiersAfter.erase(ai);
789         //printfd(__FILE__, "Notifier After removed. User %s\n", ai->GetUser()->GetLogin().c_str());
790         break;
791         }
792     ++ai;
793     }
794 }
795 //-----------------------------------------------------------------------------
796 void USERS_IMPL::AddUserIntoIndexes(user_iter user)
797 {
798 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
799 loginIndex.insert(make_pair(user->GetLogin(), user));
800 }
801 //-----------------------------------------------------------------------------
802 void USERS_IMPL::DelUserFromIndexes(user_iter user)
803 {
804 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
805 loginIndex.erase(user->GetLogin());
806 }
807 //-----------------------------------------------------------------------------
808 bool USERS_IMPL::TimeToWriteDetailStat(const struct tm & t)
809 {
810 int statTime = settings->GetDetailStatWritePeriod();
811
812 switch (statTime)
813     {
814     case dsPeriod_1:
815         if (t.tm_min == 0)
816             return true;
817         break;
818     case dsPeriod_1_2:
819         if (t.tm_min % 30 == 0)
820             return true;
821         break;
822     case dsPeriod_1_4:
823         if (t.tm_min % 15 == 0)
824             return true;
825         break;
826     case dsPeriod_1_6:
827         if (t.tm_min % 10 == 0)
828             return true;
829         break;
830     }
831 return false;
832 }