blob: b075315cf91282d8ea45760a72531e4758c7e3e8 [file] [log] [blame]
// Copyright 2022 The Android Open Source Project
//
// 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.
#include "frontend/frontend_server.h"
#include <google/protobuf/util/json_util.h>
#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include "controller/scene_controller.h"
#include "frontend.grpc.pb.h"
#include "frontend.pb.h"
#include "google/protobuf/empty.pb.h"
#include "grpcpp/server_context.h"
#include "grpcpp/support/status.h"
#include "netsim-cxx/src/lib.rs.h"
namespace netsim {
namespace {
/// The C++ implementation of the CxxServerResponseWriter interface. This is
/// used by the gRPC server to invoke the Rust pcap handler and process a
/// responses.
class CxxServerResponseWritable : public frontend::CxxServerResponseWriter {
public:
CxxServerResponseWritable()
: grpc_writer_(nullptr), err(""), is_ok(false), body(""), length(0){};
CxxServerResponseWritable(
grpc::ServerWriter<netsim::frontend::GetCaptureResponse> *grpc_writer)
: grpc_writer_(grpc_writer), err(""), is_ok(false), body(""), length(0){};
void put_error(unsigned int error_code,
const std::string &response) const override {
err = std::to_string(error_code) + ": " + response;
is_ok = false;
}
void put_ok_with_length(const std::string &mime_type,
std::size_t length) const override {
this->length = length;
is_ok = true;
}
void put_chunk(rust::Slice<const uint8_t> chunk) const override {
netsim::frontend::GetCaptureResponse response;
response.set_capture_stream(std::string(chunk.begin(), chunk.end()));
is_ok = grpc_writer_->Write(response);
}
void put_ok(const std::string &mime_type,
const std::string &body) const override {
this->body = body;
is_ok = true;
}
mutable grpc::ServerWriter<netsim::frontend::GetCaptureResponse>
*grpc_writer_;
mutable std::string err;
mutable bool is_ok;
mutable std::string body;
mutable std::size_t length;
};
class FrontendServer final : public frontend::FrontendService::Service {
public:
grpc::Status GetVersion(grpc::ServerContext *context,
const google::protobuf::Empty *empty,
frontend::VersionResponse *reply) {
reply->set_version(std::string(netsim::GetVersion()));
return grpc::Status::OK;
}
grpc::Status GetDevices(grpc::ServerContext *context,
const google::protobuf::Empty *empty,
frontend::GetDevicesResponse *reply) {
const auto scene = netsim::controller::SceneController::Singleton().Get();
for (const auto &device : scene.devices())
reply->add_devices()->CopyFrom(device);
return grpc::Status::OK;
}
grpc::Status PatchDevice(grpc::ServerContext *context,
const frontend::PatchDeviceRequest *request,
google::protobuf::Empty *response) {
auto status = netsim::controller::SceneController::Singleton().PatchDevice(
request->device());
if (!status)
return grpc::Status(grpc::StatusCode::NOT_FOUND,
"device " + request->device().name() + " not found.");
return grpc::Status::OK;
}
grpc::Status Reset(grpc::ServerContext *context,
const google::protobuf::Empty *request,
google::protobuf::Empty *empty) {
netsim::controller::SceneController::Singleton().Reset();
return grpc::Status::OK;
}
grpc::Status ListCapture(grpc::ServerContext *context,
const google::protobuf::Empty *empty,
frontend::ListCaptureResponse *reply) {
CxxServerResponseWritable writer;
HandleCaptureCxx(writer, "GET", "", "");
if (writer.is_ok) {
google::protobuf::util::JsonStringToMessage(writer.body, reply);
return grpc::Status::OK;
}
return grpc::Status(grpc::StatusCode::UNKNOWN, writer.err);
}
grpc::Status PatchCapture(grpc::ServerContext *context,
const frontend::PatchCaptureRequest *request,
google::protobuf::Empty *response) {
CxxServerResponseWritable writer;
HandleCaptureCxx(writer, "PATCH", std::to_string(request->id()),
std::to_string(request->patch().state()));
if (writer.is_ok) {
return grpc::Status::OK;
}
return grpc::Status(grpc::StatusCode::UNKNOWN, writer.err);
}
grpc::Status GetCapture(
grpc::ServerContext *context,
const netsim::frontend::GetCaptureRequest *request,
grpc::ServerWriter<netsim::frontend::GetCaptureResponse> *grpc_writer) {
CxxServerResponseWritable writer(grpc_writer);
HandleCaptureCxx(writer, "GET", std::to_string(request->id()), "");
if (writer.is_ok) {
return grpc::Status::OK;
}
return grpc::Status(grpc::StatusCode::UNKNOWN, writer.err);
}
};
} // namespace
std::unique_ptr<frontend::FrontendService::Service> GetFrontendService() {
return std::make_unique<FrontendServer>();
}
} // namespace netsim