From 0e5db63659659a4aa848160affd777890c548882 Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Tue, 27 Jun 2023 10:45:53 -0400 Subject: [PATCH 1/5] socksetopt: accept arbitrary values Allows SockSetOpt to accept arbitrary values (that are not only int32). Also adds a new "reserved" socket option level. --- imports/wasi_snapshot_preview1/wasmedge.go | 41 +++++++++++++++------- socket.go | 20 +++++++++-- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/imports/wasi_snapshot_preview1/wasmedge.go b/imports/wasi_snapshot_preview1/wasmedge.go index c8d34ac..1ea09dd 100644 --- a/imports/wasi_snapshot_preview1/wasmedge.go +++ b/imports/wasi_snapshot_preview1/wasmedge.go @@ -23,7 +23,7 @@ var WasmEdgeV1 = Extension{ "sock_send_to": wazergo.F6((*Module).WasmEdgeSockSendTo), "sock_recv_from": wazergo.F6((*Module).WasmEdgeV1SockRecvFrom), "sock_getsockopt": wazergo.F5((*Module).WasmEdgeSockGetOpt), - "sock_setsockopt": wazergo.F5((*Module).WasmEdgeSockSetOpt), + "sock_setsockopt": wazergo.F4((*Module).WasmEdgeSockSetOpt), "sock_getlocaladdr": wazergo.F4((*Module).WasmEdgeV1SockLocalAddr), "sock_getpeeraddr": wazergo.F4((*Module).WasmEdgeV1SockPeerAddr), "sock_getaddrinfo": wazergo.F6((*Module).WasmEdgeSockAddrInfo), @@ -42,7 +42,7 @@ var WasmEdgeV2 = Extension{ "sock_send_to": wazergo.F6((*Module).WasmEdgeSockSendTo), "sock_recv_from": wazergo.F7((*Module).WasmEdgeV2SockRecvFrom), "sock_getsockopt": wazergo.F5((*Module).WasmEdgeSockGetOpt), - "sock_setsockopt": wazergo.F5((*Module).WasmEdgeSockSetOpt), + "sock_setsockopt": wazergo.F4((*Module).WasmEdgeSockSetOpt), "sock_getlocaladdr": wazergo.F3((*Module).WasmEdgeV2SockLocalAddr), "sock_getpeeraddr": wazergo.F3((*Module).WasmEdgeV2SockPeerAddr), "sock_getaddrinfo": wazergo.F6((*Module).WasmEdgeSockAddrInfo), @@ -131,22 +131,37 @@ func (m *Module) WasmEdgeV2SockRecvFrom(ctx context.Context, fd Int32, iovecs Li return Errno(wasi.ESUCCESS) } -func (m *Module) WasmEdgeSockSetOpt(ctx context.Context, fd Int32, level Int32, option Int32, value Pointer[Int32], valueLen Int32) Errno { +func (m *Module) WasmEdgeSockSetOpt(ctx context.Context, fd Int32, level Int32, option Int32, value Bytes) Errno { // See socket.go - switch wasi.SocketOptionLevel(level) { + wasilevel := wasi.SocketOptionLevel(level) + switch wasilevel { case wasi.TcpLevel: option += 0x1000 + case wasi.ReservedLevel: + option += 0x9000 } - // Only int options are supported for now. - switch wasi.SocketOption(option) { - case wasi.Linger, wasi.RecvTimeout, wasi.SendTimeout, wasi.BindToDevice: - // These accept struct linger / struct timeval / string. - return Errno(wasi.ENOTSUP) - } - if valueLen != 4 { - return Errno(wasi.EINVAL) + + var val wasi.SocketOptionValue + + // Reserved level take arbitrary values. + if wasilevel == wasi.ReservedLevel { + val = wasi.StringValue(value) + } else { + // Not supported for now. + switch wasi.SocketOption(option) { + case wasi.Linger, wasi.RecvTimeout, wasi.SendTimeout, wasi.BindToDevice: + // These accept struct linger / struct timeval / string. + return Errno(wasi.ENOTSUP) + } + + // Options default to integer values. + if len(value) != 4 { + return Errno(wasi.EINVAL) + } + val = wasi.IntValue(binary.LittleEndian.Uint32(value)) } - return Errno(m.WASI.SockSetOpt(ctx, wasi.FD(fd), wasi.SocketOptionLevel(level), wasi.SocketOption(option), wasi.IntValue(value.Load()))) + + return Errno(m.WASI.SockSetOpt(ctx, wasi.FD(fd), wasilevel, wasi.SocketOption(option), val)) } func (m *Module) WasmEdgeSockGetOpt(ctx context.Context, fd Int32, level Int32, option Int32, value Pointer[Int32], valueLen Int32) Errno { diff --git a/socket.go b/socket.go index df23900..65da7f9 100644 --- a/socket.go +++ b/socket.go @@ -318,14 +318,19 @@ func (st SocketType) String() string { type SocketOptionLevel int32 const ( - SocketLevel SocketOptionLevel = 0 // SOL_SOCKET - TcpLevel SocketOptionLevel = 6 // IPPROTO_TCP + SocketLevel SocketOptionLevel = 0 // SOL_SOCKET + TcpLevel SocketOptionLevel = 6 // IPPROTO_TCP + ReservedLevel SocketOptionLevel = 0x74696d65 ) func (sl SocketOptionLevel) String() string { switch sl { case SocketLevel: return "SocketLevel" + case TcpLevel: + return "TcpLevel" + case ReservedLevel: + return "ReservedLevel" default: return fmt.Sprintf("SocketOptionLevel(%d)", sl) } @@ -354,6 +359,8 @@ const ( // 0x1000 + iota are IPPROTO_TCP level options. TcpNoDelay SocketOption = 0x1000 + iota + + // >= 0x9000 are reserved. ) func (so SocketOption) String() string { @@ -480,6 +487,15 @@ func (tv TimeValue) String() string { return time.Duration(tv).String() } +// StringValue is used to represent an arbitrary socket option value. +type StringValue string + +func (StringValue) sockopt() {} + +func (s StringValue) String() string { + return string(s) +} + // SocketsNotSupported is a helper type intended to be embeded in // implementations of the Sytem interface that do not support sockets. // From 76e0ca6d1d3b9324ffe3ca3f47b72dc1ff381125 Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Tue, 27 Jun 2023 17:23:44 -0400 Subject: [PATCH 2/5] Remove SocketOptionLevel in wasi.System --- imports/wasi_snapshot_preview1/wasmedge.go | 55 +++++++++++----------- socket.go | 22 +++++---- system.go | 4 +- systems/unix/system.go | 8 ++-- tracer.go | 12 ++--- 5 files changed, 51 insertions(+), 50 deletions(-) diff --git a/imports/wasi_snapshot_preview1/wasmedge.go b/imports/wasi_snapshot_preview1/wasmedge.go index 1ea09dd..1c74071 100644 --- a/imports/wasi_snapshot_preview1/wasmedge.go +++ b/imports/wasi_snapshot_preview1/wasmedge.go @@ -132,46 +132,45 @@ func (m *Module) WasmEdgeV2SockRecvFrom(ctx context.Context, fd Int32, iovecs Li } func (m *Module) WasmEdgeSockSetOpt(ctx context.Context, fd Int32, level Int32, option Int32, value Bytes) Errno { - // See socket.go - wasilevel := wasi.SocketOptionLevel(level) - switch wasilevel { - case wasi.TcpLevel: - option += 0x1000 - case wasi.ReservedLevel: - option += 0x9000 - } + opt := wasi.SocketOption((int64(level) << 32) | int64(option)) var val wasi.SocketOptionValue + switch opt { + case wasi.ReuseAddress, + wasi.DontRoute, + wasi.Broadcast, + wasi.SendBufferSize, + wasi.RecvBufferSize, + wasi.KeepAlive, + wasi.OOBInline, + wasi.TcpNoDelay: - // Reserved level take arbitrary values. - if wasilevel == wasi.ReservedLevel { - val = wasi.StringValue(value) - } else { - // Not supported for now. - switch wasi.SocketOption(option) { - case wasi.Linger, wasi.RecvTimeout, wasi.SendTimeout, wasi.BindToDevice: - // These accept struct linger / struct timeval / string. - return Errno(wasi.ENOTSUP) - } - - // Options default to integer values. if len(value) != 4 { return Errno(wasi.EINVAL) } val = wasi.IntValue(binary.LittleEndian.Uint32(value)) + case wasi.Linger, + wasi.RecvTimeout, + wasi.SendTimeout, + wasi.BindToDevice: + return Errno(wasi.ENOTSUP) + case wasi.QuerySocketType, + wasi.QuerySocketError, + wasi.QueryAcceptConnections: + return Errno(wasi.ENOTSUP) + + default: + val = wasi.StringValue(value) } - return Errno(m.WASI.SockSetOpt(ctx, wasi.FD(fd), wasilevel, wasi.SocketOption(option), val)) + return Errno(m.WASI.SockSetOpt(ctx, wasi.FD(fd), opt, val)) } func (m *Module) WasmEdgeSockGetOpt(ctx context.Context, fd Int32, level Int32, option Int32, value Pointer[Int32], valueLen Int32) Errno { - // See socket.go - switch wasi.SocketOptionLevel(level) { - case wasi.TcpLevel: - option += 0x1000 - } + opt := wasi.SocketOption((int64(level) << 32) | int64(option)) + // Only int options are supported for now. - switch wasi.SocketOption(option) { + switch opt { case wasi.Linger, wasi.RecvTimeout, wasi.SendTimeout, wasi.BindToDevice: // These accept struct linger / struct timeval / string. return Errno(wasi.ENOTSUP) @@ -179,7 +178,7 @@ func (m *Module) WasmEdgeSockGetOpt(ctx context.Context, fd Int32, level Int32, if valueLen != 4 { return Errno(wasi.EINVAL) } - result, errno := m.WASI.SockGetOpt(ctx, wasi.FD(fd), wasi.SocketOptionLevel(level), wasi.SocketOption(option)) + result, errno := m.WASI.SockGetOpt(ctx, wasi.FD(fd), opt) if errno != wasi.ESUCCESS { return Errno(errno) } diff --git a/socket.go b/socket.go index 65da7f9..0640a19 100644 --- a/socket.go +++ b/socket.go @@ -329,19 +329,21 @@ func (sl SocketOptionLevel) String() string { return "SocketLevel" case TcpLevel: return "TcpLevel" - case ReservedLevel: - return "ReservedLevel" default: return fmt.Sprintf("SocketOptionLevel(%d)", sl) } } // SocketOption is a socket option that can be queried or set. -type SocketOption int32 +type SocketOption int64 +func (s SocketOption) Level() SocketOptionLevel { + return SocketOptionLevel(s >> 32) +} + +// SOL_SOCKET level options. const ( - // SOL_SOCKET level options. - ReuseAddress SocketOption = iota + ReuseAddress SocketOption = (SocketOption(SocketLevel) << 32) | iota QuerySocketType QuerySocketError DontRoute @@ -356,11 +358,11 @@ const ( SendTimeout QueryAcceptConnections BindToDevice +) - // 0x1000 + iota are IPPROTO_TCP level options. - TcpNoDelay SocketOption = 0x1000 + iota - - // >= 0x9000 are reserved. +// IPPROTO_TCP level options +const ( + TcpNoDelay SocketOption = (SocketOption(TcpLevel) << 32) | (15) ) func (so SocketOption) String() string { @@ -398,7 +400,7 @@ func (so SocketOption) String() string { case TcpNoDelay: return "TcpNoDelay" default: - return fmt.Sprintf("SocketOption(%d)", so) + return fmt.Sprintf("SocketOption(%d|%d)", so.Level(), int32(so)) } } diff --git a/system.go b/system.go index dcc1fe2..6106a39 100644 --- a/system.go +++ b/system.go @@ -363,12 +363,12 @@ type System interface { // SockGetOpt gets a socket option. // // Note: This is similar to getsockopt in POSIX. - SockGetOpt(ctx context.Context, fd FD, level SocketOptionLevel, option SocketOption) (SocketOptionValue, Errno) + SockGetOpt(ctx context.Context, fd FD, option SocketOption) (SocketOptionValue, Errno) // SockSetOpt sets a socket option. // // Note: This is similar to setsockopt in POSIX. - SockSetOpt(ctx context.Context, fd FD, level SocketOptionLevel, option SocketOption, value SocketOptionValue) Errno + SockSetOpt(ctx context.Context, fd FD, option SocketOption, value SocketOptionValue) Errno // SockLocalAddress gets the local address of the socket. // diff --git a/systems/unix/system.go b/systems/unix/system.go index 5911f6e..ef02435 100644 --- a/systems/unix/system.go +++ b/systems/unix/system.go @@ -669,14 +669,14 @@ func (s *System) SockRecvFrom(ctx context.Context, fd wasi.FD, iovecs []wasi.IOV } } -func (s *System) SockGetOpt(ctx context.Context, fd wasi.FD, level wasi.SocketOptionLevel, option wasi.SocketOption) (wasi.SocketOptionValue, wasi.Errno) { +func (s *System) SockGetOpt(ctx context.Context, fd wasi.FD, option wasi.SocketOption) (wasi.SocketOptionValue, wasi.Errno) { socket, _, errno := s.LookupSocketFD(fd, 0) if errno != wasi.ESUCCESS { return nil, errno } var sysLevel int - switch level { + switch option.Level() { case wasi.SocketLevel: sysLevel = unix.SOL_SOCKET case wasi.TcpLevel: @@ -769,14 +769,14 @@ func (s *System) SockGetOpt(ctx context.Context, fd wasi.FD, level wasi.SocketOp return wasi.IntValue(value), errno } -func (s *System) SockSetOpt(ctx context.Context, fd wasi.FD, level wasi.SocketOptionLevel, option wasi.SocketOption, value wasi.SocketOptionValue) wasi.Errno { +func (s *System) SockSetOpt(ctx context.Context, fd wasi.FD, option wasi.SocketOption, value wasi.SocketOptionValue) wasi.Errno { socket, _, errno := s.LookupSocketFD(fd, 0) if errno != wasi.ESUCCESS { return errno } var sysLevel int - switch level { + switch option.Level() { case wasi.SocketLevel: sysLevel = unix.SOL_SOCKET case wasi.TcpLevel: diff --git a/tracer.go b/tracer.go index 887b046..2389dac 100644 --- a/tracer.go +++ b/tracer.go @@ -680,9 +680,9 @@ func (t *tracer) SockRecvFrom(ctx context.Context, fd FD, iovecs []IOVec, iflags return n, oflags, addr, errno } -func (t *tracer) SockGetOpt(ctx context.Context, fd FD, level SocketOptionLevel, option SocketOption) (SocketOptionValue, Errno) { - t.printf("SockGetOpt(%d, %s, %s) => ", fd, level, option) - value, errno := t.system.SockGetOpt(ctx, fd, level, option) +func (t *tracer) SockGetOpt(ctx context.Context, fd FD, option SocketOption) (SocketOptionValue, Errno) { + t.printf("SockGetOpt(%d, %s) => ", fd, option) + value, errno := t.system.SockGetOpt(ctx, fd, option) if errno == ESUCCESS { t.printf("%d", value) } else { @@ -692,9 +692,9 @@ func (t *tracer) SockGetOpt(ctx context.Context, fd FD, level SocketOptionLevel, return value, errno } -func (t *tracer) SockSetOpt(ctx context.Context, fd FD, level SocketOptionLevel, option SocketOption, value SocketOptionValue) Errno { - t.printf("SockSetOpt(%d, %s, %s, %d) => ", fd, level, option, value) - errno := t.system.SockSetOpt(ctx, fd, level, option, value) +func (t *tracer) SockSetOpt(ctx context.Context, fd FD, option SocketOption, value SocketOptionValue) Errno { + t.printf("SockSetOpt(%d, %s, %s) => ", fd, option, value) + errno := t.system.SockSetOpt(ctx, fd, option, value) if errno == ESUCCESS { t.printf("ok") } else { From 9676628681efd10ba8d3afd80f1371f5e0b83417 Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Tue, 27 Jun 2023 17:38:47 -0400 Subject: [PATCH 3/5] Also fix tests --- wasitest/socket.go | 59 ++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/wasitest/socket.go b/wasitest/socket.go index 0a6f8bb..ffa1d7a 100644 --- a/wasitest/socket.go +++ b/wasitest/socket.go @@ -668,14 +668,14 @@ var socket = testSuite{ "cannot get socket options on a file descriptor which is not a socket": testNotSocket( func(ctx context.Context, sys wasi.System, fd wasi.FD) wasi.Errno { - _, errno := sys.SockGetOpt(ctx, fd, wasi.SocketLevel, wasi.QuerySocketType) + _, errno := sys.SockGetOpt(ctx, fd, wasi.QuerySocketType) return errno }, ), "cannot set socket options on a file descriptor which is not a socket": testNotSocket( func(ctx context.Context, sys wasi.System, fd wasi.FD) wasi.Errno { - return sys.SockSetOpt(ctx, fd, wasi.SocketLevel, wasi.SendBufferSize, wasi.IntValue(4096)) + return sys.SockSetOpt(ctx, fd, wasi.SendBufferSize, wasi.IntValue(4096)) }, ), } @@ -696,7 +696,7 @@ func testSocketType(family wasi.ProtocolFamily, typ wasi.SocketType, proto wasi. sock, errno := sockOpen(t, ctx, sys, family, wasi.AnySocket, proto) assertEqual(t, errno, wasi.ESUCCESS) - opt, errno := sys.SockGetOpt(ctx, sock, wasi.SocketLevel, wasi.QuerySocketType) + opt, errno := sys.SockGetOpt(ctx, sock, wasi.QuerySocketType) assertEqual(t, errno, wasi.ESUCCESS) val, ok := opt.(wasi.IntValue) @@ -1540,24 +1540,18 @@ func testSocketTimeoutStreamBlocking(family wasi.ProtocolFamily, bind wasi.Socke const sendTimeout = 40 * time.Millisecond errno = sys.SockSetOpt(ctx, conn1, - wasi.SocketLevel, wasi.RecvTimeout, wasi.TimeValue(recvTimeout)) assertEqual(t, errno, wasi.ESUCCESS) errno = sys.SockSetOpt(ctx, conn1, - wasi.SocketLevel, wasi.SendTimeout, wasi.TimeValue(sendTimeout), ) assertEqual(t, errno, wasi.ESUCCESS) - sockRecvTimeout := sockOption[wasi.TimeValue](t, ctx, sys, conn1, - wasi.SocketLevel, - wasi.RecvTimeout) + sockRecvTimeout := sockOption[wasi.TimeValue](t, ctx, sys, conn1, wasi.RecvTimeout) assertEqual(t, sockRecvTimeout, wasi.TimeValue(recvTimeout)) - sockSendTimeout := sockOption[wasi.TimeValue](t, ctx, sys, conn1, - wasi.SocketLevel, - wasi.SendTimeout) + sockSendTimeout := sockOption[wasi.TimeValue](t, ctx, sys, conn1, wasi.SendTimeout) assertEqual(t, sockSendTimeout, wasi.TimeValue(sendTimeout)) buffer := make([]byte, 10) @@ -1589,24 +1583,18 @@ func testSocketTimeoutDatagramBlocking(family wasi.ProtocolFamily, bind wasi.Soc const sendTimeout = 40 * time.Millisecond errno = sys.SockSetOpt(ctx, sock, - wasi.SocketLevel, wasi.RecvTimeout, wasi.TimeValue(recvTimeout)) assertEqual(t, errno, wasi.ESUCCESS) errno = sys.SockSetOpt(ctx, sock, - wasi.SocketLevel, wasi.SendTimeout, wasi.TimeValue(sendTimeout), ) assertEqual(t, errno, wasi.ESUCCESS) - sockRecvTimeout := sockOption[wasi.TimeValue](t, ctx, sys, sock, - wasi.SocketLevel, - wasi.RecvTimeout) + sockRecvTimeout := sockOption[wasi.TimeValue](t, ctx, sys, sock, wasi.RecvTimeout) assertEqual(t, sockRecvTimeout, wasi.TimeValue(recvTimeout)) - sockSendTimeout := sockOption[wasi.TimeValue](t, ctx, sys, sock, - wasi.SocketLevel, - wasi.SendTimeout) + sockSendTimeout := sockOption[wasi.TimeValue](t, ctx, sys, sock, wasi.SendTimeout) assertEqual(t, sockSendTimeout, wasi.TimeValue(sendTimeout)) buffer := make([]byte, 10) @@ -2025,10 +2013,10 @@ func testSocketSendAndReceiveLargerThanRecvBufferSize(family wasi.ProtocolFamily connAddr, errno := sys.SockBind(ctx, conn, addr2) assertEqual(t, errno, wasi.ESUCCESS) - errno = sys.SockSetOpt(ctx, sock, wasi.SocketLevel, wasi.RecvBufferSize, wasi.IntValue(4096)) + errno = sys.SockSetOpt(ctx, sock, wasi.RecvBufferSize, wasi.IntValue(4096)) assertEqual(t, errno, wasi.ESUCCESS) - recvBufferSize := sockOption[wasi.IntValue](t, ctx, sys, sock, wasi.SocketLevel, wasi.RecvBufferSize) + recvBufferSize := sockOption[wasi.IntValue](t, ctx, sys, sock, wasi.RecvBufferSize) buffer1 := bytes.Repeat([]byte{'@'}, int(recvBufferSize+1)) buffer2 := make([]byte, len(buffer1)) @@ -2076,7 +2064,7 @@ func testSocketSendAndReceiveLargerThanSendBufferSize(family wasi.ProtocolFamily conn, errno := sockOpen(t, ctx, sys, family, typ, 0) assertEqual(t, errno, wasi.ESUCCESS) - sendBufferSize := sockOption[wasi.IntValue](t, ctx, sys, conn, wasi.SocketLevel, wasi.RecvBufferSize) + sendBufferSize := sockOption[wasi.IntValue](t, ctx, sys, conn, wasi.RecvBufferSize) buffer1 := bytes.Repeat([]byte{'@'}, int(sendBufferSize+1)) size1, errno := sys.SockSendTo(ctx, conn, []wasi.IOVec{buffer1}, 0, sockAddr) @@ -2105,7 +2093,7 @@ func testSocketDefaultBufferSizes(family wasi.ProtocolFamily, typ wasi.SocketTyp for _, test := range tests { t.Run(test.scenario, func(t *testing.T) { - bufferSize := sockOption[wasi.IntValue](t, ctx, sys, sock, wasi.SocketLevel, test.option) + bufferSize := sockOption[wasi.IntValue](t, ctx, sys, sock, test.option) assertNotEqual(t, bufferSize, 0) }) } @@ -2131,17 +2119,17 @@ func testSocketSetBufferSizes(family wasi.ProtocolFamily, typ wasi.SocketType) t sock, errno := sockOpen(t, ctx, sys, family, typ, 0) assertEqual(t, errno, wasi.ESUCCESS) - defaultBufferSize := sockOption[wasi.IntValue](t, ctx, sys, sock, wasi.SocketLevel, test.option) + defaultBufferSize := sockOption[wasi.IntValue](t, ctx, sys, sock, test.option) assertNotEqual(t, defaultBufferSize, 0) setBufferSize := func(size wasi.IntValue) { t.Helper() - assertEqual(t, sys.SockSetOpt(ctx, sock, wasi.SocketLevel, test.option, size), wasi.ESUCCESS) + assertEqual(t, sys.SockSetOpt(ctx, sock, test.option, size), wasi.ESUCCESS) } getBufferSize := func() wasi.IntValue { t.Helper() - return sockOption[wasi.IntValue](t, ctx, sys, sock, wasi.SocketLevel, test.option) + return sockOption[wasi.IntValue](t, ctx, sys, sock, test.option) } t.Run("grow the socket buffer size", func(t *testing.T) { @@ -2160,19 +2148,19 @@ func testSocketSetBufferSizes(family wasi.ProtocolFamily, typ wasi.SocketType) t t.Run("negative socket buffer size are fobidden", func(t *testing.T) { want := getBufferSize() - assertEqual(t, sys.SockSetOpt(ctx, sock, wasi.SocketLevel, test.option, wasi.IntValue(-1)), wasi.EINVAL) + assertEqual(t, sys.SockSetOpt(ctx, sock, test.option, wasi.IntValue(-1)), wasi.EINVAL) size := getBufferSize() assertEqual(t, size, want) }) t.Run("small socket buffer sizes are capped to a minimum value", func(t *testing.T) { - assertEqual(t, sys.SockSetOpt(ctx, sock, wasi.SocketLevel, test.option, wasi.IntValue(0)), wasi.ESUCCESS) + assertEqual(t, sys.SockSetOpt(ctx, sock, test.option, wasi.IntValue(0)), wasi.ESUCCESS) size := getBufferSize() assertNotEqual(t, size, 0) }) t.Run("large socket buffer sizes are capped to a maximum value", func(t *testing.T) { - assertEqual(t, sys.SockSetOpt(ctx, sock, wasi.SocketLevel, test.option, wasi.IntValue(math.MaxInt32)), wasi.ESUCCESS) + assertEqual(t, sys.SockSetOpt(ctx, sock, test.option, wasi.IntValue(math.MaxInt32)), wasi.ESUCCESS) size := getBufferSize() assertNotEqual(t, size, math.MaxInt32) }) @@ -2188,9 +2176,8 @@ func testSocketSetOptionInvalidLevel(family wasi.ProtocolFamily, typ wasi.Socket sys := newSystem(TestConfig{}) sock, errno := sockOpen(t, ctx, sys, family, typ, 0) assertEqual(t, errno, wasi.ESUCCESS) - const level = -1 - const option = 0 - assertEqual(t, sys.SockSetOpt(ctx, sock, level, option, wasi.IntValue(0)), wasi.EINVAL) + const option = (-1) << 32 + assertEqual(t, sys.SockSetOpt(ctx, sock, option, wasi.IntValue(0)), wasi.EINVAL) assertEqual(t, sys.FDClose(ctx, sock), wasi.ESUCCESS) } } @@ -2201,7 +2188,7 @@ func testSocketSetOptionInvalidArgument(family wasi.ProtocolFamily, typ wasi.Soc sock, errno := sockOpen(t, ctx, sys, family, typ, 0) assertEqual(t, errno, wasi.ESUCCESS) const option = -1 - assertEqual(t, sys.SockSetOpt(ctx, sock, wasi.SocketLevel, option, wasi.IntValue(0)), wasi.EINVAL) + assertEqual(t, sys.SockSetOpt(ctx, sock, option, wasi.IntValue(0)), wasi.EINVAL) assertEqual(t, sys.FDClose(ctx, sock), wasi.ESUCCESS) } } @@ -2226,9 +2213,9 @@ func setNonBlock(t *testing.T, ctx context.Context, sys wasi.System, sock wasi.F assertEqual(t, sockErrno(t, ctx, sys, sock), wasi.ESUCCESS) } -func sockOption[T wasi.SocketOptionValue](t *testing.T, ctx context.Context, sys wasi.System, sock wasi.FD, level wasi.SocketOptionLevel, option wasi.SocketOption) T { +func sockOption[T wasi.SocketOptionValue](t *testing.T, ctx context.Context, sys wasi.System, sock wasi.FD, option wasi.SocketOption) T { t.Helper() - opt, errno := sys.SockGetOpt(ctx, sock, level, option) + opt, errno := sys.SockGetOpt(ctx, sock, option) assertEqual(t, errno, wasi.ESUCCESS) val, ok := opt.(T) assertEqual(t, ok, true) @@ -2237,7 +2224,7 @@ func sockOption[T wasi.SocketOptionValue](t *testing.T, ctx context.Context, sys func sockErrno(t *testing.T, ctx context.Context, sys wasi.System, sock wasi.FD) wasi.Errno { t.Helper() - return wasi.Errno(sockOption[wasi.IntValue](t, ctx, sys, sock, wasi.SocketLevel, wasi.QuerySocketError)) + return wasi.Errno(sockOption[wasi.IntValue](t, ctx, sys, sock, wasi.QuerySocketError)) } func sockIsNonBlocking(t *testing.T, ctx context.Context, sys wasi.System, sock wasi.FD) bool { From 40b9f589de4cd63f28d5606c1e5e63a04c91eea5 Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Tue, 27 Jun 2023 18:34:12 -0400 Subject: [PATCH 4/5] Remove reserved level --- socket.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/socket.go b/socket.go index 0640a19..6f59f7f 100644 --- a/socket.go +++ b/socket.go @@ -318,9 +318,8 @@ func (st SocketType) String() string { type SocketOptionLevel int32 const ( - SocketLevel SocketOptionLevel = 0 // SOL_SOCKET - TcpLevel SocketOptionLevel = 6 // IPPROTO_TCP - ReservedLevel SocketOptionLevel = 0x74696d65 + SocketLevel SocketOptionLevel = 0 // SOL_SOCKET + TcpLevel SocketOptionLevel = 6 // IPPROTO_TCP ) func (sl SocketOptionLevel) String() string { From 2d093d310f7ba02a71dc99d6c19546cb1ab24fb6 Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Tue, 27 Jun 2023 18:53:53 -0400 Subject: [PATCH 5/5] Review feedback --- imports/wasi_snapshot_preview1/wasmedge.go | 6 +++--- socket.go | 12 ++++++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/imports/wasi_snapshot_preview1/wasmedge.go b/imports/wasi_snapshot_preview1/wasmedge.go index 1c74071..e311059 100644 --- a/imports/wasi_snapshot_preview1/wasmedge.go +++ b/imports/wasi_snapshot_preview1/wasmedge.go @@ -132,7 +132,7 @@ func (m *Module) WasmEdgeV2SockRecvFrom(ctx context.Context, fd Int32, iovecs Li } func (m *Module) WasmEdgeSockSetOpt(ctx context.Context, fd Int32, level Int32, option Int32, value Bytes) Errno { - opt := wasi.SocketOption((int64(level) << 32) | int64(option)) + opt := wasi.MakeSocketOption(wasi.SocketOptionLevel(level), int32(option)) var val wasi.SocketOptionValue switch opt { @@ -160,14 +160,14 @@ func (m *Module) WasmEdgeSockSetOpt(ctx context.Context, fd Int32, level Int32, return Errno(wasi.ENOTSUP) default: - val = wasi.StringValue(value) + val = wasi.BytesValue(value) } return Errno(m.WASI.SockSetOpt(ctx, wasi.FD(fd), opt, val)) } func (m *Module) WasmEdgeSockGetOpt(ctx context.Context, fd Int32, level Int32, option Int32, value Pointer[Int32], valueLen Int32) Errno { - opt := wasi.SocketOption((int64(level) << 32) | int64(option)) + opt := wasi.MakeSocketOption(wasi.SocketOptionLevel(level), int32(option)) // Only int options are supported for now. switch opt { diff --git a/socket.go b/socket.go index 6f59f7f..49e907d 100644 --- a/socket.go +++ b/socket.go @@ -340,6 +340,10 @@ func (s SocketOption) Level() SocketOptionLevel { return SocketOptionLevel(s >> 32) } +func MakeSocketOption(level SocketOptionLevel, option int32) SocketOption { + return (SocketOption(level) << 32) | SocketOption(option) +} + // SOL_SOCKET level options. const ( ReuseAddress SocketOption = (SocketOption(SocketLevel) << 32) | iota @@ -488,12 +492,12 @@ func (tv TimeValue) String() string { return time.Duration(tv).String() } -// StringValue is used to represent an arbitrary socket option value. -type StringValue string +// BytesValue is used to represent an arbitrary socket option value. +type BytesValue []byte -func (StringValue) sockopt() {} +func (BytesValue) sockopt() {} -func (s StringValue) String() string { +func (s BytesValue) String() string { return string(s) }