ping 代码

/*
author:	zhangzhijian
time:	2012-11-14

creater sock must root 

ping localhost [-n count]
*/
#include <stdio.h>
#include <signal.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#include <setjmp.h>
#include <errno.h>

#define MAX_WAIT_TIME	5
#define PACKET_SIZE	4096

int	sockfd;
int	data_len = 56;
int	n_send = 0;
int 	n_recv = 0;
int 	max_no_packets = 3;
pid_t	pid;
char	send_data[PACKET_SIZE];
char	recv_data[PACKET_SIZE];

struct sockaddr_in	dest_addr;
struct sockaddr_in	from;
struct timeval		tv_recv;

void statistics(int signo);
void tv_sub(struct timeval *out, struct timeval *in);

unsigned short cal_chksum(unsigned short *addr, int len);
int init_pack(int pack_no);
void send_pack();

int unpack(char *buf, int len);
void recv_pack();

int main(int argc,char *argv[])
{
	struct hostent 	*host;
	struct protoent	*protocol;
	unsigned long	inaddr = 0l;
	int 		wait_time = MAX_WAIT_TIME;
	int 		size = 50 * 1024;

	if(argv < 2)
	{
		printf("usage:%s hostname/IP [-n count]\n", argv[0]);
		exit(1);
	}

	if( (argc >= 3) ) 
	{
		max_no_packets = atoi(argv[3]);
	}

	if( (protocol = getprotobyname("icmp")) == NULL)
	{
		perror("getprotobyname");
		exit(1);
	}

	if( (sockfd = socket(AF_INET, SOCK_RAW, protocol->p_proto)) < 0 )
	{
		perror("socket error");
		exit(1);
	}

	setuid(getuid());

	setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
	bzero(&dest_addr, sizeof(dest_addr));
	dest_addr.sin_family = AF_INET;

	if( (inaddr = inet_addr(argv[1])) == INADDR_NONE)
	{//user host name
		if( (host = gethostbyname(argv[1])) == NULL)
		{
			perror("gethostbyname error");
			exit(1);
		}
		memcpy( (char*)&dest_addr.sin_addr, host->h_addr, host->h_length);
	}
	else
	{//user IP adder
		memcpy( (char*)&dest_addr, (char*)&inaddr, host->h_length);
	}

	pid = getpid();
	printf("PING %s(%s): %d bytes data in ICMP packets.\n", argv[1], 
			inet_ntoa(dest_addr.sin_addr), data_len);

	send_pack();
	recv_pack();
	statistics(SIGALRM);

	return 0;
}

void send_pack()
{
	int pack_size;
	while( n_send < max_no_packets)
	{
		n_send ++;
		pack_size = init_pack(n_send);
		if( sendto(sockfd, send_data, pack_size, 0,
				(struct sockaddr *)&dest_addr, sizeof(dest_addr)) < 0)
		{
			perror("sendto error");
			continue;
		}
		sleep(1);
	}
	return ;
}

int init_pack(int pack_no)
{
	int 		i, pack_size;
	struct icmp 	*picmp;
	struct timeval	*tval;
	picmp = (struct icmp *)send_data;
	picmp->icmp_type = ICMP_ECHO;
	picmp->icmp_code = 0;
	picmp->icmp_cksum = 0;
	picmp->icmp_seq = pack_no;
	picmp->icmp_id = pid;
	pack_size = 8 + data_len;
	tval = (struct timeval *)picmp->icmp_data;
	gettimeofday(tval, NULL);
	picmp->icmp_cksum = cal_chksum( (unsigned short *)picmp, pack_size);
	return pack_size;
}

unsigned short cal_chksum(unsigned short *addr, int len)
{
	int n_left = len;
	int sum = 0;
	unsigned short *w = addr;
	unsigned short answer = 0;

	while(n_left > 1)
	{
		sum += *w++;
		n_left -= 2;
	}	

	if(n_left == 1)
	{
		*(unsigned char *)(&answer) = *(unsigned char *)w;
		sum += answer;
	}
	
	sum = (sum >> 16) + (sum & 0xffff);
	sum += (sum >> 16);
	answer = ~sum;
	return answer;
}

void recv_pack()
{
	int	n, from_len;
	extern int	errno;
	signal(SIGALRM, statistics);
	from_len = sizeof(from);

	while( n_recv < n_send )
	{
		alarm(MAX_WAIT_TIME);
		if( (n = recvfrom(sockfd, recv_data, sizeof(recv_data), 0,
				(struct sockaddr *)&from, &from_len)) < 0 )
		{
			if(EINTR == errno)
				continue;
			perror("recvfrom error");
			continue;
		}
		gettimeofday(&tv_recv, NULL);
		if(unpack(recv_data, n) == -1)
			continue;
		n_recv ++;
	}
	return;
}

int unpack(char *buf, int len)
{
	int	i, iphdr_len;
	struct ip 	*ip;
	struct icmp	*picmp;
	struct timevak	*tv_send;
	double		rtt;
	
	ip = (struct ip *)buf;
	iphdr_len = ip->ip_hl << 2;
	picmp = (struct icmp *)(buf + iphdr_len);
	len -= iphdr_len;
	if(len < 8 )
	{
		printf("ICMP packets\'s length is less than 8.\n");
		return -1;
	}
	
	if( (picmp->icmp_type == ICMP_ECHOREPLY) && (picmp->icmp_id == pid) )
	{
		tv_send = (struct timeval *)picmp->icmp_data;
		tv_sub(&tv_recv, tv_send);
		rtt = tv_recv.tv_sec * 1000 + tv_recv.tv_usec / 1000;
		printf("%d byte from %s: icmp_seq=%u ttl=%d rtt=%.3f ms\n",
				len, inet_ntoa(from.sin_addr), 
				picmp->icmp_seq, ip->ip_ttl, rtt);
	}
	else
	{
		return -1;
	}
}

void statistics(int signo)
{
	printf("\n----------------------PING statistics---------------------\n");
	printf("%d packets transmitted, %d received, %%%d lost\n", 
			n_send, n_recv, (n_send - n_recv) / n_send * 100);
	close(sockfd);
	exit(1);
}

void tv_sub(struct timeval *out, struct timeval *in)
{
	if( (out->tv_usec -= in->tv_usec) < 0 )
	{
		-- out->tv_sec;
		out->tv_usec += 1000000;
	}
	out->tv_sec -= in->tv_sec;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值