Why can we cast sockaddr to sockaddr_in

11,023

It is possible because you normally cast pointers, not the structures themselves. You do what in natural language means "please treat this pointer to a socket structure as a pointer to an internet socket structure instead". Compiler has no problems to re-interpret the pointer.

Here is more detailed description taken up from comments:

A sockaddr is 16 bytes in size - the first two bytes are the sa_family, and the remaining 14 bytes are the sa_data which is arbitrary data. A sockaddr_in is also 16 bytes in size - the first 2 bytes are the sin_family (always AF_INET), the next 2 bytes are the sin_port, the next 4 bytes are the sin_addr (IP address), and the last 8 bytes are the sin_zero which is unused in IPv4 and provided only to ensure 16 bytes. This way, you can look at sockaddr.sa_family first, and if it is AF_INET then interpret the entire sockaddr as a sockaddr_in.

A sockaddr_in is not stored inside of sockaddr.sa_data field. The entire sockaddr is the entire sockaddr_in (when sockaddr.sa_family is AF_INET, that is). If you take a sockaddr* pointer and cast it to a sockaddr_in* pointer, then:

  • sockaddr.sa_family is sockaddr_in.sin_family
  • bytes 0-1 of sockaddr.sa_data are sockaddr_in.sin_port
  • bytes 2-5 are sockaddr_in.sin_addr
  • bytes 6-13 are sockaddr_in.sin_zero.
Share:
11,023
Jean-Luc
Author by

Jean-Luc

I am a electronic/communications engineering student with interests in C++, Ruby, Python and assembler programming. I also love LaTeX and Gnuplot.

Updated on June 05, 2022

Comments

  • Jean-Luc
    Jean-Luc almost 2 years

    I can see why it is useful to cast sockaddr to sockaddr_in, but I don't understand how this is possible. From what I've read, they're the same size and sockaddr_in is added with sin_zero to make it the same size. I would like to know how the compiler knows where to get the information from sockaddr_in if it is layed out differently to sockaddr.

  • Jean-Luc
    Jean-Luc about 12 years
    It seems odd because the variable that is supposed to store the address in sockaddr is sa_data which is char[14], yet sockaddr_in uses an unsigned short. I'm assuming that the compiler would read the first unsigned short number of bytes from the char[14] and make that the address, and the rest of char[14] is the data to be sent? Also, if I add the sizes of the two structs, they don't appear to be the same size. sin_zero seems too big. I'm just tring to get what's going on here!
  • Remy Lebeau
    Remy Lebeau about 12 years
    A sockaddr is 16 bytes in size - the first two bytes are the sa_family, and the remaining 14 bytes are the sa_data which is arbitrary data. A sockaddr_in is also 16 bytes in size - the first 2 bytes are the sin_family (always AF_INET), the next 2 bytes are the sin_port, the next 4 bytes are the sin_addr (IP address), and the last 8 bytes are the sin_zero which is unused in IPv4 and provided only to ensure 16 bytes. This way, you can look at sockaddr.sa_family first, and if it is AF_INET then interpret the entire sockaddr as a sockaddr_in.
  • Remy Lebeau
    Remy Lebeau about 12 years
    A sockaddr_in is not stored inside of sockaddr.sa_data field. The entire sockaddr is the entire sockaddr_in (when sockaddr.sa_family is AF_INET, that is). If you take a sockaddr* pointer and cast it to a sockaddr_in* pointer, sockaddr.sa_family is sockaddr_in.sin_family, bytes 0-1 of sockaddr.sa_data are sockaddr_in.sin_port, bytes 2-5 are sockaddr_in.sin_addr, and bytes 6-13 are sockaddr_in.sin_zero.
  • Michael Heidelberg
    Michael Heidelberg over 8 years
    @RemyLebeau: I hope you can edit your post and add the useful content of the comments inside ( especially the second comment that treats how the struct fields are interpreted ) It'll be more clear and more specific.
  • Roman R.
    Roman R. over 8 years
    @MichaelHeidelberg: No problem, I did it.
  • Michael Heidelberg
    Michael Heidelberg over 8 years
    @RemyLebeau: Great! Thank you, that's well explained.
  • Armen Michaeli
    Armen Michaeli over 7 years
    How does sturct padding figure into this? What gives guarantees that the two structs have similar alignment between their members in so far pointer to one can be used in place of pointer to another?
  • Roman R.
    Roman R. over 7 years
    @amn: Have a look at declarations side by side. You will see how the fields are defined similarly in the beginning and map one to one perfectly, then different declarations are different interpretations of the same data (in case of casting). The structures are defined in the way that guarantees accurate mapping.
  • U. Windl
    U. Windl about 3 years
    I think the real question is: Is it guaranteed that sizeof(struct sockaddr) == sizeof(struct sockaddr_in) (and other address families like sizeof(struct sockaddr) == sizeof(struct sockaddr_in6))?