github.com/tetratelabs/wazero@v1.2.1/internal/sysfs/sock_unix.go (about) 1 //go:build linux || darwin 2 3 package sysfs 4 5 import ( 6 "net" 7 "syscall" 8 9 "github.com/tetratelabs/wazero/internal/platform" 10 socketapi "github.com/tetratelabs/wazero/internal/sock" 11 ) 12 13 // MSG_PEEK is the constant syscall.MSG_PEEK 14 const MSG_PEEK = syscall.MSG_PEEK 15 16 // newTCPListenerFile is a constructor for a socketapi.TCPSock. 17 // 18 // Note: the implementation of socketapi.TCPSock goes straight 19 // to the syscall layer, bypassing most of the Go library. 20 // For an alternative approach, consider winTcpListenerFile 21 // where most APIs are implemented with regular Go std-lib calls. 22 func newTCPListenerFile(tl *net.TCPListener) socketapi.TCPSock { 23 conn, err := tl.File() 24 if err != nil { 25 panic(err) 26 } 27 fd := conn.Fd() 28 // We need to duplicate this file handle, or the lifecycle will be tied 29 // to the TCPListener. We rely on the TCPListener only to set up 30 // the connection correctly and parse/resolve the TCP Address 31 // (notice we actually rely on the listener in the Windows implementation). 32 sysfd, err := syscall.Dup(int(fd)) 33 if err != nil { 34 panic(err) 35 } 36 return &tcpListenerFile{fd: uintptr(sysfd), addr: tl.Addr().(*net.TCPAddr)} 37 } 38 39 var _ socketapi.TCPSock = (*tcpListenerFile)(nil) 40 41 type tcpListenerFile struct { 42 baseSockFile 43 44 fd uintptr 45 addr *net.TCPAddr 46 } 47 48 // Accept implements the same method as documented on socketapi.TCPSock 49 func (f *tcpListenerFile) Accept() (socketapi.TCPConn, syscall.Errno) { 50 nfd, _, err := syscall.Accept(int(f.fd)) 51 errno := platform.UnwrapOSError(err) 52 if errno != 0 { 53 return nil, errno 54 } 55 return &tcpConnFile{fd: uintptr(nfd)}, 0 56 } 57 58 // SetNonblock implements the same method as documented on fsapi.File 59 func (f *tcpListenerFile) SetNonblock(enabled bool) syscall.Errno { 60 return platform.UnwrapOSError(setNonblock(f.fd, enabled)) 61 } 62 63 // Close implements the same method as documented on fsapi.File 64 func (f *tcpListenerFile) Close() syscall.Errno { 65 return platform.UnwrapOSError(syscall.Close(int(f.fd))) 66 } 67 68 // Addr is exposed for testing. 69 func (f *tcpListenerFile) Addr() *net.TCPAddr { 70 return f.addr 71 } 72 73 var _ socketapi.TCPConn = (*tcpConnFile)(nil) 74 75 type tcpConnFile struct { 76 baseSockFile 77 78 fd uintptr 79 80 // closed is true when closed was called. This ensures proper syscall.EBADF 81 closed bool 82 } 83 84 func newTcpConn(tc *net.TCPConn) socketapi.TCPConn { 85 f, err := tc.File() 86 if err != nil { 87 panic(err) 88 } 89 return &tcpConnFile{fd: f.Fd()} 90 } 91 92 // SetNonblock implements the same method as documented on fsapi.File 93 func (f *tcpConnFile) SetNonblock(enabled bool) (errno syscall.Errno) { 94 return platform.UnwrapOSError(setNonblock(f.fd, enabled)) 95 } 96 97 // Read implements the same method as documented on fsapi.File 98 func (f *tcpConnFile) Read(buf []byte) (n int, errno syscall.Errno) { 99 n, err := syscall.Read(int(f.fd), buf) 100 if err != nil { 101 // Defer validation overhead until we've already had an error. 102 errno = platform.UnwrapOSError(err) 103 errno = fileError(f, f.closed, errno) 104 } 105 return n, errno 106 } 107 108 // Write implements the same method as documented on fsapi.File 109 func (f *tcpConnFile) Write(buf []byte) (n int, errno syscall.Errno) { 110 n, err := syscall.Write(int(f.fd), buf) 111 if err != nil { 112 // Defer validation overhead until we've already had an error. 113 errno = platform.UnwrapOSError(err) 114 errno = fileError(f, f.closed, errno) 115 } 116 return n, errno 117 } 118 119 // Recvfrom implements the same method as documented on socketapi.TCPConn 120 func (f *tcpConnFile) Recvfrom(p []byte, flags int) (n int, errno syscall.Errno) { 121 if flags != MSG_PEEK { 122 errno = syscall.EINVAL 123 return 124 } 125 n, _, recvfromErr := syscall.Recvfrom(int(f.fd), p, MSG_PEEK) 126 errno = platform.UnwrapOSError(recvfromErr) 127 return n, errno 128 } 129 130 // Shutdown implements the same method as documented on fsapi.Conn 131 func (f *tcpConnFile) Shutdown(how int) syscall.Errno { 132 var err error 133 switch how { 134 case syscall.SHUT_RD, syscall.SHUT_WR: 135 err = syscall.Shutdown(int(f.fd), how) 136 case syscall.SHUT_RDWR: 137 return f.close() 138 default: 139 return syscall.EINVAL 140 } 141 return platform.UnwrapOSError(err) 142 } 143 144 // Close implements the same method as documented on fsapi.File 145 func (f *tcpConnFile) Close() syscall.Errno { 146 return f.close() 147 } 148 149 func (f *tcpConnFile) close() syscall.Errno { 150 if f.closed { 151 return 0 152 } 153 f.closed = true 154 return platform.UnwrapOSError(syscall.Shutdown(int(f.fd), syscall.SHUT_RDWR)) 155 }