ping功能实现(ICMP)
简单记录下项目中ping功能实现
笔记:ping功能实现
void Handler::handlePingDepot(const char *ip)
{
int mSize=50*1024;
bzero(&mDestAddr,sizeof(mDestAddr));
mDestAddr.sin_family = AF_INET;
mDestAddr.sin_addr.s_addr = inet_addr(ip);
if( (mSockFd = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) < 0){
LogE("socket error\n");
return;
}
::setsockopt(mSockFd,SOL_SOCKET,SO_RCVBUF,&mSize,sizeof(mSize) );
mPid=getpid();
recvICMPPacket();
}
void Handler::sendICMPPacket()
{
int mPacketSize = 0;
mSend++;
int n;
mPacketSize = setICMPHander(mSend);
if((n = ::sendto(mSockFd, mSendPacket,mPacketSize, 0,(struct sockaddr *)&mDestAddr, sizeof(mDestAddr))) < 0){
LogE("send icmp packet error\n");
return;
}
}
int Handler::setICMPHander(int mSeq)
{
int mPackSize;
struct icmp *icmp;
icmp = (struct icmp*)mSendPacket;
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_cksum = 0;
icmp->icmp_seq = mSeq;
icmp->icmp_id = mPid;
mPackSize = 8 + dataLen;
icmp->icmp_cksum = calCheckSum( (unsigned short *)icmp,mPackSize);
return mPackSize;
}
void Handler::recvICMPPacket()
{
int n;
mPingTag = true;
socklen_t mFromLen;
int mMaxFds = 0;
fd_set mReadFds;
struct timeval mTimeout;
mFromLen = sizeof(struct sockaddr_in);
while(1){
sendICMPPacket();
mTimeout.tv_sec = mConfig->mSCUTimeout;
mTimeout.tv_usec = 0;
FD_ZERO(&mReadFds);
FD_SET(mSockFd,&mReadFds);
mMaxFds = mSockFd + 1;
n = select(mMaxFds, &mReadFds, NULL, NULL, &mTimeout);
if(n <= 0 ){
LogE("ping %s icmp packet error\n",inet_ntoa(mDestAddr.sin_addr));
mPingTag = false;
break;
}else{
memset(mRecvPacket, 0, sizeof(mRecvPacket));
if((n = ::recvfrom(mSockFd, mRecvPacket, sizeof(mRecvPacket), 0, (struct sockaddr *)&mFrom, &mFromLen)) < 0){
LogE("recv icmp packet error\n");
return;
}
if(parseICMPPacket(mRecvPacket, n) == true){
mIPCall->sendDepotMsg(mFlag);
mRecvPandown = true;
mSend = 0;
break;
}
}
}
}
bool Handler::parseICMPPacket(char *buf, int len)
{
int mIpHdrLen;
struct ip *mIP;
struct icmp *mICMP;
mIP = (struct ip *)buf;
mIpHdrLen = mIP->ip_hl << 2;
mICMP = (struct icmp *)(buf + mIpHdrLen);
len -= mIpHdrLen;
if( len < 8){
LogE("ICMP packets's length is less than 8\n");
return false;
}
if( (mICMP->icmp_type == ICMP_ECHOREPLY) && (mICMP->icmp_id == mPid) ) {
LogE("%d byte from %s: icmp_seq=%u ttl=%d sucess\n",
len,
inet_ntoa(mFrom.sin_addr),
mICMP->icmp_seq,
mIP->ip_ttl);
return true;
}else{
return false;
}
}
unsigned short Handler::calCheckSum(unsigned short *addr,int len)
{
int mLeft = len;
int sum=0;
unsigned short *w = addr;
unsigned short answer = 0;
while(mLeft > 1){
sum += *w++;
mLeft -= 2;
}
if( mLeft == 1){
*(unsigned char *)(&answer) = *(unsigned char *)w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer =~ sum;
return answer;
}