4 #include <sys/socket.h>
5 #include <netinet/in.h>
18 #include "stg/common.h"
19 #include "stg/locker.h"
21 #include "stg/pinger.h"
24 extern volatile time_t stgTime;
27 //-----------------------------------------------------------------------------
28 STG_PINGER::STG_PINGER(time_t d)
31 m_isRunningRecver(false),
32 m_isRunningSender(false),
37 pthread_mutex_init(&m_mutex, NULL);
38 memset(&m_pmSend, 0, sizeof(m_pmSend));
40 //-----------------------------------------------------------------------------
41 STG_PINGER::~STG_PINGER()
43 pthread_mutex_destroy(&m_mutex);
45 //-----------------------------------------------------------------------------
46 int STG_PINGER::Start()
48 struct protoent *proto = NULL;
49 proto = getprotobyname("ICMP");
50 m_sendSocket = socket(PF_INET, SOCK_RAW, proto->p_proto);
51 m_recvSocket = socket(PF_INET, SOCK_RAW, proto->p_proto);
53 m_pid = static_cast<uint32_t>(getpid()) % 65535;
54 if (m_sendSocket < 0 || m_recvSocket < 0)
56 m_errorStr = "Cannot create socket.";
60 if (pthread_create(&m_sendThread, NULL, RunSendPing, this))
62 m_errorStr = "Cannot create send thread.";
66 if (pthread_create(&m_recvThread, NULL, RunRecvPing, this))
68 m_errorStr = "Cannot create recv thread.";
74 //-----------------------------------------------------------------------------
75 int STG_PINGER::Stop()
79 if (m_isRunningRecver)
81 //5 seconds to thread stops itself
82 for (size_t i = 0; i < 25; i++)
85 SendPing(0x0100007f);//127.0.0.1
87 if (!m_isRunningRecver)
90 struct timespec ts = {0, 200000000};
95 if (m_isRunningSender)
97 //5 seconds to thread stops itself
98 for (size_t i = 0; i < 25; i++)
100 if (!m_isRunningSender)
103 struct timespec ts = {0, 200000000};
104 nanosleep(&ts, NULL);
110 if (m_isRunningSender || m_isRunningRecver)
115 //-----------------------------------------------------------------------------
116 void STG_PINGER::AddIP(uint32_t ip)
118 STG_LOCKER lock(&m_mutex);
119 m_ipToAdd.push_back(ip);
121 //-----------------------------------------------------------------------------
122 void STG_PINGER::DelIP(uint32_t ip)
124 STG_LOCKER lock(&m_mutex);
125 m_ipToDel.push_back(ip);
127 //-----------------------------------------------------------------------------
128 void STG_PINGER::RealAddIP()
130 STG_LOCKER lock(&m_mutex);
132 auto iter = m_ipToAdd.begin();
133 while (iter != m_ipToAdd.end())
135 m_pingIP.insert(std::make_pair(*iter, 0));
138 m_ipToAdd.erase(m_ipToAdd.begin(), m_ipToAdd.end());
140 //-----------------------------------------------------------------------------
141 void STG_PINGER::RealDelIP()
143 STG_LOCKER lock(&m_mutex);
145 auto iter = m_ipToDel.begin();
146 while (iter != m_ipToDel.end())
148 auto treeIter = m_pingIP.find(*iter);
149 if (treeIter != m_pingIP.end())
150 m_pingIP.erase(treeIter);
154 m_ipToDel.erase(m_ipToDel.begin(), m_ipToDel.end());
156 //-----------------------------------------------------------------------------
157 void STG_PINGER::PrintAllIP()
159 STG_LOCKER lock(&m_mutex);
160 auto iter = m_pingIP.begin();
161 while (iter != m_pingIP.end())
163 uint32_t ip = iter->first;
164 time_t t = iter->second;
165 std::string s = std::to_string(t);
166 printf("ip = %s, time = %9s\n", inet_ntostring(ip).c_str(), s.c_str());
171 //-----------------------------------------------------------------------------
172 int STG_PINGER::GetIPTime(uint32_t ip, time_t * t) const
174 STG_LOCKER lock(&m_mutex);
176 auto treeIter = m_pingIP.find(ip);
177 if (treeIter == m_pingIP.end())
180 *t = treeIter->second;
183 //-----------------------------------------------------------------------------
184 uint16_t STG_PINGER::PingCheckSum(void * data, int len)
186 uint16_t * buf = static_cast<uint16_t *>(data);
190 for ( sum = 0; len > 1; len -= 2 )
194 sum += *reinterpret_cast<uint8_t*>(buf);
196 sum = (sum >> 16) + (sum & 0xFFFF);
199 return static_cast<uint16_t>(result);
201 //-----------------------------------------------------------------------------
202 int STG_PINGER::SendPing(uint32_t ip)
204 struct sockaddr_in addr;
205 memset(&addr, 0, sizeof(addr));
206 addr.sin_family = AF_INET;
208 addr.sin_addr.s_addr = ip;
210 memset(&m_pmSend, 0, sizeof(m_pmSend));
211 m_pmSend.hdr.type = ICMP_ECHO;
212 m_pmSend.hdr.un.echo.id = static_cast<uint16_t>(m_pid);
213 memcpy(m_pmSend.msg, &ip, sizeof(ip));
215 m_pmSend.hdr.checksum = PingCheckSum(&m_pmSend, sizeof(m_pmSend));
217 if (sendto(m_sendSocket, &m_pmSend, sizeof(m_pmSend), 0, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) <= 0 )
219 m_errorStr = "Send ping error: " + std::string(strerror(errno));
226 //-----------------------------------------------------------------------------
227 uint32_t STG_PINGER::RecvPing()
229 struct sockaddr_in addr;
233 memset(buf, 0, sizeof(buf));
234 socklen_t len = sizeof(addr);
236 if (recvfrom(m_recvSocket, &buf, sizeof(buf), 0, reinterpret_cast<struct sockaddr*>(&addr), &len))
238 struct IP_HDR * ip = static_cast<struct IP_HDR *>(static_cast<void *>(buf));
239 struct ICMP_HDR *icmp = static_cast<struct ICMP_HDR *>(static_cast<void *>(buf + ip->ihl * 4));
241 if (icmp->un.echo.id != m_pid)
244 ipAddr = *static_cast<uint32_t*>(static_cast<void *>(buf + sizeof(ICMP_HDR) + ip->ihl * 4));
249 //-----------------------------------------------------------------------------
250 void * STG_PINGER::RunSendPing(void * d)
253 sigfillset(&signalSet);
254 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
256 auto* pinger = static_cast<STG_PINGER *>(d);
258 pinger->m_isRunningSender = true;
260 while (pinger->m_nonstop)
265 std::multimap<uint32_t, time_t>::iterator iter;
266 iter = pinger->m_pingIP.begin();
267 while (iter != pinger->m_pingIP.end())
269 pinger->SendPing(iter->first);
279 currTime = lastPing = time(NULL);
282 while (currTime - lastPing < pinger->m_delay && pinger->m_nonstop)
287 currTime = time(NULL);
289 struct timespec ts = {0, 20000000};
290 nanosleep(&ts, NULL);
294 pinger->m_isRunningSender = false;
298 //-----------------------------------------------------------------------------
299 void * STG_PINGER::RunRecvPing(void * d)
302 sigfillset(&signalSet);
303 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
305 auto* pinger = static_cast<STG_PINGER *>(d);
307 pinger->m_isRunningRecver = true;
309 while (pinger->m_nonstop)
311 uint32_t ip = pinger->RecvPing();
315 auto treeIterUpper = pinger->m_pingIP.upper_bound(ip);
316 auto treeIterLower = pinger->m_pingIP.lower_bound(ip);
317 while (treeIterUpper != treeIterLower)
320 treeIterLower->second = stgTime;
322 treeIterLower->second = time(NULL);
329 pinger->m_isRunningRecver = false;
332 //-----------------------------------------------------------------------------