#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <libgen.h>
#include <sys/types.h>
#include <sys/time.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <netinet/ip_icmp.h>
#ifndef likely
#define likely(x) __builtin_expect(!!(x), 1)
#endif
#ifndef unlikely
#define unlikely(x) __builtin_expect(!!(x), 0)
#endif
#define PACKETSIZE 64
struct packet_st
{
struct icmphdr icmph;
char message[PACKETSIZE-sizeof(struct icmphdr)];
};
static volatile sig_atomic_t isterm = 0; // 结束信号
static volatile sig_atomic_t isalarm = 0; // 时钟信号(1秒1次)
// 中断后的信号处理函数
static void signals_handler(int sig, siginfo_t *si, void *context)
{
switch(sig)
{
case SIGINT: case SIGTERM:
isterm = sig;
break;
case SIGALRM:
isalarm = sig;
break;
default:
break;
}
}
// 注册信号中断
static void signals_register()
{
struct sigaction act;
struct itimerval interval;
sigfillset(&act.sa_mask);
sigdelset(&act.sa_mask, SIGINT);
sigdelset(&act.sa_mask, SIGTERM);
sigdelset(&act.sa_mask, SIGALRM);
sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = signals_handler;
interval.it_interval.tv_sec = 1;
interval.it_interval.tv_usec = 0;
interval.it_value.tv_sec = 1;
interval.it_value.tv_usec = 0;
sigaction(SIGINT, &act, NULL);
sigaction(SIGTERM, &act, NULL);
sigaction(SIGALRM, &act, NULL);
setitimer(ITIMER_REAL, &interval, NULL);
}
/*
* in_cksum --
* Checksum routine for Internet Protocol family headers (C Version)
*/
unsigned short in_cksum(unsigned short *addr,int len)
{
register int sum = 0;
unsigned short answer = 0;
register unsigned short *w = addr;
register int nleft = len;
/*
* Our algorithm is simple, using a 32 bit accumulator (sum), we add
* sequential 16 bit words to it, and at the end, fold back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
*(unsigned char *)(&answer) = *(unsigned char *)w ;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return(answer);
}
int pinger(char *ip)
{
int fd = 0;
static unsigned short count = 0;
fd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(fd == -1)
{
fprintf(stderr, "socket(): %s\n", strerror(errno));
return -1;
}
fcntl(fd, F_SETFD, FD_CLOEXEC);
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
int flag = 1;
struct timeval tv = {
.tv_sec = 3,
.tv_usec = 0
};
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &flag, sizeof(int));
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval));
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
struct packet_st pkt;
memset(&pkt, 0, sizeof(struct packet_st));
pkt.icmph.type = ICMP_ECHO;
pkt.icmph.code = 0;
pkt.icmph.un.echo.id = (unsigned short)getpid();
pkt.icmph.un.echo.sequence = ++count;
pkt.icmph.checksum = in_cksum((unsigned short*)&pkt, sizeof(struct packet_st));
struct sockaddr_in addr, from;
memset(&addr, 0, sizeof(struct sockaddr_in));
memset(&from, 0, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(ip);
int ret = 0;
socklen_t len = sizeof(struct sockaddr);
ret = sendto(fd, &pkt, sizeof(struct packet_st), 0, (struct sockaddr*)&addr, len);
if(ret == -1 && errno != EINTR)
{
fprintf(stderr, "sendto(): %s\n", strerror(errno));
goto EndP;
}
fprintf(stdout, "sendto: %s\n", ip);
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
while((ret = select(fd+1, &readfds, NULL, NULL, &tv)))
{
if(ret == -1 && errno != EINTR)
{
fprintf(stderr, "select(): %s\n", strerror(errno));
continue;
}
if(0 <= fd && fd < FD_SETSIZE && FD_ISSET(fd, &readfds))
{
ret = recvfrom(fd, &pkt, sizeof(struct packet_st), 0, (struct sockaddr*)&from, &len);
if(ret == -1 && errno != EINTR)
{
fprintf(stderr, "recvfrom(): %s\n", strerror(errno));
continue;
}
fprintf(stdout, "recvfrom: %s\n", inet_ntoa(from.sin_addr));
break;
}
}
FD_CLR(fd, &readfds);
EndP:
if(fd) close(fd);
return ret;
}
int main(int argc, char *argv[])
{
if(argc != 2)
{
fprintf(stderr, "Usage: %s IPADDR\n", argv[0]);
return -1;
}
signals_register();
while(!isterm)
{
if(unlikely(isterm))
{
fprintf(stdout, "term signal: %d\n", isterm);
isterm = 0;
}
if(likely(isalarm))
{
fprintf(stdout, "alarm signal: %d\n", isalarm);
isalarm = 0;
pinger(argv[1] ? argv[1] : "127.0.0.1");
}
sleep(-1);
}
return 0;
}
Ping程序示例
最新推荐文章于 2022-03-19 14:38:55 发布