blob: 929dd565d7f0ada1e00d4e5748bf952cd7b9c549 [file] [log] [blame]
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -07001package flags
2
3import (
4 "fmt"
5 "net"
6 "strconv"
7)
8
9// TCPProtocolFlag implements flag.Value to provide validation of the
10// command line values passed to it: tcp, tcp4 or tcp6 being the
11// only allowed values.
12type TCPProtocolFlag struct{ Protocol string }
13
14// Implements flag.Value.Get
15func (t TCPProtocolFlag) Get() interface{} {
16 return t.Protocol
17}
18
19// Implements flag.Value.Set
20func (t *TCPProtocolFlag) Set(s string) error {
21 switch s {
22 case "tcp", "tcp4", "tcp6":
23 t.Protocol = s
24 return nil
25 default:
26 return fmt.Errorf("%q is not a tcp protocol", s)
27 }
28
29}
30
31// Implements flag.Value.String
32func (t TCPProtocolFlag) String() string {
33 return t.Protocol
34}
35
36// IPHostPortFlag implements flag.Value to provide validation of the
37// command line value it is set to. The allowed format is <host>:<port> in
38// ip4 and ip6 formats. The host may be specified as a hostname or as an IP
39// address (v4 or v6). If a hostname is used and it resolves to multiple IP
40// addresses then all of those addresses are stored in IPHostPort.
41type IPHostPortFlag struct {
42 Address string
43 Host string
44 IP []*net.IPAddr
45 Port string
46}
47
48// Implements flag.Value.Get
49func (ip IPHostPortFlag) Get() interface{} {
50 return ip.String()
51}
52
53// Implements flag.Value.Set
54func (ip *IPHostPortFlag) Set(s string) error {
Cosmos Nicolaoua0251092014-11-09 22:04:37 -080055 if len(s) == 0 {
56 ip.Address, ip.Port, ip.Host = "", "", ""
57 return nil
58 }
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -070059 ip.Address = s
60 host, port, err := net.SplitHostPort(s)
61 if err != nil {
62 // no port number in s.
63 host = s
64 ip.Port = "0"
65 } else {
66 // have a port in s.
67 if _, err := strconv.ParseUint(port, 10, 16); err != nil {
68 return fmt.Errorf("failed to parse port number from %s", s)
69 }
70 ip.Port = port
71 }
72 // if len(host) == 0 then we have no host, just a port.
73 if len(host) > 0 {
74 if addr := net.ParseIP(host); addr == nil {
75 // Could be a hostname.
76 addrs, err := net.LookupIP(host)
77 if err != nil {
78 return fmt.Errorf("%s is neither an IP address nor a host name:%s", host, err)
79 }
80 for _, a := range addrs {
81 ip.IP = append(ip.IP, &net.IPAddr{IP: a})
82 }
83 ip.Host = host
84 } else {
85 ip.IP = []*net.IPAddr{{IP: addr}}
86 }
87 return nil
88 }
89 return nil
90}
91
92// Implements flag.Value.String
93func (ip IPHostPortFlag) String() string {
Cosmos Nicolaoua0251092014-11-09 22:04:37 -080094 if len(ip.Address) == 0 && len(ip.Port) == 0 {
95 return ""
96 }
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -070097 host := ip.Host
98 if len(ip.Host) == 0 && ip.IP != nil && len(ip.IP) > 0 {
99 // We don't have a hostname, so there should be at most one IP address.
100 host = ip.IP[0].String()
101 }
102 return net.JoinHostPort(host, ip.Port)
103}
104
105// IPFlag implements flag.Value in order to provide validation of
106// IP addresses in the flag package.
107type IPFlag struct{ net.IP }
108
109// Implements flag.Value.Get
110func (ip IPFlag) Get() interface{} {
111 return ip.IP
112}
113
114// Implements flag.Value.Set
115func (ip *IPFlag) Set(s string) error {
116 t := net.ParseIP(s)
117 if t == nil {
118 return fmt.Errorf("failed to parse %s as an IP address", s)
119 }
120 ip.IP = t
121 return nil
122}
123
124// Implements flag.Value.String
125func (ip IPFlag) String() string {
126 return ip.IP.String()
127}