| #include "grpc_instance.h" |
| |
| #include <chrono> // NOLINT(build/c++11) |
| #include <memory> |
| #include <sstream> |
| #include <string> |
| #include <thread> // NOLINT(build/c++11) |
| |
| #include "absl/log/log.h" |
| #include "grpcblob_defs.h" |
| #include "smbios_file.h" |
| #include "grpcpp/security/server_credentials.h" |
| |
| namespace blobs { |
| |
| // Arbitrary constant to avoid overlap with other services |
| constexpr int basePort = 10166; |
| [[nodiscard]] std::string GrpcInstance::threadId( |
| const std::thread& thread) const { |
| std::stringstream ss; |
| |
| ss << thread.get_id(); |
| |
| return ss.str(); |
| } |
| |
| [[nodiscard]] bool GrpcInstance::validatePreviousFile() const { |
| LOG(INFO) << "GrpcInstance::validatePreviousFile: " << instance; |
| // Instance number must be set in order to build correct filename |
| SmbiosEntry entry(instance, basePath_); |
| |
| std::string fileName = entry.getFilename(); |
| if (!(entry.loadFromFile(fileName))) { |
| // This is normal if running for first time on clean filesystem |
| LOG(ERROR) << "Could not restore SMBIOS from file: " << fileName; |
| |
| return false; |
| } |
| |
| std::string errorMessage = entry.validate(); |
| if (!(errorMessage.empty())) { |
| LOG(ERROR) << "Loaded SMBIOS content failed validation: " << errorMessage; |
| |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void GrpcInstance::restoreLink() { |
| // Obtain consistent filename creation by asking entry for filename |
| SmbiosEntry entry(instance, basePath_); |
| |
| if (!(validatePreviousFile())) { |
| // Not error, normal if running for the first time on a fresh system |
| LOG(INFO) << "Unable to restore from previous file: " << instance; |
| return; |
| } |
| |
| // The content is restored, update app as if file came from gRPC |
| bool accepted = smbiosServiceCallback->acceptEntry(entry, false); |
| if (!accepted) { |
| LOG(ERROR) << "Unable to restore to previous link: " << instance; |
| return; |
| } |
| |
| LOG(INFO) << "Restoring previous request content: " << instance; |
| } |
| |
| void GrpcInstance::start() { |
| // Bias, because port number range 1-based but instances are 0-based |
| int offset = instance + 1; |
| if (offset == numInstances) { |
| // Base port unused, but still open, highest instance for testing |
| offset = 0; |
| } |
| |
| // The instances are at consecutive port numbers |
| int port = basePort + offset; |
| |
| std::string address = "[::]:"; |
| address += std::to_string(port); |
| |
| grpcCredentials = grpc::InsecureServerCredentials(); |
| |
| grpcBuilder.AddListeningPort(address, grpcCredentials); |
| grpcBuilder.RegisterService(smbiosServiceCallback.get()); |
| grpcBuilder.RegisterService(biosSettingGrpcService.get()); |
| grpcBuilder.RegisterService(bmServiceCallback.get()); |
| grpcBuilder.RegisterService(bootTimeServiceCallback.get()); |
| |
| LOG(INFO) << "Claimed gRPC address: " << address << " for " << instance; |
| |
| grpcServer = grpcBuilder.BuildAndStart(); |
| |
| LOG(INFO) << "Started gRPC server: " << instance; |
| |
| // Server is up, give it the thread that it needs to make progress |
| grpcThread = std::make_unique<std::thread>([this]() { this->threadRun(); }); |
| |
| LOG(INFO) << "Thread " << threadId(*grpcThread) << " created: " << instance; |
| } |
| |
| void GrpcInstance::threadRun() { |
| restoreLink(); |
| |
| // This will block until Shutdown() is called |
| grpcServer->Wait(); |
| |
| LOG(INFO) << "Finishing gRPC thread: " << instance; |
| } |
| |
| void GrpcInstance::stop() { |
| LOG(INFO) << "Stopping gRPC thread: " << instance; |
| |
| // Tells gRPC to allow Wait() to return |
| grpcServer->Shutdown(std::chrono::system_clock::now()); |
| |
| LOG(INFO) << "Cleaning up gRPC thread: " << instance; |
| |
| // This will block until threadRun() returns |
| grpcThread->join(); |
| |
| LOG(INFO) << "Stopped gRPC server: " << instance; |
| } |
| |
| } // namespace blobs |