OSDN Git Service

new repo
[bytom/vapor.git] / vendor / google.golang.org / grpc / naming / dns_resolver.go
1 /*
2  *
3  * Copyright 2017 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18
19 package naming
20
21 import (
22         "errors"
23         "fmt"
24         "net"
25         "strconv"
26         "time"
27
28         "golang.org/x/net/context"
29         "google.golang.org/grpc/grpclog"
30 )
31
32 const (
33         defaultPort = "443"
34         defaultFreq = time.Minute * 30
35 )
36
37 var (
38         errMissingAddr  = errors.New("missing address")
39         errWatcherClose = errors.New("watcher has been closed")
40 )
41
42 // NewDNSResolverWithFreq creates a DNS Resolver that can resolve DNS names, and
43 // create watchers that poll the DNS server using the frequency set by freq.
44 func NewDNSResolverWithFreq(freq time.Duration) (Resolver, error) {
45         return &dnsResolver{freq: freq}, nil
46 }
47
48 // NewDNSResolver creates a DNS Resolver that can resolve DNS names, and create
49 // watchers that poll the DNS server using the default frequency defined by defaultFreq.
50 func NewDNSResolver() (Resolver, error) {
51         return NewDNSResolverWithFreq(defaultFreq)
52 }
53
54 // dnsResolver handles name resolution for names following the DNS scheme
55 type dnsResolver struct {
56         // frequency of polling the DNS server that the watchers created by this resolver will use.
57         freq time.Duration
58 }
59
60 // formatIP returns ok = false if addr is not a valid textual representation of an IP address.
61 // If addr is an IPv4 address, return the addr and ok = true.
62 // If addr is an IPv6 address, return the addr enclosed in square brackets and ok = true.
63 func formatIP(addr string) (addrIP string, ok bool) {
64         ip := net.ParseIP(addr)
65         if ip == nil {
66                 return "", false
67         }
68         if ip.To4() != nil {
69                 return addr, true
70         }
71         return "[" + addr + "]", true
72 }
73
74 // parseTarget takes the user input target string, returns formatted host and port info.
75 // If target doesn't specify a port, set the port to be the defaultPort.
76 // If target is in IPv6 format and host-name is enclosed in sqarue brackets, brackets
77 // are strippd when setting the host.
78 // examples:
79 // target: "www.google.com" returns host: "www.google.com", port: "443"
80 // target: "ipv4-host:80" returns host: "ipv4-host", port: "80"
81 // target: "[ipv6-host]" returns host: "ipv6-host", port: "443"
82 // target: ":80" returns host: "localhost", port: "80"
83 // target: ":" returns host: "localhost", port: "443"
84 func parseTarget(target string) (host, port string, err error) {
85         if target == "" {
86                 return "", "", errMissingAddr
87         }
88
89         if ip := net.ParseIP(target); ip != nil {
90                 // target is an IPv4 or IPv6(without brackets) address
91                 return target, defaultPort, nil
92         }
93         if host, port, err := net.SplitHostPort(target); err == nil {
94                 // target has port, i.e ipv4-host:port, [ipv6-host]:port, host-name:port
95                 if host == "" {
96                         // Keep consistent with net.Dial(): If the host is empty, as in ":80", the local system is assumed.
97                         host = "localhost"
98                 }
99                 if port == "" {
100                         // If the port field is empty(target ends with colon), e.g. "[::1]:", defaultPort is used.
101                         port = defaultPort
102                 }
103                 return host, port, nil
104         }
105         if host, port, err := net.SplitHostPort(target + ":" + defaultPort); err == nil {
106                 // target doesn't have port
107                 return host, port, nil
108         }
109         return "", "", fmt.Errorf("invalid target address %v", target)
110 }
111
112 // Resolve creates a watcher that watches the name resolution of the target.
113 func (r *dnsResolver) Resolve(target string) (Watcher, error) {
114         host, port, err := parseTarget(target)
115         if err != nil {
116                 return nil, err
117         }
118
119         if net.ParseIP(host) != nil {
120                 ipWatcher := &ipWatcher{
121                         updateChan: make(chan *Update, 1),
122                 }
123                 host, _ = formatIP(host)
124                 ipWatcher.updateChan <- &Update{Op: Add, Addr: host + ":" + port}
125                 return ipWatcher, nil
126         }
127
128         ctx, cancel := context.WithCancel(context.Background())
129         return &dnsWatcher{
130                 r:      r,
131                 host:   host,
132                 port:   port,
133                 ctx:    ctx,
134                 cancel: cancel,
135                 t:      time.NewTimer(0),
136         }, nil
137 }
138
139 // dnsWatcher watches for the name resolution update for a specific target
140 type dnsWatcher struct {
141         r    *dnsResolver
142         host string
143         port string
144         // The latest resolved address set
145         curAddrs map[string]*Update
146         ctx      context.Context
147         cancel   context.CancelFunc
148         t        *time.Timer
149 }
150
151 // ipWatcher watches for the name resolution update for an IP address.
152 type ipWatcher struct {
153         updateChan chan *Update
154 }
155
156 // Next returns the adrress resolution Update for the target. For IP address,
157 // the resolution is itself, thus polling name server is unncessary. Therefore,
158 // Next() will return an Update the first time it is called, and will be blocked
159 // for all following calls as no Update exisits until watcher is closed.
160 func (i *ipWatcher) Next() ([]*Update, error) {
161         u, ok := <-i.updateChan
162         if !ok {
163                 return nil, errWatcherClose
164         }
165         return []*Update{u}, nil
166 }
167
168 // Close closes the ipWatcher.
169 func (i *ipWatcher) Close() {
170         close(i.updateChan)
171 }
172
173 // AddressType indicates the address type returned by name resolution.
174 type AddressType uint8
175
176 const (
177         // Backend indicates the server is a backend server.
178         Backend AddressType = iota
179         // GRPCLB indicates the server is a grpclb load balancer.
180         GRPCLB
181 )
182
183 // AddrMetadataGRPCLB contains the information the name resolver for grpclb should provide. The
184 // name resolver used by the grpclb balancer is required to provide this type of metadata in
185 // its address updates.
186 type AddrMetadataGRPCLB struct {
187         // AddrType is the type of server (grpc load balancer or backend).
188         AddrType AddressType
189         // ServerName is the name of the grpc load balancer. Used for authentication.
190         ServerName string
191 }
192
193 // compileUpdate compares the old resolved addresses and newly resolved addresses,
194 // and generates an update list
195 func (w *dnsWatcher) compileUpdate(newAddrs map[string]*Update) []*Update {
196         var res []*Update
197         for a, u := range w.curAddrs {
198                 if _, ok := newAddrs[a]; !ok {
199                         u.Op = Delete
200                         res = append(res, u)
201                 }
202         }
203         for a, u := range newAddrs {
204                 if _, ok := w.curAddrs[a]; !ok {
205                         res = append(res, u)
206                 }
207         }
208         return res
209 }
210
211 func (w *dnsWatcher) lookupSRV() map[string]*Update {
212         newAddrs := make(map[string]*Update)
213         _, srvs, err := lookupSRV(w.ctx, "grpclb", "tcp", w.host)
214         if err != nil {
215                 grpclog.Infof("grpc: failed dns SRV record lookup due to %v.\n", err)
216                 return nil
217         }
218         for _, s := range srvs {
219                 lbAddrs, err := lookupHost(w.ctx, s.Target)
220                 if err != nil {
221                         grpclog.Warningf("grpc: failed load banlacer address dns lookup due to %v.\n", err)
222                         continue
223                 }
224                 for _, a := range lbAddrs {
225                         a, ok := formatIP(a)
226                         if !ok {
227                                 grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err)
228                                 continue
229                         }
230                         addr := a + ":" + strconv.Itoa(int(s.Port))
231                         newAddrs[addr] = &Update{Addr: addr,
232                                 Metadata: AddrMetadataGRPCLB{AddrType: GRPCLB, ServerName: s.Target}}
233                 }
234         }
235         return newAddrs
236 }
237
238 func (w *dnsWatcher) lookupHost() map[string]*Update {
239         newAddrs := make(map[string]*Update)
240         addrs, err := lookupHost(w.ctx, w.host)
241         if err != nil {
242                 grpclog.Warningf("grpc: failed dns A record lookup due to %v.\n", err)
243                 return nil
244         }
245         for _, a := range addrs {
246                 a, ok := formatIP(a)
247                 if !ok {
248                         grpclog.Errorf("grpc: failed IP parsing due to %v.\n", err)
249                         continue
250                 }
251                 addr := a + ":" + w.port
252                 newAddrs[addr] = &Update{Addr: addr}
253         }
254         return newAddrs
255 }
256
257 func (w *dnsWatcher) lookup() []*Update {
258         newAddrs := w.lookupSRV()
259         if newAddrs == nil {
260                 // If failed to get any balancer address (either no corresponding SRV for the
261                 // target, or caused by failure during resolution/parsing of the balancer target),
262                 // return any A record info available.
263                 newAddrs = w.lookupHost()
264         }
265         result := w.compileUpdate(newAddrs)
266         w.curAddrs = newAddrs
267         return result
268 }
269
270 // Next returns the resolved address update(delta) for the target. If there's no
271 // change, it will sleep for 30 mins and try to resolve again after that.
272 func (w *dnsWatcher) Next() ([]*Update, error) {
273         for {
274                 select {
275                 case <-w.ctx.Done():
276                         return nil, errWatcherClose
277                 case <-w.t.C:
278                 }
279                 result := w.lookup()
280                 // Next lookup should happen after an interval defined by w.r.freq.
281                 w.t.Reset(w.r.freq)
282                 if len(result) > 0 {
283                         return result, nil
284                 }
285         }
286 }
287
288 func (w *dnsWatcher) Close() {
289         w.cancel()
290 }