// Copyright 2015-2016 Luke Shumaker package util import ( "fmt" "net" "os" "strconv" "strings" "sync" sd "lukeshu.com/git/go/libsystemd/sd_daemon" ) var fdsLock sync.Mutex var fds = map[int]*os.File{} var sdFds = map[string]int{} func init() { fds[0] = os.Stdin fds[1] = os.Stdout fds[2] = os.Stderr fromSd := sd.ListenFds(true) if fromSd == nil { return } for i, file := range fromSd { fds[i+3] = file sdFds[file.Name()] = i + 3 } } func FdNameToNum(name string) int { switch name { case "stdin": return 0 case "stdout": return 1 case "stderr": return 2 case "systemd": if len(sdFds) == 0 { return -1 } return 3 default: if n, err := strconv.Atoi(name); err == nil { if n >= 0 { return n } } else if strings.HasPrefix(name, "systemd:") { name = strings.TrimPrefix(name, "systemd") n, ok := sdFds[name] if ok { return n } else if n, err := strconv.Atoi(name); err == nil && n < len(sdFds) { return n + 3 } } return -1 } } func FdFile(fd int) *os.File { fdsLock.Lock() defer fdsLock.Unlock() file, ok := fds[fd] if ok { return file } file = os.NewFile(uintptr(fd), fmt.Sprintf("/dev/fd/%d", fd)) fds[fd] = file return file } func StreamListener(stype, saddr string) (net.Listener, error) { switch stype { case "fd": return net.FileListener(FdFile(FdNameToNum(saddr))) default: /* case "tcp", "tcp4", "tcp6", "unix", "unixpacket": */ return net.Listen(stype, saddr) } } func PacketListener(stype, saddr string) (net.PacketConn, error) { switch stype { case "fd": return net.FilePacketConn(FdFile(FdNameToNum(saddr))) default: /* case "udp", "udp4", "udp6", "ip", "ip4", "ip6", "unixgram": */ return net.ListenPacket(stype, saddr) } } // For completeless, I might want to implement methods for each of // these: // - FIFO // - Special // - Netlink // - MessageQueue // - USBFunction