// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !netgo
+// +build cgo,!netgo
// +build darwin dragonfly freebsd linux netbsd openbsd
package net
"unsafe"
)
-func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
- ip, err, completed := cgoLookupIP(name)
- for _, p := range ip {
- addrs = append(addrs, p.String())
+// An addrinfoErrno represents a getaddrinfo, getnameinfo-specific
+// error number. It's a signed number and a zero value is a non-error
+// by convention.
+type addrinfoErrno int
+
+func (eai addrinfoErrno) Error() string { return C.GoString(C.gai_strerror(C.int(eai))) }
+func (eai addrinfoErrno) Temporary() bool { return eai == C.EAI_AGAIN }
+func (eai addrinfoErrno) Timeout() bool { return false }
+
+func cgoLookupHost(name string) (hosts []string, err error, completed bool) {
+ addrs, err, completed := cgoLookupIP(name)
+ for _, addr := range addrs {
+ hosts = append(hosts, addr.String())
}
return
}
-func cgoLookupPort(net, service string) (port int, err error, completed bool) {
+func cgoLookupPort(network, service string) (port int, err error, completed bool) {
acquireThread()
defer releaseThread()
- var res *C.struct_addrinfo
var hints C.struct_addrinfo
-
- switch net {
- case "":
- // no hints
+ switch network {
+ case "": // no hints
case "tcp", "tcp4", "tcp6":
hints.ai_socktype = C.SOCK_STREAM
hints.ai_protocol = C.IPPROTO_TCP
hints.ai_socktype = C.SOCK_DGRAM
hints.ai_protocol = C.IPPROTO_UDP
default:
- return 0, UnknownNetworkError(net), true
+ return 0, UnknownNetworkError(network), true
}
- if len(net) >= 4 {
- switch net[3] {
+ if len(network) >= 4 {
+ switch network[3] {
case '4':
hints.ai_family = C.AF_INET
case '6':
}
s := C.CString(service)
+ var res *C.struct_addrinfo
defer C.free(unsafe.Pointer(s))
- if C.getaddrinfo(nil, s, &hints, &res) == 0 {
- defer C.freeaddrinfo(res)
- for r := res; r != nil; r = r.ai_next {
- switch r.ai_family {
- default:
- continue
- case C.AF_INET:
- sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
- p := (*[2]byte)(unsafe.Pointer(&sa.Port))
- return int(p[0])<<8 | int(p[1]), nil, true
- case C.AF_INET6:
- sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
- p := (*[2]byte)(unsafe.Pointer(&sa.Port))
- return int(p[0])<<8 | int(p[1]), nil, true
+ gerrno, err := C.getaddrinfo(nil, s, &hints, &res)
+ if gerrno != 0 {
+ switch gerrno {
+ case C.EAI_SYSTEM:
+ if err == nil { // see golang.org/issue/6232
+ err = syscall.EMFILE
}
+ default:
+ err = addrinfoErrno(gerrno)
}
+ return 0, err, true
}
- return 0, &AddrError{"unknown port", net + "/" + service}, true
+ defer C.freeaddrinfo(res)
+
+ for r := res; r != nil; r = r.ai_next {
+ switch r.ai_family {
+ case C.AF_INET:
+ sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
+ p := (*[2]byte)(unsafe.Pointer(&sa.Port))
+ return int(p[0])<<8 | int(p[1]), nil, true
+ case C.AF_INET6:
+ sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
+ p := (*[2]byte)(unsafe.Pointer(&sa.Port))
+ return int(p[0])<<8 | int(p[1]), nil, true
+ }
+ }
+ return 0, &AddrError{"unknown port", network + "/" + service}, true
}
func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, completed bool) {
acquireThread()
defer releaseThread()
- var res *C.struct_addrinfo
var hints C.struct_addrinfo
-
- hints.ai_flags = cgoAddrInfoFlags()
+ hints.ai_flags = cgoAddrInfoFlags
hints.ai_socktype = C.SOCK_STREAM
h := C.CString(name)
defer C.free(unsafe.Pointer(h))
+ var res *C.struct_addrinfo
gerrno, err := C.getaddrinfo(h, nil, &hints, &res)
if gerrno != 0 {
var str string
- if gerrno == C.EAI_NONAME {
- str = noSuchHost
- } else if gerrno == C.EAI_SYSTEM {
+ switch gerrno {
+ case C.EAI_SYSTEM:
if err == nil {
// err should not be nil, but sometimes getaddrinfo returns
// gerrno == C.EAI_SYSTEM with err == nil on Linux.
err = syscall.EMFILE
}
str = err.Error()
- } else {
- str = C.GoString(C.gai_strerror(gerrno))
+ case C.EAI_NONAME:
+ str = noSuchHost
+ default:
+ str = addrinfoErrno(gerrno).Error()
}
return nil, "", &DNSError{Err: str, Name: name}, true
}
defer C.freeaddrinfo(res)
+
if res != nil {
cname = C.GoString(res.ai_canonname)
if cname == "" {
continue
}
switch r.ai_family {
- default:
- continue
case C.AF_INET:
sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
addr := IPAddr{IP: copyIP(sa.Addr[:])}