Ping程序

ping.h

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>
#include <signal.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <pthread.h>

typedef struct pingm_pakcet
{
	struct timeval tv_begin;
	struct timeval tv_end;
	short seq;
	int flag;
}pingm_pakcet;

#define K (1024)
#define BUFFERSIZE (72)
static pingm_pakcet pingpacket[128];
static pingm_pakcet *icmp_findpacket(int seq);
static unsigned short icmp_cksum(unsigned char *data, int len);
static struct timeval icmp_tvsub(struct timeval end, struct timeval begin);
static void icmp_statistics(void);
static void icmp_pack(struct icmp *icmph, int seq, struct timeval *tv, int length);
static int icmp_unpack(char *buf, int len);
static void *icmp_recv(void *argv);
static void *icmp_send(void *argv);
static void icmp_sigint(int signo);
static void icmp_usage();
static char send_buff[BUFFERSIZE];
static char recv_buff[2*K];
static struct sockaddr_in dest;
static int rawsock = 0;
static pid_t pid = 0;
static int alive = 0;
static short packet_send = 0;
static short packet_recv = 0;
static char dest_str[80];
static struct timeval tv_begin, tv_end, tv_interval;

ping.c

#include "ping.h"

/*---------------------------------------------------------
; 函數: icmp_usage()
-----------------------------------------------------------*/
static void icmp_usage()
{
	printf("ping aaa.bbb.ccc.ddd\n");
}

/*---------------------------------------------------------
; 函數: main()
-----------------------------------------------------------*/
int main(int argc, char *argv[])
{
	struct hostent *host = NULL;
	struct protoent *protocol = NULL;
	char protoname[] = "icmp";
	unsigned long inaddr = 1;
	int size = 128 * K;
	int err  = 0;
	
	if(argc < 2)
	{
		icmp_usage();
		
		return -1;
	}
	
	protocol = getprotobyname(protoname);
	if(protocol == NULL)
	{
		perror("getprotobyname");
		
		return -1;
	}
	
	memcpy(dest_str, argv[1], strlen(argv[1]+1));
	memset(pingpacket, 0, sizeof(pingm_pakcet)*128);
	
	rawsock = socket(AF_INET, SOCK_RAW, protocol->p_proto);
	if(rawsock < 0)
	{
		perror("socket failad !\n");
		return -1;
	}
	
	pid = getuid();
	setsockopt(rawsock, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
	bzero(&dest, sizeof(dest));
	dest.sin_family = AF_INET;
	
	inaddr = inet_addr(argv[1]);
	if(inaddr == INADDR_NONE)
	{
		host = gethostbyname(argv[1]);
		if(host == NULL)
		{
			perror("gethostbyname failed !");
			
			return -1;
		}
		
		memcpy((char*)&dest.sin_addr, host->h_addr, host->h_length);
	}
	else
	{
		memcpy((char*)&dest.sin_addr, &inaddr, sizeof(inaddr));
	}
	
	inaddr = dest.sin_addr.s_addr;
	printf("Ping %s (%ld.%ld.%ld.%ld) 56(84) bytes of data.\n",
			dest_str,
			(inaddr & 0x000000FF)>>0,
			(inaddr & 0x0000FF00)>>8,
			(inaddr & 0x00FF0000)>>16,
			(inaddr & 0xFF000000)>>24
		  );
		  
	signal(SIGINT, icmp_sigint);
	alive = 1;
	pthread_t send_id, recv_id;
	
	err = pthread_create(&send_id, NULL, icmp_send, NULL);
	if(err < 0)
	{
		return -1;
	}
	
	err = pthread_create(&recv_id, NULL, icmp_recv, NULL);
	if(err < 0)
	{
		return -1;
	}
	
	pthread_join(send_id, NULL);
	pthread_join(recv_id, NULL);
	
	close(rawsock);
	icmp_statistics();
	return 0;
}

/*---------------------------------------------------------
; 函數: icmp_cksum()
-----------------------------------------------------------*/
static unsigned short icmp_cksum(unsigned char *data, int len)
{
	int sum = 0;
	int odd = len & 0x01;
	
	while(len & 0xfffe)
	{
		sum += *(unsigned short*)data;
		data+= 2;
		len -= 2;
	}
	
	if(odd)
	{
		unsigned short tmp = ((*data)<<8) & 0xff00;
	}
	
	sum = (sum >> 16) + (sum & 0xffff);
	sum += (sum >> 16);
	
	return ~sum;
}

/*---------------------------------------------------------
; 函數: icmp_pack()
-----------------------------------------------------------*/
static void icmp_pack(struct icmp *icmph, int seq, struct timeval *tv, int length)
{
	unsigned char i = 0;
	
	icmph->icmp_type = ICMP_ECHO;
	icmph->icmp_code = 0;
	icmph->icmp_cksum= 0;
	icmph->icmp_seq  = seq;
	icmph->icmp_id   = pid & 0xffff;
	
	for(i=0; i<length; i++)
	{
		icmph->icmp_data[i] = i;
	}
	
	icmph->icmp_cksum = icmp_cksum((unsigned char*)icmph, length);
}

/*---------------------------------------------------------
; 函數: icmp_unpack()
-----------------------------------------------------------*/
static int icmp_unpack(char *buf, int len)
{
	int iphdrlen;
	struct ip *ip = NULL;
	struct icmp *icmp = NULL;
	int rtt;
	
	ip = (struct ip*)buf;
	iphdrlen = ip->ip_hl * 4;
	icmp = (struct icmp*)(buf+iphdrlen);
	
	len -= iphdrlen;
	if(len < 8)
	{
		printf("ICMP packets\'s length is less than 8\n");
		
		return -1;
	}
	
	if((icmp->icmp_type == ICMP_ECHOREPLY) && (icmp->icmp_id == pid))
	{
		struct timeval tv_internel, tv_recv, tv_send;
		
		pingm_pakcet *packet = icmp_findpacket(icmp->icmp_seq);
		if(packet == NULL)
		{
			return -1;
		}
		
		packet->flag = 0;
		tv_send = packet->tv_begin;
		gettimeofday(&tv_recv, NULL);
		tv_internel = icmp_tvsub(tv_recv, tv_send);
		rtt = tv_internel.tv_sec*1000 + tv_internel.tv_usec/1000;
		
		printf("%d byte from %s: icmp_seq=%u ttl=%d rtt=%d ms\n",
				len,
				inet_ntoa(ip->ip_src),
				icmp->icmp_seq,
				ip->ip_ttl,
				rtt
			  );
			  
		packet_recv ++;
	}
	else
	{
		return -1;
	}
	
	return 0;
	
}

/*---------------------------------------------------------
; 函數: icmp_tvsub()
-----------------------------------------------------------*/
static struct timeval icmp_tvsub(struct timeval end, struct timeval begin)
{
	struct timeval tv;
	
	tv.tv_sec = end.tv_sec - begin.tv_sec;
	tv.tv_usec= end.tv_usec - begin.tv_usec;
	
	if(tv.tv_usec < 0)
	{
		tv.tv_sec --;
		tv.tv_usec += 1000000;
	}
	
	return tv;
}

/*---------------------------------------------------------
; 函數: icmp_send()
-----------------------------------------------------------*/
static void* icmp_send(void *argv)
{
	gettimeofday(&tv_begin, NULL);
	
	while(alive)
	{
		int size = 0;
		struct timeval tv;
		gettimeofday(&tv, NULL);
		
		pingm_pakcet *packet = icmp_findpacket(-1);
		if(packet)
		{
			packet->seq = packet_send;
			packet->flag = 1;
			gettimeofday(&packet->tv_begin, NULL);
		}
		
		icmp_pack((struct icmp*)send_buff, packet_send, &tv, 64);
		
		size = sendto(rawsock, send_buff, 64, 0, (struct sockaddr*)&dest, sizeof(dest));
		if(size < 0)
		{
			perror("sendto error");
			
			continue;
		}
		
		packet_send++;
		sleep(1);		
	}
}

/*---------------------------------------------------------
; 函數: icmp_recv()
-----------------------------------------------------------*/
static void *icmp_recv(void *argv)
{
	struct timeval tv;
	tv.tv_usec = 200;
	tv.tv_sec = 0;
	fd_set readfd;
	
	while(alive)
	{
		int ret = 0;
		FD_ZERO(&readfd);
		FD_SET(rawsock, &readfd);
		ret = select(rawsock+1, &readfd, NULL, NULL, &tv);
		
		switch(ret)
		{
			case -1:
			{
				break;
			}
			case 0:
			{
				break;
			}
			default:
			{
				int size = recv(rawsock, recv_buff, sizeof(recv_buff), 0);
				if(errno == EINTR)
				{
					perror("recvfrom error");
					
					continue;
				}
				
				ret = icmp_unpack(recv_buff, size);
				if(ret == -1)
				{
					continue;
				}
				
			}
			
			break;
		}
	}
}

/*---------------------------------------------------------
; 函數: icmp_findpacket()
-----------------------------------------------------------*/
static pingm_pakcet *icmp_findpacket(int seq)
{
	int i = 0;
	pingm_pakcet *found = NULL;
	
	if(seq == -1)
	{
		for(i=0; i<128; i++)
		{
			if(pingpacket[i].flag == 0)
			{
				found = &pingpacket[i];
				
				break;
			}
		}
	}
	else if(seq >= 0)
	{
		for(i=0; i<128; i++)
		{
			if(pingpacket[i].seq == seq)
			{
				found = &pingpacket[i];
				
				break;
			}
		}
	}
	
	return found;
}

/*---------------------------------------------------------
; 函數: icmp_statistics()
-----------------------------------------------------------*/
static void icmp_statistics(void)
{
	long time = (tv_interval.tv_sec * 1000) + (tv_interval.tv_usec/1000);
	printf("%s ping statistics\n", dest_str);
	printf("%d packets transmitted, %d received, %d packet loss, time %ldms\n",
			packet_send,
			packet_recv,
			(packet_send-packet_recv)*100/packet_send,
			time
		  );
}

/*---------------------------------------------------------
; 函數: icmp_signint()
-----------------------------------------------------------*/
static void icmp_sigint(int signo)
{
	alive = 0;
	gettimeofday(&tv_end, NULL);
	tv_interval = icmp_tvsub(tv_end, tv_begin);
	
	return ;
}

運行示例:

[root@Linux Ping]# ./ping.o 192.168.0.100
Ping 192.168.0.10 (192.168.0.100) 56(84) bytes of data.
64 byte from 192.168.0.100: icmp_seq=0 ttl=128 rtt=0 ms
64 byte from 192.168.0.100: icmp_seq=1 ttl=128 rtt=0 ms
64 byte from 192.168.0.100: icmp_seq=2 ttl=128 rtt=1 ms
64 byte from 192.168.0.100: icmp_seq=3 ttl=128 rtt=0 ms
64 byte from 192.168.0.100: icmp_seq=4 ttl=128 rtt=1 ms
64 byte from 192.168.0.100: icmp_seq=5 ttl=128 rtt=1 ms
64 byte from 192.168.0.100: icmp_seq=6 ttl=128 rtt=0 ms
64 byte from 192.168.0.100: icmp_seq=7 ttl=128 rtt=1 ms
64 byte from 192.168.0.100: icmp_seq=8 ttl=128 rtt=1 ms
64 byte from 192.168.0.100: icmp_seq=9 ttl=128 rtt=0 ms
64 byte from 192.168.0.100: icmp_seq=10 ttl=128 rtt=0 ms
64 byte from 192.168.0.100: icmp_seq=11 ttl=128 rtt=1 ms
64 byte from 192.168.0.100: icmp_seq=12 ttl=128 rtt=0 ms
64 byte from 192.168.0.100: icmp_seq=13 ttl=128 rtt=0 ms
64 byte from 192.168.0.100: icmp_seq=14 ttl=128 rtt=0 ms
64 byte from 192.168.0.100: icmp_seq=15 ttl=128 rtt=0 ms
64 byte from 192.168.0.100: icmp_seq=16 ttl=128 rtt=1 ms
64 byte from 192.168.0.100: icmp_seq=17 ttl=128 rtt=1 ms
64 byte from 192.168.0.100: icmp_seq=18 ttl=128 rtt=1 ms
64 byte from 192.168.0.100: icmp_seq=19 ttl=128 rtt=1 ms
64 byte from 192.168.0.100: icmp_seq=20 ttl=128 rtt=0 ms
64 byte from 192.168.0.100: icmp_seq=21 ttl=128 rtt=1 ms
^X^C192.168.0.10 ping statistics
22 packets transmitted, 22 received, 0 packet loss, time 21405ms


發佈了56 篇原創文章 · 獲贊 1 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章