unix.go raw

   1  // Package unix is the small slice of Linux socket and poll functionality that
   2  // torly's acceptor and fdConn need. It exists so that the relay does not
   3  // depend on an external syscall module: the calls are visible, reviewable and
   4  // can be adjusted for the targets TinyGo supports.
   5  package unix
   6  
   7  import (
   8  	"syscall"
   9  	"unsafe"
  10  )
  11  
  12  // Constants mirrored from the Linux ABI.
  13  const (
  14  	AF_INET       = syscall.AF_INET
  15  	SOCK_STREAM   = syscall.SOCK_STREAM
  16  	SOCK_NONBLOCK = syscall.SOCK_NONBLOCK
  17  	SOCK_CLOEXEC  = syscall.SOCK_CLOEXEC
  18  	SOL_SOCKET    = syscall.SOL_SOCKET
  19  	SO_REUSEADDR  = syscall.SO_REUSEADDR
  20  	SHUT_RDWR     = syscall.SHUT_RDWR
  21  	EAGAIN        = syscall.EAGAIN
  22  	EINTR         = syscall.EINTR
  23  	POLLIN        = 0x1
  24  	POLLOUT       = 0x4
  25  )
  26  
  27  // SockaddrInet4 is an IPv4 socket address.
  28  type SockaddrInet4 = syscall.SockaddrInet4
  29  
  30  // Sockaddr is a socket address.
  31  type Sockaddr = syscall.Sockaddr
  32  
  33  // PollFd mirrors struct pollfd.
  34  type PollFd struct {
  35  	Fd      int32
  36  	Events  int16
  37  	Revents int16
  38  }
  39  
  40  // Socket creates a socket.
  41  func Socket(domain, typ, proto int) (int, error) { return syscall.Socket(domain, typ, proto) }
  42  
  43  // Bind binds a socket.
  44  func Bind(fd int, sa Sockaddr) error { return syscall.Bind(fd, sa) }
  45  
  46  // Listen marks a socket as accepting connections.
  47  func Listen(fd, backlog int) error { return syscall.Listen(fd, backlog) }
  48  
  49  // Accept4 accepts a connection with flags.
  50  func Accept4(fd, flags int) (int, Sockaddr, error) { return syscall.Accept4(fd, flags) }
  51  
  52  // Getsockname returns the local address of a socket.
  53  func Getsockname(fd int) (Sockaddr, error) { return syscall.Getsockname(fd) }
  54  
  55  // SetsockoptInt sets an integer socket option.
  56  func SetsockoptInt(fd, level, opt, value int) error {
  57  	return syscall.SetsockoptInt(fd, level, opt, value)
  58  }
  59  
  60  // SetNonblock sets the non-blocking flag on a descriptor.
  61  func SetNonblock(fd int, nonblocking bool) error { return syscall.SetNonblock(fd, nonblocking) }
  62  
  63  // Close closes a descriptor.
  64  func Close(fd int) error { return syscall.Close(fd) }
  65  
  66  // Shutdown shuts down one or both directions of a socket.
  67  func Shutdown(fd, how int) error { return syscall.Shutdown(fd, how) }
  68  
  69  // Read reads from a descriptor.
  70  func Read(fd int, p []byte) (int, error) {
  71  	n, err := syscall.Read(fd, p)
  72  	if err != nil {
  73  		return n, err
  74  	}
  75  	return n, nil
  76  }
  77  
  78  // Write writes to a descriptor.
  79  func Write(fd int, p []byte) (int, error) {
  80  	n, err := syscall.Write(fd, p)
  81  	if err != nil {
  82  		return n, err
  83  	}
  84  	return n, nil
  85  }
  86  
  87  // Poll waits for events on the given descriptors. timeout is in milliseconds.
  88  func Poll(fds []PollFd, timeout int) (int, error) {
  89  	if len(fds) == 0 {
  90  		// Nothing to wait for; behave like a zero-timeout poll.
  91  		return 0, nil
  92  	}
  93  	r, _, errno := syscall.Syscall(syscall.SYS_POLL,
  94  		uintptr(unsafe.Pointer(&fds[0])), uintptr(len(fds)), uintptr(timeout))
  95  	if errno != 0 {
  96  		return int(r), errno
  97  	}
  98  	return int(r), nil
  99  }
 100