HighPredator
HighPredator

Reputation: 772

Sockets. Setting s_addr field of sockaddr_in structure

I'm trying a test code that connects to a remote host with data given by gethostbyname() function. In examples I found they do the following:

struct hostent* pHostent = gethostbyname(host);
struct sockaddr_in remoteAddr;
// ... code
remoteAddr.sin_addr.s_addr = ((struct in_addr*) (pHostent->h_addr))->s_addr;
// ... more code

I'm trying to understand what's being done here.

  1. Is it legal since data types are different? Maybe a memcpy() should have been used?

  2. Why does this work? Meaning what data actually resides in both places?

Upvotes: 1

Views: 351

Answers (1)

Pibben
Pibben

Reputation: 2025

We can start by looking at the actual struct layouts:

struct hostent {
   char  *h_name;
   char **h_aliases;
   int    h_addrtype
   int    h_length;
   char **h_addr_list;
}
#define h_addr h_addr_list[0]
struct sockaddr_in {
    short            sin_family;
    unsigned short   sin_port;
    struct in_addr   sin_addr;
    char             sin_zero[8];
};
struct in_addr {
    uint32_t       s_addr;    // IPv4 address
};

The gethostbyname() function can give you either IPv4 or IPv6 addresses, depending on the value of h_addrtype. So the h_addr_list need to be able to hold either IPv4 or IPv6 addresses. To accomplish this the addresses are stored as raw memory pointed to by char* pointers. To get the actual address, you need to cast the memory to the correct address type, as you found in your code:

remoteAddr.sin_addr.s_addr = ((struct in_addr*) (pHostent->h_addr))->s_addr;

So to answer your questions:

  1. The pointer types are different, but the data pointed to are the same type.
  2. No, the data is in one place only, it's just referenced to by pointers of different type.

Upvotes: 3

Related Questions