Разрешение имени URL не соответствует ожидаемому

У меня есть небольшая программа, чтобы позволить мне подключиться через 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 ответ

Решение

Проблема здесь:

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

Вы не завершаете строку нулем. Попробуйте использовать

strcpy(host, addr_tmp);

В противном случае остальная часть исходного имени хоста останется и сделает недействительным IP-адрес (1.2.3.4nkenlights.nl или похожие). google.com достаточно короток, чтобы его можно было полностью перезаписать, так как случайно IP-адрес на нём заканчивается.

Другие вопросы по тегам