//go:build !(windows && darwin)

package net

import (
	"golang.org/x/sys/unix"
	"net"
	"syscall"
)

func SetTcpInfo(conn *net.TCPConn, usingKeepAlive bool, keepAliveIdel, keepAlivePeriod, keepAliveCount, userTimeout int) error {
	rawConn, err := conn.SyscallConn()
	if err != nil {
		return err
	}
	if usingKeepAlive {
		err = rawConn.Control(func(fd uintptr) {
			err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPIDLE, keepAliveIdel)
			if err != nil {
				return
			}
			err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, keepAlivePeriod)
			if err != nil {
				return
			}
			err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, syscall.TCP_KEEPCNT, keepAliveCount)
			if err != nil {
				return
			}
		})
	} else {
		err = conn.SetKeepAlive(false)
	}
	if userTimeout > 0 {
		err = rawConn.Control(func(fd uintptr) {
			err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, 0x12, userTimeout)
		})
	}
	return err
}

func SetReUseAddr(fd uintptr) {
	syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
	syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEPORT, 1)
}

func ControlSetReUseAddr(network, address string, c syscall.RawConn) (err error) {
	if err := c.Control(func(fd uintptr) {
		err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
		if err != nil {
			return
		}

		err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
		if err != nil {
			return
		}
	}); err != nil {
		return err
	}
	return err
}