2016-02-04 32 views
0

我有一个小程序让我通过TCP连接;并具有文本交换:URL名称解析没有按预期行事

#include <arpa/inet.h> 
#include <error.h> 
#include <fcntl.h> 
#include <netdb.h> 
#include <signal.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <unistd.h> 

#define BUFLEN 1024 

int connect_to(char *host, int port) { 
    int sd; 
    struct sockaddr_in addr; 
    fd_set sfds; 
    struct timeval tv; 

    sd = socket(AF_INET, SOCK_STREAM, 0); 
    if (sd == -1) return sd; 
    if (fcntl(sd, F_SETFL, O_NONBLOCK) == -1) return -2; 
    memset(&addr, 0, sizeof (addr)); 
    addr.sin_family = AF_INET; 
    if (inet_pton(AF_INET, host, &addr.sin_addr) != 1) 
     return -3; 
    addr.sin_port = htons(port); 
    connect(sd, (struct sockaddr *) &addr, sizeof (addr)); 
    FD_ZERO(&sfds); 
    FD_SET(sd, &sfds); 
    tv.tv_sec = 4; 
    tv.tv_usec = 0; 
    if (select(sd + 1, NULL, &sfds, NULL, &tv)) return sd; 
    return -4; 
} 

int resolve(char *host) { 
    struct addrinfo hints, *servinfo; 
    struct in_addr addr; 
    char *addr_tmp; 
    int rv; 

    memset(&hints, 0, sizeof hints); 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_family = AF_INET; 
    rv = getaddrinfo(host, NULL, &hints, &servinfo); 
    if (rv) return -1; 
    addr.s_addr = ((struct sockaddr_in*)servinfo->ai_addr)->sin_addr.s_addr; 
    addr_tmp = inet_ntoa(addr); 
    memcpy(host, addr_tmp, strlen(addr_tmp)); 
    freeaddrinfo(servinfo); 
    return 0; 
} 

sig_atomic_t run = 1; 

void sig_handler(int sig) { run = 0; } 


int transfer(int fd_in, char *buf, int buf_len, int fd_out) { 
    int len = read(fd_in, buf, buf_len); 
    return len > -1? write(fd_out, buf, len) - len: -1; 
} 

int main(int argc, char **argv) { 
    int sd, rv; 
    fd_set fds; 
    struct timeval tv; 
    char buffer[BUFLEN]; 
    char host[256], *port; 

    memcpy(host, argv[1], strlen(argv[1]) + 1); 
    port = argv[2]; 
    sd = connect_to(host, atoi(port)); 
    if (sd < 0) { 
     if (resolve(host) < 0) return 1; 
     else sd = connect_to(host, atoi(port)); 
     if (sd < 0) return 2; 
    } 

    write(STDOUT_FILENO, "connected\n", 11); 

    signal(SIGINT, sig_handler); 

    FD_ZERO(&fds); 
    tv.tv_sec = 0; 
    tv.tv_usec = 100000; 
    while (run) { 
     FD_SET(sd, &fds); 
     FD_SET(STDIN_FILENO, &fds); 
     (void)select(sd + 1, &fds, NULL, NULL, &tv); 
     if (FD_ISSET(STDIN_FILENO, &fds)) rv = transfer(STDIN_FILENO, buffer, BUFLEN, sd); 
     if (FD_ISSET(sd, &fds)) rv = transfer(sd, buffer, BUFLEN, STDOUT_FILENO); 
     if (rv < 0) return 3; 
    } 
    close(sd); 

    return 0; 
} 

如果键入$ ./client google.com 80,地址解析,I型GET /,我也得到该流的转储。

但是,如果我输入$ ./client towel.blinkenlights.nl 23;该程序退出。

$ echo $? 
2 

...告诉我resolve没有返回数据有效的connect_to。我不明白为什么。

回答

1

的问题是在这里:

memcpy(host, addr_tmp, strlen(addr_tmp)); 

你不空终止字符串。尝试使用

strcpy(host, addr_tmp); 

否则,原有的主机名的其余部分将保持和无效的IP地址(1.2.3.4nkenlights.nl或类似)。 google.com足够短,足以被覆盖,偶然IP地址在那里被终止。

+0

谢谢!我认为几乎所有需要修复的bug都与这样的明显错误有关;主要是因为它们非常明显。 – motoku