]> git.stg.codes - stg.git/blob - stglibs/pinger.lib/pinger.cpp
Simplified admins API
[stg.git] / stglibs / pinger.lib / pinger.cpp
1 #include <stdlib.h>
2 #include <pthread.h>
3 #include <signal.h>
4 #include <netdb.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <arpa/inet.h>
9 #include <sys/time.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <errno.h>
14 #include <math.h>
15 #include <stdio.h>
16
17 #include "pinger.h"
18 #include "stg/common.h"
19 #include "stg/locker.h"
20
21 #ifdef STG_TIME
22 extern volatile time_t stgTime;
23 #endif
24
25 //-----------------------------------------------------------------------------
26 STG_PINGER::STG_PINGER(time_t d)
27     : delay(d),
28       nonstop(false),
29       isRunningRecver(false),
30       isRunningSender(false),
31       sendSocket(-1),
32       recvSocket(-1),
33       pid(0)
34 {
35     pthread_mutex_init(&mutex, NULL);
36     memset(&pmSend, 0, sizeof(pmSend));
37 }
38 //-----------------------------------------------------------------------------
39 STG_PINGER::~STG_PINGER()
40 {
41     pthread_mutex_destroy(&mutex);
42 }
43 //-----------------------------------------------------------------------------
44 int STG_PINGER::Start()
45 {
46     struct protoent *proto = NULL;
47     proto = getprotobyname("ICMP");
48     sendSocket = socket(PF_INET, SOCK_RAW, proto->p_proto);
49     recvSocket = socket(PF_INET, SOCK_RAW, proto->p_proto);
50     nonstop = true;
51     pid = (int) getpid() % 65535;
52     if (sendSocket < 0 || recvSocket < 0)
53         {
54         errorStr = "Cannot create socket.";
55         return -1;
56         }
57
58     if (pthread_create(&sendThread, NULL, RunSendPing, this))
59         {
60         errorStr = "Cannot create send thread.";
61         return -1;
62         }
63
64     if (pthread_create(&recvThread, NULL, RunRecvPing, this))
65         {
66         errorStr = "Cannot create recv thread.";
67         return -1;
68         }
69
70     return 0;
71 }
72 //-----------------------------------------------------------------------------
73 int STG_PINGER::Stop()
74 {
75     close(recvSocket);
76     nonstop = false;
77     if (isRunningRecver)
78         {
79         //5 seconds to thread stops itself
80         for (size_t i = 0; i < 25; i++)
81             {
82             if (i % 5 == 0)
83                 SendPing(0x0100007f);//127.0.0.1
84
85             if (!isRunningRecver)
86                 break;
87
88             usleep(200000);
89             }
90
91         //after 5 seconds waiting thread still running. now killing it
92         if (isRunningRecver)
93             {
94             if (pthread_kill(recvThread, SIGINT))
95                 {
96                 errorStr = "Cannot kill thread.";
97                 return -1;
98                 }
99             }
100         }
101
102     if (isRunningSender)
103         {
104         //5 seconds to thread stops itself
105         for (size_t i = 0; i < 25; i++)
106             {
107             if (!isRunningSender)
108                 break;
109
110             usleep(200000);
111             }
112
113         //after 5 seconds waiting thread still running. now killing it
114         if (isRunningSender)
115             {
116             if (pthread_kill(sendThread, SIGINT))
117                 {
118                 errorStr = "Cannot kill thread.";
119                 return -1;
120                 }
121             }
122         }
123
124     close(sendSocket);
125     return 0;
126 }
127 //-----------------------------------------------------------------------------
128 void STG_PINGER::AddIP(uint32_t ip)
129 {
130     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
131     ipToAdd.push_back(ip);
132 }
133 //-----------------------------------------------------------------------------
134 void STG_PINGER::DelIP(uint32_t ip)
135 {
136     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
137     ipToDel.push_back(ip);
138 }
139 //-----------------------------------------------------------------------------
140 void STG_PINGER::RealAddIP()
141     {
142     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
143
144     std::list<uint32_t>::iterator iter;
145     iter = ipToAdd.begin();
146     while (iter != ipToAdd.end())
147         {
148         pingIP.insert(std::make_pair(*iter, 0));
149         ++iter;
150         }
151     ipToAdd.erase(ipToAdd.begin(), ipToAdd.end());
152     }
153 //-----------------------------------------------------------------------------
154 void STG_PINGER::RealDelIP()
155 {
156     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
157
158     std::list<uint32_t>::iterator iter;
159     std::multimap<uint32_t, time_t>::iterator treeIter;
160     iter = ipToDel.begin();
161     while (iter != ipToDel.end())
162         {
163         treeIter = pingIP.find(*iter);
164         if (treeIter != pingIP.end())
165             pingIP.erase(treeIter);
166
167         ++iter;
168         }
169     ipToDel.erase(ipToDel.begin(), ipToDel.end());
170 }
171 //-----------------------------------------------------------------------------
172 int STG_PINGER::GetPingIPNum() const
173 {
174     return pingIP.size();
175 }
176 //-----------------------------------------------------------------------------
177 void STG_PINGER::PrintAllIP()
178 {
179     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
180     std::multimap<uint32_t, time_t>::iterator iter;
181     iter = pingIP.begin();
182     while (iter != pingIP.end())
183         {
184         uint32_t ip = iter->first;
185         time_t t = iter->second;
186         std::string s;
187         x2str(t, s);
188         printf("ip = %s, time = %9s\n", inet_ntostring(ip).c_str(), s.c_str());
189         ++iter;
190         }
191
192 }
193 //-----------------------------------------------------------------------------
194 int STG_PINGER::GetIPTime(uint32_t ip, time_t * t) const
195 {
196     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
197     std::multimap<uint32_t, time_t>::const_iterator treeIter;
198
199     treeIter = pingIP.find(ip);
200     if (treeIter == pingIP.end())
201         return -1;
202
203     *t = treeIter->second;
204     return 0;
205 }
206 //-----------------------------------------------------------------------------
207 uint16_t STG_PINGER::PingCheckSum(void * data, int len)
208 {
209     unsigned short * buf = (unsigned short *)data;
210     unsigned int sum = 0;
211     unsigned short result;
212
213     for ( sum = 0; len > 1; len -= 2 )
214         sum += *buf++;
215
216     if ( len == 1 )
217         sum += *(unsigned char*)buf;
218
219     sum = (sum >> 16) + (sum & 0xFFFF);
220     sum += (sum >> 16);
221     result = ~sum;
222     return result;
223 }
224 //-----------------------------------------------------------------------------
225 int STG_PINGER::SendPing(uint32_t ip)
226 {
227     struct sockaddr_in addr;
228     memset(&addr, 0, sizeof(addr));
229     addr.sin_family = AF_INET;
230     addr.sin_port = 0;
231     addr.sin_addr.s_addr = ip;
232
233     memset(&pmSend, 0, sizeof(pmSend));
234     pmSend.hdr.type = ICMP_ECHO;
235     pmSend.hdr.un.echo.id = pid;
236     memcpy(pmSend.msg, &ip, sizeof(ip));
237
238     pmSend.hdr.checksum = PingCheckSum(&pmSend, sizeof(pmSend));
239
240     if (sendto(sendSocket, &pmSend, sizeof(pmSend), 0, (sockaddr *)&addr, sizeof(addr)) <= 0 )
241         {
242         errorStr = "Send ping error: " + std::string(strerror(errno));
243         return -1;
244         }
245
246
247     return 0;
248 }
249 //-----------------------------------------------------------------------------
250 uint32_t STG_PINGER::RecvPing()
251 {
252     struct sockaddr_in addr;
253     uint32_t ipAddr = 0;
254
255     char buf[128];
256     memset(buf, 0, sizeof(buf));
257     int bytes;
258     socklen_t len = sizeof(addr);
259
260     bytes = recvfrom(recvSocket, &buf, sizeof(buf), 0, (struct sockaddr*)&addr, &len);
261     if (bytes > 0)
262         {
263         struct IP_HDR * ip = (struct IP_HDR *)buf;
264         struct ICMP_HDR *icmp = (struct ICMP_HDR *)(buf + ip->ihl * 4);
265
266         if (icmp->un.echo.id != pid)
267             return 0;
268
269         ipAddr = *(uint32_t*)(buf + sizeof(ICMP_HDR) + ip->ihl * 4);
270         }
271
272     return ipAddr;
273 }
274 //-----------------------------------------------------------------------------
275 void * STG_PINGER::RunSendPing(void * d)
276 {
277     STG_PINGER * pinger = static_cast<STG_PINGER *>(d);
278
279     pinger->isRunningSender = true;
280     time_t lastPing = 0;
281     while (pinger->nonstop)
282         {
283         pinger->RealAddIP();
284         pinger->RealDelIP();
285
286         std::multimap<uint32_t, time_t>::iterator iter;
287         iter = pinger->pingIP.begin();
288         while (iter != pinger->pingIP.end())
289             {
290             pinger->SendPing(iter->first);
291             ++iter;
292             }
293
294         time_t currTime;
295
296         #ifdef STG_TIME
297         lastPing = stgTime;
298         currTime = stgTime;
299         #else
300         currTime = lastPing = time(NULL);
301         #endif
302
303         while (currTime - lastPing < pinger->delay && pinger->nonstop)
304             {
305             #ifdef STG_TIME
306             currTime = stgTime;
307             #else
308             currTime = time(NULL);
309             #endif
310             usleep(20000);
311             }
312         }
313
314     pinger->isRunningSender = false;
315
316     return NULL;
317 }
318 //-----------------------------------------------------------------------------
319 void * STG_PINGER::RunRecvPing(void * d)
320 {
321     STG_PINGER * pinger = static_cast<STG_PINGER *>(d);
322
323     pinger->isRunningRecver = true;
324
325     while (pinger->nonstop)
326         {
327         uint32_t ip = pinger->RecvPing();
328
329         if (ip)
330             {
331             std::multimap<uint32_t, time_t>::iterator treeIterUpper = pinger->pingIP.upper_bound(ip);
332             std::multimap<uint32_t, time_t>::iterator treeIterLower = pinger->pingIP.lower_bound(ip);
333             while (treeIterUpper != treeIterLower)
334                 {
335                 #ifdef STG_TIME
336                 treeIterLower->second = stgTime;
337                 #else
338                 treeIterLower->second = time(NULL);
339                 #endif
340                 ++treeIterLower;
341                 }
342             }
343
344         }
345     pinger->isRunningRecver = false;
346     return NULL;
347 }
348 //-----------------------------------------------------------------------------