diff --git a/test/packetimpact/dut/posix_server.cc b/test/packetimpact/dut/posix_server.cc index 2ebd3b95b..dc3024f44 100644 --- a/test/packetimpact/dut/posix_server.cc +++ b/test/packetimpact/dut/posix_server.cc @@ -174,41 +174,41 @@ class PosixImpl final : public posix_server::Posix::Service { grpc_impl::ServerContext *context, const ::posix_server::GetSockOptRequest *request, ::posix_server::GetSockOptResponse *response) override { - socklen_t optlen = request->optlen(); - std::vector buf(optlen); - response->set_ret(::getsockopt(request->sockfd(), request->level(), - request->optname(), buf.data(), &optlen)); - response->set_errno_(errno); - if (optlen >= 0) { - response->set_optval(buf.data(), optlen); + switch (request->type()) { + case ::posix_server::GetSockOptRequest::BYTES: { + socklen_t optlen = request->optlen(); + std::vector buf(optlen); + response->set_ret(::getsockopt(request->sockfd(), request->level(), + request->optname(), buf.data(), + &optlen)); + if (optlen >= 0) { + response->mutable_optval()->set_bytesval(buf.data(), optlen); + } + break; + } + case ::posix_server::GetSockOptRequest::INT: { + int intval = 0; + socklen_t optlen = sizeof(intval); + response->set_ret(::getsockopt(request->sockfd(), request->level(), + request->optname(), &intval, &optlen)); + response->mutable_optval()->set_intval(intval); + break; + } + case ::posix_server::GetSockOptRequest::TIME: { + timeval tv; + socklen_t optlen = sizeof(tv); + response->set_ret(::getsockopt(request->sockfd(), request->level(), + request->optname(), &tv, &optlen)); + response->mutable_optval()->mutable_timeval()->set_seconds(tv.tv_sec); + response->mutable_optval()->mutable_timeval()->set_microseconds( + tv.tv_usec); + break; + } + default: + return ::grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, + "Unknown SockOpt Type"); } - return ::grpc::Status::OK; - } - - ::grpc::Status GetSockOptInt( - ::grpc::ServerContext *context, - const ::posix_server::GetSockOptIntRequest *request, - ::posix_server::GetSockOptIntResponse *response) override { - int opt = 0; - socklen_t optlen = sizeof(opt); - response->set_ret(::getsockopt(request->sockfd(), request->level(), - request->optname(), &opt, &optlen)); response->set_errno_(errno); - response->set_intval(opt); - return ::grpc::Status::OK; - } - - ::grpc::Status GetSockOptTimeval( - ::grpc::ServerContext *context, - const ::posix_server::GetSockOptTimevalRequest *request, - ::posix_server::GetSockOptTimevalResponse *response) override { - timeval tv; - socklen_t optlen = sizeof(tv); - response->set_ret(::getsockopt(request->sockfd(), request->level(), - request->optname(), &tv, &optlen)); - response->set_errno_(errno); - response->mutable_timeval()->set_seconds(tv.tv_sec); - response->mutable_timeval()->set_microseconds(tv.tv_usec); return ::grpc::Status::OK; } @@ -253,33 +253,32 @@ class PosixImpl final : public posix_server::Posix::Service { grpc_impl::ServerContext *context, const ::posix_server::SetSockOptRequest *request, ::posix_server::SetSockOptResponse *response) override { - response->set_ret(setsockopt(request->sockfd(), request->level(), - request->optname(), request->optval().c_str(), - request->optval().size())); - response->set_errno_(errno); - return ::grpc::Status::OK; - } - - ::grpc::Status SetSockOptInt( - ::grpc::ServerContext *context, - const ::posix_server::SetSockOptIntRequest *request, - ::posix_server::SetSockOptIntResponse *response) override { - int opt = request->intval(); - response->set_ret(::setsockopt(request->sockfd(), request->level(), - request->optname(), &opt, sizeof(opt))); - response->set_errno_(errno); - return ::grpc::Status::OK; - } - - ::grpc::Status SetSockOptTimeval( - ::grpc::ServerContext *context, - const ::posix_server::SetSockOptTimevalRequest *request, - ::posix_server::SetSockOptTimevalResponse *response) override { - timeval tv = {.tv_sec = static_cast<__time_t>(request->timeval().seconds()), - .tv_usec = static_cast<__suseconds_t>( - request->timeval().microseconds())}; - response->set_ret(setsockopt(request->sockfd(), request->level(), - request->optname(), &tv, sizeof(tv))); + switch (request->optval().val_case()) { + case ::posix_server::SockOptVal::kBytesval: + response->set_ret(setsockopt(request->sockfd(), request->level(), + request->optname(), + request->optval().bytesval().c_str(), + request->optval().bytesval().size())); + break; + case ::posix_server::SockOptVal::kIntval: { + int opt = request->optval().intval(); + response->set_ret(::setsockopt(request->sockfd(), request->level(), + request->optname(), &opt, sizeof(opt))); + break; + } + case ::posix_server::SockOptVal::kTimeval: { + timeval tv = {.tv_sec = static_cast<__time_t>( + request->optval().timeval().seconds()), + .tv_usec = static_cast<__suseconds_t>( + request->optval().timeval().microseconds())}; + response->set_ret(setsockopt(request->sockfd(), request->level(), + request->optname(), &tv, sizeof(tv))); + break; + } + default: + return ::grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, + "Unknown SockOpt Type"); + } response->set_errno_(errno); return ::grpc::Status::OK; } diff --git a/test/packetimpact/proto/posix_server.proto b/test/packetimpact/proto/posix_server.proto index ab5ba1c85..9dca563f1 100644 --- a/test/packetimpact/proto/posix_server.proto +++ b/test/packetimpact/proto/posix_server.proto @@ -42,6 +42,14 @@ message Timeval { int64 microseconds = 2; } +message SockOptVal { + oneof val { + bytes bytesval = 1; + int32 intval = 2; + Timeval timeval = 3; + } +} + // Request and Response pairs for each Posix service RPC call, sorted. message AcceptRequest { @@ -98,36 +106,19 @@ message GetSockOptRequest { int32 level = 2; int32 optname = 3; int32 optlen = 4; + enum SockOptType { + UNSPECIFIED = 0; + BYTES = 1; + INT = 2; + TIME = 3; + } + SockOptType type = 5; } message GetSockOptResponse { int32 ret = 1; int32 errno_ = 2; // "errno" may fail to compile in c++. - bytes optval = 3; -} - -message GetSockOptIntRequest { - int32 sockfd = 1; - int32 level = 2; - int32 optname = 3; -} - -message GetSockOptIntResponse { - int32 ret = 1; - int32 errno_ = 2; // "errno" may fail to compile in c++. - int32 intval = 3; -} - -message GetSockOptTimevalRequest { - int32 sockfd = 1; - int32 level = 2; - int32 optname = 3; -} - -message GetSockOptTimevalResponse { - int32 ret = 1; - int32 errno_ = 2; // "errno" may fail to compile in c++. - Timeval timeval = 3; + SockOptVal optval = 3; } message ListenRequest { @@ -167,7 +158,7 @@ message SetSockOptRequest { int32 sockfd = 1; int32 level = 2; int32 optname = 3; - bytes optval = 4; + SockOptVal optval = 4; } message SetSockOptResponse { @@ -175,30 +166,6 @@ message SetSockOptResponse { int32 errno_ = 2; // "errno" may fail to compile in c++. } -message SetSockOptIntRequest { - int32 sockfd = 1; - int32 level = 2; - int32 optname = 3; - int32 intval = 4; -} - -message SetSockOptIntResponse { - int32 ret = 1; - int32 errno_ = 2; -} - -message SetSockOptTimevalRequest { - int32 sockfd = 1; - int32 level = 2; - int32 optname = 3; - Timeval timeval = 4; -} - -message SetSockOptTimevalResponse { - int32 ret = 1; - int32 errno_ = 2; // "errno" may fail to compile in c++. -} - message SocketRequest { int32 domain = 1; int32 type = 2; @@ -233,32 +200,16 @@ service Posix { rpc Connect(ConnectRequest) returns (ConnectResponse); // Call getsockname() on the DUT. rpc GetSockName(GetSockNameRequest) returns (GetSockNameResponse); - // Call getsockopt() on the DUT. You should prefer one of the other - // GetSockOpt* functions with a more structured optval or else you may get the - // encoding wrong, such as making a bad assumption about the server's word - // sizes or endianness. + // Call getsockopt() on the DUT. rpc GetSockOpt(GetSockOptRequest) returns (GetSockOptResponse); - // Call getsockopt() on the DUT with an int optval. - rpc GetSockOptInt(GetSockOptIntRequest) returns (GetSockOptIntResponse); - // Call getsockopt() on the DUT with a Timeval optval. - rpc GetSockOptTimeval(GetSockOptTimevalRequest) - returns (GetSockOptTimevalResponse); // Call listen() on the DUT. rpc Listen(ListenRequest) returns (ListenResponse); // Call send() on the DUT. rpc Send(SendRequest) returns (SendResponse); // Call sendto() on the DUT. rpc SendTo(SendToRequest) returns (SendToResponse); - // Call setsockopt() on the DUT. You should prefer one of the other - // SetSockOpt* functions with a more structured optval or else you may get the - // encoding wrong, such as making a bad assumption about the server's word - // sizes or endianness. + // Call setsockopt() on the DUT. rpc SetSockOpt(SetSockOptRequest) returns (SetSockOptResponse); - // Call setsockopt() on the DUT with an int optval. - rpc SetSockOptInt(SetSockOptIntRequest) returns (SetSockOptIntResponse); - // Call setsockopt() on the DUT with a Timeval optval. - rpc SetSockOptTimeval(SetSockOptTimevalRequest) - returns (SetSockOptTimevalResponse); // Call socket() on the DUT. rpc Socket(SocketRequest) returns (SocketResponse); // Call recv() on the DUT. diff --git a/test/packetimpact/testbench/dut.go b/test/packetimpact/testbench/dut.go index 87eeeeb88..f68d9d62b 100644 --- a/test/packetimpact/testbench/dut.go +++ b/test/packetimpact/testbench/dut.go @@ -291,6 +291,26 @@ func (dut *DUT) GetSockNameWithErrno(ctx context.Context, sockfd int32) (int32, return resp.GetRet(), dut.protoToSockaddr(resp.GetAddr()), syscall.Errno(resp.GetErrno_()) } +func (dut *DUT) getSockOpt(ctx context.Context, sockfd, level, optname, optlen int32, typ pb.GetSockOptRequest_SockOptType) (int32, *pb.SockOptVal, error) { + dut.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 { + dut.t.Fatalf("failed to call GetSockOpt: %s", err) + } + optval := resp.GetOptval() + if optval == nil { + dut.t.Fatalf("GetSockOpt response does not contain a value") + } + return resp.GetRet(), optval, syscall.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 @@ -312,17 +332,12 @@ func (dut *DUT) GetSockOpt(sockfd, level, optname, optlen int32) []byte { // prefer to use a more specific GetSockOptXxxWithErrno function. func (dut *DUT) GetSockOptWithErrno(ctx context.Context, sockfd, level, optname, optlen int32) (int32, []byte, error) { dut.t.Helper() - req := pb.GetSockOptRequest{ - Sockfd: sockfd, - Level: level, - Optname: optname, - Optlen: optlen, + ret, optval, errno := dut.getSockOpt(ctx, sockfd, level, optname, optlen, pb.GetSockOptRequest_BYTES) + bytesval, ok := optval.Val.(*pb.SockOptVal_Bytesval) + if !ok { + dut.t.Fatalf("GetSockOpt got value type: %T, want bytes", optval) } - resp, err := dut.posixServer.GetSockOpt(ctx, &req) - if err != nil { - dut.t.Fatalf("failed to call GetSockOpt: %s", err) - } - return resp.GetRet(), resp.GetOptval(), syscall.Errno(resp.GetErrno_()) + return ret, bytesval.Bytesval, errno } // GetSockOptInt calls getsockopt on the DUT and causes a fatal test failure @@ -342,16 +357,12 @@ func (dut *DUT) GetSockOptInt(sockfd, level, optname int32) int32 { // GetSockOptIntWithErrno calls getsockopt with an integer optval. func (dut *DUT) GetSockOptIntWithErrno(ctx context.Context, sockfd, level, optname int32) (int32, int32, error) { dut.t.Helper() - req := pb.GetSockOptIntRequest{ - Sockfd: sockfd, - Level: level, - Optname: optname, + ret, optval, errno := dut.getSockOpt(ctx, sockfd, level, optname, 0, pb.GetSockOptRequest_INT) + intval, ok := optval.Val.(*pb.SockOptVal_Intval) + if !ok { + dut.t.Fatalf("GetSockOpt got value type: %T, want int", optval) } - resp, err := dut.posixServer.GetSockOptInt(ctx, &req) - if err != nil { - dut.t.Fatalf("failed to call GetSockOptInt: %s", err) - } - return resp.GetRet(), resp.GetIntval(), syscall.Errno(resp.GetErrno_()) + return ret, intval.Intval, errno } // GetSockOptTimeval calls getsockopt on the DUT and causes a fatal test failure @@ -371,20 +382,16 @@ func (dut *DUT) GetSockOptTimeval(sockfd, level, optname int32) unix.Timeval { // GetSockOptTimevalWithErrno calls getsockopt and returns a timeval. func (dut *DUT) GetSockOptTimevalWithErrno(ctx context.Context, sockfd, level, optname int32) (int32, unix.Timeval, error) { dut.t.Helper() - req := pb.GetSockOptTimevalRequest{ - Sockfd: sockfd, - Level: level, - Optname: optname, - } - resp, err := dut.posixServer.GetSockOptTimeval(ctx, &req) - if err != nil { - dut.t.Fatalf("failed to call GetSockOptTimeval: %s", err) + ret, optval, errno := dut.getSockOpt(ctx, sockfd, level, optname, 0, pb.GetSockOptRequest_TIME) + tv, ok := optval.Val.(*pb.SockOptVal_Timeval) + if !ok { + dut.t.Fatalf("GetSockOpt got value type: %T, want timeval", optval) } timeval := unix.Timeval{ - Sec: resp.GetTimeval().Seconds, - Usec: resp.GetTimeval().Microseconds, + Sec: tv.Timeval.Seconds, + Usec: tv.Timeval.Microseconds, } - return resp.GetRet(), timeval, syscall.Errno(resp.GetErrno_()) + return ret, timeval, errno } // Listen calls listen on the DUT and causes a fatal test failure if it doesn't @@ -473,6 +480,21 @@ func (dut *DUT) SendToWithErrno(ctx context.Context, sockfd int32, buf []byte, f return resp.GetRet(), syscall.Errno(resp.GetErrno_()) } +func (dut *DUT) setSockOpt(ctx context.Context, sockfd, level, optname int32, optval *pb.SockOptVal) (int32, error) { + dut.t.Helper() + req := pb.SetSockOptRequest{ + Sockfd: sockfd, + Level: level, + Optname: optname, + Optval: optval, + } + resp, err := dut.posixServer.SetSockOpt(ctx, &req) + if err != nil { + dut.t.Fatalf("failed to call SetSockOpt: %s", err) + } + return resp.GetRet(), syscall.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 @@ -493,17 +515,7 @@ func (dut *DUT) SetSockOpt(sockfd, level, optname int32, optval []byte) { // prefer to use a more specific SetSockOptXxxWithErrno function. func (dut *DUT) SetSockOptWithErrno(ctx context.Context, sockfd, level, optname int32, optval []byte) (int32, error) { dut.t.Helper() - req := pb.SetSockOptRequest{ - Sockfd: sockfd, - Level: level, - Optname: optname, - Optval: optval, - } - resp, err := dut.posixServer.SetSockOpt(ctx, &req) - if err != nil { - dut.t.Fatalf("failed to call SetSockOpt: %s", err) - } - return resp.GetRet(), syscall.Errno(resp.GetErrno_()) + return dut.setSockOpt(ctx, sockfd, level, optname, &pb.SockOptVal{Val: &pb.SockOptVal_Bytesval{optval}}) } // SetSockOptInt calls setsockopt on the DUT and causes a fatal test failure @@ -522,17 +534,7 @@ func (dut *DUT) SetSockOptInt(sockfd, level, optname, optval int32) { // SetSockOptIntWithErrno calls setsockopt with an integer optval. func (dut *DUT) SetSockOptIntWithErrno(ctx context.Context, sockfd, level, optname, optval int32) (int32, error) { dut.t.Helper() - req := pb.SetSockOptIntRequest{ - Sockfd: sockfd, - Level: level, - Optname: optname, - Intval: optval, - } - resp, err := dut.posixServer.SetSockOptInt(ctx, &req) - if err != nil { - dut.t.Fatalf("failed to call SetSockOptInt: %s", err) - } - return resp.GetRet(), syscall.Errno(resp.GetErrno_()) + return dut.setSockOpt(ctx, sockfd, level, optname, &pb.SockOptVal{Val: &pb.SockOptVal_Intval{optval}}) } // SetSockOptTimeval calls setsockopt on the DUT and causes a fatal test failure @@ -556,17 +558,7 @@ func (dut *DUT) SetSockOptTimevalWithErrno(ctx context.Context, sockfd, level, o Seconds: int64(tv.Sec), Microseconds: int64(tv.Usec), } - req := pb.SetSockOptTimevalRequest{ - Sockfd: sockfd, - Level: level, - Optname: optname, - Timeval: &timeval, - } - resp, err := dut.posixServer.SetSockOptTimeval(ctx, &req) - if err != nil { - dut.t.Fatalf("failed to call SetSockOptTimeval: %s", err) - } - return resp.GetRet(), syscall.Errno(resp.GetErrno_()) + return dut.setSockOpt(ctx, sockfd, level, optname, &pb.SockOptVal{Val: &pb.SockOptVal_Timeval{&timeval}}) } // Socket calls socket on the DUT and returns the file descriptor. If socket