Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass net.Listener()'s FD to child process safely?

I've been stucked with this issue for hours:

I have a main process served as a TCP server, the main process call Fork(), pass its net.Listener()'s FD to child process. Then child process can use net.Filelistener() to inherit this FD.

I have researched this issue through many open-sourced codes, also did some experiments. But unfortunately none of these solutions satisfy me for now since they are not portable, you also need many low-level jobs which are dangerous.

If there's any solution to pass net.Listener()'s FD to child process SAFELY, I'd be glad to know.

What I've tried for now:

  1. Environment values, not portable, will cause chaos with many FDs, not safe since can be changed from outside.

  2. Dup FD & Clear FD_CLOEXEC then exec/fork, portable but not supported by Go API, a syscall.NoCloseOnExec() change submitted to dev team was rejected since they want to keep syscall clean.

  3. Set SO_REUSEADDR so child process can listen to port instantly, close parent's listener before that. Failed, not portable, not supported by Go API, also unsafe.

  4. exec.Command.ExtraFiles(), have no idea how to get inherited FDs from child process, do I need a config file to save FD & names? This solution also have a bug, read exec's document for more detail.

All right guys, I've written a simple test case of this issue(with solution 4):

https://github.com/reckhou/go-fd-pass-test

Also include 2 executables on OS X & Linux. I tried Go 1.1 & Go 1.1.1 but this issue still remains.

like image 521
Reck Hou Avatar asked Jun 19 '13 13:06

Reck Hou


1 Answers

The easiest way is to pass the listener in the ExtraFiles field of exec.Cmd.

Example of parent:

var l *net.TCPListener
cmd := exec.Command(...)
f, err := l.File()
cmd.ExtraFiles = []*os.File{f}

Example of child:

l, err := net.FileListener(os.NewFile(3, "listener"))

You may also want to generalize this and have the child accept PROGRAMNAME_LISTENER_FD as an environment variable. Then the parent would set the environment variable to 3 before starting the child.

like image 74
Stephen Weinberg Avatar answered Oct 30 '22 03:10

Stephen Weinberg