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