I have a TCP server application which occasionally needs to reconfigure the bound ports by closing them and then opening them at a later time.
The application also needs to execute an external binary with communication to it. This is currently done using a popen() call. The external binary run time can span the period when the network ports need to be reconfigured.
The problem is, when the main application closes a port it is taken on by the 'forked' process which popen has created to run the binary.
That makes sense (it's discussed at What happens when a tcp server binds and forks before doing an accept ? Which process would handle the client requests? ), but is undesirable, as the main application is then unable to reopen the port.
Is this where FD_CLOEXEC O_CLOEXEC as available in popen(3) can be used? The application needs the pipe that popen(3) offers as stdin to the binary which is executed, is that filehandle left open when CLOEXEC closes the others.
Is there a better way to run the binary, which won't result in a forked process which will hold on to a closed port?
There is another, possibly related question at How to fork process without inheriting handles?
No, you cannot start another program and get back from it without fork(2) followed by some execve(2) code (which is what popen
, posix_spawn
, and system
are doing). You'll better avoid popen
or system
and code the pipe
+fork
+execve
explicitly yourself (since you know which file descriptors should be kept and which to close(2), generally after the fork
and before the execve
in the child process...), see this.
(every process & program, except /sbin/init
and some hotplug things, is started with fork
+ execve
; and your shell is constantly using fork
+ execve
for most commands, except the builtin ones like cd
)
the fork(2) call could be implemented by clone(2).
Read some good book like the Advanced Linux Programming book freely available online here. See also syscalls(2). Use (at least for debugging and to understand things) strace(1) and your debugger (gdb
). Study the source code of popen
and of system
in your free software libc (GNU libc or musl-libc), and the source code of your shell.
You could nearly mimic execve(2) by a tricky sequence of mmap(2) (and related munmap
) calls, but not quite (in particular w.r.t. close-on-exec etc...). You'll probably need also to call the obsolete setcontext(3) (or write the equivalent assembler code).
You might consider communicating with a specialized shell-like server-like program doing the fork
& execve
(see my execicar.c for example and inspiration). Maybe you'll find daemon(3) useful.
A better alternative might be to embed some interpreter (like lua or guile) in your application and/or to dlopen(3) some plugin. The disadvantage is that a bug (in the interpreted script or the plugin) affects your entire server.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With