Reputation: 3086
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
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
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