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