csocketsvxworks

Creating a sockaddr without casting


I would like to create a sockaddr struct without the funny casting because I have a function that will return sockaddr structs. But I cannot really figure out how to re-pack the data from a sockaddr_in to a sockaddr. I am following this tutorial that shows this done like this

struct sockaddr_in myaddr;
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(0);
bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr);

I have a function to return regular sockaddr

sockaddr CreateAddress(std::string ip, uint16_t port){
    sockaddr_in address = {0};
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr(ip.c_str());
    address.sin_port = htons(port);

    // return as sockaddr instead..
    sockaddr addr = {0};
    addr.sa_len = sizeof(sockaddr);
    addr.sa_family = AF_INET;
    // how to fill in sockaddr.sa_data?
    // maybe like this?
    addr.sa_data[0] = (address.sin_port >> 8) & 0xFF;
    addr.sa_data[1] = (address.sin_port) & 0xFF;
    addr.sa_data[2] = (address.sin_addr.s_addr >> 24) & 0xFF;
    addr.sa_data[3] = (address.sin_addr.s_addr >> 16) & 0xFF;
    addr.sa_data[4] = (address.sin_addr.s_addr >> 8) & 0xFF;
    addr.sa_data[5] = (address.sin_addr.s_addr) & 0xFF;
    return addr;
}

Solution

  • The socket API functions are built to take a struct sockaddr * as a parameter because there are multiple socket address types that it could accept, i.e. struct sockaddr_un for UNIX domain sockets, struct sockaddr_in for IPv4, struct sockaddr_in6 for IPv6, etc. The struct sockaddr type is how the socket API (written in C) implements inheritance.

    As such, these functions don't actually expect that a struct sockaddr * parameter actually points to a struct of that type. Based on the socket type, it will internally cast it to the proper type.

    This means that you should work with struct sockaddr_in instead of struct sockaddr and cast the address of these structs to struct sockaddr * anytime you interact with a socket function. This is the expected way to use these functions.