Ian Lance Taylor | 0ef89c4 | 2010-01-29 13:33:36 -0800 | [diff] [blame] | 1 | // Copyright 2009 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 | |
Ian Lance Taylor | 7b25b4d | 2018-08-26 18:14:49 -0700 | [diff] [blame] | 5 | // +build !js |
| 6 | |
Ian Lance Taylor | 0ef89c4 | 2010-01-29 13:33:36 -0800 | [diff] [blame] | 7 | package net |
| 8 | |
| 9 | import ( |
Ian Lance Taylor | 0ba4563 | 2017-01-13 11:17:23 -0800 | [diff] [blame] | 10 | "errors" |
| 11 | "fmt" |
Ian Lance Taylor | 7b25b4d | 2018-08-26 18:14:49 -0700 | [diff] [blame] | 12 | "internal/testenv" |
Ian Lance Taylor | 9d08a45 | 2011-12-02 18:16:25 -0800 | [diff] [blame] | 13 | "io" |
Ian Lance Taylor | b156d71 | 2016-07-22 07:41:34 -0700 | [diff] [blame] | 14 | "net/internal/socktest" |
Ian Lance Taylor | d7936ea | 2012-10-22 17:50:02 -0700 | [diff] [blame] | 15 | "os" |
Ian Lance Taylor | 991a0e1 | 2011-12-02 11:33:22 -0800 | [diff] [blame] | 16 | "runtime" |
Ian Lance Taylor | 0ef89c4 | 2010-01-29 13:33:36 -0800 | [diff] [blame] | 17 | "testing" |
Ian Lance Taylor | 1c3747d | 2016-02-17 21:53:03 -0800 | [diff] [blame] | 18 | "time" |
Ian Lance Taylor | 0ef89c4 | 2010-01-29 13:33:36 -0800 | [diff] [blame] | 19 | ) |
| 20 | |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 21 | func TestCloseRead(t *testing.T) { |
Ian Lance Taylor | d7936ea | 2012-10-22 17:50:02 -0700 | [diff] [blame] | 22 | switch runtime.GOOS { |
Ian Lance Taylor | 0ba4563 | 2017-01-13 11:17:23 -0800 | [diff] [blame] | 23 | case "plan9": |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 24 | t.Skipf("not supported on %s", runtime.GOOS) |
Ian Lance Taylor | d7936ea | 2012-10-22 17:50:02 -0700 | [diff] [blame] | 25 | } |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 26 | t.Parallel() |
Ian Lance Taylor | d7936ea | 2012-10-22 17:50:02 -0700 | [diff] [blame] | 27 | |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 28 | for _, network := range []string{"tcp", "unix", "unixpacket"} { |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 29 | network := network |
| 30 | t.Run(network, func(t *testing.T) { |
| 31 | if !testableNetwork(network) { |
| 32 | t.Skipf("network %s is not testable on the current platform", network) |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 33 | } |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 34 | t.Parallel() |
| 35 | |
| 36 | ln, err := newLocalListener(network) |
| 37 | if err != nil { |
| 38 | t.Fatal(err) |
| 39 | } |
| 40 | switch network { |
| 41 | case "unix", "unixpacket": |
| 42 | defer os.Remove(ln.Addr().String()) |
| 43 | } |
| 44 | defer ln.Close() |
| 45 | |
| 46 | c, err := Dial(ln.Addr().Network(), ln.Addr().String()) |
| 47 | if err != nil { |
| 48 | t.Fatal(err) |
| 49 | } |
| 50 | switch network { |
| 51 | case "unix", "unixpacket": |
| 52 | defer os.Remove(c.LocalAddr().String()) |
| 53 | } |
| 54 | defer c.Close() |
| 55 | |
| 56 | switch c := c.(type) { |
| 57 | case *TCPConn: |
| 58 | err = c.CloseRead() |
| 59 | case *UnixConn: |
| 60 | err = c.CloseRead() |
| 61 | } |
| 62 | if err != nil { |
| 63 | if perr := parseCloseError(err, true); perr != nil { |
| 64 | t.Error(perr) |
| 65 | } |
| 66 | t.Fatal(err) |
| 67 | } |
| 68 | var b [1]byte |
| 69 | n, err := c.Read(b[:]) |
| 70 | if n != 0 || err == nil { |
| 71 | t.Fatalf("got (%d, %v); want (0, error)", n, err) |
| 72 | } |
| 73 | }) |
Ian Lance Taylor | d7936ea | 2012-10-22 17:50:02 -0700 | [diff] [blame] | 74 | } |
| 75 | } |
| 76 | |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 77 | func TestCloseWrite(t *testing.T) { |
| 78 | switch runtime.GOOS { |
Ian Lance Taylor | c2225a7 | 2020-01-02 15:05:27 -0800 | [diff] [blame] | 79 | case "plan9": |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 80 | t.Skipf("not supported on %s", runtime.GOOS) |
Ian Lance Taylor | 9b557c4 | 2012-03-02 08:23:02 -0800 | [diff] [blame] | 81 | } |
| 82 | |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 83 | t.Parallel() |
| 84 | deadline, _ := t.Deadline() |
| 85 | if !deadline.IsZero() { |
| 86 | // Leave 10% headroom on the deadline to report errors and clean up. |
| 87 | deadline = deadline.Add(-time.Until(deadline) / 10) |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 88 | } |
| 89 | |
| 90 | for _, network := range []string{"tcp", "unix", "unixpacket"} { |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 91 | network := network |
| 92 | t.Run(network, func(t *testing.T) { |
| 93 | if !testableNetwork(network) { |
| 94 | t.Skipf("network %s is not testable on the current platform", network) |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 95 | } |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 96 | t.Parallel() |
| 97 | |
| 98 | handler := func(ls *localServer, ln Listener) { |
| 99 | c, err := ln.Accept() |
| 100 | if err != nil { |
| 101 | t.Error(err) |
| 102 | return |
| 103 | } |
| 104 | if !deadline.IsZero() { |
| 105 | c.SetDeadline(deadline) |
| 106 | } |
| 107 | defer c.Close() |
| 108 | |
| 109 | var b [1]byte |
| 110 | n, err := c.Read(b[:]) |
| 111 | if n != 0 || err != io.EOF { |
| 112 | t.Errorf("got (%d, %v); want (0, io.EOF)", n, err) |
| 113 | return |
| 114 | } |
| 115 | switch c := c.(type) { |
| 116 | case *TCPConn: |
| 117 | err = c.CloseWrite() |
| 118 | case *UnixConn: |
| 119 | err = c.CloseWrite() |
| 120 | } |
| 121 | if err != nil { |
| 122 | if perr := parseCloseError(err, true); perr != nil { |
| 123 | t.Error(perr) |
| 124 | } |
| 125 | t.Error(err) |
| 126 | return |
| 127 | } |
| 128 | n, err = c.Write(b[:]) |
| 129 | if err == nil { |
| 130 | t.Errorf("got (%d, %v); want (any, error)", n, err) |
| 131 | return |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | ls, err := newLocalServer(network) |
| 136 | if err != nil { |
| 137 | t.Fatal(err) |
| 138 | } |
| 139 | defer ls.teardown() |
| 140 | if err := ls.buildup(handler); err != nil { |
| 141 | t.Fatal(err) |
| 142 | } |
| 143 | |
| 144 | c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) |
| 145 | if err != nil { |
| 146 | t.Fatal(err) |
| 147 | } |
| 148 | if !deadline.IsZero() { |
| 149 | c.SetDeadline(deadline) |
| 150 | } |
| 151 | switch network { |
| 152 | case "unix", "unixpacket": |
| 153 | defer os.Remove(c.LocalAddr().String()) |
| 154 | } |
| 155 | defer c.Close() |
| 156 | |
| 157 | switch c := c.(type) { |
| 158 | case *TCPConn: |
| 159 | err = c.CloseWrite() |
| 160 | case *UnixConn: |
| 161 | err = c.CloseWrite() |
| 162 | } |
| 163 | if err != nil { |
| 164 | if perr := parseCloseError(err, true); perr != nil { |
| 165 | t.Error(perr) |
| 166 | } |
| 167 | t.Fatal(err) |
| 168 | } |
| 169 | var b [1]byte |
| 170 | n, err := c.Read(b[:]) |
| 171 | if n != 0 || err != io.EOF { |
| 172 | t.Fatalf("got (%d, %v); want (0, io.EOF)", n, err) |
| 173 | } |
| 174 | n, err = c.Write(b[:]) |
| 175 | if err == nil { |
| 176 | t.Fatalf("got (%d, %v); want (any, error)", n, err) |
| 177 | } |
| 178 | }) |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 179 | } |
| 180 | } |
| 181 | |
| 182 | func TestConnClose(t *testing.T) { |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 183 | t.Parallel() |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 184 | for _, network := range []string{"tcp", "unix", "unixpacket"} { |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 185 | network := network |
| 186 | t.Run(network, func(t *testing.T) { |
| 187 | if !testableNetwork(network) { |
| 188 | t.Skipf("network %s is not testable on the current platform", network) |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 189 | } |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 190 | t.Parallel() |
| 191 | |
| 192 | ln, err := newLocalListener(network) |
| 193 | if err != nil { |
| 194 | t.Fatal(err) |
| 195 | } |
| 196 | switch network { |
| 197 | case "unix", "unixpacket": |
| 198 | defer os.Remove(ln.Addr().String()) |
| 199 | } |
| 200 | defer ln.Close() |
| 201 | |
| 202 | c, err := Dial(ln.Addr().Network(), ln.Addr().String()) |
| 203 | if err != nil { |
| 204 | t.Fatal(err) |
| 205 | } |
| 206 | switch network { |
| 207 | case "unix", "unixpacket": |
| 208 | defer os.Remove(c.LocalAddr().String()) |
| 209 | } |
| 210 | defer c.Close() |
| 211 | |
| 212 | if err := c.Close(); err != nil { |
| 213 | if perr := parseCloseError(err, false); perr != nil { |
| 214 | t.Error(perr) |
| 215 | } |
| 216 | t.Fatal(err) |
| 217 | } |
| 218 | var b [1]byte |
| 219 | n, err := c.Read(b[:]) |
| 220 | if n != 0 || err == nil { |
| 221 | t.Fatalf("got (%d, %v); want (0, error)", n, err) |
| 222 | } |
| 223 | }) |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 224 | } |
| 225 | } |
| 226 | |
| 227 | func TestListenerClose(t *testing.T) { |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 228 | t.Parallel() |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 229 | for _, network := range []string{"tcp", "unix", "unixpacket"} { |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 230 | network := network |
| 231 | t.Run(network, func(t *testing.T) { |
| 232 | if !testableNetwork(network) { |
| 233 | t.Skipf("network %s is not testable on the current platform", network) |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 234 | } |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 235 | t.Parallel() |
Ian Lance Taylor | 8cedea1 | 2016-02-03 12:08:40 -0800 | [diff] [blame] | 236 | |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 237 | ln, err := newLocalListener(network) |
| 238 | if err != nil { |
| 239 | t.Fatal(err) |
| 240 | } |
| 241 | switch network { |
| 242 | case "unix", "unixpacket": |
| 243 | defer os.Remove(ln.Addr().String()) |
| 244 | } |
Ian Lance Taylor | 1c3747d | 2016-02-17 21:53:03 -0800 | [diff] [blame] | 245 | |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 246 | dst := ln.Addr().String() |
| 247 | if err := ln.Close(); err != nil { |
| 248 | if perr := parseCloseError(err, false); perr != nil { |
| 249 | t.Error(perr) |
| 250 | } |
| 251 | t.Fatal(err) |
| 252 | } |
| 253 | c, err := ln.Accept() |
Ian Lance Taylor | 8cedea1 | 2016-02-03 12:08:40 -0800 | [diff] [blame] | 254 | if err == nil { |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 255 | c.Close() |
| 256 | t.Fatal("should fail") |
Ian Lance Taylor | 8cedea1 | 2016-02-03 12:08:40 -0800 | [diff] [blame] | 257 | } |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 258 | |
| 259 | if network == "tcp" { |
| 260 | // We will have two TCP FSMs inside the |
| 261 | // kernel here. There's no guarantee that a |
| 262 | // signal comes from the far end FSM will be |
| 263 | // delivered immediately to the near end FSM, |
| 264 | // especially on the platforms that allow |
| 265 | // multiple consumer threads to pull pending |
| 266 | // established connections at the same time by |
| 267 | // enabling SO_REUSEPORT option such as Linux, |
| 268 | // DragonFly BSD. So we need to give some time |
| 269 | // quantum to the kernel. |
| 270 | // |
| 271 | // Note that net.inet.tcp.reuseport_ext=1 by |
| 272 | // default on DragonFly BSD. |
| 273 | time.Sleep(time.Millisecond) |
| 274 | |
| 275 | cc, err := Dial("tcp", dst) |
| 276 | if err == nil { |
| 277 | t.Error("Dial to closed TCP listener succeeded.") |
| 278 | cc.Close() |
| 279 | } |
| 280 | } |
| 281 | }) |
Ian Lance Taylor | 9b557c4 | 2012-03-02 08:23:02 -0800 | [diff] [blame] | 282 | } |
| 283 | } |
| 284 | |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 285 | func TestPacketConnClose(t *testing.T) { |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 286 | t.Parallel() |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 287 | for _, network := range []string{"udp", "unixgram"} { |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 288 | network := network |
| 289 | t.Run(network, func(t *testing.T) { |
| 290 | if !testableNetwork(network) { |
| 291 | t.Skipf("network %s is not testable on the current platform", network) |
Ian Lance Taylor | 5e7ded0 | 2015-10-30 16:02:38 -0700 | [diff] [blame] | 292 | } |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 293 | t.Parallel() |
| 294 | |
| 295 | c, err := newLocalPacketListener(network) |
| 296 | if err != nil { |
| 297 | t.Fatal(err) |
| 298 | } |
| 299 | switch network { |
| 300 | case "unixgram": |
| 301 | defer os.Remove(c.LocalAddr().String()) |
| 302 | } |
| 303 | defer c.Close() |
| 304 | |
| 305 | if err := c.Close(); err != nil { |
| 306 | if perr := parseCloseError(err, false); perr != nil { |
| 307 | t.Error(perr) |
| 308 | } |
| 309 | t.Fatal(err) |
| 310 | } |
| 311 | var b [1]byte |
| 312 | n, _, err := c.ReadFrom(b[:]) |
| 313 | if n != 0 || err == nil { |
| 314 | t.Fatalf("got (%d, %v); want (0, error)", n, err) |
| 315 | } |
| 316 | }) |
Ian Lance Taylor | f8f0cb4 | 2013-11-06 11:23:33 -0800 | [diff] [blame] | 317 | } |
| 318 | } |
Ian Lance Taylor | 8cedea1 | 2016-02-03 12:08:40 -0800 | [diff] [blame] | 319 | |
Ian Lance Taylor | 8cedea1 | 2016-02-03 12:08:40 -0800 | [diff] [blame] | 320 | func TestListenCloseListen(t *testing.T) { |
| 321 | const maxTries = 10 |
| 322 | for tries := 0; tries < maxTries; tries++ { |
| 323 | ln, err := newLocalListener("tcp") |
| 324 | if err != nil { |
| 325 | t.Fatal(err) |
| 326 | } |
| 327 | addr := ln.Addr().String() |
| 328 | if err := ln.Close(); err != nil { |
Ian Lance Taylor | 4e063a8 | 2017-09-09 06:18:16 -0700 | [diff] [blame] | 329 | if perr := parseCloseError(err, false); perr != nil { |
Ian Lance Taylor | 1c3747d | 2016-02-17 21:53:03 -0800 | [diff] [blame] | 330 | t.Error(perr) |
| 331 | } |
Ian Lance Taylor | 8cedea1 | 2016-02-03 12:08:40 -0800 | [diff] [blame] | 332 | t.Fatal(err) |
| 333 | } |
| 334 | ln, err = Listen("tcp", addr) |
| 335 | if err == nil { |
Ian Lance Taylor | c2225a7 | 2020-01-02 15:05:27 -0800 | [diff] [blame] | 336 | // Success. (This test didn't always make it here earlier.) |
Ian Lance Taylor | 8cedea1 | 2016-02-03 12:08:40 -0800 | [diff] [blame] | 337 | ln.Close() |
| 338 | return |
| 339 | } |
| 340 | t.Errorf("failed on try %d/%d: %v", tries+1, maxTries, err) |
| 341 | } |
| 342 | t.Fatalf("failed to listen/close/listen on same address after %d tries", maxTries) |
| 343 | } |
Ian Lance Taylor | b156d71 | 2016-07-22 07:41:34 -0700 | [diff] [blame] | 344 | |
| 345 | // See golang.org/issue/6163, golang.org/issue/6987. |
| 346 | func TestAcceptIgnoreAbortedConnRequest(t *testing.T) { |
| 347 | switch runtime.GOOS { |
| 348 | case "plan9": |
| 349 | t.Skipf("%s does not have full support of socktest", runtime.GOOS) |
| 350 | } |
| 351 | |
| 352 | syserr := make(chan error) |
| 353 | go func() { |
| 354 | defer close(syserr) |
| 355 | for _, err := range abortedConnRequestErrors { |
| 356 | syserr <- err |
| 357 | } |
| 358 | }() |
| 359 | sw.Set(socktest.FilterAccept, func(so *socktest.Status) (socktest.AfterFilter, error) { |
| 360 | if err, ok := <-syserr; ok { |
| 361 | return nil, err |
| 362 | } |
| 363 | return nil, nil |
| 364 | }) |
| 365 | defer sw.Set(socktest.FilterAccept, nil) |
| 366 | |
| 367 | operr := make(chan error, 1) |
| 368 | handler := func(ls *localServer, ln Listener) { |
| 369 | defer close(operr) |
| 370 | c, err := ln.Accept() |
| 371 | if err != nil { |
| 372 | if perr := parseAcceptError(err); perr != nil { |
| 373 | operr <- perr |
| 374 | } |
| 375 | operr <- err |
| 376 | return |
| 377 | } |
| 378 | c.Close() |
| 379 | } |
| 380 | ls, err := newLocalServer("tcp") |
| 381 | if err != nil { |
| 382 | t.Fatal(err) |
| 383 | } |
| 384 | defer ls.teardown() |
| 385 | if err := ls.buildup(handler); err != nil { |
| 386 | t.Fatal(err) |
| 387 | } |
| 388 | |
| 389 | c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) |
| 390 | if err != nil { |
| 391 | t.Fatal(err) |
| 392 | } |
| 393 | c.Close() |
| 394 | |
| 395 | for err := range operr { |
| 396 | t.Error(err) |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | func TestZeroByteRead(t *testing.T) { |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 401 | t.Parallel() |
Ian Lance Taylor | b156d71 | 2016-07-22 07:41:34 -0700 | [diff] [blame] | 402 | for _, network := range []string{"tcp", "unix", "unixpacket"} { |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 403 | network := network |
| 404 | t.Run(network, func(t *testing.T) { |
| 405 | if !testableNetwork(network) { |
| 406 | t.Skipf("network %s is not testable on the current platform", network) |
Ian Lance Taylor | b156d71 | 2016-07-22 07:41:34 -0700 | [diff] [blame] | 407 | } |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 408 | t.Parallel() |
Ian Lance Taylor | b156d71 | 2016-07-22 07:41:34 -0700 | [diff] [blame] | 409 | |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 410 | ln, err := newLocalListener(network) |
| 411 | if err != nil { |
| 412 | t.Fatal(err) |
| 413 | } |
| 414 | connc := make(chan Conn, 1) |
| 415 | go func() { |
| 416 | defer ln.Close() |
| 417 | c, err := ln.Accept() |
| 418 | if err != nil { |
| 419 | t.Error(err) |
| 420 | } |
| 421 | connc <- c // might be nil |
| 422 | }() |
| 423 | c, err := Dial(network, ln.Addr().String()) |
| 424 | if err != nil { |
| 425 | t.Fatal(err) |
| 426 | } |
| 427 | defer c.Close() |
| 428 | sc := <-connc |
| 429 | if sc == nil { |
| 430 | return |
| 431 | } |
| 432 | defer sc.Close() |
Ian Lance Taylor | b156d71 | 2016-07-22 07:41:34 -0700 | [diff] [blame] | 433 | |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 434 | if runtime.GOOS == "windows" { |
| 435 | // A zero byte read on Windows caused a wait for readability first. |
| 436 | // Rather than change that behavior, satisfy it in this test. |
| 437 | // See Issue 15735. |
| 438 | go io.WriteString(sc, "a") |
| 439 | } |
Ian Lance Taylor | b156d71 | 2016-07-22 07:41:34 -0700 | [diff] [blame] | 440 | |
Ian Lance Taylor | 2c390ba | 2020-07-27 22:27:54 -0700 | [diff] [blame] | 441 | n, err := c.Read(nil) |
| 442 | if n != 0 || err != nil { |
| 443 | t.Errorf("%s: zero byte client read = %v, %v; want 0, nil", network, n, err) |
| 444 | } |
| 445 | |
| 446 | if runtime.GOOS == "windows" { |
| 447 | // Same as comment above. |
| 448 | go io.WriteString(c, "a") |
| 449 | } |
| 450 | n, err = sc.Read(nil) |
| 451 | if n != 0 || err != nil { |
| 452 | t.Errorf("%s: zero byte server read = %v, %v; want 0, nil", network, n, err) |
| 453 | } |
| 454 | }) |
Ian Lance Taylor | b156d71 | 2016-07-22 07:41:34 -0700 | [diff] [blame] | 455 | } |
| 456 | } |
Ian Lance Taylor | 0ba4563 | 2017-01-13 11:17:23 -0800 | [diff] [blame] | 457 | |
| 458 | // withTCPConnPair sets up a TCP connection between two peers, then |
| 459 | // runs peer1 and peer2 concurrently. withTCPConnPair returns when |
| 460 | // both have completed. |
| 461 | func withTCPConnPair(t *testing.T, peer1, peer2 func(c *TCPConn) error) { |
| 462 | ln, err := newLocalListener("tcp") |
| 463 | if err != nil { |
| 464 | t.Fatal(err) |
| 465 | } |
| 466 | defer ln.Close() |
| 467 | errc := make(chan error, 2) |
| 468 | go func() { |
| 469 | c1, err := ln.Accept() |
| 470 | if err != nil { |
| 471 | errc <- err |
| 472 | return |
| 473 | } |
| 474 | defer c1.Close() |
| 475 | errc <- peer1(c1.(*TCPConn)) |
| 476 | }() |
| 477 | go func() { |
| 478 | c2, err := Dial("tcp", ln.Addr().String()) |
| 479 | if err != nil { |
| 480 | errc <- err |
| 481 | return |
| 482 | } |
| 483 | defer c2.Close() |
| 484 | errc <- peer2(c2.(*TCPConn)) |
| 485 | }() |
| 486 | for i := 0; i < 2; i++ { |
| 487 | if err := <-errc; err != nil { |
| 488 | t.Fatal(err) |
| 489 | } |
| 490 | } |
| 491 | } |
| 492 | |
| 493 | // Tests that a blocked Read is interrupted by a concurrent SetReadDeadline |
| 494 | // modifying that Conn's read deadline to the past. |
| 495 | // See golang.org/cl/30164 which documented this. The net/http package |
| 496 | // depends on this. |
| 497 | func TestReadTimeoutUnblocksRead(t *testing.T) { |
| 498 | serverDone := make(chan struct{}) |
| 499 | server := func(cs *TCPConn) error { |
| 500 | defer close(serverDone) |
| 501 | errc := make(chan error, 1) |
| 502 | go func() { |
| 503 | defer close(errc) |
| 504 | go func() { |
| 505 | // TODO: find a better way to wait |
| 506 | // until we're blocked in the cs.Read |
| 507 | // call below. Sleep is lame. |
| 508 | time.Sleep(100 * time.Millisecond) |
| 509 | |
| 510 | // Interrupt the upcoming Read, unblocking it: |
| 511 | cs.SetReadDeadline(time.Unix(123, 0)) // time in the past |
| 512 | }() |
| 513 | var buf [1]byte |
| 514 | n, err := cs.Read(buf[:1]) |
| 515 | if n != 0 || err == nil { |
| 516 | errc <- fmt.Errorf("Read = %v, %v; want 0, non-nil", n, err) |
| 517 | } |
| 518 | }() |
| 519 | select { |
| 520 | case err := <-errc: |
| 521 | return err |
| 522 | case <-time.After(5 * time.Second): |
| 523 | buf := make([]byte, 2<<20) |
| 524 | buf = buf[:runtime.Stack(buf, true)] |
| 525 | println("Stacks at timeout:\n", string(buf)) |
| 526 | return errors.New("timeout waiting for Read to finish") |
| 527 | } |
| 528 | |
| 529 | } |
| 530 | // Do nothing in the client. Never write. Just wait for the |
| 531 | // server's half to be done. |
| 532 | client := func(*TCPConn) error { |
| 533 | <-serverDone |
| 534 | return nil |
| 535 | } |
| 536 | withTCPConnPair(t, client, server) |
| 537 | } |
| 538 | |
| 539 | // Issue 17695: verify that a blocked Read is woken up by a Close. |
| 540 | func TestCloseUnblocksRead(t *testing.T) { |
| 541 | t.Parallel() |
| 542 | server := func(cs *TCPConn) error { |
| 543 | // Give the client time to get stuck in a Read: |
| 544 | time.Sleep(20 * time.Millisecond) |
| 545 | cs.Close() |
| 546 | return nil |
| 547 | } |
| 548 | client := func(ss *TCPConn) error { |
| 549 | n, err := ss.Read([]byte{0}) |
| 550 | if n != 0 || err != io.EOF { |
| 551 | return fmt.Errorf("Read = %v, %v; want 0, EOF", n, err) |
| 552 | } |
| 553 | return nil |
| 554 | } |
| 555 | withTCPConnPair(t, client, server) |
| 556 | } |
Ian Lance Taylor | 7b25b4d | 2018-08-26 18:14:49 -0700 | [diff] [blame] | 557 | |
| 558 | // Issue 24808: verify that ECONNRESET is not temporary for read. |
| 559 | func TestNotTemporaryRead(t *testing.T) { |
| 560 | if runtime.GOOS == "freebsd" { |
| 561 | testenv.SkipFlaky(t, 25289) |
| 562 | } |
Ian Lance Taylor | ceb1e4f | 2019-09-10 21:53:46 -0700 | [diff] [blame] | 563 | if runtime.GOOS == "aix" { |
| 564 | testenv.SkipFlaky(t, 29685) |
| 565 | } |
Ian Lance Taylor | 7b25b4d | 2018-08-26 18:14:49 -0700 | [diff] [blame] | 566 | t.Parallel() |
| 567 | server := func(cs *TCPConn) error { |
| 568 | cs.SetLinger(0) |
| 569 | // Give the client time to get stuck in a Read. |
Ian Lance Taylor | 51d2cb4 | 2019-02-14 18:22:34 -0800 | [diff] [blame] | 570 | time.Sleep(50 * time.Millisecond) |
Ian Lance Taylor | 7b25b4d | 2018-08-26 18:14:49 -0700 | [diff] [blame] | 571 | cs.Close() |
| 572 | return nil |
| 573 | } |
| 574 | client := func(ss *TCPConn) error { |
| 575 | _, err := ss.Read([]byte{0}) |
| 576 | if err == nil { |
| 577 | return errors.New("Read succeeded unexpectedly") |
| 578 | } else if err == io.EOF { |
Ian Lance Taylor | c2225a7 | 2020-01-02 15:05:27 -0800 | [diff] [blame] | 579 | // This happens on Plan 9. |
Ian Lance Taylor | 7b25b4d | 2018-08-26 18:14:49 -0700 | [diff] [blame] | 580 | return nil |
| 581 | } else if ne, ok := err.(Error); !ok { |
| 582 | return fmt.Errorf("unexpected error %v", err) |
| 583 | } else if ne.Temporary() { |
| 584 | return fmt.Errorf("unexpected temporary error %v", err) |
| 585 | } |
| 586 | return nil |
| 587 | } |
| 588 | withTCPConnPair(t, client, server) |
| 589 | } |