Created
February 19, 2014 17:07
-
-
Save rcrowley/9096494 to your computer and use it in GitHub Desktop.
sendmsg(2) SCM_RIGHTS demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"log" | |
"net" | |
"os" | |
"os/exec" | |
"reflect" | |
"syscall" | |
) | |
func init() { | |
log.SetFlags(log.Lmicroseconds | log.Lshortfile) | |
log.SetPrefix(fmt.Sprintf("pid:%d ", os.Getpid())) | |
} | |
func lsof() { | |
log.Printf("lsof -p %d:", os.Getpid()) | |
cmd := exec.Command("lsof", "-p", fmt.Sprint(os.Getpid())) | |
cmd.Stdout = os.Stdout | |
cmd.Stderr = os.Stderr | |
if err := cmd.Run(); nil != err { | |
log.Fatalln(err) | |
} | |
} | |
func main() { | |
// Open a UNIX domain socket. The parent process will use it to receive | |
// sentinel requests from and send file descriptors to the child process. | |
// The child process will use it to send sentinel requests to and receive | |
// file descriptors from the parent process. | |
laddr, err := net.ResolveUnixAddr( | |
"unixgram", | |
fmt.Sprintf("%d.sock", os.Getpid()), | |
) | |
if nil != err { | |
log.Fatalln(err) | |
} | |
c, err := net.DialUnix("unixgram", laddr, nil) | |
if nil != err { | |
log.Fatalln(err) | |
} | |
defer c.Close() | |
defer os.Remove(laddr.String()) | |
// Parent process. | |
if "" == os.Getenv("SENDMSG") { | |
// Fork and exec another copy of the same process image. This one | |
// has SENDMSG=1 in its environment so it goes down the other side | |
// of the if-statement above. | |
argv0, err := exec.LookPath(os.Args[0]) | |
if nil != err { | |
log.Fatalln(err) | |
} | |
p, err := os.StartProcess(argv0, os.Args, &os.ProcAttr{ | |
Env: append(os.Environ(), "SENDMSG=1"), | |
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, | |
}) | |
if nil != err { | |
log.Fatalln(err) | |
} | |
log.Println("spawned child", p.Pid) | |
// Listen. There's nothing special about this listener. The only | |
// notable thing is that it's opened after the child process has | |
// forked so it is not inherited. | |
l, err := net.Listen("tcp", "127.0.0.1:48879") | |
if nil != err { | |
log.Fatalln(err) | |
} | |
log.Println("listening on", l.Addr()) | |
// Receive a sentinel request from the UNIX domain socket that | |
// instructs us to send the listening file descriptor. | |
b := make([]byte, 128) | |
oob := make([]byte, 128) | |
n, oobn, _, addr, err := c.ReadMsgUnix(b, oob) | |
if nil != err { | |
log.Fatalln(err) | |
} | |
log.Println("b:", b[:n]) | |
log.Println("oob:", oob[:oobn]) | |
// Send the listening file descrptor to another process. | |
// | |
// Go doesn't make it super easy to get a file descriptor that | |
// hasn't been dup(2)ed. | |
if _, _, err := c.WriteMsgUnix( | |
nil, | |
syscall.UnixRights( | |
int(reflect.ValueOf(l).Elem().FieldByName("fd").Elem().FieldByName("sysfd").Int()), | |
), | |
addr, | |
); nil != err { | |
log.Fatalln(err) | |
} | |
// Wait for the child process to exit. The fun's over. | |
ps, err := p.Wait() | |
if nil != err { | |
log.Fatalln(err) | |
} | |
log.Println(ps) | |
// Child process. | |
} else { | |
// Prove this process is not listening on 127.0.0.1:48879. | |
lsof() | |
// Open a UNIX domain socket to use for receiving file descriptors | |
// from our parent process. | |
raddr, err := net.ResolveUnixAddr( | |
"unixgram", | |
fmt.Sprintf("%d.sock", os.Getppid()), | |
) | |
if nil != err { | |
log.Fatalln(err) | |
} | |
// Request the parent process send us the listening file descriptor. | |
if _, _, err := c.WriteMsgUnix(nil, nil, raddr); nil != err { | |
log.Fatalln(err) | |
} | |
// Receive the listening file descriptor. | |
b := make([]byte, 128) | |
oob := make([]byte, 128) | |
n, oobn, _, _, err := c.ReadMsgUnix(b, oob) | |
if nil != err { | |
log.Fatalln(err) | |
} | |
log.Println("b:", b[:n]) | |
log.Println("oob:", oob[:oobn]) | |
// Prove that this process is now listening on 127.0.0.1:48879. | |
lsof() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment