2016-02-04 62 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