]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/other/ping/ping.cpp
Проведен легкий рефакторинг плагина пингера. Инициализация нотификаторов
[stg.git] / projects / stargazer / plugins / other / ping / ping.cpp
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <signal.h>
4
5 #include "ping.h"
6 #include "../../../user.h"
7
8 class PING_CREATOR
9 {
10 private:
11     PING * ping;
12
13 public:
14     PING_CREATOR()
15         : ping(new PING())
16         {
17         };
18     ~PING_CREATOR()
19         {
20         delete ping;
21         };
22
23     PING * GetPlugin()
24         {
25         return ping;
26         };
27 };
28 //-----------------------------------------------------------------------------
29 //-----------------------------------------------------------------------------
30 //-----------------------------------------------------------------------------
31 PING_CREATOR pc;
32 //-----------------------------------------------------------------------------
33 //-----------------------------------------------------------------------------
34 //-----------------------------------------------------------------------------
35 // ëÌÁÓÓ ÄÌÑ ÐÏÉÓËÁ ÀÚÅÒÁ × ÓÐÉÓËÅ ÎÏÔÉÆÉËÁÔÏÒÏ×
36 template <typename varType>
37 class IS_CONTAINS_USER: public binary_function<varType, user_iter, bool>
38 {
39 public:
40     IS_CONTAINS_USER(const user_iter & u) : user(u) {}
41     bool operator()(varType notifier) const
42         {
43         return notifier.GetUser() == user;
44         };
45 private:
46     const user_iter & user;
47 };
48 //-----------------------------------------------------------------------------
49 //-----------------------------------------------------------------------------
50 //-----------------------------------------------------------------------------
51 BASE_PLUGIN * GetPlugin()
52 {
53 return pc.GetPlugin();
54 }
55 //-----------------------------------------------------------------------------
56 //-----------------------------------------------------------------------------
57 //-----------------------------------------------------------------------------
58 PING_SETTINGS::PING_SETTINGS()
59     : pingDelay(0)
60 {
61 }
62 //-----------------------------------------------------------------------------
63 int PING_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
64 {
65 PARAM_VALUE pv;
66 vector<PARAM_VALUE>::const_iterator pvi;
67
68 pv.param = "PingDelay";
69 pvi = find(s.moduleParams.begin(), s.moduleParams.end(), pv);
70 if (pvi == s.moduleParams.end())
71     {
72     errorStr = "Parameter \'PingDelay\' not found.";
73     printfd(__FILE__, "Parameter 'PingDelay' not found\n");
74     return -1;
75     }
76 if (ParseIntInRange(pvi->value[0], 5, 3600, &pingDelay))
77     {
78     errorStr = "Cannot parse parameter \'PingDelay\': " + errorStr;
79     printfd(__FILE__, "Canot parse parameter 'PingDelay'\n");
80     return -1;
81     }
82
83 return 0;
84 }
85 //-----------------------------------------------------------------------------
86 int PING_SETTINGS::ParseIntInRange(const string & str, int min, int max, int * val)
87 {
88 if (str2x(str.c_str(), *val))
89     {
90     errorStr = "Incorrect value \'" + str + "\'.";
91     return -1;
92     }
93 if (*val < min || *val > max)
94     {
95     errorStr = "Value \'" + str + "\' out of range.";
96     return -1;
97     }
98 return 0;
99 }
100 //-----------------------------------------------------------------------------
101 PING::PING()
102     : users(NULL),
103       nonstop(false),
104       isRunning(false),
105       onAddUserNotifier(*this),
106       onDelUserNotifier(*this)
107 {
108 pthread_mutex_init(&mutex, NULL);
109 }
110 //-----------------------------------------------------------------------------
111 PING::~PING()
112 {
113 pthread_mutex_destroy(&mutex);
114 }
115 //-----------------------------------------------------------------------------
116 const string PING::GetVersion() const
117 {
118 return "Pinger v.1.01";
119 }
120 //-----------------------------------------------------------------------------
121 void PING::SetSettings(const MODULE_SETTINGS & s)
122 {
123 settings = s;
124 }
125 //-----------------------------------------------------------------------------
126 int PING::ParseSettings()
127 {
128 int ret = pingSettings.ParseSettings(settings);
129 if (ret)
130     errorStr = pingSettings.GetStrError();
131 return ret;
132 }
133 //-----------------------------------------------------------------------------
134 void PING::SetUsers(USERS * u)
135 {
136 users = u;
137 }
138 //-----------------------------------------------------------------------------
139 const string & PING::GetStrError() const
140 {
141 return errorStr;
142 }
143 //-----------------------------------------------------------------------------
144 int PING::Start()
145 {
146 GetUsers();
147
148 users->AddNotifierUserAdd(&onAddUserNotifier);
149 users->AddNotifierUserDel(&onDelUserNotifier);
150
151 nonstop = true;
152
153 pinger.SetDelayTime(pingSettings.GetPingDelay());
154 pinger.Start();
155
156 if (pthread_create(&thread, NULL, Run, this))
157     {
158     errorStr = "Cannot start thread.";
159     printfd(__FILE__, "Cannot start thread\n");
160     return -1;
161     }
162
163 return 0;
164 }
165 //-----------------------------------------------------------------------------
166 int PING::Stop()
167 {
168 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
169
170 if (!isRunning)
171     return 0;
172
173 pinger.Stop();
174 nonstop = false;
175 //5 seconds to thread stops itself
176 for (int i = 0; i < 25; i++)
177     {
178     if (!isRunning)
179         break;
180
181     usleep(200000);
182     }
183
184 //after 5 seconds waiting thread still running. now kill it
185 if (isRunning)
186     {
187     printfd(__FILE__, "kill PING thread.\n");
188     if (pthread_kill(thread, SIGINT))
189         {
190         errorStr = "Cannot kill PING thread.";
191         printfd(__FILE__, "Cannot kill PING thread.\n");
192         return -1;
193         }
194     printfd(__FILE__, "PING killed\n");
195     }
196
197 users->DelNotifierUserAdd(&onAddUserNotifier);
198 users->DelNotifierUserDel(&onDelUserNotifier);
199
200 list<user_iter>::iterator users_iter;
201 users_iter = usersList.begin();
202 while (users_iter != usersList.end())
203     {
204     UnSetUserNotifiers(*users_iter);
205     users_iter++;
206     }
207
208 return 0;
209 }
210 //-----------------------------------------------------------------------------
211 bool PING::IsRunning()
212 {
213 return isRunning;
214 }
215 //-----------------------------------------------------------------------------
216 void * PING::Run(void * d)
217 {
218 PING * ping = (PING*)d;
219 ping->isRunning = true;
220 list<user_iter>::iterator iter;
221 uint32_t ip;
222 time_t t;
223
224 while (ping->nonstop)
225     {
226     iter = ping->usersList.begin();
227         {
228         STG_LOCKER lock(&ping->mutex, __FILE__, __LINE__);
229         while (iter != ping->usersList.end())
230             {
231             if ((*iter)->property.ips.ConstData().OnlyOneIP())
232                 {
233                 ip = (*iter)->property.ips.ConstData()[0].ip;
234                 if (ping->pinger.GetIPTime(ip, &t) == 0)
235                     {
236                     if (t)
237                         (*iter)->UpdatePingTime(t);
238                     }
239                 }
240             else
241                 {
242                 ip = (*iter)->GetCurrIP();
243                 if (ip)
244                     {
245                     if (ping->pinger.GetIPTime(ip, &t) == 0)
246                         {
247                         if (t)
248                             (*iter)->UpdatePingTime(t);
249                         }
250                     }
251                 }
252             iter++;
253             }
254         }
255     for (int i = 0; i < 100; i++)
256         {
257         if (ping->nonstop)
258             {
259             usleep((10000*ping->pingSettings.GetPingDelay())/3 + 50000);
260             }
261         }
262     }
263 ping->isRunning = false;
264 return NULL;
265 }
266 //-----------------------------------------------------------------------------
267 uint16_t PING::GetStartPosition() const
268 {
269 return 100;
270 }
271 //-----------------------------------------------------------------------------
272 uint16_t PING::GetStopPosition() const
273 {
274 return 100;
275 }
276 //-----------------------------------------------------------------------------
277 void PING::SetUserNotifiers(user_iter u)
278 {
279 CHG_CURRIP_NOTIFIER_PING ChgCurrIPNotifier(*this, u);
280 CHG_IPS_NOTIFIER_PING ChgIPNotifier(*this, u);
281
282 ChgCurrIPNotifierList.push_front(ChgCurrIPNotifier);
283 ChgIPNotifierList.push_front(ChgIPNotifier);
284
285 u->AddCurrIPAfterNotifier(&(*ChgCurrIPNotifierList.begin()));
286 u->property.ips.AddAfterNotifier(&(*ChgIPNotifierList.begin()));
287 }
288 //-----------------------------------------------------------------------------
289 void PING::UnSetUserNotifiers(user_iter u)
290 {
291 // ---          CurrIP              ---
292 IS_CONTAINS_USER<CHG_CURRIP_NOTIFIER_PING> IsContainsUserCurrIP(u);
293 IS_CONTAINS_USER<CHG_IPS_NOTIFIER_PING> IsContainsUserIP(u);
294
295 list<CHG_CURRIP_NOTIFIER_PING>::iterator currIPter;
296 list<CHG_IPS_NOTIFIER_PING>::iterator IPIter;
297
298 currIPter = find_if(ChgCurrIPNotifierList.begin(),
299                     ChgCurrIPNotifierList.end(),
300                     IsContainsUserCurrIP);
301
302 if (currIPter != ChgCurrIPNotifierList.end())
303     {
304     currIPter->GetUser()->DelCurrIPAfterNotifier(&(*currIPter));
305     ChgCurrIPNotifierList.erase(currIPter);
306     }
307 // ---         CurrIP end          ---
308
309 // ---          IP              ---
310 IPIter = find_if(ChgIPNotifierList.begin(),
311                  ChgIPNotifierList.end(),
312                  IsContainsUserIP);
313
314 if (IPIter != ChgIPNotifierList.end())
315     {
316     IPIter->GetUser()->property.ips.DelAfterNotifier(&(*IPIter));
317     ChgIPNotifierList.erase(IPIter);
318     }
319 // ---          IP end          ---
320 }
321 //-----------------------------------------------------------------------------
322 void PING::GetUsers()
323 {
324 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
325
326 user_iter u;
327 int h = users->OpenSearch();
328 if (!h)
329     {
330     printfd(__FILE__, "users->OpenSearch() error\n");
331     return;
332     }
333
334 while (users->SearchNext(h, &u) == 0)
335     {
336     usersList.push_back(u);
337     SetUserNotifiers(u);
338     if (u->property.ips.ConstData().OnlyOneIP())
339         {
340         pinger.AddIP(u->property.ips.ConstData()[0].ip);
341         }
342     else
343         {
344         uint32_t ip = u->GetCurrIP();
345         if (ip)
346             {
347             pinger.AddIP(ip);
348             }
349         }
350     }
351
352 users->CloseSearch(h);
353 }
354 //-----------------------------------------------------------------------------
355 void PING::AddUser(user_iter u)
356 {
357 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
358
359 SetUserNotifiers(u);
360 usersList.push_back(u);
361 }
362 //-----------------------------------------------------------------------------
363 void PING::DelUser(user_iter u)
364 {
365 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
366
367 UnSetUserNotifiers(u);
368
369 list<user_iter>::iterator users_iter;
370 users_iter = usersList.begin();
371
372 while (users_iter != usersList.end())
373     {
374     if (u == *users_iter)
375         {
376         usersList.erase(users_iter);
377         break;
378         }
379     users_iter++;
380     }
381 }
382 //-----------------------------------------------------------------------------
383 void CHG_CURRIP_NOTIFIER_PING::Notify(const uint32_t & oldIP, const uint32_t & newIP)
384 {
385 ping.pinger.DelIP(oldIP);
386 if (newIP)
387     {
388     ping.pinger.AddIP(newIP);
389     }
390 }
391 //-----------------------------------------------------------------------------
392 void CHG_IPS_NOTIFIER_PING::Notify(const USER_IPS & oldIPS, const USER_IPS & newIPS)
393 {
394 if (oldIPS.OnlyOneIP())
395     {
396     ping.pinger.DelIP(oldIPS[0].ip);
397     }
398
399 if (newIPS.OnlyOneIP())
400     {
401     ping.pinger.AddIP(newIPS[0].ip);
402     }
403 }
404 //-----------------------------------------------------------------------------
405 void ADD_USER_NONIFIER_PING::Notify(const user_iter & user)
406 {
407 ping.AddUser(user);
408 }
409 //-----------------------------------------------------------------------------
410 void DEL_USER_NONIFIER_PING::Notify(const user_iter & user)
411 {
412 ping.DelUser(user);
413 }
414 //-----------------------------------------------------------------------------