Home > Net >  How to represent the IP from addrinfo in WINAPI?
How to represent the IP from addrinfo in WINAPI?

Time:11-05

How to print the ip of the server as a.b.c.d in WINAPI

int main(int argc, char ** argv)
{
    if (argc < 3)
        return -1;
    WSADATA wsData;
    int result;
    struct addrinfo * client = NULL, *ptr = NULL, hints;
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    result = getaddrinfo(argv[1], argv[2], &hints, &ptr);
    if (result < 0 )
        return -1;

    printf("%s", inet_addr(ptr->ai_addr->sa_data));
}

this results in a segmentation fault when executed

CodePudding user response:

inet_addr() converts a null-terminated string in dotted IPv4 format into its binary 32bit number representation. That number is suitable for storing in a sockaddr_in, for instance. That is the opposite of what you want.

ptr->ai_addr->sa_data is not an null-terminated string, which is why inet_addr() crashes.

To convert an IP address in a sockaddr_... struct, such as output from getaddrinfo(), into its string representation, you can use inet_ntop(), eg:

int main(int argc, char* argv[])
{
    if (argc < 3)
        return -1;

    WSADATA wsData;
    int result = WSAStartup(MAKEWORD(2,0), &wsData);
    if (result != 0)
        return -1;
    
    struct addrinfo hints, *addrs, *ptr;
    char ipStrBuf[50];
    
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    result = getaddrinfo(argv[1], argv[2], &hints, &addrs);
    if (result != 0) {
        WSACleanup();
        return -1;
    }

    for (ptr = addrs; ptr != NULL; ptr = ptr->ai_next) {
        switch (ptr->ai_addr->sa_family) {
            case AF_INET: {
                struct sockaddr_in *ip4 = (struct sockaddr_in *) ptr->ai_addr;
                printf("%s", inet_ntop(AF_INET, &(ip4->sin_addr), ipStrBuf, sizeof(ipStrBuf)));
                break;
            }
            
            case AFINET6: {
                struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *) ptr->ai_addr;
                printf("%s", inet_ntop(AF_INET6, &(ip6->sin6_addr), ipStrBuf, sizeof(ipStrBuf)));
                break;
            }
        }
    }

    freeaddrinfo(addrs);
    WSACleanup();

    return 0;
}

Alternatively, you can use getnameinfo(), specifying the NI_NUMERICHOST flag, eg:

int main(int argc, char* argv[])
{
    if (argc < 3)
        return -1;

    WSADATA wsData;
    int result = WSAStartup(MAKEWORD(2,0), &wsData);
    if (result != 0)
        return -1;
    
    struct addrinfo hints, *addrs, *ptr;
    char ipStrBuf[50];
    
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    result = getaddrinfo(argv[1], argv[2], &hints, &addrs);
    if (result != 0) {
        WSACleanup();
        return -1;
    }

    for (ptr = addrs; ptr != NULL; ptr = ptr->ai_next) {
        result = getnameinfo(ptr->ai_addr, ptr->ai_addrlen, ipStrBuf, sizeof(ipStrBuf), NULL, 0, NI_NUMERICHOST);
        if (result == 0) {
            printf("%s", ipStrBuf);
        }
    }

    freeaddrinfo(addrs);
    WSACleanup();

    return 0;
}

Or, you can use WSAAddressToString(), eg:

int main(int argc, char* argv[])
{
    if (argc < 3)
        return -1;

    WSADATA wsData;
    int result = WSAStartup(MAKEWORD(2,0), &wsData);
    if (result != 0)
        return -1;
    
    struct addrinfo hints, *addrs, *ptr;
    char ipStrBuf[50];
    DWORD ipBufSize;
    
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    result = getaddrinfo(argv[1], argv[2], &hints, &addrs);
    if (result != 0) {
        WSACleanup();
        return -1;
    }

    for (ptr = addrs; ptr != NULL; ptr = ptr->ai_next) {
        ipBufSize = sizeof(ipStrBuf);
        result = WSAAddressToStringA(ptr->ai_addr, ptr->ai_addrlen, NULL, ipStrBuf, &ipBufSize);
        if (result == 0) {
            printf("%s", ipStrBuf);
        }
    }

    freeaddrinfo(addrs);
    WSACleanup();

    return 0;
}

Or, you can use RtlIpv4AddressToString() and RtlIpv6AddressToString(), eg:

int main(int argc, char* argv[])
{
    if (argc < 3)
        return -1;

    WSADATA wsData;
    int result = WSAStartup(MAKEWORD(2,0), &wsData);
    if (result != 0)
        return -1;
    
    struct addrinfo hints, *addrs, *ptr;
    char ipStrBuf[50];
    
    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    result = getaddrinfo(argv[1], argv[2], &hints, &addrs);
    if (result != 0) {
        WSACleanup();
        return -1;
    }

    for (ptr = addrs; ptr != NULL; ptr = ptr->ai_next) {
        switch (ptr->ai_addr->sa_family) {
            case AF_INET: {
                struct sockaddr_in *ip4 = (struct sockaddr_in *) ptr->ai_addr;
                printf("%s", RtlIpv4AddressToStringA(&(ip4->sin_addr), ipStrBuf));
                break;
            }
            
            case AFINET6: {
                struct sockaddr_in6 *ip6 = (struct sockaddr_in6 *) ptr->ai_addr;
                printf("%s", RtlIpv6AddressToStringA(&(ip6->sin6_addr), ipStrBuf));
                break;
            }
        }
    }

    freeaddrinfo(addrs);
    WSACleanup();

    return 0;
}
  • Related