github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/net/cgo_unix.go (about) 1 // Copyright 2011 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build !netgo 6 // +build darwin dragonfly freebsd linux netbsd openbsd 7 8 package net 9 10 /* 11 #include <sys/types.h> 12 #include <sys/socket.h> 13 #include <netinet/in.h> 14 #include <netdb.h> 15 #include <stdlib.h> 16 #include <unistd.h> 17 #include <string.h> 18 */ 19 import "C" 20 21 import ( 22 "syscall" 23 "unsafe" 24 ) 25 26 func cgoLookupHost(name string) (addrs []string, err error, completed bool) { 27 ip, err, completed := cgoLookupIP(name) 28 for _, p := range ip { 29 addrs = append(addrs, p.String()) 30 } 31 return 32 } 33 34 func cgoLookupPort(net, service string) (port int, err error, completed bool) { 35 acquireThread() 36 defer releaseThread() 37 38 var res *C.struct_addrinfo 39 var hints C.struct_addrinfo 40 41 switch net { 42 case "": 43 // no hints 44 case "tcp", "tcp4", "tcp6": 45 hints.ai_socktype = C.SOCK_STREAM 46 hints.ai_protocol = C.IPPROTO_TCP 47 case "udp", "udp4", "udp6": 48 hints.ai_socktype = C.SOCK_DGRAM 49 hints.ai_protocol = C.IPPROTO_UDP 50 default: 51 return 0, UnknownNetworkError(net), true 52 } 53 if len(net) >= 4 { 54 switch net[3] { 55 case '4': 56 hints.ai_family = C.AF_INET 57 case '6': 58 hints.ai_family = C.AF_INET6 59 } 60 } 61 62 s := C.CString(service) 63 defer C.free(unsafe.Pointer(s)) 64 if C.getaddrinfo(nil, s, &hints, &res) == 0 { 65 defer C.freeaddrinfo(res) 66 for r := res; r != nil; r = r.ai_next { 67 switch r.ai_family { 68 default: 69 continue 70 case C.AF_INET: 71 sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr)) 72 p := (*[2]byte)(unsafe.Pointer(&sa.Port)) 73 return int(p[0])<<8 | int(p[1]), nil, true 74 case C.AF_INET6: 75 sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr)) 76 p := (*[2]byte)(unsafe.Pointer(&sa.Port)) 77 return int(p[0])<<8 | int(p[1]), nil, true 78 } 79 } 80 } 81 return 0, &AddrError{"unknown port", net + "/" + service}, true 82 } 83 84 func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, completed bool) { 85 acquireThread() 86 defer releaseThread() 87 88 var res *C.struct_addrinfo 89 var hints C.struct_addrinfo 90 91 hints.ai_flags = cgoAddrInfoFlags() 92 hints.ai_socktype = C.SOCK_STREAM 93 94 h := C.CString(name) 95 defer C.free(unsafe.Pointer(h)) 96 gerrno, err := C.getaddrinfo(h, nil, &hints, &res) 97 if gerrno != 0 { 98 var str string 99 if gerrno == C.EAI_NONAME { 100 str = noSuchHost 101 } else if gerrno == C.EAI_SYSTEM { 102 if err == nil { 103 // err should not be nil, but sometimes getaddrinfo returns 104 // gerrno == C.EAI_SYSTEM with err == nil on Linux. 105 // The report claims that it happens when we have too many 106 // open files, so use syscall.EMFILE (too many open files in system). 107 // Most system calls would return ENFILE (too many open files), 108 // so at the least EMFILE should be easy to recognize if this 109 // comes up again. golang.org/issue/6232. 110 err = syscall.EMFILE 111 } 112 str = err.Error() 113 } else { 114 str = C.GoString(C.gai_strerror(gerrno)) 115 } 116 return nil, "", &DNSError{Err: str, Name: name}, true 117 } 118 defer C.freeaddrinfo(res) 119 if res != nil { 120 cname = C.GoString(res.ai_canonname) 121 if cname == "" { 122 cname = name 123 } 124 if len(cname) > 0 && cname[len(cname)-1] != '.' { 125 cname += "." 126 } 127 } 128 for r := res; r != nil; r = r.ai_next { 129 // We only asked for SOCK_STREAM, but check anyhow. 130 if r.ai_socktype != C.SOCK_STREAM { 131 continue 132 } 133 switch r.ai_family { 134 default: 135 continue 136 case C.AF_INET: 137 sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr)) 138 addrs = append(addrs, copyIP(sa.Addr[:])) 139 case C.AF_INET6: 140 sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr)) 141 addrs = append(addrs, copyIP(sa.Addr[:])) 142 } 143 } 144 return addrs, cname, nil, true 145 } 146 147 func cgoLookupIP(name string) (addrs []IP, err error, completed bool) { 148 addrs, _, err, completed = cgoLookupIPCNAME(name) 149 return 150 } 151 152 func cgoLookupCNAME(name string) (cname string, err error, completed bool) { 153 _, cname, err, completed = cgoLookupIPCNAME(name) 154 return 155 } 156 157 func copyIP(x IP) IP { 158 if len(x) < 16 { 159 return x.To16() 160 } 161 y := make(IP, len(x)) 162 copy(y, x) 163 return y 164 }