mirror of
https://github.com/go-i2p/go-meta-listener.git
synced 2025-06-07 18:24:22 -04:00
work on tcp lib
This commit is contained in:
@ -35,7 +35,7 @@ const (
|
||||
func Listen(network, address string) (net.Listener, error) {
|
||||
// Validate network parameter
|
||||
if !isValidNetwork(network) {
|
||||
return nil, fmt.Errorf("tcp.Listen: invalid network type %q, must be tcp, tcp4, or tcp6", network)
|
||||
return nil, fmt.Errorf("tcp.Listen: invalid network type %q for addr %s, must be tcp, tcp4, or tcp6", network, address)
|
||||
}
|
||||
|
||||
// Validate address format by attempting to resolve
|
||||
@ -77,33 +77,45 @@ func isValidNetwork(network string) bool {
|
||||
|
||||
// configureSocket applies production-ready socket options to the TCP listener
|
||||
func configureSocket(listener *net.TCPListener) error {
|
||||
// Get the underlying file descriptor for socket configuration
|
||||
file, err := listener.File()
|
||||
// Use SyscallConn to access the raw socket without duplicating the file descriptor
|
||||
rawConn, err := listener.SyscallConn()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get listener file descriptor: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fd := int(file.Fd())
|
||||
|
||||
// Enable SO_REUSEADDR to prevent "address already in use" errors
|
||||
if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
|
||||
return fmt.Errorf("failed to set SO_REUSEADDR: %w", err)
|
||||
return fmt.Errorf("failed to get listener syscall connection: %w", err)
|
||||
}
|
||||
|
||||
// Set receive buffer size for optimal throughput
|
||||
if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_RCVBUF, bufferSize); err != nil {
|
||||
return fmt.Errorf("failed to set receive buffer size: %w", err)
|
||||
}
|
||||
// Apply socket options using the raw connection
|
||||
var sockErr error
|
||||
err = rawConn.Control(func(fd uintptr) {
|
||||
// Enable SO_REUSEADDR to prevent "address already in use" errors
|
||||
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
|
||||
sockErr = fmt.Errorf("failed to set SO_REUSEADDR: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Set send buffer size for optimal throughput
|
||||
if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_SNDBUF, bufferSize); err != nil {
|
||||
return fmt.Errorf("failed to set send buffer size: %w", err)
|
||||
}
|
||||
// Set receive buffer size for optimal throughput
|
||||
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, bufferSize); err != nil {
|
||||
sockErr = fmt.Errorf("failed to set receive buffer size: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Enable TCP_NODELAY to minimize latency (disable Nagle's algorithm)
|
||||
if err := syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, 1); err != nil {
|
||||
return fmt.Errorf("failed to set TCP_NODELAY: %w", err)
|
||||
// Set send buffer size for optimal throughput
|
||||
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDBUF, bufferSize); err != nil {
|
||||
sockErr = fmt.Errorf("failed to set send buffer size: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Enable TCP_NODELAY to minimize latency (disable Nagle's algorithm)
|
||||
if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_NODELAY, 1); err != nil {
|
||||
sockErr = fmt.Errorf("failed to set TCP_NODELAY: %w", err)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to access socket for configuration: %w", err)
|
||||
}
|
||||
if sockErr != nil {
|
||||
return sockErr
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -258,3 +258,38 @@ func BenchmarkListen(b *testing.B) {
|
||||
listener.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigureSocket_NoResourceLeak(t *testing.T) {
|
||||
// Create a listener
|
||||
listener, err := net.Listen("tcp", ":0")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create base listener: %v", err)
|
||||
}
|
||||
defer listener.Close()
|
||||
|
||||
tcpListener := listener.(*net.TCPListener)
|
||||
|
||||
// Configure the socket - this should not invalidate the listener
|
||||
err = configureSocket(tcpListener)
|
||||
if err != nil {
|
||||
t.Fatalf("Socket configuration failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify the listener is still usable by accepting a connection
|
||||
addr := listener.Addr().String()
|
||||
|
||||
// Test connection in a goroutine
|
||||
go func() {
|
||||
conn, err := net.Dial("tcp", addr)
|
||||
if err == nil {
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
// This should succeed if the listener wasn't invalidated
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
t.Fatalf("Listener became unusable after configuration: %v", err)
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
|
Reference in New Issue
Block a user