Saturday, November 23, 2013

sockaddr structure

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: