TWPing.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. #include "stdafx2.h"
  2. #include "TWPing.h"
  3. #include <sys/types.h>
  4. CTWPing::CTWPing()
  5. {
  6. m_hSocket = INVALID_SOCKET;
  7. m_bCancelPing = FALSE;
  8. m_nDataSize = DEFAULT_PACKET_SIZE;
  9. m_nInterval = DEFAULT_INTERVAL;
  10. m_nTimeout = DEFAULT_TIMEOUT;
  11. m_usPacketSeqNo = 0;
  12. m_icmpData = NULL;
  13. m_recvBuf = NULL;
  14. m_bInited = false;
  15. memset(m_szIP, 0, sizeof(m_szIP));
  16. }
  17. CTWPing::~CTWPing(void)
  18. {
  19. Cleanup();
  20. }
  21. int CTWPing::Initial(const char* destIp, int nDataSize, int nTimeout, int nInterval)
  22. {
  23. WSADATA wsaData;
  24. if(WSAStartup(MAKEWORD(2,2), &wsaData) != 0)
  25. {
  26. printf("WSAStartup() failed with status %d", WSAGetLastError());
  27. return -1;
  28. }
  29. strcpy_s(m_szIP, destIp);
  30. memset(&m_addrDest, 0, sizeof(m_addrDest));
  31. m_addrDest.sin_family = AF_INET;
  32. m_addrDest.sin_addr.s_addr = inet_addr(destIp);
  33. if(m_addrDest.sin_addr.s_addr == INADDR_NONE)
  34. {
  35. PHOSTENT hp = NULL;
  36. struct addrinfo hinst;
  37. memset(&hinst, 0, sizeof(hinst));
  38. hinst.ai_family = AF_UNSPEC;
  39. hinst.ai_socktype = SOCK_STREAM;
  40. hinst.ai_protocol = IPPROTO_TCP;
  41. struct addrinfo *result = NULL;
  42. DWORD dwRet = getaddrinfo(destIp, 0, &hinst, &result);
  43. if(dwRet == 0) {
  44. struct addrinfo *ptr = NULL;
  45. for(ptr=result; ptr!=NULL; ptr=ptr->ai_next) {
  46. m_addrDest.sin_family = ptr->ai_family;
  47. memcpy(&(m_addrDest.sin_addr), ptr->ai_addr, ptr->ai_addrlen);
  48. }
  49. }
  50. //hp = gethostbyname(destIp);
  51. //if(hp != NULL)
  52. //{
  53. // memcpy(&(m_addrDest.sin_addr), hp->h_addr, hp->h_length);
  54. // m_addrDest.sin_family = hp->h_addrtype;
  55. //}
  56. else
  57. {
  58. printf("getaddrinfo() failed with status %d", WSAGetLastError());
  59. Cleanup();
  60. return -1;
  61. }
  62. }
  63. m_nDataSize = nDataSize <= 0 ? DEFAULT_PACKET_SIZE : nDataSize;
  64. m_nInterval = nInterval <= 0 ? DEFAULT_INTERVAL : nInterval;
  65. m_nTimeout = nTimeout <= 0 ? DEFAULT_TIMEOUT : nTimeout;
  66. if(InitICMPData() != 0)
  67. {
  68. Cleanup();
  69. return -1;
  70. }
  71. if(CreateSocket() != 0)
  72. {
  73. Cleanup();
  74. return -1;
  75. }
  76. m_bInited = true;
  77. return 0;
  78. }
  79. int CTWPing::InitICMPData()
  80. {
  81. if(m_icmpData == NULL)
  82. m_icmpData = static_cast<char*>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PACKET));
  83. if(m_recvBuf == NULL)
  84. m_recvBuf = static_cast<char*>(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PACKET));
  85. if(!m_icmpData || !m_recvBuf)
  86. {
  87. printf("HeapAlloc() failed with status %d", WSAGetLastError());
  88. return -1;
  89. }
  90. IcmpHeader* pIcmpHdr = NULL;
  91. char* dataPart = NULL;
  92. pIcmpHdr = reinterpret_cast<IcmpHeader*>(m_icmpData);
  93. pIcmpHdr->btType = ICMP_ECHO;
  94. pIcmpHdr->btCode = 0;
  95. pIcmpHdr->usCksum = 0;
  96. pIcmpHdr->usId = (USHORT)GetCurrentProcessId();
  97. pIcmpHdr->usSeq = 0;
  98. dataPart = m_icmpData + sizeof(IcmpHeader);
  99. memset(dataPart, 0, m_nDataSize);
  100. return 0;
  101. }
  102. int CTWPing::DecodeICMPData(int bytes)
  103. {
  104. IpHeader* ipHdr = reinterpret_cast<IpHeader*>(m_recvBuf);
  105. IcmpHeader* icmpHdr = NULL;
  106. USHORT ipHdrLen;
  107. DWORD tickTime = clock();
  108. if(bytes < DEFAULT_IP_HEAD_SIZE)
  109. {
  110. return -1;
  111. }
  112. //首部长度字节数,所表示的单位是32位字
  113. ipHdrLen = ipHdr->h_len * 4;
  114. if(ipHdrLen < DEFAULT_IP_HEAD_SIZE || ipHdrLen > MAX_IP_HDR_SIZE)
  115. {
  116. //识别到长度不能容纳最小ICMP首部长度,无法判断是否为ICMP回应报文
  117. return -1;
  118. }
  119. icmpHdr = reinterpret_cast<IcmpHeader *>(m_recvBuf + ipHdrLen);
  120. if(icmpHdr->btType != ICMP_ECHO_REPLY)
  121. {
  122. //非请求回应报文类型
  123. return -2;
  124. }
  125. if(icmpHdr->usId != (USHORT)GetCurrentProcessId())
  126. {
  127. //不是从该程序发出的数据包
  128. //Dbg("No from here");
  129. return -2;
  130. }
  131. if(icmpHdr->usSeq != GetCurrentSeqNo())
  132. {
  133. //接收的数据包序列号错误,一般会很少出现,出现则需要重新设置SOKECT句柄
  134. //Dbg("SeqNo error");
  135. return -1;
  136. }
  137. if(bytes - ipHdrLen - DEFAULT_ICMP_HEAD_SIZE != m_nDataSize)
  138. {
  139. //接收的数据包长度不完整
  140. return -1;
  141. }
  142. return 0;
  143. }
  144. int CTWPing::Ping()
  145. {
  146. int bread = 0;
  147. int errResult = 0;
  148. int result = 0;
  149. int tryCount = 0;
  150. const int maxTryCount = 3;
  151. int timeoutCount = 0;
  152. const int maxTimeoutCount = 3;
  153. int errorCount = 0;
  154. const int maxErrorCount = 3;
  155. const int aimRecvLen = m_nDataSize + DEFAULT_IP_HEAD_SIZE + DEFAULT_ICMP_HEAD_SIZE;
  156. const int aimSendLen = m_nDataSize + DEFAULT_ICMP_HEAD_SIZE;
  157. SOCKADDR_IN addrSource;
  158. int sourceSize = sizeof(addrSource);
  159. m_bCancelPing = FALSE;
  160. while(!m_bCancelPing)
  161. {
  162. if(m_hSocket == INVALID_SOCKET)
  163. {
  164. tryCount = 0;
  165. while(++tryCount <= maxTryCount)
  166. {
  167. if(!CreateSocket())
  168. break;
  169. Sleep(1000);
  170. }
  171. if(m_hSocket == INVALID_SOCKET)
  172. {
  173. printf("create socket beyond %d times", maxTryCount);
  174. return 1;
  175. }
  176. }
  177. ((IcmpHeader*)m_icmpData)->usCksum = 0;
  178. ((IcmpHeader*)m_icmpData)->ulTimestamp = clock();
  179. ((IcmpHeader*)m_icmpData)->usSeq = IncreaseCurSeqNo();
  180. ((IcmpHeader*)m_icmpData)->usCksum = CheckSum((USHORT*)m_icmpData, aimSendLen);
  181. bread = sendto(m_hSocket, m_icmpData, aimSendLen, 0,
  182. (PSOCKADDR)&m_addrDest, sizeof(m_addrDest));
  183. if(bread == SOCKET_ERROR)
  184. {
  185. errResult = WSAGetLastError();
  186. if(WSAETIMEDOUT == errResult)
  187. {
  188. ++timeoutCount;
  189. if(timeoutCount >= maxTimeoutCount)
  190. {
  191. printf("Sent ping packet timeout %d times", timeoutCount);
  192. result = 2;
  193. break;
  194. }
  195. }
  196. else
  197. {
  198. ++errorCount;
  199. if(errorCount >= maxErrorCount)
  200. {
  201. printf("Sent ping packet occur error %d", errResult);
  202. result = 3;
  203. break;
  204. }
  205. }
  206. CloseSocket();
  207. Sleep(1000);
  208. continue;
  209. }
  210. if(bread < aimSendLen)
  211. {
  212. //CloseSocket();
  213. //Sleep(1000);
  214. continue;
  215. }
  216. //ReturnToRecv:
  217. //Recv
  218. bread = recvfrom(m_hSocket, m_recvBuf, MAX_PACKET, 0, (PSOCKADDR)&addrSource, &sourceSize);
  219. if(bread == SOCKET_ERROR)
  220. {
  221. errResult = WSAGetLastError();
  222. if(WSAETIMEDOUT == errResult)
  223. {
  224. ++timeoutCount;
  225. if(timeoutCount >= maxTimeoutCount)
  226. {
  227. printf("Recv ping(%s) packet timeout %d times", m_szIP, timeoutCount);
  228. result = 2;
  229. break;
  230. }
  231. }
  232. else
  233. {
  234. ++errorCount;
  235. if(errorCount >= maxErrorCount)
  236. {
  237. printf("Recv ping(%s) packet occur error %d", m_szIP, errResult);
  238. result = 3;
  239. break;
  240. }
  241. }
  242. CloseSocket();
  243. Sleep(1000);
  244. continue;
  245. }
  246. errorCount = timeoutCount = 0;
  247. result = DecodeICMPData(bread);
  248. if(result < 0)
  249. {
  250. CloseSocket();
  251. Sleep(1000);
  252. continue;
  253. }
  254. printf("Ping once");
  255. Sleep(m_nInterval);
  256. }
  257. return result;
  258. }
  259. int CTWPing::PingOnce()
  260. {
  261. int bread = 0;
  262. int errResult = 0;
  263. int result = 0;
  264. int tryCount = 0;
  265. const int maxTryCount = 3;
  266. int revcCount = 0;
  267. const int maxRevcCount = 3;
  268. const int aimRecvLen = m_nDataSize + DEFAULT_IP_HEAD_SIZE + DEFAULT_ICMP_HEAD_SIZE;
  269. const int aimSendLen = m_nDataSize + DEFAULT_ICMP_HEAD_SIZE;
  270. SOCKADDR_IN addrSource;
  271. int sourceSize = sizeof(addrSource);
  272. do
  273. {
  274. if(m_hSocket == INVALID_SOCKET)
  275. {
  276. CreateSocket();
  277. result = 1;
  278. break;
  279. }
  280. IcmpHeader* header = reinterpret_cast<IcmpHeader*>(m_icmpData);
  281. header->usCksum = 0;
  282. header->ulTimestamp = clock();
  283. header->usSeq = IncreaseCurSeqNo();
  284. header->usCksum = CheckSum((USHORT*)m_icmpData, aimSendLen);
  285. bread = sendto(m_hSocket, m_icmpData, aimSendLen, 0,
  286. (PSOCKADDR)&m_addrDest, sizeof(m_addrDest));
  287. if(bread == SOCKET_ERROR)
  288. {
  289. errResult = WSAGetLastError();
  290. if(WSAETIMEDOUT == errResult)
  291. {
  292. LOG_TRACE("Sent ping packet timeout");
  293. result = 2;
  294. }
  295. else
  296. {
  297. LOG_TRACE("Sent ping packet occur error %d", errResult);
  298. result = 3;
  299. }
  300. break;
  301. }
  302. if(bread < aimSendLen)
  303. {
  304. LOG_TRACE("Sent ping packet seems incomplete.");
  305. result = 4;
  306. break;
  307. }
  308. //ReturnToRecv:
  309. //Recv
  310. bread = recvfrom(m_hSocket, m_recvBuf, MAX_PACKET, 0, (PSOCKADDR)&addrSource, &sourceSize);
  311. if(bread == SOCKET_ERROR)
  312. {
  313. errResult = WSAGetLastError();
  314. if(WSAETIMEDOUT == errResult)
  315. {
  316. LOG_TRACE("Recv ping(%s) packet timeout", m_szIP);
  317. result = 2;
  318. }
  319. else
  320. {
  321. LOG_TRACE("Recv ping(%s) packet occur error %d", m_szIP, errResult);
  322. result = 3;
  323. }
  324. break;
  325. }
  326. result = DecodeICMPData(bread);
  327. if(result < 0)
  328. {
  329. CloseSocket();
  330. result = 4;
  331. break;
  332. }
  333. }while(FALSE);
  334. return result;
  335. }