so.very.tired
so.very.tired

Reputation: 3086

Networking in C ; does bind() need its argument alive?

This might look basic to you, but since this is my first experience with networking in C, I wanted to make sure I'm not doing anything stupid, so I figured... better safe than running into some undefined, bizarre behaviour somewhere along the way.
Consider the following code for setting a server socket in C:

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>


int main(int argc, char* argv[]) {

    int listenfd, connfd;
    struct sockaddr_in serv_addr;

    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    // setting 'serv_addr'
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    serv_addr.sin_port = htons(5000);

    bind(listenfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));

    if (listen(listenfd, 10) == -1) {
        printf("Failed to listen\n");
        return -1;
    }



    while(1) {
        connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL);

        // do some writing/reading with connfd...

        close(connfd);
    }

    return 0;
}

Notice that the bind() function takes &struct sockaddr_in as argument.
According to the doc:

bind() assigns the address specified by addr to the socket referred to by the file descriptor sockfd.

Now suppose that no explicit references are made by me to this serv_addr again, during the execution of the while loop.
Is the struct sockaddr_in needed by the socket, or, after bind() returns, struct sockaddr_in is not needed anymore?
Are any implicit references somehow made by the socket?

To be more precise, is the following code safe?

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>


int some_other_function() {

    int listenfd;
    /* struct sockaddr_in is defined locally in some_other_function()*/
    struct sockaddr_in serv_addr;


    listenfd = socket(AF_INET, SOCK_STREAM, 0);

    // setting 'serv_addr'
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    serv_addr.sin_port = htons(5000);

    bind(listenfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));

    if (listen(listenfd, 10) == -1) {
        printf("Failed to listen\n");
        return -1;
    }

    return listenfd;
}   /* if the socket will refer to &serv_addr from now on, it'll dereference a dangling pointer */



int main(int argc, char* argv[]) {

    int listenfd=some_other_function();
    int connfd;

    while(1) {

        /** is sockaddr_in serv_addr being referenced here? is it needed by accept()? **/

        connfd = accept(listenfd, (struct sockaddr*)NULL ,NULL);

        // do some writing/reading with connfd...

        close(connfd);
    }

    return 0;
}

Upvotes: 4

Views: 67

Answers (2)

John Kugelman
John Kugelman

Reputation: 361605

It is safe. bind() does not keep a reference to the pointer after it returns. It's only taking its input as a pointer because it's receiving a variable-sized struct, which can't be passed by value. (It's polymorphism in C, essentially.)

Upvotes: 3

user149341
user149341

Reputation:

No, it does not. The contents of the address parameter are copied by the kernel; you can reuse or free that memory as soon as the call returns.

In fact, it's possible to make a more general statement here: unless the documentation specifically says otherwise, arguments passed to the kernel by pointer reference only need to be kept 'alive' for the duration of the system call. Their values will be copied by the kernel if needed.

Upvotes: 4

Related Questions