mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 02:02:25 -05:00 
			
		
		
		
	feat: initial tracing support (#1623)
This commit is contained in:
		
					parent
					
						
							
								878ed48de3
							
						
					
				
			
			
				commit
				
					
						6392e00653
					
				
			
		
					 472 changed files with 102600 additions and 12 deletions
				
			
		
							
								
								
									
										167
									
								
								vendor/google.golang.org/grpc/internal/resolver/config_selector.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								vendor/google.golang.org/grpc/internal/resolver/config_selector.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,167 @@ | |||
| /* | ||||
|  * | ||||
|  * Copyright 2020 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| // Package resolver provides internal resolver-related functionality. | ||||
| package resolver | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"sync" | ||||
| 
 | ||||
| 	"google.golang.org/grpc/internal/serviceconfig" | ||||
| 	"google.golang.org/grpc/metadata" | ||||
| 	"google.golang.org/grpc/resolver" | ||||
| ) | ||||
| 
 | ||||
| // ConfigSelector controls what configuration to use for every RPC. | ||||
| type ConfigSelector interface { | ||||
| 	// Selects the configuration for the RPC, or terminates it using the error. | ||||
| 	// This error will be converted by the gRPC library to a status error with | ||||
| 	// code UNKNOWN if it is not returned as a status error. | ||||
| 	SelectConfig(RPCInfo) (*RPCConfig, error) | ||||
| } | ||||
| 
 | ||||
| // RPCInfo contains RPC information needed by a ConfigSelector. | ||||
| type RPCInfo struct { | ||||
| 	// Context is the user's context for the RPC and contains headers and | ||||
| 	// application timeout.  It is passed for interception purposes and for | ||||
| 	// efficiency reasons.  SelectConfig should not be blocking. | ||||
| 	Context context.Context | ||||
| 	Method  string // i.e. "/Service/Method" | ||||
| } | ||||
| 
 | ||||
| // RPCConfig describes the configuration to use for each RPC. | ||||
| type RPCConfig struct { | ||||
| 	// The context to use for the remainder of the RPC; can pass info to LB | ||||
| 	// policy or affect timeout or metadata. | ||||
| 	Context      context.Context | ||||
| 	MethodConfig serviceconfig.MethodConfig // configuration to use for this RPC | ||||
| 	OnCommitted  func()                     // Called when the RPC has been committed (retries no longer possible) | ||||
| 	Interceptor  ClientInterceptor | ||||
| } | ||||
| 
 | ||||
| // ClientStream is the same as grpc.ClientStream, but defined here for circular | ||||
| // dependency reasons. | ||||
| type ClientStream interface { | ||||
| 	// Header returns the header metadata received from the server if there | ||||
| 	// is any. It blocks if the metadata is not ready to read. | ||||
| 	Header() (metadata.MD, error) | ||||
| 	// Trailer returns the trailer metadata from the server, if there is any. | ||||
| 	// It must only be called after stream.CloseAndRecv has returned, or | ||||
| 	// stream.Recv has returned a non-nil error (including io.EOF). | ||||
| 	Trailer() metadata.MD | ||||
| 	// CloseSend closes the send direction of the stream. It closes the stream | ||||
| 	// when non-nil error is met. It is also not safe to call CloseSend | ||||
| 	// concurrently with SendMsg. | ||||
| 	CloseSend() error | ||||
| 	// Context returns the context for this stream. | ||||
| 	// | ||||
| 	// It should not be called until after Header or RecvMsg has returned. Once | ||||
| 	// called, subsequent client-side retries are disabled. | ||||
| 	Context() context.Context | ||||
| 	// SendMsg is generally called by generated code. On error, SendMsg aborts | ||||
| 	// the stream. If the error was generated by the client, the status is | ||||
| 	// returned directly; otherwise, io.EOF is returned and the status of | ||||
| 	// the stream may be discovered using RecvMsg. | ||||
| 	// | ||||
| 	// SendMsg blocks until: | ||||
| 	//   - There is sufficient flow control to schedule m with the transport, or | ||||
| 	//   - The stream is done, or | ||||
| 	//   - The stream breaks. | ||||
| 	// | ||||
| 	// SendMsg does not wait until the message is received by the server. An | ||||
| 	// untimely stream closure may result in lost messages. To ensure delivery, | ||||
| 	// users should ensure the RPC completed successfully using RecvMsg. | ||||
| 	// | ||||
| 	// It is safe to have a goroutine calling SendMsg and another goroutine | ||||
| 	// calling RecvMsg on the same stream at the same time, but it is not safe | ||||
| 	// to call SendMsg on the same stream in different goroutines. It is also | ||||
| 	// not safe to call CloseSend concurrently with SendMsg. | ||||
| 	SendMsg(m interface{}) error | ||||
| 	// RecvMsg blocks until it receives a message into m or the stream is | ||||
| 	// done. It returns io.EOF when the stream completes successfully. On | ||||
| 	// any other error, the stream is aborted and the error contains the RPC | ||||
| 	// status. | ||||
| 	// | ||||
| 	// It is safe to have a goroutine calling SendMsg and another goroutine | ||||
| 	// calling RecvMsg on the same stream at the same time, but it is not | ||||
| 	// safe to call RecvMsg on the same stream in different goroutines. | ||||
| 	RecvMsg(m interface{}) error | ||||
| } | ||||
| 
 | ||||
| // ClientInterceptor is an interceptor for gRPC client streams. | ||||
| type ClientInterceptor interface { | ||||
| 	// NewStream produces a ClientStream for an RPC which may optionally use | ||||
| 	// the provided function to produce a stream for delegation.  Note: | ||||
| 	// RPCInfo.Context should not be used (will be nil). | ||||
| 	// | ||||
| 	// done is invoked when the RPC is finished using its connection, or could | ||||
| 	// not be assigned a connection.  RPC operations may still occur on | ||||
| 	// ClientStream after done is called, since the interceptor is invoked by | ||||
| 	// application-layer operations.  done must never be nil when called. | ||||
| 	NewStream(ctx context.Context, ri RPCInfo, done func(), newStream func(ctx context.Context, done func()) (ClientStream, error)) (ClientStream, error) | ||||
| } | ||||
| 
 | ||||
| // ServerInterceptor is an interceptor for incoming RPC's on gRPC server side. | ||||
| type ServerInterceptor interface { | ||||
| 	// AllowRPC checks if an incoming RPC is allowed to proceed based on | ||||
| 	// information about connection RPC was received on, and HTTP Headers. This | ||||
| 	// information will be piped into context. | ||||
| 	AllowRPC(ctx context.Context) error // TODO: Make this a real interceptor for filters such as rate limiting. | ||||
| } | ||||
| 
 | ||||
| type csKeyType string | ||||
| 
 | ||||
| const csKey = csKeyType("grpc.internal.resolver.configSelector") | ||||
| 
 | ||||
| // SetConfigSelector sets the config selector in state and returns the new | ||||
| // state. | ||||
| func SetConfigSelector(state resolver.State, cs ConfigSelector) resolver.State { | ||||
| 	state.Attributes = state.Attributes.WithValue(csKey, cs) | ||||
| 	return state | ||||
| } | ||||
| 
 | ||||
| // GetConfigSelector retrieves the config selector from state, if present, and | ||||
| // returns it or nil if absent. | ||||
| func GetConfigSelector(state resolver.State) ConfigSelector { | ||||
| 	cs, _ := state.Attributes.Value(csKey).(ConfigSelector) | ||||
| 	return cs | ||||
| } | ||||
| 
 | ||||
| // SafeConfigSelector allows for safe switching of ConfigSelector | ||||
| // implementations such that previous values are guaranteed to not be in use | ||||
| // when UpdateConfigSelector returns. | ||||
| type SafeConfigSelector struct { | ||||
| 	mu sync.RWMutex | ||||
| 	cs ConfigSelector | ||||
| } | ||||
| 
 | ||||
| // UpdateConfigSelector swaps to the provided ConfigSelector and blocks until | ||||
| // all uses of the previous ConfigSelector have completed. | ||||
| func (scs *SafeConfigSelector) UpdateConfigSelector(cs ConfigSelector) { | ||||
| 	scs.mu.Lock() | ||||
| 	defer scs.mu.Unlock() | ||||
| 	scs.cs = cs | ||||
| } | ||||
| 
 | ||||
| // SelectConfig defers to the current ConfigSelector in scs. | ||||
| func (scs *SafeConfigSelector) SelectConfig(r RPCInfo) (*RPCConfig, error) { | ||||
| 	scs.mu.RLock() | ||||
| 	defer scs.mu.RUnlock() | ||||
| 	return scs.cs.SelectConfig(r) | ||||
| } | ||||
							
								
								
									
										458
									
								
								vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										458
									
								
								vendor/google.golang.org/grpc/internal/resolver/dns/dns_resolver.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,458 @@ | |||
| /* | ||||
|  * | ||||
|  * Copyright 2018 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| // Package dns implements a dns resolver to be installed as the default resolver | ||||
| // in grpc. | ||||
| package dns | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
| 
 | ||||
| 	grpclbstate "google.golang.org/grpc/balancer/grpclb/state" | ||||
| 	"google.golang.org/grpc/grpclog" | ||||
| 	"google.golang.org/grpc/internal/backoff" | ||||
| 	"google.golang.org/grpc/internal/envconfig" | ||||
| 	"google.golang.org/grpc/internal/grpcrand" | ||||
| 	"google.golang.org/grpc/resolver" | ||||
| 	"google.golang.org/grpc/serviceconfig" | ||||
| ) | ||||
| 
 | ||||
| // EnableSRVLookups controls whether the DNS resolver attempts to fetch gRPCLB | ||||
| // addresses from SRV records.  Must not be changed after init time. | ||||
| var EnableSRVLookups = false | ||||
| 
 | ||||
| var logger = grpclog.Component("dns") | ||||
| 
 | ||||
| // Globals to stub out in tests. TODO: Perhaps these two can be combined into a | ||||
| // single variable for testing the resolver? | ||||
| var ( | ||||
| 	newTimer           = time.NewTimer | ||||
| 	newTimerDNSResRate = time.NewTimer | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	resolver.Register(NewBuilder()) | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
| 	defaultPort       = "443" | ||||
| 	defaultDNSSvrPort = "53" | ||||
| 	golang            = "GO" | ||||
| 	// txtPrefix is the prefix string to be prepended to the host name for txt record lookup. | ||||
| 	txtPrefix = "_grpc_config." | ||||
| 	// In DNS, service config is encoded in a TXT record via the mechanism | ||||
| 	// described in RFC-1464 using the attribute name grpc_config. | ||||
| 	txtAttribute = "grpc_config=" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	errMissingAddr = errors.New("dns resolver: missing address") | ||||
| 
 | ||||
| 	// Addresses ending with a colon that is supposed to be the separator | ||||
| 	// between host and port is not allowed.  E.g. "::" is a valid address as | ||||
| 	// it is an IPv6 address (host only) and "[::]:" is invalid as it ends with | ||||
| 	// a colon as the host and port separator | ||||
| 	errEndsWithColon = errors.New("dns resolver: missing port after port-separator colon") | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	defaultResolver netResolver = net.DefaultResolver | ||||
| 	// To prevent excessive re-resolution, we enforce a rate limit on DNS | ||||
| 	// resolution requests. | ||||
| 	minDNSResRate = 30 * time.Second | ||||
| ) | ||||
| 
 | ||||
| var customAuthorityDialler = func(authority string) func(ctx context.Context, network, address string) (net.Conn, error) { | ||||
| 	return func(ctx context.Context, network, address string) (net.Conn, error) { | ||||
| 		var dialer net.Dialer | ||||
| 		return dialer.DialContext(ctx, network, authority) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var customAuthorityResolver = func(authority string) (netResolver, error) { | ||||
| 	host, port, err := parseTarget(authority, defaultDNSSvrPort) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	authorityWithPort := net.JoinHostPort(host, port) | ||||
| 
 | ||||
| 	return &net.Resolver{ | ||||
| 		PreferGo: true, | ||||
| 		Dial:     customAuthorityDialler(authorityWithPort), | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // NewBuilder creates a dnsBuilder which is used to factory DNS resolvers. | ||||
| func NewBuilder() resolver.Builder { | ||||
| 	return &dnsBuilder{} | ||||
| } | ||||
| 
 | ||||
| type dnsBuilder struct{} | ||||
| 
 | ||||
| // Build creates and starts a DNS resolver that watches the name resolution of the target. | ||||
| func (b *dnsBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) { | ||||
| 	host, port, err := parseTarget(target.Endpoint(), defaultPort) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	// IP address. | ||||
| 	if ipAddr, ok := formatIP(host); ok { | ||||
| 		addr := []resolver.Address{{Addr: ipAddr + ":" + port}} | ||||
| 		cc.UpdateState(resolver.State{Addresses: addr}) | ||||
| 		return deadResolver{}, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// DNS address (non-IP). | ||||
| 	ctx, cancel := context.WithCancel(context.Background()) | ||||
| 	d := &dnsResolver{ | ||||
| 		host:                 host, | ||||
| 		port:                 port, | ||||
| 		ctx:                  ctx, | ||||
| 		cancel:               cancel, | ||||
| 		cc:                   cc, | ||||
| 		rn:                   make(chan struct{}, 1), | ||||
| 		disableServiceConfig: opts.DisableServiceConfig, | ||||
| 	} | ||||
| 
 | ||||
| 	if target.URL.Host == "" { | ||||
| 		d.resolver = defaultResolver | ||||
| 	} else { | ||||
| 		d.resolver, err = customAuthorityResolver(target.URL.Host) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	d.wg.Add(1) | ||||
| 	go d.watcher() | ||||
| 	return d, nil | ||||
| } | ||||
| 
 | ||||
| // Scheme returns the naming scheme of this resolver builder, which is "dns". | ||||
| func (b *dnsBuilder) Scheme() string { | ||||
| 	return "dns" | ||||
| } | ||||
| 
 | ||||
| type netResolver interface { | ||||
| 	LookupHost(ctx context.Context, host string) (addrs []string, err error) | ||||
| 	LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error) | ||||
| 	LookupTXT(ctx context.Context, name string) (txts []string, err error) | ||||
| } | ||||
| 
 | ||||
| // deadResolver is a resolver that does nothing. | ||||
| type deadResolver struct{} | ||||
| 
 | ||||
| func (deadResolver) ResolveNow(resolver.ResolveNowOptions) {} | ||||
| 
 | ||||
| func (deadResolver) Close() {} | ||||
| 
 | ||||
| // dnsResolver watches for the name resolution update for a non-IP target. | ||||
| type dnsResolver struct { | ||||
| 	host     string | ||||
| 	port     string | ||||
| 	resolver netResolver | ||||
| 	ctx      context.Context | ||||
| 	cancel   context.CancelFunc | ||||
| 	cc       resolver.ClientConn | ||||
| 	// rn channel is used by ResolveNow() to force an immediate resolution of the target. | ||||
| 	rn chan struct{} | ||||
| 	// wg is used to enforce Close() to return after the watcher() goroutine has finished. | ||||
| 	// Otherwise, data race will be possible. [Race Example] in dns_resolver_test we | ||||
| 	// replace the real lookup functions with mocked ones to facilitate testing. | ||||
| 	// If Close() doesn't wait for watcher() goroutine finishes, race detector sometimes | ||||
| 	// will warns lookup (READ the lookup function pointers) inside watcher() goroutine | ||||
| 	// has data race with replaceNetFunc (WRITE the lookup function pointers). | ||||
| 	wg                   sync.WaitGroup | ||||
| 	disableServiceConfig bool | ||||
| } | ||||
| 
 | ||||
| // ResolveNow invoke an immediate resolution of the target that this dnsResolver watches. | ||||
| func (d *dnsResolver) ResolveNow(resolver.ResolveNowOptions) { | ||||
| 	select { | ||||
| 	case d.rn <- struct{}{}: | ||||
| 	default: | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Close closes the dnsResolver. | ||||
| func (d *dnsResolver) Close() { | ||||
| 	d.cancel() | ||||
| 	d.wg.Wait() | ||||
| } | ||||
| 
 | ||||
| func (d *dnsResolver) watcher() { | ||||
| 	defer d.wg.Done() | ||||
| 	backoffIndex := 1 | ||||
| 	for { | ||||
| 		state, err := d.lookup() | ||||
| 		if err != nil { | ||||
| 			// Report error to the underlying grpc.ClientConn. | ||||
| 			d.cc.ReportError(err) | ||||
| 		} else { | ||||
| 			err = d.cc.UpdateState(*state) | ||||
| 		} | ||||
| 
 | ||||
| 		var timer *time.Timer | ||||
| 		if err == nil { | ||||
| 			// Success resolving, wait for the next ResolveNow. However, also wait 30 seconds at the very least | ||||
| 			// to prevent constantly re-resolving. | ||||
| 			backoffIndex = 1 | ||||
| 			timer = newTimerDNSResRate(minDNSResRate) | ||||
| 			select { | ||||
| 			case <-d.ctx.Done(): | ||||
| 				timer.Stop() | ||||
| 				return | ||||
| 			case <-d.rn: | ||||
| 			} | ||||
| 		} else { | ||||
| 			// Poll on an error found in DNS Resolver or an error received from ClientConn. | ||||
| 			timer = newTimer(backoff.DefaultExponential.Backoff(backoffIndex)) | ||||
| 			backoffIndex++ | ||||
| 		} | ||||
| 		select { | ||||
| 		case <-d.ctx.Done(): | ||||
| 			timer.Stop() | ||||
| 			return | ||||
| 		case <-timer.C: | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (d *dnsResolver) lookupSRV() ([]resolver.Address, error) { | ||||
| 	if !EnableSRVLookups { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 	var newAddrs []resolver.Address | ||||
| 	_, srvs, err := d.resolver.LookupSRV(d.ctx, "grpclb", "tcp", d.host) | ||||
| 	if err != nil { | ||||
| 		err = handleDNSError(err, "SRV") // may become nil | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, s := range srvs { | ||||
| 		lbAddrs, err := d.resolver.LookupHost(d.ctx, s.Target) | ||||
| 		if err != nil { | ||||
| 			err = handleDNSError(err, "A") // may become nil | ||||
| 			if err == nil { | ||||
| 				// If there are other SRV records, look them up and ignore this | ||||
| 				// one that does not exist. | ||||
| 				continue | ||||
| 			} | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		for _, a := range lbAddrs { | ||||
| 			ip, ok := formatIP(a) | ||||
| 			if !ok { | ||||
| 				return nil, fmt.Errorf("dns: error parsing A record IP address %v", a) | ||||
| 			} | ||||
| 			addr := ip + ":" + strconv.Itoa(int(s.Port)) | ||||
| 			newAddrs = append(newAddrs, resolver.Address{Addr: addr, ServerName: s.Target}) | ||||
| 		} | ||||
| 	} | ||||
| 	return newAddrs, nil | ||||
| } | ||||
| 
 | ||||
| func handleDNSError(err error, lookupType string) error { | ||||
| 	if dnsErr, ok := err.(*net.DNSError); ok && !dnsErr.IsTimeout && !dnsErr.IsTemporary { | ||||
| 		// Timeouts and temporary errors should be communicated to gRPC to | ||||
| 		// attempt another DNS query (with backoff).  Other errors should be | ||||
| 		// suppressed (they may represent the absence of a TXT record). | ||||
| 		return nil | ||||
| 	} | ||||
| 	if err != nil { | ||||
| 		err = fmt.Errorf("dns: %v record lookup error: %v", lookupType, err) | ||||
| 		logger.Info(err) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
| 
 | ||||
| func (d *dnsResolver) lookupTXT() *serviceconfig.ParseResult { | ||||
| 	ss, err := d.resolver.LookupTXT(d.ctx, txtPrefix+d.host) | ||||
| 	if err != nil { | ||||
| 		if envconfig.TXTErrIgnore { | ||||
| 			return nil | ||||
| 		} | ||||
| 		if err = handleDNSError(err, "TXT"); err != nil { | ||||
| 			return &serviceconfig.ParseResult{Err: err} | ||||
| 		} | ||||
| 		return nil | ||||
| 	} | ||||
| 	var res string | ||||
| 	for _, s := range ss { | ||||
| 		res += s | ||||
| 	} | ||||
| 
 | ||||
| 	// TXT record must have "grpc_config=" attribute in order to be used as service config. | ||||
| 	if !strings.HasPrefix(res, txtAttribute) { | ||||
| 		logger.Warningf("dns: TXT record %v missing %v attribute", res, txtAttribute) | ||||
| 		// This is not an error; it is the equivalent of not having a service config. | ||||
| 		return nil | ||||
| 	} | ||||
| 	sc := canaryingSC(strings.TrimPrefix(res, txtAttribute)) | ||||
| 	return d.cc.ParseServiceConfig(sc) | ||||
| } | ||||
| 
 | ||||
| func (d *dnsResolver) lookupHost() ([]resolver.Address, error) { | ||||
| 	addrs, err := d.resolver.LookupHost(d.ctx, d.host) | ||||
| 	if err != nil { | ||||
| 		err = handleDNSError(err, "A") | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	newAddrs := make([]resolver.Address, 0, len(addrs)) | ||||
| 	for _, a := range addrs { | ||||
| 		ip, ok := formatIP(a) | ||||
| 		if !ok { | ||||
| 			return nil, fmt.Errorf("dns: error parsing A record IP address %v", a) | ||||
| 		} | ||||
| 		addr := ip + ":" + d.port | ||||
| 		newAddrs = append(newAddrs, resolver.Address{Addr: addr}) | ||||
| 	} | ||||
| 	return newAddrs, nil | ||||
| } | ||||
| 
 | ||||
| func (d *dnsResolver) lookup() (*resolver.State, error) { | ||||
| 	srv, srvErr := d.lookupSRV() | ||||
| 	addrs, hostErr := d.lookupHost() | ||||
| 	if hostErr != nil && (srvErr != nil || len(srv) == 0) { | ||||
| 		return nil, hostErr | ||||
| 	} | ||||
| 
 | ||||
| 	state := resolver.State{Addresses: addrs} | ||||
| 	if len(srv) > 0 { | ||||
| 		state = grpclbstate.Set(state, &grpclbstate.State{BalancerAddresses: srv}) | ||||
| 	} | ||||
| 	if !d.disableServiceConfig { | ||||
| 		state.ServiceConfig = d.lookupTXT() | ||||
| 	} | ||||
| 	return &state, nil | ||||
| } | ||||
| 
 | ||||
| // formatIP returns ok = false if addr is not a valid textual representation of an IP address. | ||||
| // If addr is an IPv4 address, return the addr and ok = true. | ||||
| // If addr is an IPv6 address, return the addr enclosed in square brackets and ok = true. | ||||
| func formatIP(addr string) (addrIP string, ok bool) { | ||||
| 	ip := net.ParseIP(addr) | ||||
| 	if ip == nil { | ||||
| 		return "", false | ||||
| 	} | ||||
| 	if ip.To4() != nil { | ||||
| 		return addr, true | ||||
| 	} | ||||
| 	return "[" + addr + "]", true | ||||
| } | ||||
| 
 | ||||
| // parseTarget takes the user input target string and default port, returns formatted host and port info. | ||||
| // If target doesn't specify a port, set the port to be the defaultPort. | ||||
| // If target is in IPv6 format and host-name is enclosed in square brackets, brackets | ||||
| // are stripped when setting the host. | ||||
| // examples: | ||||
| // target: "www.google.com" defaultPort: "443" returns host: "www.google.com", port: "443" | ||||
| // target: "ipv4-host:80" defaultPort: "443" returns host: "ipv4-host", port: "80" | ||||
| // target: "[ipv6-host]" defaultPort: "443" returns host: "ipv6-host", port: "443" | ||||
| // target: ":80" defaultPort: "443" returns host: "localhost", port: "80" | ||||
| func parseTarget(target, defaultPort string) (host, port string, err error) { | ||||
| 	if target == "" { | ||||
| 		return "", "", errMissingAddr | ||||
| 	} | ||||
| 	if ip := net.ParseIP(target); ip != nil { | ||||
| 		// target is an IPv4 or IPv6(without brackets) address | ||||
| 		return target, defaultPort, nil | ||||
| 	} | ||||
| 	if host, port, err = net.SplitHostPort(target); err == nil { | ||||
| 		if port == "" { | ||||
| 			// If the port field is empty (target ends with colon), e.g. "[::1]:", this is an error. | ||||
| 			return "", "", errEndsWithColon | ||||
| 		} | ||||
| 		// target has port, i.e ipv4-host:port, [ipv6-host]:port, host-name:port | ||||
| 		if host == "" { | ||||
| 			// Keep consistent with net.Dial(): If the host is empty, as in ":80", the local system is assumed. | ||||
| 			host = "localhost" | ||||
| 		} | ||||
| 		return host, port, nil | ||||
| 	} | ||||
| 	if host, port, err = net.SplitHostPort(target + ":" + defaultPort); err == nil { | ||||
| 		// target doesn't have port | ||||
| 		return host, port, nil | ||||
| 	} | ||||
| 	return "", "", fmt.Errorf("invalid target address %v, error info: %v", target, err) | ||||
| } | ||||
| 
 | ||||
| type rawChoice struct { | ||||
| 	ClientLanguage *[]string        `json:"clientLanguage,omitempty"` | ||||
| 	Percentage     *int             `json:"percentage,omitempty"` | ||||
| 	ClientHostName *[]string        `json:"clientHostName,omitempty"` | ||||
| 	ServiceConfig  *json.RawMessage `json:"serviceConfig,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func containsString(a *[]string, b string) bool { | ||||
| 	if a == nil { | ||||
| 		return true | ||||
| 	} | ||||
| 	for _, c := range *a { | ||||
| 		if c == b { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func chosenByPercentage(a *int) bool { | ||||
| 	if a == nil { | ||||
| 		return true | ||||
| 	} | ||||
| 	return grpcrand.Intn(100)+1 <= *a | ||||
| } | ||||
| 
 | ||||
| func canaryingSC(js string) string { | ||||
| 	if js == "" { | ||||
| 		return "" | ||||
| 	} | ||||
| 	var rcs []rawChoice | ||||
| 	err := json.Unmarshal([]byte(js), &rcs) | ||||
| 	if err != nil { | ||||
| 		logger.Warningf("dns: error parsing service config json: %v", err) | ||||
| 		return "" | ||||
| 	} | ||||
| 	cliHostname, err := os.Hostname() | ||||
| 	if err != nil { | ||||
| 		logger.Warningf("dns: error getting client hostname: %v", err) | ||||
| 		return "" | ||||
| 	} | ||||
| 	var sc string | ||||
| 	for _, c := range rcs { | ||||
| 		if !containsString(c.ClientLanguage, golang) || | ||||
| 			!chosenByPercentage(c.Percentage) || | ||||
| 			!containsString(c.ClientHostName, cliHostname) || | ||||
| 			c.ServiceConfig == nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		sc = string(*c.ServiceConfig) | ||||
| 		break | ||||
| 	} | ||||
| 	return sc | ||||
| } | ||||
							
								
								
									
										64
									
								
								vendor/google.golang.org/grpc/internal/resolver/passthrough/passthrough.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								vendor/google.golang.org/grpc/internal/resolver/passthrough/passthrough.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | |||
| /* | ||||
|  * | ||||
|  * Copyright 2017 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| // Package passthrough implements a pass-through resolver. It sends the target | ||||
| // name without scheme back to gRPC as resolved address. | ||||
| package passthrough | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 
 | ||||
| 	"google.golang.org/grpc/resolver" | ||||
| ) | ||||
| 
 | ||||
| const scheme = "passthrough" | ||||
| 
 | ||||
| type passthroughBuilder struct{} | ||||
| 
 | ||||
| func (*passthroughBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) { | ||||
| 	if target.Endpoint() == "" && opts.Dialer == nil { | ||||
| 		return nil, errors.New("passthrough: received empty target in Build()") | ||||
| 	} | ||||
| 	r := &passthroughResolver{ | ||||
| 		target: target, | ||||
| 		cc:     cc, | ||||
| 	} | ||||
| 	r.start() | ||||
| 	return r, nil | ||||
| } | ||||
| 
 | ||||
| func (*passthroughBuilder) Scheme() string { | ||||
| 	return scheme | ||||
| } | ||||
| 
 | ||||
| type passthroughResolver struct { | ||||
| 	target resolver.Target | ||||
| 	cc     resolver.ClientConn | ||||
| } | ||||
| 
 | ||||
| func (r *passthroughResolver) start() { | ||||
| 	r.cc.UpdateState(resolver.State{Addresses: []resolver.Address{{Addr: r.target.Endpoint()}}}) | ||||
| } | ||||
| 
 | ||||
| func (*passthroughResolver) ResolveNow(o resolver.ResolveNowOptions) {} | ||||
| 
 | ||||
| func (*passthroughResolver) Close() {} | ||||
| 
 | ||||
| func init() { | ||||
| 	resolver.Register(&passthroughBuilder{}) | ||||
| } | ||||
							
								
								
									
										74
									
								
								vendor/google.golang.org/grpc/internal/resolver/unix/unix.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								vendor/google.golang.org/grpc/internal/resolver/unix/unix.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,74 @@ | |||
| /* | ||||
|  * | ||||
|  * Copyright 2020 gRPC authors. | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| // Package unix implements a resolver for unix targets. | ||||
| package unix | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"google.golang.org/grpc/internal/transport/networktype" | ||||
| 	"google.golang.org/grpc/resolver" | ||||
| ) | ||||
| 
 | ||||
| const unixScheme = "unix" | ||||
| const unixAbstractScheme = "unix-abstract" | ||||
| 
 | ||||
| type builder struct { | ||||
| 	scheme string | ||||
| } | ||||
| 
 | ||||
| func (b *builder) Build(target resolver.Target, cc resolver.ClientConn, _ resolver.BuildOptions) (resolver.Resolver, error) { | ||||
| 	if target.URL.Host != "" { | ||||
| 		return nil, fmt.Errorf("invalid (non-empty) authority: %v", target.URL.Host) | ||||
| 	} | ||||
| 
 | ||||
| 	// gRPC was parsing the dial target manually before PR #4817, and we | ||||
| 	// switched to using url.Parse() in that PR. To avoid breaking existing | ||||
| 	// resolver implementations we ended up stripping the leading "/" from the | ||||
| 	// endpoint. This obviously does not work for the "unix" scheme. Hence we | ||||
| 	// end up using the parsed URL instead. | ||||
| 	endpoint := target.URL.Path | ||||
| 	if endpoint == "" { | ||||
| 		endpoint = target.URL.Opaque | ||||
| 	} | ||||
| 	addr := resolver.Address{Addr: endpoint} | ||||
| 	if b.scheme == unixAbstractScheme { | ||||
| 		// We can not prepend \0 as c++ gRPC does, as in Golang '@' is used to signify we do | ||||
| 		// not want trailing \0 in address. | ||||
| 		addr.Addr = "@" + addr.Addr | ||||
| 	} | ||||
| 	cc.UpdateState(resolver.State{Addresses: []resolver.Address{networktype.Set(addr, "unix")}}) | ||||
| 	return &nopResolver{}, nil | ||||
| } | ||||
| 
 | ||||
| func (b *builder) Scheme() string { | ||||
| 	return b.scheme | ||||
| } | ||||
| 
 | ||||
| type nopResolver struct { | ||||
| } | ||||
| 
 | ||||
| func (*nopResolver) ResolveNow(resolver.ResolveNowOptions) {} | ||||
| 
 | ||||
| func (*nopResolver) Close() {} | ||||
| 
 | ||||
| func init() { | ||||
| 	resolver.Register(&builder{scheme: unixScheme}) | ||||
| 	resolver.Register(&builder{scheme: unixAbstractScheme}) | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue