summaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
authorJeremy Faller <jeremy@golang.org>2020-09-30 17:57:14 -0400
committerJeremy Faller <jeremy@golang.org>2020-09-30 18:00:58 -0400
commit91e4d2d57bc341dd82c98247117114c851380aef (patch)
tree15a2d023cdc63543cf8a6e99f8a561c0a0459000 /src/net
parentc863e14a6c15e174ac0979ddd7f9530d6a4ec9cc (diff)
parent846dce9d05f19a1f53465e62a304dea21b99f910 (diff)
downloadgo-git-91e4d2d57bc341dd82c98247117114c851380aef.tar.gz
[dev.link] Merge branch 'master' into dev.link
2 conflicts, that make sense. src/cmd/internal/obj/objfile.go src/cmd/link/internal/loader/loader.go Change-Id: Ib224e2d248cb568fa1e888af79dd908b2f5e05ff
Diffstat (limited to 'src/net')
-rw-r--r--src/net/conf.go2
-rw-r--r--src/net/dial_test.go4
-rw-r--r--src/net/http/cgi/child.go36
-rw-r--r--src/net/http/cgi/child_test.go58
-rw-r--r--src/net/http/cgi/host.go2
-rw-r--r--src/net/http/cgi/integration_test.go53
-rw-r--r--src/net/http/fcgi/child.go39
-rw-r--r--src/net/http/fcgi/fcgi_test.go52
-rw-r--r--src/net/http/h2_bundle.go1
-rw-r--r--src/net/interface_solaris.go28
-rw-r--r--src/net/interface_unix_test.go2
-rw-r--r--src/net/lookup_test.go4
-rw-r--r--src/net/main_test.go2
-rw-r--r--src/net/platform_test.go4
-rw-r--r--src/net/sock_bsd.go2
-rw-r--r--src/net/sock_linux.go62
-rw-r--r--src/net/sock_linux_test.go22
-rw-r--r--src/net/tcpsock_test.go2
-rw-r--r--src/net/udpsock_test.go2
-rw-r--r--src/net/writev_test.go2
-rw-r--r--src/net/writev_unix.go2
21 files changed, 317 insertions, 64 deletions
diff --git a/src/net/conf.go b/src/net/conf.go
index 971b1a399a..5340847123 100644
--- a/src/net/conf.go
+++ b/src/net/conf.go
@@ -69,7 +69,7 @@ func initConfVal() {
// Darwin pops up annoying dialog boxes if programs try to do
// their own DNS requests. So always use cgo instead, which
// avoids that.
- if runtime.GOOS == "darwin" {
+ if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
confVal.forceCgoLookupHost = true
return
}
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index 01582489de..2706de4442 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -160,7 +160,7 @@ func dialClosedPort(t *testing.T) (actual, expected time.Duration) {
// but other platforms should be instantaneous.
if runtime.GOOS == "windows" {
expected = 1500 * time.Millisecond
- } else if runtime.GOOS == "darwin" {
+ } else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
expected = 150 * time.Millisecond
} else {
expected = 95 * time.Millisecond
@@ -990,7 +990,7 @@ func TestDialerControl(t *testing.T) {
// except that it won't skip testing on non-mobile builders.
func mustHaveExternalNetwork(t *testing.T) {
t.Helper()
- mobile := runtime.GOOS == "android" || runtime.GOOS == "darwin" && runtime.GOARCH == "arm64"
+ mobile := runtime.GOOS == "android" || (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64"
if testenv.Builder() == "" || mobile {
testenv.MustHaveExternalNetwork(t)
}
diff --git a/src/net/http/cgi/child.go b/src/net/http/cgi/child.go
index d7d813e68a..690986335c 100644
--- a/src/net/http/cgi/child.go
+++ b/src/net/http/cgi/child.go
@@ -166,10 +166,12 @@ func Serve(handler http.Handler) error {
}
type response struct {
- req *http.Request
- header http.Header
- bufw *bufio.Writer
- headerSent bool
+ req *http.Request
+ header http.Header
+ code int
+ wroteHeader bool
+ wroteCGIHeader bool
+ bufw *bufio.Writer
}
func (r *response) Flush() {
@@ -181,26 +183,38 @@ func (r *response) Header() http.Header {
}
func (r *response) Write(p []byte) (n int, err error) {
- if !r.headerSent {
+ if !r.wroteHeader {
r.WriteHeader(http.StatusOK)
}
+ if !r.wroteCGIHeader {
+ r.writeCGIHeader(p)
+ }
return r.bufw.Write(p)
}
func (r *response) WriteHeader(code int) {
- if r.headerSent {
+ if r.wroteHeader {
// Note: explicitly using Stderr, as Stdout is our HTTP output.
fmt.Fprintf(os.Stderr, "CGI attempted to write header twice on request for %s", r.req.URL)
return
}
- r.headerSent = true
- fmt.Fprintf(r.bufw, "Status: %d %s\r\n", code, http.StatusText(code))
+ r.wroteHeader = true
+ r.code = code
+}
- // Set a default Content-Type
+// writeCGIHeader finalizes the header sent to the client and writes it to the output.
+// p is not written by writeHeader, but is the first chunk of the body
+// that will be written. It is sniffed for a Content-Type if none is
+// set explicitly.
+func (r *response) writeCGIHeader(p []byte) {
+ if r.wroteCGIHeader {
+ return
+ }
+ r.wroteCGIHeader = true
+ fmt.Fprintf(r.bufw, "Status: %d %s\r\n", r.code, http.StatusText(r.code))
if _, hasType := r.header["Content-Type"]; !hasType {
- r.header.Add("Content-Type", "text/html; charset=utf-8")
+ r.header.Set("Content-Type", http.DetectContentType(p))
}
-
r.header.Write(r.bufw)
r.bufw.WriteString("\r\n")
r.bufw.Flush()
diff --git a/src/net/http/cgi/child_test.go b/src/net/http/cgi/child_test.go
index 14e0af475f..18cf789bd5 100644
--- a/src/net/http/cgi/child_test.go
+++ b/src/net/http/cgi/child_test.go
@@ -7,6 +7,11 @@
package cgi
import (
+ "bufio"
+ "bytes"
+ "net/http"
+ "net/http/httptest"
+ "strings"
"testing"
)
@@ -148,3 +153,56 @@ func TestRequestWithoutRemotePort(t *testing.T) {
t.Errorf("RemoteAddr: got %q; want %q", g, e)
}
}
+
+func TestResponse(t *testing.T) {
+ var tests = []struct {
+ name string
+ body string
+ wantCT string
+ }{
+ {
+ name: "no body",
+ wantCT: "text/plain; charset=utf-8",
+ },
+ {
+ name: "html",
+ body: "<html><head><title>test page</title></head><body>This is a body</body></html>",
+ wantCT: "text/html; charset=utf-8",
+ },
+ {
+ name: "text",
+ body: strings.Repeat("gopher", 86),
+ wantCT: "text/plain; charset=utf-8",
+ },
+ {
+ name: "jpg",
+ body: "\xFF\xD8\xFF" + strings.Repeat("B", 1024),
+ wantCT: "image/jpeg",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ var buf bytes.Buffer
+ resp := response{
+ req: httptest.NewRequest("GET", "/", nil),
+ header: http.Header{},
+ bufw: bufio.NewWriter(&buf),
+ }
+ n, err := resp.Write([]byte(tt.body))
+ if err != nil {
+ t.Errorf("Write: unexpected %v", err)
+ }
+ if want := len(tt.body); n != want {
+ t.Errorf("reported short Write: got %v want %v", n, want)
+ }
+ resp.writeCGIHeader(nil)
+ resp.Flush()
+ if got := resp.Header().Get("Content-Type"); got != tt.wantCT {
+ t.Errorf("wrong content-type: got %q, want %q", got, tt.wantCT)
+ }
+ if !bytes.HasSuffix(buf.Bytes(), []byte(tt.body)) {
+ t.Errorf("body was not correctly written")
+ }
+ })
+ }
+}
diff --git a/src/net/http/cgi/host.go b/src/net/http/cgi/host.go
index 863f40638a..624044aa09 100644
--- a/src/net/http/cgi/host.go
+++ b/src/net/http/cgi/host.go
@@ -37,7 +37,7 @@ var trailingPort = regexp.MustCompile(`:([0-9]+)$`)
var osDefaultInheritEnv = func() []string {
switch runtime.GOOS {
- case "darwin":
+ case "darwin", "ios":
return []string{"DYLD_LIBRARY_PATH"}
case "linux", "freebsd", "openbsd":
return []string{"LD_LIBRARY_PATH"}
diff --git a/src/net/http/cgi/integration_test.go b/src/net/http/cgi/integration_test.go
index eaa090f6fe..76cbca8e60 100644
--- a/src/net/http/cgi/integration_test.go
+++ b/src/net/http/cgi/integration_test.go
@@ -16,7 +16,9 @@ import (
"io"
"net/http"
"net/http/httptest"
+ "net/url"
"os"
+ "strings"
"testing"
"time"
)
@@ -52,7 +54,7 @@ func TestHostingOurselves(t *testing.T) {
}
replay := runCgiTest(t, h, "GET /test.go?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n", expectedMap)
- if expected, got := "text/html; charset=utf-8", replay.Header().Get("Content-Type"); got != expected {
+ if expected, got := "text/plain; charset=utf-8", replay.Header().Get("Content-Type"); got != expected {
t.Errorf("got a Content-Type of %q; expected %q", got, expected)
}
if expected, got := "X-Test-Value", replay.Header().Get("X-Test-Header"); got != expected {
@@ -169,6 +171,51 @@ func TestNilRequestBody(t *testing.T) {
_ = runCgiTest(t, h, "POST /test.go?nil-request-body=1 HTTP/1.0\nHost: example.com\nContent-Length: 0\n\n", expectedMap)
}
+func TestChildContentType(t *testing.T) {
+ testenv.MustHaveExec(t)
+
+ h := &Handler{
+ Path: os.Args[0],
+ Root: "/test.go",
+ Args: []string{"-test.run=TestBeChildCGIProcess"},
+ }
+ var tests = []struct {
+ name string
+ body string
+ wantCT string
+ }{
+ {
+ name: "no body",
+ wantCT: "text/plain; charset=utf-8",
+ },
+ {
+ name: "html",
+ body: "<html><head><title>test page</title></head><body>This is a body</body></html>",
+ wantCT: "text/html; charset=utf-8",
+ },
+ {
+ name: "text",
+ body: strings.Repeat("gopher", 86),
+ wantCT: "text/plain; charset=utf-8",
+ },
+ {
+ name: "jpg",
+ body: "\xFF\xD8\xFF" + strings.Repeat("B", 1024),
+ wantCT: "image/jpeg",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ expectedMap := map[string]string{"_body": tt.body}
+ req := fmt.Sprintf("GET /test.go?exact-body=%s HTTP/1.0\nHost: example.com\n\n", url.QueryEscape(tt.body))
+ replay := runCgiTest(t, h, req, expectedMap)
+ if got := replay.Header().Get("Content-Type"); got != tt.wantCT {
+ t.Errorf("got a Content-Type of %q; expected it to start with %q", got, tt.wantCT)
+ }
+ })
+ }
+}
+
// golang.org/issue/7198
func Test500WithNoHeaders(t *testing.T) { want500Test(t, "/immediate-disconnect") }
func Test500WithNoContentType(t *testing.T) { want500Test(t, "/no-content-type") }
@@ -224,6 +271,10 @@ func TestBeChildCGIProcess(t *testing.T) {
if req.FormValue("no-body") == "1" {
return
}
+ if eb, ok := req.Form["exact-body"]; ok {
+ io.WriteString(rw, eb[0])
+ return
+ }
if req.FormValue("write-forever") == "1" {
io.Copy(rw, neverEnding('a'))
for {
diff --git a/src/net/http/fcgi/child.go b/src/net/http/fcgi/child.go
index 0e91042543..34761f32ee 100644
--- a/src/net/http/fcgi/child.go
+++ b/src/net/http/fcgi/child.go
@@ -74,10 +74,12 @@ func (r *request) parseParams() {
// response implements http.ResponseWriter.
type response struct {
- req *request
- header http.Header
- w *bufWriter
- wroteHeader bool
+ req *request
+ header http.Header
+ code int
+ wroteHeader bool
+ wroteCGIHeader bool
+ w *bufWriter
}
func newResponse(c *child, req *request) *response {
@@ -92,11 +94,14 @@ func (r *response) Header() http.Header {
return r.header
}
-func (r *response) Write(data []byte) (int, error) {
+func (r *response) Write(p []byte) (n int, err error) {
if !r.wroteHeader {
r.WriteHeader(http.StatusOK)
}
- return r.w.Write(data)
+ if !r.wroteCGIHeader {
+ r.writeCGIHeader(p)
+ }
+ return r.w.Write(p)
}
func (r *response) WriteHeader(code int) {
@@ -104,22 +109,34 @@ func (r *response) WriteHeader(code int) {
return
}
r.wroteHeader = true
+ r.code = code
if code == http.StatusNotModified {
// Must not have body.
r.header.Del("Content-Type")
r.header.Del("Content-Length")
r.header.Del("Transfer-Encoding")
- } else if r.header.Get("Content-Type") == "" {
- r.header.Set("Content-Type", "text/html; charset=utf-8")
}
-
if r.header.Get("Date") == "" {
r.header.Set("Date", time.Now().UTC().Format(http.TimeFormat))
}
+}
- fmt.Fprintf(r.w, "Status: %d %s\r\n", code, http.StatusText(code))
+// writeCGIHeader finalizes the header sent to the client and writes it to the output.
+// p is not written by writeHeader, but is the first chunk of the body
+// that will be written. It is sniffed for a Content-Type if none is
+// set explicitly.
+func (r *response) writeCGIHeader(p []byte) {
+ if r.wroteCGIHeader {
+ return
+ }
+ r.wroteCGIHeader = true
+ fmt.Fprintf(r.w, "Status: %d %s\r\n", r.code, http.StatusText(r.code))
+ if _, hasType := r.header["Content-Type"]; r.code != http.StatusNotModified && !hasType {
+ r.header.Set("Content-Type", http.DetectContentType(p))
+ }
r.header.Write(r.w)
r.w.WriteString("\r\n")
+ r.w.Flush()
}
func (r *response) Flush() {
@@ -293,6 +310,8 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
httpReq = httpReq.WithContext(envVarCtx)
c.handler.ServeHTTP(r, httpReq)
}
+ // Make sure we serve something even if nothing was written to r
+ r.Write(nil)
r.Close()
c.mu.Lock()
delete(c.requests, req.reqId)
diff --git a/src/net/http/fcgi/fcgi_test.go b/src/net/http/fcgi/fcgi_test.go
index e9d2b34023..4a27a12c35 100644
--- a/src/net/http/fcgi/fcgi_test.go
+++ b/src/net/http/fcgi/fcgi_test.go
@@ -10,6 +10,7 @@ import (
"io"
"io/ioutil"
"net/http"
+ "strings"
"testing"
)
@@ -344,3 +345,54 @@ func TestChildServeReadsEnvVars(t *testing.T) {
<-done
}
}
+
+func TestResponseWriterSniffsContentType(t *testing.T) {
+ var tests = []struct {
+ name string
+ body string
+ wantCT string
+ }{
+ {
+ name: "no body",
+ wantCT: "text/plain; charset=utf-8",
+ },
+ {
+ name: "html",
+ body: "<html><head><title>test page</title></head><body>This is a body</body></html>",
+ wantCT: "text/html; charset=utf-8",
+ },
+ {
+ name: "text",
+ body: strings.Repeat("gopher", 86),
+ wantCT: "text/plain; charset=utf-8",
+ },
+ {
+ name: "jpg",
+ body: "\xFF\xD8\xFF" + strings.Repeat("B", 1024),
+ wantCT: "image/jpeg",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ input := make([]byte, len(streamFullRequestStdin))
+ copy(input, streamFullRequestStdin)
+ rc := nopWriteCloser{bytes.NewBuffer(input)}
+ done := make(chan bool)
+ var resp *response
+ c := newChild(rc, http.HandlerFunc(func(
+ w http.ResponseWriter,
+ r *http.Request,
+ ) {
+ io.WriteString(w, tt.body)
+ resp = w.(*response)
+ done <- true
+ }))
+ defer c.cleanUp()
+ go c.serve()
+ <-done
+ if got := resp.Header().Get("Content-Type"); got != tt.wantCT {
+ t.Errorf("got a Content-Type of %q; expected it to start with %q", got, tt.wantCT)
+ }
+ })
+ }
+}
diff --git a/src/net/http/h2_bundle.go b/src/net/http/h2_bundle.go
index 458e0b7646..5b92eb234b 100644
--- a/src/net/http/h2_bundle.go
+++ b/src/net/http/h2_bundle.go
@@ -5265,6 +5265,7 @@ func (sc *http2serverConn) processData(f *http2DataFrame) error {
if len(data) > 0 {
wrote, err := st.body.Write(data)
if err != nil {
+ sc.sendWindowUpdate(nil, int(f.Length)-wrote)
return http2streamError(id, http2ErrCodeStreamClosed)
}
if wrote != len(data) {
diff --git a/src/net/interface_solaris.go b/src/net/interface_solaris.go
index 5f9367f996..f8d1571b90 100644
--- a/src/net/interface_solaris.go
+++ b/src/net/interface_solaris.go
@@ -32,39 +32,21 @@ func interfaceTable(ifindex int) ([]Interface, error) {
return ift, nil
}
-const (
- sysIFF_UP = 0x1
- sysIFF_BROADCAST = 0x2
- sysIFF_DEBUG = 0x4
- sysIFF_LOOPBACK = 0x8
- sysIFF_POINTOPOINT = 0x10
- sysIFF_NOTRAILERS = 0x20
- sysIFF_RUNNING = 0x40
- sysIFF_NOARP = 0x80
- sysIFF_PROMISC = 0x100
- sysIFF_ALLMULTI = 0x200
- sysIFF_INTELLIGENT = 0x400
- sysIFF_MULTICAST = 0x800
- sysIFF_MULTI_BCAST = 0x1000
- sysIFF_UNNUMBERED = 0x2000
- sysIFF_PRIVATE = 0x8000
-)
-
func linkFlags(rawFlags int) Flags {
var f Flags
- if rawFlags&sysIFF_UP != 0 {
+ if rawFlags&syscall.IFF_UP != 0 {
f |= FlagUp
}
- if rawFlags&sysIFF_BROADCAST != 0 {
+ if rawFlags&syscall.IFF_BROADCAST != 0 {
f |= FlagBroadcast
}
- if rawFlags&sysIFF_LOOPBACK != 0 {
+ if rawFlags&syscall.IFF_LOOPBACK != 0 {
f |= FlagLoopback
}
- if rawFlags&sysIFF_POINTOPOINT != 0 {
+ if rawFlags&syscall.IFF_POINTOPOINT != 0 {
f |= FlagPointToPoint
}
- if rawFlags&sysIFF_MULTICAST != 0 {
+ if rawFlags&syscall.IFF_MULTICAST != 0 {
f |= FlagMulticast
}
return f
diff --git a/src/net/interface_unix_test.go b/src/net/interface_unix_test.go
index 6a2b7f1a88..bf41a0fb82 100644
--- a/src/net/interface_unix_test.go
+++ b/src/net/interface_unix_test.go
@@ -46,7 +46,7 @@ func TestPointToPointInterface(t *testing.T) {
if testing.Short() {
t.Skip("avoid external network")
}
- if runtime.GOOS == "darwin" {
+ if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
t.Skipf("not supported on %s", runtime.GOOS)
}
if os.Getuid() != 0 {
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index 68bffcab8f..32a0d377da 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -511,7 +511,7 @@ func TestDNSFlood(t *testing.T) {
defer dnsWaitGroup.Wait()
var N = 5000
- if runtime.GOOS == "darwin" {
+ if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
// On Darwin this test consumes kernel threads much
// than other platforms for some reason.
// When we monitor the number of allocated Ms by
@@ -628,7 +628,7 @@ func TestLookupDotsWithLocalSource(t *testing.T) {
}
func TestLookupDotsWithRemoteSource(t *testing.T) {
- if runtime.GOOS == "darwin" {
+ if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
testenv.SkipFlaky(t, 27992)
}
mustHaveExternalNetwork(t)
diff --git a/src/net/main_test.go b/src/net/main_test.go
index 85a269d0f4..2d5be2ee5f 100644
--- a/src/net/main_test.go
+++ b/src/net/main_test.go
@@ -133,7 +133,7 @@ func setupTestData() {
{"udp6", "[" + addr + "%" + ifi.Name + "]:0", false},
}...)
switch runtime.GOOS {
- case "darwin", "dragonfly", "freebsd", "openbsd", "netbsd":
+ case "darwin", "ios", "dragonfly", "freebsd", "openbsd", "netbsd":
ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
{"tcp", "[localhost%" + ifi.Name + "]:0", true},
{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
diff --git a/src/net/platform_test.go b/src/net/platform_test.go
index d3bb918edb..4b92bb6df0 100644
--- a/src/net/platform_test.go
+++ b/src/net/platform_test.go
@@ -59,7 +59,7 @@ func testableNetwork(network string) bool {
}
case "unixpacket":
switch runtime.GOOS {
- case "aix", "android", "darwin", "plan9", "windows":
+ case "aix", "android", "darwin", "ios", "plan9", "windows":
return false
case "netbsd":
// It passes on amd64 at least. 386 fails (Issue 22927). arm is unknown.
@@ -82,7 +82,7 @@ func testableNetwork(network string) bool {
}
func iOS() bool {
- return runtime.GOOS == "darwin" && runtime.GOARCH == "arm64"
+ return (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64"
}
// testableAddress reports whether address of network is testable on
diff --git a/src/net/sock_bsd.go b/src/net/sock_bsd.go
index 516e557cfd..73fb6be814 100644
--- a/src/net/sock_bsd.go
+++ b/src/net/sock_bsd.go
@@ -17,7 +17,7 @@ func maxListenerBacklog() int {
err error
)
switch runtime.GOOS {
- case "darwin":
+ case "darwin", "ios":
n, err = syscall.SysctlUint32("kern.ipc.somaxconn")
case "freebsd":
n, err = syscall.SysctlUint32("kern.ipc.soacceptqueue")
diff --git a/src/net/sock_linux.go b/src/net/sock_linux.go
index 7bca37605e..4d91001937 100644
--- a/src/net/sock_linux.go
+++ b/src/net/sock_linux.go
@@ -6,6 +6,62 @@ package net
import "syscall"
+func kernelVersion() (major int, minor int) {
+ var uname syscall.Utsname
+ if err := syscall.Uname(&uname); err != nil {
+ return
+ }
+
+ rl := uname.Release
+ var values [2]int
+ vi := 0
+ value := 0
+ for _, c := range rl {
+ if c >= '0' && c <= '9' {
+ value = (value * 10) + int(c-'0')
+ } else {
+ // Note that we're assuming N.N.N here. If we see anything else we are likely to
+ // mis-parse it.
+ values[vi] = value
+ vi++
+ if vi >= len(values) {
+ break
+ }
+ }
+ }
+ switch vi {
+ case 0:
+ return 0, 0
+ case 1:
+ return values[0], 0
+ case 2:
+ return values[0], values[1]
+ }
+ return
+}
+
+// Linux stores the backlog as:
+//
+// - uint16 in kernel version < 4.1,
+// - uint32 in kernel version >= 4.1
+//
+// Truncate number to avoid wrapping.
+//
+// See issue 5030 and 41470.
+func maxAckBacklog(n int) int {
+ major, minor := kernelVersion()
+ size := 16
+ if major > 4 || (major == 4 && minor >= 1) {
+ size = 32
+ }
+
+ var max uint = 1<<size - 1
+ if uint(n) > max {
+ n = int(max)
+ }
+ return n
+}
+
func maxListenerBacklog() int {
fd, err := open("/proc/sys/net/core/somaxconn")
if err != nil {
@@ -21,11 +77,9 @@ func maxListenerBacklog() int {
if n == 0 || !ok {
return syscall.SOMAXCONN
}
- // Linux stores the backlog in a uint16.
- // Truncate number to avoid wrapping.
- // See issue 5030.
+
if n > 1<<16-1 {
- n = 1<<16 - 1
+ return maxAckBacklog(n)
}
return n
}
diff --git a/src/net/sock_linux_test.go b/src/net/sock_linux_test.go
new file mode 100644
index 0000000000..5df02935c3
--- /dev/null
+++ b/src/net/sock_linux_test.go
@@ -0,0 +1,22 @@
+// Copyright 2020 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 (
+ "testing"
+)
+
+func TestMaxAckBacklog(t *testing.T) {
+ n := 196602
+ major, minor := kernelVersion()
+ backlog := maxAckBacklog(n)
+ expected := 1<<16 - 1
+ if major > 4 || (major == 4 && minor >= 1) {
+ expected = n
+ }
+ if backlog != expected {
+ t.Fatalf(`Kernel version: "%d.%d", sk_max_ack_backlog mismatch, got %d, want %d`, major, minor, backlog, expected)
+ }
+}
diff --git a/src/net/tcpsock_test.go b/src/net/tcpsock_test.go
index 8a70496693..6e905aa091 100644
--- a/src/net/tcpsock_test.go
+++ b/src/net/tcpsock_test.go
@@ -647,7 +647,7 @@ func TestTCPSelfConnect(t *testing.T) {
n = 1000
}
switch runtime.GOOS {
- case "darwin", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "illumos", "solaris", "windows":
+ case "darwin", "ios", "dragonfly", "freebsd", "netbsd", "openbsd", "plan9", "illumos", "solaris", "windows":
// Non-Linux systems take a long time to figure
// out that there is nothing listening on localhost.
n = 100
diff --git a/src/net/udpsock_test.go b/src/net/udpsock_test.go
index 947381a57b..327eba6541 100644
--- a/src/net/udpsock_test.go
+++ b/src/net/udpsock_test.go
@@ -327,7 +327,7 @@ func TestUDPZeroBytePayload(t *testing.T) {
switch runtime.GOOS {
case "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
- case "darwin":
+ case "darwin", "ios":
testenv.SkipFlaky(t, 29225)
}
diff --git a/src/net/writev_test.go b/src/net/writev_test.go
index c43be84418..a6b3285e57 100644
--- a/src/net/writev_test.go
+++ b/src/net/writev_test.go
@@ -154,7 +154,7 @@ func testBuffer_writeTo(t *testing.T, chunks int, useCopy bool) {
var wantSum int
switch runtime.GOOS {
- case "android", "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd":
+ case "android", "darwin", "ios", "dragonfly", "freebsd", "illumos", "linux", "netbsd", "openbsd":
var wantMinCalls int
wantSum = want.Len()
v := chunks
diff --git a/src/net/writev_unix.go b/src/net/writev_unix.go
index bf0fbf8a13..8b20f42b34 100644
--- a/src/net/writev_unix.go
+++ b/src/net/writev_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 dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd illumos linux netbsd openbsd
package net