Search code examples
c++ipv6

IPv6 client can't connect to IPv6 server


My program is client server IPv6. the client can't make connection to the server? The client and server must use loop-back address the problem in this code its can't connect to the server

   SOCKET sock = socket(AF_INET6, SOCK_STREAM, 0);
 if (sock == INVALID_SOCKET)
  {
    cerr << "Can't create socket, Err #" << WSAGetLastError() << endl;
    WSACleanup();
    return;
 }

   sockaddr_in6 hint;
hint.sin6_family = AF_INET6;
hint.sin6_port = htons(port);
hint.sin6_addr = in6addr_any;
// Connect to server
int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
if (connResult == SOCKET_ERROR)
{
    cerr << "Can't connect to server, Err #" << WSAGetLastError() 
   << endl;
    closesocket(sock);
    WSACleanup();
    return;
}

Solution

  • A client TCP socket cannot connect() to in6addr_any. A TCP server can bind() to in6addr_any so it can then listen() on all available local IPv6 network interfaces with a single SOCKET. But the client must connect() to a real IPv6 address that the server is actually listening on (such as in6addr_loopback if the client is running on the same machine as the server. Your server can use GetAdaptersInfo() or GetAdaptersAddresses() to discover what its local IP addresses actually are that are valid for the client to connect() to).

    Also, you need to zero out the sockaddr_in6 struct completely. sockaddr_in6 has sin6_flowinfo and sin6_scope_id fields that you are not populating, so they will have random values from the stack. sin6_scope_id in particular will affect connect()'s ability to use the correct network interface to connect to the server.

    SOCKET sock = socket(AF_INET6, SOCK_STREAM, 0);
    if (sock == INVALID_SOCKET)
    {
        cerr << "Can't create socket, Err #" << WSAGetLastError() << endl;
        WSACleanup();
        return;
    }
    
    sockaddr_in6 hint = {};
    hint.sin6_family = AF_INET6;
    hint.sin6_port = htons(port);
    inet_pton(AF_INET6, "server IPv6 address here", &(hint.sin6_addr));
    
    // Connect to server
    int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
    ...
    

    Consider using getaddrinfo() instead. Let the OS allocate a properly-populated sockaddr_in6 for you, which you can then pass as-is to connect() (similarly to how I explained to you in your previous question for bind()).

    addrinfo hint = {};
    hint.ai_family = AF_INET6;
    hint.ai.socktype = SOCK_STREAM;
    hint.ai_protocol = IPPROTO_TCP;
    
    addrinfo *res;
    
    err = getaddrinfo("server hostname or IPv6 address here", "server port here", &hint, &res);
    if (err != 0)
    {
        cerr << "Can't get address to connect, Err #" << WSAGetLastError() << endl;
        WSACleanup();
        return;
    }
    
    SOCKET sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sock == INVALID_SOCKET)
    {
        cerr << "Can't create socket, Err #" << WSAGetLastError() << endl;
        freeaddrinfo(res);
        WSACleanup();
        return;
    }
    
    // Connect to server
    int connResult = connect(sock, res->ai_addr, res->ai_addrlen);
    if (connResult == SOCKET_ERROR)
    {
        cerr << "Can't connect to server, Err #" << WSAGetLastError() << endl;
        closesocket(sock);
        freeaddrinfo(res);
        WSACleanup();
        return;
    }
    
    freeaddrinfo(res);
    ...