socket_activation_unix.go 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. //go:build unix
  2. // +build unix
  3. package internet
  4. import (
  5. "fmt"
  6. "os"
  7. "path"
  8. "strconv"
  9. "syscall"
  10. "github.com/v2fly/v2ray-core/v5/common/net"
  11. )
  12. func activateSocket(address string, f func(network, address string, fd uintptr)) (net.Listener, error) {
  13. fd, err := strconv.Atoi(path.Base(address))
  14. if err != nil {
  15. return nil, err
  16. }
  17. err = syscall.SetNonblock(fd, true)
  18. if err != nil {
  19. return nil, err
  20. }
  21. acceptConn, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_ACCEPTCONN)
  22. if err != nil {
  23. return nil, err
  24. }
  25. if acceptConn == 0 {
  26. return nil, fmt.Errorf("socket '%s' has not been marked to accept connections", address)
  27. }
  28. sockType, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
  29. if err != nil {
  30. return nil, err
  31. }
  32. if sockType != syscall.SOCK_STREAM {
  33. // XXX: currently only stream socks are supported
  34. return nil, fmt.Errorf("socket '%s' is not a stream socket", address)
  35. }
  36. ufd := uintptr(fd)
  37. sa, err := syscall.Getsockname(fd)
  38. if err != nil {
  39. return nil, err
  40. }
  41. switch sa := sa.(type) {
  42. case *syscall.SockaddrInet4:
  43. addr := net.TCPAddr{IP: sa.Addr[:], Port: sa.Port, Zone: ""}
  44. f("tcp4", addr.String(), ufd)
  45. case *syscall.SockaddrInet6:
  46. addr := net.TCPAddr{IP: sa.Addr[:], Port: sa.Port, Zone: strconv.Itoa(int(sa.ZoneId))}
  47. f("tcp6", addr.String(), ufd)
  48. }
  49. file := os.NewFile(ufd, address)
  50. defer file.Close()
  51. return net.FileListener(file)
  52. }