ping.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. #pragma pack(4)
  2. #include "Stdafx.h"
  3. #include "ping.h"
  4. #include "winsock2.h"
  5. #include "stdlib.h"
  6. #include "stdio.h"
  7. #pragma comment(lib,"WS2_32")
  8. WSADATA wsaData;
  9. SOCKET sockRaw;
  10. int bread;
  11. int timeout = 1000;
  12. int InitPing(void)
  13. {
  14. CString str;
  15. if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0)
  16. {
  17. //fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
  18. //ExitProcess(STATUS_FAILED);
  19. str.Format("WSAStartup failed: %d\n",GetLastError());
  20. return -1;
  21. }
  22. sockRaw = WSASocket(AF_INET,SOCK_RAW,IPPROTO_ICMP,NULL, 0,WSA_FLAG_OVERLAPPED);
  23. //
  24. //注:为了使用发送接收超时设置(即设置SO_RCVTIMEO, SO_SNDTIMEO),
  25. // 必须将标志位设为WSA_FLAG_OVERLAPPED !
  26. //
  27. if (sockRaw == INVALID_SOCKET)
  28. {
  29. //fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
  30. str.Format("WSASocket() failed: %d\n",WSAGetLastError());
  31. return -1;
  32. }
  33. bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,
  34. sizeof(timeout));
  35. if(bread == SOCKET_ERROR)
  36. {
  37. //fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError());
  38. str.Format("failed to set recv timeout: %d\n",WSAGetLastError());
  39. return -1;
  40. }
  41. timeout = 1000;
  42. bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
  43. sizeof(timeout));
  44. if(bread == SOCKET_ERROR)
  45. {
  46. //fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
  47. str.Format("failed to set send timeout: %d\n",WSAGetLastError());
  48. return -1;
  49. }
  50. return 0;
  51. }
  52. void UnInitPing(void)
  53. {
  54. WSACleanup();
  55. }
  56. int Ping(UINT nRetries,LPCSTR pstrHost)
  57. {
  58. CString str;
  59. struct sockaddr_in dest,from;
  60. struct hostent * hp;
  61. int datasize;
  62. int fromlen = sizeof(from);
  63. int statistic = 0; /* 用于统计结果 */
  64. char *dest_ip;
  65. char *icmp_data;
  66. char *recvbuf;
  67. unsigned int addr=0;
  68. USHORT seq_no = 0;
  69. memset(&dest,0,sizeof(dest));
  70. hp = gethostbyname(pstrHost);
  71. if (!hp)
  72. {
  73. addr = inet_addr(pstrHost);
  74. }
  75. if ((!hp) && (addr == INADDR_NONE) )
  76. {
  77. //fprintf(stderr,"Unable to resolve %s\n",argv[1]);
  78. LOG4C((LOG_NOTICE, "Unable to resolve %s",pstrHost));
  79. return -1;
  80. }
  81. if (hp != NULL)
  82. {
  83. memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
  84. }
  85. else
  86. {
  87. dest.sin_addr.s_addr = addr;
  88. }
  89. if (hp)
  90. {
  91. dest.sin_family = hp->h_addrtype;
  92. }
  93. else
  94. {
  95. dest.sin_family = AF_INET;
  96. }
  97. dest_ip = inet_ntoa(dest.sin_addr);
  98. //
  99. // atoi函数原型是: int atoi( const char *string );
  100. // The return value is 0 if the input cannot be converted to an integer !
  101. //
  102. datasize = DEF_PACKET_SIZE;
  103. datasize += sizeof(IcmpHeader);
  104. icmp_data = (char*)xmalloc(MAX_PACKET);
  105. recvbuf = (char*)xmalloc(MAX_PACKET);
  106. if (!icmp_data)
  107. {
  108. //fprintf(stderr,"HeapAlloc failed %d\n",GetLastError());
  109. str.Format("HeapAlloc failed %d\n",GetLastError());
  110. LOG4C((LOG_NOTICE, "%s", str));
  111. return -1;
  112. }
  113. memset(icmp_data,0,MAX_PACKET);
  114. fill_icmp_data(icmp_data,datasize);
  115. //
  116. //显示提示信息
  117. //
  118. //fprintf(stdout,"\nPinging %s ....\n\n",dest_ip);
  119. //LOG4C((LOG_NOTICE, "\nPinging %s ....\n\n",dest_ip));
  120. for(int i=0;i<4;i++)
  121. {
  122. int bwrote;
  123. ((IcmpHeader*)icmp_data)->i_cksum = 0;
  124. ((IcmpHeader*)icmp_data)->timestamp = GetTickCount();
  125. ((IcmpHeader*)icmp_data)->i_seq = seq_no++;
  126. ((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data,datasize);
  127. bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,sizeof(dest));
  128. if (bwrote == SOCKET_ERROR)
  129. {
  130. if (WSAGetLastError() == WSAETIMEDOUT)
  131. {
  132. str.Format("%s=Request timed out.\n",pstrHost);
  133. //LOG4C((LOG_NOTICE, "%s", str));
  134. xfree(icmp_data);
  135. xfree(recvbuf);
  136. return 1;
  137. }
  138. //LOG4C((LOG_NOTICE, "sendto failed: %d",WSAGetLastError()));
  139. return -1;
  140. //fprintf(stderr,"sendto failed: %d\n",WSAGetLastError());
  141. //ExitProcess(STATUS_FAILED);
  142. }
  143. if (bwrote < datasize )
  144. {
  145. //LOG4C((LOG_NOTICE, "Wrote %d bytes",bwrote));
  146. //fprintf(stdout,"Wrote %d bytes\n",bwrote);
  147. }
  148. bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,&fromlen);
  149. if (bread == SOCKET_ERROR)
  150. {
  151. if (WSAGetLastError() == WSAETIMEDOUT)
  152. {
  153. //printf("Request timed out.\n");
  154. //continue;
  155. str.Format("%s=Request timed out.\n",pstrHost);
  156. //LOG4C((LOG_NOTICE, "%s", str));
  157. xfree(icmp_data);
  158. xfree(recvbuf);
  159. return 1;
  160. }
  161. LOG4C((LOG_NOTICE, "recvfrom failed: %d",WSAGetLastError()));
  162. //fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError());
  163. //ExitProcess(STATUS_FAILED);
  164. return -1;
  165. }
  166. if(!decode_resp(recvbuf,bread,&from))
  167. {
  168. //statistic++; /* 成功接收的数目++ */
  169. break;
  170. }
  171. }
  172. /*
  173. Display the statistic result
  174. */
  175. //fprintf(stdout,"\nPing statistics for %s \n",dest_ip);
  176. //fprintf(stdout," Packets: Sent = %d,Received = %d, Lost = %d (%2.0f%% loss)\n",times,
  177. // statistic,(times-statistic),(float)(times-statistic)/times*100);
  178. //LOG4C((LOG_NOTICE, "\nPing statistics for %s",dest_ip));
  179. xfree(icmp_data);
  180. xfree(recvbuf);
  181. return 0;
  182. }
  183. /*
  184. The response is an IP packet. We must decode the IP header to locate
  185. the ICMP data
  186. */
  187. int decode_resp(char *buf, int bytes,struct sockaddr_in *from)
  188. {
  189. IpHeader *iphdr;
  190. IcmpHeader *icmphdr;
  191. unsigned short iphdrlen;
  192. iphdr = (IpHeader *)buf;
  193. iphdrlen = (iphdr->h_len) * 4 ; // number of 32-bit words *4 = bytes
  194. if (bytes < iphdrlen + ICMP_MIN)
  195. {
  196. //printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
  197. }
  198. icmphdr = (IcmpHeader*)(buf + iphdrlen);
  199. if (icmphdr->i_type != ICMP_ECHOREPLY)
  200. {
  201. //fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type);
  202. return 1;
  203. }
  204. if (icmphdr->i_id != (USHORT)GetCurrentProcessId())
  205. {
  206. //fprintf(stderr,"someone else's packet!\n");
  207. return 1;
  208. }
  209. //printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr));
  210. //printf(" icmp_seq = %d. ",icmphdr->i_seq);
  211. //printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp);
  212. //printf("\n");
  213. return 0;
  214. }
  215. USHORT checksum(USHORT *buffer, int size)
  216. {
  217. unsigned long cksum=0;
  218. while(size >1)
  219. {
  220. cksum+=*buffer++;
  221. size -=sizeof(USHORT);
  222. }
  223. if(size)
  224. {
  225. cksum += *(UCHAR*)buffer;
  226. }
  227. cksum = (cksum >> 16) + (cksum & 0xffff);
  228. cksum += (cksum >>16);
  229. return (USHORT)(~cksum);
  230. }
  231. /*
  232. Helper function to fill in various stuff in our ICMP request.
  233. */
  234. void fill_icmp_data(char * icmp_data, int datasize)
  235. {
  236. IcmpHeader *icmp_hdr;
  237. char *datapart;
  238. icmp_hdr = (IcmpHeader*)icmp_data;
  239. icmp_hdr->i_type = ICMP_ECHO;
  240. icmp_hdr->i_code = 0;
  241. icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
  242. icmp_hdr->i_cksum = 0;
  243. icmp_hdr->i_seq = 0;
  244. datapart = icmp_data + sizeof(IcmpHeader);
  245. //
  246. // Place some junk in the buffer.
  247. //
  248. memset(datapart,'E', datasize - sizeof(IcmpHeader));
  249. }