]> git.stg.codes - stg.git/blob - stglibs/pinger.lib/pinger.cpp
Проведен рефакторинг библиотеки поддержки ICMP, некоторые методы сделаны
[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         int i;
80         for (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             //printf("recvThread killed\n");
100             }
101         }
102
103     if (isRunningSender)
104         {
105         //5 seconds to thread stops itself
106         int i;
107         for (i = 0; i < 25; i++)
108             {
109             if (!isRunningSender)
110                 break;
111
112             usleep(200000);
113             }
114
115         //after 5 seconds waiting thread still running. now killing it
116         if (isRunningSender)
117             {
118             //if (pthread_kill(sendThread, SIGINT))
119             //    {
120                 errorStr = "Cannot kill thread.";
121                 return -1;
122             //    }
123             //printf("sendThread killed\n");
124             }
125         }
126
127     close(sendSocket);
128     return 0;
129 }
130 //-----------------------------------------------------------------------------
131 void STG_PINGER::AddIP(uint32_t ip)
132 {
133     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
134     //printf("AddIP\n");
135     ipToAdd.push_back(ip);
136 }
137 //-----------------------------------------------------------------------------
138 void STG_PINGER::DelIP(uint32_t ip)
139 {
140     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
141     //printf("DelIP\n");
142     ipToDel.push_back(ip);
143 }
144 //-----------------------------------------------------------------------------
145 void STG_PINGER::RealAddIP()
146     {
147     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
148
149     list<uint32_t>::iterator iter;
150     iter = ipToAdd.begin();
151     while (iter != ipToAdd.end())
152         {
153         /*packets.insert(pair<RAW_PACKET, PACKET_EXTRA_DATA>(rawPacket, ed));*/
154         //pingIP[*iter] = 0;
155         pingIP.insert(pair<uint32_t, time_t>(*iter, 0));
156         iter++;
157         }
158     ipToAdd.erase(ipToAdd.begin(), ipToAdd.end());
159     }
160 //-----------------------------------------------------------------------------
161 void STG_PINGER::RealDelIP()
162 {
163     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
164
165     list<uint32_t>::iterator iter;
166     multimap<uint32_t, time_t>::iterator treeIter;
167     iter = ipToDel.begin();
168     while (iter != ipToDel.end())
169         {
170         treeIter = pingIP.find(*iter);
171         //printf("Found %X\n", *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::GetAllIP(vector<PING_IP_TIME> *) const
186 {
187     //STG_LOCKER lock(&mutex, __FILE__, __LINE__);
188 }*/
189 //-----------------------------------------------------------------------------
190 void STG_PINGER::PrintAllIP()
191 {
192     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
193     multimap<uint32_t, time_t>::iterator iter;
194     iter = pingIP.begin();
195     while (iter != pingIP.end())
196         {
197         uint32_t ip = iter->first;
198         time_t t = iter->second;
199         string s;
200         x2str(t, s);
201         printf("ip = %s, time = %9s\n", inet_ntostring(ip).c_str(), s.c_str());
202         iter++;
203         }
204
205 }
206 //-----------------------------------------------------------------------------
207 int STG_PINGER::GetIPTime(uint32_t ip, time_t * t) const
208 {
209     STG_LOCKER lock(&mutex, __FILE__, __LINE__);
210     multimap<uint32_t, time_t>::const_iterator treeIter;
211
212     treeIter = pingIP.find(ip);
213     if (treeIter == pingIP.end())
214         return -1;
215
216     *t = treeIter->second;
217     return 0;
218 }
219 //-----------------------------------------------------------------------------
220 void STG_PINGER::SetDelayTime(time_t d)
221 {
222     delay = d;
223 }
224 //-----------------------------------------------------------------------------
225 time_t STG_PINGER::GetDelayTime() const
226 {
227     return delay;
228 }
229 //-----------------------------------------------------------------------------
230 string STG_PINGER::GetStrError() const
231 {
232     return errorStr;
233 }
234 //-----------------------------------------------------------------------------
235 uint16_t STG_PINGER::PingCheckSum(void * data, int len)
236 {
237     unsigned short * buf = (unsigned short *)data;
238     unsigned int sum = 0;
239     unsigned short result;
240
241     for ( sum = 0; len > 1; len -= 2 )
242         sum += *buf++;
243
244     if ( len == 1 )
245         sum += *(unsigned char*)buf;
246
247     sum = (sum >> 16) + (sum & 0xFFFF);
248     sum += (sum >> 16);
249     result = ~sum;
250     return result;
251 }
252 //-----------------------------------------------------------------------------
253 int STG_PINGER::SendPing(uint32_t ip)
254 {
255     struct sockaddr_in addr;
256     //printf("SendPing %X \n", ip);
257     memset(&addr, 0, sizeof(addr));
258     addr.sin_family = AF_INET;
259     addr.sin_port = 0;
260     addr.sin_addr.s_addr = ip;
261
262     memset(&pmSend, 0, sizeof(pmSend));
263     pmSend.hdr.type = ICMP_ECHO;
264     pmSend.hdr.un.echo.id = pid;
265     memcpy(pmSend.msg, &ip, sizeof(ip));
266
267     pmSend.hdr.checksum = PingCheckSum(&pmSend, sizeof(pmSend));
268
269     if (sendto(sendSocket, &pmSend, sizeof(pmSend), 0, (sockaddr *)&addr, sizeof(addr)) <= 0 )
270         {
271         errorStr = "Send ping error: " + string(strerror(errno));
272         return -1;
273         }
274
275
276     return 0;
277 }
278 //-----------------------------------------------------------------------------
279 uint32_t STG_PINGER::RecvPing()
280 {
281     struct sockaddr_in addr;
282     uint32_t ipAddr = 0;
283
284     char buf[128];
285     memset(buf, 0, sizeof(buf));
286     int bytes;
287     socklen_t len = sizeof(addr);
288
289     bytes = recvfrom(recvSocket, &buf, sizeof(buf), 0, (struct sockaddr*)&addr, &len);
290     //printf("recvfrom\n");
291     if (bytes > 0)
292         {
293         struct IP_HDR * ip = (struct IP_HDR *)buf;
294         struct ICMP_HDR *icmp = (struct ICMP_HDR *)(buf + ip->ihl * 4);
295
296         //printf("icmp->un.echo.id=%d,  pid=%d, tid: %d\n", icmp->un.echo.id, pid);
297         if (icmp->un.echo.id != pid)
298             return 0;
299
300         ipAddr = *(uint32_t*)(buf + sizeof(ICMP_HDR) + ip->ihl * 4);
301         }
302
303     return ipAddr;
304 }
305 //-----------------------------------------------------------------------------
306 void * STG_PINGER::RunSendPing(void * d)
307 {
308     STG_PINGER * pinger = (STG_PINGER*)d;
309
310     pinger->isRunningSender = true;
311     time_t lastPing = 0;
312     while (pinger->nonstop)
313         {
314         pinger->RealAddIP();
315         pinger->RealDelIP();
316
317         multimap<uint32_t, time_t>::iterator iter;
318         iter = pinger->pingIP.begin();
319         while (iter != pinger->pingIP.end())
320             {
321             uint32_t ip = iter->first;
322             pinger->SendPing(ip);
323             iter++;
324             }
325
326         time_t currTime;
327
328         #ifdef STG_TIME
329         lastPing = stgTime;
330         currTime = stgTime;
331         #else
332         currTime = lastPing = time(NULL);
333         #endif
334
335         while (currTime - lastPing < pinger->delay && pinger->nonstop)
336             {
337             #ifdef STG_TIME
338             currTime = stgTime;
339             #else
340             currTime = time(NULL);
341             #endif
342             usleep(20000);
343             }
344         //printf("new ping cycle\n");
345         }
346
347     pinger->isRunningSender = false;
348
349     return NULL;
350 }
351 //-----------------------------------------------------------------------------
352 void * STG_PINGER::RunRecvPing(void * d)
353 {
354     STG_PINGER * pinger = (STG_PINGER*)d;
355
356     pinger->isRunningRecver = true;
357
358     uint32_t ip;
359     multimap<uint32_t, time_t>::iterator treeIterLower;
360     multimap<uint32_t, time_t>::iterator treeIterUpper;
361
362     while (pinger->nonstop)
363         {
364         ip = pinger->RecvPing();
365
366         if (ip)
367             {
368             //printf("RecvPing %X\n", ip);
369             treeIterUpper = pinger->pingIP.upper_bound(ip);
370             treeIterLower = pinger->pingIP.lower_bound(ip);
371             int i = 0;
372             while (treeIterUpper != treeIterLower)
373             //treeIterUpper = pinger->pingIP.find(ip);
374             //if (treeIterUpper != pinger->pingIP.end())
375                 {
376                 //printf("+++! time=%d %X i=%d !+++\n", time(NULL), ip, i);
377                 //printf("--- time=%d ---\n", time(NULL));
378                 #ifdef STG_TIME
379                 treeIterLower->second = stgTime;
380                 #else
381                 treeIterLower->second = time(NULL);
382                 #endif
383                 ++treeIterLower;
384                 i++;
385                 }
386             }
387
388         }
389     pinger->isRunningRecver = false;
390     return NULL;
391 }
392 //-----------------------------------------------------------------------------