📄 pinger.cpp
字号:
int nAddrLen = sizeof(struct sockaddr_in);
char bufICMP[1500]; // allow full MTU
// clear ICMP socket before sending UDP - not best solution, but may be needed to exclude late responses etc
u_long bytes2read = 0;
do {
nRet = ioctlsocket(is, FIONREAD, &bytes2read);
if (bytes2read > 0) { // ignore errors here
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_ANY;
sa.sin_port = 0;
nRet = recvfrom (is, /* socket */
(LPSTR)bufICMP, /* buffer */
1500, /* length */
0, /* flags */
(sockaddr*)&sa, /* source */
&nAddrLen); /* addrlen*/
//if (lastTimeOut) lastTimeOut--;
//if (!lastTimeOut && toNowTimeOut) {
// toNowTimeOut--;
// if (toNowTimeOut) lastTimeOut = 3;
//}
}
} while (bytes2read > 0);
// set TTL value for UDP packet - should success with winsock 2
// NB! take care about IP_TTL value - it's redefined in Ws2tcpip.h!
// TODO: solve next problem correctly:
// eMule is linking sockets functions using wsock32.lib (IP_TTL=7)
// to use IP_TTL define, we must enforce linker to bind this function
// to ws2_32.lib (IP_TTL=4) (linker options: ignore wsock32.lib)
nRet = setsockopt(us, IPPROTO_IP, IP_TTL, (char*)&nTTL, sizeof(int));
if (nRet==SOCKET_ERROR) {
DWORD lastError = WSAGetLastError();
PingStatus returnValue;
returnValue.success = false;
returnValue.delay = TIMEOUT;
returnValue.error = lastError;
//if (toNowTimeOut < 3) toNowTimeOut++;
// lastTimeOut = 3;
return returnValue;
}
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = lAddr;
sa.sin_port = htons(UDP_PORT);
// send lonely UDP packet with almost minimal content (0 bytes is allowed too, but no data will be sent then)
nRet = sendto(us, (LPSTR)&nTTL, 4, 0, (sockaddr*)&sa, sizeof(sa)); // send four bytes - TTL :)
CTimeTick m_time;
m_time.Tick();
if (nRet==SOCKET_ERROR) {
DWORD lastError = WSAGetLastError();
PingStatus returnValue;
returnValue.success = false;
returnValue.error = lastError;
//if (toNowTimeOut < 3) toNowTimeOut++;
// lastTimeOut = 3;
return returnValue;
}
IPHeader* reply = (IPHeader*)bufICMP;
bytes2read = 0;
int timeoutOpt = TIMEOUT;
bool noRcvTimeOut = false;
nRet = setsockopt(is, SOL_SOCKET, SO_RCVTIMEO, (const char*) &timeoutOpt, sizeof(timeoutOpt));
if (nRet==SOCKET_ERROR)
noRcvTimeOut = true;
float usResTime = 0.0f;
while((usResTime += m_time.Tick()) < TIMEOUT){
if (noRcvTimeOut){
nRet = ioctlsocket(is, FIONREAD, &bytes2read);
if (nRet != 0) {
DWORD lastError = WSAGetLastError();
PingStatus returnValue;
returnValue.success = false;
returnValue.delay = TIMEOUT;
returnValue.error = lastError;
//if (toNowTimeOut < 3) toNowTimeOut++;
// lastTimeOut = 3;
return returnValue;
}
if (bytes2read > 0) { // read and filter incoming ICMP
} else {
Sleep(1); // share time with other threads
continue;
}
}
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_ANY;
sa.sin_port = 0;
nRet = recvfrom (is, /* socket */
(LPSTR)bufICMP, /* buffer */
1500, /* length */
0, /* flags */
(sockaddr*)&sa, /* source */
&nAddrLen); /* addrlen*/
usResTime += m_time.Tick();
if (nRet==SOCKET_ERROR) {
DWORD lastError = WSAGetLastError();
PingStatus returnValue;
returnValue.success = false;
returnValue.delay = TIMEOUT;
returnValue.error = lastError;
//if (toNowTimeOut < 3) toNowTimeOut++;
// lastTimeOut = 3;
return returnValue;
}
unsigned short header_len = reply->h_len * 4;
ICMPHeader* icmphdr = (ICMPHeader*)(bufICMP + header_len);
IN_ADDR stDestAddr;
stDestAddr.s_addr = reply->source_ip;
if (((icmphdr->type == ICMP_TTL_EXPIRE) || (icmphdr->type == ICMP_DEST_UNREACH)) &&
(icmphdr->UDP.dest_port == htons(UDP_PORT)) && (icmphdr->hdrsent.dest_ip == lAddr)) {
PingStatus returnValue;
if(icmphdr->type == ICMP_TTL_EXPIRE) {
returnValue.success = true;
returnValue.status = IP_TTL_EXPIRED_TRANSIT;
returnValue.delay = usResTime;
returnValue.destinationAddress = stDestAddr.s_addr;
returnValue.ttl = ttl;
} else {
returnValue.success = true;
returnValue.status = IP_DEST_HOST_UNREACHABLE;
returnValue.delay = usResTime;
returnValue.destinationAddress = stDestAddr.s_addr;
returnValue.ttl = 64 - (reply->ttl & 63);
}
if(doLog) {
theApp.QueueDebugLogLine(false,_T("Reply (UDP-pinger) from %s: bytes=%d time=%3.2fms TTL=%i"),
ipstr(stDestAddr),
nRet,
usResTime,
returnValue.ttl);
}
return returnValue;
} else { // verbose log filtered packets info (not seen yet...)
//if (lastTimeOut) lastTimeOut--;
//if (!lastTimeOut && toNowTimeOut) {
// toNowTimeOut--;
// if (toNowTimeOut) lastTimeOut = 3;
//}
if(doLog) {
theApp.QueueDebugLogLine(false,_T("Filtered reply (UDP-pinger) from %s: bytes=%d time=%3.2fms TTL=%i type=%i"),
ipstr(stDestAddr),
nRet,
usResTime,
64 - (reply->ttl & 63),
icmphdr->type);
}
}
}
//if (usResTime >= TIMEOUT) {
// if (toNowTimeOut < 3) toNowTimeOut++;
// lastTimeOut = 3;
//}
// UDPing reworked ping sequence end <--
PingStatus returnValue;
returnValue.success = false;
returnValue.delay = TIMEOUT;
returnValue.error = IP_REQ_TIMED_OUT;
return returnValue;
}
PingStatus Pinger::PingICMP(uint32 lAddr, uint32 ttl, bool doLog) {
PingStatus returnValue;
IN_ADDR stDestAddr;
char achRepData[sizeof(ICMPECHO) + BUFSIZE];
// Address is assumed to be ok
stDestAddr.s_addr = lAddr;
stIPInfo.Ttl = ttl;
CTimeTick m_time;
m_time.Tick();
// Send the ICMP Echo Request and read the Reply
DWORD dwReplyCount = lpfnIcmpSendEcho(hICMP,
stDestAddr.s_addr,
0, // databuffer
0, // DataLen, length of databuffer
&stIPInfo,
achRepData,
sizeof(achRepData),
TIMEOUT
);
float usResTime=m_time.Tick();
if (dwReplyCount != 0) {
long pingTime = *(u_long *) &(achRepData[8]);
IN_ADDR stDestAddr;
stDestAddr.s_addr = *(u_long *)achRepData;
returnValue.success = true;
returnValue.status = *(DWORD *) &(achRepData[4]);
returnValue.delay = (m_time.isPerformanceCounter() && (pingTime <= 20 || pingTime%10 == 0) && (pingTime+10 > usResTime && usResTime+10 > pingTime )? usResTime : pingTime);
returnValue.destinationAddress = stDestAddr.s_addr;
returnValue.ttl = (returnValue.status != IP_SUCCESS)?ttl:(*(char *)&(achRepData[20]))&0x00FF;
if(doLog) {
theApp.QueueDebugLogLine(false,_T("Reply (ICMP-pinger) from %s: bytes=%d time=%3.2fms (%3.2fms %ldms) TTL=%i"),
ipstr(stDestAddr),
*(u_long *) &(achRepData[12]),
returnValue.delay,
m_time.isPerformanceCounter() ? usResTime : -1.0f,
(u_long)(achRepData[8]),
returnValue.ttl);
}
} else {
DWORD lastError = GetLastError();
returnValue.success = false;
returnValue.error = lastError;
if(doLog) {
theApp.QueueDebugLogLine(false,_T("Error from %s: Error=%i"),
ipstr(stDestAddr),
returnValue.error);
}
}
return returnValue;
}
void Pinger::PIcmpErr(int nICMPErr) {
int nErrIndex = nICMPErr - IP_STATUS_BASE;
if ((nICMPErr > MAX_ICMP_ERR_STRING) ||
(nICMPErr < IP_STATUS_BASE+1)) {
// Error value is out of range, display normally
theApp.QueueDebugLogLine(false,_T("Pinger: %s"),GetErrorMessage(nICMPErr,1));
} else {
// Display ICMP Error String
theApp.QueueDebugLogLine(false,_T("%s"), aszSendEchoErr[nErrIndex]);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -