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