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