Source file src/net/net_fake_test.go

     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  
     7  package 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  
    16  import (
    17  	"errors"
    18  	"syscall"
    19  	"testing"
    20  )
    21  
    22  func 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  

View as plain text