summaryrefslogtreecommitdiffhomepage
path: root/test/packetimpact/testbench/dut.go
diff options
context:
space:
mode:
Diffstat (limited to 'test/packetimpact/testbench/dut.go')
-rw-r--r--test/packetimpact/testbench/dut.go832
1 files changed, 0 insertions, 832 deletions
diff --git a/test/packetimpact/testbench/dut.go b/test/packetimpact/testbench/dut.go
deleted file mode 100644
index 0cac0bf1b..000000000
--- a/test/packetimpact/testbench/dut.go
+++ /dev/null
@@ -1,832 +0,0 @@
-// Copyright 2020 The gVisor Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package testbench
-
-import (
- "context"
- "encoding/binary"
- "fmt"
- "net"
- "testing"
- "time"
-
- "golang.org/x/sys/unix"
- "google.golang.org/grpc"
- "google.golang.org/grpc/keepalive"
- "gvisor.dev/gvisor/pkg/abi/linux"
- bin "gvisor.dev/gvisor/pkg/binary"
- "gvisor.dev/gvisor/pkg/hostarch"
- pb "gvisor.dev/gvisor/test/packetimpact/proto/posix_server_go_proto"
-)
-
-// DUT communicates with the DUT to force it to make POSIX calls.
-type DUT struct {
- conn *grpc.ClientConn
- posixServer POSIXClient
- Net *DUTTestNet
- Uname *DUTUname
-}
-
-// NewDUT creates a new connection with the DUT over gRPC.
-func NewDUT(t *testing.T) DUT {
- t.Helper()
- info := getDUTInfo()
- dut := info.ConnectToDUT(t)
- t.Cleanup(func() {
- dut.TearDownConnection()
- info.release()
- })
- return dut
-}
-
-// ConnectToDUT connects to DUT through gRPC.
-func (info *DUTInfo) ConnectToDUT(t *testing.T) DUT {
- t.Helper()
-
- n := info.Net
- posixServerAddress := net.JoinHostPort(n.POSIXServerIP.String(), fmt.Sprintf("%d", n.POSIXServerPort))
- conn, err := grpc.Dial(posixServerAddress, grpc.WithInsecure(), grpc.WithKeepaliveParams(keepalive.ClientParameters{Timeout: RPCKeepalive}))
- if err != nil {
- t.Fatalf("failed to grpc.Dial(%s): %s", posixServerAddress, err)
- }
- posixServer := NewPOSIXClient(conn)
- return DUT{
- conn: conn,
- posixServer: posixServer,
- Net: n,
- Uname: info.Uname,
- }
-}
-
-// TearDownConnection closes the underlying connection.
-func (dut *DUT) TearDownConnection() {
- dut.conn.Close()
-}
-
-func (dut *DUT) sockaddrToProto(t *testing.T, sa unix.Sockaddr) *pb.Sockaddr {
- t.Helper()
-
- switch s := sa.(type) {
- case *unix.SockaddrInet4:
- return &pb.Sockaddr{
- Sockaddr: &pb.Sockaddr_In{
- In: &pb.SockaddrIn{
- Family: unix.AF_INET,
- Port: uint32(s.Port),
- Addr: s.Addr[:],
- },
- },
- }
- case *unix.SockaddrInet6:
- return &pb.Sockaddr{
- Sockaddr: &pb.Sockaddr_In6{
- In6: &pb.SockaddrIn6{
- Family: unix.AF_INET6,
- Port: uint32(s.Port),
- Flowinfo: 0,
- ScopeId: s.ZoneId,
- Addr: s.Addr[:],
- },
- },
- }
- }
- t.Fatalf("can't parse Sockaddr struct: %+v", sa)
- return nil
-}
-
-func (dut *DUT) protoToSockaddr(t *testing.T, sa *pb.Sockaddr) unix.Sockaddr {
- t.Helper()
-
- switch s := sa.Sockaddr.(type) {
- case *pb.Sockaddr_In:
- ret := unix.SockaddrInet4{
- Port: int(s.In.GetPort()),
- }
- copy(ret.Addr[:], s.In.GetAddr())
- return &ret
- case *pb.Sockaddr_In6:
- ret := unix.SockaddrInet6{
- Port: int(s.In6.GetPort()),
- ZoneId: s.In6.GetScopeId(),
- }
- copy(ret.Addr[:], s.In6.GetAddr())
- return &ret
- }
- t.Fatalf("can't parse Sockaddr proto: %#v", sa)
- return nil
-}
-
-// CreateBoundSocket makes a new socket on the DUT, with type typ and protocol
-// proto, and bound to the IP address addr. Returns the new file descriptor and
-// the port that was selected on the DUT.
-func (dut *DUT) CreateBoundSocket(t *testing.T, typ, proto int32, addr net.IP) (int32, uint16) {
- t.Helper()
-
- var fd int32
- if addr.To4() != nil {
- fd = dut.Socket(t, unix.AF_INET, typ, proto)
- sa := unix.SockaddrInet4{}
- copy(sa.Addr[:], addr.To4())
- dut.Bind(t, fd, &sa)
- } else if addr.To16() != nil {
- fd = dut.Socket(t, unix.AF_INET6, typ, proto)
- sa := unix.SockaddrInet6{}
- copy(sa.Addr[:], addr.To16())
- sa.ZoneId = dut.Net.RemoteDevID
- dut.Bind(t, fd, &sa)
- } else {
- t.Fatalf("invalid IP address: %s", addr)
- }
- sa := dut.GetSockName(t, fd)
- var port int
- switch s := sa.(type) {
- case *unix.SockaddrInet4:
- port = s.Port
- case *unix.SockaddrInet6:
- port = s.Port
- default:
- t.Fatalf("unknown sockaddr type from getsockname: %T", sa)
- }
- return fd, uint16(port)
-}
-
-// CreateListener makes a new TCP connection. If it fails, the test ends.
-func (dut *DUT) CreateListener(t *testing.T, typ, proto, backlog int32) (int32, uint16) {
- t.Helper()
-
- fd, remotePort := dut.CreateBoundSocket(t, typ, proto, dut.Net.RemoteIPv4)
- dut.Listen(t, fd, backlog)
- return fd, remotePort
-}
-
-// All the functions that make gRPC calls to the POSIX service are below, sorted
-// alphabetically.
-
-// Accept calls accept on the DUT and causes a fatal test failure if it doesn't
-// succeed. If more control over the timeout or error handling is needed, use
-// AcceptWithErrno.
-func (dut *DUT) Accept(t *testing.T, sockfd int32) (int32, unix.Sockaddr) {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- fd, sa, err := dut.AcceptWithErrno(ctx, t, sockfd)
- if fd < 0 {
- t.Fatalf("failed to accept: %s", err)
- }
- return fd, sa
-}
-
-// AcceptWithErrno calls accept on the DUT.
-func (dut *DUT) AcceptWithErrno(ctx context.Context, t *testing.T, sockfd int32) (int32, unix.Sockaddr, error) {
- t.Helper()
-
- req := &pb.AcceptRequest{
- Sockfd: sockfd,
- }
- resp, err := dut.posixServer.Accept(ctx, req)
- if err != nil {
- t.Fatalf("failed to call Accept: %s", err)
- }
- return resp.GetFd(), dut.protoToSockaddr(t, resp.GetAddr()), unix.Errno(resp.GetErrno_())
-}
-
-// Bind calls bind on the DUT and causes a fatal test failure if it doesn't
-// succeed. If more control over the timeout or error handling is
-// needed, use BindWithErrno.
-func (dut *DUT) Bind(t *testing.T, fd int32, sa unix.Sockaddr) {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, err := dut.BindWithErrno(ctx, t, fd, sa)
- if ret != 0 {
- t.Fatalf("failed to bind socket: %s", err)
- }
-}
-
-// BindWithErrno calls bind on the DUT.
-func (dut *DUT) BindWithErrno(ctx context.Context, t *testing.T, fd int32, sa unix.Sockaddr) (int32, error) {
- t.Helper()
-
- req := &pb.BindRequest{
- Sockfd: fd,
- Addr: dut.sockaddrToProto(t, sa),
- }
- resp, err := dut.posixServer.Bind(ctx, req)
- if err != nil {
- t.Fatalf("failed to call Bind: %s", err)
- }
- return resp.GetRet(), unix.Errno(resp.GetErrno_())
-}
-
-// Close calls close on the DUT and causes a fatal test failure if it doesn't
-// succeed. If more control over the timeout or error handling is needed, use
-// CloseWithErrno.
-func (dut *DUT) Close(t *testing.T, fd int32) {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, err := dut.CloseWithErrno(ctx, t, fd)
- if ret != 0 {
- t.Fatalf("failed to close: %s", err)
- }
-}
-
-// CloseWithErrno calls close on the DUT.
-func (dut *DUT) CloseWithErrno(ctx context.Context, t *testing.T, fd int32) (int32, error) {
- t.Helper()
-
- req := &pb.CloseRequest{
- Fd: fd,
- }
- resp, err := dut.posixServer.Close(ctx, req)
- if err != nil {
- t.Fatalf("failed to call Close: %s", err)
- }
- return resp.GetRet(), unix.Errno(resp.GetErrno_())
-}
-
-// Connect calls connect on the DUT and causes a fatal test failure if it
-// doesn't succeed. If more control over the timeout or error handling is
-// needed, use ConnectWithErrno.
-func (dut *DUT) Connect(t *testing.T, fd int32, sa unix.Sockaddr) {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, err := dut.ConnectWithErrno(ctx, t, fd, sa)
- // Ignore 'operation in progress' error that can be returned when the socket
- // is non-blocking.
- if err != unix.EINPROGRESS && ret != 0 {
- t.Fatalf("failed to connect socket: %s", err)
- }
-}
-
-// ConnectWithErrno calls bind on the DUT.
-func (dut *DUT) ConnectWithErrno(ctx context.Context, t *testing.T, fd int32, sa unix.Sockaddr) (int32, error) {
- t.Helper()
-
- req := &pb.ConnectRequest{
- Sockfd: fd,
- Addr: dut.sockaddrToProto(t, sa),
- }
- resp, err := dut.posixServer.Connect(ctx, req)
- if err != nil {
- t.Fatalf("failed to call Connect: %s", err)
- }
- return resp.GetRet(), unix.Errno(resp.GetErrno_())
-}
-
-// GetSockName calls getsockname on the DUT and causes a fatal test failure if
-// it doesn't succeed. If more control over the timeout or error handling is
-// needed, use GetSockNameWithErrno.
-func (dut *DUT) GetSockName(t *testing.T, sockfd int32) unix.Sockaddr {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, sa, err := dut.GetSockNameWithErrno(ctx, t, sockfd)
- if ret != 0 {
- t.Fatalf("failed to getsockname: %s", err)
- }
- return sa
-}
-
-// GetSockNameWithErrno calls getsockname on the DUT.
-func (dut *DUT) GetSockNameWithErrno(ctx context.Context, t *testing.T, sockfd int32) (int32, unix.Sockaddr, error) {
- t.Helper()
-
- req := &pb.GetSockNameRequest{
- Sockfd: sockfd,
- }
- resp, err := dut.posixServer.GetSockName(ctx, req)
- if err != nil {
- t.Fatalf("failed to call Bind: %s", err)
- }
- return resp.GetRet(), dut.protoToSockaddr(t, resp.GetAddr()), unix.Errno(resp.GetErrno_())
-}
-
-func (dut *DUT) getSockOpt(ctx context.Context, t *testing.T, sockfd, level, optname, optlen int32, typ pb.GetSockOptRequest_SockOptType) (int32, *pb.SockOptVal, error) {
- t.Helper()
-
- req := &pb.GetSockOptRequest{
- Sockfd: sockfd,
- Level: level,
- Optname: optname,
- Optlen: optlen,
- Type: typ,
- }
- resp, err := dut.posixServer.GetSockOpt(ctx, req)
- if err != nil {
- t.Fatalf("failed to call GetSockOpt: %s", err)
- }
- optval := resp.GetOptval()
- if optval == nil {
- t.Fatalf("GetSockOpt response does not contain a value")
- }
- return resp.GetRet(), optval, unix.Errno(resp.GetErrno_())
-}
-
-// GetSockOpt calls getsockopt on the DUT and causes a fatal test failure if it
-// doesn't succeed. If more control over the timeout or error handling is
-// needed, use GetSockOptWithErrno. Because endianess and the width of values
-// might differ between the testbench and DUT architectures, prefer to use a
-// more specific GetSockOptXxx function.
-func (dut *DUT) GetSockOpt(t *testing.T, sockfd, level, optname, optlen int32) []byte {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, optval, err := dut.GetSockOptWithErrno(ctx, t, sockfd, level, optname, optlen)
- if ret != 0 {
- t.Fatalf("failed to GetSockOpt: %s", err)
- }
- return optval
-}
-
-// GetSockOptWithErrno calls getsockopt on the DUT. Because endianess and the
-// width of values might differ between the testbench and DUT architectures,
-// prefer to use a more specific GetSockOptXxxWithErrno function.
-func (dut *DUT) GetSockOptWithErrno(ctx context.Context, t *testing.T, sockfd, level, optname, optlen int32) (int32, []byte, error) {
- t.Helper()
-
- ret, optval, errno := dut.getSockOpt(ctx, t, sockfd, level, optname, optlen, pb.GetSockOptRequest_BYTES)
- bytesval, ok := optval.Val.(*pb.SockOptVal_Bytesval)
- if !ok {
- t.Fatalf("GetSockOpt got value type: %T, want bytes", optval.Val)
- }
- return ret, bytesval.Bytesval, errno
-}
-
-// GetSockOptInt calls getsockopt on the DUT and causes a fatal test failure
-// if it doesn't succeed. If more control over the int optval or error handling
-// is needed, use GetSockOptIntWithErrno.
-func (dut *DUT) GetSockOptInt(t *testing.T, sockfd, level, optname int32) int32 {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, intval, err := dut.GetSockOptIntWithErrno(ctx, t, sockfd, level, optname)
- if ret != 0 {
- t.Fatalf("failed to GetSockOptInt: %s", err)
- }
- return intval
-}
-
-// GetSockOptIntWithErrno calls getsockopt with an integer optval.
-func (dut *DUT) GetSockOptIntWithErrno(ctx context.Context, t *testing.T, sockfd, level, optname int32) (int32, int32, error) {
- t.Helper()
-
- ret, optval, errno := dut.getSockOpt(ctx, t, sockfd, level, optname, 0, pb.GetSockOptRequest_INT)
- intval, ok := optval.Val.(*pb.SockOptVal_Intval)
- if !ok {
- t.Fatalf("GetSockOpt got value type: %T, want int", optval.Val)
- }
- return ret, intval.Intval, errno
-}
-
-// GetSockOptTimeval calls getsockopt on the DUT and causes a fatal test failure
-// if it doesn't succeed. If more control over the timeout or error handling is
-// needed, use GetSockOptTimevalWithErrno.
-func (dut *DUT) GetSockOptTimeval(t *testing.T, sockfd, level, optname int32) unix.Timeval {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, timeval, err := dut.GetSockOptTimevalWithErrno(ctx, t, sockfd, level, optname)
- if ret != 0 {
- t.Fatalf("failed to GetSockOptTimeval: %s", err)
- }
- return timeval
-}
-
-// GetSockOptTimevalWithErrno calls getsockopt and returns a timeval.
-func (dut *DUT) GetSockOptTimevalWithErrno(ctx context.Context, t *testing.T, sockfd, level, optname int32) (int32, unix.Timeval, error) {
- t.Helper()
-
- ret, optval, errno := dut.getSockOpt(ctx, t, sockfd, level, optname, 0, pb.GetSockOptRequest_TIME)
- tv, ok := optval.Val.(*pb.SockOptVal_Timeval)
- if !ok {
- t.Fatalf("GetSockOpt got value type: %T, want timeval", optval.Val)
- }
- timeval := unix.Timeval{
- Sec: tv.Timeval.Seconds,
- Usec: tv.Timeval.Microseconds,
- }
- return ret, timeval, errno
-}
-
-// GetSockOptTCPInfo retreives TCPInfo for the given socket descriptor.
-func (dut *DUT) GetSockOptTCPInfo(t *testing.T, sockfd int32) linux.TCPInfo {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, info, err := dut.GetSockOptTCPInfoWithErrno(ctx, t, sockfd)
- if ret != 0 || err != unix.Errno(0) {
- t.Fatalf("failed to GetSockOptTCPInfo: %s", err)
- }
- return info
-}
-
-// GetSockOptTCPInfoWithErrno retreives TCPInfo with any errno.
-func (dut *DUT) GetSockOptTCPInfoWithErrno(ctx context.Context, t *testing.T, sockfd int32) (int32, linux.TCPInfo, error) {
- t.Helper()
-
- info := linux.TCPInfo{}
- ret, infoBytes, errno := dut.GetSockOptWithErrno(ctx, t, sockfd, unix.SOL_TCP, unix.TCP_INFO, int32(linux.SizeOfTCPInfo))
- if got, want := len(infoBytes), linux.SizeOfTCPInfo; got != want {
- t.Fatalf("expected %T, got %d bytes want %d bytes", info, got, want)
- }
- bin.Unmarshal(infoBytes, hostarch.ByteOrder, &info)
-
- return ret, info, errno
-}
-
-// Listen calls listen on the DUT and causes a fatal test failure if it doesn't
-// succeed. If more control over the timeout or error handling is needed, use
-// ListenWithErrno.
-func (dut *DUT) Listen(t *testing.T, sockfd, backlog int32) {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, err := dut.ListenWithErrno(ctx, t, sockfd, backlog)
- if ret != 0 {
- t.Fatalf("failed to listen: %s", err)
- }
-}
-
-// ListenWithErrno calls listen on the DUT.
-func (dut *DUT) ListenWithErrno(ctx context.Context, t *testing.T, sockfd, backlog int32) (int32, error) {
- t.Helper()
-
- req := &pb.ListenRequest{
- Sockfd: sockfd,
- Backlog: backlog,
- }
- resp, err := dut.posixServer.Listen(ctx, req)
- if err != nil {
- t.Fatalf("failed to call Listen: %s", err)
- }
- return resp.GetRet(), unix.Errno(resp.GetErrno_())
-}
-
-// PollOne calls poll on the DUT and asserts that the expected event must be
-// signaled on the given fd within the given timeout.
-func (dut *DUT) PollOne(t *testing.T, fd int32, events int16, timeout time.Duration) {
- t.Helper()
-
- pfds := dut.Poll(t, []unix.PollFd{{Fd: fd, Events: events}}, timeout)
- if n := len(pfds); n != 1 {
- t.Fatalf("Poll returned %d ready file descriptors, expected 1", n)
- }
- if readyFd := pfds[0].Fd; readyFd != fd {
- t.Fatalf("Poll returned an fd %d that was not requested (%d)", readyFd, fd)
- }
- if got, want := pfds[0].Revents, int16(events); got&want != want {
- t.Fatalf("Poll returned events does not include all of the interested events, got: %#b, want: %#b", got, want)
- }
-}
-
-// Poll calls poll on the DUT and causes a fatal test failure if it doesn't
-// succeed. If more control over error handling is needed, use PollWithErrno.
-// Only pollfds with non-empty revents are returned, the only way to tie the
-// response back to the original request is using the fd number.
-func (dut *DUT) Poll(t *testing.T, pfds []unix.PollFd, timeout time.Duration) []unix.PollFd {
- t.Helper()
-
- ctx := context.Background()
- var cancel context.CancelFunc
- if timeout >= 0 {
- ctx, cancel = context.WithTimeout(ctx, timeout+RPCTimeout)
- defer cancel()
- }
- ret, result, err := dut.PollWithErrno(ctx, t, pfds, timeout)
- if ret < 0 {
- t.Fatalf("failed to poll: %s", err)
- }
- return result
-}
-
-// PollWithErrno calls poll on the DUT.
-func (dut *DUT) PollWithErrno(ctx context.Context, t *testing.T, pfds []unix.PollFd, timeout time.Duration) (int32, []unix.PollFd, error) {
- t.Helper()
-
- req := &pb.PollRequest{
- TimeoutMillis: int32(timeout.Milliseconds()),
- }
- for _, pfd := range pfds {
- req.Pfds = append(req.Pfds, &pb.PollFd{
- Fd: pfd.Fd,
- Events: uint32(pfd.Events),
- })
- }
- resp, err := dut.posixServer.Poll(ctx, req)
- if err != nil {
- t.Fatalf("failed to call Poll: %s", err)
- }
- if ret, npfds := resp.GetRet(), len(resp.GetPfds()); ret >= 0 && int(ret) != npfds {
- t.Fatalf("nonsensical poll response: ret(%d) != len(pfds)(%d)", ret, npfds)
- }
- var result []unix.PollFd
- for _, protoPfd := range resp.GetPfds() {
- result = append(result, unix.PollFd{
- Fd: protoPfd.GetFd(),
- Revents: int16(protoPfd.GetEvents()),
- })
- }
- return resp.GetRet(), result, unix.Errno(resp.GetErrno_())
-}
-
-// Send calls send on the DUT and causes a fatal test failure if it doesn't
-// succeed. If more control over the timeout or error handling is needed, use
-// SendWithErrno.
-func (dut *DUT) Send(t *testing.T, sockfd int32, buf []byte, flags int32) int32 {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, err := dut.SendWithErrno(ctx, t, sockfd, buf, flags)
- if ret == -1 {
- t.Fatalf("failed to send: %s", err)
- }
- return ret
-}
-
-// SendWithErrno calls send on the DUT.
-func (dut *DUT) SendWithErrno(ctx context.Context, t *testing.T, sockfd int32, buf []byte, flags int32) (int32, error) {
- t.Helper()
-
- req := &pb.SendRequest{
- Sockfd: sockfd,
- Buf: buf,
- Flags: flags,
- }
- resp, err := dut.posixServer.Send(ctx, req)
- if err != nil {
- t.Fatalf("failed to call Send: %s", err)
- }
- return resp.GetRet(), unix.Errno(resp.GetErrno_())
-}
-
-// SendTo calls sendto on the DUT and causes a fatal test failure if it doesn't
-// succeed. If more control over the timeout or error handling is needed, use
-// SendToWithErrno.
-func (dut *DUT) SendTo(t *testing.T, sockfd int32, buf []byte, flags int32, destAddr unix.Sockaddr) int32 {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, err := dut.SendToWithErrno(ctx, t, sockfd, buf, flags, destAddr)
- if ret == -1 {
- t.Fatalf("failed to sendto: %s", err)
- }
- return ret
-}
-
-// SendToWithErrno calls sendto on the DUT.
-func (dut *DUT) SendToWithErrno(ctx context.Context, t *testing.T, sockfd int32, buf []byte, flags int32, destAddr unix.Sockaddr) (int32, error) {
- t.Helper()
-
- req := &pb.SendToRequest{
- Sockfd: sockfd,
- Buf: buf,
- Flags: flags,
- DestAddr: dut.sockaddrToProto(t, destAddr),
- }
- resp, err := dut.posixServer.SendTo(ctx, req)
- if err != nil {
- t.Fatalf("failed to call SendTo: %s", err)
- }
- return resp.GetRet(), unix.Errno(resp.GetErrno_())
-}
-
-// SetNonBlocking will set O_NONBLOCK flag for fd if nonblocking
-// is true, otherwise it will clear the flag.
-func (dut *DUT) SetNonBlocking(t *testing.T, fd int32, nonblocking bool) {
- t.Helper()
-
- req := &pb.SetNonblockingRequest{
- Fd: fd,
- Nonblocking: nonblocking,
- }
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
-
- resp, err := dut.posixServer.SetNonblocking(ctx, req)
- if err != nil {
- t.Fatalf("failed to call SetNonblocking: %s", err)
- }
- if resp.GetRet() == -1 {
- t.Fatalf("fcntl(%d, %s) failed: %s", fd, resp.GetCmd(), unix.Errno(resp.GetErrno_()))
- }
-}
-
-func (dut *DUT) setSockOpt(ctx context.Context, t *testing.T, sockfd, level, optname int32, optval *pb.SockOptVal) (int32, error) {
- t.Helper()
-
- req := &pb.SetSockOptRequest{
- Sockfd: sockfd,
- Level: level,
- Optname: optname,
- Optval: optval,
- }
- resp, err := dut.posixServer.SetSockOpt(ctx, req)
- if err != nil {
- t.Fatalf("failed to call SetSockOpt: %s", err)
- }
- return resp.GetRet(), unix.Errno(resp.GetErrno_())
-}
-
-// SetSockOpt calls setsockopt on the DUT and causes a fatal test failure if it
-// doesn't succeed. If more control over the timeout or error handling is
-// needed, use SetSockOptWithErrno. Because endianess and the width of values
-// might differ between the testbench and DUT architectures, prefer to use a
-// more specific SetSockOptXxx function.
-func (dut *DUT) SetSockOpt(t *testing.T, sockfd, level, optname int32, optval []byte) {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, err := dut.SetSockOptWithErrno(ctx, t, sockfd, level, optname, optval)
- if ret != 0 {
- t.Fatalf("failed to SetSockOpt: %s", err)
- }
-}
-
-// SetSockOptWithErrno calls setsockopt on the DUT. Because endianess and the
-// width of values might differ between the testbench and DUT architectures,
-// prefer to use a more specific SetSockOptXxxWithErrno function.
-func (dut *DUT) SetSockOptWithErrno(ctx context.Context, t *testing.T, sockfd, level, optname int32, optval []byte) (int32, error) {
- t.Helper()
-
- return dut.setSockOpt(ctx, t, sockfd, level, optname, &pb.SockOptVal{Val: &pb.SockOptVal_Bytesval{optval}})
-}
-
-// SetSockOptInt calls setsockopt on the DUT and causes a fatal test failure
-// if it doesn't succeed. If more control over the int optval or error handling
-// is needed, use SetSockOptIntWithErrno.
-func (dut *DUT) SetSockOptInt(t *testing.T, sockfd, level, optname, optval int32) {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, err := dut.SetSockOptIntWithErrno(ctx, t, sockfd, level, optname, optval)
- if ret != 0 {
- t.Fatalf("failed to SetSockOptInt: %s", err)
- }
-}
-
-// SetSockOptIntWithErrno calls setsockopt with an integer optval.
-func (dut *DUT) SetSockOptIntWithErrno(ctx context.Context, t *testing.T, sockfd, level, optname, optval int32) (int32, error) {
- t.Helper()
-
- return dut.setSockOpt(ctx, t, sockfd, level, optname, &pb.SockOptVal{Val: &pb.SockOptVal_Intval{optval}})
-}
-
-// SetSockOptTimeval calls setsockopt on the DUT and causes a fatal test failure
-// if it doesn't succeed. If more control over the timeout or error handling is
-// needed, use SetSockOptTimevalWithErrno.
-func (dut *DUT) SetSockOptTimeval(t *testing.T, sockfd, level, optname int32, tv *unix.Timeval) {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, err := dut.SetSockOptTimevalWithErrno(ctx, t, sockfd, level, optname, tv)
- if ret != 0 {
- t.Fatalf("failed to SetSockOptTimeval: %s", err)
- }
-}
-
-// SetSockOptTimevalWithErrno calls setsockopt with the timeval converted to
-// bytes.
-func (dut *DUT) SetSockOptTimevalWithErrno(ctx context.Context, t *testing.T, sockfd, level, optname int32, tv *unix.Timeval) (int32, error) {
- t.Helper()
-
- timeval := pb.Timeval{
- Seconds: int64(tv.Sec),
- Microseconds: int64(tv.Usec),
- }
- return dut.setSockOpt(ctx, t, sockfd, level, optname, &pb.SockOptVal{Val: &pb.SockOptVal_Timeval{&timeval}})
-}
-
-// Socket calls socket on the DUT and returns the file descriptor. If socket
-// fails on the DUT, the test ends.
-func (dut *DUT) Socket(t *testing.T, domain, typ, proto int32) int32 {
- t.Helper()
-
- fd, err := dut.SocketWithErrno(t, domain, typ, proto)
- if fd < 0 {
- t.Fatalf("failed to create socket: %s", err)
- }
- return fd
-}
-
-// SocketWithErrno calls socket on the DUT and returns the fd and errno.
-func (dut *DUT) SocketWithErrno(t *testing.T, domain, typ, proto int32) (int32, error) {
- t.Helper()
-
- req := &pb.SocketRequest{
- Domain: domain,
- Type: typ,
- Protocol: proto,
- }
- ctx := context.Background()
- resp, err := dut.posixServer.Socket(ctx, req)
- if err != nil {
- t.Fatalf("failed to call Socket: %s", err)
- }
- return resp.GetFd(), unix.Errno(resp.GetErrno_())
-}
-
-// Recv calls recv on the DUT and causes a fatal test failure if it doesn't
-// succeed. If more control over the timeout or error handling is needed, use
-// RecvWithErrno.
-func (dut *DUT) Recv(t *testing.T, sockfd, len, flags int32) []byte {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, buf, err := dut.RecvWithErrno(ctx, t, sockfd, len, flags)
- if ret == -1 {
- t.Fatalf("failed to recv: %s", err)
- }
- return buf
-}
-
-// RecvWithErrno calls recv on the DUT.
-func (dut *DUT) RecvWithErrno(ctx context.Context, t *testing.T, sockfd, len, flags int32) (int32, []byte, error) {
- t.Helper()
-
- req := &pb.RecvRequest{
- Sockfd: sockfd,
- Len: len,
- Flags: flags,
- }
- resp, err := dut.posixServer.Recv(ctx, req)
- if err != nil {
- t.Fatalf("failed to call Recv: %s", err)
- }
- return resp.GetRet(), resp.GetBuf(), unix.Errno(resp.GetErrno_())
-}
-
-// SetSockLingerOption sets SO_LINGER socket option on the DUT.
-func (dut *DUT) SetSockLingerOption(t *testing.T, sockfd int32, timeout time.Duration, enable bool) {
- var linger unix.Linger
- if enable {
- linger.Onoff = 1
- }
- linger.Linger = int32(timeout / time.Second)
-
- buf := make([]byte, 8)
- binary.LittleEndian.PutUint32(buf, uint32(linger.Onoff))
- binary.LittleEndian.PutUint32(buf[4:], uint32(linger.Linger))
- dut.SetSockOpt(t, sockfd, unix.SOL_SOCKET, unix.SO_LINGER, buf)
-}
-
-// Shutdown calls shutdown on the DUT and causes a fatal test failure if it
-// doesn't succeed. If more control over the timeout or error handling is
-// needed, use ShutdownWithErrno.
-func (dut *DUT) Shutdown(t *testing.T, fd, how int32) {
- t.Helper()
-
- ctx, cancel := context.WithTimeout(context.Background(), RPCTimeout)
- defer cancel()
- ret, err := dut.ShutdownWithErrno(ctx, t, fd, how)
- if ret != 0 {
- t.Fatalf("failed to shutdown(%d, %d): %s", fd, how, err)
- }
-}
-
-// ShutdownWithErrno calls shutdown on the DUT.
-func (dut *DUT) ShutdownWithErrno(ctx context.Context, t *testing.T, fd, how int32) (int32, error) {
- t.Helper()
-
- req := &pb.ShutdownRequest{
- Fd: fd,
- How: how,
- }
- resp, err := dut.posixServer.Shutdown(ctx, req)
- if err != nil {
- t.Fatalf("failed to call Shutdown: %s", err)
- }
- if resp.GetErrno_() == 0 {
- return resp.GetRet(), nil
- }
- return resp.GetRet(), unix.Errno(resp.GetErrno_())
-}