| #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 |