]> Cypherpunks repositories - gostls13.git/commitdiff
net: clean up cgo
authorMikio Hara <mikioh.mikioh@gmail.com>
Fri, 17 Apr 2015 08:56:58 +0000 (17:56 +0900)
committerMikio Hara <mikioh.mikioh@gmail.com>
Fri, 17 Apr 2015 23:19:19 +0000 (23:19 +0000)
This change adds a type addrinfoErrno to represent getaddrinfo,
getnameinfo-specific errors, and uses it in cgo-based lookup functions.

Also retags cgo files for clarification and does minor cleanup.

Change-Id: I6db7130ad7bf35bbd4e8839a97759e1364c43828
Reviewed-on: https://go-review.googlesource.com/9020
Reviewed-by: Ian Lance Taylor <iant@golang.org>
src/net/cgo_android.go
src/net/cgo_bsd.go
src/net/cgo_linux.go
src/net/cgo_netbsd.go
src/net/cgo_openbsd.go
src/net/cgo_stub.go
src/net/cgo_unix.go
src/net/cgo_windows.go [new file with mode: 0644]
src/net/error_test.go

index 3819ce56a4fa0409c539c8ee5c71fc151307b7e4..fe9925b840a4e19a1bcf69fa2472aac9b227b5cd 100644 (file)
@@ -9,6 +9,4 @@ package net
 //#include <netdb.h>
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-       return C.AI_CANONNAME
-}
+const cgoAddrInfoFlags = C.AI_CANONNAME
index 388eab4fe1a0f7faec1dc6d9ffc017fa80a6c2bb..c5ec9dd9c858d50dcf37d0cc2cd7a42c6b72cdf5 100644 (file)
@@ -2,7 +2,7 @@
 // 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
 
 package net
@@ -12,6 +12,4 @@ package net
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-       return (C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL) & C.AI_MASK
-}
+const cgoAddrInfoFlags = (C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL) & C.AI_MASK
index 4ef2d0cd12c91d537be8321ab2ef0d98b37f513b..9a5f898c267b57a2f6c8364d31322eee5c8f1189 100644 (file)
@@ -11,12 +11,10 @@ package net
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-       // NOTE(rsc): In theory there are approximately balanced
-       // arguments for and against including AI_ADDRCONFIG
-       // in the flags (it includes IPv4 results only on IPv4 systems,
-       // and similarly for IPv6), but in practice setting it causes
-       // getaddrinfo to return the wrong canonical name on Linux.
-       // So definitely leave it out.
-       return C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
-}
+// NOTE(rsc): In theory there are approximately balanced
+// arguments for and against including AI_ADDRCONFIG
+// in the flags (it includes IPv4 results only on IPv4 systems,
+// and similarly for IPv6), but in practice setting it causes
+// getaddrinfo to return the wrong canonical name on Linux.
+// So definitely leave it out.
+const cgoAddrInfoFlags = C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
index 09c5ad2d9fde595bd5a3dbdef199d98d356bf8a3..183091366cbed7750122050b7a4241f5c62a9f57 100644 (file)
@@ -11,6 +11,4 @@ package net
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-       return C.AI_CANONNAME
-}
+const cgoAddrInfoFlags = C.AI_CANONNAME
index 09c5ad2d9fde595bd5a3dbdef199d98d356bf8a3..183091366cbed7750122050b7a4241f5c62a9f57 100644 (file)
@@ -11,6 +11,4 @@ package net
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-       return C.AI_CANONNAME
-}
+const cgoAddrInfoFlags = C.AI_CANONNAME
index d2d40da74f14fc9201f01d9704111e1afb37b225..c4937efde2a6736843ef8c02e2a1976762c121cf 100644 (file)
@@ -4,10 +4,14 @@
 
 // +build !cgo netgo
 
-// Stub cgo routines for systems that do not use cgo to do network lookups.
-
 package net
 
+type addrinfoErrno int
+
+func (eai addrinfoErrno) Error() string   { return "<nil>" }
+func (eai addrinfoErrno) Temporary() bool { return false }
+func (eai addrinfoErrno) Timeout() bool   { return false }
+
 func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
        return nil, nil, false
 }
index eba57773479321a8b5532ae4104d9b830cfa7765..38c3d70d55699a94a7beff496d7ce66d1ff018c0 100644 (file)
@@ -2,7 +2,7 @@
 // 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
@@ -23,24 +23,30 @@ import (
        "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
@@ -48,10 +54,10 @@ func cgoLookupPort(net, service string) (port int, err error, completed bool) {
                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':
@@ -60,45 +66,53 @@ func cgoLookupPort(net, service string) (port int, err error, completed bool) {
        }
 
        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.
@@ -110,12 +124,15 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, com
                                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 == "" {
@@ -131,8 +148,6 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, com
                        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[:])}
diff --git a/src/net/cgo_windows.go b/src/net/cgo_windows.go
new file mode 100644 (file)
index 0000000..8968b75
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2015 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 cgo,!netgo
+
+package net
+
+type addrinfoErrno int
+
+func (eai addrinfoErrno) Error() string   { return "<nil>" }
+func (eai addrinfoErrno) Temporary() bool { return false }
+func (eai addrinfoErrno) Timeout() bool   { return false }
index 642790e68b8dad179cce44966d3bdd3afeab0bdd..8448eb1c392bcd620ffcb1a6999c707fa514d13d 100644 (file)
@@ -84,7 +84,7 @@ second:
                return nil
        }
        switch err := nestedErr.(type) {
-       case *AddrError, *DNSError, InvalidAddrError, *ParseError, UnknownNetworkError, *timeoutError:
+       case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
                return nil
        case *DNSConfigError:
                nestedErr = err.Err