summaryrefslogtreecommitdiff
path: root/vendor/github.com/pion/transport/vnet/resolver.go
blob: e5166e3cd8c049eff0f158ce849051ac9a99bacc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package vnet

import (
	"errors"
	"fmt"
	"net"
	"sync"

	"github.com/pion/logging"
)

var (
	errHostnameEmpty       = errors.New("host name must not be empty")
	errFailedtoParseIPAddr = errors.New("failed to parse IP address")
)

type resolverConfig struct {
	LoggerFactory logging.LoggerFactory
}

type resolver struct {
	parent *resolver             // read-only
	hosts  map[string]net.IP     // requires mutex
	mutex  sync.RWMutex          // thread-safe
	log    logging.LeveledLogger // read-only
}

func newResolver(config *resolverConfig) *resolver {
	r := &resolver{
		hosts: map[string]net.IP{},
		log:   config.LoggerFactory.NewLogger("vnet"),
	}

	if err := r.addHost("localhost", "127.0.0.1"); err != nil {
		r.log.Warn("failed to add localhost to resolver")
	}
	return r
}

func (r *resolver) setParent(parent *resolver) {
	r.mutex.Lock()
	defer r.mutex.Unlock()

	r.parent = parent
}

func (r *resolver) addHost(name string, ipAddr string) error {
	r.mutex.Lock()
	defer r.mutex.Unlock()

	if len(name) == 0 {
		return errHostnameEmpty
	}
	ip := net.ParseIP(ipAddr)
	if ip == nil {
		return fmt.Errorf("%w \"%s\"", errFailedtoParseIPAddr, ipAddr)
	}
	r.hosts[name] = ip
	return nil
}

func (r *resolver) lookUp(hostName string) (net.IP, error) {
	ip := func() net.IP {
		r.mutex.RLock()
		defer r.mutex.RUnlock()

		if ip2, ok := r.hosts[hostName]; ok {
			return ip2
		}
		return nil
	}()
	if ip != nil {
		return ip, nil
	}

	// mutex must be unlocked before calling into parent resolver

	if r.parent != nil {
		return r.parent.lookUp(hostName)
	}

	return nil, &net.DNSError{
		Err:         "host not found",
		Name:        hostName,
		Server:      "vnet resolver",
		IsTimeout:   false,
		IsTemporary: false,
	}
}