Search code examples
cnetwork-programminggetaddrinfo

How to get actual size of ai_addr->sa_data returned by getaddrinfo()


getaddrinfo() fills struct addrinfo where actual packed address stored in struct sockaddr *ai_addr field. struct sockaddr has field char *sa_data with actual binary address representation. I want to copy this sa_data to another variable using memcpy(), for this I need to know actual length of this field.

I thinked ai_addrlen is what I need. But in fact it returns 16 for IPv4 and 28 for IPv6. Too much I think. So, what is the most correct way to get sa_data length? May be length = sa_family == AF_INET ? 4 : 16 or length = ai_addrlen - 12?


Solution

  • The getaddrinfo() function returns a linked list consisting of struct addrinfo records. Each of those records includes a pointer to struct sockaddr which is a polymorphic type, behind which there is actually a struct sockaddr_in or struct sockaddr_in6. The ai_addrlen member tells you how large is that structure, i.e. returns either sizeof (struct sockaddr_in) or sizeof (struct sockaddr_in6).

    Those structures contain the binary IP address, the port number (for the transport protocol like TCP or UDP), the family (repeated in struct addrinfo as well) and other data (flowinfo and scope_id for IPv6, when looking at linux docs).

    The actual binary address is inside the struct sockaddr_in and strict sockaddr_in6 as struct in_addr sin_addr and struct in6_addr sin6_addr. You can use those fields or types to determine the size.

    length = sa_family == AF_INET ? sizeof (struct in_addr) : sizeof (struct in6_addr)
    

    As those are known numbers, you can of course use what you have already in your question.

    length = sa_family == AF_INET ? 4 : 16
    

    But you also tried to do arithmetics on ai_addrlen and that is not a good idea, as the types can vary by operating system and there's no logic in that anyway. I can add more details if you had a specific use case or specific code.