ping功能实现(ICMP)
阅读原文时间:2023年07月16日阅读:1

简单记录下项目中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;
}