mirror of https://go.googlesource.com/go
108 lines
2.8 KiB
Go
108 lines
2.8 KiB
Go
// Copyright 2023 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
//go:build js || wasip1
|
|
|
|
package net
|
|
|
|
// GOOS=js and GOOS=wasip1 do not have typical socket networking capabilities
|
|
// found on other platforms. To help run test suites of the stdlib packages,
|
|
// an in-memory "fake network" facility is implemented.
|
|
//
|
|
// The tests in this files are intended to validate the behavior of the fake
|
|
// network stack on these platforms.
|
|
|
|
import (
|
|
"errors"
|
|
"syscall"
|
|
"testing"
|
|
)
|
|
|
|
func TestFakePortExhaustion(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skipf("skipping test that opens 1<<16 connections")
|
|
}
|
|
|
|
ln := newLocalListener(t, "tcp")
|
|
done := make(chan struct{})
|
|
go func() {
|
|
var accepted []Conn
|
|
defer func() {
|
|
for _, c := range accepted {
|
|
c.Close()
|
|
}
|
|
close(done)
|
|
}()
|
|
|
|
for {
|
|
c, err := ln.Accept()
|
|
if err != nil {
|
|
return
|
|
}
|
|
accepted = append(accepted, c)
|
|
}
|
|
}()
|
|
|
|
var dialed []Conn
|
|
defer func() {
|
|
ln.Close()
|
|
for _, c := range dialed {
|
|
c.Close()
|
|
}
|
|
<-done
|
|
}()
|
|
|
|
// Since this test is not running in parallel, we expect to be able to open
|
|
// all 65535 valid (fake) ports. The listener is already using one, so
|
|
// we should be able to Dial the remaining 65534.
|
|
for len(dialed) < (1<<16)-2 {
|
|
c, err := Dial(ln.Addr().Network(), ln.Addr().String())
|
|
if err != nil {
|
|
t.Fatalf("unexpected error from Dial with %v connections: %v", len(dialed), err)
|
|
}
|
|
dialed = append(dialed, c)
|
|
if testing.Verbose() && len(dialed)%(1<<12) == 0 {
|
|
t.Logf("dialed %d connections", len(dialed))
|
|
}
|
|
}
|
|
t.Logf("dialed %d connections", len(dialed))
|
|
|
|
// Now that all of the ports are in use, dialing another should fail due
|
|
// to port exhaustion, which (for POSIX-like socket APIs) should return
|
|
// an EADDRINUSE error.
|
|
c, err := Dial(ln.Addr().Network(), ln.Addr().String())
|
|
if err == nil {
|
|
c.Close()
|
|
}
|
|
if errors.Is(err, syscall.EADDRINUSE) {
|
|
t.Logf("Dial returned expected error: %v", err)
|
|
} else {
|
|
t.Errorf("unexpected error from Dial: %v\nwant: %v", err, syscall.EADDRINUSE)
|
|
}
|
|
|
|
// Opening a Listener should fail at this point too.
|
|
ln2, err := Listen("tcp", "localhost:0")
|
|
if err == nil {
|
|
ln2.Close()
|
|
}
|
|
if errors.Is(err, syscall.EADDRINUSE) {
|
|
t.Logf("Listen returned expected error: %v", err)
|
|
} else {
|
|
t.Errorf("unexpected error from Listen: %v\nwant: %v", err, syscall.EADDRINUSE)
|
|
}
|
|
|
|
// When we close an arbitrary connection, we should be able to reuse its port
|
|
// even if the server hasn't yet seen the ECONNRESET for the connection.
|
|
dialed[0].Close()
|
|
dialed = dialed[1:]
|
|
t.Logf("closed one connection")
|
|
c, err = Dial(ln.Addr().Network(), ln.Addr().String())
|
|
if err == nil {
|
|
c.Close()
|
|
t.Logf("Dial succeeded")
|
|
} else {
|
|
t.Errorf("unexpected error from Dial: %v", err)
|
|
}
|
|
}
|