////////////////////////////////////////////////// //Title : pub_inet.c //Auhtor : Liu Wei //Desc : public inet function implementation //Created : 2007-06-22 //Revision : // //Revision : // ////////////////////////////////////////////////// #include "./include/pub_inet.h" /*@ignore@*/ /////////////////////////////////////////////////////////////////////////// // Inet If Address infomation interface /////////////////////////////////////////////////////////////////////////// extern int GetNetIfInfo ( IfAddr * pIfAddr ) { int fd; struct ifreq buf[MAXINTERFACES]; struct arpreq arp; struct ifconf ifc; pIfAddr->uIfNum = 0; if ( ( fd = socket ( AF_INET, SOCK_DGRAM, 0 ) ) >= 0 ) { ifc.ifc_len = sizeof buf; ifc.ifc_buf = ( caddr_t ) buf; if ( !ioctl ( fd, SIOCGIFCONF, ( char * ) &ifc ) ) { int i; pIfAddr->uIfNum = ifc.ifc_len / sizeof ( struct ifreq ); pIfAddr->uIfNum = pIfAddr->uIfNum % MAXINTERFACES; for ( i = 0; i < pIfAddr->uIfNum; i++ ) { ioctl ( fd, SIOCGIFFLAGS, ( char * ) &buf[i] ); pIfAddr->tIfEntity[i].uIfState = buf[i].ifr_flags & IFF_UP; if ( !( ioctl ( fd, SIOCGIFADDR, ( char * ) &buf[i] ) ) ) { pIfAddr->tIfEntity[i].dIfIP = ( ( struct sockaddr_in * ) ( &buf[i].ifr_addr ) )-> sin_addr.s_addr; } } } } close ( fd ); return pIfAddr->uIfNum; } static u32 wxc2_bind_ip=0xFFFFFFFF, wxc2_shm_shift; void ReadMCMSParam() { char cnf_file[]="./conf/mcms_conf.txt"; char info_str[256], *buf_ptr;; FILE *fp=NULL; fp = fopen(cnf_file,"r"); wxc2_bind_ip = 0; wxc2_shm_shift = 0; if(fp == NULL) return; while (!feof(fp)) { info_str[0] = '\n'; fgets(info_str,250,fp); if (info_str[0] == '#' || info_str[0] == '\n') continue; buf_ptr = info_str; if(!strncasecmp(info_str,"bind ip=",8)) { wxc2_bind_ip = inet_addr(&info_str[8]); continue; } if(!strncasecmp(info_str,"shm key shift=",14)) { wxc2_shm_shift = atoi(&info_str[14]); continue; } } fclose(fp); } u32 GetLocalIP( ) { struct hostent *host; struct in_addr *hostip_addr; char name[100]; if(wxc2_bind_ip == 0xFFFFFFFF) ReadMCMSParam(); if(wxc2_bind_ip == 0) { gethostname ( name, 24 ); host = gethostbyname ( name ); hostip_addr = ( struct in_addr * ) ( *host->h_addr_list ); return hostip_addr->s_addr; } return wxc2_bind_ip; } u32 GetLocalIP1( ) { if(wxc2_bind_ip == 0xFFFFFFFF) ReadMCMSParam(); if(wxc2_bind_ip == 0) { return INADDR_ANY; } return wxc2_bind_ip; } u32 wxc2_get_shm_offset() { if(wxc2_bind_ip == 0xFFFFFFFF) ReadMCMSParam(); return wxc2_shm_shift; } /////////////////////////////////////////////////////////////////////////// // Inet If Address infomation interface /////////////////////////////////////////////////////////////////////////// //校验和算法 static u16 IcmpCheckSum ( u16 * addr, int len ) { int nleft = len; int sum = 0; u16 *w = addr; u16 answer = 0; //把ICMP报头二进制数据以2字节为单位累加起来 while ( nleft > 1 ) { sum += *w++; nleft -= 2; } //若ICMP报头为奇数个字节,会剩下最后一字节。 //把最后一个字节视为一个2字节数据的高字节,这个2字节数据的低字节为0,继续累加 if ( nleft == 1 ) { *( unsigned char * ) ( &answer ) = *( unsigned char * ) w; sum += answer; } sum = ( sum >> 16 ) + ( sum & 0xffff ); sum += ( sum >> 16 ); answer = ~sum; return answer; } //设置ICMP报头 static int IcmpPacking ( IcmpSrv * pIS ) { int i, packsize; struct icmp *icmp; struct timeval *tval; icmp = ( struct icmp * ) pIS->aSendBuff; icmp->icmp_type = ICMP_ECHO; icmp->icmp_code = 0; icmp->icmp_cksum = 0; icmp->icmp_seq = pIS->nPackNumSend; icmp->icmp_id = pIS->tPid; packsize = 8 + pIS->uDataLen; //记录发送时间 tval = ( struct timeval * ) icmp->icmp_data; gettimeofday ( tval, NULL ); icmp->icmp_cksum = IcmpCheckSum ( ( u16 * ) icmp, packsize ); return packsize; } //剥去ICMP报头 static int IcmpUnPack ( u8 * buf, int len, IcmpSrv * pIS ) { int i, nIpHdrLen; struct ip *pIP; struct icmp *icmp; struct timeval *tvSend; struct timeval tvRecv; double rtt; gettimeofday ( &tvRecv, NULL ); pIP = ( struct ip * ) buf; //求ip报头长度,即ip报头的长度标志乘4 nIpHdrLen = pIP->ip_hl << 2; //越过ip报头,指向ICMP报头 icmp = ( struct icmp * ) ( buf + nIpHdrLen ); //ICMP报头及ICMP数据报的总长度 len -= nIpHdrLen; if ( len < 8 ) //小于ICMP报头长度则不合理 { printf ( "ICMP packets's length is less than 8 " ); return 0; } //确保所接收的是我所发的的ICMP的回应 if ( ( icmp->icmp_type == ICMP_ECHOREPLY ) && ( icmp->icmp_id == pIS->tPid ) ) { tvSend = ( struct timeval * ) icmp->icmp_data; rtt = ( tvRecv.tv_sec * 1000 + tvRecv.tv_usec / 1000 ) - ( tvSend->tv_sec * 1000 + tvSend->tv_usec / 1000 ); printf ( "%d byte from %s: icmp_seq=%u ttl=%d rtt=%.3f ms \n", len, inet_ntoa ( pIS->tFromAddr.sin_addr ), icmp->icmp_seq, pIP->ip_ttl, rtt ); return 1; } return 0; } static void IcmpStatis ( IcmpSrv * pIS ) { int nSend, nRecv; nSend = pIS->nPackNumSend; nRecv = pIS->nPackNumRecv; printf ( " --------------------PING statistics------------------- \n" ); printf ( "%d packets transmitted, %d received , %%%d lost \n\n", nSend, nRecv, ( nSend - nRecv ) / nSend * 100 ); close ( pIS->wSockfd ); pIS->uSrvState = 0; } //发送三个ICMP报文 static int IcmpSend ( IcmpSrv * pIS ) { int nSize; if ( pIS->nPackNumSend < MAX_NO_PACKETS ) { pIS->nPackNumSend++; nSize = IcmpPacking ( pIS ); //设置ICMP报头 if ( sendto ( pIS->wSockfd, pIS->aSendBuff, nSize, 0, ( struct sockaddr * ) &pIS->tToAddr, sizeof ( pIS->tToAddr ) ) < 0 ) { perror ( "sendto error" ); return 0; } printf ( "[IcmpSend] : Send icmp Pack %d \n", pIS->nPackNumSend ); return 1; } return 0; } //接收所有ICMP报文 static void IcmpRecv ( IcmpSrv * pIS ) { int n, fromlen; extern int errno; fromlen = sizeof ( pIS->tFromAddr ); while ( pIS->nPackNumRecv < pIS->nPackNumSend ) { if ( ( n = recvfrom ( pIS->wSockfd, pIS->aRecvBuff, sizeof ( pIS->aRecvBuff ), 0, ( struct sockaddr * ) &pIS->tFromAddr, &fromlen ) ) < 0 ) { if ( errno == EINTR ) continue; perror ( "recvfrom error" ); continue; } if ( IcmpUnPack ( pIS->aRecvBuff, n, pIS ) == -1 ) continue; pIS->nPackNumRecv++; } } extern int PingInit ( IcmpSrv * pIS, int nDataLen ) { memset ( pIS, 0, sizeof ( IcmpSrv ) ); pIS->uSrvState = 0; pIS->uDataLen = 56; if ( ( pIS->pProtoent = getprotobyname ( "icmp" ) ) == NULL ) { perror ( "getprotobyname" ); exit ( 1 ); } // 回收root权限,设置当前用户权限 setuid ( getuid ( ) ); //获取main的进程id,用于设置ICMP的标志符 pIS->tPid = getpid ( ); } extern int PingStart ( IcmpSrv * pIS, char *sIP, PingCallBack fCallBack ) { int nSize; struct hostent *pHost; //struct in_addr *pInAddr; u32 nInetAddr; if ( pIS->uSrvState ) { return 0; } pIS->fCallBack = fCallBack; //生成使用ICMP的原始套接字,这种套接字只有root才能生成 if ( ( pIS->wSockfd = socket ( AF_INET, SOCK_RAW, pIS->pProtoent->p_proto ) ) < 0 ) { perror ( "socket error" ); exit ( 1 ); } //扩大套接字接收缓冲区到50K这样做主要为了减小接收缓冲区溢出的 //的可能性, 若无意中ping会引来大量应答 setsockopt ( pIS->wSockfd, SOL_SOCKET, SO_RCVBUF, &nSize, sizeof ( nSize ) ); bzero ( &pIS->tToAddr, sizeof ( pIS->tToAddr ) ); pIS->tToAddr.sin_family = AF_INET; //判断是主机名还是ip地址 nInetAddr = inet_addr ( sIP ); if ( nInetAddr == INADDR_NONE ) { if ( ( pHost = gethostbyname ( sIP ) ) == NULL ) //是主机名 { perror ( "gethostbyname error" ); exit ( 1 ); } memcpy ( ( char * ) &pIS->tToAddr.sin_addr, pHost->h_addr, pHost->h_length ); } else //是ip地址 { pIS->tToAddr.sin_addr.s_addr = nInetAddr; //memcpy( (char *)&pIS->tToAddr,(char *)&nInetAddr,host->h_length); } printf ( "PING %s(%s): %d bytes data in ICMP packets. \n", sIP, inet_ntoa ( pIS->tToAddr.sin_addr ), pIS->uDataLen ); pIS->uSrvState = 1; pIS->uIcmpState = 1; } extern int PingTimer ( IcmpSrv * pIS ) { if ( pIS->uSrvState ) { IcmpRecv ( pIS ); switch ( pIS->uIcmpState ) { case 1: case 2: case 3: IcmpSend ( pIS ); pIS->uIcmpState++; break; default: if ( pIS->nPackNumRecv >= 3 ) { IcmpStatis ( pIS ); pIS->fCallBack ( 1 ); } if ( pIS->uIcmpState++ > 200 ) { IcmpStatis ( pIS ); pIS->fCallBack ( 0 ); } break; } } } /*@end@*/