Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

socket: long options #75

Merged
merged 5 commits into from
Jun 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 37 additions & 23 deletions imports/wasi_snapshot_preview1/wasmedge.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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),
Expand Down Expand Up @@ -131,40 +131,54 @@ 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 {
// See socket.go
switch wasi.SocketOptionLevel(level) {
case wasi.TcpLevel:
option += 0x1000
}
// 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.
func (m *Module) WasmEdgeSockSetOpt(ctx context.Context, fd Int32, level Int32, option Int32, value Bytes) Errno {
opt := wasi.MakeSocketOption(wasi.SocketOptionLevel(level), int32(option))

var val wasi.SocketOptionValue
switch opt {
case wasi.ReuseAddress,
wasi.DontRoute,
wasi.Broadcast,
wasi.SendBufferSize,
wasi.RecvBufferSize,
wasi.KeepAlive,
wasi.OOBInline,
wasi.TcpNoDelay:

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)
chriso marked this conversation as resolved.
Show resolved Hide resolved

default:
val = wasi.BytesValue(value)
}
if valueLen != 4 {
return Errno(wasi.EINVAL)
}
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), 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.MakeSocketOption(wasi.SocketOptionLevel(level), int32(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)
}
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)
}
Expand Down
33 changes: 27 additions & 6 deletions socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,17 +326,27 @@ func (sl SocketOptionLevel) String() string {
switch sl {
case SocketLevel:
return "SocketLevel"
case TcpLevel:
return "TcpLevel"
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)
}

func MakeSocketOption(level SocketOptionLevel, option int32) SocketOption {
return (SocketOption(level) << 32) | SocketOption(option)
}

// SOL_SOCKET level options.
const (
// SOL_SOCKET level options.
ReuseAddress SocketOption = iota
ReuseAddress SocketOption = (SocketOption(SocketLevel) << 32) | iota
QuerySocketType
QuerySocketError
DontRoute
Expand All @@ -351,9 +361,11 @@ const (
SendTimeout
QueryAcceptConnections
BindToDevice
)

// 0x1000 + iota are IPPROTO_TCP level options.
TcpNoDelay SocketOption = 0x1000 + iota
// IPPROTO_TCP level options
const (
TcpNoDelay SocketOption = (SocketOption(TcpLevel) << 32) | (15)
)

func (so SocketOption) String() string {
Expand Down Expand Up @@ -391,7 +403,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))
}
}

Expand Down Expand Up @@ -480,6 +492,15 @@ func (tv TimeValue) String() string {
return time.Duration(tv).String()
}

// BytesValue is used to represent an arbitrary socket option value.
type BytesValue []byte

func (BytesValue) sockopt() {}

func (s BytesValue) 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.
//
Expand Down
4 changes: 2 additions & 2 deletions system.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//
Expand Down
8 changes: 4 additions & 4 deletions systems/unix/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
12 changes: 6 additions & 6 deletions tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down
Loading