Как я могу привязать сокет к IPv6-адресу? - PullRequest
2 голосов
/ 24 октября 2019

Я пытаюсь портировать приложения ipv4 на ipv6, но не могу связать сокет с адресом ipv6.

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

err=bind(listening, (sockaddr*)&hint, sizeof(hint));

Значение err должно быть 0, но в этом коде возвращается -1. Что не так?

SOCKET listening = socket(AF_INET6, SOCK_STREAM, 0);
    if (listening == INVALID_SOCKET)
    {
        cerr << "Can't create a socket! Quitting" << endl;
        return;
    }
    int err;
    // Bind the ip address and port to a socket
    sockaddr_in6 hint;
    hint.sin6_family = AF_INET6;
    hint.sin6_flowinfo = 0;
    hint.sin6_port = htons(54000);
    hint.sin6_addr = in6addr_any;
    err=bind(listening, (sockaddr*)&hint, sizeof(hint)); //<======= here

Ответы [ 2 ]

3 голосов
/ 24 октября 2019

Вместо того, чтобы заполнять sockaddr_in6 вручную, вы можете (и должны) использовать getaddrinfo() вместо этого и позволить ему выделить для вас правильно заполненный sockaddr_in6, например:

int err;

SOCKET listening = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (listening == INVALID_SOCKET)
{
    err = WSAGetLastError(); // or errno on non-Windows platforms...
    cerr << "Can't create a socket! Error " << err << ". Quitting" << endl;
    return;
}

// Bind the ip address and port to a socket

addrinfo hint = {};
hint.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
hint.ai_family = AF_INET6;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;

addrinfo *res;

err = getaddrinfo("::0", "54000", &hint, &res);
if (err != 0)
{
    cerr << "Can't get address to bind the socket! Error " << err << ". Quitting" << endl;
    closesocket(listening); // or close() on non-Windows platforms...
    return;
}

err = bind(listening, res->ai_addr, res->ai_addrlen);
if (err == SOCKET_ERROR)
{
    err = WSAGetLastError(); // or errno on non-Windows platforms...
    cerr << "Can't bind the socket! Error " << err << ". Quitting" << endl;
    freeaddrinfo(res);
    closesocket(listening); // or close() on non-Windows platforms...
    return;
}

freeaddrinfo(res);

...
2 голосов
/ 24 октября 2019

Это может зависеть от вашей платформы, но в Linux начиная с 2.4 структура sockaddr_in6 также содержит член sin6_scope_id для определения области IPv6, а поскольку переменная hint находится в стеке, она получает случайные данные вit.

Область IPv6 описывает, какой это тип адреса: одноадресная, многоадресная, локальная ссылка и некоторые другие, и я знаю их только за рулем. Но если там есть мусор, это может быть чем-то особенным.

Рекомендовать исключить это как проблему, либо жестко установив sin6_scope_id на ноль, либо (лучше) просто обнулить всю структуру sockaddr_in6перед тем, как присвоить ему материал;Я давно делал это с моими sockaddr_in переменными, просто чтобы быть уверенным, что я не закончил ненужным мусором.

memset(&hint, 0, sizeof hint);

И да, errno действительно важен.

...