gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/packetimpact/dut/posix_server.cc (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at //
     6  //     http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  #include <arpa/inet.h>
    15  #include <fcntl.h>
    16  #include <getopt.h>
    17  #include <netdb.h>
    18  #include <netinet/in.h>
    19  #include <poll.h>
    20  #include <stdio.h>
    21  #include <stdlib.h>
    22  #include <string.h>
    23  #include <sys/socket.h>
    24  #include <sys/types.h>
    25  #include <time.h>
    26  #include <unistd.h>
    27  
    28  #include <iostream>
    29  #include <unordered_map>
    30  
    31  #include "absl/strings/str_format.h"
    32  #include "include/grpcpp/security/server_credentials.h"
    33  #include "include/grpcpp/server_builder.h"
    34  #include "include/grpcpp/server_context.h"
    35  #include "test/packetimpact/proto/posix_server.grpc.pb.h"
    36  #include "test/packetimpact/proto/posix_server.pb.h"
    37  
    38  // Converts a sockaddr_storage to a Sockaddr message.
    39  ::grpc::Status sockaddr_to_proto(const sockaddr_storage &addr,
    40                                   socklen_t addrlen,
    41                                   posix_server::Sockaddr *sockaddr_proto) {
    42    switch (addr.ss_family) {
    43      case AF_INET: {
    44        auto addr_in = reinterpret_cast<const sockaddr_in *>(&addr);
    45        auto response_in = sockaddr_proto->mutable_in();
    46        response_in->set_family(addr_in->sin_family);
    47        response_in->set_port(ntohs(addr_in->sin_port));
    48        response_in->mutable_addr()->assign(
    49            reinterpret_cast<const char *>(&addr_in->sin_addr.s_addr), 4);
    50        return ::grpc::Status::OK;
    51      }
    52      case AF_INET6: {
    53        auto addr_in6 = reinterpret_cast<const sockaddr_in6 *>(&addr);
    54        auto response_in6 = sockaddr_proto->mutable_in6();
    55        response_in6->set_family(addr_in6->sin6_family);
    56        response_in6->set_port(ntohs(addr_in6->sin6_port));
    57        response_in6->set_flowinfo(ntohl(addr_in6->sin6_flowinfo));
    58        response_in6->mutable_addr()->assign(
    59            reinterpret_cast<const char *>(&addr_in6->sin6_addr.s6_addr), 16);
    60        // sin6_scope_id is stored in host byte order.
    61        //
    62        // https://www.gnu.org/software/libc/manual/html_node/Internet-Address-Formats.html
    63        response_in6->set_scope_id(addr_in6->sin6_scope_id);
    64        return ::grpc::Status::OK;
    65      }
    66    }
    67    return ::grpc::Status(grpc::StatusCode::INVALID_ARGUMENT, "Unknown Sockaddr");
    68  }
    69  
    70  ::grpc::Status proto_to_sockaddr(const posix_server::Sockaddr &sockaddr_proto,
    71                                   sockaddr_storage *addr, socklen_t *addr_len) {
    72    switch (sockaddr_proto.sockaddr_case()) {
    73      case posix_server::Sockaddr::SockaddrCase::kIn: {
    74        auto proto_in = sockaddr_proto.in();
    75        if (proto_in.addr().size() != 4) {
    76          return ::grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
    77                                "IPv4 address must be 4 bytes");
    78        }
    79        auto addr_in = reinterpret_cast<sockaddr_in *>(addr);
    80        addr_in->sin_family = proto_in.family();
    81        addr_in->sin_port = htons(proto_in.port());
    82        proto_in.addr().copy(reinterpret_cast<char *>(&addr_in->sin_addr.s_addr),
    83                             4);
    84        *addr_len = sizeof(*addr_in);
    85        break;
    86      }
    87      case posix_server::Sockaddr::SockaddrCase::kIn6: {
    88        auto proto_in6 = sockaddr_proto.in6();
    89        if (proto_in6.addr().size() != 16) {
    90          return ::grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
    91                                "IPv6 address must be 16 bytes");
    92        }
    93        auto addr_in6 = reinterpret_cast<sockaddr_in6 *>(addr);
    94        addr_in6->sin6_family = proto_in6.family();
    95        addr_in6->sin6_port = htons(proto_in6.port());
    96        addr_in6->sin6_flowinfo = htonl(proto_in6.flowinfo());
    97        proto_in6.addr().copy(
    98            reinterpret_cast<char *>(&addr_in6->sin6_addr.s6_addr), 16);
    99        // sin6_scope_id is stored in host byte order.
   100        //
   101        // https://www.gnu.org/software/libc/manual/html_node/Internet-Address-Formats.html
   102        addr_in6->sin6_scope_id = proto_in6.scope_id();
   103        *addr_len = sizeof(*addr_in6);
   104        break;
   105      }
   106      case posix_server::Sockaddr::SockaddrCase::SOCKADDR_NOT_SET:
   107      default:
   108        return ::grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
   109                              "Unknown Sockaddr");
   110    }
   111    return ::grpc::Status::OK;
   112  }
   113  
   114  class PosixImpl final : public posix_server::Posix::Service {
   115    ::grpc::Status Accept(grpc::ServerContext *context,
   116                          const ::posix_server::AcceptRequest *request,
   117                          ::posix_server::AcceptResponse *response) override {
   118      sockaddr_storage addr;
   119      socklen_t addrlen = sizeof(addr);
   120      response->set_fd(accept(request->sockfd(),
   121                              reinterpret_cast<sockaddr *>(&addr), &addrlen));
   122      if (response->fd() < 0) {
   123        response->set_errno_(errno);
   124      }
   125      return sockaddr_to_proto(addr, addrlen, response->mutable_addr());
   126    }
   127  
   128    ::grpc::Status Bind(grpc::ServerContext *context,
   129                        const ::posix_server::BindRequest *request,
   130                        ::posix_server::BindResponse *response) override {
   131      if (!request->has_addr()) {
   132        return ::grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
   133                              "Missing address");
   134      }
   135  
   136      sockaddr_storage addr;
   137      socklen_t addr_len;
   138      auto err = proto_to_sockaddr(request->addr(), &addr, &addr_len);
   139      if (!err.ok()) {
   140        return err;
   141      }
   142  
   143      response->set_ret(
   144          bind(request->sockfd(), reinterpret_cast<sockaddr *>(&addr), addr_len));
   145      if (response->ret() < 0) {
   146        response->set_errno_(errno);
   147      }
   148      return ::grpc::Status::OK;
   149    }
   150  
   151    ::grpc::Status Close(grpc::ServerContext *context,
   152                         const ::posix_server::CloseRequest *request,
   153                         ::posix_server::CloseResponse *response) override {
   154      response->set_ret(close(request->fd()));
   155      if (response->ret() < 0) {
   156        response->set_errno_(errno);
   157      }
   158      return ::grpc::Status::OK;
   159    }
   160  
   161    ::grpc::Status Connect(grpc::ServerContext *context,
   162                           const ::posix_server::ConnectRequest *request,
   163                           ::posix_server::ConnectResponse *response) override {
   164      if (!request->has_addr()) {
   165        return ::grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
   166                              "Missing address");
   167      }
   168      sockaddr_storage addr;
   169      socklen_t addr_len;
   170      auto err = proto_to_sockaddr(request->addr(), &addr, &addr_len);
   171      if (!err.ok()) {
   172        return err;
   173      }
   174  
   175      response->set_ret(connect(request->sockfd(),
   176                                reinterpret_cast<sockaddr *>(&addr), addr_len));
   177      if (response->ret() < 0) {
   178        response->set_errno_(errno);
   179      }
   180      return ::grpc::Status::OK;
   181    }
   182  
   183    ::grpc::Status GetSockName(
   184        grpc::ServerContext *context,
   185        const ::posix_server::GetSockNameRequest *request,
   186        ::posix_server::GetSockNameResponse *response) override {
   187      sockaddr_storage addr;
   188      socklen_t addrlen = sizeof(addr);
   189      response->set_ret(getsockname(
   190          request->sockfd(), reinterpret_cast<sockaddr *>(&addr), &addrlen));
   191      if (response->ret() < 0) {
   192        response->set_errno_(errno);
   193      }
   194      return sockaddr_to_proto(addr, addrlen, response->mutable_addr());
   195    }
   196  
   197    ::grpc::Status GetSockOpt(
   198        grpc::ServerContext *context,
   199        const ::posix_server::GetSockOptRequest *request,
   200        ::posix_server::GetSockOptResponse *response) override {
   201      switch (request->type()) {
   202        case ::posix_server::GetSockOptRequest::BYTES: {
   203          socklen_t optlen = request->optlen();
   204          std::vector<char> buf(optlen);
   205          response->set_ret(::getsockopt(request->sockfd(), request->level(),
   206                                         request->optname(), buf.data(),
   207                                         &optlen));
   208          if (optlen >= 0) {
   209            response->mutable_optval()->set_bytesval(buf.data(), optlen);
   210          }
   211          break;
   212        }
   213        case ::posix_server::GetSockOptRequest::INT: {
   214          int intval = 0;
   215          socklen_t optlen = sizeof(intval);
   216          response->set_ret(::getsockopt(request->sockfd(), request->level(),
   217                                         request->optname(), &intval, &optlen));
   218          response->mutable_optval()->set_intval(intval);
   219          break;
   220        }
   221        case ::posix_server::GetSockOptRequest::TIME: {
   222          timeval tv;
   223          socklen_t optlen = sizeof(tv);
   224          response->set_ret(::getsockopt(request->sockfd(), request->level(),
   225                                         request->optname(), &tv, &optlen));
   226          response->mutable_optval()->mutable_timeval()->set_seconds(tv.tv_sec);
   227          response->mutable_optval()->mutable_timeval()->set_microseconds(
   228              tv.tv_usec);
   229          break;
   230        }
   231        default:
   232          return ::grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
   233                                "Unknown SockOpt Type");
   234      }
   235      if (response->ret() < 0) {
   236        response->set_errno_(errno);
   237      }
   238      return ::grpc::Status::OK;
   239    }
   240  
   241    ::grpc::Status Listen(grpc::ServerContext *context,
   242                          const ::posix_server::ListenRequest *request,
   243                          ::posix_server::ListenResponse *response) override {
   244      response->set_ret(listen(request->sockfd(), request->backlog()));
   245      if (response->ret() < 0) {
   246        response->set_errno_(errno);
   247      }
   248      return ::grpc::Status::OK;
   249    }
   250  
   251    ::grpc::Status Poll(::grpc::ServerContext *context,
   252                        const ::posix_server::PollRequest *request,
   253                        ::posix_server::PollResponse *response) override {
   254      std::vector<struct pollfd> pfds;
   255      pfds.reserve(request->pfds_size());
   256      for (const auto &pfd : request->pfds()) {
   257        pfds.push_back({
   258            .fd = pfd.fd(),
   259            .events = static_cast<short>(pfd.events()),
   260        });
   261      }
   262      int ret = ::poll(pfds.data(), pfds.size(), request->timeout_millis());
   263  
   264      response->set_ret(ret);
   265      if (ret < 0) {
   266        response->set_errno_(errno);
   267      } else {
   268        // Only pollfds that have non-empty revents are returned, the client can't
   269        // rely on indexes of the request array.
   270        for (const auto &pfd : pfds) {
   271          if (pfd.revents) {
   272            auto *proto_pfd = response->add_pfds();
   273            proto_pfd->set_fd(pfd.fd);
   274            proto_pfd->set_events(pfd.revents);
   275          }
   276        }
   277        if (int ready = response->pfds_size(); ret != ready) {
   278          return ::grpc::Status(
   279              ::grpc::StatusCode::INTERNAL,
   280              absl::StrFormat(
   281                  "poll's return value(%d) doesn't match the number of "
   282                  "file descriptors that are actually ready(%d)",
   283                  ret, ready));
   284        }
   285      }
   286      return ::grpc::Status::OK;
   287    }
   288  
   289    ::grpc::Status Send(::grpc::ServerContext *context,
   290                        const ::posix_server::SendRequest *request,
   291                        ::posix_server::SendResponse *response) override {
   292      response->set_ret(::send(request->sockfd(), request->buf().data(),
   293                               request->buf().size(), request->flags()));
   294      if (response->ret() < 0) {
   295        response->set_errno_(errno);
   296      }
   297      return ::grpc::Status::OK;
   298    }
   299  
   300    ::grpc::Status SendTo(::grpc::ServerContext *context,
   301                          const ::posix_server::SendToRequest *request,
   302                          ::posix_server::SendToResponse *response) override {
   303      if (!request->has_dest_addr()) {
   304        return ::grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
   305                              "Missing address");
   306      }
   307      sockaddr_storage addr;
   308      socklen_t addr_len;
   309      auto err = proto_to_sockaddr(request->dest_addr(), &addr, &addr_len);
   310      if (!err.ok()) {
   311        return err;
   312      }
   313  
   314      response->set_ret(::sendto(request->sockfd(), request->buf().data(),
   315                                 request->buf().size(), request->flags(),
   316                                 reinterpret_cast<sockaddr *>(&addr), addr_len));
   317      if (response->ret() < 0) {
   318        response->set_errno_(errno);
   319      }
   320      return ::grpc::Status::OK;
   321    }
   322  
   323    ::grpc::Status SetNonblocking(
   324        grpc::ServerContext *context,
   325        const ::posix_server::SetNonblockingRequest *request,
   326        ::posix_server::SetNonblockingResponse *response) override {
   327      int flags = fcntl(request->fd(), F_GETFL);
   328      if (flags == -1) {
   329        response->set_ret(-1);
   330        response->set_errno_(errno);
   331        response->set_cmd("F_GETFL");
   332        return ::grpc::Status::OK;
   333      }
   334      if (request->nonblocking()) {
   335        flags |= O_NONBLOCK;
   336      } else {
   337        flags &= ~O_NONBLOCK;
   338      }
   339      int ret = fcntl(request->fd(), F_SETFL, flags);
   340      response->set_ret(ret);
   341      if (ret == -1) {
   342        response->set_errno_(errno);
   343        response->set_cmd("F_SETFL");
   344      }
   345      return ::grpc::Status::OK;
   346    }
   347  
   348    ::grpc::Status SetSockOpt(
   349        grpc::ServerContext *context,
   350        const ::posix_server::SetSockOptRequest *request,
   351        ::posix_server::SetSockOptResponse *response) override {
   352      switch (request->optval().val_case()) {
   353        case ::posix_server::SockOptVal::kBytesval:
   354          response->set_ret(setsockopt(request->sockfd(), request->level(),
   355                                       request->optname(),
   356                                       request->optval().bytesval().c_str(),
   357                                       request->optval().bytesval().size()));
   358          break;
   359        case ::posix_server::SockOptVal::kIntval: {
   360          int opt = request->optval().intval();
   361          response->set_ret(::setsockopt(request->sockfd(), request->level(),
   362                                         request->optname(), &opt, sizeof(opt)));
   363          break;
   364        }
   365        case ::posix_server::SockOptVal::kTimeval: {
   366          timeval tv = {.tv_sec = static_cast<time_t>(
   367                            request->optval().timeval().seconds()),
   368                        .tv_usec = static_cast<suseconds_t>(
   369                            request->optval().timeval().microseconds())};
   370          response->set_ret(setsockopt(request->sockfd(), request->level(),
   371                                       request->optname(), &tv, sizeof(tv)));
   372          break;
   373        }
   374        default:
   375          return ::grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
   376                                "Unknown SockOpt Type");
   377      }
   378      if (response->ret() < 0) {
   379        response->set_errno_(errno);
   380      }
   381      return ::grpc::Status::OK;
   382    }
   383  
   384    ::grpc::Status Socket(grpc::ServerContext *context,
   385                          const ::posix_server::SocketRequest *request,
   386                          ::posix_server::SocketResponse *response) override {
   387      response->set_fd(
   388          socket(request->domain(), request->type(), request->protocol()));
   389      if (response->fd() < 0) {
   390        response->set_errno_(errno);
   391      }
   392      return ::grpc::Status::OK;
   393    }
   394  
   395    ::grpc::Status Shutdown(grpc::ServerContext *context,
   396                            const ::posix_server::ShutdownRequest *request,
   397                            ::posix_server::ShutdownResponse *response) override {
   398      response->set_ret(shutdown(request->fd(), request->how()));
   399      if (response->ret() < 0) {
   400        response->set_errno_(errno);
   401      }
   402      return ::grpc::Status::OK;
   403    }
   404  
   405    ::grpc::Status Recv(::grpc::ServerContext *context,
   406                        const ::posix_server::RecvRequest *request,
   407                        ::posix_server::RecvResponse *response) override {
   408      std::vector<char> buf(request->len());
   409      response->set_ret(
   410          recv(request->sockfd(), buf.data(), buf.size(), request->flags()));
   411      if (response->ret() >= 0) {
   412        response->set_buf(buf.data(), response->ret());
   413      }
   414      if (response->ret() < 0) {
   415        response->set_errno_(errno);
   416      }
   417      return ::grpc::Status::OK;
   418    }
   419  };
   420  
   421  // Parse command line options. Returns a pointer to the first argument beyond
   422  // the options.
   423  void parse_command_line_options(int argc, char *argv[], std::string *ip,
   424                                  int *port) {
   425    static struct option options[] = {{"ip", required_argument, NULL, 1},
   426                                      {"port", required_argument, NULL, 2},
   427                                      {0, 0, 0, 0}};
   428  
   429    // Parse the arguments.
   430    int c;
   431    while ((c = getopt_long(argc, argv, "", options, NULL)) > 0) {
   432      if (c == 1) {
   433        *ip = optarg;
   434      } else if (c == 2) {
   435        *port = std::stoi(std::string(optarg));
   436      }
   437    }
   438  }
   439  
   440  void run_server(const std::string &ip, int port) {
   441    PosixImpl posix_service;
   442    grpc::ServerBuilder builder;
   443    std::string server_address = ip + ":" + std::to_string(port);
   444    // Set the authentication mechanism.
   445    std::shared_ptr<grpc::ServerCredentials> creds =
   446        grpc::InsecureServerCredentials();
   447    builder.AddListeningPort(server_address, creds);
   448    builder.RegisterService(&posix_service);
   449  
   450    std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
   451    std::cerr << "Server listening on " << server_address << std::endl;
   452    server->Wait();
   453    std::cerr << "posix_server is finished." << std::endl;
   454  }
   455  
   456  int main(int argc, char *argv[]) {
   457    std::cerr << "posix_server is starting." << std::endl;
   458    std::string ip;
   459    int port;
   460    parse_command_line_options(argc, argv, &ip, &port);
   461  
   462    std::cerr << "Got IP " << ip << " and port " << port << "." << std::endl;
   463    run_server(ip, port);
   464  }