listen_test.go 3.1 KB

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