#define ICMP_ECHOREPLY 0
#define ICMP_UNREACH 3
#ifdef _WIN32
#define my_sleep(milsec) Sleep(milsec)
#define sock_close(s) closesocket(s)
#endif
#ifdef __linux__
#define my_sleep(milsec) usleep(milsec*1000)
#define sock_close(s) close(s)
#endif
int ping(const char *host, int loop)
{
int sock, use_icmp_socket, i, ttl, maxdiff, mindiff, alldiff, allreceive;
char *ip, raw[DATALEN];
struct sockaddr_in dst_addr, *sockaddr;
struct timeval wait_timeout;
struct addrinfo *result;
fd_set readfds;
#ifdef _WIN32
WSADATA WSAData;
if (WSAStartup(MAKEWORD(2, 2), &WSAData) != 0) {
return -1;
}
#endif
/* find ip */
if (getaddrinfo(host, NULL, NULL, &result) != 0) {
fprintf(stderr, "getaddrinfo() error.\n");
return -1;
}
/* use the first result */
sockaddr = (struct sockaddr_in *)result->ai_addr;
ip = strdup(inet_ntoa(sockaddr->sin_addr));
freeaddrinfo(result);
/* address */
dst_addr.sin_family = AF_INET;
dst_addr.sin_port = 0;
dst_addr.sin_addr.s_addr = inet_addr(ip);
for (i = 0; i < DATALEN; i++) {
raw[i] = ' ' + (char)i;
}
/* socket */
use_icmp_socket = 0;
sock = -1;
#ifdef __linux__
/* icmp socket available in kernel 3.0 */
/* # echo 1000 1000 | sudo tee -a /proc/sys/net/ipv4/ping_group_range */
sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (sock != -1) {
int hold = 1;
use_icmp_socket = 1;
if (setsockopt(sock, SOL_IP, IP_RECVTTL, (char *)&hold, sizeof(hold))) {
fprintf(stderr, "setsockopt(IP_RECVTTL) error.\n");
}
}
#endif
if (sock == -1) {
sock = (int)socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sock == -1) {
fprintf(stderr, "socket() error.\n");
free(ip);
return -1;
}
}
/* loop */
maxdiff = mindiff = alldiff = allreceive = 0;
printf("PING %s (%s) %d(%d) bytes of data.\n", host, ip, DATALEN-8, sizeof(icmp_echo_reply_t));
for (i = 0; i < loop; i++) {
send_echo_request(sock, &dst_addr, i, raw);
/* select */
FD_ZERO(&readfds);
FD_SET(sock, &readfds);
wait_timeout.tv_sec = 3;
wait_timeout.tv_usec = 0;
if (select(sock+1, &readfds, NULL, NULL, &wait_timeout) <= 0) {
printf("Request timed out.\n");
} else {
int diff;
icmp_echo_request_t reply;
#ifdef _WIN32
if (recv_echo_reply(sock, use_icmp_socket, &ttl, &reply) == -1) {
continue;
}
diff = GetTickCount() - reply.data.tick;
#endif
#ifdef __linux__
struct timeval cur_tv;
if (recv_echo_reply(sock, use_icmp_socket, &ttl, &reply) == -1) {
continue;
}
gettimeofday(&cur_tv, NULL);
diff = (cur_tv.tv_sec-reply.data.tv.tv_sec)*1000*1000 + (cur_tv.tv_usec-reply.data.tv.tv_usec);
diff /= 1000;
#endif
if (reply.icmp_hd.type == ICMP_UNREACH) {
/* ??? */
} else if (reply.icmp_hd.type == ICMP_ECHOREPLY) {
allreceive++;
alldiff += diff;
maxdiff = (diff > maxdiff) ? diff : maxdiff;
if (mindiff == 0) {
mindiff = diff;
} else {
mindiff = (diff < mindiff) ? diff : mindiff;
}
printf("%d bytes from %s (%s): icmp_req=%d ttl=%d time=%d ms\n",
DATALEN, host, ip, reply.icmp_hd.sequence, ttl, diff);
}
}
my_sleep(1000);
}
/* statistic */
printf("\n--- %s ping statistics ---\n", host);
printf("%d packets transmitted, %d received, %d%% packet loss, time %d ms\n",
loop, allreceive, (loop-allreceive)*100/loop, alldiff);
if (allreceive != 0) {
printf("rtt min/avg/max = %d/%d/%d ms\n", mindiff, alldiff/allreceive, maxdiff);
}
printf("\n");
free(ip);
sock_close(sock);
#ifdef WIN32
WSACleanup();
#endif
return 0;
}