// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris

package net

import (
	
	
	
	

	
)

var onceReadProtocols sync.Once

// readProtocols loads contents of /etc/protocols into protocols map
// for quick access.
func readProtocols() {
	,  := open("/etc/protocols")
	if  != nil {
		return
	}
	defer .close()

	for ,  := .readLine(); ; ,  = .readLine() {
		// tcp    6   TCP    # transmission control protocol
		if  := bytealg.IndexByteString(, '#');  >= 0 {
			 = [0:]
		}
		 := getFields()
		if len() < 2 {
			continue
		}
		if , ,  := dtoi([1]);  {
			if ,  := protocols[[0]]; ! {
				protocols[[0]] = 
			}
			for ,  := range [2:] {
				if ,  := protocols[]; ! {
					protocols[] = 
				}
			}
		}
	}
}

// lookupProtocol looks up IP protocol name in /etc/protocols and
// returns correspondent protocol number.
func lookupProtocol( context.Context,  string) (int, error) {
	onceReadProtocols.Do(readProtocols)
	return lookupProtocolMap()
}

func ( *Resolver) ( context.Context, ,  string) (Conn, error) {
	// Calling Dial here is scary -- we have to be sure not to
	// dial a name that will require a DNS lookup, or Dial will
	// call back here to translate it. The DNS config parser has
	// already checked that all the cfg.servers are IP
	// addresses, which Dial will use without a DNS lookup.
	var  Conn
	var  error
	if  != nil && .Dial != nil {
		,  = .Dial(, , )
	} else {
		var  Dialer
		,  = .DialContext(, , )
	}
	if  != nil {
		return nil, mapErr()
	}
	return , nil
}

func ( *Resolver) ( context.Context,  string) ( []string,  error) {
	 := systemConf().hostLookupOrder(, )
	if !.preferGo() &&  == hostLookupCgo {
		if , ,  := cgoLookupHost(, );  {
			return , 
		}
		// cgo not available (or netgo); fall back to Go's DNS resolver
		 = hostLookupFilesDNS
	}
	return .goLookupHostOrder(, , )
}

func ( *Resolver) ( context.Context, ,  string) ( []IPAddr,  error) {
	if .preferGo() {
		return .goLookupIP(, )
	}
	 := systemConf().hostLookupOrder(, )
	if  == hostLookupCgo {
		if , ,  := cgoLookupIP(, , );  {
			return , 
		}
		// cgo not available (or netgo); fall back to Go's DNS resolver
		 = hostLookupFilesDNS
	}
	, ,  := .goLookupIPCNAMEOrder(, , )
	return , 
}

func ( *Resolver) ( context.Context, ,  string) (int, error) {
	if !.preferGo() && systemConf().canUseCgo() {
		if , ,  := cgoLookupPort(, , );  {
			if  != nil {
				// Issue 18213: if cgo fails, first check to see whether we
				// have the answer baked-in to the net package.
				if ,  := goLookupPort(, );  == nil {
					return , nil
				}
			}
			return , 
		}
	}
	return goLookupPort(, )
}

func ( *Resolver) ( context.Context,  string) (string, error) {
	if !.preferGo() && systemConf().canUseCgo() {
		if , ,  := cgoLookupCNAME(, );  {
			return , 
		}
	}
	return .goLookupCNAME(, )
}

func ( *Resolver) ( context.Context, , ,  string) (string, []*SRV, error) {
	var  string
	if  == "" &&  == "" {
		 = 
	} else {
		 = "_" +  + "._" +  + "." + 
	}
	, ,  := .lookup(, , dnsmessage.TypeSRV)
	if  != nil {
		return "", nil, 
	}
	var  []*SRV
	var  dnsmessage.Name
	for {
		,  := .AnswerHeader()
		if  == dnsmessage.ErrSectionDone {
			break
		}
		if  != nil {
			return "", nil, &DNSError{
				Err:    "cannot unmarshal DNS message",
				Name:   ,
				Server: ,
			}
		}
		if .Type != dnsmessage.TypeSRV {
			if  := .SkipAnswer();  != nil {
				return "", nil, &DNSError{
					Err:    "cannot unmarshal DNS message",
					Name:   ,
					Server: ,
				}
			}
			continue
		}
		if .Length == 0 && .Name.Length != 0 {
			 = .Name
		}
		,  := .SRVResource()
		if  != nil {
			return "", nil, &DNSError{
				Err:    "cannot unmarshal DNS message",
				Name:   ,
				Server: ,
			}
		}
		 = append(, &SRV{Target: .Target.String(), Port: .Port, Priority: .Priority, Weight: .Weight})
	}
	byPriorityWeight().sort()
	return .String(), , nil
}

func ( *Resolver) ( context.Context,  string) ([]*MX, error) {
	, ,  := .lookup(, , dnsmessage.TypeMX)
	if  != nil {
		return nil, 
	}
	var  []*MX
	for {
		,  := .AnswerHeader()
		if  == dnsmessage.ErrSectionDone {
			break
		}
		if  != nil {
			return nil, &DNSError{
				Err:    "cannot unmarshal DNS message",
				Name:   ,
				Server: ,
			}
		}
		if .Type != dnsmessage.TypeMX {
			if  := .SkipAnswer();  != nil {
				return nil, &DNSError{
					Err:    "cannot unmarshal DNS message",
					Name:   ,
					Server: ,
				}
			}
			continue
		}
		,  := .MXResource()
		if  != nil {
			return nil, &DNSError{
				Err:    "cannot unmarshal DNS message",
				Name:   ,
				Server: ,
			}
		}
		 = append(, &MX{Host: .MX.String(), Pref: .Pref})

	}
	byPref().sort()
	return , nil
}

func ( *Resolver) ( context.Context,  string) ([]*NS, error) {
	, ,  := .lookup(, , dnsmessage.TypeNS)
	if  != nil {
		return nil, 
	}
	var  []*NS
	for {
		,  := .AnswerHeader()
		if  == dnsmessage.ErrSectionDone {
			break
		}
		if  != nil {
			return nil, &DNSError{
				Err:    "cannot unmarshal DNS message",
				Name:   ,
				Server: ,
			}
		}
		if .Type != dnsmessage.TypeNS {
			if  := .SkipAnswer();  != nil {
				return nil, &DNSError{
					Err:    "cannot unmarshal DNS message",
					Name:   ,
					Server: ,
				}
			}
			continue
		}
		,  := .NSResource()
		if  != nil {
			return nil, &DNSError{
				Err:    "cannot unmarshal DNS message",
				Name:   ,
				Server: ,
			}
		}
		 = append(, &NS{Host: .NS.String()})
	}
	return , nil
}

func ( *Resolver) ( context.Context,  string) ([]string, error) {
	, ,  := .lookup(, , dnsmessage.TypeTXT)
	if  != nil {
		return nil, 
	}
	var  []string
	for {
		,  := .AnswerHeader()
		if  == dnsmessage.ErrSectionDone {
			break
		}
		if  != nil {
			return nil, &DNSError{
				Err:    "cannot unmarshal DNS message",
				Name:   ,
				Server: ,
			}
		}
		if .Type != dnsmessage.TypeTXT {
			if  := .SkipAnswer();  != nil {
				return nil, &DNSError{
					Err:    "cannot unmarshal DNS message",
					Name:   ,
					Server: ,
				}
			}
			continue
		}
		,  := .TXTResource()
		if  != nil {
			return nil, &DNSError{
				Err:    "cannot unmarshal DNS message",
				Name:   ,
				Server: ,
			}
		}
		// Multiple strings in one TXT record need to be
		// concatenated without separator to be consistent
		// with previous Go resolver.
		 := 0
		for ,  := range .TXT {
			 += len()
		}
		 := make([]byte, 0, )
		for ,  := range .TXT {
			 = append(, ...)
		}
		if len() == 0 {
			 = make([]string, 0, 1)
		}
		 = append(, string())
	}
	return , nil
}

func ( *Resolver) ( context.Context,  string) ([]string, error) {
	if !.preferGo() && systemConf().canUseCgo() {
		if , ,  := cgoLookupPTR(, );  {
			return , 
		}
	}
	return .goLookupPTR(, )
}

// concurrentThreadsLimit returns the number of threads we permit to
// run concurrently doing DNS lookups via cgo. A DNS lookup may use a
// file descriptor so we limit this to less than the number of
// permitted open files. On some systems, notably Darwin, if
// getaddrinfo is unable to open a file descriptor it simply returns
// EAI_NONAME rather than a useful error. Limiting the number of
// concurrent getaddrinfo calls to less than the permitted number of
// file descriptors makes that error less likely. We don't bother to
// apply the same limit to DNS lookups run directly from Go, because
// there we will return a meaningful "too many open files" error.
func concurrentThreadsLimit() int {
	var  syscall.Rlimit
	if  := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &);  != nil {
		return 500
	}
	 := int(.Cur)
	if  > 500 {
		 = 500
	} else if  > 30 {
		 -= 30
	}
	return 
}