The socket API specifies a generic data type called sockaddr for used by API calls.
struct sockaddr {
sa_family_t sa_family; // address family e.g. AF_INET or AF_INET6
char sa_data[14]; // address info - A blob of bits to handle diff OS and network
};
Note that this sockaddr structure is not large enough to handle a IPV6 address which is 16 bytes long. The actual data structure used in socket call are sockaddr_in (for IPV4) and sockaddr_in6 (for IPV6). They have just a more detailed layout of sockaddr.
struct in_addr { uint32_t s_addr; }; // 4-byte IPV4 address
struct sockadr_in {
sa_family_t sin_family; //address family AF_INET
in_port_t sin_port; //16-bit port
struct in_addr sin_addr;
char sin_zero[8]; //padding
};
struct in_addr { uint32_t s_addr[16]; }; //128-bit address
struct sockadr_in6 {
sa_family_t sin6_family; //address family AF_INET6
in_port_t sin_port; //16-bit port
uint32_t sin6_flowinfo; //flow info
struct in6_addr sin6_addr;
uint32_t sin6_scope_id; //scope ID
};
The structure is casted with (struct sockaddr *) when used. For example,
result = bind(servSock, (struct sockaddr*) &servAddr, sizeof(servAddr));
As sockaddr_in is not big enough to hold a IPV6 address, program allocate space using a sockaddr_storage structure
struct sockaddr_storage { sa_family_t .... } ; //the sa_faimily is used to determine the actual address type.
struct sockaddr_storage sockAddr
:
:
switch (sockAddr->sa_family) {
case AF_INET: ...
case AF_INET6: ...
default: ...
};
No comments:
Post a Comment