Source file src/pkg/net/cgo_unix.go
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 darwin freebsd linux
6
7 package net
8
9 /*
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <netdb.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <string.h>
17 */
18 import "C"
19
20 import (
21 "syscall"
22 "unsafe"
23 )
24
25 func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
26 ip, err, completed := cgoLookupIP(name)
27 for _, p := range ip {
28 addrs = append(addrs, p.String())
29 }
30 return
31 }
32
33 func cgoLookupPort(net, service string) (port int, err error, completed bool) {
34 var res *C.struct_addrinfo
35 var hints C.struct_addrinfo
36
37 switch net {
38 case "":
39 // no hints
40 case "tcp", "tcp4", "tcp6":
41 hints.ai_socktype = C.SOCK_STREAM
42 hints.ai_protocol = C.IPPROTO_TCP
43 case "udp", "udp4", "udp6":
44 hints.ai_socktype = C.SOCK_DGRAM
45 hints.ai_protocol = C.IPPROTO_UDP
46 default:
47 return 0, UnknownNetworkError(net), true
48 }
49 if len(net) >= 4 {
50 switch net[3] {
51 case '4':
52 hints.ai_family = C.AF_INET
53 case '6':
54 hints.ai_family = C.AF_INET6
55 }
56 }
57
58 s := C.CString(service)
59 defer C.free(unsafe.Pointer(s))
60 if C.getaddrinfo(nil, s, &hints, &res) == 0 {
61 defer C.freeaddrinfo(res)
62 for r := res; r != nil; r = r.ai_next {
63 switch r.ai_family {
64 default:
65 continue
66 case C.AF_INET:
67 sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
68 p := (*[2]byte)(unsafe.Pointer(&sa.Port))
69 return int(p[0])<<8 | int(p[1]), nil, true
70 case C.AF_INET6:
71 sa := (*syscall.RawSockaddrInet6)(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 }
75 }
76 }
77 return 0, &AddrError{"unknown port", net + "/" + service}, true
78 }
79
80 func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, completed bool) {
81 var res *C.struct_addrinfo
82 var hints C.struct_addrinfo
83
84 // NOTE(rsc): In theory there are approximately balanced
85 // arguments for and against including AI_ADDRCONFIG
86 // in the flags (it includes IPv4 results only on IPv4 systems,
87 // and similarly for IPv6), but in practice setting it causes
88 // getaddrinfo to return the wrong canonical name on Linux.
89 // So definitely leave it out.
90 hints.ai_flags = (C.AI_ALL | C.AI_V4MAPPED | C.AI_CANONNAME) & cgoAddrInfoMask()
91
92 h := C.CString(name)
93 defer C.free(unsafe.Pointer(h))
94 gerrno, err := C.getaddrinfo(h, nil, &hints, &res)
95 if gerrno != 0 {
96 var str string
97 if gerrno == C.EAI_NONAME {
98 str = noSuchHost
99 } else if gerrno == C.EAI_SYSTEM {
100 str = err.Error()
101 } else {
102 str = C.GoString(C.gai_strerror(gerrno))
103 }
104 return nil, "", &DNSError{Err: str, Name: name}, true
105 }
106 defer C.freeaddrinfo(res)
107 if res != nil {
108 cname = C.GoString(res.ai_canonname)
109 if cname == "" {
110 cname = name
111 }
112 if len(cname) > 0 && cname[len(cname)-1] != '.' {
113 cname += "."
114 }
115 }
116 for r := res; r != nil; r = r.ai_next {
117 // Everything comes back twice, once for UDP and once for TCP.
118 if r.ai_socktype != C.SOCK_STREAM {
119 continue
120 }
121 switch r.ai_family {
122 default:
123 continue
124 case C.AF_INET:
125 sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
126 addrs = append(addrs, copyIP(sa.Addr[:]))
127 case C.AF_INET6:
128 sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
129 addrs = append(addrs, copyIP(sa.Addr[:]))
130 }
131 }
132 return addrs, cname, nil, true
133 }
134
135 func cgoLookupIP(name string) (addrs []IP, err error, completed bool) {
136 addrs, _, err, completed = cgoLookupIPCNAME(name)
137 return
138 }
139
140 func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
141 _, cname, err, completed = cgoLookupIPCNAME(name)
142 return
143 }
144
145 func copyIP(x IP) IP {
146 y := make(IP, len(x))
147 copy(y, x)
148 return y
149 }