You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

148 lines
2.9 KiB

  1. // Copyright 2013 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package netutil
  5. import (
  6. "errors"
  7. "fmt"
  8. "io"
  9. "io/ioutil"
  10. "net"
  11. "net/http"
  12. "sync"
  13. "sync/atomic"
  14. "testing"
  15. "time"
  16. "golang.org/x/net/internal/nettest"
  17. )
  18. func TestLimitListener(t *testing.T) {
  19. const max = 5
  20. attempts := (nettest.MaxOpenFiles() - max) / 2
  21. if attempts > 256 { // maximum length of accept queue is 128 by default
  22. attempts = 256
  23. }
  24. l, err := net.Listen("tcp", "127.0.0.1:0")
  25. if err != nil {
  26. t.Fatal(err)
  27. }
  28. defer l.Close()
  29. l = LimitListener(l, max)
  30. var open int32
  31. go http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  32. if n := atomic.AddInt32(&open, 1); n > max {
  33. t.Errorf("%d open connections, want <= %d", n, max)
  34. }
  35. defer atomic.AddInt32(&open, -1)
  36. time.Sleep(10 * time.Millisecond)
  37. fmt.Fprint(w, "some body")
  38. }))
  39. var wg sync.WaitGroup
  40. var failed int32
  41. for i := 0; i < attempts; i++ {
  42. wg.Add(1)
  43. go func() {
  44. defer wg.Done()
  45. c := http.Client{Timeout: 3 * time.Second}
  46. r, err := c.Get("http://" + l.Addr().String())
  47. if err != nil {
  48. t.Log(err)
  49. atomic.AddInt32(&failed, 1)
  50. return
  51. }
  52. defer r.Body.Close()
  53. io.Copy(ioutil.Discard, r.Body)
  54. }()
  55. }
  56. wg.Wait()
  57. // We expect some Gets to fail as the kernel's accept queue is filled,
  58. // but most should succeed.
  59. if int(failed) >= attempts/2 {
  60. t.Errorf("%d requests failed within %d attempts", failed, attempts)
  61. }
  62. }
  63. type errorListener struct {
  64. net.Listener
  65. }
  66. func (errorListener) Accept() (net.Conn, error) {
  67. return nil, errFake
  68. }
  69. var errFake = errors.New("fake error from errorListener")
  70. // This used to hang.
  71. func TestLimitListenerError(t *testing.T) {
  72. donec := make(chan bool, 1)
  73. go func() {
  74. const n = 2
  75. ll := LimitListener(errorListener{}, n)
  76. for i := 0; i < n+1; i++ {
  77. _, err := ll.Accept()
  78. if err != errFake {
  79. t.Fatalf("Accept error = %v; want errFake", err)
  80. }
  81. }
  82. donec <- true
  83. }()
  84. select {
  85. case <-donec:
  86. case <-time.After(5 * time.Second):
  87. t.Fatal("timeout. deadlock?")
  88. }
  89. }
  90. func TestLimitListenerClose(t *testing.T) {
  91. ln, err := net.Listen("tcp", "127.0.0.1:0")
  92. if err != nil {
  93. t.Fatal(err)
  94. }
  95. defer ln.Close()
  96. ln = LimitListener(ln, 1)
  97. doneCh := make(chan struct{})
  98. defer close(doneCh)
  99. go func() {
  100. c, err := net.Dial("tcp", ln.Addr().String())
  101. if err != nil {
  102. t.Fatal(err)
  103. }
  104. defer c.Close()
  105. <-doneCh
  106. }()
  107. c, err := ln.Accept()
  108. if err != nil {
  109. t.Fatal(err)
  110. }
  111. defer c.Close()
  112. acceptDone := make(chan struct{})
  113. go func() {
  114. c, err := ln.Accept()
  115. if err == nil {
  116. c.Close()
  117. t.Errorf("Unexpected successful Accept()")
  118. }
  119. close(acceptDone)
  120. }()
  121. // Wait a tiny bit to ensure the Accept() is blocking.
  122. time.Sleep(10 * time.Millisecond)
  123. ln.Close()
  124. select {
  125. case <-acceptDone:
  126. case <-time.After(5 * time.Second):
  127. t.Fatalf("Accept() still blocking")
  128. }
  129. }