gitee.com/sy_183/go-common@v1.0.5-0.20231205030221-958cfe129b47/utils/net/alloc-port_linux.go (about)

     1  package netUtils
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net"
     7  	"syscall"
     8  )
     9  
    10  type fdSocket int
    11  
    12  func (s fdSocket) Close() error {
    13  	return syscall.Close(int(s))
    14  }
    15  
    16  func AllocPort(network string, ip net.IP) (socket io.Closer, port int, err error) {
    17  	switch network {
    18  	case "tcp", "tcp4", "tcp6":
    19  	case "udp", "udp4", "udp6":
    20  	default:
    21  		return nil, 0, &net.OpError{Op: "dial", Net: network, Source: ipToAddr(ip), Addr: ipToAddr(ip), Err: net.UnknownNetworkError(network)}
    22  	}
    23  	var sockaddr syscall.Sockaddr
    24  retry:
    25  	switch len(ip) {
    26  	case 0:
    27  		switch network {
    28  		case "tcp", "tcp4", "udp", "udp4":
    29  			sockaddr = &syscall.SockaddrInet4{}
    30  		case "tcp6", "udp6":
    31  			sockaddr = &syscall.SockaddrInet6{}
    32  		}
    33  	case net.IPv4len:
    34  		if network == "tcp6" || network == "udp6" {
    35  			ip = ip.To16()
    36  			goto retry
    37  		}
    38  		sockaddrInet4 := &syscall.SockaddrInet4{}
    39  		copy(sockaddrInet4.Addr[:], ip)
    40  		sockaddr = sockaddrInet4
    41  	case net.IPv6len:
    42  		if network == "tcp4" || network == "udp4" {
    43  			ipv4 := ip.To4()
    44  			if ipv4 == nil {
    45  				return nil, 0, &net.AddrError{Err: "错误的IPV4地址", Addr: ip.String()}
    46  			}
    47  			ip = ipv4
    48  			goto retry
    49  		}
    50  		sockaddrInet6 := &syscall.SockaddrInet6{}
    51  		copy(sockaddrInet6.Addr[:], ip)
    52  		sockaddr = sockaddrInet6
    53  	default:
    54  		return nil, 0, &net.AddrError{Err: "错误的IP地址", Addr: ip.String()}
    55  	}
    56  
    57  	var fd int
    58  	switch network[:3] {
    59  	case "tcp":
    60  		fd, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
    61  	case "udp":
    62  		fd, err = syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
    63  	}
    64  	if err != nil {
    65  		return nil, 0, err
    66  	}
    67  	defer func() {
    68  		if err != nil {
    69  			syscall.Close(fd)
    70  		}
    71  	}()
    72  
    73  	if err = syscall.Bind(fd, sockaddr); err != nil {
    74  		return nil, 0, err
    75  	}
    76  
    77  	sockaddr, err = syscall.Getsockname(fd)
    78  	if err != nil {
    79  		return nil, 0, err
    80  	}
    81  
    82  	switch sa := sockaddr.(type) {
    83  	case *syscall.SockaddrInet4:
    84  		return fdSocket(fd), sa.Port, nil
    85  	case *syscall.SockaddrInet6:
    86  		return fdSocket(fd), sa.Port, nil
    87  	default:
    88  		return nil, 0, &net.AddrError{Err: "无效的sockaddr类型", Addr: fmt.Sprint(sa)}
    89  	}
    90  }