1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "device_config.h"
18 
19 #include <chrono>
20 #include <thread>
21 
22 #include <cutils/properties.h>
23 #include <glog/logging.h>
24 
25 namespace cvd {
26 
27 namespace {
28 
29 static constexpr auto kDataSize = sizeof(DeviceConfig::RawData);
30 static constexpr int kRetries = 5;
31 static constexpr int kRetryDelaySeconds = 5;
32 
GetRawFromServer(DeviceConfig::RawData * data)33 bool GetRawFromServer(DeviceConfig::RawData* data) {
34   auto port_property = "ro.boot.cuttlefish_config_server_port";
35   auto port = property_get_int64(port_property, -1);
36   if (port < 0) {
37     LOG(ERROR) << "Unable to get config server port from property: " <<
38         port_property;
39     return false;
40   }
41   auto config_server =
42       cvd::SharedFD::VsockClient(2 /*host cid*/,
43                                  static_cast<unsigned int>(port), SOCK_STREAM);
44   if (!config_server->IsOpen()) {
45     LOG(ERROR) << "Unable to connect to config server: "
46                << config_server->StrError();
47     return false;
48   }
49   uint8_t* buffer = reinterpret_cast<uint8_t*>(data);
50   size_t read_idx = 0;
51   while (read_idx < kDataSize) {
52     auto read = config_server->Read(buffer + read_idx, kDataSize - read_idx);
53     if (read == 0) {
54       LOG(ERROR) << "Unexpected EOF while reading from config server, read "
55                  << read_idx << " bytes, expected " << kDataSize;
56       return false;
57     }
58     if (read < 0) {
59       LOG(ERROR) << "Error reading from config server: "
60                  << config_server->StrError();
61       return false;
62     }
63     read_idx += read;
64   }
65   return true;
66 }
67 
68 }  // namespace
69 
Get()70 std::unique_ptr<DeviceConfig> DeviceConfig::Get() {
71   DeviceConfig::RawData data;
72 
73   int attempts_remaining = 1 + kRetries;
74   while (attempts_remaining > 0) {
75     if (GetRawFromServer(&data)) {
76       return std::unique_ptr<DeviceConfig>(new DeviceConfig(data));
77     }
78 
79     std::this_thread::sleep_for(std::chrono::seconds(kRetryDelaySeconds));
80 
81     --attempts_remaining;
82   }
83   return nullptr;
84 }
85 
DeviceConfig(const DeviceConfig::RawData & data)86 DeviceConfig::DeviceConfig(const DeviceConfig::RawData& data) : data_(data) {
87   generate_address_and_prefix();
88 }
89 
90 }  // namespace cvd
91