summaryrefslogtreecommitdiff
path: root/src/util/fd.go
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-11-01 14:46:15 -0400
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-11-01 14:46:15 -0400
commitc7eea383aeaf6748daf994e9e28e4d0c25350736 (patch)
treea0979cbd4e6be06385fd0340e050147fdacd6e35 /src/util/fd.go
initial commit
Diffstat (limited to 'src/util/fd.go')
-rw-r--r--src/util/fd.go101
1 files changed, 101 insertions, 0 deletions
diff --git a/src/util/fd.go b/src/util/fd.go
new file mode 100644
index 0000000..17c64cd
--- /dev/null
+++ b/src/util/fd.go
@@ -0,0 +1,101 @@
+// Copyright 2015-2016 Luke Shumaker
+
+package util
+
+import (
+ "net"
+ "os"
+ "strings"
+ "fmt"
+ "sync"
+ "strconv"
+
+ 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