在setsockopt()中设置超时

时间:2013-07-08 14:21:51

标签: c linux sockets recv

我使用此代码发送数据(IPPROTO_ICMP),使用套接字发送和接收数据

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <string.h>
#include <unistd.h>


char dst_addr[20];
char src_addr[20];

unsigned short in_cksum(unsigned short *, int);
void parse_argvs(char**, char*, char* );
void usage();
char* getip();
char* toip(char*);

int main(int argc, char* argv[])
{
struct iphdr* ip;
struct iphdr* ip_reply;
struct icmphdr* icmp;
struct icmphdr* icmp_reply;
struct sockaddr_in connection;
char* packet;
char* buffer;
int sockfd;
int optval;
int addrlen;
int siz;
int i;
//int toto=0;
//struct timeval timeout;      



//timeout.tv_sec = 10;
//timeout.tv_usec = 0;

if (getuid() != 0)
{
fprintf(stderr, "%s: root privelidges needed\n", *(argv + 0));
exit(EXIT_FAILURE);
}
//icmp_type = 11;
parse_argvs(argv, dst_addr, src_addr);
strncpy(dst_addr, toip(dst_addr), 20);
strncpy(src_addr, toip(src_addr), 20);
printf("Source address: %s\n", src_addr);
printf("Destination address: %s\n", dst_addr);

/*
* allocate all necessary memory
*/
packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
buffer = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));
/****************************************************************/

ip = (struct iphdr*) packet;
icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));

/*
* here the ip packet is set up
*/
ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr);
ip->id = htons(0);
ip->frag_off = 0;
ip->ttl = 1;
ip->protocol = IPPROTO_ICMP;
ip->saddr = inet_addr(src_addr);
ip->daddr = inet_addr(dst_addr);
ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr));

if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)
{
perror("socket");
exit(EXIT_FAILURE);
}
printf("=====> sockfd= %d \n",sockfd);
/*
* IP_HDRINCL must be set on the socket so that
* the kernel does not attempt to automatically add
* a default ip header to the packet
*/

setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));
/*
if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
            sizeof(timeout)) < 0)
    error("setsockopt failed\n");

if (setsockopt (sockfd, SOL_SOCKET , SO_SNDTIMEO, (char *)&timeout,
            sizeof(timeout)) < 0)
    error("setsockopt failed\n");*/

/*
* here the icmp packet is created
* also the ip checksum is generated
*/
icmp->type = ICMP_ECHO;
icmp->code = 0;
icmp->un.echo.id = random();
icmp->un.echo.sequence = 0;
icmp-> checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));


connection.sin_family = AF_INET;
connection.sin_addr.s_addr = inet_addr(dst_addr);

/*
* now the packet is sent
*/
//ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
              // const struct sockaddr *dest_addr, socklen_t addrlen);

//toto=11;
for(ip->ttl =1;ip->ttl <25 /*&& (icmp_type==11)*/;ip->ttl++)
{

sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&connection, sizeof(struct sockaddr));
printf("Sent %d byte packet to %s , >>>>> TTL=%d\n", ip->tot_len, dst_addr,ip->ttl);

for (i = 0; i < ip->tot_len; i++) {
      printf("%02X%s", (uint8_t)packet[i], (i + 1)%16 ? " " : "\n");
    }
printf("\n");

printf("ICMP msgtype=%d, code=%d \n", icmp->type, icmp->code);
/*
* now we listen for responses
*/
addrlen = sizeof(connection);
printf("recvfrom 00\n");
if (( siz = recvfrom(sockfd, buffer, sizeof(struct iphdr) + sizeof(struct icmphdr), 0, (struct sockaddr *)&connection, &addrlen)) == -1)
    {
    perror("recv");
    }
else
{
    printf("recvfrom 11\n");
    //printf("Received %d byte reply from %s:\n", siz , dst_addr);
    printf("node num :[ %d]  IP= %s:\n", ip->ttl, dst_addr);

    ip_reply   = (struct iphdr*) buffer;
    icmp_reply = (struct icmphdr*)(buffer+sizeof(struct iphdr));

    for (i = 0; i < siz; i++) 
        {
    printf("%02X%s", (uint8_t)buffer[i], (i + 1)%16 ? " " : "\n");
        }
    printf("\n icmp_reply->type %d \n",icmp_reply->type);
    printf("RCV ip->daddr = %s \n",inet_ntoa(*((struct in_addr *)&ip_reply->saddr)));

    printf("\n");
    printf("ID: %d\n", ntohs(ip_reply->id));
    printf("TTL: %d\n", ip_reply->ttl);
}
    printf("recvfrom 12\n");
}

free(packet);
free(buffer);
close(sockfd);
return 0;
}



void parse_argvs(char** argv, char* dst, char* src)
{
int i;
if(!(*(argv + 1)))
{
/* there are no options on the command line */
usage();
exit(EXIT_FAILURE);
}
if (*(argv + 1) && (!(*(argv + 2))))
{
/*
* only one argument provided
* assume it is the destination server
* source address is local host
*/
strncpy(dst, *(argv + 1), 15);
strncpy(src, getip(), 15);
return;
}
else if ((*(argv + 1) && (*(argv + 2))))
{
/*
* both the destination and source address are defined
* for now only implemented is a source address and
* destination address
*/
strncpy(dst, *(argv + 1), 15);
i = 2;
while(*(argv + i + 1))
{
    if (strncmp(*(argv + i), "-s", 2) == 0)
    {
    strncpy(src, *(argv + i + 1), 15);
    break;
    }
        i++;
    }
}

}

void usage()
{
fprintf(stderr, "\nUsage: pinger [destination] <-s [source]>\n");
fprintf(stderr, "Destination must be provided\n");
fprintf(stderr, "Source is optional\n\n");
}

char* getip()
{
char buffer[256];
struct hostent* h;

gethostname(buffer, 256);
h = gethostbyname(buffer);

return inet_ntoa(*(struct in_addr *)h->h_addr);

}

/*
* return the ip address if host provided by DNS name
*/
char* toip(char* address)
{
struct hostent* h;
h = gethostbyname(address);
return inet_ntoa(*(struct in_addr *)h->h_addr);
}

/*
* in_cksum --
* Checksum routine for Internet Protocol
* family headers (C Version)
*/
unsigned short in_cksum(unsigned short *addr, int len)
{
register int sum = 0;
u_short answer = 0;
register u_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)
{
*(u_char *) (&answer) = *(u_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);
}

问题是当我添加“toto”变量时,程序正在阻止

===&GT;阻止时运行代码的结果

root@root:/home/aa/test# ./ping www.yahoo.com
Source address: 192.168.1.227
Destination address: 98.139.183.24
=====> sockfd= 3 
Sent 28 byte packet to 98.139.183.24 , >>>>> TTL=1
45 00 1C 00 00 00 00 00 01 01 C1 CE C0 A8 01 E3
62 8B B7 18 08 00 90 BA 67 45 00 00 
ICMP msgtype=8, code=0 
recvfrom 00

这很奇怪,但是当我使用优化标志编译时,问题不会发生

==&GT; gcc -O -o ping ping.c而不是使用gcc -O -o ping ping.c

这是第一个问题!!

我在setsockopt函数中使用超时时发生了第二个问题。 !!

代码中的

我替换了这个函数

setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));

by:

if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
            sizeof(timeout)) < 0)
    error("setsockopt failed\n");

if (setsockopt (sockfd, SOL_SOCKET , SO_SNDTIMEO, (char *)&timeout,
            sizeof(timeout)) < 0)
    error("setsockopt failed\n");

==&GT;运行带有错误“recv:资源暂时不可用”的代码的结果

Source address: 192.168.1.227
Destination address: 98.139.183.24
=====> sockfd= 3 
Sent 28 byte packet to 98.139.183.24 , >>>>> TTL=1
45 00 1C 00 00 00 00 00 01 01 C1 CE C0 A8 01 E3
62 8B B7 18 08 00 90 BA 67 45 00 00 
ICMP msgtype=8, code=0 
recvfrom 00
recv: Resource temporarily unavailable
recvfrom 12
Sent 28 byte packet to 98.139.183.24 , >>>>> TTL=2
45 00 1C 00 00 00 00 00 02 01 C1 CE C0 A8 01 E3
62 8B B7 18 08 00 90 BA 67 45 00 00 
ICMP msgtype=8, code=0 
recvfrom 00
recv: Resource temporarily unavailable
recvfrom 12
Sent 28 byte packet to 98.139.183.24 , >>>>> TTL=3
45 00 1C 00 00 00 00 00 03 01 C1 CE C0 A8 01 E3
62 8B B7 18 08 00 90 BA 67 45 00 00 
ICMP msgtype=8, code=0 
recvfrom 00

0 个答案:

没有答案