summaryrefslogtreecommitdiff
path: root/src/pkg/net
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-08-10 15:05:15 +0200
committerOndřej Surý <ondrej@sury.org>2011-08-10 15:05:15 +0200
commit825e92f34920934f09dbf4c614dbd2913ba464cb (patch)
tree2af4eb446f544e17f65b34ad2b9668d2bb8ab78b /src/pkg/net
parente6b380032482808aee5e4c5222b6d7390f468e74 (diff)
downloadgolang-825e92f34920934f09dbf4c614dbd2913ba464cb.tar.gz
Imported Upstream version 2011.08.10upstream-weekly/2011.08.10
Diffstat (limited to 'src/pkg/net')
-rw-r--r--src/pkg/net/Makefile14
-rw-r--r--src/pkg/net/dnsclient.go27
-rw-r--r--src/pkg/net/fd_openbsd.go116
-rw-r--r--src/pkg/net/interface.go9
-rw-r--r--src/pkg/net/interface_bsd.go44
-rw-r--r--src/pkg/net/interface_darwin.go49
-rw-r--r--src/pkg/net/interface_freebsd.go49
-rw-r--r--src/pkg/net/interface_linux.go91
-rw-r--r--src/pkg/net/interface_stub.go7
-rw-r--r--src/pkg/net/interface_test.go7
-rw-r--r--src/pkg/net/interface_windows.go7
-rw-r--r--src/pkg/net/lookup_test.go (renamed from src/pkg/net/srv_test.go)28
-rw-r--r--src/pkg/net/lookup_unix.go19
-rw-r--r--src/pkg/net/lookup_windows.go41
14 files changed, 466 insertions, 42 deletions
diff --git a/src/pkg/net/Makefile b/src/pkg/net/Makefile
index 536fe369d..6b3d0b328 100644
--- a/src/pkg/net/Makefile
+++ b/src/pkg/net/Makefile
@@ -29,6 +29,7 @@ GOFILES_freebsd=\
fd.go\
file.go\
interface_bsd.go\
+ interface_freebsd.go\
lookup_unix.go\
newpollserver.go\
port.go\
@@ -45,6 +46,7 @@ GOFILES_darwin=\
fd.go\
file.go\
interface_bsd.go\
+ interface_darwin.go\
lookup_unix.go\
newpollserver.go\
port.go\
@@ -67,6 +69,18 @@ GOFILES_linux=\
sendfile_linux.go\
sock_linux.go\
+GOFILES_openbsd=\
+ dnsclient.go\
+ dnsconfig.go\
+ fd.go\
+ file.go\
+ interface_bsd.go\
+ newpollserver.go\
+ port.go\
+ sendfile_stub.go\
+ sock_bsd.go\
+ cgo_stub.go\
+
GOFILES_plan9=\
interface_stub.go\
lookup_unix.go\
diff --git a/src/pkg/net/dnsclient.go b/src/pkg/net/dnsclient.go
index 280b19453..93c04f6b5 100644
--- a/src/pkg/net/dnsclient.go
+++ b/src/pkg/net/dnsclient.go
@@ -9,6 +9,7 @@ import (
"fmt"
"os"
"rand"
+ "sort"
)
// DNSError represents a DNS lookup error.
@@ -182,9 +183,9 @@ func (s byPriorityWeight) Less(i, j int) bool {
(s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
}
-// shuffleSRVByWeight shuffles SRV records by weight using the algorithm
+// shuffleByWeight shuffles SRV records by weight using the algorithm
// described in RFC 2782.
-func shuffleSRVByWeight(addrs []*SRV) {
+func (addrs byPriorityWeight) shuffleByWeight() {
sum := 0
for _, addr := range addrs {
sum += int(addr.Weight)
@@ -208,6 +209,19 @@ func shuffleSRVByWeight(addrs []*SRV) {
}
}
+// sort reorders SRV records as specified in RFC 2782.
+func (addrs byPriorityWeight) sort() {
+ sort.Sort(addrs)
+ i := 0
+ for j := 1; j < len(addrs); j++ {
+ if addrs[i].Priority != addrs[j].Priority {
+ addrs[i:j].shuffleByWeight()
+ i = j
+ }
+ }
+ addrs[i:].shuffleByWeight()
+}
+
// An MX represents a single DNS MX record.
type MX struct {
Host string
@@ -222,3 +236,12 @@ func (s byPref) Len() int { return len(s) }
func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref }
func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
+// sort reorders MX records as specified in RFC 5321.
+func (s byPref) sort() {
+ for i := range s {
+ j := rand.Intn(i + 1)
+ s[i], s[j] = s[j], s[i]
+ }
+ sort.Sort(s)
+}
diff --git a/src/pkg/net/fd_openbsd.go b/src/pkg/net/fd_openbsd.go
new file mode 100644
index 000000000..e50883e94
--- /dev/null
+++ b/src/pkg/net/fd_openbsd.go
@@ -0,0 +1,116 @@
+// Copyright 2009 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.
+
+// Waiting for FDs via kqueue/kevent.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+type pollster struct {
+ kq int
+ eventbuf [10]syscall.Kevent_t
+ events []syscall.Kevent_t
+
+ // An event buffer for AddFD/DelFD.
+ // Must hold pollServer lock.
+ kbuf [1]syscall.Kevent_t
+}
+
+func newpollster() (p *pollster, err os.Error) {
+ p = new(pollster)
+ var e int
+ if p.kq, e = syscall.Kqueue(); e != 0 {
+ return nil, os.NewSyscallError("kqueue", e)
+ }
+ p.events = p.eventbuf[0:0]
+ return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, os.Error) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_ADD - add event to kqueue list
+ // EV_ONESHOT - delete the event the first time it triggers
+ flags := syscall.EV_ADD
+ if !repeat {
+ flags |= syscall.EV_ONESHOT
+ }
+ syscall.SetKevent(ev, fd, kmode, flags)
+
+ n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+ if e != 0 {
+ return false, os.NewSyscallError("kevent", e)
+ }
+ if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
+ return false, os.NewSyscallError("kqueue phase error", e)
+ }
+ if ev.Data != 0 {
+ return false, os.Errno(int(ev.Data))
+ }
+ return false, nil
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+ // pollServer is locked.
+
+ var kmode int
+ if mode == 'r' {
+ kmode = syscall.EVFILT_READ
+ } else {
+ kmode = syscall.EVFILT_WRITE
+ }
+ ev := &p.kbuf[0]
+ // EV_DELETE - delete event from kqueue list
+ syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
+ syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+}
+
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
+ var t *syscall.Timespec
+ for len(p.events) == 0 {
+ if nsec > 0 {
+ if t == nil {
+ t = new(syscall.Timespec)
+ }
+ *t = syscall.NsecToTimespec(nsec)
+ }
+
+ s.Unlock()
+ nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+ s.Lock()
+
+ if e != 0 {
+ if e == syscall.EINTR {
+ continue
+ }
+ return -1, 0, os.NewSyscallError("kevent", e)
+ }
+ if nn == 0 {
+ return -1, 0, nil
+ }
+ p.events = p.eventbuf[0:nn]
+ }
+ ev := &p.events[0]
+ p.events = p.events[1:]
+ fd = int(ev.Ident)
+ if ev.Filter == syscall.EVFILT_READ {
+ mode = 'r'
+ } else {
+ mode = 'w'
+ }
+ return fd, mode, nil
+}
+
+func (p *pollster) Close() os.Error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/src/pkg/net/interface.go b/src/pkg/net/interface.go
index f6de36f64..8a14cb232 100644
--- a/src/pkg/net/interface.go
+++ b/src/pkg/net/interface.go
@@ -79,6 +79,15 @@ func (ifi *Interface) Addrs() ([]Addr, os.Error) {
return interfaceAddrTable(ifi.Index)
}
+// MulticastAddrs returns multicast, joined group addresses for
+// a specific interface.
+func (ifi *Interface) MulticastAddrs() ([]Addr, os.Error) {
+ if ifi == nil {
+ return nil, os.NewError("net: invalid interface")
+ }
+ return interfaceMulticastAddrTable(ifi.Index)
+}
+
// Interfaces returns a list of the systems's network interfaces.
func Interfaces() ([]Interface, os.Error) {
return interfaceTable(0)
diff --git a/src/pkg/net/interface_bsd.go b/src/pkg/net/interface_bsd.go
index a4c3e71fe..130820d4a 100644
--- a/src/pkg/net/interface_bsd.go
+++ b/src/pkg/net/interface_bsd.go
@@ -148,25 +148,55 @@ func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, os.Error) {
}
for _, s := range sas {
- var ifa IPAddr
+
switch v := s.(type) {
case *syscall.SockaddrInet4:
- ifa.IP = IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])
+ ifa := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
+ ifat = append(ifat, ifa.toAddr())
case *syscall.SockaddrInet6:
- ifa.IP = make(IP, IPv6len)
+ ifa := &IPAddr{IP: make(IP, IPv6len)}
copy(ifa.IP, v.Addr[:])
// NOTE: KAME based IPv6 protcol stack usually embeds
// the interface index in the interface-local or link-
// local address as the kernel-internal form.
- if ifa.IP.IsLinkLocalUnicast() ||
- ifa.IP.IsInterfaceLocalMulticast() ||
- ifa.IP.IsLinkLocalMulticast() {
+ if ifa.IP.IsLinkLocalUnicast() {
// remove embedded scope zone ID
ifa.IP[2], ifa.IP[3] = 0, 0
}
+ ifat = append(ifat, ifa.toAddr())
}
- ifat = append(ifat, ifa.toAddr())
}
return ifat, nil
}
+
+func newMulticastAddr(m *syscall.InterfaceMulticastAddrMessage) ([]Addr, os.Error) {
+ var ifmat []Addr
+
+ sas, e := syscall.ParseRoutingSockaddr(m)
+ if e != 0 {
+ return nil, os.NewSyscallError("route sockaddr", e)
+ }
+
+ for _, s := range sas {
+ switch v := s.(type) {
+ case *syscall.SockaddrInet4:
+ ifma := &IPAddr{IP: IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3])}
+ ifmat = append(ifmat, ifma.toAddr())
+ case *syscall.SockaddrInet6:
+ ifma := &IPAddr{IP: make(IP, IPv6len)}
+ copy(ifma.IP, v.Addr[:])
+ // NOTE: KAME based IPv6 protcol stack usually embeds
+ // the interface index in the interface-local or link-
+ // local address as the kernel-internal form.
+ if ifma.IP.IsInterfaceLocalMulticast() ||
+ ifma.IP.IsLinkLocalMulticast() {
+ // remove embedded scope zone ID
+ ifma.IP[2], ifma.IP[3] = 0, 0
+ }
+ ifmat = append(ifmat, ifma.toAddr())
+ }
+ }
+
+ return ifmat, nil
+}
diff --git a/src/pkg/net/interface_darwin.go b/src/pkg/net/interface_darwin.go
new file mode 100644
index 000000000..6fbcd3723
--- /dev/null
+++ b/src/pkg/net/interface_darwin.go
@@ -0,0 +1,49 @@
+// Copyright 2011 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.
+
+// Network interface identification for Darwin
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ifmat []Addr
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceMulticastAddrMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifma, err := newMulticastAddr(v)
+ if err != nil {
+ return nil, err
+ }
+ ifmat = append(ifmat, ifma...)
+ }
+ }
+ }
+
+ return ifmat, nil
+}
diff --git a/src/pkg/net/interface_freebsd.go b/src/pkg/net/interface_freebsd.go
new file mode 100644
index 000000000..e0ff6caf0
--- /dev/null
+++ b/src/pkg/net/interface_freebsd.go
@@ -0,0 +1,49 @@
+// Copyright 2011 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.
+
+// Network interface identification for FreeBSD
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ifmat []Addr
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifindex)
+ if e != 0 {
+ return nil, os.NewSyscallError("route rib", e)
+ }
+
+ msgs, e = syscall.ParseRoutingMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("route message", e)
+ }
+
+ for _, m := range msgs {
+ switch v := m.(type) {
+ case *syscall.InterfaceMulticastAddrMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifma, err := newMulticastAddr(v)
+ if err != nil {
+ return nil, err
+ }
+ ifmat = append(ifmat, ifma...)
+ }
+ }
+ }
+
+ return ifmat, nil
+}
diff --git a/src/pkg/net/interface_linux.go b/src/pkg/net/interface_linux.go
index e869cd630..3d2a0bb9f 100644
--- a/src/pkg/net/interface_linux.go
+++ b/src/pkg/net/interface_linux.go
@@ -7,6 +7,7 @@
package net
import (
+ "fmt"
"os"
"syscall"
"unsafe"
@@ -102,13 +103,13 @@ func linkFlags(rawFlags uint32) Flags {
// for a specific interface.
func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
var (
+ tab []byte
+ e int
+ err os.Error
ifat4 []Addr
ifat6 []Addr
- tab []byte
msgs4 []syscall.NetlinkMessage
msgs6 []syscall.NetlinkMessage
- e int
- err os.Error
)
tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET)
@@ -169,17 +170,93 @@ func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
for _, a := range attrs {
switch a.Attr.Type {
case syscall.IFA_ADDRESS:
- ifa := IPAddr{}
switch family {
case syscall.AF_INET:
- ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])
+ ifa := &IPAddr{IP: IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3])}
+ ifat = append(ifat, ifa.toAddr())
case syscall.AF_INET6:
- ifa.IP = make(IP, IPv6len)
+ ifa := &IPAddr{IP: make(IP, IPv6len)}
copy(ifa.IP, a.Value[:])
+ ifat = append(ifat, ifa.toAddr())
}
- ifat = append(ifat, ifa.toAddr())
}
}
return ifat
}
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ ifi *Interface
+ err os.Error
+ )
+
+ if ifindex > 0 {
+ ifi, err = InterfaceByIndex(ifindex)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ ifmat4 := parseProcNetIGMP(ifi)
+ ifmat6 := parseProcNetIGMP6(ifi)
+
+ return append(ifmat4, ifmat6...), nil
+}
+
+func parseProcNetIGMP(ifi *Interface) []Addr {
+ var (
+ ifmat []Addr
+ name string
+ )
+
+ fd, err := open("/proc/net/igmp")
+ if err != nil {
+ return nil
+ }
+ defer fd.close()
+
+ fd.readLine() // skip first line
+ b := make([]byte, IPv4len)
+ for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
+ f := getFields(l)
+ switch len(f) {
+ case 4:
+ if ifi == nil || name == ifi.Name {
+ fmt.Sscanf(f[0], "%08x", &b)
+ ifma := IPAddr{IP: IPv4(b[3], b[2], b[1], b[0])}
+ ifmat = append(ifmat, ifma.toAddr())
+ }
+ case 5:
+ name = f[1]
+ }
+ }
+
+ return ifmat
+}
+
+func parseProcNetIGMP6(ifi *Interface) []Addr {
+ var ifmat []Addr
+
+ fd, err := open("/proc/net/igmp6")
+ if err != nil {
+ return nil
+ }
+ defer fd.close()
+
+ b := make([]byte, IPv6len)
+ for l, ok := fd.readLine(); ok; l, ok = fd.readLine() {
+ f := getFields(l)
+ if ifi == nil || f[1] == ifi.Name {
+ fmt.Sscanf(f[2], "%32x", &b)
+ ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
+ ifmat = append(ifmat, ifma.toAddr())
+
+ }
+ }
+
+ return ifmat
+}
diff --git a/src/pkg/net/interface_stub.go b/src/pkg/net/interface_stub.go
index 24a7431c5..950de6c59 100644
--- a/src/pkg/net/interface_stub.go
+++ b/src/pkg/net/interface_stub.go
@@ -21,3 +21,10 @@ func interfaceTable(ifindex int) ([]Interface, os.Error) {
func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
return nil, nil
}
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ return nil, nil
+}
diff --git a/src/pkg/net/interface_test.go b/src/pkg/net/interface_test.go
index ac523a049..0e4089abf 100644
--- a/src/pkg/net/interface_test.go
+++ b/src/pkg/net/interface_test.go
@@ -45,10 +45,17 @@ func TestInterfaces(t *testing.T) {
if err != nil {
t.Fatalf("Interface.Addrs() failed: %v", err)
}
+ ifmat, err := ifi.MulticastAddrs()
+ if err != nil {
+ t.Fatalf("Interface.MulticastAddrs() failed: %v", err)
+ }
t.Logf("%q: flags %q, ifindex %v, mtu %v\n", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
for _, ifa := range ifat {
t.Logf("\tinterface address %q\n", ifa.String())
}
+ for _, ifma := range ifmat {
+ t.Logf("\tjoined group address %q\n", ifma.String())
+ }
t.Logf("\thardware address %q", ifi.HardwareAddr.String())
}
}
diff --git a/src/pkg/net/interface_windows.go b/src/pkg/net/interface_windows.go
index 571f74cdc..7f5169c87 100644
--- a/src/pkg/net/interface_windows.go
+++ b/src/pkg/net/interface_windows.go
@@ -149,3 +149,10 @@ func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
}
return ifat, nil
}
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces. Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, os.Error) {
+ return nil, nil
+}
diff --git a/src/pkg/net/srv_test.go b/src/pkg/net/lookup_test.go
index f1c7a0ab4..995ab03d0 100644
--- a/src/pkg/net/srv_test.go
+++ b/src/pkg/net/lookup_test.go
@@ -27,3 +27,31 @@ func TestGoogleSRV(t *testing.T) {
t.Errorf("no results")
}
}
+
+func TestGmailMX(t *testing.T) {
+ if testing.Short() || avoidMacFirewall {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+ mx, err := LookupMX("gmail.com")
+ if err != nil {
+ t.Errorf("failed: %s", err)
+ }
+ if len(mx) == 0 {
+ t.Errorf("no results")
+ }
+}
+
+func TestGoogleDNSAddr(t *testing.T) {
+ if testing.Short() || avoidMacFirewall {
+ t.Logf("skipping test to avoid external network")
+ return
+ }
+ names, err := LookupAddr("8.8.8.8")
+ if err != nil {
+ t.Errorf("failed: %s", err)
+ }
+ if len(names) == 0 {
+ t.Errorf("no results")
+ }
+}
diff --git a/src/pkg/net/lookup_unix.go b/src/pkg/net/lookup_unix.go
index 168d3fa6d..8f5e66212 100644
--- a/src/pkg/net/lookup_unix.go
+++ b/src/pkg/net/lookup_unix.go
@@ -6,8 +6,6 @@ package net
import (
"os"
- "rand"
- "sort"
)
// LookupHost looks up the given host using the local resolver.
@@ -68,15 +66,7 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
r := rr.(*dnsRR_SRV)
addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
}
- sort.Sort(byPriorityWeight(addrs))
- i := 0
- for j := 1; j < len(addrs); j++ {
- if addrs[i].Priority != addrs[j].Priority {
- shuffleSRVByWeight(addrs[i:j])
- i = j
- }
- }
- shuffleSRVByWeight(addrs[i:len(addrs)])
+ byPriorityWeight(addrs).sort()
return
}
@@ -91,12 +81,7 @@ func LookupMX(name string) (mx []*MX, err os.Error) {
r := rr[i].(*dnsRR_MX)
mx[i] = &MX{r.Mx, r.Pref}
}
- // Shuffle the records to match RFC 5321 when sorted
- for i := range mx {
- j := rand.Intn(i + 1)
- mx[i], mx[j] = mx[j], mx[i]
- }
- sort.Sort(byPref(mx))
+ byPref(mx).sort()
return
}
diff --git a/src/pkg/net/lookup_windows.go b/src/pkg/net/lookup_windows.go
index 16b37f56c..fa3ad7c7f 100644
--- a/src/pkg/net/lookup_windows.go
+++ b/src/pkg/net/lookup_windows.go
@@ -85,23 +85,46 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.
return "", nil, os.NewSyscallError("LookupSRV", int(e))
}
defer syscall.DnsRecordListFree(r, 1)
- addrs = make([]*SRV, 100)
- i := 0
+ addrs = make([]*SRV, 0, 10)
for p := r; p != nil && p.Type == syscall.DNS_TYPE_SRV; p = p.Next {
v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
- addrs[i] = &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight}
- i++
+ addrs = append(addrs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
}
- addrs = addrs[0:i]
+ byPriorityWeight(addrs).sort()
return name, addrs, nil
}
-// TODO(brainman): implement LookupMX and LookupAddr.
-
func LookupMX(name string) (mx []*MX, err os.Error) {
- return nil, os.NewSyscallError("LookupMX", syscall.EWINDOWS)
+ var r *syscall.DNSRecord
+ e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
+ if int(e) != 0 {
+ return nil, os.NewSyscallError("LookupMX", int(e))
+ }
+ defer syscall.DnsRecordListFree(r, 1)
+ mx = make([]*MX, 0, 10)
+ for p := r; p != nil && p.Type == syscall.DNS_TYPE_MX; p = p.Next {
+ v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
+ mx = append(mx, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
+ }
+ byPref(mx).sort()
+ return mx, nil
}
func LookupAddr(addr string) (name []string, err os.Error) {
- return nil, os.NewSyscallError("LookupAddr", syscall.EWINDOWS)
+ arpa, err := reverseaddr(addr)
+ if err != nil {
+ return nil, err
+ }
+ var r *syscall.DNSRecord
+ e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
+ if int(e) != 0 {
+ return nil, os.NewSyscallError("LookupAddr", int(e))
+ }
+ defer syscall.DnsRecordListFree(r, 1)
+ name = make([]string, 0, 10)
+ for p := r; p != nil && p.Type == syscall.DNS_TYPE_PTR; p = p.Next {
+ v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
+ name = append(name, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
+ }
+ return name, nil
}