github.com/axw/llgo@v0.0.0-20160805011314-95b5fe4dca20/third_party/gofrontend/libgo/go/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 cgo,!netgo 6 // +build darwin dragonfly freebsd linux netbsd openbsd solaris 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 20 import ( 21 "syscall" 22 "unsafe" 23 ) 24 25 //extern getaddrinfo 26 func libc_getaddrinfo(node *byte, service *byte, hints *syscall.Addrinfo, res **syscall.Addrinfo) int 27 28 //extern freeaddrinfo 29 func libc_freeaddrinfo(res *syscall.Addrinfo) 30 31 //extern gai_strerror 32 func libc_gai_strerror(errcode int) *byte 33 34 // bytePtrToString takes a NUL-terminated array of bytes and convert 35 // it to a Go string. 36 func bytePtrToString(p *byte) string { 37 a := (*[10000]byte)(unsafe.Pointer(p)) 38 i := 0 39 for a[i] != 0 { 40 i++ 41 } 42 return string(a[:i]) 43 } 44 45 // An addrinfoErrno represents a getaddrinfo, getnameinfo-specific 46 // error number. It's a signed number and a zero value is a non-error 47 // by convention. 48 type addrinfoErrno int 49 50 func (eai addrinfoErrno) Error() string { return bytePtrToString(libc_gai_strerror(int(eai))) } 51 func (eai addrinfoErrno) Temporary() bool { return eai == syscall.EAI_AGAIN } 52 func (eai addrinfoErrno) Timeout() bool { return false } 53 54 func cgoLookupHost(name string) (hosts []string, err error, completed bool) { 55 addrs, err, completed := cgoLookupIP(name) 56 for _, addr := range addrs { 57 hosts = append(hosts, addr.String()) 58 } 59 return 60 } 61 62 func cgoLookupPort(network, service string) (port int, err error, completed bool) { 63 acquireThread() 64 defer releaseThread() 65 66 var hints syscall.Addrinfo 67 switch network { 68 case "": // no hints 69 case "tcp", "tcp4", "tcp6": 70 hints.Ai_socktype = syscall.SOCK_STREAM 71 hints.Ai_protocol = syscall.IPPROTO_TCP 72 case "udp", "udp4", "udp6": 73 hints.Ai_socktype = syscall.SOCK_DGRAM 74 hints.Ai_protocol = syscall.IPPROTO_UDP 75 default: 76 return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}, true 77 } 78 if len(network) >= 4 { 79 switch network[3] { 80 case '4': 81 hints.Ai_family = syscall.AF_INET 82 case '6': 83 hints.Ai_family = syscall.AF_INET6 84 } 85 } 86 87 s := syscall.StringBytePtr(service) 88 var res *syscall.Addrinfo 89 syscall.Entersyscall() 90 gerrno := libc_getaddrinfo(nil, s, &hints, &res) 91 syscall.Exitsyscall() 92 if gerrno != 0 { 93 switch gerrno { 94 case syscall.EAI_SYSTEM: 95 errno := syscall.GetErrno() 96 if errno == 0 { // see golang.org/issue/6232 97 errno = syscall.EMFILE 98 } 99 err = errno 100 default: 101 err = addrinfoErrno(gerrno) 102 } 103 return 0, &DNSError{Err: err.Error(), Name: network + "/" + service}, true 104 } 105 defer libc_freeaddrinfo(res) 106 107 for r := res; r != nil; r = r.Ai_next { 108 switch r.Ai_family { 109 case syscall.AF_INET: 110 sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.Ai_addr)) 111 p := (*[2]byte)(unsafe.Pointer(&sa.Port)) 112 return int(p[0])<<8 | int(p[1]), nil, true 113 case syscall.AF_INET6: 114 sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.Ai_addr)) 115 p := (*[2]byte)(unsafe.Pointer(&sa.Port)) 116 return int(p[0])<<8 | int(p[1]), nil, true 117 } 118 } 119 return 0, &DNSError{Err: "unknown port", Name: network + "/" + service}, true 120 } 121 122 func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, completed bool) { 123 acquireThread() 124 defer releaseThread() 125 126 var hints syscall.Addrinfo 127 hints.Ai_flags = int32(cgoAddrInfoFlags) 128 hints.Ai_socktype = syscall.SOCK_STREAM 129 130 h := syscall.StringBytePtr(name) 131 var res *syscall.Addrinfo 132 syscall.Entersyscall() 133 gerrno := libc_getaddrinfo(h, nil, &hints, &res) 134 syscall.Exitsyscall() 135 if gerrno != 0 { 136 switch gerrno { 137 case syscall.EAI_SYSTEM: 138 errno := syscall.GetErrno() 139 if errno == 0 { 140 // err should not be nil, but sometimes getaddrinfo returns 141 // gerrno == C.EAI_SYSTEM with err == nil on Linux. 142 // The report claims that it happens when we have too many 143 // open files, so use syscall.EMFILE (too many open files in system). 144 // Most system calls would return ENFILE (too many open files), 145 // so at the least EMFILE should be easy to recognize if this 146 // comes up again. golang.org/issue/6232. 147 errno = syscall.EMFILE 148 } 149 err = errno 150 case syscall.EAI_NONAME: 151 err = errNoSuchHost 152 default: 153 err = addrinfoErrno(gerrno) 154 } 155 return nil, "", &DNSError{Err: err.Error(), Name: name}, true 156 } 157 defer libc_freeaddrinfo(res) 158 159 if res != nil { 160 cname = bytePtrToString((*byte)(unsafe.Pointer(res.Ai_canonname))) 161 if cname == "" { 162 cname = name 163 } 164 if len(cname) > 0 && cname[len(cname)-1] != '.' { 165 cname += "." 166 } 167 } 168 for r := res; r != nil; r = r.Ai_next { 169 // We only asked for SOCK_STREAM, but check anyhow. 170 if r.Ai_socktype != syscall.SOCK_STREAM { 171 continue 172 } 173 switch r.Ai_family { 174 case syscall.AF_INET: 175 sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.Ai_addr)) 176 addr := IPAddr{IP: copyIP(sa.Addr[:])} 177 addrs = append(addrs, addr) 178 case syscall.AF_INET6: 179 sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.Ai_addr)) 180 addr := IPAddr{IP: copyIP(sa.Addr[:]), Zone: zoneToString(int(sa.Scope_id))} 181 addrs = append(addrs, addr) 182 } 183 } 184 return addrs, cname, nil, true 185 } 186 187 func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) { 188 addrs, _, err, completed = cgoLookupIPCNAME(name) 189 return 190 } 191 192 func cgoLookupCNAME(name string) (cname string, err error, completed bool) { 193 _, cname, err, completed = cgoLookupIPCNAME(name) 194 return 195 } 196 197 // These are roughly enough for the following: 198 // 199 // Source Encoding Maximum length of single name entry 200 // Unicast DNS ASCII or <=253 + a NUL terminator 201 // Unicode in RFC 5892 252 * total number of labels + delimiters + a NUL terminator 202 // Multicast DNS UTF-8 in RFC 5198 or <=253 + a NUL terminator 203 // the same as unicast DNS ASCII <=253 + a NUL terminator 204 // Local database various depends on implementation 205 const ( 206 nameinfoLen = 64 207 maxNameinfoLen = 4096 208 ) 209 210 func cgoLookupPTR(addr string) ([]string, error, bool) { 211 acquireThread() 212 defer releaseThread() 213 214 ip := ParseIP(addr) 215 if ip == nil { 216 return nil, &DNSError{Err: "invalid address", Name: addr}, true 217 } 218 sa, salen := cgoSockaddr(ip) 219 if sa == nil { 220 return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr}, true 221 } 222 var err error 223 var b []byte 224 var gerrno int 225 for l := nameinfoLen; l <= maxNameinfoLen; l *= 2 { 226 b = make([]byte, l) 227 gerrno, err = cgoNameinfoPTR(b, sa, salen) 228 if gerrno == 0 || gerrno != syscall.EAI_OVERFLOW { 229 break 230 } 231 } 232 if gerrno != 0 { 233 switch gerrno { 234 case syscall.EAI_SYSTEM: 235 if err == nil { // see golang.org/issue/6232 236 err = syscall.EMFILE 237 } 238 default: 239 err = addrinfoErrno(gerrno) 240 } 241 return nil, &DNSError{Err: err.Error(), Name: addr}, true 242 } 243 244 for i := 0; i < len(b); i++ { 245 if b[i] == 0 { 246 b = b[:i] 247 break 248 } 249 } 250 // Add trailing dot to match pure Go reverse resolver 251 // and all other lookup routines. See golang.org/issue/12189. 252 if len(b) > 0 && b[len(b)-1] != '.' { 253 b = append(b, '.') 254 } 255 return []string{string(b)}, nil, true 256 } 257 258 func cgoSockaddr(ip IP) (*syscall.RawSockaddr, syscall.Socklen_t) { 259 if ip4 := ip.To4(); ip4 != nil { 260 return cgoSockaddrInet4(ip4), syscall.Socklen_t(syscall.SizeofSockaddrInet4) 261 } 262 if ip6 := ip.To16(); ip6 != nil { 263 return cgoSockaddrInet6(ip6), syscall.Socklen_t(syscall.SizeofSockaddrInet6) 264 } 265 return nil, 0 266 } 267 268 func copyIP(x IP) IP { 269 if len(x) < 16 { 270 return x.To16() 271 } 272 y := make(IP, len(x)) 273 copy(y, x) 274 return y 275 }