Skip to content

Instantly share code, notes, and snippets.

@poolpOrg
Created April 9, 2021 17:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save poolpOrg/6ddd5226f59ef60f4af1ade97aed8566 to your computer and use it in GitHub Desktop.
Save poolpOrg/6ddd5226f59ef60f4af1ade97aed8566 to your computer and use it in GitHub Desktop.
ipcmsg example
package main
import (
"log"
"os"
"os/exec"
"syscall"
"time"
"github.com/poolpOrg/ipcmsg"
)
// fork a child and build an ipcmsg channel over the child fd
//
func parent() {
log.Println("starting parent")
pid, fd := fork_child()
_, child_w := ipcmsg.Channel(pid, fd)
for {
time.Sleep(1 * time.Second)
pfd, _ := syscall.Open("/private/etc/passwd", 0700, 0)
child_w <- ipcmsg.MessageWithFd(42, []byte("foobar"), pfd)
child_w <- ipcmsg.Message(42, []byte("barbaz"))
child_w <- ipcmsg.Message(42, []byte("barbaz"))
child_w <- ipcmsg.Message(42, []byte("barbaz"))
child_w <- ipcmsg.Message(42, []byte("barbaz"))
}
}
// build an ipcmsg channel over fd 3
//
func child() {
log.Println("hellow, i'm child of", os.Getppid())
parent_r, _ := ipcmsg.Channel(os.Getppid(), 3)
for {
msg := <-parent_r
if msg.Fd != -1 {
log.Println(string(msg.Data), "fd=", msg.Fd)
syscall.Close(msg.Fd)
} else {
log.Println(string(msg.Data), "nofd")
}
}
}
// fork a child and reexec the process with env REEXEC=CHILD so executable can assign a
// different task to child in main()
//
func fork_child() (int, int) {
binary, err := exec.LookPath(os.Args[0])
if err != nil {
log.Fatal(err)
}
sp, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, syscall.AF_UNSPEC)
if err != nil {
log.Fatal(err)
}
procAttr := syscall.ProcAttr{}
procAttr.Files = []uintptr{
uintptr(syscall.Stdin),
uintptr(syscall.Stdout),
uintptr(syscall.Stderr),
uintptr(sp[0]),
}
procAttr.Env = []string{
"REEXEC=CHILD",
}
var pid int
pid, err = syscall.ForkExec(binary, []string{os.Args[0]}, &procAttr)
if err != nil {
log.Fatal(err)
}
if syscall.Close(sp[0]) != nil {
log.Fatal(err)
}
return pid, sp[1]
}
// execute parent() or child() depending on the process REEXEC name
//
func main() {
reexec := os.Getenv("REEXEC")
switch reexec {
case "":
parent()
case "CHILD":
child()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment