diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-01-13 05:11:45 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-01-13 05:11:45 +0000 |
commit | df4aa89a5e7acb315655f193e7f549e8d32367e2 (patch) | |
tree | eb5eccc07097c5fcf940967f33ab84a7d47c96fe /libgo/go/net | |
parent | f83fa0bf8f411697ec908cfa86ee6faf4cd9c476 (diff) | |
download | gcc-df4aa89a5e7acb315655f193e7f549e8d32367e2.zip gcc-df4aa89a5e7acb315655f193e7f549e8d32367e2.tar.gz gcc-df4aa89a5e7acb315655f193e7f549e8d32367e2.tar.bz2 |
libgo: Update to weekly.2011-12-22.
From-SVN: r183150
Diffstat (limited to 'libgo/go/net')
35 files changed, 514 insertions, 161 deletions
diff --git a/libgo/go/net/cgo_stub.go b/libgo/go/net/cgo_stub.go index fbe6150..66aff83 100644 --- a/libgo/go/net/cgo_stub.go +++ b/libgo/go/net/cgo_stub.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build openbsd +// +build nocgo // Stub cgo routines for systems that do not use cgo to do network lookups. diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go index 43866dc..00acb84 100644 --- a/libgo/go/net/dial.go +++ b/libgo/go/net/dial.go @@ -4,6 +4,10 @@ package net +import ( + "time" +) + func resolveNetAddr(op, net, addr string) (a Addr, err error) { if addr == "" { return nil, &OpError{op, net, nil, errMissingAddress} @@ -42,11 +46,15 @@ func resolveNetAddr(op, net, addr string) (a Addr, err error) { // Dial("tcp", "google.com:80") // Dial("tcp", "[de:ad:be:ef::ca:fe]:80") // -func Dial(net, addr string) (c Conn, err error) { +func Dial(net, addr string) (Conn, error) { addri, err := resolveNetAddr("dial", net, addr) if err != nil { return nil, err } + return dialAddr(net, addr, addri) +} + +func dialAddr(net, addr string, addri Addr) (c Conn, err error) { switch ra := addri.(type) { case *TCPAddr: c, err = DialTCP(net, nil, ra) @@ -65,6 +73,62 @@ func Dial(net, addr string) (c Conn, err error) { return } +// DialTimeout acts like Dial but takes a timeout. +// The timeout includes name resolution, if required. +func DialTimeout(net, addr string, timeout time.Duration) (Conn, error) { + // TODO(bradfitz): the timeout should be pushed down into the + // net package's event loop, so on timeout to dead hosts we + // don't have a goroutine sticking around for the default of + // ~3 minutes. + t := time.NewTimer(timeout) + defer t.Stop() + type pair struct { + Conn + error + } + ch := make(chan pair, 1) + resolvedAddr := make(chan Addr, 1) + go func() { + addri, err := resolveNetAddr("dial", net, addr) + if err != nil { + ch <- pair{nil, err} + return + } + resolvedAddr <- addri // in case we need it for OpError + c, err := dialAddr(net, addr, addri) + ch <- pair{c, err} + }() + select { + case <-t.C: + // Try to use the real Addr in our OpError, if we resolved it + // before the timeout. Otherwise we just use stringAddr. + var addri Addr + select { + case a := <-resolvedAddr: + addri = a + default: + addri = &stringAddr{net, addr} + } + err := &OpError{ + Op: "dial", + Net: net, + Addr: addri, + Err: &timeoutError{}, + } + return nil, err + case p := <-ch: + return p.Conn, p.error + } + panic("unreachable") +} + +type stringAddr struct { + net, addr string +} + +func (a stringAddr) Network() string { return a.net } +func (a stringAddr) String() string { return a.addr } + // Listen announces on the local network address laddr. // The network string net must be a stream-oriented // network: "tcp", "tcp4", "tcp6", or "unix", or "unixpacket". diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go new file mode 100644 index 0000000..16b7263 --- /dev/null +++ b/libgo/go/net/dial_test.go @@ -0,0 +1,88 @@ +// 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 ( + "runtime" + "testing" + "time" +) + +func newLocalListener(t *testing.T) Listener { + ln, err := Listen("tcp", "127.0.0.1:0") + if err != nil { + ln, err = Listen("tcp6", "[::1]:0") + } + if err != nil { + t.Fatal(err) + } + return ln +} + +func TestDialTimeout(t *testing.T) { + ln := newLocalListener(t) + defer ln.Close() + + errc := make(chan error) + + const SOMAXCONN = 0x80 // copied from syscall, but not always available + const numConns = SOMAXCONN + 10 + + // TODO(bradfitz): It's hard to test this in a portable + // way. This is unforunate, but works for now. + switch runtime.GOOS { + case "linux": + // The kernel will start accepting TCP connections before userspace + // gets a chance to not accept them, so fire off a bunch to fill up + // the kernel's backlog. Then we test we get a failure after that. + for i := 0; i < numConns; i++ { + go func() { + _, err := DialTimeout("tcp", ln.Addr().String(), 200*time.Millisecond) + errc <- err + }() + } + case "darwin": + // At least OS X 10.7 seems to accept any number of + // connections, ignoring listen's backlog, so resort + // to connecting to a hopefully-dead 127/8 address. + go func() { + _, err := DialTimeout("tcp", "127.0.71.111:80", 200*time.Millisecond) + errc <- err + }() + default: + // TODO(bradfitz): this probably doesn't work on + // Windows? SOMAXCONN is huge there. I'm not sure how + // listen works there. + // OpenBSD may have a reject route to 10/8. + // FreeBSD likely works, but is untested. + t.Logf("skipping test on %q; untested.", runtime.GOOS) + return + } + + connected := 0 + for { + select { + case <-time.After(15 * time.Second): + t.Fatal("too slow") + case err := <-errc: + if err == nil { + connected++ + if connected == numConns { + t.Fatal("all connections connected; expected some to time out") + } + } else { + terr, ok := err.(timeout) + if !ok { + t.Fatalf("got error %q; want error with timeout interface", err) + } + if !terr.Timeout() { + t.Fatalf("got error %q; not a timeout", err) + } + // Pass. We saw a timeout error. + return + } + } + } +} diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go index 79a958e..07e72cc 100644 --- a/libgo/go/net/dnsclient_unix.go +++ b/libgo/go/net/dnsclient_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd +// +build darwin freebsd linux netbsd openbsd // DNS client: see RFC 1035. // Has to be linked into package net for Dial. diff --git a/libgo/go/net/dnsconfig.go b/libgo/go/net/dnsconfig.go index 379fec9..c0ab802 100644 --- a/libgo/go/net/dnsconfig.go +++ b/libgo/go/net/dnsconfig.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd +// +build darwin freebsd linux netbsd openbsd // Read system DNS config from /etc/resolv.conf diff --git a/libgo/go/net/fd.go b/libgo/go/net/fd.go index 5318c51..3dec9f4 100644 --- a/libgo/go/net/fd.go +++ b/libgo/go/net/fd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd +// +build darwin freebsd linux netbsd openbsd package net @@ -377,14 +377,6 @@ func (fd *netFD) CloseWrite() error { return fd.shutdown(syscall.SHUT_WR) } -type timeoutError struct{} - -func (e *timeoutError) Error() string { return "i/o timeout" } -func (e *timeoutError) Timeout() bool { return true } -func (e *timeoutError) Temporary() bool { return true } - -var errTimeout error = &timeoutError{} - func (fd *netFD) Read(p []byte) (n int, err error) { if fd == nil { return 0, os.EINVAL diff --git a/libgo/go/net/fd_linux.go b/libgo/go/net/fd_linux.go index 8e07833..c8df9c9 100644 --- a/libgo/go/net/fd_linux.go +++ b/libgo/go/net/fd_linux.go @@ -37,11 +37,17 @@ func newpollster() (p *pollster, err error) { p = new(pollster) var e error - // The arg to epoll_create is a hint to the kernel - // about the number of FDs we will care about. - // We don't know, and since 2.6.8 the kernel ignores it anyhow. - if p.epfd, e = syscall.EpollCreate(16); e != nil { - return nil, os.NewSyscallError("epoll_create", e) + if p.epfd, e = syscall.EpollCreate1(syscall.EPOLL_CLOEXEC); e != nil { + if e != syscall.ENOSYS { + return nil, os.NewSyscallError("epoll_create1", e) + } + // The arg to epoll_create is a hint to the kernel + // about the number of FDs we will care about. + // We don't know, and since 2.6.8 the kernel ignores it anyhow. + if p.epfd, e = syscall.EpollCreate(16); e != nil { + return nil, os.NewSyscallError("epoll_create", e) + } + syscall.CloseOnExec(p.epfd) } p.events = make(map[int]uint32) return p, nil diff --git a/libgo/go/net/fd_netbsd.go b/libgo/go/net/fd_netbsd.go new file mode 100644 index 0000000..31d0744 --- /dev/null +++ b/libgo/go/net/fd_netbsd.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 error) { + p = new(pollster) + if p.kq, err = syscall.Kqueue(); err != nil { + return nil, os.NewSyscallError("kqueue", err) + } + syscall.CloseOnExec(p.kq) + p.events = p.eventbuf[0:0] + return p, nil +} + +func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, 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 != nil { + 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, syscall.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 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 != nil { + 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() error { return os.NewSyscallError("close", syscall.Close(p.kq)) } diff --git a/libgo/go/net/fd_openbsd.go b/libgo/go/net/fd_openbsd.go index e52ac35..31d0744 100644 --- a/libgo/go/net/fd_openbsd.go +++ b/libgo/go/net/fd_openbsd.go @@ -26,6 +26,7 @@ func newpollster() (p *pollster, err error) { if p.kq, err = syscall.Kqueue(); err != nil { return nil, os.NewSyscallError("kqueue", err) } + syscall.CloseOnExec(p.kq) p.events = p.eventbuf[0:0] return p, nil } diff --git a/libgo/go/net/file.go b/libgo/go/net/file.go index bf8cd9d..4ac280b 100644 --- a/libgo/go/net/file.go +++ b/libgo/go/net/file.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd +// +build darwin freebsd linux netbsd openbsd package net diff --git a/libgo/go/net/http/client.go b/libgo/go/net/http/client.go index 211ac44..a4f8f19 100644 --- a/libgo/go/net/http/client.go +++ b/libgo/go/net/http/client.go @@ -38,6 +38,11 @@ type Client struct { // If CheckRedirect is nil, the Client uses its default policy, // which is to stop after 10 consecutive requests. CheckRedirect func(req *Request, via []*Request) error + + // Jar specifies the cookie jar. + // If Jar is nil, cookies are not sent in requests and ignored + // in responses. + Jar CookieJar } // DefaultClient is the default Client and is used by Get, Head, and Post. @@ -180,6 +185,11 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) { return nil, errors.New("http: nil Request.URL") } + jar := c.Jar + if jar == nil { + jar = blackHoleJar{} + } + req := ireq urlStr := "" // next relative or absolute URL to fetch (after first request) for redirect := 0; ; redirect++ { @@ -203,12 +213,19 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) { break } } + for _, cookie := range jar.Cookies(req.URL) { + req.AddCookie(cookie) + } } urlStr = req.URL.String() if r, err = send(req, c.Transport); err != nil { break } + if c := r.Cookies(); len(c) > 0 { + jar.SetCookies(req.URL, c) + } + if shouldRedirect(r.StatusCode) { r.Body.Close() if urlStr = r.Header.Get("Location"); urlStr == "" { diff --git a/libgo/go/net/http/jar.go b/libgo/go/net/http/jar.go new file mode 100644 index 0000000..2c2caa2 --- /dev/null +++ b/libgo/go/net/http/jar.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. + +package http + +import ( + "net/url" +) + +// A CookieJar manages storage and use of cookies in HTTP requests. +// +// Implementations of CookieJar must be safe for concurrent use by multiple +// goroutines. +type CookieJar interface { + // SetCookies handles the receipt of the cookies in a reply for the + // given URL. It may or may not choose to save the cookies, depending + // on the jar's policy and implementation. + SetCookies(u *url.URL, cookies []*Cookie) + + // Cookies returns the cookies to send in a request for the given URL. + // It is up to the implementation to honor the standard cookie use + // restrictions such as in RFC 6265. + Cookies(u *url.URL) []*Cookie +} + +type blackHoleJar struct{} + +func (blackHoleJar) SetCookies(u *url.URL, cookies []*Cookie) {} +func (blackHoleJar) Cookies(u *url.URL) []*Cookie { return nil } diff --git a/libgo/go/net/http/readrequest_test.go b/libgo/go/net/http/readrequest_test.go index c64fff6..ad7e3c0 100644 --- a/libgo/go/net/http/readrequest_test.go +++ b/libgo/go/net/http/readrequest_test.go @@ -219,7 +219,7 @@ func TestReadRequest(t *testing.T) { t.Errorf("#%d: Body = %q want %q", i, body, tt.Body) } if !reflect.DeepEqual(tt.Trailer, req.Trailer) { - t.Errorf("%#d. Trailers differ.\n got: %v\nwant: %v", i, req.Trailer, tt.Trailer) + t.Errorf("#%d. Trailers differ.\n got: %v\nwant: %v", i, req.Trailer, tt.Trailer) } } } diff --git a/libgo/go/net/http/request_test.go b/libgo/go/net/http/request_test.go index 714cb64..7b78645 100644 --- a/libgo/go/net/http/request_test.go +++ b/libgo/go/net/http/request_test.go @@ -202,8 +202,8 @@ func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) { if g, e := req.FormValue("texta"), textaValue; g != e { t.Errorf("texta value = %q, want %q", g, e) } - if g, e := req.FormValue("texta"), textaValue; g != e { - t.Errorf("texta value = %q, want %q", g, e) + if g, e := req.FormValue("textb"), textbValue; g != e { + t.Errorf("textb value = %q, want %q", g, e) } if g := req.FormValue("missing"); g != "" { t.Errorf("missing value = %q, want empty string", g) @@ -214,14 +214,16 @@ func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) { t.Error(n, " is *os.File, should not be") } } - fd := testMultipartFile(t, req, "filea", "filea.txt", fileaContents) - assertMem("filea", fd) - fd = testMultipartFile(t, req, "fileb", "fileb.txt", filebContents) + fda := testMultipartFile(t, req, "filea", "filea.txt", fileaContents) + defer fda.Close() + assertMem("filea", fda) + fdb := testMultipartFile(t, req, "fileb", "fileb.txt", filebContents) + defer fdb.Close() if allMem { - assertMem("fileb", fd) + assertMem("fileb", fdb) } else { - if _, ok := fd.(*os.File); !ok { - t.Errorf("fileb has unexpected underlying type %T", fd) + if _, ok := fdb.(*os.File); !ok { + t.Errorf("fileb has unexpected underlying type %T", fdb) } } diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go index c68e661..24e6b50 100644 --- a/libgo/go/net/http/serve_test.go +++ b/libgo/go/net/http/serve_test.go @@ -1164,15 +1164,15 @@ func BenchmarkClientServer(b *testing.B) { for i := 0; i < b.N; i++ { res, err := Get(ts.URL) if err != nil { - panic("Get: " + err.Error()) + b.Fatal("Get:", err) } all, err := ioutil.ReadAll(res.Body) if err != nil { - panic("ReadAll: " + err.Error()) + b.Fatal("ReadAll:", err) } body := string(all) if body != "Hello world.\n" { - panic("Got body: " + body) + b.Fatal("Got body:", body) } } diff --git a/libgo/go/net/interface_bsd.go b/libgo/go/net/interface_bsd.go index e896d43..907f80a 100644 --- a/libgo/go/net/interface_bsd.go +++ b/libgo/go/net/interface_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd openbsd +// +build darwin freebsd netbsd openbsd // Network interface identification for BSD variants @@ -18,21 +18,16 @@ import ( // network interfaces. Otheriwse it returns a mapping of a specific // interface. func interfaceTable(ifindex int) ([]Interface, error) { - var ( - tab []byte - e error - msgs []syscall.RoutingMessage - ift []Interface - ) - - tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex) - if e != nil { - return nil, os.NewSyscallError("route rib", e) + var ift []Interface + + tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex) + if err != nil { + return nil, os.NewSyscallError("route rib", err) } - msgs, e = syscall.ParseRoutingMessage(tab) - if e != nil { - return nil, os.NewSyscallError("route message", e) + msgs, err := syscall.ParseRoutingMessage(tab) + if err != nil { + return nil, os.NewSyscallError("route message", err) } for _, m := range msgs { @@ -54,9 +49,9 @@ func interfaceTable(ifindex int) ([]Interface, error) { func newLink(m *syscall.InterfaceMessage) ([]Interface, error) { var ift []Interface - sas, e := syscall.ParseRoutingSockaddr(m) - if e != nil { - return nil, os.NewSyscallError("route sockaddr", e) + sas, err := syscall.ParseRoutingSockaddr(m) + if err != nil { + return nil, os.NewSyscallError("route sockaddr", err) } for _, s := range sas { @@ -108,21 +103,16 @@ func linkFlags(rawFlags int32) Flags { // for all network interfaces. Otherwise it returns addresses // for a specific interface. func interfaceAddrTable(ifindex int) ([]Addr, error) { - var ( - tab []byte - e error - msgs []syscall.RoutingMessage - ifat []Addr - ) - - tab, e = syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex) - if e != nil { - return nil, os.NewSyscallError("route rib", e) + var ifat []Addr + + tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex) + if err != nil { + return nil, os.NewSyscallError("route rib", err) } - msgs, e = syscall.ParseRoutingMessage(tab) - if e != nil { - return nil, os.NewSyscallError("route message", e) + msgs, err := syscall.ParseRoutingMessage(tab) + if err != nil { + return nil, os.NewSyscallError("route message", err) } for _, m := range msgs { @@ -133,7 +123,7 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) { if err != nil { return nil, err } - ifat = append(ifat, ifa...) + ifat = append(ifat, ifa) } } } @@ -141,32 +131,41 @@ func interfaceAddrTable(ifindex int) ([]Addr, error) { return ifat, nil } -func newAddr(m *syscall.InterfaceAddrMessage) ([]Addr, error) { - var ifat []Addr +func newAddr(m *syscall.InterfaceAddrMessage) (Addr, error) { + ifa := &IPNet{} - sas, e := syscall.ParseRoutingSockaddr(m) - if e != nil { - return nil, os.NewSyscallError("route sockaddr", e) + sas, err := syscall.ParseRoutingSockaddr(m) + if err != nil { + return nil, os.NewSyscallError("route sockaddr", err) } - for _, s := range sas { + for i, 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()) + switch i { + case 0: + ifa.Mask = IPv4Mask(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3]) + case 1: + ifa.IP = IPv4(v.Addr[0], v.Addr[1], v.Addr[2], v.Addr[3]) + } 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 + switch i { + case 0: + ifa.Mask = make(IPMask, IPv6len) + copy(ifa.Mask, v.Addr[:]) + case 1: + ifa.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 + return ifa, nil } diff --git a/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go index 96db718..c0887c5 100644 --- a/libgo/go/net/interface_linux.go +++ b/libgo/go/net/interface_linux.go @@ -17,21 +17,16 @@ import ( // network interfaces. Otheriwse it returns a mapping of a specific // interface. func interfaceTable(ifindex int) ([]Interface, error) { - var ( - ift []Interface - tab []byte - msgs []syscall.NetlinkMessage - e error - ) + var ift []Interface - tab, e = syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) - if e != nil { - return nil, os.NewSyscallError("netlink rib", e) + tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) + if err != nil { + return nil, os.NewSyscallError("netlink rib", err) } - msgs, e = syscall.ParseNetlinkMessage(tab) - if e != nil { - return nil, os.NewSyscallError("netlink message", e) + msgs, err := syscall.ParseNetlinkMessage(tab) + if err != nil { + return nil, os.NewSyscallError("netlink message", err) } for _, m := range msgs { @@ -41,11 +36,11 @@ func interfaceTable(ifindex int) ([]Interface, error) { 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 != nil { - return nil, os.NewSyscallError("netlink routeattr", e) + attrs, err := syscall.ParseNetlinkRouteAttr(&m) + if err != nil { + return nil, os.NewSyscallError("netlink routeattr", err) } - ifi := newLink(attrs, ifim) + ifi := newLink(ifim, attrs) ift = append(ift, ifi) } } @@ -55,7 +50,7 @@ done: return ift, nil } -func newLink(attrs []syscall.NetlinkRouteAttr, ifim *syscall.IfInfomsg) Interface { +func newLink(ifim *syscall.IfInfomsg, attrs []syscall.NetlinkRouteAttr) Interface { ifi := Interface{Index: int(ifim.Index), Flags: linkFlags(ifim.Flags)} for _, a := range attrs { switch a.Attr.Type { @@ -102,19 +97,19 @@ func linkFlags(rawFlags uint32) Flags { // for all network interfaces. Otherwise it returns addresses // for a specific interface. func interfaceAddrTable(ifindex int) ([]Addr, error) { - tab, e := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC) - if e != nil { - return nil, os.NewSyscallError("netlink rib", e) + tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC) + if err != nil { + return nil, os.NewSyscallError("netlink rib", err) } - msgs, e := syscall.ParseNetlinkMessage(tab) - if e != nil { - return nil, os.NewSyscallError("netlink message", e) + msgs, err := syscall.ParseNetlinkMessage(tab) + if err != nil { + return nil, os.NewSyscallError("netlink message", err) } - ifat, e := addrTable(msgs, ifindex) - if e != nil { - return nil, e + ifat, err := addrTable(msgs, ifindex) + if err != nil { + return nil, err } return ifat, nil @@ -130,11 +125,11 @@ func addrTable(msgs []syscall.NetlinkMessage, ifindex int) ([]Addr, error) { 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 != nil { - return nil, os.NewSyscallError("netlink routeattr", e) + attrs, err := syscall.ParseNetlinkRouteAttr(&m) + if err != nil { + return nil, os.NewSyscallError("netlink routeattr", err) } - ifat = append(ifat, newAddr(attrs, int(ifam.Family))...) + ifat = append(ifat, newAddr(attrs, int(ifam.Family), int(ifam.Prefixlen))) } } } @@ -143,25 +138,23 @@ done: return ifat, nil } -func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr { - var ifat []Addr - +func newAddr(attrs []syscall.NetlinkRouteAttr, family, pfxlen int) Addr { + ifa := &IPNet{} 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()) + ifa.IP = IPv4(a.Value[0], a.Value[1], a.Value[2], a.Value[3]) + ifa.Mask = CIDRMask(pfxlen, 8*IPv4len) case syscall.AF_INET6: - ifa := &IPAddr{IP: make(IP, IPv6len)} + ifa.IP = make(IP, IPv6len) copy(ifa.IP, a.Value[:]) - ifat = append(ifat, ifa.toAddr()) + ifa.Mask = CIDRMask(pfxlen, 8*IPv6len) } } } - - return ifat + return ifa } // If the ifindex is zero, interfaceMulticastAddrTable returns @@ -169,8 +162,8 @@ func newAddr(attrs []syscall.NetlinkRouteAttr, family int) []Addr { // addresses for a specific interface. func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) { var ( - ifi *Interface err error + ifi *Interface ) if ifindex > 0 { diff --git a/libgo/go/net/interface_netbsd.go b/libgo/go/net/interface_netbsd.go new file mode 100644 index 0000000..4150e9a --- /dev/null +++ b/libgo/go/net/interface_netbsd.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. + +// Network interface identification for NetBSD + +package net + +// 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, error) { + return nil, nil +} diff --git a/libgo/go/net/interface_test.go b/libgo/go/net/interface_test.go index cc61491..4ce01dc 100644 --- a/libgo/go/net/interface_test.go +++ b/libgo/go/net/interface_test.go @@ -24,7 +24,7 @@ func sameInterface(i, j *Interface) bool { func TestInterfaces(t *testing.T) { ift, err := Interfaces() if err != nil { - t.Fatalf("Interfaces() failed: %v", err) + t.Fatalf("Interfaces failed: %v", err) } t.Logf("table: len/cap = %v/%v\n", len(ift), cap(ift)) @@ -43,34 +43,57 @@ func TestInterfaces(t *testing.T) { 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()) + testInterfaceAddrs(t, &ifi) + testInterfaceMulticastAddrs(t, &ifi) } } func TestInterfaceAddrs(t *testing.T) { ifat, err := InterfaceAddrs() if err != nil { - t.Fatalf("InterfaceAddrs() failed: %v", err) + t.Fatalf("InterfaceAddrs failed: %v", err) } t.Logf("table: len/cap = %v/%v\n", len(ifat), cap(ifat)) + testAddrs(t, ifat) +} + +func testInterfaceAddrs(t *testing.T, ifi *Interface) { + ifat, err := ifi.Addrs() + if err != nil { + t.Fatalf("Interface.Addrs failed: %v", err) + } + testAddrs(t, ifat) +} + +func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) { + ifmat, err := ifi.MulticastAddrs() + if err != nil { + t.Fatalf("Interface.MulticastAddrs failed: %v", err) + } + testMulticastAddrs(t, ifmat) +} +func testAddrs(t *testing.T, ifat []Addr) { for _, ifa := range ifat { - t.Logf("interface address %q\n", ifa.String()) + switch ifa.(type) { + case *IPAddr, *IPNet: + t.Logf("\tinterface address %q\n", ifa.String()) + default: + t.Errorf("\tunexpected type: %T", ifa) + } + } +} + +func testMulticastAddrs(t *testing.T, ifmat []Addr) { + for _, ifma := range ifmat { + switch ifma.(type) { + case *IPAddr: + t.Logf("\tjoined group address %q\n", ifma.String()) + default: + t.Errorf("\tunexpected type: %T", ifma) + } } } diff --git a/libgo/go/net/ip.go b/libgo/go/net/ip.go index 4a38882..979d7ac 100644 --- a/libgo/go/net/ip.go +++ b/libgo/go/net/ip.go @@ -450,6 +450,9 @@ func (n *IPNet) String() string { return nn.String() + "/" + itod(uint(l)) } +// Network returns the address's network name, "ip+net". +func (n *IPNet) Network() string { return "ip+net" } + // Parse IPv4 address (d.d.d.d). func parseIPv4(s string) IP { var p [IPv4len]byte diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go index 60c405a..67a4049 100644 --- a/libgo/go/net/ipraw_test.go +++ b/libgo/go/net/ipraw_test.go @@ -59,6 +59,7 @@ func parsePingReply(p []byte) (id, seq int) { } var srchost = flag.String("srchost", "", "Source of the ICMP ECHO request") + // 127.0.0.1 because this is an IPv4-specific test. var dsthost = flag.String("dsthost", "127.0.0.1", "Destination for the ICMP ECHO request") diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go index d3cb38a..7bb4c7d 100644 --- a/libgo/go/net/iprawsock_posix.go +++ b/libgo/go/net/iprawsock_posix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd windows +// +build darwin freebsd linux netbsd openbsd windows // (Raw) IP sockets diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go index f0ca7da..d141c05 100644 --- a/libgo/go/net/ipsock_posix.go +++ b/libgo/go/net/ipsock_posix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd windows +// +build darwin freebsd linux netbsd openbsd windows package net diff --git a/libgo/go/net/lookup_unix.go b/libgo/go/net/lookup_unix.go index aae6d6c..5c47547 100644 --- a/libgo/go/net/lookup_unix.go +++ b/libgo/go/net/lookup_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd +// +build darwin freebsd linux netbsd openbsd package net diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go index 48f0ae7..b236dfd 100644 --- a/libgo/go/net/net.go +++ b/libgo/go/net/net.go @@ -157,6 +157,14 @@ func (e *OpError) Timeout() bool { return ok && t.Timeout() } +type timeoutError struct{} + +func (e *timeoutError) Error() string { return "i/o timeout" } +func (e *timeoutError) Timeout() bool { return true } +func (e *timeoutError) Temporary() bool { return true } + +var errTimeout error = &timeoutError{} + type AddrError struct { Err string Addr string diff --git a/libgo/go/net/newpollserver.go b/libgo/go/net/newpollserver.go index 035df4a..a410bb6 100644 --- a/libgo/go/net/newpollserver.go +++ b/libgo/go/net/newpollserver.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd +// +build darwin freebsd linux netbsd openbsd package net diff --git a/libgo/go/net/port.go b/libgo/go/net/port.go index 80597f7..16780da 100644 --- a/libgo/go/net/port.go +++ b/libgo/go/net/port.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd +// +build darwin freebsd linux netbsd openbsd // Read system port mappings from /etc/services diff --git a/libgo/go/net/rpc/server_test.go b/libgo/go/net/rpc/server_test.go index a52a86e..c1845fa 100644 --- a/libgo/go/net/rpc/server_test.go +++ b/libgo/go/net/rpc/server_test.go @@ -516,12 +516,10 @@ func benchmarkEndToEnd(dial func() (*Client, error), b *testing.B) { for atomic.AddInt32(&N, -1) >= 0 { err = client.Call("Arith.Add", args, reply) if err != nil { - fmt.Printf("Add: expected no error but got string %q", err.Error()) - panic("rpc error") + b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error()) } if reply.C != args.A+args.B { - fmt.Printf("Add: expected %d got %d", reply.C, args.A+args.B) - panic("rpc error") + b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B) } } wg.Done() @@ -536,8 +534,7 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) { once.Do(startServer) client, err := dial() if err != nil { - fmt.Println("error dialing", err) - return + b.Fatalf("error dialing:", err) } // Asynchronous calls @@ -561,12 +558,11 @@ func benchmarkEndToEndAsync(dial func() (*Client, error), b *testing.B) { }() go func() { for call := range res { - a := call.Args.(*Args).A - b := call.Args.(*Args).B - c := call.Reply.(*Reply).C - if a+b != c { - fmt.Printf("Add: expected %d got %d", a+b, c) - panic("incorrect reply") + A := call.Args.(*Args).A + B := call.Args.(*Args).B + C := call.Reply.(*Reply).C + if A+B != C { + b.Fatalf("incorrect reply: Add: expected %d got %d", A+B, C) } <-gate if atomic.AddInt32(&recv, -1) == 0 { diff --git a/libgo/go/net/sendfile_stub.go b/libgo/go/net/sendfile_stub.go index b0adea4..ff76ab9 100644 --- a/libgo/go/net/sendfile_stub.go +++ b/libgo/go/net/sendfile_stub.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd openbsd +// +build darwin freebsd netbsd openbsd package net diff --git a/libgo/go/net/sock.go b/libgo/go/net/sock.go index 777f204..dc07392 100644 --- a/libgo/go/net/sock.go +++ b/libgo/go/net/sock.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd windows +// +build darwin freebsd linux netbsd openbsd windows // Sockets diff --git a/libgo/go/net/sock_bsd.go b/libgo/go/net/sock_bsd.go index 7025edf..816e4fc 100644 --- a/libgo/go/net/sock_bsd.go +++ b/libgo/go/net/sock_bsd.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd openbsd +// +build darwin freebsd netbsd openbsd // Sockets for BSD variants diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go index 44890ba..a7c09c7 100644 --- a/libgo/go/net/tcpsock_posix.go +++ b/libgo/go/net/tcpsock_posix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd windows +// +build darwin freebsd linux netbsd openbsd windows // TCP sockets diff --git a/libgo/go/net/textproto/reader_test.go b/libgo/go/net/textproto/reader_test.go index 5aefe39..0460c1c 100644 --- a/libgo/go/net/textproto/reader_test.go +++ b/libgo/go/net/textproto/reader_test.go @@ -203,7 +203,7 @@ func TestRFC959Lines(t *testing.T) { t.Errorf("#%d: code=%d, want %d", i, code, tt.wantCode) } if msg != tt.wantMsg { - t.Errorf("%#d: msg=%q, want %q", i, msg, tt.wantMsg) + t.Errorf("#%d: msg=%q, want %q", i, msg, tt.wantMsg) } } } diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go index c25ec9c..6bb1571 100644 --- a/libgo/go/net/udpsock_posix.go +++ b/libgo/go/net/udpsock_posix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd windows +// +build darwin freebsd linux netbsd openbsd windows // UDP sockets diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go index 929f640..10632c1 100644 --- a/libgo/go/net/unixsock_posix.go +++ b/libgo/go/net/unixsock_posix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin freebsd linux openbsd windows +// +build darwin freebsd linux netbsd openbsd windows // Unix domain sockets |