blob: 33c86cfc9ccb6aafd4fd831a38817634ef2bcded [file] [log] [blame]
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001package naming
2
3import (
4 "errors"
5 "fmt"
6 "net"
7 "strconv"
8 "strings"
9
Jiri Simsa519c5072014-09-17 21:37:57 -070010 "veyron.io/veyron/veyron2/ipc/version"
11 "veyron.io/veyron/veyron2/naming"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070012)
13
14const (
15 separator = "@"
16 suffix = "@@"
17)
18
19var errInvalidEndpointString = errors.New("invalid endpoint string")
20
21// Network is the string returned by naming.Endpoint.Network implementations
22// defined in this package.
23const Network = "veyron"
24
25// Endpoint is a naming.Endpoint implementation used to convey RPC information.
26type Endpoint struct {
27 Protocol string
28 Address string
29 RID naming.RoutingID
30 MinIPCVersion version.IPCVersion
31 MaxIPCVersion version.IPCVersion
Cosmos Nicolaouf4107592014-10-09 17:17:11 -070032 IsMountTable bool
Jiri Simsa5293dcb2014-05-10 09:56:38 -070033}
34
35// NewEndpoint creates a new endpoint from a string as per naming.NewEndpoint
Asim Shankar7cf29002014-10-09 00:38:37 -070036func NewEndpoint(input string) (*Endpoint, error) {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -080037 ep := new(Endpoint)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070038
David Why Use Two When One Will Do Presotto9d3cfb12014-11-20 12:50:54 -080039 // We have to guess this is a mount table if we don't know.
40 ep.IsMountTable = true
41
Jiri Simsa5293dcb2014-05-10 09:56:38 -070042 // The prefix and suffix are optional.
43 input = strings.TrimPrefix(strings.TrimSuffix(input, suffix), separator)
44
45 parts := strings.Split(input, separator)
46 if len(parts) == 1 {
47 err := ep.parseHostPort(parts[0])
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -080048 return ep, err
Jiri Simsa5293dcb2014-05-10 09:56:38 -070049 }
50
51 version, err := strconv.ParseUint(parts[0], 10, 16)
52 if err != nil {
53 return nil, fmt.Errorf("invalid version: %v", err)
54 }
55
56 switch version {
57 case 1:
58 err = ep.parseV1(parts)
59 case 2:
60 err = ep.parseV2(parts)
Cosmos Nicolaouf4107592014-10-09 17:17:11 -070061 case 3:
62 err = ep.parseV3(parts)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070063 default:
64 err = errInvalidEndpointString
65 }
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -080066 return ep, err
Jiri Simsa5293dcb2014-05-10 09:56:38 -070067}
68
69func (ep *Endpoint) parseHostPort(input string) error {
70 // Could be in host:port format.
71 if _, _, err := net.SplitHostPort(input); err != nil {
72 return errInvalidEndpointString
73 }
74 ep.Protocol = "tcp"
75 ep.Address = input
76 ep.RID = naming.NullRoutingID
77
78 return nil
79}
80
81func (ep *Endpoint) parseV1(parts []string) error {
82 if len(parts) != 4 {
83 return errInvalidEndpointString
84 }
85
86 ep.Protocol = parts[1]
87 if len(ep.Protocol) == 0 {
88 ep.Protocol = "tcp"
89 }
90
91 ep.Address = parts[2]
92 if len(ep.Address) == 0 {
93 ep.Address = net.JoinHostPort("", "0")
94 }
95
96 if err := ep.RID.FromString(parts[3]); err != nil {
97 return fmt.Errorf("invalid routing id: %v", err)
98 }
99
100 return nil
101}
102
103func parseIPCVersion(input string) (version.IPCVersion, error) {
104 if input == "" {
105 return version.UnknownIPCVersion, nil
106 }
107 v, err := strconv.ParseUint(input, 10, 32)
108 if err != nil {
109 err = fmt.Errorf("invalid IPC version: %s, %v", err)
110 }
111 return version.IPCVersion(v), err
112}
113
114func printIPCVersion(v version.IPCVersion) string {
115 if v == version.UnknownIPCVersion {
116 return ""
117 }
118 return strconv.FormatUint(uint64(v), 10)
119}
120
Cosmos Nicolaouf4107592014-10-09 17:17:11 -0700121func parseMountTableFlag(input string) (bool, error) {
David Why Use Two When One Will Do Presotto9d3cfb12014-11-20 12:50:54 -0800122 switch len(input) {
123 case 0:
124 return true, nil
125 case 1:
Cosmos Nicolaouf4107592014-10-09 17:17:11 -0700126 switch f := input[0]; f {
127 case 'm':
128 return true, nil
129 case 's':
130 return false, nil
131 default:
132 return false, fmt.Errorf("%c is not one of 'm' or 's'", f)
133 }
134 }
135 return false, fmt.Errorf("flag is either missing or too long")
136}
137
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700138func (ep *Endpoint) parseV2(parts []string) error {
139 var err error
140 if len(parts) != 6 {
141 return errInvalidEndpointString
142 }
143 if err = ep.parseV1(parts[:4]); err != nil {
144 return err
145 }
146 if ep.MinIPCVersion, err = parseIPCVersion(parts[4]); err != nil {
147 return fmt.Errorf("invalid IPC version: %v", err)
148 }
149 if ep.MaxIPCVersion, err = parseIPCVersion(parts[5]); err != nil {
150 return fmt.Errorf("invalid IPC version: %v", err)
151 }
152 return nil
153}
154
Cosmos Nicolaouf4107592014-10-09 17:17:11 -0700155func (ep *Endpoint) parseV3(parts []string) error {
156 var err error
157 if len(parts) != 7 {
158 return errInvalidEndpointString
159 }
160 if err = ep.parseV2(parts[:6]); err != nil {
161 return err
162 }
163 if ep.IsMountTable, err = parseMountTableFlag(parts[6]); err != nil {
164 return fmt.Errorf("invalid mount table flag: %v", err)
165 }
166 return nil
167}
168
Mehrdad Afsharicd9852b2014-09-26 11:07:35 -0700169func (ep *Endpoint) RoutingID() naming.RoutingID {
170 //nologcall
171 return ep.RID
172}
173func (ep *Endpoint) Network() string {
174 //nologcall
175 return Network
176}
Cosmos Nicolaouf4107592014-10-09 17:17:11 -0700177
David Why Use Two When One Will Do Presotto9d3cfb12014-11-20 12:50:54 -0800178var defaultVersion = 3
Cosmos Nicolaouf4107592014-10-09 17:17:11 -0700179
180func (ep *Endpoint) VersionedString(version int) string {
181 switch version {
182 default:
183 return ep.VersionedString(defaultVersion)
184 case 1:
185 return fmt.Sprintf("@1@%s@%s@@", ep.Protocol, ep.Address)
186 case 2:
187 return fmt.Sprintf("@2@%s@%s@%s@%s@%s@@",
188 ep.Protocol, ep.Address, ep.RID,
189 printIPCVersion(ep.MinIPCVersion), printIPCVersion(ep.MaxIPCVersion))
190 case 3:
191 mt := "s"
192 if ep.IsMountTable {
193 mt = "m"
194 }
195 return fmt.Sprintf("@3@%s@%s@%s@%s@%s@%s@@",
196 ep.Protocol, ep.Address, ep.RID,
197 printIPCVersion(ep.MinIPCVersion), printIPCVersion(ep.MaxIPCVersion),
198 mt)
199 }
200}
201
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700202func (ep *Endpoint) String() string {
Mehrdad Afsharicd9852b2014-09-26 11:07:35 -0700203 //nologcall
Cosmos Nicolaouf4107592014-10-09 17:17:11 -0700204 return ep.VersionedString(defaultVersion)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700205}
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700206
207func (ep *Endpoint) Addr() net.Addr {
Mehrdad Afsharicd9852b2014-09-26 11:07:35 -0700208 //nologcall
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700209 return &addr{network: ep.Protocol, address: ep.Address}
210}
211
Cosmos Nicolaouf4107592014-10-09 17:17:11 -0700212func (ep *Endpoint) ServesMountTable() bool {
213 //nologcall
David Why Use Two When One Will Do Presotto9d3cfb12014-11-20 12:50:54 -0800214 return ep.IsMountTable
Cosmos Nicolaouf4107592014-10-09 17:17:11 -0700215}
216
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700217type addr struct {
218 network, address string
219}
220
221func (a *addr) Network() string {
222 return a.network
223}
224
225func (a *addr) String() string {
226 return a.address
227}