blob: da8bb9072d71e950da6dabbde97ad74119981026 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -07005package flags
6
7import (
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -07008 "net"
9 "strconv"
Mike Burrows4d7b13b2015-03-31 18:15:21 -070010
11 "v.io/v23/verror"
12)
13
14var (
15 errNotTCP = verror.Register(pkgPath+".errNotTCP", verror.NoRetry, "{1:}{2:} {3} is not a tcp protocol{:_}")
16 errCantParsePort = verror.Register(pkgPath+".errCantParsePort", verror.NoRetry, "{1:}{2:} failed to parse port number from {3}{:_}")
17 errNeedIPOrHostName = verror.Register(pkgPath+".errNeedIPOrHostName", verror.NoRetry, "{1:}{2:} {3} is neither an IP address nor a host name{:_}")
18 errBadIP = verror.Register(pkgPath+".errBadIP", verror.NoRetry, "{1:}{2:} failed to parse {3} as an IP address{:_}")
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -070019)
20
Nicolas LaCasse29d1d3a2015-01-22 10:48:18 -080021// TCPProtocolFlag implements flag.Value to provide validation of the command
22// line values passed to it: tcp, tcp4, tcp6, ws, ws4, ws6, wsh, wsh4, and wsh6
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -080023// being the only allowed values.
Cosmos Nicolaou036c30c2015-03-24 10:05:20 -070024type TCPProtocolFlag struct {
25 Protocol string
26}
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -070027
28// Implements flag.Value.Get
29func (t TCPProtocolFlag) Get() interface{} {
30 return t.Protocol
31}
32
33// Implements flag.Value.Set
34func (t *TCPProtocolFlag) Set(s string) error {
35 switch s {
Nicolas LaCasse29d1d3a2015-01-22 10:48:18 -080036 case "tcp", "tcp4", "tcp6", "ws", "ws4", "ws6", "wsh", "wsh4", "wsh6":
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -070037 t.Protocol = s
38 return nil
39 default:
Mike Burrows4d7b13b2015-03-31 18:15:21 -070040 return verror.New(errNotTCP, nil, s)
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -070041 }
42
43}
44
45// Implements flag.Value.String
46func (t TCPProtocolFlag) String() string {
47 return t.Protocol
48}
49
50// IPHostPortFlag implements flag.Value to provide validation of the
51// command line value it is set to. The allowed format is <host>:<port> in
52// ip4 and ip6 formats. The host may be specified as a hostname or as an IP
53// address (v4 or v6). If a hostname is used and it resolves to multiple IP
54// addresses then all of those addresses are stored in IPHostPort.
55type IPHostPortFlag struct {
56 Address string
57 Host string
58 IP []*net.IPAddr
59 Port string
60}
61
62// Implements flag.Value.Get
63func (ip IPHostPortFlag) Get() interface{} {
64 return ip.String()
65}
66
67// Implements flag.Value.Set
68func (ip *IPHostPortFlag) Set(s string) error {
Cosmos Nicolaoua0251092014-11-09 22:04:37 -080069 if len(s) == 0 {
70 ip.Address, ip.Port, ip.Host = "", "", ""
71 return nil
72 }
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -070073 ip.Address = s
74 host, port, err := net.SplitHostPort(s)
75 if err != nil {
76 // no port number in s.
77 host = s
78 ip.Port = "0"
79 } else {
80 // have a port in s.
81 if _, err := strconv.ParseUint(port, 10, 16); err != nil {
Mike Burrows4d7b13b2015-03-31 18:15:21 -070082 return verror.New(errCantParsePort, nil, s)
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -070083 }
84 ip.Port = port
85 }
86 // if len(host) == 0 then we have no host, just a port.
87 if len(host) > 0 {
88 if addr := net.ParseIP(host); addr == nil {
89 // Could be a hostname.
90 addrs, err := net.LookupIP(host)
91 if err != nil {
Mike Burrows4d7b13b2015-03-31 18:15:21 -070092 return verror.New(errNeedIPOrHostName, nil, host, err)
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -070093 }
94 for _, a := range addrs {
95 ip.IP = append(ip.IP, &net.IPAddr{IP: a})
96 }
97 ip.Host = host
98 } else {
99 ip.IP = []*net.IPAddr{{IP: addr}}
100 }
101 return nil
102 }
103 return nil
104}
105
106// Implements flag.Value.String
107func (ip IPHostPortFlag) String() string {
Cosmos Nicolaoua0251092014-11-09 22:04:37 -0800108 if len(ip.Address) == 0 && len(ip.Port) == 0 {
109 return ""
110 }
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -0700111 host := ip.Host
112 if len(ip.Host) == 0 && ip.IP != nil && len(ip.IP) > 0 {
113 // We don't have a hostname, so there should be at most one IP address.
114 host = ip.IP[0].String()
115 }
116 return net.JoinHostPort(host, ip.Port)
117}
118
119// IPFlag implements flag.Value in order to provide validation of
120// IP addresses in the flag package.
121type IPFlag struct{ net.IP }
122
123// Implements flag.Value.Get
124func (ip IPFlag) Get() interface{} {
125 return ip.IP
126}
127
128// Implements flag.Value.Set
129func (ip *IPFlag) Set(s string) error {
130 t := net.ParseIP(s)
131 if t == nil {
Mike Burrows4d7b13b2015-03-31 18:15:21 -0700132 return verror.New(errBadIP, nil, s)
Cosmos Nicolaoua18394e2014-09-11 13:18:32 -0700133 }
134 ip.IP = t
135 return nil
136}
137
138// Implements flag.Value.String
139func (ip IPFlag) String() string {
140 return ip.IP.String()
141}