0

I'm looking for a summary of the socket address structures interpreted as a union to have a complete overview. The only Q&A similar to this I've found is Sockaddr union and getaddrinfo() but it doesn't summarizes the structures.

How does a union of the socket address structures looks like and what address structures in detail are used?

timrau
  • 22,578
  • 4
  • 51
  • 64
Ingo
  • 588
  • 9
  • 21
  • You are looking for `` or `sockets.h`, and therefore off-topic. – user207421 Jun 25 '23 at 02:30
  • @user207421 What is the topic? Why can a question be off-topic? And do you mean `` and `socket.h`? Have a look at the references of my answer. – Ingo Jun 25 '23 at 08:22
  • Questions asking for recommendations for off-site resources are off--topic here. If you're just asking yourself Dorothy Dixer questions I fail to see the point. – user207421 Jun 25 '23 at 09:48
  • @user207421 The topic is *"sockaddr structures as union"*. The question is "*How does a union of the socket address structures looks like and what address structures in detail are used?*". This does not contain any direct question to off-site resources. I have explained that I cannot find information about an union of sockaddr structures. From that point of view it is a new aspect not given in any off-site resources. I have taken some effort to collect the background information and document this union use. – Ingo Jun 25 '23 at 22:44
  • @user207421 Stack Exchange explicitly encouraged users to answer their own questions. *"If you have a question that you already know the answer to, and you would like to document that knowledge in public so that others **(including yourself)** can find it later, it's perfectly okay to ask and answer your own question on a Stack Exchange site."* That is exactly my intention. [Can I answer my own question?](https://stackoverflow.com/help/self-answer). – Ingo Jun 25 '23 at 22:45

1 Answers1

0

I'm missing a handy summary for the socket address structures. Yes, I know there are a great amount of examples on the web but couldn't find one that gives me all in one place.

The socket address structures are made to overlap each other in memory. So they can be declared as a union type. By specification, the sockaddr_storage structure is big enough to hold all structures so it determines the size of the union. With using the union there is no need for type casting anymore (except (sockaddr*) for function arguments).

using sockaddr_t = union {
    sockaddr_storage ss;
    sockaddr_in6     sin6;
    sockaddr_in      sin;
    sockaddr         sa;
};

struct sockaddr_storage {
    sa_family_t      ss_family;
    // Following field(s) are implementation specific
    // only for padding to mostly 128 bytes.
    // No information usable.
};

struct sockaddr_in6 {
    sa_family_t      sin6_family;   // AF_INET6.
    in_port_t        sin6_port;     // Port number.
    uint32_t         sin6_flowinfo; // IPv6 traffic class and flow info.
    struct in6_addr  sin6_addr;     // IPv6 address.
    uint32_t         sin6_scope_id; // Set of interfaces for a scope.
};

struct sockaddr_in {
    sa_family_t      sin_family;    // AF_INET.
    in_port_t        sin_port;      // Port number.
    struct in_addr   sin_addr;      // IP address.
};

struct sockaddr {
    sa_family_t      sa_family;     // Address family.
    // char          sa_data[];     // Socket address (variable-length data).
};

struct in6_addr {
    uint8_t s6_addr[16];
};

struct in_addr {
    in_addr_t s_addr;
};

using sa_family_t = unsigned short int;
using in_addr_t = uint32_t;
using in_port_t = uint16_t;

Examples:

#include <netdb.h> // for sockaddr structures
#include <cstring> // for memcmp()
#include <cassert>

int main() {
    sockaddr_t saddr{};

    assert(saddr.ss.ss_family == saddr.sin6.sin6_family);
    assert(saddr.ss.ss_family == saddr.sin.sin_family);
    assert(saddr.ss.ss_family == saddr.sa.sa_family);

    if (saddr.ss.ss_family == AF_INET6) {
        in_port_t port6 = saddr.sin6.sin6_port;
        in6_addr addr6 = saddr.sin6.sin6_addr;

        // Check if sin6_addr is null
        uint8_t s6_addr0[16]{};
        bool res =
            (memcmp(saddr.sin6.sin6_addr.s6_addr, s6_addr0, sizeof(s6_addr0)) == 0);
    }

   if (saddr.ss.ss_family == AF_INET) {
        in_port_t port = saddr.sin.sin_port;
        in_addr_t addr = saddr.sin.sin_addr.s_addr;
    }

    // sockaddr is only used for type casting on function arguments
    if (saddr.ss.ss_family == AF_INET6) {
        int sockfd = socket(saddr.ss.ss_family, SOCK_DGRAM, 0);
        socklen_t len = sizeof(saddr.sin6);
        int ret = getsockname(sockfd, (sockaddr*)&saddr, &len);
    }
}

A more useful example you can find at Sockaddr union and getaddrinfo().

References:

Ingo
  • 588
  • 9
  • 21