diff options
| author | Ondřej Surý <ondrej@sury.org> | 2011-08-10 15:05:15 +0200 | 
|---|---|---|
| committer | Ondřej Surý <ondrej@sury.org> | 2011-08-10 15:05:15 +0200 | 
| commit | 825e92f34920934f09dbf4c614dbd2913ba464cb (patch) | |
| tree | 2af4eb446f544e17f65b34ad2b9668d2bb8ab78b /src/pkg/net | |
| parent | e6b380032482808aee5e4c5222b6d7390f468e74 (diff) | |
| download | golang-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/Makefile | 14 | ||||
| -rw-r--r-- | src/pkg/net/dnsclient.go | 27 | ||||
| -rw-r--r-- | src/pkg/net/fd_openbsd.go | 116 | ||||
| -rw-r--r-- | src/pkg/net/interface.go | 9 | ||||
| -rw-r--r-- | src/pkg/net/interface_bsd.go | 44 | ||||
| -rw-r--r-- | src/pkg/net/interface_darwin.go | 49 | ||||
| -rw-r--r-- | src/pkg/net/interface_freebsd.go | 49 | ||||
| -rw-r--r-- | src/pkg/net/interface_linux.go | 91 | ||||
| -rw-r--r-- | src/pkg/net/interface_stub.go | 7 | ||||
| -rw-r--r-- | src/pkg/net/interface_test.go | 7 | ||||
| -rw-r--r-- | src/pkg/net/interface_windows.go | 7 | ||||
| -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.go | 19 | ||||
| -rw-r--r-- | src/pkg/net/lookup_windows.go | 41 | 
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  } | 
