bec692fa400e48bf8fc2a08c9d3b08efa473a98f
[stg.git] / projects / stargazer / plugins / other / ping / ping.cpp
1 #include <cstdio>
2 #include <cassert>
3 #include <csignal>
4 #include <ctime>
5 #include <algorithm>
6
7 #include "stg/user.h"
8 #include "stg/locker.h"
9 #include "stg/user_property.h"
10 #include "stg/plugin_creator.h"
11 #include "ping.h"
12
13 namespace
14 {
15 PLUGIN_CREATOR<PING> pc;
16
17 //-----------------------------------------------------------------------------
18 //-----------------------------------------------------------------------------
19 //-----------------------------------------------------------------------------
20 // ëÌÁÓÓ ÄÌÑ ÐÏÉÓËÁ ÀÚÅÒÁ × ÓÐÉÓËÅ ÎÏÔÉÆÉËÁÔÏÒÏ×
21 template <typename varType>
22 class IS_CONTAINS_USER: public std::binary_function<varType, USER_PTR, bool>
23 {
24 public:
25     IS_CONTAINS_USER(const USER_PTR & u) : user(u) {}
26     bool operator()(varType notifier) const
27         {
28         return notifier.GetUser() == user;
29         }
30 private:
31     const USER_PTR & user;
32 };
33 }
34
35 extern "C" PLUGIN * GetPlugin();
36 //-----------------------------------------------------------------------------
37 //-----------------------------------------------------------------------------
38 //-----------------------------------------------------------------------------
39 PLUGIN * GetPlugin()
40 {
41 return pc.GetPlugin();
42 }
43 //-----------------------------------------------------------------------------
44 //-----------------------------------------------------------------------------
45 //-----------------------------------------------------------------------------
46 int PING_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
47 {
48 PARAM_VALUE pv;
49 std::vector<PARAM_VALUE>::const_iterator pvi;
50
51 pv.param = "PingDelay";
52 pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
53 if (pvi == s.moduleParams.end() || pvi->value.empty())
54     {
55     errorStr = "Parameter \'PingDelay\' not found.";
56     printfd(__FILE__, "Parameter 'PingDelay' not found\n");
57     return -1;
58     }
59 if (ParseIntInRange(pvi->value[0], 5, 3600, &pingDelay))
60     {
61     errorStr = "Cannot parse parameter \'PingDelay\': " + errorStr;
62     printfd(__FILE__, "Canot parse parameter 'PingDelay'\n");
63     return -1;
64     }
65
66 return 0;
67 }
68 //-----------------------------------------------------------------------------
69 PING::PING()
70     : users(NULL),
71       nonstop(false),
72       isRunning(false),
73       onAddUserNotifier(*this),
74       onDelUserNotifier(*this),
75       logger(GetPluginLogger(GetStgLogger(), "ping"))
76 {
77 pthread_mutex_init(&mutex, NULL);
78 }
79 //-----------------------------------------------------------------------------
80 PING::~PING()
81 {
82 pthread_mutex_destroy(&mutex);
83 }
84 //-----------------------------------------------------------------------------
85 int PING::ParseSettings()
86 {
87 int ret = pingSettings.ParseSettings(settings);
88 if (ret)
89     errorStr = pingSettings.GetStrError();
90 return ret;
91 }
92 //-----------------------------------------------------------------------------
93 int PING::Start()
94 {
95 GetUsers();
96
97 users->AddNotifierUserAdd(&onAddUserNotifier);
98 users->AddNotifierUserDel(&onDelUserNotifier);
99
100 nonstop = true;
101
102 pinger.SetDelayTime(pingSettings.GetPingDelay());
103 pinger.Start();
104
105 if (pthread_create(&thread, NULL, Run, this))
106     {
107     errorStr = "Cannot start thread.";
108     logger("Cannot create thread.");
109     printfd(__FILE__, "Cannot start thread\n");
110     return -1;
111     }
112
113 return 0;
114 }
115 //-----------------------------------------------------------------------------
116 int PING::Stop()
117 {
118 STG_LOCKER lock(&mutex);
119
120 if (!isRunning)
121     return 0;
122
123 pinger.Stop();
124 nonstop = false;
125 //5 seconds to thread stops itself
126 struct timespec ts = {0, 200000000};
127 for (int i = 0; i < 25; i++)
128     {
129     if (!isRunning)
130         break;
131
132     nanosleep(&ts, NULL);
133     }
134
135 users->DelNotifierUserAdd(&onAddUserNotifier);
136 users->DelNotifierUserDel(&onDelUserNotifier);
137
138 std::list<USER_PTR>::iterator users_iter;
139 users_iter = usersList.begin();
140 while (users_iter != usersList.end())
141     {
142     UnSetUserNotifiers(*users_iter);
143     ++users_iter;
144     }
145
146 if (isRunning)
147     return -1;
148
149 return 0;
150 }
151 //-----------------------------------------------------------------------------
152 bool PING::IsRunning()
153 {
154 return isRunning;
155 }
156 //-----------------------------------------------------------------------------
157 void * PING::Run(void * d)
158 {
159 sigset_t signalSet;
160 sigfillset(&signalSet);
161 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
162
163 PING * ping = static_cast<PING *>(d);
164 ping->isRunning = true;
165
166 long delay = (10000000 * ping->pingSettings.GetPingDelay()) / 3 + 50000000;
167  
168 while (ping->nonstop)
169     {
170     std::list<USER_PTR>::iterator iter = ping->usersList.begin();
171         {
172         STG_LOCKER lock(&ping->mutex);
173         while (iter != ping->usersList.end())
174             {
175             if ((*iter)->GetProperty().ips.ConstData().OnlyOneIP())
176                 {
177                 uint32_t ip = (*iter)->GetProperty().ips.ConstData()[0].ip;
178                 time_t t;
179                 if (ping->pinger.GetIPTime(ip, &t) == 0)
180                     {
181                     if (t)
182                         (*iter)->UpdatePingTime(t);
183                     }
184                 }
185             else
186                 {
187                 uint32_t ip = (*iter)->GetCurrIP();
188                 if (ip)
189                     {
190                     time_t t;
191                     if (ping->pinger.GetIPTime(ip, &t) == 0)
192                         {
193                         if (t)
194                             (*iter)->UpdatePingTime(t);
195                         }
196                     }
197                 }
198             ++iter;
199             }
200         }
201     struct timespec ts = {delay / 1000000000, delay % 1000000000};
202     for (int i = 0; i < 100; i++)
203         {
204         if (ping->nonstop)
205             {
206             nanosleep(&ts, NULL);
207             }
208         }
209     }
210
211 ping->isRunning = false;
212 return NULL;
213 }
214 //-----------------------------------------------------------------------------
215 void PING::SetUserNotifiers(USER_PTR u)
216 {
217 CHG_CURRIP_NOTIFIER_PING ChgCurrIPNotifier(*this, u);
218 CHG_IPS_NOTIFIER_PING ChgIPNotifier(*this, u);
219
220 ChgCurrIPNotifierList.push_front(ChgCurrIPNotifier);
221 ChgIPNotifierList.push_front(ChgIPNotifier);
222
223 u->AddCurrIPAfterNotifier(&(*ChgCurrIPNotifierList.begin()));
224 u->GetProperty().ips.AddAfterNotifier(&(*ChgIPNotifierList.begin()));
225 }
226 //-----------------------------------------------------------------------------
227 void PING::UnSetUserNotifiers(USER_PTR u)
228 {
229 // ---          CurrIP              ---
230 IS_CONTAINS_USER<CHG_CURRIP_NOTIFIER_PING> IsContainsUserCurrIP(u);
231 IS_CONTAINS_USER<CHG_IPS_NOTIFIER_PING> IsContainsUserIP(u);
232
233 std::list<CHG_CURRIP_NOTIFIER_PING>::iterator currIPter;
234 std::list<CHG_IPS_NOTIFIER_PING>::iterator IPIter;
235
236 currIPter = find_if(ChgCurrIPNotifierList.begin(),
237                     ChgCurrIPNotifierList.end(),
238                     IsContainsUserCurrIP);
239
240 if (currIPter != ChgCurrIPNotifierList.end())
241     {
242     currIPter->GetUser()->DelCurrIPAfterNotifier(&(*currIPter));
243     ChgCurrIPNotifierList.erase(currIPter);
244     }
245 // ---         CurrIP end          ---
246
247 // ---          IP              ---
248 IPIter = find_if(ChgIPNotifierList.begin(),
249                  ChgIPNotifierList.end(),
250                  IsContainsUserIP);
251
252 if (IPIter != ChgIPNotifierList.end())
253     {
254     IPIter->GetUser()->GetProperty().ips.DelAfterNotifier(&(*IPIter));
255     ChgIPNotifierList.erase(IPIter);
256     }
257 // ---          IP end          ---
258 }
259 //-----------------------------------------------------------------------------
260 void PING::GetUsers()
261 {
262 STG_LOCKER lock(&mutex);
263
264 USER_PTR u;
265 int h = users->OpenSearch();
266 assert(h && "USERS::OpenSearch is always correct");
267
268 while (users->SearchNext(h, &u) == 0)
269     {
270     usersList.push_back(u);
271     SetUserNotifiers(u);
272     if (u->GetProperty().ips.ConstData().OnlyOneIP())
273         {
274         pinger.AddIP(u->GetProperty().ips.ConstData()[0].ip);
275         }
276     else
277         {
278         uint32_t ip = u->GetCurrIP();
279         if (ip)
280             {
281             pinger.AddIP(ip);
282             }
283         }
284     }
285
286 users->CloseSearch(h);
287 }
288 //-----------------------------------------------------------------------------
289 void PING::AddUser(USER_PTR u)
290 {
291 STG_LOCKER lock(&mutex);
292
293 SetUserNotifiers(u);
294 usersList.push_back(u);
295 }
296 //-----------------------------------------------------------------------------
297 void PING::DelUser(USER_PTR u)
298 {
299 STG_LOCKER lock(&mutex);
300
301 UnSetUserNotifiers(u);
302
303 std::list<USER_PTR>::iterator users_iter;
304 users_iter = usersList.begin();
305
306 while (users_iter != usersList.end())
307     {
308     if (u == *users_iter)
309         {
310         usersList.erase(users_iter);
311         break;
312         }
313     ++users_iter;
314     }
315 }
316 //-----------------------------------------------------------------------------
317 void CHG_CURRIP_NOTIFIER_PING::Notify(const uint32_t & oldIP, const uint32_t & newIP)
318 {
319 ping.pinger.DelIP(oldIP);
320 if (newIP)
321     {
322     ping.pinger.AddIP(newIP);
323     }
324 }
325 //-----------------------------------------------------------------------------
326 void CHG_IPS_NOTIFIER_PING::Notify(const USER_IPS & oldIPS, const USER_IPS & newIPS)
327 {
328 if (oldIPS.OnlyOneIP())
329     {
330     ping.pinger.DelIP(oldIPS[0].ip);
331     }
332
333 if (newIPS.OnlyOneIP())
334     {
335     ping.pinger.AddIP(newIPS[0].ip);
336     }
337 }
338 //-----------------------------------------------------------------------------
339 void ADD_USER_NONIFIER_PING::Notify(const USER_PTR & user)
340 {
341 ping.AddUser(user);
342 }
343 //-----------------------------------------------------------------------------
344 void DEL_USER_NONIFIER_PING::Notify(const USER_PTR & user)
345 {
346 ping.DelUser(user);
347 }
348 //-----------------------------------------------------------------------------