Jiri Simsa | d7616c9 | 2015-03-24 23:44:30 -0700 | [diff] [blame] | 1 | // 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 Nicolaou | a18394e | 2014-09-11 13:18:32 -0700 | [diff] [blame] | 5 | package flags |
| 6 | |
| 7 | import ( |
Cosmos Nicolaou | a18394e | 2014-09-11 13:18:32 -0700 | [diff] [blame] | 8 | "net" |
| 9 | "strconv" |
Mike Burrows | 4d7b13b | 2015-03-31 18:15:21 -0700 | [diff] [blame] | 10 | |
| 11 | "v.io/v23/verror" |
| 12 | ) |
| 13 | |
| 14 | var ( |
| 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 Nicolaou | a18394e | 2014-09-11 13:18:32 -0700 | [diff] [blame] | 19 | ) |
| 20 | |
Nicolas LaCasse | 29d1d3a | 2015-01-22 10:48:18 -0800 | [diff] [blame] | 21 | // 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 Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 23 | // being the only allowed values. |
Cosmos Nicolaou | 036c30c | 2015-03-24 10:05:20 -0700 | [diff] [blame] | 24 | type TCPProtocolFlag struct { |
| 25 | Protocol string |
| 26 | } |
Cosmos Nicolaou | a18394e | 2014-09-11 13:18:32 -0700 | [diff] [blame] | 27 | |
| 28 | // Implements flag.Value.Get |
| 29 | func (t TCPProtocolFlag) Get() interface{} { |
| 30 | return t.Protocol |
| 31 | } |
| 32 | |
| 33 | // Implements flag.Value.Set |
| 34 | func (t *TCPProtocolFlag) Set(s string) error { |
| 35 | switch s { |
Nicolas LaCasse | 29d1d3a | 2015-01-22 10:48:18 -0800 | [diff] [blame] | 36 | case "tcp", "tcp4", "tcp6", "ws", "ws4", "ws6", "wsh", "wsh4", "wsh6": |
Cosmos Nicolaou | a18394e | 2014-09-11 13:18:32 -0700 | [diff] [blame] | 37 | t.Protocol = s |
| 38 | return nil |
| 39 | default: |
Mike Burrows | 4d7b13b | 2015-03-31 18:15:21 -0700 | [diff] [blame] | 40 | return verror.New(errNotTCP, nil, s) |
Cosmos Nicolaou | a18394e | 2014-09-11 13:18:32 -0700 | [diff] [blame] | 41 | } |
| 42 | |
| 43 | } |
| 44 | |
| 45 | // Implements flag.Value.String |
| 46 | func (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. |
| 55 | type IPHostPortFlag struct { |
| 56 | Address string |
| 57 | Host string |
| 58 | IP []*net.IPAddr |
| 59 | Port string |
| 60 | } |
| 61 | |
| 62 | // Implements flag.Value.Get |
| 63 | func (ip IPHostPortFlag) Get() interface{} { |
| 64 | return ip.String() |
| 65 | } |
| 66 | |
| 67 | // Implements flag.Value.Set |
| 68 | func (ip *IPHostPortFlag) Set(s string) error { |
Cosmos Nicolaou | a025109 | 2014-11-09 22:04:37 -0800 | [diff] [blame] | 69 | if len(s) == 0 { |
| 70 | ip.Address, ip.Port, ip.Host = "", "", "" |
| 71 | return nil |
| 72 | } |
Cosmos Nicolaou | a18394e | 2014-09-11 13:18:32 -0700 | [diff] [blame] | 73 | 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 Burrows | 4d7b13b | 2015-03-31 18:15:21 -0700 | [diff] [blame] | 82 | return verror.New(errCantParsePort, nil, s) |
Cosmos Nicolaou | a18394e | 2014-09-11 13:18:32 -0700 | [diff] [blame] | 83 | } |
| 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 Burrows | 4d7b13b | 2015-03-31 18:15:21 -0700 | [diff] [blame] | 92 | return verror.New(errNeedIPOrHostName, nil, host, err) |
Cosmos Nicolaou | a18394e | 2014-09-11 13:18:32 -0700 | [diff] [blame] | 93 | } |
| 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 |
| 107 | func (ip IPHostPortFlag) String() string { |
Cosmos Nicolaou | a025109 | 2014-11-09 22:04:37 -0800 | [diff] [blame] | 108 | if len(ip.Address) == 0 && len(ip.Port) == 0 { |
| 109 | return "" |
| 110 | } |
Cosmos Nicolaou | a18394e | 2014-09-11 13:18:32 -0700 | [diff] [blame] | 111 | 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. |
| 121 | type IPFlag struct{ net.IP } |
| 122 | |
| 123 | // Implements flag.Value.Get |
| 124 | func (ip IPFlag) Get() interface{} { |
| 125 | return ip.IP |
| 126 | } |
| 127 | |
| 128 | // Implements flag.Value.Set |
| 129 | func (ip *IPFlag) Set(s string) error { |
| 130 | t := net.ParseIP(s) |
| 131 | if t == nil { |
Mike Burrows | 4d7b13b | 2015-03-31 18:15:21 -0700 | [diff] [blame] | 132 | return verror.New(errBadIP, nil, s) |
Cosmos Nicolaou | a18394e | 2014-09-11 13:18:32 -0700 | [diff] [blame] | 133 | } |
| 134 | ip.IP = t |
| 135 | return nil |
| 136 | } |
| 137 | |
| 138 | // Implements flag.Value.String |
| 139 | func (ip IPFlag) String() string { |
| 140 | return ip.IP.String() |
| 141 | } |