I have a SIP server (daemon) which is listening on tcp socket 5060. Now in this parent process I create a child process and do something in child.
Now, What happens is when I close this tcp socket in parent process and try to create again (Lets say I am disabling and enabling SIP on this server), creating this socket gives me error. I have debugged this issue and found the root-cause. Root-cause is when child is created it inherits (gets a copy of) all the opened fd/sockets from parent. when parent closes the tcp socket it still opened in child (ref_counter!=0) and thus I cant open the socket again in parent!!
Now, the generic solution i want is - As soon as a child process is started it checks any opened fd (of type IPv4/TCP) and close them so that there is no side effect of this child process on parent. How can this be done in C-unix ?
I have contemplated about doing in the direction of system(lsof | grep | awk) and get the file descriptors, but then how do i close them ?
Any other solution to close the socket in child ? Is there a method where I can pass port number and it gives me already created fd ?
Solution which I dont want are (Which will not be helpful for me ) -
1. In parent process, initially while creating tcp socket with some flag so that they are not copied by child. (I can not modify that socket creation in parent)!
2. Passing file descriptor from parent to child at the time of creation of child process. I can not do that as I dont have that fd. The solution has to be something which needs to be put in child process!
Thanks
Here is a way to determine in your child whether your file descriptors are sockets.
Since the child is going to inherit the fd table, just iterate through the FDs testing each one. The child in the following program gets the max size of the fd table via getrlimit
and iterates through the table determining if each file descriptor is (a) open, (b) a socket and if so (c) if it is a listening socket. The parent just opens a listening and regular socket (for test purposes) before forking and then waiting on the child.
You should be able to use this outline to accomplish your goal without resorting to awk and the like.
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/stat.h>
#include <string.h>
#include <netdb.h>
int isListeningSocket(int fd)
{
int retval;
socklen_t len = sizeof(retval);
if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &retval, &len) != -1)
if (retval)
return(1);
return(0);
}
int main (int argc, char *argv[])
{
//create a listening socket
int lsock = socket(AF_INET,SOCK_STREAM, 0);
struct sockaddr_in serverinfo;
memset(&serverinfo, '0', sizeof(serverinfo));
serverinfo.sin_family=AF_INET;
serverinfo.sin_port=htons(atoi("9999"));
serverinfo.sin_addr.s_addr=INADDR_ANY;
int ret;
if ((ret = bind(lsock,(struct sockaddr *) &serverinfo, sizeof(serverinfo))) == -1)
{
perror("bind");
exit(1);
}
if ((ret = listen(lsock,1000)) == -1)
{
perror("listen");
exit(1);
}
//create a regular socket
int rsock = socket(AF_INET,SOCK_STREAM, 0);
int pid = fork();
if (pid == -1)
{
perror("fork");
exit(1);
}
if (pid) //parent
{
wait(NULL);
exit(0);
}
//child ----------
struct rlimit rlim;
if ((ret = getrlimit(RLIMIT_NOFILE, &rlim)) == -1)
{
perror("getrlimit");
exit(1);
}
int maxFD = rlim.rlim_cur;
for (int i = 0; i < maxFD; ++i)
{
struct stat statbuf;
if (fstat(i, &statbuf) == -1)
if (errno == EBADF)
{
printf("file descriptor %d is not open\n", i);
continue;
}
else
{
perror("fstat");
exit(1);
}
if (S_ISSOCK(statbuf.st_mode))
if (isListeningSocket(i))
printf("file descriptor %d is a LISTENING socket\n", i);
else
printf("file descriptor %d is a REGULAR socket\n", i);
else
printf("file descriptor %d is NOT a socket\n", i);
}
return 0;
}
You have the file descriptors. Just close the ones you don't need!
In the child you should close the listening socket.
In the parent you should close the accepted socket (=the new connection).
Children inherit their parents' open file descriptors (this also includes sockets). In your case, the child process also has the socket open and bound to the port above. Thus, no other process (in normal case) can listen on this port anymore. What you need to do is to close the socket in the child (or, in case you don't need it before fork()
) close it in the parent prior to forking.