]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/other/ping/ping.cpp
Check that IP is not in use before changing.
[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())
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     : errorStr(),
71       pingSettings(),
72       settings(),
73       users(NULL),
74       usersList(),
75       thread(),
76       mutex(),
77       nonstop(false),
78       isRunning(false),
79       pinger(),
80       ChgCurrIPNotifierList(),
81       ChgIPNotifierList(),
82       onAddUserNotifier(*this),
83       onDelUserNotifier(*this),
84       logger(GetPluginLogger(GetStgLogger(), "ping"))
85 {
86 pthread_mutex_init(&mutex, NULL);
87 }
88 //-----------------------------------------------------------------------------
89 PING::~PING()
90 {
91 pthread_mutex_destroy(&mutex);
92 }
93 //-----------------------------------------------------------------------------
94 int PING::ParseSettings()
95 {
96 int ret = pingSettings.ParseSettings(settings);
97 if (ret)
98     errorStr = pingSettings.GetStrError();
99 return ret;
100 }
101 //-----------------------------------------------------------------------------
102 int PING::Start()
103 {
104 GetUsers();
105
106 users->AddNotifierUserAdd(&onAddUserNotifier);
107 users->AddNotifierUserDel(&onDelUserNotifier);
108
109 nonstop = true;
110
111 pinger.SetDelayTime(pingSettings.GetPingDelay());
112 pinger.Start();
113
114 if (pthread_create(&thread, NULL, Run, this))
115     {
116     errorStr = "Cannot start thread.";
117     logger("Cannot create thread.");
118     printfd(__FILE__, "Cannot start thread\n");
119     return -1;
120     }
121
122 return 0;
123 }
124 //-----------------------------------------------------------------------------
125 int PING::Stop()
126 {
127 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
128
129 if (!isRunning)
130     return 0;
131
132 pinger.Stop();
133 nonstop = false;
134 //5 seconds to thread stops itself
135 struct timespec ts = {0, 200000000};
136 for (int i = 0; i < 25; i++)
137     {
138     if (!isRunning)
139         break;
140
141     nanosleep(&ts, NULL);
142     }
143
144 users->DelNotifierUserAdd(&onAddUserNotifier);
145 users->DelNotifierUserDel(&onDelUserNotifier);
146
147 std::list<USER_PTR>::iterator users_iter;
148 users_iter = usersList.begin();
149 while (users_iter != usersList.end())
150     {
151     UnSetUserNotifiers(*users_iter);
152     ++users_iter;
153     }
154
155 if (isRunning)
156     return -1;
157
158 return 0;
159 }
160 //-----------------------------------------------------------------------------
161 bool PING::IsRunning()
162 {
163 return isRunning;
164 }
165 //-----------------------------------------------------------------------------
166 void * PING::Run(void * d)
167 {
168 sigset_t signalSet;
169 sigfillset(&signalSet);
170 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
171
172 PING * ping = static_cast<PING *>(d);
173 ping->isRunning = true;
174
175 long delay = (10000000 * ping->pingSettings.GetPingDelay()) / 3 + 50000000;
176  
177 while (ping->nonstop)
178     {
179     std::list<USER_PTR>::iterator iter = ping->usersList.begin();
180         {
181         STG_LOCKER lock(&ping->mutex, __FILE__, __LINE__);
182         while (iter != ping->usersList.end())
183             {
184             if ((*iter)->GetProperty().ips.ConstData().OnlyOneIP())
185                 {
186                 uint32_t ip = (*iter)->GetProperty().ips.ConstData()[0].ip;
187                 time_t t;
188                 if (ping->pinger.GetIPTime(ip, &t) == 0)
189                     {
190                     if (t)
191                         (*iter)->UpdatePingTime(t);
192                     }
193                 }
194             else
195                 {
196                 uint32_t ip = (*iter)->GetCurrIP();
197                 if (ip)
198                     {
199                     time_t t;
200                     if (ping->pinger.GetIPTime(ip, &t) == 0)
201                         {
202                         if (t)
203                             (*iter)->UpdatePingTime(t);
204                         }
205                     }
206                 }
207             ++iter;
208             }
209         }
210     struct timespec ts = {delay / 1000000000, delay % 1000000000};
211     for (int i = 0; i < 100; i++)
212         {
213         if (ping->nonstop)
214             {
215             nanosleep(&ts, NULL);
216             }
217         }
218     }
219
220 ping->isRunning = false;
221 return NULL;
222 }
223 //-----------------------------------------------------------------------------
224 void PING::SetUserNotifiers(USER_PTR u)
225 {
226 CHG_CURRIP_NOTIFIER_PING ChgCurrIPNotifier(*this, u);
227 CHG_IPS_NOTIFIER_PING ChgIPNotifier(*this, u);
228
229 ChgCurrIPNotifierList.push_front(ChgCurrIPNotifier);
230 ChgIPNotifierList.push_front(ChgIPNotifier);
231
232 u->AddCurrIPAfterNotifier(&(*ChgCurrIPNotifierList.begin()));
233 u->GetProperty().ips.AddAfterNotifier(&(*ChgIPNotifierList.begin()));
234 }
235 //-----------------------------------------------------------------------------
236 void PING::UnSetUserNotifiers(USER_PTR u)
237 {
238 // ---          CurrIP              ---
239 IS_CONTAINS_USER<CHG_CURRIP_NOTIFIER_PING> IsContainsUserCurrIP(u);
240 IS_CONTAINS_USER<CHG_IPS_NOTIFIER_PING> IsContainsUserIP(u);
241
242 std::list<CHG_CURRIP_NOTIFIER_PING>::iterator currIPter;
243 std::list<CHG_IPS_NOTIFIER_PING>::iterator IPIter;
244
245 currIPter = find_if(ChgCurrIPNotifierList.begin(),
246                     ChgCurrIPNotifierList.end(),
247                     IsContainsUserCurrIP);
248
249 if (currIPter != ChgCurrIPNotifierList.end())
250     {
251     currIPter->GetUser()->DelCurrIPAfterNotifier(&(*currIPter));
252     ChgCurrIPNotifierList.erase(currIPter);
253     }
254 // ---         CurrIP end          ---
255
256 // ---          IP              ---
257 IPIter = find_if(ChgIPNotifierList.begin(),
258                  ChgIPNotifierList.end(),
259                  IsContainsUserIP);
260
261 if (IPIter != ChgIPNotifierList.end())
262     {
263     IPIter->GetUser()->GetProperty().ips.DelAfterNotifier(&(*IPIter));
264     ChgIPNotifierList.erase(IPIter);
265     }
266 // ---          IP end          ---
267 }
268 //-----------------------------------------------------------------------------
269 void PING::GetUsers()
270 {
271 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
272
273 USER_PTR u;
274 int h = users->OpenSearch();
275 assert(h && "USERS::OpenSearch is always correct");
276
277 while (users->SearchNext(h, &u) == 0)
278     {
279     usersList.push_back(u);
280     SetUserNotifiers(u);
281     if (u->GetProperty().ips.ConstData().OnlyOneIP())
282         {
283         pinger.AddIP(u->GetProperty().ips.ConstData()[0].ip);
284         }
285     else
286         {
287         uint32_t ip = u->GetCurrIP();
288         if (ip)
289             {
290             pinger.AddIP(ip);
291             }
292         }
293     }
294
295 users->CloseSearch(h);
296 }
297 //-----------------------------------------------------------------------------
298 void PING::AddUser(USER_PTR u)
299 {
300 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
301
302 SetUserNotifiers(u);
303 usersList.push_back(u);
304 }
305 //-----------------------------------------------------------------------------
306 void PING::DelUser(USER_PTR u)
307 {
308 STG_LOCKER lock(&mutex, __FILE__, __LINE__);
309
310 UnSetUserNotifiers(u);
311
312 std::list<USER_PTR>::iterator users_iter;
313 users_iter = usersList.begin();
314
315 while (users_iter != usersList.end())
316     {
317     if (u == *users_iter)
318         {
319         usersList.erase(users_iter);
320         break;
321         }
322     ++users_iter;
323     }
324 }
325 //-----------------------------------------------------------------------------
326 void CHG_CURRIP_NOTIFIER_PING::Notify(const uint32_t & oldIP, const uint32_t & newIP)
327 {
328 ping.pinger.DelIP(oldIP);
329 if (newIP)
330     {
331     ping.pinger.AddIP(newIP);
332     }
333 }
334 //-----------------------------------------------------------------------------
335 void CHG_IPS_NOTIFIER_PING::Notify(const USER_IPS & oldIPS, const USER_IPS & newIPS)
336 {
337 if (oldIPS.OnlyOneIP())
338     {
339     ping.pinger.DelIP(oldIPS[0].ip);
340     }
341
342 if (newIPS.OnlyOneIP())
343     {
344     ping.pinger.AddIP(newIPS[0].ip);
345     }
346 }
347 //-----------------------------------------------------------------------------
348 void ADD_USER_NONIFIER_PING::Notify(const USER_PTR & user)
349 {
350 ping.AddUser(user);
351 }
352 //-----------------------------------------------------------------------------
353 void DEL_USER_NONIFIER_PING::Notify(const USER_PTR & user)
354 {
355 ping.DelUser(user);
356 }
357 //-----------------------------------------------------------------------------