Search code examples
c++serveripip-address

What does ai_addr contain?


I am currently learning socket programming and while programming I noticed that in a lot of functions you need to Pass in stuff from addrinfo*, and I understand what most of the stuff does. But my Question is: What exactly is ai_addr? It is never specified by me, though if I let the Programm output me the value that it has, I get a wierd Hash-like result. It's a mix of Numbers and Letters, though the first 5 symbols seem to be always 000000. I have assumed that it was the IP or TCP of a local Network, but to me, what I get output does not seem like a IP adress, and since i am using AF_INET as a Network family it should be a IPx4 address, but it is not.

When i look in the libary in which ai_addr is defined i also can't find a answer and looking online also hasn't helped me. My Current Code:

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <iostream>

#pragma comment(lib, "Ws2_32.lib")

WSADATA wsaData;

int main()
{
    int iResult;

    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

#define DEFAULT_PORT "27015"

    struct addrinfo* result = NULL, * ptr = NULL, hints;

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the local address and port to be used by the server
    iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
    if (iResult != 0) {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return 1;
    }


    SOCKET ListenSocket = INVALID_SOCKET;
    
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);

    if (ListenSocket == INVALID_SOCKET) {
        printf("Error at socket(): %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    iResult = bind(ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        printf("bind failed with error: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    std::cout << result->ai_addr << ' ' << result->ai_addrlen;

    if (listen(ListenSocket, SOMAXCONN) == SOCKET_ERROR) {
        printf("Listen failed with error: %ld\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    SOCKET ClientSocket;

    ClientSocket = INVALID_SOCKET;

    // Accept a client socket
    ClientSocket = accept(ListenSocket, NULL, NULL);
    if (ClientSocket == INVALID_SOCKET) {
        printf("accept failed: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

Also I use Visual Studio 2021 Community edition.


Solution

  • The socket API supports many different ways of specifying the address of each endpoint in the communication, depending on the socket's type.

    The 1st parameter of the socket() call specifies the type of address family to be used for all subsequent API calls on the socket that deal with endpoints.

    Each address family defines its own unique sockaddr_... struct type to carry its particular address information.

    All socket API functions that accept/return a socket address will take a generic sockaddr* pointer as a parameter, which must be typecasted in order to access the struct data. The 1st field of all sockaddr_... types must specify its family so the API/receiver knows how to access the struct data correctly.

    The ai_addr field is a sockaddr* pointer to a sockaddr_... struct that is appropriate to the family specified in the ai_family field.

    For example:

    • when the ai_family is AF_INET (IPv4) then ai_addr points to a sockaddr_in struct containing the IPv4 address and port.

    • when the ai_family is AF_INET6 (IPv6) then ai_addr points to a sockaddr_in6 struct containing the IPv6 address, port, and scope id.

    • when the ai_family is AF_UNIX (UNIX domain) then ai_addr points to a sockaddr_un struct containing a filesystem path.

    • when the ai_family is AF_BTH (Bluetooth) then ai_addr points to a sockaddr_bth struct containing the ID and port of a paired Bluetooth device.

    • etc...