• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The Android Open Source Project
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 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "frontend/frontend_server.h"
16 
17 #include <google/protobuf/util/json_util.h>
18 
19 #include <iostream>
20 #include <memory>
21 #include <string>
22 #include <utility>
23 
24 #include "controller/scene_controller.h"
25 #include "frontend.grpc.pb.h"
26 #include "frontend.pb.h"
27 #include "google/protobuf/empty.pb.h"
28 #include "grpcpp/server_context.h"
29 #include "grpcpp/support/status.h"
30 #include "netsim-cxx/src/lib.rs.h"
31 
32 namespace netsim {
33 namespace {
34 
35 /// The C++ implementation of the CxxServerResponseWriter interface. This is
36 /// used by the gRPC server to invoke the Rust pcap handler and process a
37 /// responses.
38 class CxxServerResponseWritable : public frontend::CxxServerResponseWriter {
39  public:
CxxServerResponseWritable()40   CxxServerResponseWritable()
41       : grpc_writer_(nullptr), err(""), is_ok(false), body(""), length(0){};
CxxServerResponseWritable(grpc::ServerWriter<netsim::frontend::GetCaptureResponse> * grpc_writer)42   CxxServerResponseWritable(
43       grpc::ServerWriter<netsim::frontend::GetCaptureResponse> *grpc_writer)
44       : grpc_writer_(grpc_writer), err(""), is_ok(false), body(""), length(0){};
45 
put_error(unsigned int error_code,const std::string & response) const46   void put_error(unsigned int error_code,
47                  const std::string &response) const override {
48     err = std::to_string(error_code) + ": " + response;
49     is_ok = false;
50   }
51 
put_ok_with_length(const std::string & mime_type,std::size_t length) const52   void put_ok_with_length(const std::string &mime_type,
53                           std::size_t length) const override {
54     this->length = length;
55     is_ok = true;
56   }
57 
put_chunk(rust::Slice<const uint8_t> chunk) const58   void put_chunk(rust::Slice<const uint8_t> chunk) const override {
59     netsim::frontend::GetCaptureResponse response;
60     response.set_capture_stream(std::string(chunk.begin(), chunk.end()));
61     is_ok = grpc_writer_->Write(response);
62   }
63 
put_ok(const std::string & mime_type,const std::string & body) const64   void put_ok(const std::string &mime_type,
65               const std::string &body) const override {
66     this->body = body;
67     is_ok = true;
68   }
69 
70   mutable grpc::ServerWriter<netsim::frontend::GetCaptureResponse>
71       *grpc_writer_;
72   mutable std::string err;
73   mutable bool is_ok;
74   mutable std::string body;
75   mutable std::size_t length;
76 };
77 
78 class FrontendServer final : public frontend::FrontendService::Service {
79  public:
GetVersion(grpc::ServerContext * context,const google::protobuf::Empty * empty,frontend::VersionResponse * reply)80   grpc::Status GetVersion(grpc::ServerContext *context,
81                           const google::protobuf::Empty *empty,
82                           frontend::VersionResponse *reply) {
83     reply->set_version(std::string(netsim::GetVersion()));
84     return grpc::Status::OK;
85   }
86 
GetDevices(grpc::ServerContext * context,const google::protobuf::Empty * empty,frontend::GetDevicesResponse * reply)87   grpc::Status GetDevices(grpc::ServerContext *context,
88                           const google::protobuf::Empty *empty,
89                           frontend::GetDevicesResponse *reply) {
90     const auto scene = netsim::controller::SceneController::Singleton().Get();
91     for (const auto &device : scene.devices())
92       reply->add_devices()->CopyFrom(device);
93     return grpc::Status::OK;
94   }
95 
PatchDevice(grpc::ServerContext * context,const frontend::PatchDeviceRequest * request,google::protobuf::Empty * response)96   grpc::Status PatchDevice(grpc::ServerContext *context,
97                            const frontend::PatchDeviceRequest *request,
98                            google::protobuf::Empty *response) {
99     auto status = netsim::controller::SceneController::Singleton().PatchDevice(
100         request->device());
101     if (!status)
102       return grpc::Status(grpc::StatusCode::NOT_FOUND,
103                           "device " + request->device().name() + " not found.");
104     return grpc::Status::OK;
105   }
106 
SetPacketCapture(grpc::ServerContext * context,const frontend::SetPacketCaptureRequest * request,google::protobuf::Empty * empty)107   grpc::Status SetPacketCapture(
108       grpc::ServerContext *context,
109       const frontend::SetPacketCaptureRequest *request,
110       google::protobuf::Empty *empty) {
111     model::Device device;
112     model::Chip chip;
113     // Turn on bt packet capture
114     chip.set_capture(request->capture() ? model::State::ON : model::State::OFF);
115     chip.mutable_bt();
116     device.mutable_chips()->Add()->CopyFrom(chip);
117     controller::SceneController::Singleton().PatchDevice(device);
118     return grpc::Status::OK;
119   }
120 
Reset(grpc::ServerContext * context,const google::protobuf::Empty * request,google::protobuf::Empty * empty)121   grpc::Status Reset(grpc::ServerContext *context,
122                      const google::protobuf::Empty *request,
123                      google::protobuf::Empty *empty) {
124     netsim::controller::SceneController::Singleton().Reset();
125     return grpc::Status::OK;
126   }
127 
ListCapture(grpc::ServerContext * context,const google::protobuf::Empty * empty,frontend::ListCaptureResponse * reply)128   grpc::Status ListCapture(grpc::ServerContext *context,
129                            const google::protobuf::Empty *empty,
130                            frontend::ListCaptureResponse *reply) {
131     CxxServerResponseWritable writer;
132     HandleCaptureCxx(writer, "GET", "", "");
133     if (writer.is_ok) {
134       google::protobuf::util::JsonStringToMessage(writer.body, reply);
135       return grpc::Status::OK;
136     }
137     return grpc::Status(grpc::StatusCode::UNKNOWN, writer.err);
138   }
139 
PatchCapture(grpc::ServerContext * context,const frontend::PatchCaptureRequest * request,google::protobuf::Empty * response)140   grpc::Status PatchCapture(grpc::ServerContext *context,
141                             const frontend::PatchCaptureRequest *request,
142                             google::protobuf::Empty *response) {
143     CxxServerResponseWritable writer;
144     HandleCaptureCxx(writer, "PATCH", std::to_string(request->id()),
145                      std::to_string(request->patch().state()));
146     if (writer.is_ok) {
147       return grpc::Status::OK;
148     }
149     return grpc::Status(grpc::StatusCode::UNKNOWN, writer.err);
150   }
GetCapture(grpc::ServerContext * context,const netsim::frontend::GetCaptureRequest * request,grpc::ServerWriter<netsim::frontend::GetCaptureResponse> * grpc_writer)151   grpc::Status GetCapture(
152       grpc::ServerContext *context,
153       const netsim::frontend::GetCaptureRequest *request,
154       grpc::ServerWriter<netsim::frontend::GetCaptureResponse> *grpc_writer) {
155     CxxServerResponseWritable writer(grpc_writer);
156     HandleCaptureCxx(writer, "GET", std::to_string(request->id()), "");
157     if (writer.is_ok) {
158       return grpc::Status::OK;
159     }
160     return grpc::Status(grpc::StatusCode::UNKNOWN, writer.err);
161   }
162 };
163 }  // namespace
164 
GetFrontendService()165 std::unique_ptr<frontend::FrontendService::Service> GetFrontendService() {
166   return std::make_unique<FrontendServer>();
167 }
168 
169 }  // namespace netsim
170