aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/net
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net')
-rw-r--r--libgo/go/net/dial.go93
-rw-r--r--libgo/go/net/dialgoogle_test.go8
-rw-r--r--libgo/go/net/dict/dict.go7
-rw-r--r--libgo/go/net/dnsclient.go398
-rw-r--r--libgo/go/net/dnsclient_unix.go261
-rw-r--r--libgo/go/net/dnsconfig.go1
-rw-r--r--libgo/go/net/dnsmsg.go56
-rw-r--r--libgo/go/net/dnsmsg_test.go7
-rw-r--r--libgo/go/net/dnsname_test.go4
-rw-r--r--libgo/go/net/fd.go14
-rw-r--r--libgo/go/net/fd_linux.go11
-rw-r--r--libgo/go/net/fd_openbsd.go116
-rw-r--r--libgo/go/net/fd_windows.go65
-rw-r--r--libgo/go/net/file_plan9.go33
-rw-r--r--libgo/go/net/file_test.go10
-rw-r--r--libgo/go/net/hosts_test.go2
-rw-r--r--libgo/go/net/interface.go132
-rw-r--r--libgo/go/net/interface_bsd.go171
-rw-r--r--libgo/go/net/interface_darwin.go80
-rw-r--r--libgo/go/net/interface_freebsd.go80
-rw-r--r--libgo/go/net/interface_linux.go262
-rw-r--r--libgo/go/net/interface_openbsd.go16
-rw-r--r--libgo/go/net/interface_stub.go30
-rw-r--r--libgo/go/net/interface_test.go73
-rw-r--r--libgo/go/net/interface_windows.go158
-rw-r--r--libgo/go/net/ip.go65
-rw-r--r--libgo/go/net/ip_test.go112
-rw-r--r--libgo/go/net/ipraw_test.go9
-rw-r--r--libgo/go/net/iprawsock.go317
-rw-r--r--libgo/go/net/iprawsock_plan9.go99
-rw-r--r--libgo/go/net/iprawsock_posix.go305
-rw-r--r--libgo/go/net/ipsock.go202
-rw-r--r--libgo/go/net/ipsock_plan9.go305
-rw-r--r--libgo/go/net/ipsock_posix.go174
-rw-r--r--libgo/go/net/lookup.go50
-rw-r--r--libgo/go/net/lookup_plan9.go226
-rw-r--r--libgo/go/net/lookup_test.go (renamed from libgo/go/net/srv_test.go)28
-rw-r--r--libgo/go/net/lookup_unix.go111
-rw-r--r--libgo/go/net/lookup_windows.go (renamed from libgo/go/net/resolv_windows.go)111
-rw-r--r--libgo/go/net/net.go2
-rw-r--r--libgo/go/net/net_test.go4
-rw-r--r--libgo/go/net/newpollserver.go14
-rw-r--r--libgo/go/net/parse_test.go4
-rw-r--r--libgo/go/net/sendfile_linux.go84
-rw-r--r--libgo/go/net/sendfile_stub.go14
-rw-r--r--libgo/go/net/sendfile_windows.go68
-rw-r--r--libgo/go/net/server_test.go48
-rw-r--r--libgo/go/net/sock.go42
-rw-r--r--libgo/go/net/sock_windows.go2
-rw-r--r--libgo/go/net/tcpsock.go262
-rw-r--r--libgo/go/net/tcpsock_plan9.go63
-rw-r--r--libgo/go/net/tcpsock_posix.go283
-rw-r--r--libgo/go/net/textproto/reader.go64
-rw-r--r--libgo/go/net/udpsock.go290
-rw-r--r--libgo/go/net/udpsock_plan9.go187
-rw-r--r--libgo/go/net/udpsock_posix.go294
-rw-r--r--libgo/go/net/unixsock.go399
-rw-r--r--libgo/go/net/unixsock_plan9.go105
-rw-r--r--libgo/go/net/unixsock_posix.go418
59 files changed, 4768 insertions, 2081 deletions
diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go
index 16896b4..10c67dc 100644
--- a/libgo/go/net/dial.go
+++ b/libgo/go/net/dial.go
@@ -6,6 +6,28 @@ package net
import "os"
+func resolveNetAddr(op, net, addr string) (a Addr, err os.Error) {
+ if addr == "" {
+ return nil, &OpError{op, net, nil, errMissingAddress}
+ }
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ a, err = ResolveTCPAddr(net, addr)
+ case "udp", "udp4", "udp6":
+ a, err = ResolveUDPAddr(net, addr)
+ case "unix", "unixgram", "unixpacket":
+ a, err = ResolveUnixAddr(net, addr)
+ case "ip", "ip4", "ip6":
+ a, err = ResolveIPAddr(net, addr)
+ default:
+ err = UnknownNetworkError(net)
+ }
+ if err != nil {
+ return nil, &OpError{op, net + " " + addr, nil, err}
+ }
+ return
+}
+
// Dial connects to the address addr on the network net.
//
// Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
@@ -23,56 +45,26 @@ import "os"
// Dial("tcp", "[de:ad:be:ef::ca:fe]:80")
//
func Dial(net, addr string) (c Conn, err os.Error) {
- raddr := addr
- if raddr == "" {
- return nil, &OpError{"dial", net, nil, errMissingAddress}
+ addri, err := resolveNetAddr("dial", net, addr)
+ if err != nil {
+ return nil, err
}
- switch net {
- case "tcp", "tcp4", "tcp6":
- var ra *TCPAddr
- if ra, err = ResolveTCPAddr(net, raddr); err != nil {
- goto Error
- }
- c, err := DialTCP(net, nil, ra)
- if err != nil {
- return nil, err
- }
- return c, nil
- case "udp", "udp4", "udp6":
- var ra *UDPAddr
- if ra, err = ResolveUDPAddr(net, raddr); err != nil {
- goto Error
- }
- c, err := DialUDP(net, nil, ra)
- if err != nil {
- return nil, err
- }
- return c, nil
- case "unix", "unixgram", "unixpacket":
- var ra *UnixAddr
- if ra, err = ResolveUnixAddr(net, raddr); err != nil {
- goto Error
- }
+ switch ra := addri.(type) {
+ case *TCPAddr:
+ c, err = DialTCP(net, nil, ra)
+ case *UDPAddr:
+ c, err = DialUDP(net, nil, ra)
+ case *UnixAddr:
c, err = DialUnix(net, nil, ra)
- if err != nil {
- return nil, err
- }
- return c, nil
- case "ip", "ip4", "ip6":
- var ra *IPAddr
- if ra, err = ResolveIPAddr(raddr); err != nil {
- goto Error
- }
- c, err := DialIP(net, nil, ra)
- if err != nil {
- return nil, err
- }
- return c, nil
-
+ case *IPAddr:
+ c, err = DialIP(net, nil, ra)
+ default:
+ err = UnknownNetworkError(net)
+ }
+ if err != nil {
+ return nil, &OpError{"dial", net + " " + addr, nil, err}
}
- err = UnknownNetworkError(net)
-Error:
- return nil, &OpError{"dial", net + " " + raddr, nil, err}
+ return
}
// Listen announces on the local network address laddr.
@@ -139,12 +131,13 @@ func ListenPacket(net, laddr string) (c PacketConn, err os.Error) {
return c, nil
}
- if i := last(net, ':'); i > 0 {
- switch net[0:i] {
+ var rawnet string
+ if rawnet, _, err = splitNetProto(net); err != nil {
+ switch rawnet {
case "ip", "ip4", "ip6":
var la *IPAddr
if laddr != "" {
- if la, err = ResolveIPAddr(laddr); err != nil {
+ if la, err = ResolveIPAddr(rawnet, laddr); err != nil {
return nil, err
}
}
diff --git a/libgo/go/net/dialgoogle_test.go b/libgo/go/net/dialgoogle_test.go
index e90c4f3..9ad1770 100644
--- a/libgo/go/net/dialgoogle_test.go
+++ b/libgo/go/net/dialgoogle_test.go
@@ -105,14 +105,12 @@ func TestDialGoogleIPv4(t *testing.T) {
doDial(t, "tcp", addr)
if addr[0] != '[' {
doDial(t, "tcp4", addr)
- if !preferIPv4 {
- // make sure preferIPv4 flag works.
- preferIPv4 = true
+ if supportsIPv6 {
+ // make sure syscall.SocketDisableIPv6 flag works.
syscall.SocketDisableIPv6 = true
doDial(t, "tcp", addr)
doDial(t, "tcp4", addr)
syscall.SocketDisableIPv6 = false
- preferIPv4 = false
}
}
}
@@ -132,7 +130,7 @@ func TestDialGoogleIPv6(t *testing.T) {
return
}
// Only run tcp6 if the kernel will take it.
- if !*ipv6 || !kernelSupportsIPv6() {
+ if !*ipv6 || !supportsIPv6 {
return
}
diff --git a/libgo/go/net/dict/dict.go b/libgo/go/net/dict/dict.go
index 42f6553..b146ea2 100644
--- a/libgo/go/net/dict/dict.go
+++ b/libgo/go/net/dict/dict.go
@@ -7,7 +7,6 @@
package dict
import (
- "container/vector"
"net/textproto"
"os"
"strconv"
@@ -144,7 +143,7 @@ func (c *Client) Define(dict, word string) ([]*Defn, os.Error) {
// Fields are space separated unquoted words
// or quoted with single or double quote.
func fields(s string) ([]string, os.Error) {
- var v vector.StringVector
+ var v []string
i := 0
for {
for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
@@ -170,7 +169,7 @@ func fields(s string) ([]string, os.Error) {
break
}
}
- v.Push(unquote(s[i+1 : j-1]))
+ v = append(v, unquote(s[i+1:j-1]))
i = j
} else {
// atom
@@ -180,7 +179,7 @@ func fields(s string) ([]string, os.Error) {
break
}
}
- v.Push(s[i:j])
+ v = append(v, s[i:j])
i = j
}
if i < len(s) {
diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go
index 3466003..93c04f6 100644
--- a/libgo/go/net/dnsclient.go
+++ b/libgo/go/net/dnsclient.go
@@ -2,16 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// DNS client: see RFC 1035.
-// Has to be linked into package net for Dial.
-
-// TODO(rsc):
-// Check periodically whether /etc/resolv.conf has changed.
-// Could potentially handle many outstanding lookups faster.
-// Could have a small cache.
-// Random UDP source port (net.Dial should do that for us).
-// Random request IDs.
-
package net
import (
@@ -19,8 +9,6 @@ import (
"fmt"
"os"
"rand"
- "sync"
- "time"
"sort"
)
@@ -49,54 +37,31 @@ func (e *DNSError) Temporary() bool { return e.IsTimeout }
const noSuchHost = "no such host"
-// Send a request on the connection and hope for a reply.
-// Up to cfg.attempts attempts.
-func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Error) {
- if len(name) >= 256 {
- return nil, &DNSError{Error: "name too long", Name: name}
- }
- out := new(dnsMsg)
- out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
- out.question = []dnsQuestion{
- {name, qtype, dnsClassINET},
- }
- out.recursion_desired = true
- msg, ok := out.Pack()
- if !ok {
- return nil, &DNSError{Error: "internal error - cannot pack message", Name: name}
+// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
+// address addr suitable for rDNS (PTR) record lookup or an error if it fails
+// to parse the IP address.
+func reverseaddr(addr string) (arpa string, err os.Error) {
+ ip := ParseIP(addr)
+ if ip == nil {
+ return "", &DNSError{Error: "unrecognized address", Name: addr}
}
-
- for attempt := 0; attempt < cfg.attempts; attempt++ {
- n, err := c.Write(msg)
- if err != nil {
- return nil, err
- }
-
- c.SetReadTimeout(int64(cfg.timeout) * 1e9) // nanoseconds
-
- buf := make([]byte, 2000) // More than enough.
- n, err = c.Read(buf)
- if err != nil {
- if e, ok := err.(Error); ok && e.Timeout() {
- continue
- }
- return nil, err
- }
- buf = buf[0:n]
- in := new(dnsMsg)
- if !in.Unpack(buf) || in.id != out.id {
- continue
- }
- return in, nil
+ if ip.To4() != nil {
+ return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil
}
- var server string
- if a := c.RemoteAddr(); a != nil {
- server = a.String()
+ // Must be IPv6
+ var buf bytes.Buffer
+ // Add it, in reverse, to the buffer
+ for i := len(ip) - 1; i >= 0; i-- {
+ s := fmt.Sprintf("%02x", ip[i])
+ buf.WriteByte(s[1])
+ buf.WriteByte('.')
+ buf.WriteByte(s[0])
+ buf.WriteByte('.')
}
- return nil, &DNSError{Error: "no answer from server", Name: name, Server: server, IsTimeout: true}
+ // Append "ip6.arpa." and return (buf already has the final .)
+ return buf.String() + "ip6.arpa.", nil
}
-
// Find answer for name in dns message.
// On return, if err == nil, addrs != nil.
func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
@@ -150,63 +115,6 @@ Cname:
return "", nil, &DNSError{Error: "too many redirects", Name: name, Server: server}
}
-// Do a lookup for a single name, which must be rooted
-// (otherwise answer will not find the answers).
-func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
- if len(cfg.servers) == 0 {
- return "", nil, &DNSError{Error: "no DNS servers", Name: name}
- }
- for i := 0; i < len(cfg.servers); i++ {
- // Calling Dial here is scary -- we have to be sure
- // not to dial a name that will require a DNS lookup,
- // or Dial will call back here to translate it.
- // The DNS config parser has already checked that
- // all the cfg.servers[i] are IP addresses, which
- // Dial will use without a DNS lookup.
- server := cfg.servers[i] + ":53"
- c, cerr := Dial("udp", server)
- if cerr != nil {
- err = cerr
- continue
- }
- msg, merr := exchange(cfg, c, name, qtype)
- c.Close()
- if merr != nil {
- err = merr
- continue
- }
- cname, addrs, err = answer(name, server, msg, qtype)
- if err == nil || err.(*DNSError).Error == noSuchHost {
- break
- }
- }
- return
-}
-
-func convertRR_A(records []dnsRR) []IP {
- addrs := make([]IP, len(records))
- for i, rr := range records {
- a := rr.(*dnsRR_A).A
- addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
- }
- return addrs
-}
-
-func convertRR_AAAA(records []dnsRR) []IP {
- addrs := make([]IP, len(records))
- for i, rr := range records {
- a := make(IP, 16)
- copy(a, rr.(*dnsRR_AAAA).AAAA[:])
- addrs[i] = a
- }
- return addrs
-}
-
-var cfg *dnsConfig
-var dnserr os.Error
-
-func loadConfig() { cfg, dnserr = dnsReadConfig() }
-
func isDomainName(s string) bool {
// See RFC 1035, RFC 3696.
if len(s) == 0 {
@@ -255,166 +163,63 @@ func isDomainName(s string) bool {
return ok
}
-var onceLoadConfig sync.Once
-
-func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
- if !isDomainName(name) {
- return name, nil, &DNSError{Error: "invalid domain name", Name: name}
- }
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
- // If name is rooted (trailing dot) or has enough dots,
- // try it by itself first.
- rooted := len(name) > 0 && name[len(name)-1] == '.'
- if rooted || count(name, '.') >= cfg.ndots {
- rname := name
- if !rooted {
- rname += "."
- }
- // Can try as ordinary name.
- cname, addrs, err = tryOneName(cfg, rname, qtype)
- if err == nil {
- return
- }
- }
- if rooted {
- return
- }
+// An SRV represents a single DNS SRV record.
+type SRV struct {
+ Target string
+ Port uint16
+ Priority uint16
+ Weight uint16
+}
- // Otherwise, try suffixes.
- for i := 0; i < len(cfg.search); i++ {
- rname := name + "." + cfg.search[i]
- if rname[len(rname)-1] != '.' {
- rname += "."
- }
- cname, addrs, err = tryOneName(cfg, rname, qtype)
- if err == nil {
- return
- }
- }
+// byPriorityWeight sorts SRV records by ascending priority and weight.
+type byPriorityWeight []*SRV
- // Last ditch effort: try unsuffixed.
- rname := name
- if !rooted {
- rname += "."
- }
- cname, addrs, err = tryOneName(cfg, rname, qtype)
- if err == nil {
- return
- }
- return
-}
+func (s byPriorityWeight) Len() int { return len(s) }
-// goLookupHost is the native Go implementation of LookupHost.
-// Used only if cgoLookupHost refuses to handle the request
-// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupHost(name string) (addrs []string, err os.Error) {
- // Use entries from /etc/hosts if they match.
- addrs = lookupStaticHost(name)
- if len(addrs) > 0 {
- return
- }
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
- ips, err := goLookupIP(name)
- if err != nil {
- return
- }
- addrs = make([]string, 0, len(ips))
- for _, ip := range ips {
- addrs = append(addrs, ip.String())
- }
- return
-}
+func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-// goLookupIP is the native Go implementation of LookupIP.
-// Used only if cgoLookupIP refuses to handle the request
-// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupIP(name string) (addrs []IP, err os.Error) {
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
- }
- var records []dnsRR
- var cname string
- cname, records, err = lookup(name, dnsTypeA)
- if err != nil {
- return
- }
- addrs = convertRR_A(records)
- if cname != "" {
- name = cname
- }
- _, records, err = lookup(name, dnsTypeAAAA)
- if err != nil && len(addrs) > 0 {
- // Ignore error because A lookup succeeded.
- err = nil
- }
- if err != nil {
- return
- }
- addrs = append(addrs, convertRR_AAAA(records)...)
- return
+func (s byPriorityWeight) Less(i, j int) bool {
+ return s[i].Priority < s[j].Priority ||
+ (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
}
-// goLookupCNAME is the native Go implementation of LookupCNAME.
-// Used only if cgoLookupCNAME refuses to handle the request
-// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of
-// depending on our lookup code, so that Go and C get the same
-// answers.
-func goLookupCNAME(name string) (cname string, err os.Error) {
- onceLoadConfig.Do(loadConfig)
- if dnserr != nil || cfg == nil {
- err = dnserr
- return
+// shuffleByWeight shuffles SRV records by weight using the algorithm
+// described in RFC 2782.
+func (addrs byPriorityWeight) shuffleByWeight() {
+ sum := 0
+ for _, addr := range addrs {
+ sum += int(addr.Weight)
}
- _, rr, err := lookup(name, dnsTypeCNAME)
- if err != nil {
- return
+ for sum > 0 && len(addrs) > 1 {
+ s := 0
+ n := rand.Intn(sum + 1)
+ for i := range addrs {
+ s += int(addrs[i].Weight)
+ if s >= n {
+ if i > 0 {
+ t := addrs[i]
+ copy(addrs[1:i+1], addrs[0:i])
+ addrs[0] = t
+ }
+ break
+ }
+ }
+ sum -= int(addrs[0].Weight)
+ addrs = addrs[1:]
}
- cname = rr[0].(*dnsRR_CNAME).Cname
- return
}
-// An SRV represents a single DNS SRV record.
-type SRV struct {
- Target string
- Port uint16
- Priority uint16
- Weight uint16
-}
-
-// LookupSRV tries to resolve an SRV query of the given service,
-// protocol, and domain name, as specified in RFC 2782. In most cases
-// the proto argument can be the same as the corresponding
-// Addr.Network().
-func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
- target := "_" + service + "._" + proto + "." + name
- var records []dnsRR
- cname, records, err = lookup(target, dnsTypeSRV)
- if err != nil {
- return
- }
- addrs = make([]*SRV, len(records))
- for i, rr := range records {
- r := rr.(*dnsRR_SRV)
- addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
+// 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
+ }
}
- return
+ addrs[i:].shuffleByWeight()
}
// An MX represents a single DNS MX record.
@@ -432,72 +237,11 @@ 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] }
-// LookupMX returns the DNS MX records for the given domain name sorted by preference.
-func LookupMX(name string) (mx []*MX, err os.Error) {
- _, rr, err := lookup(name, dnsTypeMX)
- if err != nil {
- return
- }
- mx = make([]*MX, len(rr))
- for i := range rr {
- 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 {
+// sort reorders MX records as specified in RFC 5321.
+func (s byPref) sort() {
+ for i := range s {
j := rand.Intn(i + 1)
- mx[i], mx[j] = mx[j], mx[i]
- }
- sort.Sort(byPref(mx))
- return
-}
-
-// reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
-// address addr suitable for rDNS (PTR) record lookup or an error if it fails
-// to parse the IP address.
-func reverseaddr(addr string) (arpa string, err os.Error) {
- ip := ParseIP(addr)
- if ip == nil {
- return "", &DNSError{Error: "unrecognized address", Name: addr}
- }
- if ip.To4() != nil {
- return fmt.Sprintf("%d.%d.%d.%d.in-addr.arpa.", ip[15], ip[14], ip[13], ip[12]), nil
- }
- // Must be IPv6
- var buf bytes.Buffer
- // Add it, in reverse, to the buffer
- for i := len(ip) - 1; i >= 0; i-- {
- s := fmt.Sprintf("%02x", ip[i])
- buf.WriteByte(s[1])
- buf.WriteByte('.')
- buf.WriteByte(s[0])
- buf.WriteByte('.')
- }
- // Append "ip6.arpa." and return (buf already has the final .)
- return buf.String() + "ip6.arpa.", nil
-}
-
-// LookupAddr performs a reverse lookup for the given address, returning a list
-// of names mapping to that address.
-func LookupAddr(addr string) (name []string, err os.Error) {
- name = lookupStaticAddr(addr)
- if len(name) > 0 {
- return
- }
- var arpa string
- arpa, err = reverseaddr(addr)
- if err != nil {
- return
- }
- var records []dnsRR
- _, records, err = lookup(arpa, dnsTypePTR)
- if err != nil {
- return
- }
- name = make([]string, len(records))
- for i := range records {
- r := records[i].(*dnsRR_PTR)
- name[i] = r.Ptr
+ s[i], s[j] = s[j], s[i]
}
- return
+ sort.Sort(s)
}
diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go
new file mode 100644
index 0000000..f407b17
--- /dev/null
+++ b/libgo/go/net/dnsclient_unix.go
@@ -0,0 +1,261 @@
+// 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.
+
+// DNS client: see RFC 1035.
+// Has to be linked into package net for Dial.
+
+// TODO(rsc):
+// Check periodically whether /etc/resolv.conf has changed.
+// Could potentially handle many outstanding lookups faster.
+// Could have a small cache.
+// Random UDP source port (net.Dial should do that for us).
+// Random request IDs.
+
+package net
+
+import (
+ "os"
+ "rand"
+ "sync"
+ "time"
+)
+
+// Send a request on the connection and hope for a reply.
+// Up to cfg.attempts attempts.
+func exchange(cfg *dnsConfig, c Conn, name string, qtype uint16) (*dnsMsg, os.Error) {
+ if len(name) >= 256 {
+ return nil, &DNSError{Error: "name too long", Name: name}
+ }
+ out := new(dnsMsg)
+ out.id = uint16(rand.Int()) ^ uint16(time.Nanoseconds())
+ out.question = []dnsQuestion{
+ {name, qtype, dnsClassINET},
+ }
+ out.recursion_desired = true
+ msg, ok := out.Pack()
+ if !ok {
+ return nil, &DNSError{Error: "internal error - cannot pack message", Name: name}
+ }
+
+ for attempt := 0; attempt < cfg.attempts; attempt++ {
+ n, err := c.Write(msg)
+ if err != nil {
+ return nil, err
+ }
+
+ c.SetReadTimeout(int64(cfg.timeout) * 1e9) // nanoseconds
+
+ buf := make([]byte, 2000) // More than enough.
+ n, err = c.Read(buf)
+ if err != nil {
+ if e, ok := err.(Error); ok && e.Timeout() {
+ continue
+ }
+ return nil, err
+ }
+ buf = buf[0:n]
+ in := new(dnsMsg)
+ if !in.Unpack(buf) || in.id != out.id {
+ continue
+ }
+ return in, nil
+ }
+ var server string
+ if a := c.RemoteAddr(); a != nil {
+ server = a.String()
+ }
+ return nil, &DNSError{Error: "no answer from server", Name: name, Server: server, IsTimeout: true}
+}
+
+// Do a lookup for a single name, which must be rooted
+// (otherwise answer will not find the answers).
+func tryOneName(cfg *dnsConfig, name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
+ if len(cfg.servers) == 0 {
+ return "", nil, &DNSError{Error: "no DNS servers", Name: name}
+ }
+ for i := 0; i < len(cfg.servers); i++ {
+ // Calling Dial here is scary -- we have to be sure
+ // not to dial a name that will require a DNS lookup,
+ // or Dial will call back here to translate it.
+ // The DNS config parser has already checked that
+ // all the cfg.servers[i] are IP addresses, which
+ // Dial will use without a DNS lookup.
+ server := cfg.servers[i] + ":53"
+ c, cerr := Dial("udp", server)
+ if cerr != nil {
+ err = cerr
+ continue
+ }
+ msg, merr := exchange(cfg, c, name, qtype)
+ c.Close()
+ if merr != nil {
+ err = merr
+ continue
+ }
+ cname, addrs, err = answer(name, server, msg, qtype)
+ if err == nil || err.(*DNSError).Error == noSuchHost {
+ break
+ }
+ }
+ return
+}
+
+func convertRR_A(records []dnsRR) []IP {
+ addrs := make([]IP, len(records))
+ for i, rr := range records {
+ a := rr.(*dnsRR_A).A
+ addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
+ }
+ return addrs
+}
+
+func convertRR_AAAA(records []dnsRR) []IP {
+ addrs := make([]IP, len(records))
+ for i, rr := range records {
+ a := make(IP, 16)
+ copy(a, rr.(*dnsRR_AAAA).AAAA[:])
+ addrs[i] = a
+ }
+ return addrs
+}
+
+var cfg *dnsConfig
+var dnserr os.Error
+
+func loadConfig() { cfg, dnserr = dnsReadConfig() }
+
+var onceLoadConfig sync.Once
+
+func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
+ if !isDomainName(name) {
+ return name, nil, &DNSError{Error: "invalid domain name", Name: name}
+ }
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ // If name is rooted (trailing dot) or has enough dots,
+ // try it by itself first.
+ rooted := len(name) > 0 && name[len(name)-1] == '.'
+ if rooted || count(name, '.') >= cfg.ndots {
+ rname := name
+ if !rooted {
+ rname += "."
+ }
+ // Can try as ordinary name.
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ }
+ if rooted {
+ return
+ }
+
+ // Otherwise, try suffixes.
+ for i := 0; i < len(cfg.search); i++ {
+ rname := name + "." + cfg.search[i]
+ if rname[len(rname)-1] != '.' {
+ rname += "."
+ }
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ }
+
+ // Last ditch effort: try unsuffixed.
+ rname := name
+ if !rooted {
+ rname += "."
+ }
+ cname, addrs, err = tryOneName(cfg, rname, qtype)
+ if err == nil {
+ return
+ }
+ return
+}
+
+// goLookupHost is the native Go implementation of LookupHost.
+// Used only if cgoLookupHost refuses to handle the request
+// (that is, only if cgoLookupHost is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupHost(name string) (addrs []string, err os.Error) {
+ // Use entries from /etc/hosts if they match.
+ addrs = lookupStaticHost(name)
+ if len(addrs) > 0 {
+ return
+ }
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ ips, err := goLookupIP(name)
+ if err != nil {
+ return
+ }
+ addrs = make([]string, 0, len(ips))
+ for _, ip := range ips {
+ addrs = append(addrs, ip.String())
+ }
+ return
+}
+
+// goLookupIP is the native Go implementation of LookupIP.
+// Used only if cgoLookupIP refuses to handle the request
+// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupIP(name string) (addrs []IP, err os.Error) {
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ var records []dnsRR
+ var cname string
+ cname, records, err = lookup(name, dnsTypeA)
+ if err != nil {
+ return
+ }
+ addrs = convertRR_A(records)
+ if cname != "" {
+ name = cname
+ }
+ _, records, err = lookup(name, dnsTypeAAAA)
+ if err != nil && len(addrs) > 0 {
+ // Ignore error because A lookup succeeded.
+ err = nil
+ }
+ if err != nil {
+ return
+ }
+ addrs = append(addrs, convertRR_AAAA(records)...)
+ return
+}
+
+// goLookupCNAME is the native Go implementation of LookupCNAME.
+// Used only if cgoLookupCNAME refuses to handle the request
+// (that is, only if cgoLookupCNAME is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupCNAME(name string) (cname string, err os.Error) {
+ onceLoadConfig.Do(loadConfig)
+ if dnserr != nil || cfg == nil {
+ err = dnserr
+ return
+ }
+ _, rr, err := lookup(name, dnsTypeCNAME)
+ if err != nil {
+ return
+ }
+ cname = rr[0].(*dnsRR_CNAME).Cname
+ return
+}
diff --git a/libgo/go/net/dnsconfig.go b/libgo/go/net/dnsconfig.go
index 26f0e04..54e3343 100644
--- a/libgo/go/net/dnsconfig.go
+++ b/libgo/go/net/dnsconfig.go
@@ -30,7 +30,6 @@ func (e *DNSConfigError) String() string {
func (e *DNSConfigError) Timeout() bool { return false }
func (e *DNSConfigError) Temporary() bool { return false }
-
// See resolv.conf(5) on a Linux machine.
// TODO(rsc): Supposed to call uname() and chop the beginning
// of the host name to get the default search domain.
diff --git a/libgo/go/net/dnsmsg.go b/libgo/go/net/dnsmsg.go
index 731efe2..7595aa2 100644
--- a/libgo/go/net/dnsmsg.go
+++ b/libgo/go/net/dnsmsg.go
@@ -93,7 +93,7 @@ const (
// DNS queries.
type dnsQuestion struct {
- Name string "domain-name" // "domain-name" specifies encoding; see packers below
+ Name string `net:"domain-name"` // `net:"domain-name"` specifies encoding; see packers below
Qtype uint16
Qclass uint16
}
@@ -102,7 +102,7 @@ type dnsQuestion struct {
// There are many types of messages,
// but they all share the same header.
type dnsRR_Header struct {
- Name string "domain-name"
+ Name string `net:"domain-name"`
Rrtype uint16
Class uint16
Ttl uint32
@@ -117,12 +117,11 @@ type dnsRR interface {
Header() *dnsRR_Header
}
-
// Specific DNS RR formats for each query type.
type dnsRR_CNAME struct {
Hdr dnsRR_Header
- Cname string "domain-name"
+ Cname string `net:"domain-name"`
}
func (rr *dnsRR_CNAME) Header() *dnsRR_Header {
@@ -141,7 +140,7 @@ func (rr *dnsRR_HINFO) Header() *dnsRR_Header {
type dnsRR_MB struct {
Hdr dnsRR_Header
- Mb string "domain-name"
+ Mb string `net:"domain-name"`
}
func (rr *dnsRR_MB) Header() *dnsRR_Header {
@@ -150,7 +149,7 @@ func (rr *dnsRR_MB) Header() *dnsRR_Header {
type dnsRR_MG struct {
Hdr dnsRR_Header
- Mg string "domain-name"
+ Mg string `net:"domain-name"`
}
func (rr *dnsRR_MG) Header() *dnsRR_Header {
@@ -159,8 +158,8 @@ func (rr *dnsRR_MG) Header() *dnsRR_Header {
type dnsRR_MINFO struct {
Hdr dnsRR_Header
- Rmail string "domain-name"
- Email string "domain-name"
+ Rmail string `net:"domain-name"`
+ Email string `net:"domain-name"`
}
func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
@@ -169,7 +168,7 @@ func (rr *dnsRR_MINFO) Header() *dnsRR_Header {
type dnsRR_MR struct {
Hdr dnsRR_Header
- Mr string "domain-name"
+ Mr string `net:"domain-name"`
}
func (rr *dnsRR_MR) Header() *dnsRR_Header {
@@ -179,7 +178,7 @@ func (rr *dnsRR_MR) Header() *dnsRR_Header {
type dnsRR_MX struct {
Hdr dnsRR_Header
Pref uint16
- Mx string "domain-name"
+ Mx string `net:"domain-name"`
}
func (rr *dnsRR_MX) Header() *dnsRR_Header {
@@ -188,7 +187,7 @@ func (rr *dnsRR_MX) Header() *dnsRR_Header {
type dnsRR_NS struct {
Hdr dnsRR_Header
- Ns string "domain-name"
+ Ns string `net:"domain-name"`
}
func (rr *dnsRR_NS) Header() *dnsRR_Header {
@@ -197,7 +196,7 @@ func (rr *dnsRR_NS) Header() *dnsRR_Header {
type dnsRR_PTR struct {
Hdr dnsRR_Header
- Ptr string "domain-name"
+ Ptr string `net:"domain-name"`
}
func (rr *dnsRR_PTR) Header() *dnsRR_Header {
@@ -206,8 +205,8 @@ func (rr *dnsRR_PTR) Header() *dnsRR_Header {
type dnsRR_SOA struct {
Hdr dnsRR_Header
- Ns string "domain-name"
- Mbox string "domain-name"
+ Ns string `net:"domain-name"`
+ Mbox string `net:"domain-name"`
Serial uint32
Refresh uint32
Retry uint32
@@ -233,7 +232,7 @@ type dnsRR_SRV struct {
Priority uint16
Weight uint16
Port uint16
- Target string "domain-name"
+ Target string `net:"domain-name"`
}
func (rr *dnsRR_SRV) Header() *dnsRR_Header {
@@ -242,7 +241,7 @@ func (rr *dnsRR_SRV) Header() *dnsRR_Header {
type dnsRR_A struct {
Hdr dnsRR_Header
- A uint32 "ipv4"
+ A uint32 `net:"ipv4"`
}
func (rr *dnsRR_A) Header() *dnsRR_Header {
@@ -251,7 +250,7 @@ func (rr *dnsRR_A) Header() *dnsRR_Header {
type dnsRR_AAAA struct {
Hdr dnsRR_Header
- AAAA [16]byte "ipv6"
+ AAAA [16]byte `net:"ipv6"`
}
func (rr *dnsRR_AAAA) Header() *dnsRR_Header {
@@ -395,7 +394,6 @@ func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool)
f := val.Type().Field(i)
switch fv := val.Field(i); fv.Kind() {
default:
- BadType:
fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
return len(msg), false
case reflect.Struct:
@@ -420,7 +418,8 @@ func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool)
off += 4
case reflect.Array:
if fv.Type().Elem().Kind() != reflect.Uint8 {
- goto BadType
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
}
n := fv.Len()
if off+n > len(msg) {
@@ -436,7 +435,7 @@ func packStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok bool)
default:
fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
return len(msg), false
- case "domain-name":
+ case `net:"domain-name"`:
off, ok = packDomainName(s, msg, off)
if !ok {
return len(msg), false
@@ -472,7 +471,6 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
f := val.Type().Field(i)
switch fv := val.Field(i); fv.Kind() {
default:
- BadType:
fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
return len(msg), false
case reflect.Struct:
@@ -493,7 +491,8 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
off += 4
case reflect.Array:
if fv.Type().Elem().Kind() != reflect.Uint8 {
- goto BadType
+ fmt.Fprintf(os.Stderr, "net: dns: unknown packing type %v", f.Type)
+ return len(msg), false
}
n := fv.Len()
if off+n > len(msg) {
@@ -507,7 +506,7 @@ func unpackStructValue(val reflect.Value, msg []byte, off int) (off1 int, ok boo
default:
fmt.Fprintf(os.Stderr, "net: dns: unknown string tag %v", f.Tag)
return len(msg), false
- case "domain-name":
+ case `net:"domain-name"`:
s, off, ok = unpackDomainName(msg, off)
if !ok {
return len(msg), false
@@ -537,9 +536,9 @@ func unpackStruct(any interface{}, msg []byte, off int) (off1 int, ok bool) {
}
// Generic struct printer.
-// Doesn't care about the string tag "domain-name",
-// but does look for an "ipv4" tag on uint32 variables
-// and the "ipv6" tag on array variables,
+// Doesn't care about the string tag `net:"domain-name"`,
+// but does look for an `net:"ipv4"` tag on uint32 variables
+// and the `net:"ipv6"` tag on array variables,
// printing them as IP addresses.
func printStructValue(val reflect.Value) string {
s := "{"
@@ -554,10 +553,10 @@ func printStructValue(val reflect.Value) string {
fval := val.Field(i)
if fv := fval; fv.Kind() == reflect.Struct {
s += printStructValue(fv)
- } else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == "ipv4" {
+ } else if fv := fval; (fv.Kind() == reflect.Uint || fv.Kind() == reflect.Uint8 || fv.Kind() == reflect.Uint16 || fv.Kind() == reflect.Uint32 || fv.Kind() == reflect.Uint64 || fv.Kind() == reflect.Uintptr) && f.Tag == `net:"ipv4"` {
i := fv.Uint()
s += IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i)).String()
- } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == "ipv6" {
+ } else if fv := fval; fv.Kind() == reflect.Array && f.Tag == `net:"ipv6"` {
i := fv.Interface().([]byte)
s += IP(i).String()
} else {
@@ -636,7 +635,6 @@ type dnsMsg struct {
extra []dnsRR
}
-
func (dns *dnsMsg) Pack() (msg []byte, ok bool) {
var dh dnsHeader
diff --git a/libgo/go/net/dnsmsg_test.go b/libgo/go/net/dnsmsg_test.go
index 20c9f02..06152a0 100644
--- a/libgo/go/net/dnsmsg_test.go
+++ b/libgo/go/net/dnsmsg_test.go
@@ -6,14 +6,10 @@ package net
import (
"encoding/hex"
- "runtime"
"testing"
)
func TestDNSParseSRVReply(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
data, err := hex.DecodeString(dnsSRVReply)
if err != nil {
t.Fatal(err)
@@ -45,9 +41,6 @@ func TestDNSParseSRVReply(t *testing.T) {
}
func TestDNSParseCorruptSRVReply(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
data, err := hex.DecodeString(dnsSRVCorruptReply)
if err != nil {
t.Fatal(err)
diff --git a/libgo/go/net/dnsname_test.go b/libgo/go/net/dnsname_test.go
index 0c1a625..70df693 100644
--- a/libgo/go/net/dnsname_test.go
+++ b/libgo/go/net/dnsname_test.go
@@ -6,7 +6,6 @@ package net
import (
"testing"
- "runtime"
)
type testCase struct {
@@ -55,9 +54,6 @@ func getTestCases(ch chan<- testCase) {
}
func TestDNSNames(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
ch := make(chan testCase)
go getTestCases(ch)
for tc := range ch {
diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go
index cd1a21d..707dcca 100644
--- a/libgo/go/net/fd.go
+++ b/libgo/go/net/fd.go
@@ -585,20 +585,25 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
fd.incref()
defer fd.decref()
+ if fd.rdeadline_delta > 0 {
+ fd.rdeadline = pollserver.Now() + fd.rdeadline_delta
+ } else {
+ fd.rdeadline = 0
+ }
// See ../syscall/exec.go for description of ForkLock.
// It is okay to hold the lock across syscall.Accept
// because we have put fd.sysfd into non-blocking mode.
syscall.ForkLock.RLock()
var s, e int
- var sa syscall.Sockaddr
+ var rsa syscall.Sockaddr
for {
if fd.closing {
syscall.ForkLock.RUnlock()
return nil, os.EINVAL
}
- s, sa, e = syscall.Accept(fd.sysfd)
- if e != syscall.EAGAIN {
+ s, rsa, e = syscall.Accept(fd.sysfd)
+ if e != syscall.EAGAIN || fd.rdeadline < 0 {
break
}
syscall.ForkLock.RUnlock()
@@ -616,7 +621,8 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
syscall.Close(s)
return nil, err
}
- nfd.setAddr(fd.laddr, toAddr(sa))
+ lsa, _ := syscall.Getsockname(nfd.sysfd)
+ nfd.setAddr(toAddr(lsa), toAddr(rsa))
return nfd, nil
}
diff --git a/libgo/go/net/fd_linux.go b/libgo/go/net/fd_linux.go
index dcf65c0..70fc344b 100644
--- a/libgo/go/net/fd_linux.go
+++ b/libgo/go/net/fd_linux.go
@@ -117,6 +117,17 @@ func (p *pollster) DelFD(fd int, mode int) {
} else {
p.StopWaiting(fd, writeFlags)
}
+
+ // Discard any queued up events.
+ i := 0
+ for i < len(p.waitEvents) {
+ if fd == int(p.waitEvents[i].Fd) {
+ copy(p.waitEvents[i:], p.waitEvents[i+1:])
+ p.waitEvents = p.waitEvents[:len(p.waitEvents)-1]
+ } else {
+ i++
+ }
+ }
}
func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err os.Error) {
diff --git a/libgo/go/net/fd_openbsd.go b/libgo/go/net/fd_openbsd.go
new file mode 100644
index 0000000..e50883e
--- /dev/null
+++ b/libgo/go/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/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go
index c2f736c..3757e14 100644
--- a/libgo/go/net/fd_windows.go
+++ b/libgo/go/net/fd_windows.go
@@ -29,8 +29,8 @@ func init() {
}
}
-func closesocket(s int) (errno int) {
- return syscall.Closesocket(int32(s))
+func closesocket(s syscall.Handle) (errno int) {
+ return syscall.Closesocket(s)
}
// Interface for all io operations.
@@ -84,11 +84,11 @@ func (o *bufOp) Init(fd *netFD, buf []byte) {
}
}
-// resultSrv will retreive all io completion results from
+// resultSrv will retrieve all io completion results from
// iocp and send them to the correspondent waiting client
// goroutine via channel supplied in the request.
type resultSrv struct {
- iocp int32
+ iocp syscall.Handle
}
func (s *resultSrv) Run() {
@@ -113,7 +113,6 @@ func (s *resultSrv) Run() {
}
}
-
// ioSrv executes net io requests.
type ioSrv struct {
submchan chan anOpIface // submit io requests
@@ -132,7 +131,7 @@ func (s *ioSrv) ProcessRemoteIO() {
case o := <-s.submchan:
o.Op().errnoc <- o.Submit()
case o := <-s.canchan:
- o.Op().errnoc <- syscall.CancelIo(uint32(o.Op().fd.sysfd))
+ o.Op().errnoc <- syscall.CancelIo(syscall.Handle(o.Op().fd.sysfd))
}
}
}
@@ -155,7 +154,7 @@ func (s *ioSrv) ExecIO(oi anOpIface, deadline_delta int64) (n int, err os.Error)
case 0:
// IO completed immediately, but we need to get our completion message anyway.
case syscall.ERROR_IO_PENDING:
- // IO started, and we have to wait for it's completion.
+ // IO started, and we have to wait for its completion.
default:
return 0, &OpError{oi.Name(), o.fd.net, o.fd.laddr, os.Errno(e)}
}
@@ -189,7 +188,7 @@ var onceStartServer sync.Once
func startServer() {
resultsrv = new(resultSrv)
var errno int
- resultsrv.iocp, errno = syscall.CreateIoCompletionPort(-1, 0, 0, 1)
+ resultsrv.iocp, errno = syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 1)
if errno != 0 {
panic("CreateIoCompletionPort failed " + syscall.Errstr(errno))
}
@@ -209,7 +208,7 @@ type netFD struct {
closing bool
// immutable until Close
- sysfd int
+ sysfd syscall.Handle
family int
proto int
net string
@@ -225,7 +224,7 @@ type netFD struct {
wio sync.Mutex
}
-func allocFD(fd, family, proto int, net string) (f *netFD) {
+func allocFD(fd syscall.Handle, family, proto int, net string) (f *netFD) {
f = &netFD{
sysfd: fd,
family: family,
@@ -236,13 +235,13 @@ func allocFD(fd, family, proto int, net string) (f *netFD) {
return f
}
-func newFD(fd, family, proto int, net string) (f *netFD, err os.Error) {
+func newFD(fd syscall.Handle, family, proto int, net string) (f *netFD, err os.Error) {
if initErr != nil {
return nil, initErr
}
onceStartServer.Do(startServer)
// Associate our socket with resultsrv.iocp.
- if _, e := syscall.CreateIoCompletionPort(int32(fd), resultsrv.iocp, 0, 0); e != 0 {
+ if _, e := syscall.CreateIoCompletionPort(syscall.Handle(fd), resultsrv.iocp, 0, 0); e != 0 {
return nil, os.Errno(e)
}
return allocFD(fd, family, proto, net), nil
@@ -273,14 +272,14 @@ func (fd *netFD) incref() {
func (fd *netFD) decref() {
fd.sysmu.Lock()
fd.sysref--
- if fd.closing && fd.sysref == 0 && fd.sysfd >= 0 {
+ if fd.closing && fd.sysref == 0 && fd.sysfd != syscall.InvalidHandle {
// In case the user has set linger, switch to blocking mode so
// the close blocks. As long as this doesn't happen often, we
// can handle the extra OS processes. Otherwise we'll need to
// use the resultsrv for Close too. Sigh.
syscall.SetNonblock(fd.sysfd, false)
closesocket(fd.sysfd)
- fd.sysfd = -1
+ fd.sysfd = syscall.InvalidHandle
// no need for a finalizer anymore
runtime.SetFinalizer(fd, nil)
}
@@ -288,7 +287,7 @@ func (fd *netFD) decref() {
}
func (fd *netFD) Close() os.Error {
- if fd == nil || fd.sysfd == -1 {
+ if fd == nil || fd.sysfd == syscall.InvalidHandle {
return os.EINVAL
}
@@ -307,7 +306,7 @@ type readOp struct {
func (o *readOp) Submit() (errno int) {
var d, f uint32
- return syscall.WSARecv(uint32(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
+ return syscall.WSARecv(syscall.Handle(o.fd.sysfd), &o.buf, 1, &d, &f, &o.o, nil)
}
func (o *readOp) Name() string {
@@ -322,7 +321,7 @@ func (fd *netFD) Read(buf []byte) (n int, err os.Error) {
defer fd.rio.Unlock()
fd.incref()
defer fd.decref()
- if fd.sysfd == -1 {
+ if fd.sysfd == syscall.InvalidHandle {
return 0, os.EINVAL
}
var o readOp
@@ -338,13 +337,13 @@ func (fd *netFD) Read(buf []byte) (n int, err os.Error) {
type readFromOp struct {
bufOp
- rsa syscall.RawSockaddrAny
+ rsa syscall.RawSockaddrAny
+ rsan int32
}
func (o *readFromOp) Submit() (errno int) {
var d, f uint32
- l := int32(unsafe.Sizeof(o.rsa))
- return syscall.WSARecvFrom(uint32(o.fd.sysfd), &o.buf, 1, &d, &f, &o.rsa, &l, &o.o, nil)
+ return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &d, &f, &o.rsa, &o.rsan, &o.o, nil)
}
func (o *readFromOp) Name() string {
@@ -362,12 +361,16 @@ func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err os.Error)
defer fd.rio.Unlock()
fd.incref()
defer fd.decref()
- if fd.sysfd == -1 {
+ if fd.sysfd == syscall.InvalidHandle {
return 0, nil, os.EINVAL
}
var o readFromOp
o.Init(fd, buf)
+ o.rsan = int32(unsafe.Sizeof(o.rsa))
n, err = iosrv.ExecIO(&o, fd.rdeadline_delta)
+ if err != nil {
+ return 0, nil, err
+ }
sa, _ = o.rsa.Sockaddr()
return
}
@@ -380,7 +383,7 @@ type writeOp struct {
func (o *writeOp) Submit() (errno int) {
var d uint32
- return syscall.WSASend(uint32(o.fd.sysfd), &o.buf, 1, &d, 0, &o.o, nil)
+ return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &d, 0, &o.o, nil)
}
func (o *writeOp) Name() string {
@@ -395,7 +398,7 @@ func (fd *netFD) Write(buf []byte) (n int, err os.Error) {
defer fd.wio.Unlock()
fd.incref()
defer fd.decref()
- if fd.sysfd == -1 {
+ if fd.sysfd == syscall.InvalidHandle {
return 0, os.EINVAL
}
var o writeOp
@@ -412,7 +415,7 @@ type writeToOp struct {
func (o *writeToOp) Submit() (errno int) {
var d uint32
- return syscall.WSASendto(uint32(o.fd.sysfd), &o.buf, 1, &d, 0, o.sa, &o.o, nil)
+ return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &d, 0, o.sa, &o.o, nil)
}
func (o *writeToOp) Name() string {
@@ -430,7 +433,7 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error)
defer fd.wio.Unlock()
fd.incref()
defer fd.decref()
- if fd.sysfd == -1 {
+ if fd.sysfd == syscall.InvalidHandle {
return 0, os.EINVAL
}
var o writeToOp
@@ -443,14 +446,14 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (n int, err os.Error)
type acceptOp struct {
anOp
- newsock int
+ newsock syscall.Handle
attrs [2]syscall.RawSockaddrAny // space for local and remote address only
}
func (o *acceptOp) Submit() (errno int) {
var d uint32
l := uint32(unsafe.Sizeof(o.attrs[0]))
- return syscall.AcceptEx(uint32(o.fd.sysfd), uint32(o.newsock),
+ return syscall.AcceptEx(o.fd.sysfd, o.newsock,
(*byte)(unsafe.Pointer(&o.attrs[0])), 0, l, l, &d, &o.o)
}
@@ -459,7 +462,7 @@ func (o *acceptOp) Name() string {
}
func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.Error) {
- if fd == nil || fd.sysfd == -1 {
+ if fd == nil || fd.sysfd == syscall.InvalidHandle {
return nil, os.EINVAL
}
fd.incref()
@@ -478,7 +481,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
// Associate our new socket with IOCP.
onceStartServer.Do(startServer)
- if _, e = syscall.CreateIoCompletionPort(int32(s), resultsrv.iocp, 0, 0); e != 0 {
+ if _, e = syscall.CreateIoCompletionPort(s, resultsrv.iocp, 0, 0); e != 0 {
return nil, &OpError{"CreateIoCompletionPort", fd.net, fd.laddr, os.Errno(e)}
}
@@ -493,7 +496,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
}
// Inherit properties of the listening socket.
- e = syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, fd.sysfd)
+ e = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
if e != 0 {
closesocket(s)
return nil, err
@@ -513,7 +516,7 @@ func (fd *netFD) accept(toAddr func(syscall.Sockaddr) Addr) (nfd *netFD, err os.
return nfd, nil
}
-// Not implemeted functions.
+// Unimplemented functions.
func (fd *netFD) dup() (f *os.File, err os.Error) {
// TODO: Implement this
diff --git a/libgo/go/net/file_plan9.go b/libgo/go/net/file_plan9.go
new file mode 100644
index 0000000..a07e743
--- /dev/null
+++ b/libgo/go/net/file_plan9.go
@@ -0,0 +1,33 @@
+// 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.
+
+package net
+
+import (
+ "os"
+)
+
+// FileConn returns a copy of the network connection corresponding to
+// the open file f. It is the caller's responsibility to close f when
+// finished. Closing c does not affect f, and closing f does not
+// affect c.
+func FileConn(f *os.File) (c Conn, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// FileListener returns a copy of the network listener corresponding
+// to the open file f. It is the caller's responsibility to close l
+// when finished. Closing c does not affect l, and closing l does not
+// affect c.
+func FileListener(f *os.File) (l Listener, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f. It is the caller's
+// responsibility to close f when finished. Closing c does not affect
+// f, and closing f does not affect c.
+func FilePacketConn(f *os.File) (c PacketConn, err os.Error) {
+ return nil, os.EPLAN9
+}
diff --git a/libgo/go/net/file_test.go b/libgo/go/net/file_test.go
index 1ec05fd..9a8c2dc 100644
--- a/libgo/go/net/file_test.go
+++ b/libgo/go/net/file_test.go
@@ -57,12 +57,12 @@ func testFileListener(t *testing.T, net, laddr string) {
}
func TestFileListener(t *testing.T) {
- if runtime.GOOS == "windows" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
testFileListener(t, "tcp", "127.0.0.1")
testFileListener(t, "tcp", "127.0.0.1")
- if kernelSupportsIPv6() {
+ if supportsIPv6 && supportsIPv4map {
testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
testFileListener(t, "tcp", "127.0.0.1")
testFileListener(t, "tcp", "[::ffff:127.0.0.1]")
@@ -116,13 +116,15 @@ func testFilePacketConnDial(t *testing.T, net, raddr string) {
}
func TestFilePacketConn(t *testing.T) {
- if runtime.GOOS == "windows" {
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
testFilePacketConnListen(t, "udp", "127.0.0.1:0")
testFilePacketConnDial(t, "udp", "127.0.0.1:12345")
- if kernelSupportsIPv6() {
+ if supportsIPv6 {
testFilePacketConnListen(t, "udp", "[::1]:0")
+ }
+ if supportsIPv6 && supportsIPv4map {
testFilePacketConnDial(t, "udp", "[::ffff:127.0.0.1]:12345")
}
if syscall.OS == "linux" {
diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go
index e5793ee..1bd0054 100644
--- a/libgo/go/net/hosts_test.go
+++ b/libgo/go/net/hosts_test.go
@@ -59,7 +59,7 @@ func TestLookupHost(t *testing.T) {
// duplicate addresses (a common bug due to the way
// getaddrinfo works).
addrs, _ := LookupHost("localhost")
- sort.SortStrings(addrs)
+ sort.Strings(addrs)
for i := 0; i+1 < len(addrs); i++ {
if addrs[i] == addrs[i+1] {
t.Fatalf("LookupHost(\"localhost\") = %v, has duplicate addresses", addrs)
diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go
new file mode 100644
index 0000000..8a14cb2
--- /dev/null
+++ b/libgo/go/net/interface.go
@@ -0,0 +1,132 @@
+// 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
+
+package net
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+)
+
+// A HardwareAddr represents a physical hardware address.
+type HardwareAddr []byte
+
+func (a HardwareAddr) String() string {
+ var buf bytes.Buffer
+ for i, b := range a {
+ if i > 0 {
+ buf.WriteByte(':')
+ }
+ fmt.Fprintf(&buf, "%02x", b)
+ }
+ return buf.String()
+}
+
+// Interface represents a mapping between network interface name
+// and index. It also represents network interface facility
+// information.
+type Interface struct {
+ Index int // positive integer that starts at one, zero is never used
+ MTU int // maximum transmission unit
+ Name string // e.g., "en0", "lo0", "eth0.100"
+ HardwareAddr HardwareAddr // IEEE MAC-48, EUI-48 and EUI-64 form
+ Flags Flags // e.g., FlagUp, FlagLoopback, FlagMulticast
+}
+
+type Flags uint
+
+const (
+ FlagUp Flags = 1 << iota // interface is up
+ FlagBroadcast // interface supports broadcast access capability
+ FlagLoopback // interface is a loopback interface
+ FlagPointToPoint // interface belongs to a point-to-point link
+ FlagMulticast // interface supports multicast access capability
+)
+
+var flagNames = []string{
+ "up",
+ "broadcast",
+ "loopback",
+ "pointtopoint",
+ "multicast",
+}
+
+func (f Flags) String() string {
+ s := ""
+ for i, name := range flagNames {
+ if f&(1<<uint(i)) != 0 {
+ if s != "" {
+ s += "|"
+ }
+ s += name
+ }
+ }
+ if s == "" {
+ s = "0"
+ }
+ return s
+}
+
+// Addrs returns interface addresses for a specific interface.
+func (ifi *Interface) Addrs() ([]Addr, os.Error) {
+ if ifi == nil {
+ return nil, os.NewError("net: invalid interface")
+ }
+ 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)
+}
+
+// InterfaceAddrs returns a list of the system's network interface
+// addresses.
+func InterfaceAddrs() ([]Addr, os.Error) {
+ return interfaceAddrTable(0)
+}
+
+// InterfaceByIndex returns the interface specified by index.
+func InterfaceByIndex(index int) (*Interface, os.Error) {
+ if index <= 0 {
+ return nil, os.NewError("net: invalid interface index")
+ }
+ ift, err := interfaceTable(index)
+ if err != nil {
+ return nil, err
+ }
+ for _, ifi := range ift {
+ return &ifi, nil
+ }
+ return nil, os.NewError("net: no such interface")
+}
+
+// InterfaceByName returns the interface specified by name.
+func InterfaceByName(name string) (*Interface, os.Error) {
+ if name == "" {
+ return nil, os.NewError("net: invalid interface name")
+ }
+ ift, err := interfaceTable(0)
+ if err != nil {
+ return nil, err
+ }
+ for _, ifi := range ift {
+ if name == ifi.Name {
+ return &ifi, nil
+ }
+ }
+ return nil, os.NewError("net: no such interface")
+}
diff --git a/libgo/go/net/interface_bsd.go b/libgo/go/net/interface_bsd.go
new file mode 100644
index 0000000..2675f94
--- /dev/null
+++ b/libgo/go/net/interface_bsd.go
@@ -0,0 +1,171 @@
+// 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 BSD variants
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ift []Interface
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, 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.InterfaceMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifi, err := newLink(v)
+ if err != nil {
+ return nil, err
+ }
+ ift = append(ift, ifi...)
+ }
+ }
+ }
+
+ return ift, nil
+}
+
+func newLink(m *syscall.InterfaceMessage) ([]Interface, os.Error) {
+ var ift []Interface
+
+ 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.SockaddrDatalink:
+ // NOTE: SockaddrDatalink.Data is minimum work area,
+ // can be larger.
+ m.Data = m.Data[unsafe.Offsetof(v.Data):]
+ ifi := Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
+ var name [syscall.IFNAMSIZ]byte
+ for i := 0; i < int(v.Nlen); i++ {
+ name[i] = byte(m.Data[i])
+ }
+ ifi.Name = string(name[:v.Nlen])
+ ifi.MTU = int(m.Header.Data.Mtu)
+ addr := make([]byte, v.Alen)
+ for i := 0; i < int(v.Alen); i++ {
+ addr[i] = byte(m.Data[int(v.Nlen)+i])
+ }
+ ifi.HardwareAddr = addr[:v.Alen]
+ ift = append(ift, ifi)
+ }
+ }
+
+ return ift, nil
+}
+
+func linkFlags(rawFlags int32) Flags {
+ var f Flags
+ if rawFlags&syscall.IFF_UP != 0 {
+ f |= FlagUp
+ }
+ if rawFlags&syscall.IFF_BROADCAST != 0 {
+ f |= FlagBroadcast
+ }
+ if rawFlags&syscall.IFF_LOOPBACK != 0 {
+ f |= FlagLoopback
+ }
+ if rawFlags&syscall.IFF_POINTOPOINT != 0 {
+ f |= FlagPointToPoint
+ }
+ if rawFlags&syscall.IFF_MULTICAST != 0 {
+ f |= FlagMulticast
+ }
+ return f
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ msgs []syscall.RoutingMessage
+ ifat []Addr
+ )
+
+ tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, 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.InterfaceAddrMessage:
+ if ifindex == 0 || ifindex == int(v.Header.Index) {
+ ifa, err := newAddr(v)
+ if err != nil {
+ return nil, err
+ }
+ ifat = append(ifat, ifa...)
+ }
+ }
+ }
+
+ return ifat, nil
+}
+
+func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, os.Error) {
+ var ifat []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:
+ 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 := &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() {
+ // remove embedded scope zone ID
+ ifa.IP[2], ifa.IP[3] = 0, 0
+ }
+ ifat = append(ifat, ifa.toAddr())
+ }
+ }
+
+ return ifat, nil
+}
diff --git a/libgo/go/net/interface_darwin.go b/libgo/go/net/interface_darwin.go
new file mode 100644
index 0000000..a7b68ad
--- /dev/null
+++ b/libgo/go/net/interface_darwin.go
@@ -0,0 +1,80 @@
+// 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
+}
+
+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/libgo/go/net/interface_freebsd.go b/libgo/go/net/interface_freebsd.go
new file mode 100644
index 0000000..20f506b
--- /dev/null
+++ b/libgo/go/net/interface_freebsd.go
@@ -0,0 +1,80 @@
+// 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
+}
+
+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/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go
new file mode 100644
index 0000000..3d2a0bb
--- /dev/null
+++ b/libgo/go/net/interface_linux.go
@@ -0,0 +1,262 @@
+// 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 Linux
+
+package net
+
+import (
+ "fmt"
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ var (
+ ift []Interface
+ tab []byte
+ msgs []syscall.NetlinkMessage
+ e int
+ )
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+
+ msgs, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ goto done
+ case syscall.RTM_NEWLINK:
+ ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
+ if ifindex == 0 || ifindex == int(ifim.Index) {
+ attrs, e := syscall.ParseNetlinkRouteAttr(&m)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink routeattr", e)
+ }
+ ifi := newLink(attrs, ifim)
+ ift = append(ift, ifi)
+ }
+ }
+ }
+
+done:
+ return ift, nil
+}
+
+func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface {
+ ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)}
+ for _, a := range attrs {
+ switch a.Attr.Type {
+ case syscall.IFLA_ADDRESS:
+ var nonzero bool
+ for _, b := range a.Value {
+ if b != 0 {
+ nonzero = true
+ }
+ }
+ if nonzero {
+ ifi.HardwareAddr = a.Value[:]
+ }
+ case syscall.IFLA_IFNAME:
+ ifi.Name = string(a.Value[:len(a.Value)-1])
+ case syscall.IFLA_MTU:
+ ifi.MTU = int(uint32(a.Value[3])<<24 | uint32(a.Value[2])<<16 | uint32(a.Value[1])<<8 | uint32(a.Value[0]))
+ }
+ }
+ return ifi
+}
+
+func linkFlags(rawFlags uint32) Flags {
+ var f Flags
+ if rawFlags&syscall.IFF_UP != 0 {
+ f |= FlagUp
+ }
+ if rawFlags&syscall.IFF_BROADCAST != 0 {
+ f |= FlagBroadcast
+ }
+ if rawFlags&syscall.IFF_LOOPBACK != 0 {
+ f |= FlagLoopback
+ }
+ if rawFlags&syscall.IFF_POINTOPOINT != 0 {
+ f |= FlagPointToPoint
+ }
+ if rawFlags&syscall.IFF_MULTICAST != 0 {
+ f |= FlagMulticast
+ }
+ return f
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ var (
+ tab []byte
+ e int
+ err os.Error
+ ifat4 []Addr
+ ifat6 []Addr
+ msgs4 []syscall.NetlinkMessage
+ msgs6 []syscall.NetlinkMessage
+ )
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+ msgs4, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+ ifat4, err = addrTable(msgs4, ifindex)
+ if err != nil {
+ return nil, err
+ }
+
+ tab, e = syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_INET6)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink rib", e)
+ }
+ msgs6, e = syscall.ParseNetlinkMessage(tab)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink message", e)
+ }
+ ifat6, err = addrTable(msgs6, ifindex)
+ if err != nil {
+ return nil, err
+ }
+
+ return append(ifat4, ifat6...), nil
+}
+
+func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, os.Error) {
+ var ifat []Addr
+
+ for _, m := range msgs {
+ switch m.Header.Type {
+ case syscall.NLMSG_DONE:
+ goto done
+ case syscall.RTM_NEWADDR:
+ ifam := (*syscall.IfAddrmsg)(unsafe.Pointer(&m.Data[0]))
+ if ifindex == 0 || ifindex == int(ifam.Index) {
+ attrs, e := syscall.ParseNetlinkRouteAttr(&m)
+ if e != 0 {
+ return nil, os.NewSyscallError("netlink routeattr", e)
+ }
+ ifat = append(ifat, newAddr(attrs, int(ifam.Family))...)
+ }
+ }
+ }
+
+done:
+ return ifat, nil
+}
+
+func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr {
+ var ifat []Addr
+
+ for _, a := range attrs {
+ switch a.Attr.Type {
+ case syscall.IFA_ADDRESS:
+ switch family {
+ case syscall.AF_INET:
+ 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 := &IPAddr{IP: make(IP, IPv6len)}
+ copy(ifa.IP, a.Value[:])
+ 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/libgo/go/net/interface_openbsd.go b/libgo/go/net/interface_openbsd.go
new file mode 100644
index 0000000..f181493
--- /dev/null
+++ b/libgo/go/net/interface_openbsd.go
@@ -0,0 +1,16 @@
+// 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 OpenBSD
+
+package net
+
+import "os"
+
+// 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/libgo/go/net/interface_stub.go b/libgo/go/net/interface_stub.go
new file mode 100644
index 0000000..950de6c
--- /dev/null
+++ b/libgo/go/net/interface_stub.go
@@ -0,0 +1,30 @@
+// 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
+
+package net
+
+import "os"
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ return nil, nil
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+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/libgo/go/net/interface_test.go b/libgo/go/net/interface_test.go
new file mode 100644
index 0000000..0e4089a
--- /dev/null
+++ b/libgo/go/net/interface_test.go
@@ -0,0 +1,73 @@
+// 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.
+
+package net
+
+import (
+ "bytes"
+ "testing"
+)
+
+func sameInterface(i, j *Interface) bool {
+ if i == nil || j == nil {
+ return false
+ }
+ if i.Index == j.Index && i.Name == j.Name && bytes.Equal(i.HardwareAddr, j.HardwareAddr) {
+ return true
+ }
+ return false
+}
+
+func TestInterfaces(t *testing.T) {
+ ift, err := Interfaces()
+ if err != nil {
+ t.Fatalf("Interfaces() failed: %v", err)
+ }
+ t.Logf("table: len/cap = %v/%v\n", len(ift), cap(ift))
+
+ for _, ifi := range ift {
+ ifxi, err := InterfaceByIndex(ifi.Index)
+ if err != nil {
+ t.Fatalf("InterfaceByIndex(%#q) failed: %v", ifi.Index, err)
+ }
+ if !sameInterface(ifxi, &ifi) {
+ t.Fatalf("InterfaceByIndex(%#q) = %v, want %v", ifi.Index, *ifxi, ifi)
+ }
+ ifxn, err := InterfaceByName(ifi.Name)
+ if err != nil {
+ t.Fatalf("InterfaceByName(%#q) failed: %v", ifi.Name, err)
+ }
+ if !sameInterface(ifxn, &ifi) {
+ t.Fatalf("InterfaceByName(%#q) = %v, want %v", ifi.Name, *ifxn, ifi)
+ }
+ ifat, err := ifi.Addrs()
+ 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())
+ }
+}
+
+func TestInterfaceAddrs(t *testing.T) {
+ ifat, err := InterfaceAddrs()
+ if err != nil {
+ t.Fatalf("InterfaceAddrs() failed: %v", err)
+ }
+ t.Logf("table: len/cap = %v/%v\n", len(ifat), cap(ifat))
+
+ for _, ifa := range ifat {
+ t.Logf("interface address %q\n", ifa.String())
+ }
+}
diff --git a/libgo/go/net/interface_windows.go b/libgo/go/net/interface_windows.go
new file mode 100644
index 0000000..7f5169c
--- /dev/null
+++ b/libgo/go/net/interface_windows.go
@@ -0,0 +1,158 @@
+// 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 Windows
+
+package net
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+func bytePtrToString(p *uint8) string {
+ a := (*[10000]uint8)(unsafe.Pointer(p))
+ i := 0
+ for a[i] != 0 {
+ i++
+ }
+ return string(a[:i])
+}
+
+func getAdapterList() (*syscall.IpAdapterInfo, os.Error) {
+ b := make([]byte, 1000)
+ l := uint32(len(b))
+ a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
+ e := syscall.GetAdaptersInfo(a, &l)
+ if e == syscall.ERROR_BUFFER_OVERFLOW {
+ b = make([]byte, l)
+ a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
+ e = syscall.GetAdaptersInfo(a, &l)
+ }
+ if e != 0 {
+ return nil, os.NewSyscallError("GetAdaptersInfo", e)
+ }
+ return a, nil
+}
+
+func getInterfaceList() ([]syscall.InterfaceInfo, os.Error) {
+ s, e := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
+ if e != 0 {
+ return nil, os.NewSyscallError("Socket", e)
+ }
+ defer syscall.Closesocket(s)
+
+ ii := [20]syscall.InterfaceInfo{}
+ ret := uint32(0)
+ size := uint32(unsafe.Sizeof(ii))
+ e = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
+ if e != 0 {
+ return nil, os.NewSyscallError("WSAIoctl", e)
+ }
+ c := ret / uint32(unsafe.Sizeof(ii[0]))
+ return ii[:c-1], nil
+}
+
+// If the ifindex is zero, interfaceTable returns mappings of all
+// network interfaces. Otheriwse it returns a mapping of a specific
+// interface.
+func interfaceTable(ifindex int) ([]Interface, os.Error) {
+ ai, e := getAdapterList()
+ if e != nil {
+ return nil, e
+ }
+
+ ii, e := getInterfaceList()
+ if e != nil {
+ return nil, e
+ }
+
+ var ift []Interface
+ for ; ai != nil; ai = ai.Next {
+ index := ai.Index
+ if ifindex == 0 || ifindex == int(index) {
+ var flags Flags
+
+ row := syscall.MibIfRow{Index: index}
+ e := syscall.GetIfEntry(&row)
+ if e != 0 {
+ return nil, os.NewSyscallError("GetIfEntry", e)
+ }
+
+ for _, ii := range ii {
+ ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
+ ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3])
+ ipl := &ai.IpAddressList
+ for ipl != nil {
+ ips := bytePtrToString(&ipl.IpAddress.String[0])
+ if ipv4.Equal(parseIPv4(ips)) {
+ break
+ }
+ ipl = ipl.Next
+ }
+ if ipl == nil {
+ continue
+ }
+ if ii.Flags&syscall.IFF_UP != 0 {
+ flags |= FlagUp
+ }
+ if ii.Flags&syscall.IFF_LOOPBACK != 0 {
+ flags |= FlagLoopback
+ }
+ if ii.Flags&syscall.IFF_BROADCAST != 0 {
+ flags |= FlagBroadcast
+ }
+ if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
+ flags |= FlagPointToPoint
+ }
+ if ii.Flags&syscall.IFF_MULTICAST != 0 {
+ flags |= FlagMulticast
+ }
+ }
+
+ name := bytePtrToString(&ai.AdapterName[0])
+
+ ifi := Interface{
+ Index: int(index),
+ MTU: int(row.Mtu),
+ Name: name,
+ HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]),
+ Flags: flags}
+ ift = append(ift, ifi)
+ }
+ }
+ return ift, nil
+}
+
+// If the ifindex is zero, interfaceAddrTable returns addresses
+// for all network interfaces. Otherwise it returns addresses
+// for a specific interface.
+func interfaceAddrTable(ifindex int) ([]Addr, os.Error) {
+ ai, e := getAdapterList()
+ if e != nil {
+ return nil, e
+ }
+
+ var ifat []Addr
+ for ; ai != nil; ai = ai.Next {
+ index := ai.Index
+ if ifindex == 0 || ifindex == int(index) {
+ ipl := &ai.IpAddressList
+ for ; ipl != nil; ipl = ipl.Next {
+ ifa := IPAddr{}
+ ifa.IP = parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))
+ ifat = append(ifat, ifa.toAddr())
+ }
+ }
+ }
+ 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/libgo/go/net/ip.go b/libgo/go/net/ip.go
index 61b2c68..b0e2c42 100644
--- a/libgo/go/net/ip.go
+++ b/libgo/go/net/ip.go
@@ -75,10 +75,71 @@ var (
// Well-known IPv6 addresses
var (
- IPzero = make(IP, IPv6len) // all zeros
- IPv6loopback = IP([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1})
+ IPv6zero = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ IPv6unspecified = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+ IPv6loopback = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
+ IPv6interfacelocalallnodes = IP{0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
+ IPv6linklocalallnodes = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
+ IPv6linklocalallrouters = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02}
)
+// IsUnspecified returns true if ip is an unspecified address.
+func (ip IP) IsUnspecified() bool {
+ if ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified) {
+ return true
+ }
+ return false
+}
+
+// IsLoopback returns true if ip is a loopback address.
+func (ip IP) IsLoopback() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0] == 127 {
+ return true
+ }
+ return ip.Equal(IPv6loopback)
+}
+
+// IsMulticast returns true if ip is a multicast address.
+func (ip IP) IsMulticast() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0]&0xf0 == 0xe0 {
+ return true
+ }
+ return ip[0] == 0xff
+}
+
+// IsInterfaceLinkLocalMulticast returns true if ip is
+// an interface-local multicast address.
+func (ip IP) IsInterfaceLocalMulticast() bool {
+ return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01
+}
+
+// IsLinkLocalMulticast returns true if ip is a link-local
+// multicast address.
+func (ip IP) IsLinkLocalMulticast() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0 {
+ return true
+ }
+ return ip[0] == 0xff && ip[1]&0x0f == 0x02
+}
+
+// IsLinkLocalUnicast returns true if ip is a link-local
+// unicast address.
+func (ip IP) IsLinkLocalUnicast() bool {
+ if ip4 := ip.To4(); ip4 != nil && ip4[0] == 169 && ip4[1] == 254 {
+ return true
+ }
+ return ip[0] == 0xfe && ip[1]&0xc0 == 0x80
+}
+
+// IsGlobalUnicast returns true if ip is a global unicast
+// address.
+func (ip IP) IsGlobalUnicast() bool {
+ return !ip.IsUnspecified() &&
+ !ip.IsLoopback() &&
+ !ip.IsMulticast() &&
+ !ip.IsLinkLocalUnicast()
+}
+
// Is p all zeros?
func isZeros(p IP) bool {
for i := 0; i < len(p); i++ {
diff --git a/libgo/go/net/ip_test.go b/libgo/go/net/ip_test.go
index 2008953..b189b10 100644
--- a/libgo/go/net/ip_test.go
+++ b/libgo/go/net/ip_test.go
@@ -9,6 +9,7 @@ import (
"reflect"
"testing"
"os"
+ "runtime"
)
func isEqual(a, b []byte) bool {
@@ -31,11 +32,7 @@ var parseiptests = []struct {
{"abc", nil},
{"123:", nil},
{"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)},
- {"2001:4860:0:2001::68",
- IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01,
- 0, 0, 0, 0, 0, 0, 0x00, 0x68,
- },
- },
+ {"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
{"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)},
}
@@ -52,29 +49,21 @@ var ipstringtests = []struct {
out string
}{
// cf. RFC 5952 (A Recommendation for IPv6 Address Text Representation)
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
- 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1},
"2001:db8::123:12:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0x1},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1},
"2001:db8::1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1,
- 0, 0, 0, 0x1, 0, 0, 0, 0x1},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1},
"2001:db8:0:1:0:1:0:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0,
- 0, 0x1, 0, 0, 0, 0x1, 0, 0},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0x1, 0, 0, 0, 0x1, 0, 0, 0, 0x1, 0, 0},
"2001:db8:1:0:1:0:1:0"},
- {IP{0x20, 0x1, 0, 0, 0, 0, 0, 0,
- 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ {IP{0x20, 0x1, 0, 0, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
"2001::1:0:0:1"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
- 0, 0x1, 0, 0, 0, 0, 0, 0},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0},
"2001:db8:0:0:1::"},
- {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0,
- 0, 0x1, 0, 0, 0, 0, 0, 0x1},
+ {IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0x1, 0, 0, 0, 0, 0, 0x1},
"2001:db8::1:0:0:1"},
- {IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0,
- 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD},
+ {IP{0x20, 0x1, 0xD, 0xB8, 0, 0, 0, 0, 0, 0xA, 0, 0xB, 0, 0xC, 0, 0xD},
"2001:db8::a:b:c:d"},
}
@@ -143,3 +132,84 @@ func TestJoinHostPort(t *testing.T) {
}
}
}
+
+var ipaftests = []struct {
+ in IP
+ af4 bool
+ af6 bool
+}{
+ {IPv4bcast, true, false},
+ {IPv4allsys, true, false},
+ {IPv4allrouter, true, false},
+ {IPv4zero, true, false},
+ {IPv4(224, 0, 0, 1), true, false},
+ {IPv4(127, 0, 0, 1), true, false},
+ {IPv4(240, 0, 0, 1), true, false},
+ {IPv6unspecified, false, true},
+ {IPv6loopback, false, true},
+ {IPv6interfacelocalallnodes, false, true},
+ {IPv6linklocalallnodes, false, true},
+ {IPv6linklocalallrouters, false, true},
+ {ParseIP("ff05::a:b:c:d"), false, true},
+ {ParseIP("fe80::1:2:3:4"), false, true},
+ {ParseIP("2001:db8::123:12:1"), false, true},
+}
+
+func TestIPAddrFamily(t *testing.T) {
+ for _, tt := range ipaftests {
+ if af := tt.in.To4() != nil; af != tt.af4 {
+ t.Errorf("verifying IPv4 address family for %#q = %v, want %v", tt.in, af, tt.af4)
+ }
+ if af := len(tt.in) == IPv6len && tt.in.To4() == nil; af != tt.af6 {
+ t.Errorf("verifying IPv6 address family for %#q = %v, want %v", tt.in, af, tt.af6)
+ }
+ }
+}
+
+var ipscopetests = []struct {
+ scope func(IP) bool
+ in IP
+ ok bool
+}{
+ {IP.IsUnspecified, IPv4zero, true},
+ {IP.IsUnspecified, IPv4(127, 0, 0, 1), false},
+ {IP.IsUnspecified, IPv6unspecified, true},
+ {IP.IsUnspecified, IPv6interfacelocalallnodes, false},
+ {IP.IsLoopback, IPv4(127, 0, 0, 1), true},
+ {IP.IsLoopback, IPv4(127, 255, 255, 254), true},
+ {IP.IsLoopback, IPv4(128, 1, 2, 3), false},
+ {IP.IsLoopback, IPv6loopback, true},
+ {IP.IsLoopback, IPv6linklocalallrouters, false},
+ {IP.IsMulticast, IPv4(224, 0, 0, 0), true},
+ {IP.IsMulticast, IPv4(239, 0, 0, 0), true},
+ {IP.IsMulticast, IPv4(240, 0, 0, 0), false},
+ {IP.IsMulticast, IPv6linklocalallnodes, true},
+ {IP.IsMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
+ {IP.IsMulticast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsLinkLocalMulticast, IPv4(224, 0, 0, 0), true},
+ {IP.IsLinkLocalMulticast, IPv4(239, 0, 0, 0), false},
+ {IP.IsLinkLocalMulticast, IPv6linklocalallrouters, true},
+ {IP.IsLinkLocalMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsLinkLocalUnicast, IPv4(169, 254, 0, 0), true},
+ {IP.IsLinkLocalUnicast, IPv4(169, 255, 0, 0), false},
+ {IP.IsLinkLocalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
+ {IP.IsLinkLocalUnicast, IP{0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsGlobalUnicast, IPv4(240, 0, 0, 0), true},
+ {IP.IsGlobalUnicast, IPv4(232, 0, 0, 0), false},
+ {IP.IsGlobalUnicast, IPv4(169, 254, 0, 0), false},
+ {IP.IsGlobalUnicast, IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, true},
+ {IP.IsGlobalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+ {IP.IsGlobalUnicast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+}
+
+func name(f interface{}) string {
+ return runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
+}
+
+func TestIPAddrScope(t *testing.T) {
+ for _, tt := range ipscopetests {
+ if ok := tt.scope(tt.in); ok != tt.ok {
+ t.Errorf("%s(%#q) = %v, want %v", name(tt.scope), tt.in, ok, tt.ok)
+ }
+ }
+}
diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go
index 0c0b675..6894ce6 100644
--- a/libgo/go/net/ipraw_test.go
+++ b/libgo/go/net/ipraw_test.go
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-
// TODO(cw): ListenPacket test, Read() test, ipv6 test &
// Dial()/Listen() level tests
@@ -75,15 +74,15 @@ func TestICMP(t *testing.T) {
err os.Error
)
if *srchost != "" {
- laddr, err = ResolveIPAddr(*srchost)
+ laddr, err = ResolveIPAddr("ip4", *srchost)
if err != nil {
- t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *srchost, laddr, err)
+ t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *srchost, laddr, err)
}
}
- raddr, err := ResolveIPAddr(*dsthost)
+ raddr, err := ResolveIPAddr("ip4", *dsthost)
if err != nil {
- t.Fatalf(`net.ResolveIPAddr("%v") = %v, %v`, *dsthost, raddr, err)
+ t.Fatalf(`net.ResolveIPAddr("ip4", %v") = %v, %v`, *dsthost, raddr, err)
}
c, err := ListenIP("ip4:icmp", laddr)
diff --git a/libgo/go/net/iprawsock.go b/libgo/go/net/iprawsock.go
index 5be6fe4..662b9f5 100644
--- a/libgo/go/net/iprawsock.go
+++ b/libgo/go/net/iprawsock.go
@@ -8,22 +8,8 @@ package net
import (
"os"
- "sync"
- "syscall"
)
-var onceReadProtocols sync.Once
-
-func sockaddrToIP(sa syscall.Sockaddr) Addr {
- switch sa := sa.(type) {
- case *syscall.SockaddrInet4:
- return &IPAddr{sa.Addr[0:]}
- case *syscall.SockaddrInet6:
- return &IPAddr{sa.Addr[0:]}
- }
- return nil
-}
-
// IPAddr represents the address of a IP end point.
type IPAddr struct {
IP IP
@@ -39,320 +25,45 @@ func (a *IPAddr) String() string {
return a.IP.String()
}
-func (a *IPAddr) family() int {
- if a == nil || len(a.IP) <= 4 {
- return syscall.AF_INET
- }
- if ip := a.IP.To4(); ip != nil {
- return syscall.AF_INET
- }
- return syscall.AF_INET6
-}
-
-func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
- return ipToSockaddr(family, a.IP, 0)
-}
-
-func (a *IPAddr) toAddr() sockaddr {
- if a == nil { // nil *IPAddr
- return nil // nil interface
- }
- return a
-}
-
// ResolveIPAddr parses addr as a IP address and resolves domain
-// names to numeric addresses. A literal IPv6 host address must be
+// names to numeric addresses on the network net, which must be
+// "ip", "ip4" or "ip6". A literal IPv6 host address must be
// enclosed in square brackets, as in "[::]".
-func ResolveIPAddr(addr string) (*IPAddr, os.Error) {
- ip, err := hostToIP(addr)
+func ResolveIPAddr(net, addr string) (*IPAddr, os.Error) {
+ ip, err := hostToIP(net, addr)
if err != nil {
return nil, err
}
return &IPAddr{ip}, nil
}
-// IPConn is the implementation of the Conn and PacketConn
-// interfaces for IP network connections.
-type IPConn struct {
- fd *netFD
-}
-
-func newIPConn(fd *netFD) *IPConn { return &IPConn{fd} }
-
-func (c *IPConn) ok() bool { return c != nil && c.fd != nil }
-
-// Implementation of the Conn interface - see Conn for documentation.
-
-// Read implements the net.Conn Read method.
-func (c *IPConn) Read(b []byte) (n int, err os.Error) {
- n, _, err = c.ReadFrom(b)
- return
-}
-
-// Write implements the net.Conn Write method.
-func (c *IPConn) Write(b []byte) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- return c.fd.Write(b)
-}
-
-// Close closes the IP connection.
-func (c *IPConn) Close() os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- err := c.fd.Close()
- c.fd = nil
- return err
-}
-
-// LocalAddr returns the local network address.
-func (c *IPConn) LocalAddr() Addr {
- if !c.ok() {
- return nil
- }
- return c.fd.laddr
-}
-
-// RemoteAddr returns the remote network address, a *IPAddr.
-func (c *IPConn) RemoteAddr() Addr {
- if !c.ok() {
- return nil
- }
- return c.fd.raddr
-}
-
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *IPConn) SetTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setTimeout(c.fd, nsec)
-}
-
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *IPConn) SetReadTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setReadTimeout(c.fd, nsec)
-}
-
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *IPConn) SetWriteTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setWriteTimeout(c.fd, nsec)
-}
-
-// SetReadBuffer sets the size of the operating system's
-// receive buffer associated with the connection.
-func (c *IPConn) SetReadBuffer(bytes int) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setReadBuffer(c.fd, bytes)
-}
-
-// SetWriteBuffer sets the size of the operating system's
-// transmit buffer associated with the connection.
-func (c *IPConn) SetWriteBuffer(bytes int) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setWriteBuffer(c.fd, bytes)
-}
-
-// IP-specific methods.
-
-// ReadFromIP reads a IP packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
-//
-// ReadFromIP can be made to time out and return an error with
-// Timeout() == true after a fixed time limit; see SetTimeout and
-// SetReadTimeout.
-func (c *IPConn) ReadFromIP(b []byte) (n int, addr *IPAddr, err os.Error) {
- if !c.ok() {
- return 0, nil, os.EINVAL
- }
- // TODO(cw,rsc): consider using readv if we know the family
- // type to avoid the header trim/copy
- n, sa, err := c.fd.ReadFrom(b)
- switch sa := sa.(type) {
- case *syscall.SockaddrInet4:
- addr = &IPAddr{sa.Addr[0:]}
- if len(b) >= 4 { // discard ipv4 header
- hsize := (int(b[0]) & 0xf) * 4
- copy(b, b[hsize:])
- n -= hsize
- }
- case *syscall.SockaddrInet6:
- addr = &IPAddr{sa.Addr[0:]}
- }
- return
-}
-
-// ReadFrom implements the net.PacketConn ReadFrom method.
-func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
- if !c.ok() {
- return 0, nil, os.EINVAL
- }
- n, uaddr, err := c.ReadFromIP(b)
- return n, uaddr.toAddr(), err
-}
-
-// WriteToIP writes a IP packet to addr via c, copying the payload from b.
-//
-// WriteToIP can be made to time out and return
-// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetWriteTimeout.
-// On packet-oriented connections, write timeouts are rare.
-func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- sa, err1 := addr.sockaddr(c.fd.family)
- if err1 != nil {
- return 0, &OpError{Op: "write", Net: "ip", Addr: addr, Error: err1}
- }
- return c.fd.WriteTo(b, sa)
-}
-
-// WriteTo implements the net.PacketConn WriteTo method.
-func (c *IPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- a, ok := addr.(*IPAddr)
- if !ok {
- return 0, &OpError{"writeto", "ip", addr, os.EINVAL}
- }
- return c.WriteToIP(b, a)
-}
-
// Convert "host" into IP address.
-func hostToIP(host string) (ip IP, err os.Error) {
+func hostToIP(net, host string) (ip IP, err os.Error) {
var addr IP
// Try as an IP address.
addr = ParseIP(host)
if addr == nil {
+ filter := anyaddr
+ if net != "" && net[len(net)-1] == '4' {
+ filter = ipv4only
+ }
+ if net != "" && net[len(net)-1] == '6' {
+ filter = ipv6only
+ }
// Not an IP address. Try as a DNS name.
addrs, err1 := LookupHost(host)
if err1 != nil {
err = err1
goto Error
}
- addr = firstSupportedAddr(anyaddr, addrs)
+ addr = firstFavoriteAddr(filter, addrs)
if addr == nil {
// should not happen
- err = &AddrError{"LookupHost returned invalid address", addrs[0]}
+ err = &AddrError{"LookupHost returned no suitable address", addrs[0]}
goto Error
}
}
-
return addr, nil
-
Error:
return nil, err
}
-
-
-var protocols map[string]int
-
-func readProtocols() {
- protocols = make(map[string]int)
- if file, err := open("/etc/protocols"); err == nil {
- for line, ok := file.readLine(); ok; line, ok = file.readLine() {
- // tcp 6 TCP # transmission control protocol
- if i := byteIndex(line, '#'); i >= 0 {
- line = line[0:i]
- }
- f := getFields(line)
- if len(f) < 2 {
- continue
- }
- if proto, _, ok := dtoi(f[1], 0); ok {
- protocols[f[0]] = proto
- for _, alias := range f[2:] {
- protocols[alias] = proto
- }
- }
- }
- file.close()
- }
-}
-
-func netProtoSplit(netProto string) (net string, proto int, err os.Error) {
- onceReadProtocols.Do(readProtocols)
- i := last(netProto, ':')
- if i < 0 { // no colon
- return "", 0, os.ErrorString("no IP protocol specified")
- }
- net = netProto[0:i]
- protostr := netProto[i+1:]
- proto, i, ok := dtoi(protostr, 0)
- if !ok || i != len(protostr) {
- // lookup by name
- proto, ok = protocols[protostr]
- if ok {
- return
- }
- }
- return
-}
-
-// DialIP connects to the remote address raddr on the network net,
-// which must be "ip", "ip4", or "ip6".
-func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err os.Error) {
- net, proto, err := netProtoSplit(netProto)
- if err != nil {
- return
- }
- switch net {
- case "ip", "ip4", "ip6":
- default:
- return nil, UnknownNetworkError(net)
- }
- if raddr == nil {
- return nil, &OpError{"dial", "ip", nil, errMissingAddress}
- }
- fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
- if e != nil {
- return nil, e
- }
- return newIPConn(fd), nil
-}
-
-// ListenIP listens for incoming IP packets addressed to the
-// local address laddr. The returned connection c's ReadFrom
-// and WriteTo methods can be used to receive and send IP
-// packets with per-packet addressing.
-func ListenIP(netProto string, laddr *IPAddr) (c *IPConn, err os.Error) {
- net, proto, err := netProtoSplit(netProto)
- if err != nil {
- return
- }
- switch net {
- case "ip", "ip4", "ip6":
- default:
- return nil, UnknownNetworkError(net)
- }
- fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
- if e != nil {
- return nil, e
- }
- return newIPConn(fd), nil
-}
-
-// BindToDevice binds an IPConn to a network interface.
-func (c *IPConn) BindToDevice(device string) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- c.fd.incref()
- defer c.fd.decref()
- return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
-}
diff --git a/libgo/go/net/iprawsock_plan9.go b/libgo/go/net/iprawsock_plan9.go
new file mode 100644
index 0000000..808e179
--- /dev/null
+++ b/libgo/go/net/iprawsock_plan9.go
@@ -0,0 +1,99 @@
+// Copyright 2010 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.
+
+// (Raw) IP sockets stubs for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// IPConn is the implementation of the Conn and PacketConn
+// interfaces for IP network connections.
+type IPConn bool
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *IPConn) Read(b []byte) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// Write implements the net.Conn Write method.
+func (c *IPConn) Write(b []byte) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// Close closes the IP connection.
+func (c *IPConn) Close() os.Error {
+ return os.EPLAN9
+}
+
+// LocalAddr returns the local network address.
+func (c *IPConn) LocalAddr() Addr {
+ return nil
+}
+
+// RemoteAddr returns the remote network address, a *IPAddr.
+func (c *IPConn) RemoteAddr() Addr {
+ return nil
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *IPConn) SetTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *IPConn) SetReadTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *IPConn) SetWriteTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// IP-specific methods.
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ err = os.EPLAN9
+ return
+}
+
+// WriteToIP writes a IP packet to addr via c, copying the payload from b.
+//
+// WriteToIP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *IPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+func splitNetProto(netProto string) (net string, proto int, err os.Error) {
+ err = os.EPLAN9
+ return
+}
+
+// DialIP connects to the remote address raddr on the network net,
+// which must be "ip", "ip4", or "ip6".
+func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// ListenIP listens for incoming IP packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send IP
+// packets with per-packet addressing.
+func ListenIP(netProto string, laddr *IPAddr) (c *IPConn, err os.Error) {
+ return nil, os.EPLAN9
+}
diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go
new file mode 100644
index 0000000..4e11518
--- /dev/null
+++ b/libgo/go/net/iprawsock_posix.go
@@ -0,0 +1,305 @@
+// Copyright 2010 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.
+
+// (Raw) IP sockets
+
+package net
+
+import (
+ "os"
+ "sync"
+ "syscall"
+)
+
+var onceReadProtocols sync.Once
+
+func sockaddrToIP(sa syscall.Sockaddr) Addr {
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return &IPAddr{sa.Addr[0:]}
+ case *syscall.SockaddrInet6:
+ return &IPAddr{sa.Addr[0:]}
+ }
+ return nil
+}
+
+func (a *IPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if a.IP.To4() != nil {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+ return ipToSockaddr(family, a.IP, 0)
+}
+
+func (a *IPAddr) toAddr() sockaddr {
+ if a == nil { // nil *IPAddr
+ return nil // nil interface
+ }
+ return a
+}
+
+// IPConn is the implementation of the Conn and PacketConn
+// interfaces for IP network connections.
+type IPConn struct {
+ fd *netFD
+}
+
+func newIPConn(fd *netFD) *IPConn { return &IPConn{fd} }
+
+func (c *IPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *IPConn) Read(b []byte) (n int, err os.Error) {
+ n, _, err = c.ReadFrom(b)
+ return
+}
+
+// Write implements the net.Conn Write method.
+func (c *IPConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the IP connection.
+func (c *IPConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address.
+func (c *IPConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *IPAddr.
+func (c *IPConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *IPConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *IPConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *IPConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *IPConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *IPConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// IP-specific methods.
+
+// ReadFromIP reads a IP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromIP can be made to time out and return an error with
+// Timeout() == true after a fixed time limit; see SetTimeout and
+// SetReadTimeout.
+func (c *IPConn) ReadFromIP(b []byte) (n int, addr *IPAddr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ // TODO(cw,rsc): consider using readv if we know the family
+ // type to avoid the header trim/copy
+ n, sa, err := c.fd.ReadFrom(b)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ addr = &IPAddr{sa.Addr[0:]}
+ if len(b) >= 4 { // discard ipv4 header
+ hsize := (int(b[0]) & 0xf) * 4
+ copy(b, b[hsize:])
+ n -= hsize
+ }
+ case *syscall.SockaddrInet6:
+ addr = &IPAddr{sa.Addr[0:]}
+ }
+ return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *IPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, uaddr, err := c.ReadFromIP(b)
+ return n, uaddr.toAddr(), err
+}
+
+// WriteToIP writes a IP packet to addr via c, copying the payload from b.
+//
+// WriteToIP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ sa, err1 := addr.sockaddr(c.fd.family)
+ if err1 != nil {
+ return 0, &OpError{Op: "write", Net: "ip", Addr: addr, Error: err1}
+ }
+ return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *IPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ a, ok := addr.(*IPAddr)
+ if !ok {
+ return 0, &OpError{"writeto", "ip", addr, os.EINVAL}
+ }
+ return c.WriteToIP(b, a)
+}
+
+var protocols map[string]int
+
+func readProtocols() {
+ protocols = make(map[string]int)
+ if file, err := open("/etc/protocols"); err == nil {
+ for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+ // tcp 6 TCP # transmission control protocol
+ if i := byteIndex(line, '#'); i >= 0 {
+ line = line[0:i]
+ }
+ f := getFields(line)
+ if len(f) < 2 {
+ continue
+ }
+ if proto, _, ok := dtoi(f[1], 0); ok {
+ protocols[f[0]] = proto
+ for _, alias := range f[2:] {
+ protocols[alias] = proto
+ }
+ }
+ }
+ file.close()
+ }
+}
+
+func splitNetProto(netProto string) (net string, proto int, err os.Error) {
+ onceReadProtocols.Do(readProtocols)
+ i := last(netProto, ':')
+ if i < 0 { // no colon
+ return "", 0, os.NewError("no IP protocol specified")
+ }
+ net = netProto[0:i]
+ protostr := netProto[i+1:]
+ proto, i, ok := dtoi(protostr, 0)
+ if !ok || i != len(protostr) {
+ // lookup by name
+ proto, ok = protocols[protostr]
+ if ok {
+ return
+ }
+ }
+ return
+}
+
+// DialIP connects to the remote address raddr on the network net,
+// which must be "ip", "ip4", or "ip6".
+func DialIP(netProto string, laddr, raddr *IPAddr) (c *IPConn, err os.Error) {
+ net, proto, err := splitNetProto(netProto)
+ if err != nil {
+ return
+ }
+ switch net {
+ case "ip", "ip4", "ip6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if raddr == nil {
+ return nil, &OpError{"dial", "ip", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
+ if e != nil {
+ return nil, e
+ }
+ return newIPConn(fd), nil
+}
+
+// ListenIP listens for incoming IP packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send IP
+// packets with per-packet addressing.
+func ListenIP(netProto string, laddr *IPAddr) (c *IPConn, err os.Error) {
+ net, proto, err := splitNetProto(netProto)
+ if err != nil {
+ return
+ }
+ switch net {
+ case "ip", "ip4", "ip6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_RAW, proto, "dial", sockaddrToIP)
+ if e != nil {
+ return nil, e
+ }
+ return newIPConn(fd), nil
+}
+
+// BindToDevice binds an IPConn to a network interface.
+func (c *IPConn) BindToDevice(device string) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ c.fd.incref()
+ defer c.fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
+}
diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go
index e8bcac6..4e2a562 100644
--- a/libgo/go/net/ipsock.go
+++ b/libgo/go/net/ipsock.go
@@ -8,33 +8,27 @@ package net
import (
"os"
- "syscall"
)
-// Should we try to use the IPv4 socket interface if we're
-// only dealing with IPv4 sockets? As long as the host system
-// understands IPv6, it's okay to pass IPv4 addresses to the IPv6
-// interface. That simplifies our code and is most general.
-// Unfortunately, we need to run on kernels built without IPv6 support too.
-// So probe the kernel to figure it out.
-func kernelSupportsIPv6() bool {
- s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
- if err != 0 {
- return false
- }
- defer closesocket(s)
+var supportsIPv6, supportsIPv4map = probeIPv6Stack()
- la := &TCPAddr{IP: IPv4(127, 0, 0, 1)}
- sa, oserr := la.toAddr().sockaddr(syscall.AF_INET6)
- if oserr != nil {
- return false
+func firstFavoriteAddr(filter func(IP) IP, addrs []string) (addr IP) {
+ if filter == anyaddr {
+ // We'll take any IP address, but since the dialing code
+ // does not yet try multiple addresses, prefer to use
+ // an IPv4 address if possible. This is especially relevant
+ // if localhost resolves to [ipv6-localhost, ipv4-localhost].
+ // Too much code assumes localhost == ipv4-localhost.
+ addr = firstSupportedAddr(ipv4only, addrs)
+ if addr == nil {
+ addr = firstSupportedAddr(anyaddr, addrs)
+ }
+ } else {
+ addr = firstSupportedAddr(filter, addrs)
}
-
- return syscall.Bind(s, sa) == 0
+ return
}
-var preferIPv4 = !kernelSupportsIPv6()
-
func firstSupportedAddr(filter func(IP) IP, addrs []string) IP {
for _, s := range addrs {
if addr := filter(ParseIP(s)); addr != nil {
@@ -44,98 +38,25 @@ func firstSupportedAddr(filter func(IP) IP, addrs []string) IP {
return nil
}
-func anyaddr(x IP) IP { return x }
+func anyaddr(x IP) IP {
+ if x4 := x.To4(); x4 != nil {
+ return x4
+ }
+ if supportsIPv6 {
+ return x
+ }
+ return nil
+}
+
func ipv4only(x IP) IP { return x.To4() }
func ipv6only(x IP) IP {
// Only return addresses that we can use
// with the kernel's IPv6 addressing modes.
- // If preferIPv4 is set, it means the IPv6 stack
- // cannot take IPv4 addresses directly (we prefer
- // to use the IPv4 stack) so reject IPv4 addresses.
- if x.To4() != nil && preferIPv4 {
- return nil
- }
- return x
-}
-
-// TODO(rsc): if syscall.OS == "linux", we're supposd to read
-// /proc/sys/net/core/somaxconn,
-// to take advantage of kernels that have raised the limit.
-func listenBacklog() int { return syscall.SOMAXCONN }
-
-// Internet sockets (TCP, UDP)
-
-// A sockaddr represents a TCP or UDP network address that can
-// be converted into a syscall.Sockaddr.
-type sockaddr interface {
- Addr
- sockaddr(family int) (syscall.Sockaddr, os.Error)
- family() int
-}
-
-func internetSocket(net string, laddr, raddr sockaddr, socktype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
- // Figure out IP version.
- // If network has a suffix like "tcp4", obey it.
- var oserr os.Error
- family := syscall.AF_INET6
- switch net[len(net)-1] {
- case '4':
- family = syscall.AF_INET
- case '6':
- // nothing to do
- default:
- // Otherwise, guess.
- // If the addresses are IPv4 and we prefer IPv4, use 4; else 6.
- if preferIPv4 &&
- (laddr == nil || laddr.family() == syscall.AF_INET) &&
- (raddr == nil || raddr.family() == syscall.AF_INET) {
- family = syscall.AF_INET
- }
+ if len(x) == IPv6len && x.To4() == nil && supportsIPv6 {
+ return x
}
-
- var la, ra syscall.Sockaddr
- if laddr != nil {
- if la, oserr = laddr.sockaddr(family); oserr != nil {
- goto Error
- }
- }
- if raddr != nil {
- if ra, oserr = raddr.sockaddr(family); oserr != nil {
- goto Error
- }
- }
- fd, oserr = socket(net, family, socktype, proto, la, ra, toAddr)
- if oserr != nil {
- goto Error
- }
- return fd, nil
-
-Error:
- addr := raddr
- if mode == "listen" {
- addr = laddr
- }
- return nil, &OpError{mode, net, addr, oserr}
-}
-
-func getip(fd int, remote bool) (ip []byte, port int, ok bool) {
- // No attempt at error reporting because
- // there are no possible errors, and the
- // caller won't report them anyway.
- var sa syscall.Sockaddr
- if remote {
- sa, _ = syscall.Getpeername(fd)
- } else {
- sa, _ = syscall.Getsockname(fd)
- }
- switch sa := sa.(type) {
- case *syscall.SockaddrInet4:
- return sa.Addr[0:], sa.Port, true
- case *syscall.SockaddrInet6:
- return sa.Addr[0:], sa.Port, true
- }
- return
+ return nil
}
type InvalidAddrError string
@@ -144,44 +65,6 @@ func (e InvalidAddrError) String() string { return string(e) }
func (e InvalidAddrError) Timeout() bool { return false }
func (e InvalidAddrError) Temporary() bool { return false }
-func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
- switch family {
- case syscall.AF_INET:
- if len(ip) == 0 {
- ip = IPv4zero
- }
- if ip = ip.To4(); ip == nil {
- return nil, InvalidAddrError("non-IPv4 address")
- }
- s := new(syscall.SockaddrInet4)
- for i := 0; i < IPv4len; i++ {
- s.Addr[i] = ip[i]
- }
- s.Port = port
- return s, nil
- case syscall.AF_INET6:
- if len(ip) == 0 {
- ip = IPzero
- }
- // IPv4 callers use 0.0.0.0 to mean "announce on any available address".
- // In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
- // which it refuses to do. Rewrite to the IPv6 all zeros.
- if p4 := ip.To4(); p4 != nil && p4[0] == 0 && p4[1] == 0 && p4[2] == 0 && p4[3] == 0 {
- ip = IPzero
- }
- if ip = ip.To16(); ip == nil {
- return nil, InvalidAddrError("non-IPv6 address")
- }
- s := new(syscall.SockaddrInet6)
- for i := 0; i < IPv6len; i++ {
- s.Addr[i] = ip[i]
- }
- s.Port = port
- return s, nil
- }
- return nil, InvalidAddrError("unexpected socket family")
-}
-
// SplitHostPort splits a network address of the form
// "host:port" or "[host]:port" into host and port.
// The latter form must be used when host contains a colon.
@@ -220,20 +103,25 @@ func JoinHostPort(host, port string) string {
// Convert "host:port" into IP address and port.
func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
+ var (
+ addr IP
+ p, i int
+ ok bool
+ )
host, port, err := SplitHostPort(hostport)
if err != nil {
goto Error
}
- var addr IP
if host != "" {
// Try as an IP address.
addr = ParseIP(host)
if addr == nil {
filter := anyaddr
- if len(net) >= 4 && net[3] == '4' {
+ if net != "" && net[len(net)-1] == '4' {
filter = ipv4only
- } else if len(net) >= 4 && net[3] == '6' {
+ }
+ if net != "" && net[len(net)-1] == '6' {
filter = ipv6only
}
// Not an IP address. Try as a DNS name.
@@ -242,28 +130,16 @@ func hostPortToIP(net, hostport string) (ip IP, iport int, err os.Error) {
err = err1
goto Error
}
- if filter == anyaddr {
- // We'll take any IP address, but since the dialing code
- // does not yet try multiple addresses, prefer to use
- // an IPv4 address if possible. This is especially relevant
- // if localhost resolves to [ipv6-localhost, ipv4-localhost].
- // Too much code assumes localhost == ipv4-localhost.
- addr = firstSupportedAddr(ipv4only, addrs)
- if addr == nil {
- addr = firstSupportedAddr(anyaddr, addrs)
- }
- } else {
- addr = firstSupportedAddr(filter, addrs)
- }
+ addr = firstFavoriteAddr(filter, addrs)
if addr == nil {
// should not happen
- err = &AddrError{"LookupHost returned invalid address", addrs[0]}
+ err = &AddrError{"LookupHost returned no suitable address", addrs[0]}
goto Error
}
}
}
- p, i, ok := dtoi(port, 0)
+ p, i, ok = dtoi(port, 0)
if !ok || i != len(port) {
p, err = LookupPort(net, port)
if err != nil {
diff --git a/libgo/go/net/ipsock_plan9.go b/libgo/go/net/ipsock_plan9.go
new file mode 100644
index 0000000..9e5da6d
--- /dev/null
+++ b/libgo/go/net/ipsock_plan9.go
@@ -0,0 +1,305 @@
+// 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.
+
+// IP sockets stubs for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// probeIPv6Stack returns two boolean values. If the first boolean value is
+// true, kernel supports basic IPv6 functionality. If the second
+// boolean value is true, kernel supports IPv6 IPv4-mapping.
+func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
+ return false, false
+}
+
+// parsePlan9Addr parses address of the form [ip!]port (e.g. 127.0.0.1!80).
+func parsePlan9Addr(s string) (ip IP, iport int, err os.Error) {
+ var (
+ addr IP
+ p, i int
+ ok bool
+ )
+ addr = IPv4zero // address contains port only
+ i = byteIndex(s, '!')
+ if i >= 0 {
+ addr = ParseIP(s[:i])
+ if addr == nil {
+ err = os.NewError("net: parsing IP failed")
+ goto Error
+ }
+ }
+ p, _, ok = dtoi(s[i+1:], 0)
+ if !ok {
+ err = os.NewError("net: parsing port failed")
+ goto Error
+ }
+ if p < 0 || p > 0xFFFF {
+ err = &AddrError{"invalid port", string(p)}
+ goto Error
+ }
+ return addr, p, nil
+
+Error:
+ return nil, 0, err
+}
+
+func readPlan9Addr(proto, filename string) (addr Addr, err os.Error) {
+ var buf [128]byte
+
+ f, err := os.Open(filename)
+ if err != nil {
+ return
+ }
+ n, err := f.Read(buf[:])
+ if err != nil {
+ return
+ }
+ ip, port, err := parsePlan9Addr(string(buf[:n]))
+ if err != nil {
+ return
+ }
+ switch proto {
+ case "tcp":
+ addr = &TCPAddr{ip, port}
+ case "udp":
+ addr = &UDPAddr{ip, port}
+ default:
+ return nil, os.NewError("unknown protocol " + proto)
+ }
+ return addr, nil
+}
+
+type plan9Conn struct {
+ proto, name, dir string
+ ctl, data *os.File
+ laddr, raddr Addr
+}
+
+func newPlan9Conn(proto, name string, ctl *os.File, laddr, raddr Addr) *plan9Conn {
+ return &plan9Conn{proto, name, "/net/" + proto + "/" + name, ctl, nil, laddr, raddr}
+}
+
+func (c *plan9Conn) ok() bool { return c != nil && c.ctl != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *plan9Conn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, err
+ }
+ }
+ n, err = c.data.Read(b)
+ if c.proto == "udp" && err == os.EOF {
+ n = 0
+ err = nil
+ }
+ return
+}
+
+// Write implements the net.Conn Write method.
+func (c *plan9Conn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, err
+ }
+ }
+ return c.data.Write(b)
+}
+
+// Close closes the connection.
+func (c *plan9Conn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.ctl.Close()
+ if err != nil {
+ return err
+ }
+ if c.data != nil {
+ err = c.data.Close()
+ }
+ c.ctl = nil
+ c.data = nil
+ return err
+}
+
+// LocalAddr returns the local network address.
+func (c *plan9Conn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.laddr
+}
+
+// RemoteAddr returns the remote network address.
+func (c *plan9Conn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *plan9Conn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *plan9Conn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *plan9Conn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+func startPlan9(net string, addr Addr) (ctl *os.File, dest, proto, name string, err os.Error) {
+ var (
+ ip IP
+ port int
+ )
+ switch a := addr.(type) {
+ case *TCPAddr:
+ proto = "tcp"
+ ip = a.IP
+ port = a.Port
+ case *UDPAddr:
+ proto = "udp"
+ ip = a.IP
+ port = a.Port
+ default:
+ err = UnknownNetworkError(net)
+ return
+ }
+
+ clone, dest, err := queryCS1(proto, ip, port)
+ if err != nil {
+ return
+ }
+ f, err := os.OpenFile(clone, os.O_RDWR, 0)
+ if err != nil {
+ return
+ }
+ var buf [16]byte
+ n, err := f.Read(buf[:])
+ if err != nil {
+ return
+ }
+ return f, dest, proto, string(buf[:n]), nil
+}
+
+func dialPlan9(net string, laddr, raddr Addr) (c *plan9Conn, err os.Error) {
+ f, dest, proto, name, err := startPlan9(net, raddr)
+ if err != nil {
+ return
+ }
+ _, err = f.WriteString("connect " + dest)
+ if err != nil {
+ return
+ }
+ laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+ if err != nil {
+ return
+ }
+ raddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/remote")
+ if err != nil {
+ return
+ }
+ return newPlan9Conn(proto, name, f, laddr, raddr), nil
+}
+
+type plan9Listener struct {
+ proto, name, dir string
+ ctl *os.File
+ laddr Addr
+}
+
+func listenPlan9(net string, laddr Addr) (l *plan9Listener, err os.Error) {
+ f, dest, proto, name, err := startPlan9(net, laddr)
+ if err != nil {
+ return
+ }
+ _, err = f.WriteString("announce " + dest)
+ if err != nil {
+ return
+ }
+ laddr, err = readPlan9Addr(proto, "/net/"+proto+"/"+name+"/local")
+ if err != nil {
+ return
+ }
+ l = new(plan9Listener)
+ l.proto = proto
+ l.name = name
+ l.dir = "/net/" + proto + "/" + name
+ l.ctl = f
+ l.laddr = laddr
+ return l, nil
+}
+
+func (l *plan9Listener) plan9Conn() *plan9Conn {
+ return newPlan9Conn(l.proto, l.name, l.ctl, l.laddr, nil)
+}
+
+func (l *plan9Listener) acceptPlan9() (c *plan9Conn, err os.Error) {
+ f, err := os.Open(l.dir + "/listen")
+ if err != nil {
+ return
+ }
+ var buf [16]byte
+ n, err := f.Read(buf[:])
+ if err != nil {
+ return
+ }
+ name := string(buf[:n])
+ laddr, err := readPlan9Addr(l.proto, l.dir+"/local")
+ if err != nil {
+ return
+ }
+ raddr, err := readPlan9Addr(l.proto, l.dir+"/remote")
+ if err != nil {
+ return
+ }
+ return newPlan9Conn(l.proto, name, f, laddr, raddr), nil
+}
+
+func (l *plan9Listener) Accept() (c Conn, err os.Error) {
+ c1, err := l.acceptPlan9()
+ if err != nil {
+ return
+ }
+ return c1, nil
+}
+
+func (l *plan9Listener) Close() os.Error {
+ if l == nil || l.ctl == nil {
+ return os.EINVAL
+ }
+ return l.ctl.Close()
+}
+
+func (l *plan9Listener) Addr() Addr { return l.laddr }
diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go
new file mode 100644
index 0000000..0c522fb
--- /dev/null
+++ b/libgo/go/net/ipsock_posix.go
@@ -0,0 +1,174 @@
+// 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.
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+// Should we try to use the IPv4 socket interface if we're
+// only dealing with IPv4 sockets? As long as the host system
+// understands IPv6, it's okay to pass IPv4 addresses to the IPv6
+// interface. That simplifies our code and is most general.
+// Unfortunately, we need to run on kernels built without IPv6
+// support too. So probe the kernel to figure it out.
+//
+// probeIPv6Stack probes both basic IPv6 capability and IPv6 IPv4-
+// mapping capability which is controlled by IPV6_V6ONLY socket
+// option and/or kernel state "net.inet6.ip6.v6only".
+// It returns two boolean values. If the first boolean value is
+// true, kernel supports basic IPv6 functionality. If the second
+// boolean value is true, kernel supports IPv6 IPv4-mapping.
+func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
+ var probes = []struct {
+ la TCPAddr
+ ok bool
+ }{
+ // IPv6 communication capability
+ {TCPAddr{IP: ParseIP("::1")}, false},
+ // IPv6 IPv4-mapped address communication capability
+ {TCPAddr{IP: IPv4(127, 0, 0, 1)}, false},
+ }
+
+ for i := range probes {
+ s, errno := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+ if errno != 0 {
+ continue
+ }
+ defer closesocket(s)
+ sa, err := probes[i].la.toAddr().sockaddr(syscall.AF_INET6)
+ if err != nil {
+ continue
+ }
+ errno = syscall.Bind(s, sa)
+ if errno != 0 {
+ continue
+ }
+ probes[i].ok = true
+ }
+
+ return probes[0].ok, probes[1].ok
+}
+
+// favoriteAddrFamily returns the appropriate address family to
+// the given net, raddr, laddr and mode. At first it figures
+// address family out from the net. If mode indicates "listen"
+// and laddr.(type).IP is nil, it assumes that the user wants to
+// make a passive connection with wildcard address family, both
+// INET and INET6, and wildcard address. Otherwise guess: if the
+// addresses are IPv4 then returns INET, or else returns INET6.
+func favoriteAddrFamily(net string, raddr, laddr sockaddr, mode string) int {
+ switch net[len(net)-1] {
+ case '4':
+ return syscall.AF_INET
+ case '6':
+ return syscall.AF_INET6
+ }
+
+ if mode == "listen" {
+ switch a := laddr.(type) {
+ case *TCPAddr:
+ if a.IP == nil && supportsIPv6 {
+ return syscall.AF_INET6
+ }
+ case *UDPAddr:
+ if a.IP == nil && supportsIPv6 {
+ return syscall.AF_INET6
+ }
+ case *IPAddr:
+ if a.IP == nil && supportsIPv6 {
+ return syscall.AF_INET6
+ }
+ }
+ }
+
+ if (laddr == nil || laddr.family() == syscall.AF_INET) &&
+ (raddr == nil || raddr.family() == syscall.AF_INET) {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+// TODO(rsc): if syscall.OS == "linux", we're supposed to read
+// /proc/sys/net/core/somaxconn,
+// to take advantage of kernels that have raised the limit.
+func listenBacklog() int { return syscall.SOMAXCONN }
+
+// Internet sockets (TCP, UDP)
+
+// A sockaddr represents a TCP or UDP network address that can
+// be converted into a syscall.Sockaddr.
+type sockaddr interface {
+ Addr
+ sockaddr(family int) (syscall.Sockaddr, os.Error)
+ family() int
+}
+
+func internetSocket(net string, laddr, raddr sockaddr, socktype, proto int, mode string, toAddr func(syscall.Sockaddr) Addr) (fd *netFD, err os.Error) {
+ var oserr os.Error
+ var la, ra syscall.Sockaddr
+ family := favoriteAddrFamily(net, raddr, laddr, mode)
+ if laddr != nil {
+ if la, oserr = laddr.sockaddr(family); oserr != nil {
+ goto Error
+ }
+ }
+ if raddr != nil {
+ if ra, oserr = raddr.sockaddr(family); oserr != nil {
+ goto Error
+ }
+ }
+ fd, oserr = socket(net, family, socktype, proto, la, ra, toAddr)
+ if oserr != nil {
+ goto Error
+ }
+ return fd, nil
+
+Error:
+ addr := raddr
+ if mode == "listen" {
+ addr = laddr
+ }
+ return nil, &OpError{mode, net, addr, oserr}
+}
+
+func ipToSockaddr(family int, ip IP, port int) (syscall.Sockaddr, os.Error) {
+ switch family {
+ case syscall.AF_INET:
+ if len(ip) == 0 {
+ ip = IPv4zero
+ }
+ if ip = ip.To4(); ip == nil {
+ return nil, InvalidAddrError("non-IPv4 address")
+ }
+ s := new(syscall.SockaddrInet4)
+ for i := 0; i < IPv4len; i++ {
+ s.Addr[i] = ip[i]
+ }
+ s.Port = port
+ return s, nil
+ case syscall.AF_INET6:
+ if len(ip) == 0 {
+ ip = IPv6zero
+ }
+ // IPv4 callers use 0.0.0.0 to mean "announce on any available address".
+ // In IPv6 mode, Linux treats that as meaning "announce on 0.0.0.0",
+ // which it refuses to do. Rewrite to the IPv6 all zeros.
+ if ip.Equal(IPv4zero) {
+ ip = IPv6zero
+ }
+ if ip = ip.To16(); ip == nil {
+ return nil, InvalidAddrError("non-IPv6 address")
+ }
+ s := new(syscall.SockaddrInet6)
+ for i := 0; i < IPv6len; i++ {
+ s.Addr[i] = ip[i]
+ }
+ s.Port = port
+ return s, nil
+ }
+ return nil, InvalidAddrError("unexpected socket family")
+}
diff --git a/libgo/go/net/lookup.go b/libgo/go/net/lookup.go
deleted file mode 100644
index eeb22a8..0000000
--- a/libgo/go/net/lookup.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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.
-
-package net
-
-import (
- "os"
-)
-
-// LookupHost looks up the given host using the local resolver.
-// It returns an array of that host's addresses.
-func LookupHost(host string) (addrs []string, err os.Error) {
- addrs, err, ok := cgoLookupHost(host)
- if !ok {
- addrs, err = goLookupHost(host)
- }
- return
-}
-
-// LookupIP looks up host using the local resolver.
-// It returns an array of that host's IPv4 and IPv6 addresses.
-func LookupIP(host string) (addrs []IP, err os.Error) {
- addrs, err, ok := cgoLookupIP(host)
- if !ok {
- addrs, err = goLookupIP(host)
- }
- return
-}
-
-// LookupPort looks up the port for the given network and service.
-func LookupPort(network, service string) (port int, err os.Error) {
- port, err, ok := cgoLookupPort(network, service)
- if !ok {
- port, err = goLookupPort(network, service)
- }
- return
-}
-
-// LookupCNAME returns the canonical DNS host for the given name.
-// Callers that do not care about the canonical name can call
-// LookupHost or LookupIP directly; both take care of resolving
-// the canonical name as part of the lookup.
-func LookupCNAME(name string) (cname string, err os.Error) {
- cname, err, ok := cgoLookupCNAME(name)
- if !ok {
- cname, err = goLookupCNAME(name)
- }
- return
-}
diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go
new file mode 100644
index 0000000..37d6b8e
--- /dev/null
+++ b/libgo/go/net/lookup_plan9.go
@@ -0,0 +1,226 @@
+// 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.
+
+package net
+
+import (
+ "os"
+)
+
+func query(filename, query string, bufSize int) (res []string, err os.Error) {
+ file, err := os.OpenFile(filename, os.O_RDWR, 0)
+ if err != nil {
+ return
+ }
+ defer file.Close()
+
+ _, err = file.WriteString(query)
+ if err != nil {
+ return
+ }
+ _, err = file.Seek(0, 0)
+ if err != nil {
+ return
+ }
+ buf := make([]byte, bufSize)
+ for {
+ n, _ := file.Read(buf)
+ if n <= 0 {
+ break
+ }
+ res = append(res, string(buf[:n]))
+ }
+ return
+}
+
+func queryCS(net, host, service string) (res []string, err os.Error) {
+ switch net {
+ case "tcp4", "tcp6":
+ net = "tcp"
+ case "udp4", "udp6":
+ net = "udp"
+ }
+ if host == "" {
+ host = "*"
+ }
+ return query("/net/cs", net+"!"+host+"!"+service, 128)
+}
+
+func queryCS1(net string, ip IP, port int) (clone, dest string, err os.Error) {
+ ips := "*"
+ if !ip.IsUnspecified() {
+ ips = ip.String()
+ }
+ lines, err := queryCS(net, ips, itoa(port))
+ if err != nil {
+ return
+ }
+ f := getFields(lines[0])
+ if len(f) < 2 {
+ return "", "", os.NewError("net: bad response from ndb/cs")
+ }
+ clone, dest = f[0], f[1]
+ return
+}
+
+func queryDNS(addr string, typ string) (res []string, err os.Error) {
+ return query("/net/dns", addr+" "+typ, 1024)
+}
+
+// LookupHost looks up the given host using the local resolver.
+// It returns an array of that host's addresses.
+func LookupHost(host string) (addrs []string, err os.Error) {
+ // Use /net/cs insead of /net/dns because cs knows about
+ // host names in local network (e.g. from /lib/ndb/local)
+ lines, err := queryCS("tcp", host, "1")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 2 {
+ continue
+ }
+ addr := f[1]
+ if i := byteIndex(addr, '!'); i >= 0 {
+ addr = addr[:i] // remove port
+ }
+ if ParseIP(addr) == nil {
+ continue
+ }
+ addrs = append(addrs, addr)
+ }
+ return
+}
+
+// LookupIP looks up host using the local resolver.
+// It returns an array of that host's IPv4 and IPv6 addresses.
+func LookupIP(host string) (ips []IP, err os.Error) {
+ addrs, err := LookupHost(host)
+ if err != nil {
+ return
+ }
+ for _, addr := range addrs {
+ if ip := ParseIP(addr); ip != nil {
+ ips = append(ips, ip)
+ }
+ }
+ return
+}
+
+// LookupPort looks up the port for the given network and service.
+func LookupPort(network, service string) (port int, err os.Error) {
+ switch network {
+ case "tcp4", "tcp6":
+ network = "tcp"
+ case "udp4", "udp6":
+ network = "udp"
+ }
+ lines, err := queryCS(network, "127.0.0.1", service)
+ if err != nil {
+ return
+ }
+ unknownPortError := &AddrError{"unknown port", network + "/" + service}
+ if len(lines) == 0 {
+ return 0, unknownPortError
+ }
+ f := getFields(lines[0])
+ if len(f) < 2 {
+ return 0, unknownPortError
+ }
+ s := f[1]
+ if i := byteIndex(s, '!'); i >= 0 {
+ s = s[i+1:] // remove address
+ }
+ if n, _, ok := dtoi(s, 0); ok {
+ return n, nil
+ }
+ return 0, unknownPortError
+}
+
+// LookupCNAME returns the canonical DNS host for the given name.
+// Callers that do not care about the canonical name can call
+// LookupHost or LookupIP directly; both take care of resolving
+// the canonical name as part of the lookup.
+func LookupCNAME(name string) (cname string, err os.Error) {
+ lines, err := queryDNS(name, "cname")
+ if err != nil {
+ return
+ }
+ if len(lines) > 0 {
+ if f := getFields(lines[0]); len(f) >= 3 {
+ return f[2] + ".", nil
+ }
+ }
+ return "", os.NewError("net: bad response from ndb/dns")
+}
+
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name, as specified in RFC 2782. In most cases
+// the proto argument can be the same as the corresponding
+// Addr.Network(). The returned records are sorted by priority
+// and randomized by weight within a priority.
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+ target := "_" + service + "._" + proto + "." + name
+ lines, err := queryDNS(target, "srv")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 6 {
+ continue
+ }
+ port, _, portOk := dtoi(f[2], 0)
+ priority, _, priorityOk := dtoi(f[3], 0)
+ weight, _, weightOk := dtoi(f[4], 0)
+ if !(portOk && priorityOk && weightOk) {
+ continue
+ }
+ addrs = append(addrs, &SRV{f[5], uint16(port), uint16(priority), uint16(weight)})
+ cname = f[0]
+ }
+ byPriorityWeight(addrs).sort()
+ return
+}
+
+// LookupMX returns the DNS MX records for the given domain name sorted by preference.
+func LookupMX(name string) (mx []*MX, err os.Error) {
+ lines, err := queryDNS(name, "mx")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 4 {
+ continue
+ }
+ if pref, _, ok := dtoi(f[2], 0); ok {
+ mx = append(mx, &MX{f[3], uint16(pref)})
+ }
+ }
+ byPref(mx).sort()
+ return
+}
+
+// LookupAddr performs a reverse lookup for the given address, returning a list
+// of names mapping to that address.
+func LookupAddr(addr string) (name []string, err os.Error) {
+ arpa, err := reverseaddr(addr)
+ if err != nil {
+ return
+ }
+ lines, err := queryDNS(arpa, "ptr")
+ if err != nil {
+ return
+ }
+ for _, line := range lines {
+ f := getFields(line)
+ if len(f) < 3 {
+ continue
+ }
+ name = append(name, f[2])
+ }
+ return
+}
diff --git a/libgo/go/net/srv_test.go b/libgo/go/net/lookup_test.go
index f1c7a0ab..995ab03 100644
--- a/libgo/go/net/srv_test.go
+++ b/libgo/go/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/libgo/go/net/lookup_unix.go b/libgo/go/net/lookup_unix.go
new file mode 100644
index 0000000..8f5e66212
--- /dev/null
+++ b/libgo/go/net/lookup_unix.go
@@ -0,0 +1,111 @@
+// 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.
+
+package net
+
+import (
+ "os"
+)
+
+// LookupHost looks up the given host using the local resolver.
+// It returns an array of that host's addresses.
+func LookupHost(host string) (addrs []string, err os.Error) {
+ addrs, err, ok := cgoLookupHost(host)
+ if !ok {
+ addrs, err = goLookupHost(host)
+ }
+ return
+}
+
+// LookupIP looks up host using the local resolver.
+// It returns an array of that host's IPv4 and IPv6 addresses.
+func LookupIP(host string) (addrs []IP, err os.Error) {
+ addrs, err, ok := cgoLookupIP(host)
+ if !ok {
+ addrs, err = goLookupIP(host)
+ }
+ return
+}
+
+// LookupPort looks up the port for the given network and service.
+func LookupPort(network, service string) (port int, err os.Error) {
+ port, err, ok := cgoLookupPort(network, service)
+ if !ok {
+ port, err = goLookupPort(network, service)
+ }
+ return
+}
+
+// LookupCNAME returns the canonical DNS host for the given name.
+// Callers that do not care about the canonical name can call
+// LookupHost or LookupIP directly; both take care of resolving
+// the canonical name as part of the lookup.
+func LookupCNAME(name string) (cname string, err os.Error) {
+ cname, err, ok := cgoLookupCNAME(name)
+ if !ok {
+ cname, err = goLookupCNAME(name)
+ }
+ return
+}
+
+// LookupSRV tries to resolve an SRV query of the given service,
+// protocol, and domain name, as specified in RFC 2782. In most cases
+// the proto argument can be the same as the corresponding
+// Addr.Network(). The returned records are sorted by priority
+// and randomized by weight within a priority.
+func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
+ target := "_" + service + "._" + proto + "." + name
+ var records []dnsRR
+ cname, records, err = lookup(target, dnsTypeSRV)
+ if err != nil {
+ return
+ }
+ addrs = make([]*SRV, len(records))
+ for i, rr := range records {
+ r := rr.(*dnsRR_SRV)
+ addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
+ }
+ byPriorityWeight(addrs).sort()
+ return
+}
+
+// LookupMX returns the DNS MX records for the given domain name sorted by preference.
+func LookupMX(name string) (mx []*MX, err os.Error) {
+ _, rr, err := lookup(name, dnsTypeMX)
+ if err != nil {
+ return
+ }
+ mx = make([]*MX, len(rr))
+ for i := range rr {
+ r := rr[i].(*dnsRR_MX)
+ mx[i] = &MX{r.Mx, r.Pref}
+ }
+ byPref(mx).sort()
+ return
+}
+
+// LookupAddr performs a reverse lookup for the given address, returning a list
+// of names mapping to that address.
+func LookupAddr(addr string) (name []string, err os.Error) {
+ name = lookupStaticAddr(addr)
+ if len(name) > 0 {
+ return
+ }
+ var arpa string
+ arpa, err = reverseaddr(addr)
+ if err != nil {
+ return
+ }
+ var records []dnsRR
+ _, records, err = lookup(arpa, dnsTypePTR)
+ if err != nil {
+ return
+ }
+ name = make([]string, len(records))
+ for i := range records {
+ r := records[i].(*dnsRR_PTR)
+ name[i] = r.Ptr
+ }
+ return
+}
diff --git a/libgo/go/net/resolv_windows.go b/libgo/go/net/lookup_windows.go
index f7c3f51..fa3ad7c 100644
--- a/libgo/go/net/resolv_windows.go
+++ b/libgo/go/net/lookup_windows.go
@@ -14,8 +14,8 @@ import (
var hostentLock sync.Mutex
var serventLock sync.Mutex
-func goLookupHost(name string) (addrs []string, err os.Error) {
- ips, err := goLookupIP(name)
+func LookupHost(name string) (addrs []string, err os.Error) {
+ ips, err := LookupIP(name)
if err != nil {
return
}
@@ -26,7 +26,7 @@ func goLookupHost(name string) (addrs []string, err os.Error) {
return
}
-func goLookupIP(name string) (addrs []IP, err os.Error) {
+func LookupIP(name string) (addrs []IP, err os.Error) {
hostentLock.Lock()
defer hostentLock.Unlock()
h, e := syscall.GetHostByName(name)
@@ -47,7 +47,23 @@ func goLookupIP(name string) (addrs []IP, err os.Error) {
return addrs, nil
}
-func goLookupCNAME(name string) (cname string, err os.Error) {
+func LookupPort(network, service string) (port int, err os.Error) {
+ switch network {
+ case "tcp4", "tcp6":
+ network = "tcp"
+ case "udp4", "udp6":
+ network = "udp"
+ }
+ serventLock.Lock()
+ defer serventLock.Unlock()
+ s, e := syscall.GetServByName(service, network)
+ if e != 0 {
+ return 0, os.NewSyscallError("GetServByName", e)
+ }
+ return int(syscall.Ntohs(s.Port)), nil
+}
+
+func LookupCNAME(name string) (cname string, err os.Error) {
var r *syscall.DNSRecord
e := syscall.DnsQuery(name, syscall.DNS_TYPE_CNAME, 0, nil, &r, nil)
if int(e) != 0 {
@@ -61,13 +77,6 @@ func goLookupCNAME(name string) (cname string, err os.Error) {
return
}
-type SRV struct {
- Target string
- Port uint16
- Priority uint16
- Weight uint16
-}
-
func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err os.Error) {
var r *syscall.DNSRecord
target := "_" + service + "._" + proto + "." + name
@@ -76,66 +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
}
-func goLookupPort(network, service string) (port int, err os.Error) {
- switch network {
- case "tcp4", "tcp6":
- network = "tcp"
- case "udp4", "udp6":
- network = "udp"
+func LookupMX(name string) (mx []*MX, err os.Error) {
+ 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))
}
- serventLock.Lock()
- defer serventLock.Unlock()
- s, e := syscall.GetServByName(service, network)
- if e != 0 {
- return 0, os.NewSyscallError("GetServByName", 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})
}
- return int(syscall.Ntohs(s.Port)), nil
-}
-
-// TODO(brainman): Following code is only to get tests running.
-
-func isDomainName(s string) bool {
- panic("unimplemented")
+ byPref(mx).sort()
+ return mx, nil
}
-func reverseaddr(addr string) (arpa string, err os.Error) {
- panic("unimplemented")
-}
-
-func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs []dnsRR, err os.Error) {
- panic("unimplemented")
-}
-
-// DNSError represents a DNS lookup error.
-type DNSError struct {
- Error string // description of the error
- Name string // name looked for
- Server string // server used
- IsTimeout bool
-}
-
-func (e *DNSError) String() string {
- if e == nil {
- return "<nil>"
+func LookupAddr(addr string) (name []string, err os.Error) {
+ arpa, err := reverseaddr(addr)
+ if err != nil {
+ return nil, err
}
- s := "lookup " + e.Name
- if e.Server != "" {
- s += " on " + e.Server
+ 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))
}
- s += ": " + e.Error
- return s
+ 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
}
-
-func (e *DNSError) Timeout() bool { return e.IsTimeout }
-func (e *DNSError) Temporary() bool { return e.IsTimeout }
diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go
index 51db107..5c84d34 100644
--- a/libgo/go/net/net.go
+++ b/libgo/go/net/net.go
@@ -115,7 +115,7 @@ type Listener interface {
Addr() Addr
}
-var errMissingAddress = os.ErrorString("missing address")
+var errMissingAddress = os.NewError("missing address")
type OpError struct {
Op string
diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go
index da79283..dc0d49d 100644
--- a/libgo/go/net/net_test.go
+++ b/libgo/go/net/net_test.go
@@ -7,7 +7,6 @@ package net
import (
"flag"
"regexp"
- "runtime"
"testing"
)
@@ -103,9 +102,6 @@ var revAddrTests = []struct {
}
func TestReverseAddress(t *testing.T) {
- if runtime.GOOS == "windows" {
- return
- }
for i, tt := range revAddrTests {
a, e := reverseaddr(tt.Addr)
if len(tt.ErrPrefix) > 0 && e == nil {
diff --git a/libgo/go/net/newpollserver.go b/libgo/go/net/newpollserver.go
index fff54db..4272087 100644
--- a/libgo/go/net/newpollserver.go
+++ b/libgo/go/net/newpollserver.go
@@ -18,12 +18,7 @@ func newPollServer() (s *pollServer, err os.Error) {
}
var e int
if e = syscall.SetNonblock(s.pr.Fd(), true); e != 0 {
- Errno:
- err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
- Error:
- s.pr.Close()
- s.pw.Close()
- return nil, err
+ goto Errno
}
if e = syscall.SetNonblock(s.pw.Fd(), true); e != 0 {
goto Errno
@@ -38,4 +33,11 @@ func newPollServer() (s *pollServer, err os.Error) {
s.pending = make(map[int]*netFD)
go s.Run()
return s, nil
+
+Errno:
+ err = &os.PathError{"setnonblock", s.pr.Name(), os.Errno(e)}
+Error:
+ s.pr.Close()
+ s.pw.Close()
+ return nil, err
}
diff --git a/libgo/go/net/parse_test.go b/libgo/go/net/parse_test.go
index 226f354..8d51eba 100644
--- a/libgo/go/net/parse_test.go
+++ b/libgo/go/net/parse_test.go
@@ -12,8 +12,8 @@ import (
)
func TestReadLine(t *testing.T) {
- // /etc/services file does not exist on windows.
- if runtime.GOOS == "windows" {
+ // /etc/services file does not exist on windows and Plan 9.
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
filename := "/etc/services" // a nice big file
diff --git a/libgo/go/net/sendfile_linux.go b/libgo/go/net/sendfile_linux.go
new file mode 100644
index 0000000..6a5a06c
--- /dev/null
+++ b/libgo/go/net/sendfile_linux.go
@@ -0,0 +1,84 @@
+// 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.
+
+package net
+
+import (
+ "io"
+ "os"
+ "syscall"
+)
+
+// maxSendfileSize is the largest chunk size we ask the kernel to copy
+// at a time.
+const maxSendfileSize int = 4 << 20
+
+// sendFile copies the contents of r to c using the sendfile
+// system call to minimize copies.
+//
+// if handled == true, sendFile returns the number of bytes copied and any
+// non-EOF error.
+//
+// if handled == false, sendFile performed no work.
+func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool) {
+ var remain int64 = 1 << 62 // by default, copy until EOF
+
+ lr, ok := r.(*io.LimitedReader)
+ if ok {
+ remain, r = lr.N, lr.R
+ if remain <= 0 {
+ return 0, nil, true
+ }
+ }
+ f, ok := r.(*os.File)
+ if !ok {
+ return 0, nil, false
+ }
+
+ c.wio.Lock()
+ defer c.wio.Unlock()
+ c.incref()
+ defer c.decref()
+ if c.wdeadline_delta > 0 {
+ // This is a little odd that we're setting the timeout
+ // for the entire file but Write has the same issue
+ // (if one slurps the whole file into memory and
+ // do one large Write). At least they're consistent.
+ c.wdeadline = pollserver.Now() + c.wdeadline_delta
+ } else {
+ c.wdeadline = 0
+ }
+
+ dst := c.sysfd
+ src := f.Fd()
+ for remain > 0 {
+ n := maxSendfileSize
+ if int64(n) > remain {
+ n = int(remain)
+ }
+ n, errno := syscall.Sendfile(dst, src, nil, n)
+ if n > 0 {
+ written += int64(n)
+ remain -= int64(n)
+ }
+ if n == 0 && errno == 0 {
+ break
+ }
+ if errno == syscall.EAGAIN && c.wdeadline >= 0 {
+ pollserver.WaitWrite(c)
+ continue
+ }
+ if errno != 0 {
+ // This includes syscall.ENOSYS (no kernel
+ // support) and syscall.EINVAL (fd types which
+ // don't implement sendfile together)
+ err = &OpError{"sendfile", c.net, c.raddr, os.Errno(errno)}
+ break
+ }
+ }
+ if lr != nil {
+ lr.N = remain
+ }
+ return written, err, written > 0
+}
diff --git a/libgo/go/net/sendfile_stub.go b/libgo/go/net/sendfile_stub.go
new file mode 100644
index 0000000..43e8104
--- /dev/null
+++ b/libgo/go/net/sendfile_stub.go
@@ -0,0 +1,14 @@
+// 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.
+
+package net
+
+import (
+ "io"
+ "os"
+)
+
+func sendFile(c *netFD, r io.Reader) (n int64, err os.Error, handled bool) {
+ return 0, nil, false
+}
diff --git a/libgo/go/net/sendfile_windows.go b/libgo/go/net/sendfile_windows.go
new file mode 100644
index 0000000..3772eee
--- /dev/null
+++ b/libgo/go/net/sendfile_windows.go
@@ -0,0 +1,68 @@
+// 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.
+
+package net
+
+import (
+ "io"
+ "os"
+ "syscall"
+)
+
+type sendfileOp struct {
+ anOp
+ src syscall.Handle // source
+ n uint32
+}
+
+func (o *sendfileOp) Submit() (errno int) {
+ return syscall.TransmitFile(o.fd.sysfd, o.src, o.n, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
+}
+
+func (o *sendfileOp) Name() string {
+ return "TransmitFile"
+}
+
+// sendFile copies the contents of r to c using the TransmitFile
+// system call to minimize copies.
+//
+// if handled == true, sendFile returns the number of bytes copied and any
+// non-EOF error.
+//
+// if handled == false, sendFile performed no work.
+//
+// Note that sendfile for windows does not suppport >2GB file.
+func sendFile(c *netFD, r io.Reader) (written int64, err os.Error, handled bool) {
+ var n int64 = 0 // by default, copy until EOF
+
+ lr, ok := r.(*io.LimitedReader)
+ if ok {
+ n, r = lr.N, lr.R
+ if n <= 0 {
+ return 0, nil, true
+ }
+ }
+ f, ok := r.(*os.File)
+ if !ok {
+ return 0, nil, false
+ }
+
+ c.wio.Lock()
+ defer c.wio.Unlock()
+ c.incref()
+ defer c.decref()
+
+ var o sendfileOp
+ o.Init(c)
+ o.n = uint32(n)
+ o.src = f.Fd()
+ done, err := iosrv.ExecIO(&o, 0)
+ if err != nil {
+ return 0, err, false
+ }
+ if lr != nil {
+ lr.N -= int64(done)
+ }
+ return int64(done), nil, true
+}
diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go
index 075748b..7d7f7fc 100644
--- a/libgo/go/net/server_test.go
+++ b/libgo/go/net/server_test.go
@@ -92,15 +92,22 @@ func connect(t *testing.T, network, addr string, isEmpty bool) {
}
func doTest(t *testing.T, network, listenaddr, dialaddr string) {
- t.Logf("Test %s %s %s\n", network, listenaddr, dialaddr)
+ t.Logf("Test %q %q %q\n", network, listenaddr, dialaddr)
+ switch listenaddr {
+ case "", "0.0.0.0", "[::]", "[::ffff:0.0.0.0]":
+ if testing.Short() || avoidMacFirewall {
+ t.Logf("skip wildcard listen during short test")
+ return
+ }
+ }
listening := make(chan string)
done := make(chan int)
- if network == "tcp" {
+ if network == "tcp" || network == "tcp4" || network == "tcp6" {
listenaddr += ":0" // any available port
}
go runServe(t, network, listenaddr, listening, done)
addr := <-listening // wait for server to start
- if network == "tcp" {
+ if network == "tcp" || network == "tcp4" || network == "tcp6" {
dialaddr += addr[strings.LastIndex(addr, ":"):]
}
connect(t, network, dialaddr, false)
@@ -108,16 +115,39 @@ func doTest(t *testing.T, network, listenaddr, dialaddr string) {
}
func TestTCPServer(t *testing.T) {
+ doTest(t, "tcp", "", "127.0.0.1")
+ doTest(t, "tcp", "0.0.0.0", "127.0.0.1")
doTest(t, "tcp", "127.0.0.1", "127.0.0.1")
- if kernelSupportsIPv6() {
+ doTest(t, "tcp4", "", "127.0.0.1")
+ doTest(t, "tcp4", "0.0.0.0", "127.0.0.1")
+ doTest(t, "tcp4", "127.0.0.1", "127.0.0.1")
+ if supportsIPv6 {
+ doTest(t, "tcp", "", "[::1]")
+ doTest(t, "tcp", "[::]", "[::1]")
doTest(t, "tcp", "[::1]", "[::1]")
+ doTest(t, "tcp6", "", "[::1]")
+ doTest(t, "tcp6", "[::]", "[::1]")
+ doTest(t, "tcp6", "[::1]", "[::1]")
+ }
+ if supportsIPv6 && supportsIPv4map {
+ doTest(t, "tcp", "[::ffff:0.0.0.0]", "127.0.0.1")
+ doTest(t, "tcp", "[::]", "127.0.0.1")
+ doTest(t, "tcp4", "[::ffff:0.0.0.0]", "127.0.0.1")
+ doTest(t, "tcp6", "", "127.0.0.1")
+ doTest(t, "tcp6", "[::ffff:0.0.0.0]", "127.0.0.1")
+ doTest(t, "tcp6", "[::]", "127.0.0.1")
doTest(t, "tcp", "127.0.0.1", "[::ffff:127.0.0.1]")
+ doTest(t, "tcp", "[::ffff:127.0.0.1]", "127.0.0.1")
+ doTest(t, "tcp4", "127.0.0.1", "[::ffff:127.0.0.1]")
+ doTest(t, "tcp4", "[::ffff:127.0.0.1]", "127.0.0.1")
+ doTest(t, "tcp6", "127.0.0.1", "[::ffff:127.0.0.1]")
+ doTest(t, "tcp6", "[::ffff:127.0.0.1]", "127.0.0.1")
}
}
func TestUnixServer(t *testing.T) {
- // "unix" sockets are not supported on windows.
- if runtime.GOOS == "windows" {
+ // "unix" sockets are not supported on windows and Plan 9.
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
os.Remove("/tmp/gotest.net")
@@ -186,7 +216,7 @@ func TestUDPServer(t *testing.T) {
for _, isEmpty := range []bool{false, true} {
doTestPacket(t, "udp", "0.0.0.0", "127.0.0.1", isEmpty)
doTestPacket(t, "udp", "", "127.0.0.1", isEmpty)
- if kernelSupportsIPv6() {
+ if supportsIPv6 && supportsIPv4map {
doTestPacket(t, "udp", "[::]", "[::ffff:127.0.0.1]", isEmpty)
doTestPacket(t, "udp", "[::]", "127.0.0.1", isEmpty)
doTestPacket(t, "udp", "0.0.0.0", "[::ffff:127.0.0.1]", isEmpty)
@@ -195,8 +225,8 @@ func TestUDPServer(t *testing.T) {
}
func TestUnixDatagramServer(t *testing.T) {
- // "unix" sockets are not supported on windows.
- if runtime.GOOS == "windows" {
+ // "unix" sockets are not supported on windows and Plan 9.
+ if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
return
}
for _, isEmpty := range []bool{false} {
diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go
index 21bd5f0..821716e 100644
--- a/libgo/go/net/sock.go
+++ b/libgo/go/net/sock.go
@@ -7,6 +7,7 @@
package net
import (
+ "io"
"os"
"reflect"
"syscall"
@@ -49,8 +50,7 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
if ra != nil {
if err = fd.connect(ra); err != nil {
- fd.sysfd = -1
- closesocket(s)
+ fd.Close()
return nil, err
}
}
@@ -64,25 +64,25 @@ func socket(net string, f, p, t int, la, ra syscall.Sockaddr, toAddr func(syscal
return fd, nil
}
-func setsockoptInt(fd, level, opt int, value int) os.Error {
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd, level, opt, value))
+func setsockoptInt(fd *netFD, level, opt int, value int) os.Error {
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, level, opt, value))
}
-func setsockoptNsec(fd, level, opt int, nsec int64) os.Error {
+func setsockoptNsec(fd *netFD, level, opt int, nsec int64) os.Error {
var tv = syscall.NsecToTimeval(nsec)
- return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd, level, opt, &tv))
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd.sysfd, level, opt, &tv))
}
func setReadBuffer(fd *netFD, bytes int) os.Error {
fd.incref()
defer fd.decref()
- return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes)
}
func setWriteBuffer(fd *netFD, bytes int) os.Error {
fd.incref()
defer fd.decref()
- return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes)
}
func setReadTimeout(fd *netFD, nsec int64) os.Error {
@@ -105,7 +105,7 @@ func setTimeout(fd *netFD, nsec int64) os.Error {
func setReuseAddr(fd *netFD, reuse bool) os.Error {
fd.incref()
defer fd.decref()
- return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse))
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, boolint(reuse))
}
func bindToDevice(fd *netFD, dev string) os.Error {
@@ -116,19 +116,19 @@ func bindToDevice(fd *netFD, dev string) os.Error {
func setDontRoute(fd *netFD, dontroute bool) os.Error {
fd.incref()
defer fd.decref()
- return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute))
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_DONTROUTE, boolint(dontroute))
}
func setKeepAlive(fd *netFD, keepalive bool) os.Error {
fd.incref()
defer fd.decref()
- return setsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
+ return setsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, boolint(keepalive))
}
func setNoDelay(fd *netFD, noDelay bool) os.Error {
fd.incref()
defer fd.decref()
- return setsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
+ return setsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, boolint(noDelay))
}
func setLinger(fd *netFD, sec int) os.Error {
@@ -154,15 +154,13 @@ func (e *UnknownSocketError) String() string {
return "unknown socket address type " + reflect.TypeOf(e.sa).String()
}
-func sockaddrToString(sa syscall.Sockaddr) (name string, err os.Error) {
- switch a := sa.(type) {
- case *syscall.SockaddrInet4:
- return JoinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
- case *syscall.SockaddrInet6:
- return JoinHostPort(IP(a.Addr[0:]).String(), itoa(a.Port)), nil
- case *syscall.SockaddrUnix:
- return a.Name, nil
- }
+type writerOnly struct {
+ io.Writer
+}
- return "", &UnknownSocketError{sa}
+// Fallback implementation of io.ReaderFrom's ReadFrom, when sendfile isn't
+// applicable.
+func genericReadFrom(w io.Writer, r io.Reader) (n int64, err os.Error) {
+ // Use wrapper to hide existing r.ReadFrom from io.Copy.
+ return io.Copy(writerOnly{w}, r)
}
diff --git a/libgo/go/net/sock_windows.go b/libgo/go/net/sock_windows.go
index e17c60b..c6dbd04 100644
--- a/libgo/go/net/sock_windows.go
+++ b/libgo/go/net/sock_windows.go
@@ -10,7 +10,7 @@ import (
"syscall"
)
-func setKernelSpecificSockopt(s, f int) {
+func setKernelSpecificSockopt(s syscall.Handle, f int) {
// Allow reuse of recently-used addresses and ports.
syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
diff --git a/libgo/go/net/tcpsock.go b/libgo/go/net/tcpsock.go
index d9aa7cf..f5c0a27 100644
--- a/libgo/go/net/tcpsock.go
+++ b/libgo/go/net/tcpsock.go
@@ -8,19 +8,8 @@ package net
import (
"os"
- "syscall"
)
-func sockaddrToTCP(sa syscall.Sockaddr) Addr {
- switch sa := sa.(type) {
- case *syscall.SockaddrInet4:
- return &TCPAddr{sa.Addr[0:], sa.Port}
- case *syscall.SockaddrInet6:
- return &TCPAddr{sa.Addr[0:], sa.Port}
- }
- return nil
-}
-
// TCPAddr represents the address of a TCP end point.
type TCPAddr struct {
IP IP
@@ -37,258 +26,15 @@ func (a *TCPAddr) String() string {
return JoinHostPort(a.IP.String(), itoa(a.Port))
}
-func (a *TCPAddr) family() int {
- if a == nil || len(a.IP) <= 4 {
- return syscall.AF_INET
- }
- if ip := a.IP.To4(); ip != nil {
- return syscall.AF_INET
- }
- return syscall.AF_INET6
-}
-
-func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
- return ipToSockaddr(family, a.IP, a.Port)
-}
-
-func (a *TCPAddr) toAddr() sockaddr {
- if a == nil { // nil *TCPAddr
- return nil // nil interface
- }
- return a
-}
-
// ResolveTCPAddr parses addr as a TCP address of the form
// host:port and resolves domain names or port names to
-// numeric addresses. A literal IPv6 host address must be
+// numeric addresses on the network net, which must be "tcp",
+// "tcp4" or "tcp6". A literal IPv6 host address must be
// enclosed in square brackets, as in "[::]:80".
-func ResolveTCPAddr(network, addr string) (*TCPAddr, os.Error) {
- ip, port, err := hostPortToIP(network, addr)
+func ResolveTCPAddr(net, addr string) (*TCPAddr, os.Error) {
+ ip, port, err := hostPortToIP(net, addr)
if err != nil {
return nil, err
}
return &TCPAddr{ip, port}, nil
}
-
-// TCPConn is an implementation of the Conn interface
-// for TCP network connections.
-type TCPConn struct {
- fd *netFD
-}
-
-func newTCPConn(fd *netFD) *TCPConn {
- c := &TCPConn{fd}
- c.SetNoDelay(true)
- return c
-}
-
-func (c *TCPConn) ok() bool { return c != nil && c.fd != nil }
-
-// Implementation of the Conn interface - see Conn for documentation.
-
-// Read implements the net.Conn Read method.
-func (c *TCPConn) Read(b []byte) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- return c.fd.Read(b)
-}
-
-// Write implements the net.Conn Write method.
-func (c *TCPConn) Write(b []byte) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- return c.fd.Write(b)
-}
-
-// Close closes the TCP connection.
-func (c *TCPConn) Close() os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- err := c.fd.Close()
- c.fd = nil
- return err
-}
-
-// LocalAddr returns the local network address, a *TCPAddr.
-func (c *TCPConn) LocalAddr() Addr {
- if !c.ok() {
- return nil
- }
- return c.fd.laddr
-}
-
-// RemoteAddr returns the remote network address, a *TCPAddr.
-func (c *TCPConn) RemoteAddr() Addr {
- if !c.ok() {
- return nil
- }
- return c.fd.raddr
-}
-
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *TCPConn) SetTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setTimeout(c.fd, nsec)
-}
-
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *TCPConn) SetReadTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setReadTimeout(c.fd, nsec)
-}
-
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *TCPConn) SetWriteTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setWriteTimeout(c.fd, nsec)
-}
-
-// SetReadBuffer sets the size of the operating system's
-// receive buffer associated with the connection.
-func (c *TCPConn) SetReadBuffer(bytes int) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setReadBuffer(c.fd, bytes)
-}
-
-// SetWriteBuffer sets the size of the operating system's
-// transmit buffer associated with the connection.
-func (c *TCPConn) SetWriteBuffer(bytes int) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setWriteBuffer(c.fd, bytes)
-}
-
-// SetLinger sets the behavior of Close() on a connection
-// which still has data waiting to be sent or to be acknowledged.
-//
-// If sec < 0 (the default), Close returns immediately and
-// the operating system finishes sending the data in the background.
-//
-// If sec == 0, Close returns immediately and the operating system
-// discards any unsent or unacknowledged data.
-//
-// If sec > 0, Close blocks for at most sec seconds waiting for
-// data to be sent and acknowledged.
-func (c *TCPConn) SetLinger(sec int) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setLinger(c.fd, sec)
-}
-
-// SetKeepAlive sets whether the operating system should send
-// keepalive messages on the connection.
-func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setKeepAlive(c.fd, keepalive)
-}
-
-// SetNoDelay controls whether the operating system should delay
-// packet transmission in hopes of sending fewer packets
-// (Nagle's algorithm). The default is true (no delay), meaning
-// that data is sent as soon as possible after a Write.
-func (c *TCPConn) SetNoDelay(noDelay bool) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setNoDelay(c.fd, noDelay)
-}
-
-// File returns a copy of the underlying os.File, set to blocking mode.
-// It is the caller's responsibility to close f when finished.
-// Closing c does not affect f, and closing f does not affect c.
-func (c *TCPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
-
-// DialTCP connects to the remote address raddr on the network net,
-// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
-// as the local address for the connection.
-func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
- if raddr == nil {
- return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
- }
- fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
- if e != nil {
- return nil, e
- }
- return newTCPConn(fd), nil
-}
-
-// TCPListener is a TCP network listener.
-// Clients should typically use variables of type Listener
-// instead of assuming TCP.
-type TCPListener struct {
- fd *netFD
-}
-
-// ListenTCP announces on the TCP address laddr and returns a TCP listener.
-// Net must be "tcp", "tcp4", or "tcp6".
-// If laddr has a port of 0, it means to listen on some available port.
-// The caller can use l.Addr() to retrieve the chosen address.
-func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) {
- fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
- if err != nil {
- return nil, err
- }
- errno := syscall.Listen(fd.sysfd, listenBacklog())
- if errno != 0 {
- closesocket(fd.sysfd)
- return nil, &OpError{"listen", "tcp", laddr, os.Errno(errno)}
- }
- l = new(TCPListener)
- l.fd = fd
- return l, nil
-}
-
-// AcceptTCP accepts the next incoming call and returns the new connection
-// and the remote address.
-func (l *TCPListener) AcceptTCP() (c *TCPConn, err os.Error) {
- if l == nil || l.fd == nil || l.fd.sysfd < 0 {
- return nil, os.EINVAL
- }
- fd, err := l.fd.accept(sockaddrToTCP)
- if err != nil {
- return nil, err
- }
- return newTCPConn(fd), nil
-}
-
-// Accept implements the Accept method in the Listener interface;
-// it waits for the next call and returns a generic Conn.
-func (l *TCPListener) Accept() (c Conn, err os.Error) {
- c1, err := l.AcceptTCP()
- if err != nil {
- return nil, err
- }
- return c1, nil
-}
-
-// Close stops listening on the TCP address.
-// Already Accepted connections are not closed.
-func (l *TCPListener) Close() os.Error {
- if l == nil || l.fd == nil {
- return os.EINVAL
- }
- return l.fd.Close()
-}
-
-// Addr returns the listener's network address, a *TCPAddr.
-func (l *TCPListener) Addr() Addr { return l.fd.laddr }
-
-// File returns a copy of the underlying os.File, set to blocking mode.
-// It is the caller's responsibility to close f when finished.
-// Closing c does not affect f, and closing f does not affect c.
-func (l *TCPListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
diff --git a/libgo/go/net/tcpsock_plan9.go b/libgo/go/net/tcpsock_plan9.go
new file mode 100644
index 0000000..f4f6e9f
--- /dev/null
+++ b/libgo/go/net/tcpsock_plan9.go
@@ -0,0 +1,63 @@
+// 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.
+
+// TCP for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// TCPConn is an implementation of the Conn interface
+// for TCP network connections.
+type TCPConn struct {
+ plan9Conn
+}
+
+// DialTCP connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if raddr == nil {
+ return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
+ }
+ c1, err := dialPlan9(net, laddr, raddr)
+ if err != nil {
+ return
+ }
+ return &TCPConn{*c1}, nil
+}
+
+// TCPListener is a TCP network listener.
+// Clients should typically use variables of type Listener
+// instead of assuming TCP.
+type TCPListener struct {
+ plan9Listener
+}
+
+// ListenTCP announces on the TCP address laddr and returns a TCP listener.
+// Net must be "tcp", "tcp4", or "tcp6".
+// If laddr has a port of 0, it means to listen on some available port.
+// The caller can use l.Addr() to retrieve the chosen address.
+func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) {
+ switch net {
+ case "tcp", "tcp4", "tcp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr == nil {
+ return nil, &OpError{"listen", "tcp", nil, errMissingAddress}
+ }
+ l1, err := listenPlan9(net, laddr)
+ if err != nil {
+ return
+ }
+ return &TCPListener{*l1}, nil
+}
diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go
new file mode 100644
index 0000000..5560301
--- /dev/null
+++ b/libgo/go/net/tcpsock_posix.go
@@ -0,0 +1,283 @@
+// 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.
+
+// TCP sockets
+
+package net
+
+import (
+ "io"
+ "os"
+ "syscall"
+)
+
+func sockaddrToTCP(sa syscall.Sockaddr) Addr {
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return &TCPAddr{sa.Addr[0:], sa.Port}
+ case *syscall.SockaddrInet6:
+ return &TCPAddr{sa.Addr[0:], sa.Port}
+ }
+ return nil
+}
+
+func (a *TCPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if a.IP.To4() != nil {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+ return ipToSockaddr(family, a.IP, a.Port)
+}
+
+func (a *TCPAddr) toAddr() sockaddr {
+ if a == nil { // nil *TCPAddr
+ return nil // nil interface
+ }
+ return a
+}
+
+// TCPConn is an implementation of the Conn interface
+// for TCP network connections.
+type TCPConn struct {
+ fd *netFD
+}
+
+func newTCPConn(fd *netFD) *TCPConn {
+ c := &TCPConn{fd}
+ c.SetNoDelay(true)
+ return c
+}
+
+func (c *TCPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *TCPConn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Read(b)
+}
+
+// ReadFrom implements the io.ReaderFrom ReadFrom method.
+func (c *TCPConn) ReadFrom(r io.Reader) (int64, os.Error) {
+ if n, err, handled := sendFile(c.fd, r); handled {
+ return n, err
+ }
+ return genericReadFrom(c, r)
+}
+
+// Write implements the net.Conn Write method.
+func (c *TCPConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the TCP connection.
+func (c *TCPConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address, a *TCPAddr.
+func (c *TCPConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *TCPAddr.
+func (c *TCPConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *TCPConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *TCPConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *TCPConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *TCPConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *TCPConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// SetLinger sets the behavior of Close() on a connection
+// which still has data waiting to be sent or to be acknowledged.
+//
+// If sec < 0 (the default), Close returns immediately and
+// the operating system finishes sending the data in the background.
+//
+// If sec == 0, Close returns immediately and the operating system
+// discards any unsent or unacknowledged data.
+//
+// If sec > 0, Close blocks for at most sec seconds waiting for
+// data to be sent and acknowledged.
+func (c *TCPConn) SetLinger(sec int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setLinger(c.fd, sec)
+}
+
+// SetKeepAlive sets whether the operating system should send
+// keepalive messages on the connection.
+func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setKeepAlive(c.fd, keepalive)
+}
+
+// SetNoDelay controls whether the operating system should delay
+// packet transmission in hopes of sending fewer packets
+// (Nagle's algorithm). The default is true (no delay), meaning
+// that data is sent as soon as possible after a Write.
+func (c *TCPConn) SetNoDelay(noDelay bool) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setNoDelay(c.fd, noDelay)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *TCPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
+// DialTCP connects to the remote address raddr on the network net,
+// which must be "tcp", "tcp4", or "tcp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialTCP(net string, laddr, raddr *TCPAddr) (c *TCPConn, err os.Error) {
+ if raddr == nil {
+ return nil, &OpError{"dial", "tcp", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_STREAM, 0, "dial", sockaddrToTCP)
+ if e != nil {
+ return nil, e
+ }
+ return newTCPConn(fd), nil
+}
+
+// TCPListener is a TCP network listener.
+// Clients should typically use variables of type Listener
+// instead of assuming TCP.
+type TCPListener struct {
+ fd *netFD
+}
+
+// ListenTCP announces on the TCP address laddr and returns a TCP listener.
+// Net must be "tcp", "tcp4", or "tcp6".
+// If laddr has a port of 0, it means to listen on some available port.
+// The caller can use l.Addr() to retrieve the chosen address.
+func ListenTCP(net string, laddr *TCPAddr) (l *TCPListener, err os.Error) {
+ fd, err := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_STREAM, 0, "listen", sockaddrToTCP)
+ if err != nil {
+ return nil, err
+ }
+ errno := syscall.Listen(fd.sysfd, listenBacklog())
+ if errno != 0 {
+ closesocket(fd.sysfd)
+ return nil, &OpError{"listen", "tcp", laddr, os.Errno(errno)}
+ }
+ l = new(TCPListener)
+ l.fd = fd
+ return l, nil
+}
+
+// AcceptTCP accepts the next incoming call and returns the new connection
+// and the remote address.
+func (l *TCPListener) AcceptTCP() (c *TCPConn, err os.Error) {
+ if l == nil || l.fd == nil || l.fd.sysfd < 0 {
+ return nil, os.EINVAL
+ }
+ fd, err := l.fd.accept(sockaddrToTCP)
+ if err != nil {
+ return nil, err
+ }
+ return newTCPConn(fd), nil
+}
+
+// Accept implements the Accept method in the Listener interface;
+// it waits for the next call and returns a generic Conn.
+func (l *TCPListener) Accept() (c Conn, err os.Error) {
+ c1, err := l.AcceptTCP()
+ if err != nil {
+ return nil, err
+ }
+ return c1, nil
+}
+
+// Close stops listening on the TCP address.
+// Already Accepted connections are not closed.
+func (l *TCPListener) Close() os.Error {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+ return l.fd.Close()
+}
+
+// Addr returns the listener's network address, a *TCPAddr.
+func (l *TCPListener) Addr() Addr { return l.fd.laddr }
+
+// SetTimeout sets the deadline associated with the listener
+func (l *TCPListener) SetTimeout(nsec int64) os.Error {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+ return setTimeout(l.fd, nsec)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (l *TCPListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
diff --git a/libgo/go/net/textproto/reader.go b/libgo/go/net/textproto/reader.go
index ac12786..ce0ddc7 100644
--- a/libgo/go/net/textproto/reader.go
+++ b/libgo/go/net/textproto/reader.go
@@ -7,7 +7,6 @@ package textproto
import (
"bufio"
"bytes"
- "container/vector"
"io"
"io/ioutil"
"os"
@@ -33,22 +32,25 @@ func NewReader(r *bufio.Reader) *Reader {
// ReadLine reads a single line from r,
// eliding the final \n or \r\n from the returned string.
func (r *Reader) ReadLine() (string, os.Error) {
- line, err := r.ReadLineBytes()
+ line, err := r.readLineSlice()
return string(line), err
}
// ReadLineBytes is like ReadLine but returns a []byte instead of a string.
func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
- r.closeDot()
- line, err := r.R.ReadBytes('\n')
- n := len(line)
- if n > 0 && line[n-1] == '\n' {
- n--
- if n > 0 && line[n-1] == '\r' {
- n--
- }
+ line, err := r.readLineSlice()
+ if line != nil {
+ buf := make([]byte, len(line))
+ copy(buf, line)
+ line = buf
}
- return line[0:n], err
+ return line, err
+}
+
+func (r *Reader) readLineSlice() ([]byte, os.Error) {
+ r.closeDot()
+ line, _, err := r.R.ReadLine()
+ return line, err
}
// ReadContinuedLine reads a possibly continued line from r,
@@ -71,7 +73,7 @@ func (r *Reader) ReadLineBytes() ([]byte, os.Error) {
// A line consisting of only white space is never continued.
//
func (r *Reader) ReadContinuedLine() (string, os.Error) {
- line, err := r.ReadContinuedLineBytes()
+ line, err := r.readContinuedLineSlice()
return string(line), err
}
@@ -92,8 +94,18 @@ func trim(s []byte) []byte {
// ReadContinuedLineBytes is like ReadContinuedLine but
// returns a []byte instead of a string.
func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
+ line, err := r.readContinuedLineSlice()
+ if line != nil {
+ buf := make([]byte, len(line))
+ copy(buf, line)
+ line = buf
+ }
+ return line, err
+}
+
+func (r *Reader) readContinuedLineSlice() ([]byte, os.Error) {
// Read the first line.
- line, err := r.ReadLineBytes()
+ line, err := r.readLineSlice()
if err != nil {
return line, err
}
@@ -102,6 +114,13 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
}
line = trim(line)
+ copied := false
+ if r.R.Buffered() < 1 {
+ // ReadByte will flush the buffer; make a copy of the slice.
+ copied = true
+ line = append([]byte(nil), line...)
+ }
+
// Look for a continuation line.
c, err := r.R.ReadByte()
if err != nil {
@@ -114,6 +133,11 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
return line, nil
}
+ if !copied {
+ // The next readLineSlice will invalidate the previous one.
+ line = append(make([]byte, 0, len(line)*2), line...)
+ }
+
// Read continuation lines.
for {
// Consume leading spaces; one already gone.
@@ -128,7 +152,7 @@ func (r *Reader) ReadContinuedLineBytes() ([]byte, os.Error) {
}
}
var cont []byte
- cont, err = r.ReadLineBytes()
+ cont, err = r.readLineSlice()
cont = trim(cont)
line = append(line, ' ')
line = append(line, cont...)
@@ -237,7 +261,7 @@ func (r *Reader) ReadResponse(expectCode int) (code int, message string, err os.
// to a method on r.
//
// Dot encoding is a common framing used for data blocks
-// in text protcols like SMTP. The data consists of a sequence
+// in text protocols such as SMTP. The data consists of a sequence
// of lines, each of which ends in "\r\n". The sequence itself
// ends at a line containing just a dot: ".\r\n". Lines beginning
// with a dot are escaped with an additional dot to avoid
@@ -375,7 +399,7 @@ func (r *Reader) ReadDotLines() ([]string, os.Error) {
// We could use ReadDotBytes and then Split it,
// but reading a line at a time avoids needing a
// large contiguous block of memory and is simpler.
- var v vector.StringVector
+ var v []string
var err os.Error
for {
var line string
@@ -394,7 +418,7 @@ func (r *Reader) ReadDotLines() ([]string, os.Error) {
}
line = line[1:]
}
- v.Push(line)
+ v = append(v, line)
}
return v, err
}
@@ -422,7 +446,7 @@ func (r *Reader) ReadDotLines() ([]string, os.Error) {
func (r *Reader) ReadMIMEHeader() (MIMEHeader, os.Error) {
m := make(MIMEHeader)
for {
- kv, err := r.ReadContinuedLineBytes()
+ kv, err := r.readContinuedLineSlice()
if len(kv) == 0 {
return m, err
}
@@ -441,9 +465,7 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, os.Error) {
}
value := string(kv[i:])
- v := vector.StringVector(m[key])
- v.Push(value)
- m[key] = v
+ m[key] = append(m[key], value)
if err != nil {
return m, err
diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go
index 6768447..3dfa716 100644
--- a/libgo/go/net/udpsock.go
+++ b/libgo/go/net/udpsock.go
@@ -8,19 +8,8 @@ package net
import (
"os"
- "syscall"
)
-func sockaddrToUDP(sa syscall.Sockaddr) Addr {
- switch sa := sa.(type) {
- case *syscall.SockaddrInet4:
- return &UDPAddr{sa.Addr[0:], sa.Port}
- case *syscall.SockaddrInet6:
- return &UDPAddr{sa.Addr[0:], sa.Port}
- }
- return nil
-}
-
// UDPAddr represents the address of a UDP end point.
type UDPAddr struct {
IP IP
@@ -37,286 +26,15 @@ func (a *UDPAddr) String() string {
return JoinHostPort(a.IP.String(), itoa(a.Port))
}
-func (a *UDPAddr) family() int {
- if a == nil || len(a.IP) <= 4 {
- return syscall.AF_INET
- }
- if ip := a.IP.To4(); ip != nil {
- return syscall.AF_INET
- }
- return syscall.AF_INET6
-}
-
-func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
- return ipToSockaddr(family, a.IP, a.Port)
-}
-
-func (a *UDPAddr) toAddr() sockaddr {
- if a == nil { // nil *UDPAddr
- return nil // nil interface
- }
- return a
-}
-
// ResolveUDPAddr parses addr as a UDP address of the form
// host:port and resolves domain names or port names to
-// numeric addresses. A literal IPv6 host address must be
+// numeric addresses on the network net, which must be "udp",
+// "udp4" or "udp6". A literal IPv6 host address must be
// enclosed in square brackets, as in "[::]:80".
-func ResolveUDPAddr(network, addr string) (*UDPAddr, os.Error) {
- ip, port, err := hostPortToIP(network, addr)
+func ResolveUDPAddr(net, addr string) (*UDPAddr, os.Error) {
+ ip, port, err := hostPortToIP(net, addr)
if err != nil {
return nil, err
}
return &UDPAddr{ip, port}, nil
}
-
-// UDPConn is the implementation of the Conn and PacketConn
-// interfaces for UDP network connections.
-type UDPConn struct {
- fd *netFD
-}
-
-func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{fd} }
-
-func (c *UDPConn) ok() bool { return c != nil && c.fd != nil }
-
-// Implementation of the Conn interface - see Conn for documentation.
-
-// Read implements the net.Conn Read method.
-func (c *UDPConn) Read(b []byte) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- return c.fd.Read(b)
-}
-
-// Write implements the net.Conn Write method.
-func (c *UDPConn) Write(b []byte) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- return c.fd.Write(b)
-}
-
-// Close closes the UDP connection.
-func (c *UDPConn) Close() os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- err := c.fd.Close()
- c.fd = nil
- return err
-}
-
-// LocalAddr returns the local network address.
-func (c *UDPConn) LocalAddr() Addr {
- if !c.ok() {
- return nil
- }
- return c.fd.laddr
-}
-
-// RemoteAddr returns the remote network address, a *UDPAddr.
-func (c *UDPConn) RemoteAddr() Addr {
- if !c.ok() {
- return nil
- }
- return c.fd.raddr
-}
-
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *UDPConn) SetTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setTimeout(c.fd, nsec)
-}
-
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *UDPConn) SetReadTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setReadTimeout(c.fd, nsec)
-}
-
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *UDPConn) SetWriteTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setWriteTimeout(c.fd, nsec)
-}
-
-// SetReadBuffer sets the size of the operating system's
-// receive buffer associated with the connection.
-func (c *UDPConn) SetReadBuffer(bytes int) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setReadBuffer(c.fd, bytes)
-}
-
-// SetWriteBuffer sets the size of the operating system's
-// transmit buffer associated with the connection.
-func (c *UDPConn) SetWriteBuffer(bytes int) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setWriteBuffer(c.fd, bytes)
-}
-
-// UDP-specific methods.
-
-// ReadFromUDP reads a UDP packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
-//
-// ReadFromUDP can be made to time out and return an error with Timeout() == true
-// after a fixed time limit; see SetTimeout and SetReadTimeout.
-func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
- if !c.ok() {
- return 0, nil, os.EINVAL
- }
- n, sa, err := c.fd.ReadFrom(b)
- switch sa := sa.(type) {
- case *syscall.SockaddrInet4:
- addr = &UDPAddr{sa.Addr[0:], sa.Port}
- case *syscall.SockaddrInet6:
- addr = &UDPAddr{sa.Addr[0:], sa.Port}
- }
- return
-}
-
-// ReadFrom implements the net.PacketConn ReadFrom method.
-func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
- if !c.ok() {
- return 0, nil, os.EINVAL
- }
- n, uaddr, err := c.ReadFromUDP(b)
- return n, uaddr.toAddr(), err
-}
-
-// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
-//
-// WriteToUDP can be made to time out and return
-// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetWriteTimeout.
-// On packet-oriented connections, write timeouts are rare.
-func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- sa, err1 := addr.sockaddr(c.fd.family)
- if err1 != nil {
- return 0, &OpError{Op: "write", Net: "udp", Addr: addr, Error: err1}
- }
- return c.fd.WriteTo(b, sa)
-}
-
-// WriteTo implements the net.PacketConn WriteTo method.
-func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- a, ok := addr.(*UDPAddr)
- if !ok {
- return 0, &OpError{"writeto", "udp", addr, os.EINVAL}
- }
- return c.WriteToUDP(b, a)
-}
-
-// DialUDP connects to the remote address raddr on the network net,
-// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is used
-// as the local address for the connection.
-func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error) {
- switch net {
- case "udp", "udp4", "udp6":
- default:
- return nil, UnknownNetworkError(net)
- }
- if raddr == nil {
- return nil, &OpError{"dial", "udp", nil, errMissingAddress}
- }
- fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
- if e != nil {
- return nil, e
- }
- return newUDPConn(fd), nil
-}
-
-// ListenUDP listens for incoming UDP packets addressed to the
-// local address laddr. The returned connection c's ReadFrom
-// and WriteTo methods can be used to receive and send UDP
-// packets with per-packet addressing.
-func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err os.Error) {
- switch net {
- case "udp", "udp4", "udp6":
- default:
- return nil, UnknownNetworkError(net)
- }
- if laddr == nil {
- return nil, &OpError{"listen", "udp", nil, errMissingAddress}
- }
- fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
- if e != nil {
- return nil, e
- }
- return newUDPConn(fd), nil
-}
-
-// BindToDevice binds a UDPConn to a network interface.
-func (c *UDPConn) BindToDevice(device string) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- c.fd.incref()
- defer c.fd.decref()
- return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
-}
-
-// File returns a copy of the underlying os.File, set to blocking mode.
-// It is the caller's responsibility to close f when finished.
-// Closing c does not affect f, and closing f does not affect c.
-func (c *UDPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
-
-var errInvalidMulticast = os.ErrorString("invalid IPv4 multicast address")
-
-// JoinGroup joins the IPv4 multicast group named by addr.
-// The UDPConn must use the "udp4" network.
-func (c *UDPConn) JoinGroup(addr IP) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- ip := addr.To4()
- if ip == nil {
- return &OpError{"joingroup", "udp", &IPAddr{ip}, errInvalidMulticast}
- }
- mreq := &syscall.IpMreq{
- Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
- }
- err := os.NewSyscallError("setsockopt", syscall.SetsockoptIpMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
- if err != nil {
- return &OpError{"joingroup", "udp", &IPAddr{ip}, err}
- }
- return nil
-}
-
-// LeaveGroup exits the IPv4 multicast group named by addr.
-func (c *UDPConn) LeaveGroup(addr IP) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- ip := addr.To4()
- if ip == nil {
- return &OpError{"leavegroup", "udp", &IPAddr{ip}, errInvalidMulticast}
- }
- mreq := &syscall.IpMreq{
- Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
- }
- err := os.NewSyscallError("setsockopt", syscall.SetsockoptIpMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq))
- if err != nil {
- return &OpError{"leavegroup", "udp", &IPAddr{ip}, err}
- }
- return nil
-}
diff --git a/libgo/go/net/udpsock_plan9.go b/libgo/go/net/udpsock_plan9.go
new file mode 100644
index 0000000..bb71960
--- /dev/null
+++ b/libgo/go/net/udpsock_plan9.go
@@ -0,0 +1,187 @@
+// 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.
+
+// UDP for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// UDPConn is the implementation of the Conn and PacketConn
+// interfaces for UDP network connections.
+type UDPConn struct {
+ plan9Conn
+}
+
+// UDP-specific methods.
+
+// ReadFromUDP reads a UDP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromUDP can be made to time out and return an error with Timeout() == true
+// after a fixed time limit; see SetTimeout and SetReadTimeout.
+func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, nil, err
+ }
+ }
+ buf := make([]byte, udpHeaderSize+len(b))
+ m, err := c.data.Read(buf)
+ if err != nil {
+ return
+ }
+ if m < udpHeaderSize {
+ return 0, nil, os.NewError("short read reading UDP header")
+ }
+ buf = buf[:m]
+
+ h, buf := unmarshalUDPHeader(buf)
+ n = copy(b, buf)
+ return n, &UDPAddr{h.raddr, int(h.rport)}, nil
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ return c.ReadFromUDP(b)
+}
+
+// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
+//
+// WriteToUDP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ if c.data == nil {
+ c.data, err = os.OpenFile(c.dir+"/data", os.O_RDWR, 0)
+ if err != nil {
+ return 0, err
+ }
+ }
+ h := new(udpHeader)
+ h.raddr = addr.IP.To16()
+ h.laddr = c.laddr.(*UDPAddr).IP.To16()
+ h.ifcaddr = IPv6zero // ignored (receive only)
+ h.rport = uint16(addr.Port)
+ h.lport = uint16(c.laddr.(*UDPAddr).Port)
+
+ buf := make([]byte, udpHeaderSize+len(b))
+ i := copy(buf, h.Bytes())
+ copy(buf[i:], b)
+ return c.data.Write(buf)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ a, ok := addr.(*UDPAddr)
+ if !ok {
+ return 0, &OpError{"writeto", "udp", addr, os.EINVAL}
+ }
+ return c.WriteToUDP(b, a)
+}
+
+// DialUDP connects to the remote address raddr on the network net,
+// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if raddr == nil {
+ return nil, &OpError{"dial", "udp", nil, errMissingAddress}
+ }
+ c1, err := dialPlan9(net, laddr, raddr)
+ if err != nil {
+ return
+ }
+ return &UDPConn{*c1}, nil
+}
+
+const udpHeaderSize = 16*3 + 2*2
+
+type udpHeader struct {
+ raddr, laddr, ifcaddr IP
+ rport, lport uint16
+}
+
+func (h *udpHeader) Bytes() []byte {
+ b := make([]byte, udpHeaderSize)
+ i := 0
+ i += copy(b[i:i+16], h.raddr)
+ i += copy(b[i:i+16], h.laddr)
+ i += copy(b[i:i+16], h.ifcaddr)
+ b[i], b[i+1], i = byte(h.rport>>8), byte(h.rport), i+2
+ b[i], b[i+1], i = byte(h.lport>>8), byte(h.lport), i+2
+ return b
+}
+
+func unmarshalUDPHeader(b []byte) (*udpHeader, []byte) {
+ h := new(udpHeader)
+ h.raddr, b = IP(b[:16]), b[16:]
+ h.laddr, b = IP(b[:16]), b[16:]
+ h.ifcaddr, b = IP(b[:16]), b[16:]
+ h.rport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
+ h.lport, b = uint16(b[0])<<8|uint16(b[1]), b[2:]
+ return h, b
+}
+
+// ListenUDP listens for incoming UDP packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send UDP
+// packets with per-packet addressing.
+func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr == nil {
+ return nil, &OpError{"listen", "udp", nil, errMissingAddress}
+ }
+ l, err := listenPlan9(net, laddr)
+ if err != nil {
+ return
+ }
+ _, err = l.ctl.WriteString("headers")
+ if err != nil {
+ return
+ }
+ return &UDPConn{*l.plan9Conn()}, nil
+}
+
+// JoinGroup joins the IPv4 multicast group named by addr.
+// The UDPConn must use the "udp4" network.
+func (c *UDPConn) JoinGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
+
+// LeaveGroup exits the IPv4 multicast group named by addr.
+func (c *UDPConn) LeaveGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return os.EPLAN9
+}
diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go
new file mode 100644
index 0000000..d4ea056
--- /dev/null
+++ b/libgo/go/net/udpsock_posix.go
@@ -0,0 +1,294 @@
+// 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.
+
+// UDP sockets
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func sockaddrToUDP(sa syscall.Sockaddr) Addr {
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ return &UDPAddr{sa.Addr[0:], sa.Port}
+ case *syscall.SockaddrInet6:
+ return &UDPAddr{sa.Addr[0:], sa.Port}
+ }
+ return nil
+}
+
+func (a *UDPAddr) family() int {
+ if a == nil || len(a.IP) <= 4 {
+ return syscall.AF_INET
+ }
+ if a.IP.To4() != nil {
+ return syscall.AF_INET
+ }
+ return syscall.AF_INET6
+}
+
+func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, os.Error) {
+ return ipToSockaddr(family, a.IP, a.Port)
+}
+
+func (a *UDPAddr) toAddr() sockaddr {
+ if a == nil { // nil *UDPAddr
+ return nil // nil interface
+ }
+ return a
+}
+
+// UDPConn is the implementation of the Conn and PacketConn
+// interfaces for UDP network connections.
+type UDPConn struct {
+ fd *netFD
+}
+
+func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{fd} }
+
+func (c *UDPConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *UDPConn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Read(b)
+}
+
+// Write implements the net.Conn Write method.
+func (c *UDPConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the UDP connection.
+func (c *UDPConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address.
+func (c *UDPConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *UDPAddr.
+func (c *UDPConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *UDPConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *UDPConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *UDPConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *UDPConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *UDPConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// UDP-specific methods.
+
+// ReadFromUDP reads a UDP packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromUDP can be made to time out and return an error with Timeout() == true
+// after a fixed time limit; see SetTimeout and SetReadTimeout.
+func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, sa, err := c.fd.ReadFrom(b)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ addr = &UDPAddr{sa.Addr[0:], sa.Port}
+ case *syscall.SockaddrInet6:
+ addr = &UDPAddr{sa.Addr[0:], sa.Port}
+ }
+ return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UDPConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, uaddr, err := c.ReadFromUDP(b)
+ return n, uaddr.toAddr(), err
+}
+
+// WriteToUDP writes a UDP packet to addr via c, copying the payload from b.
+//
+// WriteToUDP can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ sa, err1 := addr.sockaddr(c.fd.family)
+ if err1 != nil {
+ return 0, &OpError{Op: "write", Net: "udp", Addr: addr, Error: err1}
+ }
+ return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UDPConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ a, ok := addr.(*UDPAddr)
+ if !ok {
+ return 0, &OpError{"writeto", "udp", addr, os.EINVAL}
+ }
+ return c.WriteToUDP(b, a)
+}
+
+// DialUDP connects to the remote address raddr on the network net,
+// which must be "udp", "udp4", or "udp6". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUDP(net string, laddr, raddr *UDPAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if raddr == nil {
+ return nil, &OpError{"dial", "udp", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), raddr.toAddr(), syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
+ if e != nil {
+ return nil, e
+ }
+ return newUDPConn(fd), nil
+}
+
+// ListenUDP listens for incoming UDP packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send UDP
+// packets with per-packet addressing.
+func ListenUDP(net string, laddr *UDPAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "udp", "udp4", "udp6":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr == nil {
+ return nil, &OpError{"listen", "udp", nil, errMissingAddress}
+ }
+ fd, e := internetSocket(net, laddr.toAddr(), nil, syscall.SOCK_DGRAM, 0, "dial", sockaddrToUDP)
+ if e != nil {
+ return nil, e
+ }
+ return newUDPConn(fd), nil
+}
+
+// BindToDevice binds a UDPConn to a network interface.
+func (c *UDPConn) BindToDevice(device string) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ c.fd.incref()
+ defer c.fd.decref()
+ return os.NewSyscallError("setsockopt", syscall.BindToDevice(c.fd.sysfd, device))
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UDPConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
+var errInvalidMulticast = os.NewError("invalid IPv4 multicast address")
+
+// JoinGroup joins the IPv4 multicast group named by addr.
+// The UDPConn must use the "udp4" network.
+func (c *UDPConn) JoinGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ ip := addr.To4()
+ if ip == nil {
+ return &OpError{"joingroup", "udp", &IPAddr{ip}, errInvalidMulticast}
+ }
+ mreq := &syscall.IPMreq{
+ Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
+ }
+ err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_ADD_MEMBERSHIP, mreq))
+ if err != nil {
+ return &OpError{"joingroup", "udp", &IPAddr{ip}, err}
+ }
+ return nil
+}
+
+// LeaveGroup exits the IPv4 multicast group named by addr.
+func (c *UDPConn) LeaveGroup(addr IP) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ ip := addr.To4()
+ if ip == nil {
+ return &OpError{"leavegroup", "udp", &IPAddr{ip}, errInvalidMulticast}
+ }
+ mreq := &syscall.IPMreq{
+ Multiaddr: [4]byte{ip[0], ip[1], ip[2], ip[3]},
+ }
+ err := os.NewSyscallError("setsockopt", syscall.SetsockoptIPMreq(c.fd.sysfd, syscall.IPPROTO_IP, syscall.IP_DROP_MEMBERSHIP, mreq))
+ if err != nil {
+ return &OpError{"leavegroup", "udp", &IPAddr{ip}, err}
+ }
+ return nil
+}
diff --git a/libgo/go/net/unixsock.go b/libgo/go/net/unixsock.go
index 8c26a7b..d5040f9 100644
--- a/libgo/go/net/unixsock.go
+++ b/libgo/go/net/unixsock.go
@@ -8,109 +8,14 @@ package net
import (
"os"
- "syscall"
)
-func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err os.Error) {
- var proto int
- switch net {
- default:
- return nil, UnknownNetworkError(net)
- case "unix":
- proto = syscall.SOCK_STREAM
- case "unixgram":
- proto = syscall.SOCK_DGRAM
- case "unixpacket":
- proto = syscall.SOCK_SEQPACKET
- }
-
- var la, ra syscall.Sockaddr
- switch mode {
- default:
- panic("unixSocket mode " + mode)
-
- case "dial":
- if laddr != nil {
- la = &syscall.SockaddrUnix{Name: laddr.Name}
- }
- if raddr != nil {
- ra = &syscall.SockaddrUnix{Name: raddr.Name}
- } else if proto != syscall.SOCK_DGRAM || laddr == nil {
- return nil, &OpError{Op: mode, Net: net, Error: errMissingAddress}
- }
-
- case "listen":
- if laddr == nil {
- return nil, &OpError{mode, net, nil, errMissingAddress}
- }
- la = &syscall.SockaddrUnix{Name: laddr.Name}
- if raddr != nil {
- return nil, &OpError{Op: mode, Net: net, Addr: raddr, Error: &AddrError{Error: "unexpected remote address", Addr: raddr.String()}}
- }
- }
-
- f := sockaddrToUnix
- if proto == syscall.SOCK_DGRAM {
- f = sockaddrToUnixgram
- } else if proto == syscall.SOCK_SEQPACKET {
- f = sockaddrToUnixpacket
- }
-
- fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f)
- if oserr != nil {
- goto Error
- }
- return fd, nil
-
-Error:
- addr := raddr
- if mode == "listen" {
- addr = laddr
- }
- return nil, &OpError{Op: mode, Net: net, Addr: addr, Error: oserr}
-}
-
// UnixAddr represents the address of a Unix domain socket end point.
type UnixAddr struct {
Name string
Net string
}
-func sockaddrToUnix(sa syscall.Sockaddr) Addr {
- if s, ok := sa.(*syscall.SockaddrUnix); ok {
- return &UnixAddr{s.Name, "unix"}
- }
- return nil
-}
-
-func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
- if s, ok := sa.(*syscall.SockaddrUnix); ok {
- return &UnixAddr{s.Name, "unixgram"}
- }
- return nil
-}
-
-func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
- if s, ok := sa.(*syscall.SockaddrUnix); ok {
- return &UnixAddr{s.Name, "unixpacket"}
- }
- return nil
-}
-
-func protoToNet(proto int) string {
- switch proto {
- case syscall.SOCK_STREAM:
- return "unix"
- case syscall.SOCK_SEQPACKET:
- return "unixpacket"
- case syscall.SOCK_DGRAM:
- return "unixgram"
- default:
- panic("protoToNet unknown protocol")
- }
- return ""
-}
-
// Network returns the address's network name, "unix" or "unixgram".
func (a *UnixAddr) Network() string {
return a.Net
@@ -143,307 +48,3 @@ func ResolveUnixAddr(net, addr string) (*UnixAddr, os.Error) {
}
return &UnixAddr{addr, net}, nil
}
-
-// UnixConn is an implementation of the Conn interface
-// for connections to Unix domain sockets.
-type UnixConn struct {
- fd *netFD
-}
-
-func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{fd} }
-
-func (c *UnixConn) ok() bool { return c != nil && c.fd != nil }
-
-// Implementation of the Conn interface - see Conn for documentation.
-
-// Read implements the net.Conn Read method.
-func (c *UnixConn) Read(b []byte) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- return c.fd.Read(b)
-}
-
-// Write implements the net.Conn Write method.
-func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- return c.fd.Write(b)
-}
-
-// Close closes the Unix domain connection.
-func (c *UnixConn) Close() os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- err := c.fd.Close()
- c.fd = nil
- return err
-}
-
-// LocalAddr returns the local network address, a *UnixAddr.
-// Unlike in other protocols, LocalAddr is usually nil for dialed connections.
-func (c *UnixConn) LocalAddr() Addr {
- if !c.ok() {
- return nil
- }
- return c.fd.laddr
-}
-
-// RemoteAddr returns the remote network address, a *UnixAddr.
-// Unlike in other protocols, RemoteAddr is usually nil for connections
-// accepted by a listener.
-func (c *UnixConn) RemoteAddr() Addr {
- if !c.ok() {
- return nil
- }
- return c.fd.raddr
-}
-
-// SetTimeout implements the net.Conn SetTimeout method.
-func (c *UnixConn) SetTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setTimeout(c.fd, nsec)
-}
-
-// SetReadTimeout implements the net.Conn SetReadTimeout method.
-func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setReadTimeout(c.fd, nsec)
-}
-
-// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
-func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setWriteTimeout(c.fd, nsec)
-}
-
-// SetReadBuffer sets the size of the operating system's
-// receive buffer associated with the connection.
-func (c *UnixConn) SetReadBuffer(bytes int) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setReadBuffer(c.fd, bytes)
-}
-
-// SetWriteBuffer sets the size of the operating system's
-// transmit buffer associated with the connection.
-func (c *UnixConn) SetWriteBuffer(bytes int) os.Error {
- if !c.ok() {
- return os.EINVAL
- }
- return setWriteBuffer(c.fd, bytes)
-}
-
-// ReadFromUnix reads a packet from c, copying the payload into b.
-// It returns the number of bytes copied into b and the return address
-// that was on the packet.
-//
-// ReadFromUnix can be made to time out and return
-// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetReadTimeout.
-func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error) {
- if !c.ok() {
- return 0, nil, os.EINVAL
- }
- n, sa, err := c.fd.ReadFrom(b)
- switch sa := sa.(type) {
- case *syscall.SockaddrUnix:
- addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
- }
- return
-}
-
-// ReadFrom implements the net.PacketConn ReadFrom method.
-func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
- if !c.ok() {
- return 0, nil, os.EINVAL
- }
- n, uaddr, err := c.ReadFromUnix(b)
- return n, uaddr.toAddr(), err
-}
-
-// WriteToUnix writes a packet to addr via c, copying the payload from b.
-//
-// WriteToUnix can be made to time out and return
-// an error with Timeout() == true after a fixed time limit;
-// see SetTimeout and SetWriteTimeout.
-// On packet-oriented connections, write timeouts are rare.
-func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- if addr.Net != protoToNet(c.fd.proto) {
- return 0, os.EAFNOSUPPORT
- }
- sa := &syscall.SockaddrUnix{Name: addr.Name}
- return c.fd.WriteTo(b, sa)
-}
-
-// WriteTo implements the net.PacketConn WriteTo method.
-func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
- if !c.ok() {
- return 0, os.EINVAL
- }
- a, ok := addr.(*UnixAddr)
- if !ok {
- return 0, &OpError{"writeto", "unix", addr, os.EINVAL}
- }
- return c.WriteToUnix(b, a)
-}
-
-func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err os.Error) {
- if !c.ok() {
- return 0, 0, 0, nil, os.EINVAL
- }
- n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
- switch sa := sa.(type) {
- case *syscall.SockaddrUnix:
- addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
- }
- return
-}
-
-func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err os.Error) {
- if !c.ok() {
- return 0, 0, os.EINVAL
- }
- if addr != nil {
- if addr.Net != protoToNet(c.fd.proto) {
- return 0, 0, os.EAFNOSUPPORT
- }
- sa := &syscall.SockaddrUnix{Name: addr.Name}
- return c.fd.WriteMsg(b, oob, sa)
- }
- return c.fd.WriteMsg(b, oob, nil)
-}
-
-// File returns a copy of the underlying os.File, set to blocking mode.
-// It is the caller's responsibility to close f when finished.
-// Closing c does not affect f, and closing f does not affect c.
-func (c *UnixConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
-
-// DialUnix connects to the remote address raddr on the network net,
-// which must be "unix" or "unixgram". If laddr is not nil, it is used
-// as the local address for the connection.
-func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err os.Error) {
- fd, e := unixSocket(net, laddr, raddr, "dial")
- if e != nil {
- return nil, e
- }
- return newUnixConn(fd), nil
-}
-
-// UnixListener is a Unix domain socket listener.
-// Clients should typically use variables of type Listener
-// instead of assuming Unix domain sockets.
-type UnixListener struct {
- fd *netFD
- path string
-}
-
-// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
-// Net must be "unix" (stream sockets).
-func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
- if net != "unix" && net != "unixgram" && net != "unixpacket" {
- return nil, UnknownNetworkError(net)
- }
- if laddr != nil {
- laddr = &UnixAddr{laddr.Name, net} // make our own copy
- }
- fd, err := unixSocket(net, laddr, nil, "listen")
- if err != nil {
- return nil, err
- }
- e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
- if e1 != 0 {
- closesocket(fd.sysfd)
- return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Error: os.Errno(e1)}
- }
- return &UnixListener{fd, laddr.Name}, nil
-}
-
-// AcceptUnix accepts the next incoming call and returns the new connection
-// and the remote address.
-func (l *UnixListener) AcceptUnix() (c *UnixConn, err os.Error) {
- if l == nil || l.fd == nil {
- return nil, os.EINVAL
- }
- fd, e := l.fd.accept(sockaddrToUnix)
- if e != nil {
- return nil, e
- }
- c = newUnixConn(fd)
- return c, nil
-}
-
-// Accept implements the Accept method in the Listener interface;
-// it waits for the next call and returns a generic Conn.
-func (l *UnixListener) Accept() (c Conn, err os.Error) {
- c1, err := l.AcceptUnix()
- if err != nil {
- return nil, err
- }
- return c1, nil
-}
-
-// Close stops listening on the Unix address.
-// Already accepted connections are not closed.
-func (l *UnixListener) Close() os.Error {
- if l == nil || l.fd == nil {
- return os.EINVAL
- }
-
- // The operating system doesn't clean up
- // the file that announcing created, so
- // we have to clean it up ourselves.
- // There's a race here--we can't know for
- // sure whether someone else has come along
- // and replaced our socket name already--
- // but this sequence (remove then close)
- // is at least compatible with the auto-remove
- // sequence in ListenUnix. It's only non-Go
- // programs that can mess us up.
- if l.path[0] != '@' {
- syscall.Unlink(l.path)
- }
- err := l.fd.Close()
- l.fd = nil
- return err
-}
-
-// Addr returns the listener's network address.
-func (l *UnixListener) Addr() Addr { return l.fd.laddr }
-
-// File returns a copy of the underlying os.File, set to blocking mode.
-// It is the caller's responsibility to close f when finished.
-// Closing c does not affect f, and closing f does not affect c.
-func (l *UnixListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
-
-// ListenUnixgram listens for incoming Unix datagram packets addressed to the
-// local address laddr. The returned connection c's ReadFrom
-// and WriteTo methods can be used to receive and send UDP
-// packets with per-packet addressing. The network net must be "unixgram".
-func ListenUnixgram(net string, laddr *UnixAddr) (c *UDPConn, err os.Error) {
- switch net {
- case "unixgram":
- default:
- return nil, UnknownNetworkError(net)
- }
- if laddr == nil {
- return nil, &OpError{"listen", "unixgram", nil, errMissingAddress}
- }
- fd, e := unixSocket(net, laddr, nil, "listen")
- if e != nil {
- return nil, e
- }
- return newUDPConn(fd), nil
-}
diff --git a/libgo/go/net/unixsock_plan9.go b/libgo/go/net/unixsock_plan9.go
new file mode 100644
index 0000000..7e212df
--- /dev/null
+++ b/libgo/go/net/unixsock_plan9.go
@@ -0,0 +1,105 @@
+// 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.
+
+// Unix domain sockets stubs for Plan 9
+
+package net
+
+import (
+ "os"
+)
+
+// UnixConn is an implementation of the Conn interface
+// for connections to Unix domain sockets.
+type UnixConn bool
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *UnixConn) Read(b []byte) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// Write implements the net.Conn Write method.
+func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
+ return 0, os.EPLAN9
+}
+
+// Close closes the Unix domain connection.
+func (c *UnixConn) Close() os.Error {
+ return os.EPLAN9
+}
+
+// LocalAddr returns the local network address, a *UnixAddr.
+// Unlike in other protocols, LocalAddr is usually nil for dialed connections.
+func (c *UnixConn) LocalAddr() Addr {
+ return nil
+}
+
+// RemoteAddr returns the remote network address, a *UnixAddr.
+// Unlike in other protocols, RemoteAddr is usually nil for connections
+// accepted by a listener.
+func (c *UnixConn) RemoteAddr() Addr {
+ return nil
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *UnixConn) SetTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
+ return os.EPLAN9
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ err = os.EPLAN9
+ return
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ err = os.EPLAN9
+ return
+}
+
+// DialUnix connects to the remote address raddr on the network net,
+// which must be "unix" or "unixgram". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// UnixListener is a Unix domain socket listener.
+// Clients should typically use variables of type Listener
+// instead of assuming Unix domain sockets.
+type UnixListener bool
+
+// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
+// Net must be "unix" (stream sockets).
+func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// Accept implements the Accept method in the Listener interface;
+// it waits for the next call and returns a generic Conn.
+func (l *UnixListener) Accept() (c Conn, err os.Error) {
+ return nil, os.EPLAN9
+}
+
+// Close stops listening on the Unix address.
+// Already accepted connections are not closed.
+func (l *UnixListener) Close() os.Error {
+ return os.EPLAN9
+}
+
+// Addr returns the listener's network address.
+func (l *UnixListener) Addr() Addr { return nil }
diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go
new file mode 100644
index 0000000..38c6fe9
--- /dev/null
+++ b/libgo/go/net/unixsock_posix.go
@@ -0,0 +1,418 @@
+// 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.
+
+// Unix domain sockets
+
+package net
+
+import (
+ "os"
+ "syscall"
+)
+
+func unixSocket(net string, laddr, raddr *UnixAddr, mode string) (fd *netFD, err os.Error) {
+ var proto int
+ switch net {
+ default:
+ return nil, UnknownNetworkError(net)
+ case "unix":
+ proto = syscall.SOCK_STREAM
+ case "unixgram":
+ proto = syscall.SOCK_DGRAM
+ case "unixpacket":
+ proto = syscall.SOCK_SEQPACKET
+ }
+
+ var la, ra syscall.Sockaddr
+ switch mode {
+ default:
+ panic("unixSocket mode " + mode)
+
+ case "dial":
+ if laddr != nil {
+ la = &syscall.SockaddrUnix{Name: laddr.Name}
+ }
+ if raddr != nil {
+ ra = &syscall.SockaddrUnix{Name: raddr.Name}
+ } else if proto != syscall.SOCK_DGRAM || laddr == nil {
+ return nil, &OpError{Op: mode, Net: net, Error: errMissingAddress}
+ }
+
+ case "listen":
+ if laddr == nil {
+ return nil, &OpError{mode, net, nil, errMissingAddress}
+ }
+ la = &syscall.SockaddrUnix{Name: laddr.Name}
+ if raddr != nil {
+ return nil, &OpError{Op: mode, Net: net, Addr: raddr, Error: &AddrError{Error: "unexpected remote address", Addr: raddr.String()}}
+ }
+ }
+
+ f := sockaddrToUnix
+ if proto == syscall.SOCK_DGRAM {
+ f = sockaddrToUnixgram
+ } else if proto == syscall.SOCK_SEQPACKET {
+ f = sockaddrToUnixpacket
+ }
+
+ fd, oserr := socket(net, syscall.AF_UNIX, proto, 0, la, ra, f)
+ if oserr != nil {
+ goto Error
+ }
+ return fd, nil
+
+Error:
+ addr := raddr
+ if mode == "listen" {
+ addr = laddr
+ }
+ return nil, &OpError{Op: mode, Net: net, Addr: addr, Error: oserr}
+}
+
+func sockaddrToUnix(sa syscall.Sockaddr) Addr {
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
+ return &UnixAddr{s.Name, "unix"}
+ }
+ return nil
+}
+
+func sockaddrToUnixgram(sa syscall.Sockaddr) Addr {
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
+ return &UnixAddr{s.Name, "unixgram"}
+ }
+ return nil
+}
+
+func sockaddrToUnixpacket(sa syscall.Sockaddr) Addr {
+ if s, ok := sa.(*syscall.SockaddrUnix); ok {
+ return &UnixAddr{s.Name, "unixpacket"}
+ }
+ return nil
+}
+
+func protoToNet(proto int) string {
+ switch proto {
+ case syscall.SOCK_STREAM:
+ return "unix"
+ case syscall.SOCK_SEQPACKET:
+ return "unixpacket"
+ case syscall.SOCK_DGRAM:
+ return "unixgram"
+ default:
+ panic("protoToNet unknown protocol")
+ }
+ return ""
+}
+
+// UnixConn is an implementation of the Conn interface
+// for connections to Unix domain sockets.
+type UnixConn struct {
+ fd *netFD
+}
+
+func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{fd} }
+
+func (c *UnixConn) ok() bool { return c != nil && c.fd != nil }
+
+// Implementation of the Conn interface - see Conn for documentation.
+
+// Read implements the net.Conn Read method.
+func (c *UnixConn) Read(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Read(b)
+}
+
+// Write implements the net.Conn Write method.
+func (c *UnixConn) Write(b []byte) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ return c.fd.Write(b)
+}
+
+// Close closes the Unix domain connection.
+func (c *UnixConn) Close() os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ err := c.fd.Close()
+ c.fd = nil
+ return err
+}
+
+// LocalAddr returns the local network address, a *UnixAddr.
+// Unlike in other protocols, LocalAddr is usually nil for dialed connections.
+func (c *UnixConn) LocalAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.laddr
+}
+
+// RemoteAddr returns the remote network address, a *UnixAddr.
+// Unlike in other protocols, RemoteAddr is usually nil for connections
+// accepted by a listener.
+func (c *UnixConn) RemoteAddr() Addr {
+ if !c.ok() {
+ return nil
+ }
+ return c.fd.raddr
+}
+
+// SetTimeout implements the net.Conn SetTimeout method.
+func (c *UnixConn) SetTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setTimeout(c.fd, nsec)
+}
+
+// SetReadTimeout implements the net.Conn SetReadTimeout method.
+func (c *UnixConn) SetReadTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadTimeout(c.fd, nsec)
+}
+
+// SetWriteTimeout implements the net.Conn SetWriteTimeout method.
+func (c *UnixConn) SetWriteTimeout(nsec int64) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteTimeout(c.fd, nsec)
+}
+
+// SetReadBuffer sets the size of the operating system's
+// receive buffer associated with the connection.
+func (c *UnixConn) SetReadBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setReadBuffer(c.fd, bytes)
+}
+
+// SetWriteBuffer sets the size of the operating system's
+// transmit buffer associated with the connection.
+func (c *UnixConn) SetWriteBuffer(bytes int) os.Error {
+ if !c.ok() {
+ return os.EINVAL
+ }
+ return setWriteBuffer(c.fd, bytes)
+}
+
+// ReadFromUnix reads a packet from c, copying the payload into b.
+// It returns the number of bytes copied into b and the return address
+// that was on the packet.
+//
+// ReadFromUnix can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetReadTimeout.
+func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, sa, err := c.fd.ReadFrom(b)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrUnix:
+ addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
+ }
+ return
+}
+
+// ReadFrom implements the net.PacketConn ReadFrom method.
+func (c *UnixConn) ReadFrom(b []byte) (n int, addr Addr, err os.Error) {
+ if !c.ok() {
+ return 0, nil, os.EINVAL
+ }
+ n, uaddr, err := c.ReadFromUnix(b)
+ return n, uaddr.toAddr(), err
+}
+
+// WriteToUnix writes a packet to addr via c, copying the payload from b.
+//
+// WriteToUnix can be made to time out and return
+// an error with Timeout() == true after a fixed time limit;
+// see SetTimeout and SetWriteTimeout.
+// On packet-oriented connections, write timeouts are rare.
+func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ if addr.Net != protoToNet(c.fd.proto) {
+ return 0, os.EAFNOSUPPORT
+ }
+ sa := &syscall.SockaddrUnix{Name: addr.Name}
+ return c.fd.WriteTo(b, sa)
+}
+
+// WriteTo implements the net.PacketConn WriteTo method.
+func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err os.Error) {
+ if !c.ok() {
+ return 0, os.EINVAL
+ }
+ a, ok := addr.(*UnixAddr)
+ if !ok {
+ return 0, &OpError{"writeto", "unix", addr, os.EINVAL}
+ }
+ return c.WriteToUnix(b, a)
+}
+
+func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err os.Error) {
+ if !c.ok() {
+ return 0, 0, 0, nil, os.EINVAL
+ }
+ n, oobn, flags, sa, err := c.fd.ReadMsg(b, oob)
+ switch sa := sa.(type) {
+ case *syscall.SockaddrUnix:
+ addr = &UnixAddr{sa.Name, protoToNet(c.fd.proto)}
+ }
+ return
+}
+
+func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err os.Error) {
+ if !c.ok() {
+ return 0, 0, os.EINVAL
+ }
+ if addr != nil {
+ if addr.Net != protoToNet(c.fd.proto) {
+ return 0, 0, os.EAFNOSUPPORT
+ }
+ sa := &syscall.SockaddrUnix{Name: addr.Name}
+ return c.fd.WriteMsg(b, oob, sa)
+ }
+ return c.fd.WriteMsg(b, oob, nil)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (c *UnixConn) File() (f *os.File, err os.Error) { return c.fd.dup() }
+
+// DialUnix connects to the remote address raddr on the network net,
+// which must be "unix" or "unixgram". If laddr is not nil, it is used
+// as the local address for the connection.
+func DialUnix(net string, laddr, raddr *UnixAddr) (c *UnixConn, err os.Error) {
+ fd, e := unixSocket(net, laddr, raddr, "dial")
+ if e != nil {
+ return nil, e
+ }
+ return newUnixConn(fd), nil
+}
+
+// UnixListener is a Unix domain socket listener.
+// Clients should typically use variables of type Listener
+// instead of assuming Unix domain sockets.
+type UnixListener struct {
+ fd *netFD
+ path string
+}
+
+// ListenUnix announces on the Unix domain socket laddr and returns a Unix listener.
+// Net must be "unix" (stream sockets).
+func ListenUnix(net string, laddr *UnixAddr) (l *UnixListener, err os.Error) {
+ if net != "unix" && net != "unixgram" && net != "unixpacket" {
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr != nil {
+ laddr = &UnixAddr{laddr.Name, net} // make our own copy
+ }
+ fd, err := unixSocket(net, laddr, nil, "listen")
+ if err != nil {
+ return nil, err
+ }
+ e1 := syscall.Listen(fd.sysfd, 8) // listenBacklog());
+ if e1 != 0 {
+ closesocket(fd.sysfd)
+ return nil, &OpError{Op: "listen", Net: "unix", Addr: laddr, Error: os.Errno(e1)}
+ }
+ return &UnixListener{fd, laddr.Name}, nil
+}
+
+// AcceptUnix accepts the next incoming call and returns the new connection
+// and the remote address.
+func (l *UnixListener) AcceptUnix() (c *UnixConn, err os.Error) {
+ if l == nil || l.fd == nil {
+ return nil, os.EINVAL
+ }
+ fd, e := l.fd.accept(sockaddrToUnix)
+ if e != nil {
+ return nil, e
+ }
+ c = newUnixConn(fd)
+ return c, nil
+}
+
+// Accept implements the Accept method in the Listener interface;
+// it waits for the next call and returns a generic Conn.
+func (l *UnixListener) Accept() (c Conn, err os.Error) {
+ c1, err := l.AcceptUnix()
+ if err != nil {
+ return nil, err
+ }
+ return c1, nil
+}
+
+// Close stops listening on the Unix address.
+// Already accepted connections are not closed.
+func (l *UnixListener) Close() os.Error {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+
+ // The operating system doesn't clean up
+ // the file that announcing created, so
+ // we have to clean it up ourselves.
+ // There's a race here--we can't know for
+ // sure whether someone else has come along
+ // and replaced our socket name already--
+ // but this sequence (remove then close)
+ // is at least compatible with the auto-remove
+ // sequence in ListenUnix. It's only non-Go
+ // programs that can mess us up.
+ if l.path[0] != '@' {
+ syscall.Unlink(l.path)
+ }
+ err := l.fd.Close()
+ l.fd = nil
+ return err
+}
+
+// Addr returns the listener's network address.
+func (l *UnixListener) Addr() Addr { return l.fd.laddr }
+
+// SetTimeout sets the deadline associated wuth the listener
+func (l *UnixListener) SetTimeout(nsec int64) (err os.Error) {
+ if l == nil || l.fd == nil {
+ return os.EINVAL
+ }
+ return setTimeout(l.fd, nsec)
+}
+
+// File returns a copy of the underlying os.File, set to blocking mode.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func (l *UnixListener) File() (f *os.File, err os.Error) { return l.fd.dup() }
+
+// ListenUnixgram listens for incoming Unix datagram packets addressed to the
+// local address laddr. The returned connection c's ReadFrom
+// and WriteTo methods can be used to receive and send UDP
+// packets with per-packet addressing. The network net must be "unixgram".
+func ListenUnixgram(net string, laddr *UnixAddr) (c *UDPConn, err os.Error) {
+ switch net {
+ case "unixgram":
+ default:
+ return nil, UnknownNetworkError(net)
+ }
+ if laddr == nil {
+ return nil, &OpError{"listen", "unixgram", nil, errMissingAddress}
+ }
+ fd, e := unixSocket(net, laddr, nil, "listen")
+ if e != nil {
+ return nil, e
+ }
+ return newUDPConn(fd), nil
+}