1// Copyright 2023 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 5//go:build js || wasip1 6 7package net 8 9// GOOS=js and GOOS=wasip1 do not have typical socket networking capabilities 10// found on other platforms. To help run test suites of the stdlib packages, 11// an in-memory "fake network" facility is implemented. 12// 13// The tests in this files are intended to validate the behavior of the fake 14// network stack on these platforms. 15 16import ( 17 "errors" 18 "syscall" 19 "testing" 20) 21 22func TestFakePortExhaustion(t *testing.T) { 23 if testing.Short() { 24 t.Skipf("skipping test that opens 1<<16 connections") 25 } 26 27 ln := newLocalListener(t, "tcp") 28 done := make(chan struct{}) 29 go func() { 30 var accepted []Conn 31 defer func() { 32 for _, c := range accepted { 33 c.Close() 34 } 35 close(done) 36 }() 37 38 for { 39 c, err := ln.Accept() 40 if err != nil { 41 return 42 } 43 accepted = append(accepted, c) 44 } 45 }() 46 47 var dialed []Conn 48 defer func() { 49 ln.Close() 50 for _, c := range dialed { 51 c.Close() 52 } 53 <-done 54 }() 55 56 // Since this test is not running in parallel, we expect to be able to open 57 // all 65535 valid (fake) ports. The listener is already using one, so 58 // we should be able to Dial the remaining 65534. 59 for len(dialed) < (1<<16)-2 { 60 c, err := Dial(ln.Addr().Network(), ln.Addr().String()) 61 if err != nil { 62 t.Fatalf("unexpected error from Dial with %v connections: %v", len(dialed), err) 63 } 64 dialed = append(dialed, c) 65 if testing.Verbose() && len(dialed)%(1<<12) == 0 { 66 t.Logf("dialed %d connections", len(dialed)) 67 } 68 } 69 t.Logf("dialed %d connections", len(dialed)) 70 71 // Now that all of the ports are in use, dialing another should fail due 72 // to port exhaustion, which (for POSIX-like socket APIs) should return 73 // an EADDRINUSE error. 74 c, err := Dial(ln.Addr().Network(), ln.Addr().String()) 75 if err == nil { 76 c.Close() 77 } 78 if errors.Is(err, syscall.EADDRINUSE) { 79 t.Logf("Dial returned expected error: %v", err) 80 } else { 81 t.Errorf("unexpected error from Dial: %v\nwant: %v", err, syscall.EADDRINUSE) 82 } 83 84 // Opening a Listener should fail at this point too. 85 ln2, err := Listen("tcp", "localhost:0") 86 if err == nil { 87 ln2.Close() 88 } 89 if errors.Is(err, syscall.EADDRINUSE) { 90 t.Logf("Listen returned expected error: %v", err) 91 } else { 92 t.Errorf("unexpected error from Listen: %v\nwant: %v", err, syscall.EADDRINUSE) 93 } 94 95 // When we close an arbitrary connection, we should be able to reuse its port 96 // even if the server hasn't yet seen the ECONNRESET for the connection. 97 dialed[0].Close() 98 dialed = dialed[1:] 99 t.Logf("closed one connection") 100 c, err = Dial(ln.Addr().Network(), ln.Addr().String()) 101 if err == nil { 102 c.Close() 103 t.Logf("Dial succeeded") 104 } else { 105 t.Errorf("unexpected error from Dial: %v", err) 106 } 107} 108