X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/8c6fa3fbaccc22127280bf77a48fab5a3ee0716e..46b0747592074017ff0ea4b33d4a7194235886e5:/libs/pinger/pinger.cpp diff --git a/libs/pinger/pinger.cpp b/libs/pinger/pinger.cpp new file mode 100644 index 00000000..1689e294 --- /dev/null +++ b/libs/pinger/pinger.cpp @@ -0,0 +1,346 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "stg/common.h" +#include "stg/locker.h" + +#include "stg/pinger.h" + +#ifdef STG_TIME +extern volatile time_t stgTime; +#endif + +//----------------------------------------------------------------------------- +STG_PINGER::STG_PINGER(time_t d) + : delay(d), + nonstop(false), + isRunningRecver(false), + isRunningSender(false), + sendSocket(-1), + recvSocket(-1), + sendThread(), + recvThread(), + pmSend(), + pid(0), + errorStr(), + pingIP(), + ipToAdd(), + ipToDel(), + mutex() +{ +pthread_mutex_init(&mutex, NULL); +memset(&pmSend, 0, sizeof(pmSend)); +} +//----------------------------------------------------------------------------- +STG_PINGER::~STG_PINGER() +{ +pthread_mutex_destroy(&mutex); +} +//----------------------------------------------------------------------------- +int STG_PINGER::Start() +{ +struct protoent *proto = NULL; +proto = getprotobyname("ICMP"); +sendSocket = socket(PF_INET, SOCK_RAW, proto->p_proto); +recvSocket = socket(PF_INET, SOCK_RAW, proto->p_proto); +nonstop = true; +pid = (int) getpid() % 65535; +if (sendSocket < 0 || recvSocket < 0) + { + errorStr = "Cannot create socket."; + return -1; + } + +if (pthread_create(&sendThread, NULL, RunSendPing, this)) + { + errorStr = "Cannot create send thread."; + return -1; + } + +if (pthread_create(&recvThread, NULL, RunRecvPing, this)) + { + errorStr = "Cannot create recv thread."; + return -1; + } + +return 0; +} +//----------------------------------------------------------------------------- +int STG_PINGER::Stop() +{ +close(recvSocket); +nonstop = false; +if (isRunningRecver) + { + //5 seconds to thread stops itself + for (size_t i = 0; i < 25; i++) + { + if (i % 5 == 0) + SendPing(0x0100007f);//127.0.0.1 + + if (!isRunningRecver) + break; + + struct timespec ts = {0, 200000000}; + nanosleep(&ts, NULL); + } + } + +if (isRunningSender) + { + //5 seconds to thread stops itself + for (size_t i = 0; i < 25; i++) + { + if (!isRunningSender) + break; + + struct timespec ts = {0, 200000000}; + nanosleep(&ts, NULL); + } + } + +close(sendSocket); + +if (isRunningSender || isRunningRecver) + return -1; + +return 0; +} +//----------------------------------------------------------------------------- +void STG_PINGER::AddIP(uint32_t ip) +{ +STG_LOCKER lock(&mutex); +ipToAdd.push_back(ip); +} +//----------------------------------------------------------------------------- +void STG_PINGER::DelIP(uint32_t ip) +{ +STG_LOCKER lock(&mutex); +ipToDel.push_back(ip); +} +//----------------------------------------------------------------------------- +void STG_PINGER::RealAddIP() +{ +STG_LOCKER lock(&mutex); + +std::list::iterator iter; +iter = ipToAdd.begin(); +while (iter != ipToAdd.end()) + { + pingIP.insert(std::make_pair(*iter, 0)); + ++iter; + } +ipToAdd.erase(ipToAdd.begin(), ipToAdd.end()); +} +//----------------------------------------------------------------------------- +void STG_PINGER::RealDelIP() +{ +STG_LOCKER lock(&mutex); + +std::list::iterator iter; +std::multimap::iterator treeIter; +iter = ipToDel.begin(); +while (iter != ipToDel.end()) + { + treeIter = pingIP.find(*iter); + if (treeIter != pingIP.end()) + pingIP.erase(treeIter); + + ++iter; + } +ipToDel.erase(ipToDel.begin(), ipToDel.end()); +} +//----------------------------------------------------------------------------- +void STG_PINGER::PrintAllIP() +{ +STG_LOCKER lock(&mutex); +std::multimap::iterator iter; +iter = pingIP.begin(); +while (iter != pingIP.end()) + { + uint32_t ip = iter->first; + time_t t = iter->second; + std::string s; + x2str(t, s); + printf("ip = %s, time = %9s\n", inet_ntostring(ip).c_str(), s.c_str()); + ++iter; + } + +} +//----------------------------------------------------------------------------- +int STG_PINGER::GetIPTime(uint32_t ip, time_t * t) const +{ +STG_LOCKER lock(&mutex); +std::multimap::const_iterator treeIter; + +treeIter = pingIP.find(ip); +if (treeIter == pingIP.end()) + return -1; + +*t = treeIter->second; +return 0; +} +//----------------------------------------------------------------------------- +uint16_t STG_PINGER::PingCheckSum(void * data, int len) +{ +uint16_t * buf = static_cast(data); +uint32_t sum = 0; +uint32_t result; + +for ( sum = 0; len > 1; len -= 2 ) + sum += *buf++; + +if ( len == 1 ) + sum += *reinterpret_cast(buf); + +sum = (sum >> 16) + (sum & 0xFFFF); +sum += (sum >> 16); +result = ~sum; +return static_cast(result); +} +//----------------------------------------------------------------------------- +int STG_PINGER::SendPing(uint32_t ip) +{ +struct sockaddr_in addr; +memset(&addr, 0, sizeof(addr)); +addr.sin_family = AF_INET; +addr.sin_port = 0; +addr.sin_addr.s_addr = ip; + +memset(&pmSend, 0, sizeof(pmSend)); +pmSend.hdr.type = ICMP_ECHO; +pmSend.hdr.un.echo.id = static_cast(pid); +memcpy(pmSend.msg, &ip, sizeof(ip)); + +pmSend.hdr.checksum = PingCheckSum(&pmSend, sizeof(pmSend)); + +if (sendto(sendSocket, &pmSend, sizeof(pmSend), 0, (sockaddr *)&addr, sizeof(addr)) <= 0 ) + { + errorStr = "Send ping error: " + std::string(strerror(errno)); + return -1; + } + + +return 0; +} +//----------------------------------------------------------------------------- +uint32_t STG_PINGER::RecvPing() +{ +struct sockaddr_in addr; +uint32_t ipAddr = 0; + +char buf[128]; +memset(buf, 0, sizeof(buf)); +socklen_t len = sizeof(addr); + +if (recvfrom(recvSocket, &buf, sizeof(buf), 0, reinterpret_cast(&addr), &len)) + { + struct IP_HDR * ip = static_cast(static_cast(buf)); + struct ICMP_HDR *icmp = static_cast(static_cast(buf + ip->ihl * 4)); + + if (icmp->un.echo.id != pid) + return 0; + + ipAddr = *static_cast(static_cast(buf + sizeof(ICMP_HDR) + ip->ihl * 4)); + } + +return ipAddr; +} +//----------------------------------------------------------------------------- +void * STG_PINGER::RunSendPing(void * d) +{ +sigset_t signalSet; +sigfillset(&signalSet); +pthread_sigmask(SIG_BLOCK, &signalSet, NULL); + +STG_PINGER * pinger = static_cast(d); + +pinger->isRunningSender = true; +time_t lastPing = 0; +while (pinger->nonstop) + { + pinger->RealAddIP(); + pinger->RealDelIP(); + + std::multimap::iterator iter; + iter = pinger->pingIP.begin(); + while (iter != pinger->pingIP.end()) + { + pinger->SendPing(iter->first); + ++iter; + } + + time_t currTime; + + #ifdef STG_TIME + lastPing = stgTime; + currTime = stgTime; + #else + currTime = lastPing = time(NULL); + #endif + + while (currTime - lastPing < pinger->delay && pinger->nonstop) + { + #ifdef STG_TIME + currTime = stgTime; + #else + currTime = time(NULL); + #endif + struct timespec ts = {0, 20000000}; + nanosleep(&ts, NULL); + } + } + +pinger->isRunningSender = false; + +return NULL; +} +//----------------------------------------------------------------------------- +void * STG_PINGER::RunRecvPing(void * d) +{ +sigset_t signalSet; +sigfillset(&signalSet); +pthread_sigmask(SIG_BLOCK, &signalSet, NULL); + +STG_PINGER * pinger = static_cast(d); + +pinger->isRunningRecver = true; + +while (pinger->nonstop) + { + uint32_t ip = pinger->RecvPing(); + + if (ip) + { + std::multimap::iterator treeIterUpper = pinger->pingIP.upper_bound(ip); + std::multimap::iterator treeIterLower = pinger->pingIP.lower_bound(ip); + while (treeIterUpper != treeIterLower) + { + #ifdef STG_TIME + treeIterLower->second = stgTime; + #else + treeIterLower->second = time(NULL); + #endif + ++treeIterLower; + } + } + + } +pinger->isRunningRecver = false; +return NULL; +} +//-----------------------------------------------------------------------------