Search code examples
csocketstcpsegmentation-faultclient-server

TCP-IP sockets C: Bad address error when trying to connect to server socket


I am trying to create a client-server tic-tac-toe game as homework. I am setting up the server-listener and the connections in separate functions, not in the main program. The server socket creation is successful, but the client connections fail, which I think is what causes the seg fault that follows.

I ve already looked up similar problems and made adjustments to my code as best as I could, like setting a variable for sizeof(cli_addr) instead of passing it to accept() directly. I do not know why it is not working.

This is the function that sets up the connections

void setup_connections(int serversocket,int *clientsocket,int portnum){
int cli_size,con_num = 0;
struct sockaddr_in cli_addr;

//server is listening for clients
listen(serversocket,5);

while(con_num<2){


    cli_addr.sin_family = AF_INET;
    cli_addr.sin_addr.s_addr = INADDR_ANY;
    cli_addr.sin_port = htons(portnum);

    //accept connection while creating client socket
    cli_size = sizeof(cli_addr);
    clientsocket[con_num] = accept(serversocket,(struct sockaddr *) &cli_addr,cli_size);

    if(clientsocket[con_num]<0){
        perror("Error: ");
    }

    con_num++;

    }
}

I get a warning when compiling about cli_size type.

*warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'socklen_t *' (aka 'unsigned int *') [-Wint-conversion] clientsocket[con_num] = accept(serversocket,(struct sockaddr ) &cli_addr,cli_size);

However, all the examples I checked pass it like this.

This is the function that sets up the server socket.

int setup_server(int portnum){
int serversocket,serv_bind;
struct sockaddr_in server_addr;


serversocket = socket(AF_INET, SOCK_STREAM, 0);
if(serversocket<0){
    printf("Failed to create server\n");
}

//set up server info
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(portnum); //port number given by user

//link server address to socket
serv_bind = bind(serversocket,(struct sockaddr *) &server_addr,sizeof(server_addr));
if(serv_bind<0){
    printf("Failed to bind\n");
}

return serversocket;
}

And this is the code in main.c that calls them:

int portnum,serversocket, clientsocket[2]; //sockets


portnum = atoi(argv[1]);
if(argc < 2){
    printf("Port number not given");
}

//create sockets
serversocket = setup_server(portnum);
setup_connections(serversocket,clientsocket);

What I get after running the program is:

Error: : Bad Address

Error: : Bad Address

Segmentation fault: 11

If you can explain to me what I am doing wrong, it would be very helpful.


Solution

  • You are right to take note of the warning you receive:

    warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'socklen_t *' (aka 'unsigned int *') [-Wint-conversion] clientsocket[con_num] = accept(serversocket,(struct sockaddr ) &cli_addr,cli_size);

    You are wrong to discount it:

    However, all the examples I checked pass it like this.

    If all the examples you've looked at use code analogous to yours then you desperately need to find better examples. More importantly, however, you need to learn to rely on documentation, preferably as your first recourse, but at least to clear up uncertainties, such as "is this warning something I should care about?" (Hint: until and unless you can express a documentation-based reason otherwise, the answer is always "yes, I should care about warnings".)

    A quick look at the docs for accept() would reveal that the third parameter is expected to be a pointer to a variable containing the size of the address object you pass, and the function will update that variable (via the pointer) to contain the actual length of the address returned. You are instead passing the size itself, and conversion to a pointer will almost certainly produce an invalid one. You're actually lucky that it does, so that you get a runtime error, for the alternative is that you silently produce memory corruption at some random place in your program.

    Note that bind() is different. It requires you to pass the size of the address directly, not indirectly. This is sensible because there is no reason for it to want to modify the size.