diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-06 17:57:23 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2012-03-06 17:57:23 +0000 |
commit | 593f74bbab63d34c7060918088bcbad686c31c66 (patch) | |
tree | 4ce83ca433796a728e9fdd00af105bce158532b5 /libgo/go/net | |
parent | 46402cbe0ba3ea92be9642cf18eedaefe57a414c (diff) | |
download | gcc-593f74bbab63d34c7060918088bcbad686c31c66.zip gcc-593f74bbab63d34c7060918088bcbad686c31c66.tar.gz gcc-593f74bbab63d34c7060918088bcbad686c31c66.tar.bz2 |
libgo: Update to weekly.2012-03-04 release.
From-SVN: r185010
Diffstat (limited to 'libgo/go/net')
30 files changed, 471 insertions, 290 deletions
diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go index 61b8911..10ca5fa 100644 --- a/libgo/go/net/dial.go +++ b/libgo/go/net/dial.go @@ -69,7 +69,7 @@ func resolveNetAddr(op, net, addr string) (afnet string, a Addr, err error) { // // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), // "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4" -// (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and "unixpacket". +// (IPv4-only), "ip6" (IPv6-only), "unix" and "unixpacket". // // For TCP and UDP networks, addresses have the form host:port. // If host is a literal IPv6 address, it must be enclosed diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go index e5a797e..5f5aea1 100644 --- a/libgo/go/net/dial_test.go +++ b/libgo/go/net/dial_test.go @@ -5,6 +5,8 @@ package net import ( + "flag" + "regexp" "runtime" "testing" "time" @@ -128,3 +130,82 @@ func TestSelfConnect(t *testing.T) { } } } + +var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors") + +type DialErrorTest struct { + Net string + Raddr string + Pattern string +} + +var dialErrorTests = []DialErrorTest{ + { + "datakit", "mh/astro/r70", + "dial datakit mh/astro/r70: unknown network datakit", + }, + { + "tcp", "127.0.0.1:☺", + "dial tcp 127.0.0.1:☺: unknown port tcp/☺", + }, + { + "tcp", "no-such-name.google.com.:80", + "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)", + }, + { + "tcp", "no-such-name.no-such-top-level-domain.:80", + "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)", + }, + { + "tcp", "no-such-name:80", + `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`, + }, + { + "tcp", "mh/astro/r70:http", + "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name", + }, + { + "unix", "/etc/file-not-found", + "dial unix /etc/file-not-found: no such file or directory", + }, + { + "unix", "/etc/", + "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)", + }, + { + "unixpacket", "/etc/file-not-found", + "dial unixpacket /etc/file-not-found: no such file or directory", + }, + { + "unixpacket", "/etc/", + "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)", + }, +} + +var duplicateErrorPattern = `dial (.*) dial (.*)` + +func TestDialError(t *testing.T) { + if !*runErrorTest { + t.Logf("test disabled; use -run_error_test to enable") + return + } + for i, tt := range dialErrorTests { + c, err := Dial(tt.Net, tt.Raddr) + if c != nil { + c.Close() + } + if err == nil { + t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern) + continue + } + s := err.Error() + match, _ := regexp.MatchString(tt.Pattern, s) + if !match { + t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern) + } + match, _ = regexp.MatchString(duplicateErrorPattern, s) + if match { + t.Errorf("#%d: %q, duplicate error return from Dial", i, s) + } + } +} diff --git a/libgo/go/net/dialgoogle_test.go b/libgo/go/net/dialgoogle_test.go index 14356da..03c4499 100644 --- a/libgo/go/net/dialgoogle_test.go +++ b/libgo/go/net/dialgoogle_test.go @@ -42,9 +42,8 @@ func doDial(t *testing.T, network, addr string) { } func TestLookupCNAME(t *testing.T) { - if testing.Short() { - // Don't use external network. - t.Logf("skipping external network test during -short") + if testing.Short() || !*testExternal { + t.Logf("skipping test to avoid external network") return } cname, err := LookupCNAME("www.google.com") @@ -67,9 +66,8 @@ var googleaddrsipv4 = []string{ } func TestDialGoogleIPv4(t *testing.T) { - if testing.Short() { - // Don't use external network. - t.Logf("skipping external network test during -short") + if testing.Short() || !*testExternal { + t.Logf("skipping test to avoid external network") return } @@ -124,9 +122,8 @@ var googleaddrsipv6 = []string{ } func TestDialGoogleIPv6(t *testing.T) { - if testing.Short() { - // Don't use external network. - t.Logf("skipping external network test during -short") + if testing.Short() || !*testExternal { + t.Logf("skipping test to avoid external network") return } // Only run tcp6 if the kernel will take it. diff --git a/libgo/go/net/http/cgi/child.go b/libgo/go/net/http/cgi/child.go index e6c3ef9..1ba7bec 100644 --- a/libgo/go/net/http/cgi/child.go +++ b/libgo/go/net/http/cgi/child.go @@ -144,6 +144,7 @@ func Serve(handler http.Handler) error { bufw: bufio.NewWriter(os.Stdout), } handler.ServeHTTP(rw, req) + rw.Write(nil) // make sure a response is sent if err = rw.bufw.Flush(); err != nil { return err } diff --git a/libgo/go/net/http/cgi/host_test.go b/libgo/go/net/http/cgi/host_test.go index fec35b7..859911f 100644 --- a/libgo/go/net/http/cgi/host_test.go +++ b/libgo/go/net/http/cgi/host_test.go @@ -41,6 +41,7 @@ func runCgiTest(t *testing.T, h *Handler, httpreq string, expectedMap map[string // Make a map to hold the test map that the CGI returns. m := make(map[string]string) + m["_body"] = rw.Body.String() linesRead := 0 readlines: for { diff --git a/libgo/go/net/http/cgi/matryoshka_test.go b/libgo/go/net/http/cgi/matryoshka_test.go index 1a44df2..e1a78c8 100644 --- a/libgo/go/net/http/cgi/matryoshka_test.go +++ b/libgo/go/net/http/cgi/matryoshka_test.go @@ -51,6 +51,22 @@ func TestHostingOurselves(t *testing.T) { } } +// Test that a child handler only writing headers works. +func TestChildOnlyHeaders(t *testing.T) { + h := &Handler{ + Path: os.Args[0], + Root: "/test.go", + Args: []string{"-test.run=TestBeChildCGIProcess"}, + } + expectedMap := map[string]string{ + "_body": "", + } + replay := runCgiTest(t, h, "GET /test.go?no-body=1 HTTP/1.0\nHost: example.com\n\n", expectedMap) + if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected { + t.Errorf("got a X-Test-Header of %q; expected %q", got, expected) + } +} + // Note: not actually a test. func TestBeChildCGIProcess(t *testing.T) { if os.Getenv("REQUEST_METHOD") == "" { @@ -59,8 +75,11 @@ func TestBeChildCGIProcess(t *testing.T) { } Serve(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { rw.Header().Set("X-Test-Header", "X-Test-Value") - fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n") req.ParseForm() + if req.FormValue("no-body") == "1" { + return + } + fmt.Fprintf(rw, "test=Hello CGI-in-CGI\n") for k, vv := range req.Form { for _, v := range vv { fmt.Fprintf(rw, "param-%s=%s\n", k, v) diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go index 0409008..5aa93ce 100644 --- a/libgo/go/net/http/fs_test.go +++ b/libgo/go/net/http/fs_test.go @@ -152,12 +152,19 @@ func TestFileServerCleans(t *testing.T) { } } +func mustRemoveAll(dir string) { + err := os.RemoveAll(dir) + if err != nil { + panic(err) + } +} + func TestFileServerImplicitLeadingSlash(t *testing.T) { tempDir, err := ioutil.TempDir("", "") if err != nil { t.Fatalf("TempDir: %v", err) } - defer os.RemoveAll(tempDir) + defer mustRemoveAll(tempDir) if err := ioutil.WriteFile(filepath.Join(tempDir, "foo.txt"), []byte("Hello world"), 0644); err != nil { t.Fatalf("WriteFile: %v", err) } @@ -172,6 +179,7 @@ func TestFileServerImplicitLeadingSlash(t *testing.T) { if err != nil { t.Fatalf("ReadAll %s: %v", suffix, err) } + res.Body.Close() return string(b) } if s := get("/bar/"); !strings.Contains(s, ">foo.txt<") { diff --git a/libgo/go/net/http/httptest/server.go b/libgo/go/net/http/httptest/server.go index 8d911f7..57cf0c9 100644 --- a/libgo/go/net/http/httptest/server.go +++ b/libgo/go/net/http/httptest/server.go @@ -13,6 +13,7 @@ import ( "net" "net/http" "os" + "sync" ) // A Server is an HTTP server listening on a system-chosen port on the @@ -25,6 +26,10 @@ type Server struct { // Config may be changed after calling NewUnstartedServer and // before Start or StartTLS. Config *http.Server + + // wg counts the number of outstanding HTTP requests on this server. + // Close blocks until all requests are finished. + wg sync.WaitGroup } // historyListener keeps track of all connections that it's ever @@ -93,6 +98,7 @@ func (s *Server) Start() { } s.Listener = &historyListener{s.Listener, make([]net.Conn, 0)} s.URL = "http://" + s.Listener.Addr().String() + s.wrapHandler() go s.Config.Serve(s.Listener) if *serve != "" { fmt.Fprintln(os.Stderr, "httptest: serving on", s.URL) @@ -118,9 +124,21 @@ func (s *Server) StartTLS() { s.Listener = &historyListener{tlsListener, make([]net.Conn, 0)} s.URL = "https://" + s.Listener.Addr().String() + s.wrapHandler() go s.Config.Serve(s.Listener) } +func (s *Server) wrapHandler() { + h := s.Config.Handler + if h == nil { + h = http.DefaultServeMux + } + s.Config.Handler = &waitGroupHandler{ + s: s, + h: h, + } +} + // NewTLSServer starts and returns a new Server using TLS. // The caller should call Close when finished, to shut it down. func NewTLSServer(handler http.Handler) *Server { @@ -129,9 +147,11 @@ func NewTLSServer(handler http.Handler) *Server { return ts } -// Close shuts down the server. +// Close shuts down the server and blocks until all outstanding +// requests on this server have completed. func (s *Server) Close() { s.Listener.Close() + s.wg.Wait() } // CloseClientConnections closes any currently open HTTP connections @@ -146,6 +166,20 @@ func (s *Server) CloseClientConnections() { } } +// waitGroupHandler wraps a handler, incrementing and decrementing a +// sync.WaitGroup on each request, to enable Server.Close to block +// until outstanding requests are finished. +type waitGroupHandler struct { + s *Server + h http.Handler // non-nil +} + +func (h *waitGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + h.s.wg.Add(1) + defer h.s.wg.Done() // a defer, in case ServeHTTP below panics + h.h.ServeHTTP(w, r) +} + // localhostCert is a PEM-encoded TLS cert with SAN DNS names // "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end // of ASN.1 time). diff --git a/libgo/go/net/http/httputil/dump.go b/libgo/go/net/http/httputil/dump.go index c853066..892ef4e 100644 --- a/libgo/go/net/http/httputil/dump.go +++ b/libgo/go/net/http/httputil/dump.go @@ -12,6 +12,7 @@ import ( "io/ioutil" "net" "net/http" + "net/url" "strings" "time" ) @@ -59,6 +60,19 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) { } } + // Since we're using the actual Transport code to write the request, + // switch to http so the Transport doesn't try to do an SSL + // negotiation with our dumpConn and its bytes.Buffer & pipe. + // The wire format for https and http are the same, anyway. + reqSend := req + if req.URL.Scheme == "https" { + reqSend = new(http.Request) + *reqSend = *req + reqSend.URL = new(url.URL) + *reqSend.URL = *req.URL + reqSend.URL.Scheme = "http" + } + // Use the actual Transport code to record what we would send // on the wire, but not using TCP. Use a Transport with a // customer dialer that returns a fake net.Conn that waits @@ -79,7 +93,7 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) { }, } - _, err := t.RoundTrip(req) + _, err := t.RoundTrip(reqSend) req.Body = save if err != nil { diff --git a/libgo/go/net/http/httputil/dump_test.go b/libgo/go/net/http/httputil/dump_test.go index 819efb5..5afe9ba 100644 --- a/libgo/go/net/http/httputil/dump_test.go +++ b/libgo/go/net/http/httputil/dump_test.go @@ -71,6 +71,18 @@ var dumpTests = []dumpTest{ "User-Agent: Go http package\r\n" + "Accept-Encoding: gzip\r\n\r\n", }, + + // Test that an https URL doesn't try to do an SSL negotiation + // with a bytes.Buffer and hang with all goroutines not + // runnable. + { + Req: *mustNewRequest("GET", "https://example.com/foo", nil), + + WantDumpOut: "GET /foo HTTP/1.1\r\n" + + "Host: example.com\r\n" + + "User-Agent: Go http package\r\n" + + "Accept-Encoding: gzip\r\n\r\n", + }, } func TestDumpRequest(t *testing.T) { diff --git a/libgo/go/net/http/httputil/persist.go b/libgo/go/net/http/httputil/persist.go index 32f4662..507938a 100644 --- a/libgo/go/net/http/httputil/persist.go +++ b/libgo/go/net/http/httputil/persist.go @@ -383,7 +383,7 @@ func (cc *ClientConn) Read(req *http.Request) (resp *http.Response, err error) { // Make sure body is fully consumed, even if user does not call body.Close if lastbody != nil { // body.Close is assumed to be idempotent and multiple calls to - // it should return the error that its first invokation + // it should return the error that its first invocation // returned. err = lastbody.Close() if err != nil { diff --git a/libgo/go/net/http/lex.go b/libgo/go/net/http/lex.go index 93b67e7..ffb393c 100644 --- a/libgo/go/net/http/lex.go +++ b/libgo/go/net/http/lex.go @@ -14,14 +14,6 @@ func isSeparator(c byte) bool { return false } -func isSpace(c byte) bool { - switch c { - case ' ', '\t', '\r', '\n': - return true - } - return false -} - func isCtl(c byte) bool { return (0 <= c && c <= 31) || c == 127 } func isChar(c byte) bool { return 0 <= c && c <= 127 } diff --git a/libgo/go/net/http/sniff_test.go b/libgo/go/net/http/sniff_test.go index 6efa8ce..8ab72ac 100644 --- a/libgo/go/net/http/sniff_test.go +++ b/libgo/go/net/http/sniff_test.go @@ -129,9 +129,10 @@ func TestSniffWriteSize(t *testing.T) { })) defer ts.Close() for _, size := range []int{0, 1, 200, 600, 999, 1000, 1023, 1024, 512 << 10, 1 << 20} { - _, err := Get(fmt.Sprintf("%s/?size=%d", ts.URL, size)) + res, err := Get(fmt.Sprintf("%s/?size=%d", ts.URL, size)) if err != nil { t.Fatalf("size %d: %v", size, err) } + res.Body.Close() } } diff --git a/libgo/go/net/http/status.go b/libgo/go/net/http/status.go index b6e2d65..5af0b77 100644 --- a/libgo/go/net/http/status.go +++ b/libgo/go/net/http/status.go @@ -43,6 +43,7 @@ const ( StatusUnsupportedMediaType = 415 StatusRequestedRangeNotSatisfiable = 416 StatusExpectationFailed = 417 + StatusTeapot = 418 StatusInternalServerError = 500 StatusNotImplemented = 501 @@ -90,6 +91,7 @@ var statusText = map[int]string{ StatusUnsupportedMediaType: "Unsupported Media Type", StatusRequestedRangeNotSatisfiable: "Requested Range Not Satisfiable", StatusExpectationFailed: "Expectation Failed", + StatusTeapot: "I'm a teapot", StatusInternalServerError: "Internal Server Error", StatusNotImplemented: "Not Implemented", diff --git a/libgo/go/net/http/transfer.go b/libgo/go/net/http/transfer.go index ef9564a..3c8fe7f 100644 --- a/libgo/go/net/http/transfer.go +++ b/libgo/go/net/http/transfer.go @@ -383,7 +383,7 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, error) // chunked encoding must always come first. for _, encoding := range encodings { encoding = strings.ToLower(strings.TrimSpace(encoding)) - // "identity" encoding is not recored + // "identity" encoding is not recorded if encoding == "identity" { break } diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go index 3e48aba..09579f8 100644 --- a/libgo/go/net/http/transport.go +++ b/libgo/go/net/http/transport.go @@ -76,7 +76,9 @@ type Transport struct { // ProxyFromEnvironment returns the URL of the proxy to use for a // given request, as indicated by the environment variables // $HTTP_PROXY and $NO_PROXY (or $http_proxy and $no_proxy). -// Either URL or an error is returned. +// An error is returned if the proxy environment is invalid. +// A nil URL and nil error are returned if no proxy is defined in the +// environment, or a proxy should not be used for the given request. func ProxyFromEnvironment(req *Request) (*url.URL, error) { proxy := getenvEitherCase("HTTP_PROXY") if proxy == "" { @@ -86,7 +88,7 @@ func ProxyFromEnvironment(req *Request) (*url.URL, error) { return nil, nil } proxyURL, err := url.Parse(proxy) - if err != nil { + if err != nil || proxyURL.Scheme == "" { if u, err := url.Parse("http://" + proxy); err == nil { proxyURL = u err = nil diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go index 1a629c1..cbb3884 100644 --- a/libgo/go/net/http/transport_test.go +++ b/libgo/go/net/http/transport_test.go @@ -16,6 +16,7 @@ import ( . "net/http" "net/http/httptest" "net/url" + "os" "runtime" "strconv" "strings" @@ -727,6 +728,36 @@ func TestTransportAltProto(t *testing.T) { } } +var proxyFromEnvTests = []struct { + env string + wanturl string + wanterr error +}{ + {"127.0.0.1:8080", "http://127.0.0.1:8080", nil}, + {"http://127.0.0.1:8080", "http://127.0.0.1:8080", nil}, + {"https://127.0.0.1:8080", "https://127.0.0.1:8080", nil}, + {"", "<nil>", nil}, +} + +func TestProxyFromEnvironment(t *testing.T) { + os.Setenv("HTTP_PROXY", "") + os.Setenv("http_proxy", "") + os.Setenv("NO_PROXY", "") + os.Setenv("no_proxy", "") + for i, tt := range proxyFromEnvTests { + os.Setenv("HTTP_PROXY", tt.env) + req, _ := NewRequest("GET", "http://example.com", nil) + url, err := ProxyFromEnvironment(req) + if g, e := fmt.Sprintf("%v", err), fmt.Sprintf("%v", tt.wanterr); g != e { + t.Errorf("%d. got error = %q, want %q", i, g, e) + continue + } + if got := fmt.Sprintf("%s", url); got != tt.wanturl { + t.Errorf("%d. got URL = %q, want %q", i, url, tt.wanturl) + } + } +} + // rgz is a gzip quine that uncompresses to itself. var rgz = []byte{ 0x1f, 0x8b, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, diff --git a/libgo/go/net/http/triv.go b/libgo/go/net/http/triv.go index c88a0fb..269af0c 100644 --- a/libgo/go/net/http/triv.go +++ b/libgo/go/net/http/triv.go @@ -108,7 +108,6 @@ func DateServer(rw http.ResponseWriter, req *http.Request) { fmt.Fprintf(rw, "fork/exec: %s\n", err) return } - defer p.Release() io.Copy(rw, r) wait, err := p.Wait(0) if err != nil { diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go index 5e7b352..f25d046 100644 --- a/libgo/go/net/interface.go +++ b/libgo/go/net/interface.go @@ -6,11 +6,7 @@ package net -import ( - "bytes" - "errors" - "fmt" -) +import "errors" var ( errInvalidInterface = errors.New("net: invalid interface") @@ -20,77 +16,6 @@ var ( errNoSuchMulticastInterface = errors.New("net: no such multicast interface") ) -// 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() -} - -// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, or EUI-64 using one of the -// following formats: -// 01:23:45:67:89:ab -// 01:23:45:67:89:ab:cd:ef -// 01-23-45-67-89-ab -// 01-23-45-67-89-ab-cd-ef -// 0123.4567.89ab -// 0123.4567.89ab.cdef -func ParseMAC(s string) (hw HardwareAddr, err error) { - if len(s) < 14 { - goto error - } - - if s[2] == ':' || s[2] == '-' { - if (len(s)+1)%3 != 0 { - goto error - } - n := (len(s) + 1) / 3 - if n != 6 && n != 8 { - goto error - } - hw = make(HardwareAddr, n) - for x, i := 0, 0; i < n; i++ { - var ok bool - if hw[i], ok = xtoi2(s[x:], s[2]); !ok { - goto error - } - x += 3 - } - } else if s[4] == '.' { - if (len(s)+1)%5 != 0 { - goto error - } - n := 2 * (len(s) + 1) / 5 - if n != 6 && n != 8 { - goto error - } - hw = make(HardwareAddr, n) - for x, i := 0, 0; i < n; i += 2 { - var ok bool - if hw[i], ok = xtoi2(s[x:x+2], 0); !ok { - goto error - } - if hw[i+1], ok = xtoi2(s[x+2:], s[4]); !ok { - goto error - } - x += 5 - } - } else { - goto error - } - return hw, nil - -error: - return nil, errors.New("invalid MAC address: " + s) -} - // Interface represents a mapping between network interface name // and index. It also represents network interface facility // information. diff --git a/libgo/go/net/interface_test.go b/libgo/go/net/interface_test.go index 769414e..0a33bfd 100644 --- a/libgo/go/net/interface_test.go +++ b/libgo/go/net/interface_test.go @@ -6,8 +6,6 @@ package net import ( "bytes" - "reflect" - "strings" "testing" ) @@ -96,46 +94,3 @@ func testMulticastAddrs(t *testing.T, ifmat []Addr) { } } } - -var mactests = []struct { - in string - out HardwareAddr - err string -}{ - {"01:23:45:67:89:AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""}, - {"01-23-45-67-89-AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""}, - {"0123.4567.89AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""}, - {"ab:cd:ef:AB:CD:EF", HardwareAddr{0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef}, ""}, - {"01.02.03.04.05.06", nil, "invalid MAC address"}, - {"01:02:03:04:05:06:", nil, "invalid MAC address"}, - {"x1:02:03:04:05:06", nil, "invalid MAC address"}, - {"01002:03:04:05:06", nil, "invalid MAC address"}, - {"01:02003:04:05:06", nil, "invalid MAC address"}, - {"01:02:03004:05:06", nil, "invalid MAC address"}, - {"01:02:03:04005:06", nil, "invalid MAC address"}, - {"01:02:03:04:05006", nil, "invalid MAC address"}, - {"01-02:03:04:05:06", nil, "invalid MAC address"}, - {"01:02-03-04-05-06", nil, "invalid MAC address"}, - {"0123:4567:89AF", nil, "invalid MAC address"}, - {"0123-4567-89AF", nil, "invalid MAC address"}, - {"01:23:45:67:89:AB:CD:EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""}, - {"01-23-45-67-89-AB-CD-EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""}, - {"0123.4567.89AB.CDEF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""}, -} - -func match(err error, s string) bool { - if s == "" { - return err == nil - } - return err != nil && strings.Contains(err.Error(), s) -} - -func TestParseMAC(t *testing.T) { - for _, tt := range mactests { - out, err := ParseMAC(tt.in) - if !reflect.DeepEqual(out, tt.out) || !match(err, tt.err) { - t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out, - tt.err) - } - } -} diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go index b08a9fb..2c69830 100644 --- a/libgo/go/net/lookup_plan9.go +++ b/libgo/go/net/lookup_plan9.go @@ -76,7 +76,7 @@ func lookupProtocol(name string) (proto int, err error) { } func lookupHost(host string) (addrs []string, err error) { - // Use /net/cs insead of /net/dns because cs knows about + // Use /net/cs instead 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 { diff --git a/libgo/go/net/lookup_test.go b/libgo/go/net/lookup_test.go index 7b9ea84..3a61dfb 100644 --- a/libgo/go/net/lookup_test.go +++ b/libgo/go/net/lookup_test.go @@ -12,7 +12,7 @@ import ( "testing" ) -var testExternal = flag.Bool("external", false, "allow use of external networks during test") +var testExternal = flag.Bool("external", true, "allow use of external networks during long test") func TestGoogleSRV(t *testing.T) { if testing.Short() || !*testExternal { @@ -78,3 +78,40 @@ func TestGoogleDNSAddr(t *testing.T) { t.Errorf("no results") } } + +var revAddrTests = []struct { + Addr string + Reverse string + ErrPrefix string +}{ + {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""}, + {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""}, + {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""}, + {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""}, + {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""}, + {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, + {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, + {"1.2.3", "", "unrecognized address"}, + {"1.2.3.4.5", "", "unrecognized address"}, + {"1234:567:bcbca::89a:bcde", "", "unrecognized address"}, + {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"}, +} + +func TestReverseAddress(t *testing.T) { + for i, tt := range revAddrTests { + a, err := reverseaddr(tt.Addr) + if len(tt.ErrPrefix) > 0 && err == nil { + t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix) + continue + } + if len(tt.ErrPrefix) == 0 && err != nil { + t.Errorf("#%d: expected <nil>, got %q (error)", i, err) + } + if err != nil && err.(*DNSError).Err != tt.ErrPrefix { + t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err) + } + if a != tt.Reverse { + t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a) + } + } +} diff --git a/libgo/go/net/mac.go b/libgo/go/net/mac.go new file mode 100644 index 0000000..e0637d0 --- /dev/null +++ b/libgo/go/net/mac.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. + +// MAC address manipulations + +package net + +import ( + "bytes" + "errors" + "fmt" +) + +// 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() +} + +// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, or EUI-64 using one of the +// following formats: +// 01:23:45:67:89:ab +// 01:23:45:67:89:ab:cd:ef +// 01-23-45-67-89-ab +// 01-23-45-67-89-ab-cd-ef +// 0123.4567.89ab +// 0123.4567.89ab.cdef +func ParseMAC(s string) (hw HardwareAddr, err error) { + if len(s) < 14 { + goto error + } + + if s[2] == ':' || s[2] == '-' { + if (len(s)+1)%3 != 0 { + goto error + } + n := (len(s) + 1) / 3 + if n != 6 && n != 8 { + goto error + } + hw = make(HardwareAddr, n) + for x, i := 0, 0; i < n; i++ { + var ok bool + if hw[i], ok = xtoi2(s[x:], s[2]); !ok { + goto error + } + x += 3 + } + } else if s[4] == '.' { + if (len(s)+1)%5 != 0 { + goto error + } + n := 2 * (len(s) + 1) / 5 + if n != 6 && n != 8 { + goto error + } + hw = make(HardwareAddr, n) + for x, i := 0, 0; i < n; i += 2 { + var ok bool + if hw[i], ok = xtoi2(s[x:x+2], 0); !ok { + goto error + } + if hw[i+1], ok = xtoi2(s[x+2:], s[4]); !ok { + goto error + } + x += 5 + } + } else { + goto error + } + return hw, nil + +error: + return nil, errors.New("invalid MAC address: " + s) +} diff --git a/libgo/go/net/mac_test.go b/libgo/go/net/mac_test.go new file mode 100644 index 0000000..3837e740 --- /dev/null +++ b/libgo/go/net/mac_test.go @@ -0,0 +1,54 @@ +// 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 ( + "reflect" + "strings" + "testing" +) + +var mactests = []struct { + in string + out HardwareAddr + err string +}{ + {"01:23:45:67:89:AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""}, + {"01-23-45-67-89-AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""}, + {"0123.4567.89AB", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab}, ""}, + {"ab:cd:ef:AB:CD:EF", HardwareAddr{0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef}, ""}, + {"01.02.03.04.05.06", nil, "invalid MAC address"}, + {"01:02:03:04:05:06:", nil, "invalid MAC address"}, + {"x1:02:03:04:05:06", nil, "invalid MAC address"}, + {"01002:03:04:05:06", nil, "invalid MAC address"}, + {"01:02003:04:05:06", nil, "invalid MAC address"}, + {"01:02:03004:05:06", nil, "invalid MAC address"}, + {"01:02:03:04005:06", nil, "invalid MAC address"}, + {"01:02:03:04:05006", nil, "invalid MAC address"}, + {"01-02:03:04:05:06", nil, "invalid MAC address"}, + {"01:02-03-04-05-06", nil, "invalid MAC address"}, + {"0123:4567:89AF", nil, "invalid MAC address"}, + {"0123-4567-89AF", nil, "invalid MAC address"}, + {"01:23:45:67:89:AB:CD:EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""}, + {"01-23-45-67-89-AB-CD-EF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""}, + {"0123.4567.89AB.CDEF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""}, +} + +func match(err error, s string) bool { + if s == "" { + return err == nil + } + return err != nil && strings.Contains(err.Error(), s) +} + +func TestParseMAC(t *testing.T) { + for _, tt := range mactests { + out, err := ParseMAC(tt.in) + if !reflect.DeepEqual(out, tt.out) || !match(err, tt.err) { + t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out, + tt.err) + } + } +} diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go index 69d7ac8..c1a90de 100644 --- a/libgo/go/net/net_test.go +++ b/libgo/go/net/net_test.go @@ -5,130 +5,12 @@ package net import ( - "flag" "io" - "regexp" "runtime" "testing" "time" ) -var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors") - -type DialErrorTest struct { - Net string - Raddr string - Pattern string -} - -var dialErrorTests = []DialErrorTest{ - { - "datakit", "mh/astro/r70", - "dial datakit mh/astro/r70: unknown network datakit", - }, - { - "tcp", "127.0.0.1:☺", - "dial tcp 127.0.0.1:☺: unknown port tcp/☺", - }, - { - "tcp", "no-such-name.google.com.:80", - "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)", - }, - { - "tcp", "no-such-name.no-such-top-level-domain.:80", - "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)", - }, - { - "tcp", "no-such-name:80", - `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`, - }, - { - "tcp", "mh/astro/r70:http", - "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name", - }, - { - "unix", "/etc/file-not-found", - "dial unix /etc/file-not-found: [nN]o such file or directory", - }, - { - "unix", "/etc/", - "dial unix /etc/: ([pP]ermission denied|socket operation on non-socket|connection refused)", - }, - { - "unixpacket", "/etc/file-not-found", - "dial unixpacket /etc/file-not-found: no such file or directory", - }, - { - "unixpacket", "/etc/", - "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)", - }, -} - -var duplicateErrorPattern = `dial (.*) dial (.*)` - -func TestDialError(t *testing.T) { - if !*runErrorTest { - t.Logf("test disabled; use --run_error_test to enable") - return - } - for i, tt := range dialErrorTests { - c, err := Dial(tt.Net, tt.Raddr) - if c != nil { - c.Close() - } - if err == nil { - t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern) - continue - } - s := err.Error() - match, _ := regexp.MatchString(tt.Pattern, s) - if !match { - t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern) - } - match, _ = regexp.MatchString(duplicateErrorPattern, s) - if match { - t.Errorf("#%d: %q, duplicate error return from Dial", i, s) - } - } -} - -var revAddrTests = []struct { - Addr string - Reverse string - ErrPrefix string -}{ - {"1.2.3.4", "4.3.2.1.in-addr.arpa.", ""}, - {"245.110.36.114", "114.36.110.245.in-addr.arpa.", ""}, - {"::ffff:12.34.56.78", "78.56.34.12.in-addr.arpa.", ""}, - {"::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", ""}, - {"1::", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.ip6.arpa.", ""}, - {"1234:567::89a:bcde", "e.d.c.b.a.9.8.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, - {"1234:567:fefe:bcbc:adad:9e4a:89a:bcde", "e.d.c.b.a.9.8.0.a.4.e.9.d.a.d.a.c.b.c.b.e.f.e.f.7.6.5.0.4.3.2.1.ip6.arpa.", ""}, - {"1.2.3", "", "unrecognized address"}, - {"1.2.3.4.5", "", "unrecognized address"}, - {"1234:567:bcbca::89a:bcde", "", "unrecognized address"}, - {"1234:567::bcbc:adad::89a:bcde", "", "unrecognized address"}, -} - -func TestReverseAddress(t *testing.T) { - for i, tt := range revAddrTests { - a, err := reverseaddr(tt.Addr) - if len(tt.ErrPrefix) > 0 && err == nil { - t.Errorf("#%d: expected %q, got <nil> (error)", i, tt.ErrPrefix) - continue - } - if len(tt.ErrPrefix) == 0 && err != nil { - t.Errorf("#%d: expected <nil>, got %q (error)", i, err) - } - if err != nil && err.(*DNSError).Err != tt.ErrPrefix { - t.Errorf("#%d: expected %q, got %q (mismatched error)", i, tt.ErrPrefix, err.(*DNSError).Err) - } - if a != tt.Reverse { - t.Errorf("#%d: expected %q, got %q (reverse address)", i, tt.Reverse, a) - } - } -} - func TestShutdown(t *testing.T) { if runtime.GOOS == "plan9" { return diff --git a/libgo/go/net/rpc/client.go b/libgo/go/net/rpc/client.go index 34f9ae3..f7abf21 100644 --- a/libgo/go/net/rpc/client.go +++ b/libgo/go/net/rpc/client.go @@ -140,7 +140,7 @@ func (client *Client) input() { } client.mutex.Unlock() client.sending.Unlock() - if err != io.EOF || !closing { + if err != io.EOF && !closing { log.Println("rpc: client protocol error:", err) } } diff --git a/libgo/go/net/rpc/server.go b/libgo/go/net/rpc/server.go index 920ae91..1680e2f 100644 --- a/libgo/go/net/rpc/server.go +++ b/libgo/go/net/rpc/server.go @@ -13,13 +13,19 @@ Only methods that satisfy these criteria will be made available for remote access; other methods will be ignored: - - the method name is exported, that is, begins with an upper case letter. - - the method receiver is exported or local (defined in the package - registering the service). - - the method has two arguments, both exported or local types. + - the method is exported. + - the method has two arguments, both exported (or builtin) types. - the method's second argument is a pointer. - the method has return type error. + In effect, the method must look schematically like + + func (t *T) MethodName(argType T1, replyType *T2) error + + where T, T1 and T2 can be marshaled by encoding/gob. + These requirements apply even if a different codec is used. + (In future, these requirements may soften for custom codecs.) + The method's first argument represents the arguments provided by the caller; the second argument represents the result parameters to be returned to the caller. The method's return value, if non-nil, is passed back as a string that the client @@ -36,10 +42,12 @@ call, a pointer containing the arguments, and a pointer to receive the result parameters. - Call waits for the remote call to complete; Go launches the call asynchronously - and returns a channel that will signal completion. + The Call method waits for the remote call to complete while the Go method + launches the call asynchronously and signals completion using the Call + structure's Done channel. - Package "gob" is used to transport the data. + Unless an explicit codec is set up, package encoding/gob is used to + transport the data. Here is a simple example. A server wishes to export an object of type Arith: @@ -256,6 +264,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro method := s.typ.Method(m) mtype := method.Type mname := method.Name + // Method must be exported. if method.PkgPath != "" { continue } @@ -267,7 +276,7 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro // First arg need not be a pointer. argType := mtype.In(1) if !isExportedOrBuiltinType(argType) { - log.Println(mname, "argument type not exported or local:", argType) + log.Println(mname, "argument type not exported:", argType) continue } // Second arg must be a pointer. @@ -276,15 +285,17 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro log.Println("method", mname, "reply type not a pointer:", replyType) continue } + // Reply type must be exported. if !isExportedOrBuiltinType(replyType) { - log.Println("method", mname, "reply type not exported or local:", replyType) + log.Println("method", mname, "reply type not exported:", replyType) continue } - // Method needs one out: error. + // Method needs one out. if mtype.NumOut() != 1 { log.Println("method", mname, "has wrong number of outs:", mtype.NumOut()) continue } + // The return type of the method must be error. if returnType := mtype.Out(0); returnType != typeOfError { log.Println("method", mname, "returns", returnType.String(), "not error") continue @@ -301,10 +312,10 @@ func (server *Server) register(rcvr interface{}, name string, useName bool) erro return nil } -// A value sent as a placeholder for the response when the server receives an invalid request. -type InvalidRequest struct{} - -var invalidRequest = InvalidRequest{} +// A value sent as a placeholder for the server's response value when the server +// receives an invalid request. It is never decoded by the client since the Response +// contains an error when it is used. +var invalidRequest = struct{}{} func (server *Server) sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec ServerCodec, errmsg string) { resp := server.getResponse() diff --git a/libgo/go/net/sockoptip_netbsd.go b/libgo/go/net/sockoptip_netbsd.go new file mode 100644 index 0000000..446d92a --- /dev/null +++ b/libgo/go/net/sockoptip_netbsd.go @@ -0,0 +1,39 @@ +// Copyright 2012 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-level socket options for NetBSD + +package net + +import "syscall" + +func ipv4MulticastInterface(fd *netFD) (*Interface, error) { + // TODO: Implement this + return nil, syscall.EAFNOSUPPORT +} + +func setIPv4MulticastInterface(fd *netFD, ifi *Interface) error { + // TODO: Implement this + return syscall.EAFNOSUPPORT +} + +func ipv4MulticastLoopback(fd *netFD) (bool, error) { + // TODO: Implement this + return false, syscall.EAFNOSUPPORT +} + +func setIPv4MulticastLoopback(fd *netFD, v bool) error { + // TODO: Implement this + return syscall.EAFNOSUPPORT +} + +func ipv4ReceiveInterface(fd *netFD) (bool, error) { + // TODO: Implement this + return false, syscall.EAFNOSUPPORT +} + +func setIPv4ReceiveInterface(fd *netFD, v bool) error { + // TODO: Implement this + return syscall.EAFNOSUPPORT +} diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go index bae37c8..ef350f0 100644 --- a/libgo/go/net/timeout_test.go +++ b/libgo/go/net/timeout_test.go @@ -40,7 +40,7 @@ func testTimeout(t *testing.T, network, addr string, readFrom bool) { errc <- fmt.Errorf("fd.%s on %s %s did not return 0, timeout: %v, %v", what, network, addr, n, err1) return } - if dt := t1.Sub(t0); dt < 50*time.Millisecond || dt > 250*time.Millisecond { + if dt := t1.Sub(t0); dt < 50*time.Millisecond || !testing.Short() && dt > 250*time.Millisecond { errc <- fmt.Errorf("fd.%s on %s %s took %s, expected 0.1s", what, network, addr, dt) return } diff --git a/libgo/go/net/udp_test.go b/libgo/go/net/udp_test.go index 6ba762b..ea5fad4 100644 --- a/libgo/go/net/udp_test.go +++ b/libgo/go/net/udp_test.go @@ -38,18 +38,18 @@ func testWriteToConn(t *testing.T, raddr string) { _, err = c.(*UDPConn).WriteToUDP([]byte("Connection-oriented mode socket"), ra) if err == nil { - t.Fatal("WriteToUDP should be failed") + t.Fatal("WriteToUDP should fail") } if err != nil && err.(*OpError).Err != ErrWriteToConnected { - t.Fatalf("WriteToUDP should be failed as ErrWriteToConnected: %v", err) + t.Fatalf("WriteToUDP should fail as ErrWriteToConnected: %v", err) } _, err = c.(*UDPConn).WriteTo([]byte("Connection-oriented mode socket"), ra) if err == nil { - t.Fatal("WriteTo should be failed") + t.Fatal("WriteTo should fail") } if err != nil && err.(*OpError).Err != ErrWriteToConnected { - t.Fatalf("WriteTo should be failed as ErrWriteToConnected: %v", err) + t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err) } _, err = c.Write([]byte("Connection-oriented mode socket")) @@ -82,6 +82,6 @@ func testWriteToPacketConn(t *testing.T, raddr string) { _, err = c.(*UDPConn).Write([]byte("Connection-less mode socket")) if err == nil { - t.Fatal("Write should be failed") + t.Fatal("Write should fail") } } |