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 }