github.com/bananabytelabs/wazero@v0.0.0-20240105073314-54b22a776da8/imports/wasi_snapshot_preview1/sock.go (about) 1 package wasi_snapshot_preview1 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/bananabytelabs/wazero/api" 8 "github.com/bananabytelabs/wazero/experimental/sys" 9 socketapi "github.com/bananabytelabs/wazero/internal/sock" 10 "github.com/bananabytelabs/wazero/internal/sysfs" 11 "github.com/bananabytelabs/wazero/internal/wasip1" 12 "github.com/bananabytelabs/wazero/internal/wasm" 13 ) 14 15 var sockSendTo = newHostFunc("sock_send_to", sockSendToFn, []wasm.ValueType{i32, i32, i32, i32, i32, i32, i32}, "foo", "bar", "baz", "a", "b", "v") 16 17 func sockSendToFn(_ context.Context, mod api.Module, params []uint64) (errno sys.Errno) { 18 fmt.Println("sock send to") 19 return 20 } 21 22 var sockRecvFrom = newHostFunc("sock_recv_from", sockRecvFromFn, []wasm.ValueType{i32, i32, i32, i32, i32, i32, i32, i32}, "foo", "bar", "baz", "a", "b", "v", "d") 23 24 func sockRecvFromFn(_ context.Context, mod api.Module, params []uint64) (errno sys.Errno) { 25 fmt.Println("sock recv from") 26 return 27 } 28 29 var sockGetPeerAddr = newHostFunc("sock_getpeeraddr", sockGetPeerAddrFn, []wasm.ValueType{i32, i32, i32}, "foo", "bar", "baz") 30 31 func sockGetPeerAddrFn(_ context.Context, mod api.Module, params []uint64) (errno sys.Errno) { 32 fmt.Println("sock get peer addr") 33 return 34 } 35 36 var sockGetLocalAddr = newHostFunc("sock_getlocaladdr", sockGetLocalAddrFn, []wasm.ValueType{i32, i32, i32}, "foo", "bar", "baz") 37 38 func sockGetLocalAddrFn(_ context.Context, mod api.Module, params []uint64) (errno sys.Errno) { 39 fmt.Println("sock get local addr") 40 return 41 } 42 43 var sockSetSockOpt = newHostFunc("sock_setsockopt", sockSetSockOptFn, []wasm.ValueType{i32, i32, i32, i32, i32}, "foo", "bar", "baz", "a", "b") 44 45 func sockSetSockOptFn(_ context.Context, mod api.Module, params []uint64) (errno sys.Errno) { 46 fmt.Println("sock set opt") 47 return 48 } 49 50 var sockGetSockOpt = newHostFunc("sock_getsockopt", sockGetSockOptFn, []wasm.ValueType{i32, i32, i32, i32, i32}, "foo", "bar", "baz", "a", "b") 51 52 func sockGetSockOptFn(_ context.Context, mod api.Module, params []uint64) (errno sys.Errno) { 53 fmt.Println("sock get opt") 54 return 55 } 56 57 var sockConnect = newHostFunc("sock_connect", sockConnectFn, []wasm.ValueType{i32, i32, i32}, "foo", "bar", "baz") 58 59 func sockConnectFn(_ context.Context, mod api.Module, params []uint64) (errno sys.Errno) { 60 fmt.Println("sock connect opt") 61 return 62 } 63 64 var sockOpen = newHostFunc("sock_open", sockOpenFn, []wasm.ValueType{i32, i32, i32}, "foo", "bar", "baz") 65 66 func sockOpenFn(_ context.Context, mod api.Module, params []uint64) (errno sys.Errno) { 67 fmt.Println("sock open") 68 return 69 } 70 71 // sockAccept is the WASI function named SockAcceptName which accepts a new 72 // incoming connection. 73 // 74 // See: https://github.com/WebAssembly/WASI/blob/0ba0c5e2e37625ca5a6d3e4255a998dfaa3efc52/phases/snapshot/docs.md#sock_accept 75 // and https://github.com/WebAssembly/WASI/pull/458 76 var sockAccept = newHostFunc( 77 wasip1.SockAcceptName, 78 sockAcceptFn, 79 []wasm.ValueType{i32, i32, i32}, 80 "fd", "flags", "result.fd", 81 ) 82 83 func sockAcceptFn(_ context.Context, mod api.Module, params []uint64) (errno sys.Errno) { 84 mem := mod.Memory() 85 fsc := mod.(*wasm.ModuleInstance).Sys.FS() 86 87 fd := int32(params[0]) 88 flags := uint32(params[1]) 89 resultFd := uint32(params[2]) 90 nonblock := flags&uint32(wasip1.FD_NONBLOCK) != 0 91 92 var connFD int32 93 if connFD, errno = fsc.SockAccept(fd, nonblock); errno == 0 { 94 mem.WriteUint32Le(resultFd, uint32(connFD)) 95 } 96 return 97 } 98 99 // sockRecv is the WASI function named SockRecvName which receives a 100 // message from a socket. 101 // 102 // See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_recvfd-fd-ri_data-iovec_array-ri_flags-riflags---errno-size-roflags 103 var sockRecv = newHostFunc( 104 wasip1.SockRecvName, 105 sockRecvFn, 106 []wasm.ValueType{i32, i32, i32, i32, i32, i32}, 107 "fd", "ri_data", "ri_data_len", "ri_flags", "result.ro_datalen", "result.ro_flags", 108 ) 109 110 func sockRecvFn(_ context.Context, mod api.Module, params []uint64) sys.Errno { 111 mem := mod.Memory() 112 fsc := mod.(*wasm.ModuleInstance).Sys.FS() 113 114 fd := int32(params[0]) 115 riData := uint32(params[1]) 116 riDataCount := uint32(params[2]) 117 riFlags := uint8(params[3]) 118 resultRoDatalen := uint32(params[4]) 119 resultRoFlags := uint32(params[5]) 120 121 var conn socketapi.TCPConn 122 if e, ok := fsc.LookupFile(fd); !ok { 123 return sys.EBADF // Not open 124 } else if conn, ok = e.File.(socketapi.TCPConn); !ok { 125 return sys.EBADF // Not a conn 126 } 127 128 if riFlags & ^(wasip1.RI_RECV_PEEK|wasip1.RI_RECV_WAITALL) != 0 { 129 return sys.ENOTSUP 130 } 131 132 if riFlags&wasip1.RI_RECV_PEEK != 0 { 133 // Each record in riData is of the form: 134 // type iovec struct { buf *uint8; bufLen uint32 } 135 // This means that the first `uint32` is a `buf *uint8`. 136 firstIovecBufAddr, ok := mem.ReadUint32Le(riData) 137 if !ok { 138 return sys.EINVAL 139 } 140 // Read bufLen 141 firstIovecBufLen, ok := mem.ReadUint32Le(riData + 4) 142 if !ok { 143 return sys.EINVAL 144 } 145 firstIovecBuf, ok := mem.Read(firstIovecBufAddr, firstIovecBufLen) 146 if !ok { 147 return sys.EINVAL 148 } 149 n, err := conn.Recvfrom(firstIovecBuf, sysfs.MSG_PEEK) 150 if err != 0 { 151 return err 152 } 153 mem.WriteUint32Le(resultRoDatalen, uint32(n)) 154 mem.WriteUint16Le(resultRoFlags, 0) 155 return 0 156 } 157 158 // If riFlags&wasip1.RECV_WAITALL != 0 then we should 159 // do a blocking operation until all data has been retrieved; 160 // otherwise we are able to return earlier. 161 // For simplicity, we currently wait all regardless the flag. 162 bufSize, errno := readv(mem, riData, riDataCount, conn.Read) 163 if errno != 0 { 164 return errno 165 } 166 mem.WriteUint32Le(resultRoDatalen, bufSize) 167 mem.WriteUint16Le(resultRoFlags, 0) 168 return 0 169 } 170 171 // sockSend is the WASI function named SockSendName which sends a message 172 // on a socket. 173 // 174 // See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_sendfd-fd-si_data-ciovec_array-si_flags-siflags---errno-size 175 var sockSend = newHostFunc( 176 wasip1.SockSendName, 177 sockSendFn, 178 []wasm.ValueType{i32, i32, i32, i32, i32}, 179 "fd", "si_data", "si_data_len", "si_flags", "result.so_datalen", 180 ) 181 182 func sockSendFn(_ context.Context, mod api.Module, params []uint64) sys.Errno { 183 mem := mod.Memory() 184 fsc := mod.(*wasm.ModuleInstance).Sys.FS() 185 186 fd := int32(params[0]) 187 siData := uint32(params[1]) 188 siDataCount := uint32(params[2]) 189 siFlags := uint32(params[3]) 190 resultSoDatalen := uint32(params[4]) 191 192 if siFlags != 0 { 193 return sys.ENOTSUP 194 } 195 196 var conn socketapi.TCPConn 197 if e, ok := fsc.LookupFile(fd); !ok { 198 return sys.EBADF // Not open 199 } else if conn, ok = e.File.(socketapi.TCPConn); !ok { 200 return sys.EBADF // Not a conn 201 } 202 203 bufSize, errno := writev(mem, siData, siDataCount, conn.Write) 204 if errno != 0 { 205 return errno 206 } 207 mem.WriteUint32Le(resultSoDatalen, bufSize) 208 return 0 209 } 210 211 // sockShutdown is the WASI function named SockShutdownName which shuts 212 // down socket send and receive channels. 213 // 214 // See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_shutdownfd-fd-how-sdflags---errno 215 var sockShutdown = newHostFunc(wasip1.SockShutdownName, sockShutdownFn, []wasm.ValueType{i32, i32}, "fd", "how") 216 217 func sockShutdownFn(_ context.Context, mod api.Module, params []uint64) sys.Errno { 218 fsc := mod.(*wasm.ModuleInstance).Sys.FS() 219 220 fd := int32(params[0]) 221 how := uint8(params[1]) 222 223 var conn socketapi.TCPConn 224 if e, ok := fsc.LookupFile(fd); !ok { 225 return sys.EBADF // Not open 226 } else if conn, ok = e.File.(socketapi.TCPConn); !ok { 227 return sys.EBADF // Not a conn 228 } 229 230 sysHow := 0 231 232 switch how { 233 case wasip1.SD_RD | wasip1.SD_WR: 234 sysHow = socketapi.SHUT_RD | socketapi.SHUT_WR 235 case wasip1.SD_RD: 236 sysHow = socketapi.SHUT_RD 237 case wasip1.SD_WR: 238 sysHow = socketapi.SHUT_WR 239 default: 240 return sys.EINVAL 241 } 242 243 // TODO: Map this instead of relying on syscall symbols. 244 return conn.Shutdown(sysHow) 245 }