// 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.

syntax = "proto3";

package posix_server;

message SockaddrIn {
  int32 family = 1;
  uint32 port = 2;
  bytes addr = 3;
}

message SockaddrIn6 {
  uint32 family = 1;
  uint32 port = 2;
  uint32 flowinfo = 3;
  bytes addr = 4;
  uint32 scope_id = 5;
}

message Sockaddr {
  oneof sockaddr {
    SockaddrIn in = 1;
    SockaddrIn6 in6 = 2;
  }
}

message Timeval {
  int64 seconds = 1;
  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 {
  int32 sockfd = 1;
}

message AcceptResponse {
  int32 fd = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
  Sockaddr addr = 3;
}

message BindRequest {
  int32 sockfd = 1;
  Sockaddr addr = 2;
}

message BindResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
}

message CloseRequest {
  int32 fd = 1;
}

message CloseResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
}

message ConnectRequest {
  int32 sockfd = 1;
  Sockaddr addr = 2;
}

message ConnectResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
}

message GetSockNameRequest {
  int32 sockfd = 1;
}

message GetSockNameResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
  Sockaddr addr = 3;
}

message GetSockOptRequest {
  int32 sockfd = 1;
  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++.
  SockOptVal optval = 3;
}

message ListenRequest {
  int32 sockfd = 1;
  int32 backlog = 2;
}

message ListenResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
}

// The events field is overloaded: when used for request, it is copied into the
// events field of posix struct pollfd; when used for response, it is filled by
// the revents field from the posix struct pollfd.
message PollFd {
  int32 fd = 1;
  uint32 events = 2;
}

message PollRequest {
  repeated PollFd pfds = 1;
  int32 timeout_millis = 2;
}

message PollResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
  repeated PollFd pfds = 3;
}

message SendRequest {
  int32 sockfd = 1;
  bytes buf = 2;
  int32 flags = 3;
}

message SendResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
}

message SendToRequest {
  int32 sockfd = 1;
  bytes buf = 2;
  int32 flags = 3;
  Sockaddr dest_addr = 4;
}

message SendToResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
}

message SetNonblockingRequest {
  int32 fd = 1;
  bool nonblocking = 2;
}

message SetNonblockingResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
  // The failed fcntl cmd.
  string cmd = 3;
}

message SetSockOptRequest {
  int32 sockfd = 1;
  int32 level = 2;
  int32 optname = 3;
  SockOptVal optval = 4;
}

message SetSockOptResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
}

message SocketRequest {
  int32 domain = 1;
  int32 type = 2;
  int32 protocol = 3;
}

message SocketResponse {
  int32 fd = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
}

message ShutdownRequest {
  int32 fd = 1;
  int32 how = 2;
}

message ShutdownResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
}

message RecvRequest {
  int32 sockfd = 1;
  int32 len = 2;
  int32 flags = 3;
}

message RecvResponse {
  int32 ret = 1;
  int32 errno_ = 2;  // "errno" may fail to compile in c++.
  bytes buf = 3;
}

service Posix {
  // Call accept() on the DUT.
  rpc Accept(AcceptRequest) returns (AcceptResponse);
  // Call bind() on the DUT.
  rpc Bind(BindRequest) returns (BindResponse);
  // Call close() on the DUT.
  rpc Close(CloseRequest) returns (CloseResponse);
  // Call connect() on the DUT.
  rpc Connect(ConnectRequest) returns (ConnectResponse);
  // Call getsockname() on the DUT.
  rpc GetSockName(GetSockNameRequest) returns (GetSockNameResponse);
  // Call getsockopt() on the DUT.
  rpc GetSockOpt(GetSockOptRequest) returns (GetSockOptResponse);
  // Call listen() on the DUT.
  rpc Listen(ListenRequest) returns (ListenResponse);
  // Call poll() on the DUT. Only pollfds that have non-empty revents are
  // returned, the only way to tie the response back to the original request
  // is using the fd number.
  rpc Poll(PollRequest) returns (PollResponse);
  // Call send() on the DUT.
  rpc Send(SendRequest) returns (SendResponse);
  // Call sendto() on the DUT.
  rpc SendTo(SendToRequest) returns (SendToResponse);
  // Set/Clear O_NONBLOCK flag on the requested fd. This is needed because the
  // operating system on DUT may have a different definition for O_NONBLOCK, it
  // is not sound to assemble flags on testbench.
  rpc SetNonblocking(SetNonblockingRequest) returns (SetNonblockingResponse);
  // Call setsockopt() on the DUT.
  rpc SetSockOpt(SetSockOptRequest) returns (SetSockOptResponse);
  // Call socket() on the DUT.
  rpc Socket(SocketRequest) returns (SocketResponse);
  // Call shutdown() on the DUT.
  rpc Shutdown(ShutdownRequest) returns (ShutdownResponse);
  // Call recv() on the DUT.
  rpc Recv(RecvRequest) returns (RecvResponse);
}
