// Copyright 2015 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 unix || (js && wasm) || wasip1

package socktest

import 

// Socket wraps [syscall.Socket].
func ( *Switch) (, ,  int) ( int,  error) {
	.once.Do(.init)

	 := &Status{Cookie: cookie(, , )}
	.fmu.RLock()
	 := .fltab[FilterSocket]
	.fmu.RUnlock()

	,  := .apply()
	if  != nil {
		return -1, 
	}
	, .Err = syscall.Socket(, , )
	if  = .apply();  != nil {
		if .Err == nil {
			syscall.Close()
		}
		return -1, 
	}

	.smu.Lock()
	defer .smu.Unlock()
	if .Err != nil {
		.stats.getLocked(.Cookie).OpenFailed++
		return -1, .Err
	}
	 := .addLocked(, , , )
	.stats.getLocked(.Cookie).Opened++
	return , nil
}

// Close wraps syscall.Close.
func ( *Switch) ( int) ( error) {
	 := .sockso()
	if  == nil {
		return syscall.Close()
	}
	.fmu.RLock()
	 := .fltab[FilterClose]
	.fmu.RUnlock()

	,  := .apply()
	if  != nil {
		return 
	}
	.Err = syscall.Close()
	if  = .apply();  != nil {
		return 
	}

	.smu.Lock()
	defer .smu.Unlock()
	if .Err != nil {
		.stats.getLocked(.Cookie).CloseFailed++
		return .Err
	}
	delete(.sotab, )
	.stats.getLocked(.Cookie).Closed++
	return nil
}

// Connect wraps syscall.Connect.
func ( *Switch) ( int,  syscall.Sockaddr) ( error) {
	 := .sockso()
	if  == nil {
		return syscall.Connect(, )
	}
	.fmu.RLock()
	 := .fltab[FilterConnect]
	.fmu.RUnlock()

	,  := .apply()
	if  != nil {
		return 
	}
	.Err = syscall.Connect(, )
	if  = .apply();  != nil {
		return 
	}

	.smu.Lock()
	defer .smu.Unlock()
	if .Err != nil {
		.stats.getLocked(.Cookie).ConnectFailed++
		return .Err
	}
	.stats.getLocked(.Cookie).Connected++
	return nil
}

// Listen wraps syscall.Listen.
func ( *Switch) (,  int) ( error) {
	 := .sockso()
	if  == nil {
		return syscall.Listen(, )
	}
	.fmu.RLock()
	 := .fltab[FilterListen]
	.fmu.RUnlock()

	,  := .apply()
	if  != nil {
		return 
	}
	.Err = syscall.Listen(, )
	if  = .apply();  != nil {
		return 
	}

	.smu.Lock()
	defer .smu.Unlock()
	if .Err != nil {
		.stats.getLocked(.Cookie).ListenFailed++
		return .Err
	}
	.stats.getLocked(.Cookie).Listened++
	return nil
}

// Accept wraps syscall.Accept.
func ( *Switch) ( int) ( int,  syscall.Sockaddr,  error) {
	 := .sockso()
	if  == nil {
		return syscall.Accept()
	}
	.fmu.RLock()
	 := .fltab[FilterAccept]
	.fmu.RUnlock()

	,  := .apply()
	if  != nil {
		return -1, nil, 
	}
	, , .Err = syscall.Accept()
	if  = .apply();  != nil {
		if .Err == nil {
			syscall.Close()
		}
		return -1, nil, 
	}

	.smu.Lock()
	defer .smu.Unlock()
	if .Err != nil {
		.stats.getLocked(.Cookie).AcceptFailed++
		return -1, nil, .Err
	}
	 := .addLocked(, .Cookie.Family(), .Cookie.Type(), .Cookie.Protocol())
	.stats.getLocked(.Cookie).Accepted++
	return , , nil
}

// GetsockoptInt wraps syscall.GetsockoptInt.
func ( *Switch) (, ,  int) ( int,  error) {
	 := .sockso()
	if  == nil {
		return syscall.GetsockoptInt(, , )
	}
	.fmu.RLock()
	 := .fltab[FilterGetsockoptInt]
	.fmu.RUnlock()

	,  := .apply()
	if  != nil {
		return -1, 
	}
	, .Err = syscall.GetsockoptInt(, , )
	.SocketErr = syscall.Errno()
	if  = .apply();  != nil {
		return -1, 
	}

	if .Err != nil {
		return -1, .Err
	}
	if  == syscall.SO_ERROR && (.SocketErr == syscall.Errno(0) || .SocketErr == syscall.EISCONN) {
		.smu.Lock()
		.stats.getLocked(.Cookie).Connected++
		.smu.Unlock()
	}
	return , nil
}