What's the pad to sockaddr_in for?

Viewed 267

I'm new to C and socket programming, still struggling in sockaddr_in structure:

struct sockaddr_in {
    short            sin_family;   /* Protocol family (always AF_INET) */
    unsigned short   sin_port;     /* Port number in network byte order */
    struct in_addr   sin_addr;     /* IP address in network byte order */
    unsigned char    sin_zero[8];  /* Pad to sizeof(struct sockaddr) */
};

and

struct in_addr {
   uint32_t s_addr; /* Address in network byte order (big-endian) */
};

I'm not sure about the need of sin_zero other than alignment requirement, below is my assumption, please correct me if I was wrong:

Assumption 1-since sin_addr is 32 bit for ipv4 address, if we need a ipv6 address, the the first 4 bytes of sin_zero will be assigned and combined with sin_addr to form a 64 bit ipv6 address.

Assumption 2-If my assumption is correct, then is the reason why we need to specific the length of a socket address such as:

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

is because the possibility of ipv6 addresses? so if ipv4 is used, then addrlen should be 8, and if ipv6 is used, then addrlen should be 12?

1 Answers

There are multiple protocol families. Each family has its own address structure.

Example: AF_INET uses sockaddr_in, AF_INET6 uses sockaddr_in6, AF_UNIX uses sockaddr_un, etc. But sockaddr is the base structure. All these structures must be type-cast to sockaddr while binding/connecting a socket.

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

Let's look at the structures of sockaddr_in and sockaddr:

struct sockaddr_in {
    short            sin_family;   /* Protocol family (always AF_INET) */
    unsigned short   sin_port;     /* Port number in network byte order */
    struct in_addr   sin_addr;     /* IP address in network byte order */
    unsigned char    sin_zero[8];  /* Pad to sizeof(struct sockaddr) */
};


struct in_addr {
   uint32_t s_addr; /* Address in network byte order (big-endian) */
};

The structure of sockaddr is:

struct sockaddr 
{
    sa_family_t sa_family;
    char        sa_data[14];
}

Look at the sizes of the elements in the two structures sockaddr_in and sockaddr.

The first element in both structures is the same and occupies the same memory.

sin_port --> 2 bytes
sin_addr --> 4 bytes
sin_zero[8] --> 8 bytes
Total = 14 bytes (equal to size of sa_data[14])

We add padding bytes to make their structure sizes equal.

reference:
https://man7.org/linux/man-pages/man2/bind.2.html
https://man7.org/linux/man-pages/man2/connect.2.html

Related