Search code examples
c++csocketsvxworks

Assigning IPv4 Address from ifaddrs Structure to sockaddr_in Structure


I'm developing a UDP Server application.
I wish to bind my server socket to a particular interface (read from configuration file). In this case eth0.
I'm using getifaddrs to read all information about present network interfaces.
I then iterate over the linked list as returned getifaddrs and check the name of each interface against the interface I want.
Once a match is found I plan extract the IPv4 address from struct ifaddrs and assign it to struct sockaddr_in object.
Currently I'm unsure on how I can pass struct ifaddrs->ifa_addr->sa_data to struct sockaddr_in.sin_addr.s_addr or is it the right/recommended approach I'm following.

Code :

bool start_server(void)
{
    struct sockaddr_in  server_address;
    struct ifaddrs      *ifaddr;
    int                 return_value;
    try
    {
        this->sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (this->sock_fd < 0) 
        {
            //TODO : Log Error
            return false;
        }

        // Initialize and configure struct sockaddr_in server_address
        std::memset(&server_address, sizeof(sockaddr_in), 0); // Initialize struct sockaddr_in server_address to 0
        server_address.sin_family = AF_INET;
        server_address.sin_port = htons(6666); //We are using the port 6666

        //Get IP address from the interface (eth0 currently) -> Interface name to be read from the configuration file
        return_value = getifaddrs(&ifaddr);
        if (return_value < 0) //On error, -1 is returned
        {
            //TODO : Log Error
            return false;
        }
        for (struct ifaddrs *ifa; ifa != nullptr; ifa = ifaddr->ifa_next)//ifa stand for interface address
        {
            if (std::strcmp(ifa->ifa_name, "eth0") == 0) //We check the interface name in the linked Strings are exact match
            {
                if (ifa->ifa_addr == nullptr)
                {
                    //TODO : Log Error - Selected interface doesn't have an assoiciated IP address
                    break; 
                }
                else
                {
                    server_address.sin_addr.s_addr = inet_addr(ifa->ifa_addr->sa_data); //I am unsure will this work or if this is the right approach
                    break;
                }

            }
        }
        freeifaddrs(ifaddr); //Free up memeory allocated by getifaddrs. Prevents Memory Leaks
}

Solution

  • The ifa_addr member is a pointer to a struct sockaddr. First, you want to make sure it's for an IPv4 address by checking if sa_family is set to AF_INET, and if so you can use memcpy to copy it to a struct sockadr_in.

        for (struct ifaddrs *ifa = ifaddr; ifa != nullptr; ifa = ifaddr->ifa_next)
        {
            if (std::strcmp(ifa->ifa_name, "eth0") == 0)
            {
                if (ifa->ifa_addr == nullptr)
                {
                    //TODO : Log Error - 
                    //Selected interface doesn't have an assoiciated IP address
                    break; 
                }
                else if (ifa->ifa_addr->sa_family == AF_INET)
                {
                    memcpy(&server_address.sin_addr, ifa->ifa_addr, 
                           sizeof(server_address.sin_addr));
                    break;
                }
    
            }
        }