亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区
Chinaunix
標題:
[已解決] ping程序的問題.
[打印本頁]
作者:
PCliangtao
時間:
2010-11-17 19:58
標題:
[已解決] ping程序的問題.
本帖最后由 PCliangtao 于 2010-11-17 20:50 編輯
在看UNP的時候,把書中的ping程序的例子的原理掌握之后,自己嘗試寫了一下.換湯不換藥... 只不過純粹只于IPv4打交道...
不知道什么原理. 在發(fā)出echo的ICMP之后... 卻一直阻塞在recvmsg調用上... 我用tcpdump看...的確發(fā)生了ICMP ECHO...
還有奇怪的一點的所... ping
www.hao123.com能夠正常工作...
ping
www.baidu.com
www.goolge.com這樣的時候就一直阻塞在recvmsg上...
接觸網絡變成不久... 希望有經驗的兄弟們給瞧瞧... 多謝..
NB: 仔細想了一下... 估計是發(fā)送的ICMP 包被遠端丟棄了... 仔細看了一下構造ICMP 頭部的代碼... 汗ing... 校驗和的計算參數(shù)傳錯了...沒有把ICMP頭部算在內...修改了一下...
就好了...
可是還有一點奇怪的是... ICMP 對回送請求的應答應該是在內核里進行的吧... 但是為什么
www.hao123.com
主機能夠接受錯誤的校驗和的ICMP ECHO請求包呢?
翻一翻TCP/IP的源代碼去...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>
#define BUFSIZE 1024
/* need those global vars, for simplicity */
const char Usage[] = "Usage: ping [-v] host(hostname or hostIP)\n";
static int nsnd;
static int datalen;
static int sockfd;
static int verbose;
static pid_t pid;
static char sndbuf[BUFSIZE];
static struct sockaddr *rcvaddr;
static struct sockaddr *sndaddr;
static socklen_t addrlen;
/* some of the function prototypes */
static void send_echo_icmp(void);
static void recv_echoreply_icmp(char *, int, struct timeval *);
static void sig_alrm(int signo);
static char *show_addr_ip(struct sockaddr *, socklen_t len);
static inline u_int16_t ip_fast_csum(const void *, unsigned int);
static inline void err_quit(const char *str)
{
perror(str);
exit(-1);
}
static inline void err_sys(const char *str)
{
perror(str);
}
int main(int argc, char *argv[])
{
int c;
char *host;
char *hostip;
char rcvbuf[BUFSIZE], ctlbuf[BUFSIZE];
struct msghdr msg;
struct iovec iov;
struct timeval rcvtv;
int size, n;
struct addrinfo *ai, *saved_ai, hint;
while((c = getopt(argc, argv, "v")) != -1) {
switch(c) {
case 'v':
verbose++;
break;
default:
printf("unrecognized option %c\n", c);
exit(-1);
}
}
if(optind != argc - 1) {
printf(Usage);
exit(-1);
}
host = argv[optind];
datalen = 56;
signal(SIGALRM, sig_alrm);
pid = getpid() & 0xffff;
bzero(&hint, sizeof(hint));
hint.ai_flags = AI_CANONNAME;
hint.ai_family = AF_INET;
if(getaddrinfo(host, NULL, &hint, &ai) < 0)
err_quit("getaddrinfo error: ");
saved_ai = ai; /* don't need to do this actually */
for(; ai; ai = ai->ai_next)
if(ai->ai_family == AF_INET)
break;
if(!ai) {
printf("cann't get IPv4 addrinfo\n");
exit(-1);
}
hostip = show_addr_ip(ai->ai_addr, ai->ai_addrlen);
printf("ping %s (%s): %d data bytes\n", ai->ai_canonname ? \
ai->ai_canonname : hostip, hostip, datalen);
sndaddr = ai->ai_addr;
addrlen = ai->ai_addrlen;
rcvaddr = (struct sockaddr *) malloc(addrlen);
if(!rcvaddr) {
printf("malloc failed, OOM\n");
exit(-1);
}
/* now we got all the information required, create the RAW socket and get started */
sockfd = socket(sndaddr->sa_family, SOCK_RAW, IPPROTO_ICMP);
if(sockfd < 0)
err_quit("create socket error: ");
setuid(getuid()); /* only create RAW sock need privilege */
size = 60 * 1024;
setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
sig_alrm(SIGALRM);
iov.iov_base = rcvbuf;
iov.iov_len = sizeof(rcvbuf);
msg.msg_name = rcvaddr;
msg.msg_namelen = addrlen;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = ctlbuf;
msg.msg_controllen = sizeof(ctlbuf);
while(1) {
n = recvmsg(sockfd, &msg, 0);
if(n < 0) {
if(errno == EINTR)
continue;
else {
err_sys("recvmsg error: ");
continue;
}
}
gettimeofday(&rcvtv, NULL);
/*
* what if this process is slower than recv...maybe we'll get corrupted
* rcvtv .this should not be a problem, cause the internet is much much
* slower, respectly.
*/
recv_echoreply_icmp(rcvbuf, n, &rcvtv);
}
}
static void sig_alrm(int signo)
{
send_echo_icmp();
alarm(1);
return;
}
/* send the icmp echo request */
static void send_echo_icmp()
{
int len;
struct icmp *icmp;
icmp = (struct icmp *)sndbuf;
/* build the icmp header */
icmp->icmp_type = ICMP_ECHO;
icmp->icmp_code = 0;
icmp->icmp_id = pid;
icmp->icmp_seq = ++nsnd;
if(datalen & 3) {
fprintf(stderr, "datalen must be a multiple of 4!\n");
datalen = (datalen + 3) & (~3UL);
}
memset(icmp->icmp_data, 0xa5, datalen);
gettimeofday((struct timeval *)icmp->icmp_data, NULL);
len = 8 + datalen;
icmp->icmp_cksum = 0;
icmp->icmp_cksum = ip_fast_csum(icmp->icmp_data, len >> 2);
if(sendto(sockfd, sndbuf, len, 0, sndaddr, addrlen) < 0)
if(errno != EINTR)
err_quit("sendto error: ");
}
static inline void cal_rtt(struct timeval *rcv, struct timeval *snd, double *rtt)
{
if((rcv->tv_usec -= snd->tv_usec) < 0) {
rcv->tv_sec--;
rcv->tv_usec += 1000000;
}
rcv->tv_sec -= snd->tv_sec;
*rtt = rcv->tv_sec * 1000.0+ rcv->tv_usec / 1000.0;
}
static void recv_echoreply_icmp(char *rcvbuf, int len, struct timeval *rcv_tv)
{
int iplen, icmplen;
double rtt;
struct ip *ip;
struct icmp *icmp;
struct timeval *snd_tv;
ip = (struct ip *)rcvbuf;
iplen = ip->ip_hl << 2;
if(ip->ip_p != IPPROTO_ICMP)
goto ignore;
icmp = (struct icmp *)(rcvbuf + iplen);
icmplen = len - iplen;
if(icmplen < 8)
goto ignore;
if(icmp->icmp_type == ICMP_ECHOREPLY) {
if(icmp->icmp_id != pid)
goto ignore;
if(icmplen < 8+sizeof(struct timeval))
goto ignore;
snd_tv = (struct timeval *)icmp->icmp_data;
cal_rtt(rcv_tv, snd_tv, &rtt);
printf("%d bytes from %s: seq=%d, ttl=%d, rtt=%.3f ms\n", \
icmplen, show_addr_ip(rcvaddr, addrlen), icmp->icmp_seq, \
ip->ip_ttl, rtt);
} else if(verbose) {
printf("%d bytes from %s: type=%d, code=%d\n", icmplen, \
show_addr_ip(rcvaddr, addrlen), icmp->icmp_type,\
icmp->icmp_code);
}
ignore:
return;
}
/* it's not safe, though */
static char *show_addr_ip(struct sockaddr *sa, socklen_t len)
{
static char ipbuf[INET6_ADDRSTRLEN];
switch(sa->sa_family) {
case AF_INET: {
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
if(len < sizeof(struct sockaddr_in))
return NULL;
if(inet_ntop(AF_INET, &sin->sin_addr, ipbuf,\
INET6_ADDRSTRLEN) < 0)
return NULL;
return ipbuf;
break;
}
default:
printf("don't support other addr type\n");
return NULL;
}
}
/*
* This is a version of ip_compute_csum() optimized for IP headers,
* which always checksum on 4 octet boundaries.
*
* By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
* Arnt Gulbrandsen.
*/
static inline u_int16_t ip_fast_csum(const void *iph, unsigned int ihl)
{
unsigned int sum;
asm volatile("movl (%1), %0 ;\n"
"subl $4, %2 ;\n"
"jbe 2f ;\n"
"addl 4(%1), %0 ;\n"
"adcl 8(%1), %0 ;\n"
"adcl 12(%1), %0;\n"
"1: adcl 16(%1), %0 ;\n"
"lea 4(%1), %1 ;\n"
"decl %2 ;\n"
"jne 1b ;\n"
"adcl $0, %0 ;\n"
"movl %0, %2 ;\n"
"shrl $16, %0 ;\n"
"addw %w2, %w0 ;\n"
"adcl $0, %0 ;\n"
"notl %0 ;\n"
"2: ;\n"
/* Since the input registers which are loaded with iph and ihl
are modified, we must also specify them as outputs, or gcc
will assume they contain their original values. */
: "=r" (sum), "=r" (iph), "=r" (ihl)
: "1" (iph), "2" (ihl)
: "memory");
return (u_int16_t)sum;
}
復制代碼
歡迎光臨 Chinaunix (http://www.72891.cn/)
Powered by Discuz! X3.2