1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17 package listen
18
19 import (
20 "errors"
21 "flag"
22 "fmt"
23 "net"
24 "os"
25 "runtime"
26 "strconv"
27 "strings"
28 )
29
30
31 func NewFlag(flagName, defaultValue string, serverType string) *Addr {
32 addr := &Addr{
33 s: defaultValue,
34 }
35 flag.Var(addr, flagName, Usage(serverType))
36 return addr
37 }
38
39
40
41
42
43
44 func Listen(addr string) (net.Listener, error) {
45 a := &Addr{s: addr}
46 return a.Listen()
47 }
48
49
50
51 func Usage(name string) string {
52 if name == "" {
53 name = "Listen address"
54 }
55 if !strings.HasSuffix(name, " address") {
56 name += " address"
57 }
58 return name + "; may be port, :port, ip:port, or FD:<fd_num>"
59 }
60
61
62
63
64
65
66
67 type Addr struct {
68 s string
69 ln net.Listener
70 err error
71 }
72
73 func (a *Addr) String() string {
74 return a.s
75 }
76
77
78 func (a *Addr) Set(v string) error {
79 a.s = v
80
81 if strings.HasPrefix(v, "FD:") {
82 fdStr := v[len("FD:"):]
83 fd, err := strconv.ParseUint(fdStr, 10, 32)
84 if err != nil {
85 return fmt.Errorf("invalid file descriptor %q: %v", fdStr, err)
86 }
87 return a.listenOnFD(uintptr(fd))
88 }
89
90 ipPort := v
91 if isPort(v) {
92 ipPort = ":" + v
93 }
94
95 _, _, err := net.SplitHostPort(ipPort)
96 if err != nil {
97 return fmt.Errorf("invalid PORT or IP:PORT %q: %v", v, err)
98 }
99 a.ln, err = net.Listen("tcp", ipPort)
100 return err
101 }
102
103 func isPort(s string) bool {
104 _, err := strconv.ParseUint(s, 10, 16)
105 return err == nil
106 }
107
108 func (a *Addr) listenOnFD(fd uintptr) (err error) {
109 if runtime.GOOS == "windows" {
110 panic("listenOnFD unsupported on Windows")
111 }
112 f := os.NewFile(fd, fmt.Sprintf("fd #%d from process parent", fd))
113 a.ln, err = net.FileListener(f)
114 return
115 }
116
117 var _ flag.Value = (*Addr)(nil)
118
119
120 func (a *Addr) Listen() (net.Listener, error) {
121
122
123 if a.err == nil && a.ln == nil && a.s != "" {
124 if err := a.Set(a.s); err != nil {
125 return nil, err
126 }
127 }
128 if a.err != nil {
129 return nil, a.err
130 }
131 if a.ln != nil {
132 return a.ln, nil
133 }
134 return nil, errors.New("listen: no error or listener")
135 }