URL名称解析不符合预期

时间:2016-02-04 22:21:03

标签: c sockets tcp ip name-resolution

我有一个小程序让我通过TCP连接;并进行文字交流:

#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,地址会解析,我输入GET /,然后我获得该流的转储。

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

$ echo $?
2

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

1 个答案:

答案 0 :(得分:1)

问题在于:

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

您不会终止字符串。尝试使用

strcpy(host, addr_tmp);

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