blob: 707b19d20e44459f75cc3991baa37ac7c3f1d562 [file] [log] [blame]
// Copyright 2014 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "buffet/utils.h"
#include <map>
#include <netdb.h>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <base/files/file_util.h>
#include <base/json/json_reader.h>
#include <chromeos/errors/error_codes.h>
namespace buffet {
namespace {
// Truncates a string if it is too long. Used for error reporting with really
// long JSON strings.
std::string LimitString(const std::string& text, size_t max_len) {
if (text.size() <= max_len)
return text;
return text.substr(0, max_len - 3) + "...";
}
const size_t kMaxStrLen = 1700; // Log messages are limited to 2000 chars.
} // anonymous namespace
const char kErrorDomainBuffet[] = "buffet";
const char kFileReadError[] = "file_read_error";
const char kInvalidCategoryError[] = "invalid_category";
const char kInvalidPackageError[] = "invalid_package";
std::unique_ptr<base::DictionaryValue> LoadJsonDict(
const base::FilePath& json_file_path,
chromeos::ErrorPtr* error) {
std::string json_string;
if (!base::ReadFileToString(json_file_path, &json_string)) {
chromeos::errors::system::AddSystemError(error, FROM_HERE, errno);
chromeos::Error::AddToPrintf(error, FROM_HERE, kErrorDomainBuffet,
kFileReadError,
"Failed to read file '%s'",
json_file_path.value().c_str());
return {};
}
return LoadJsonDict(json_string, error);
}
std::unique_ptr<base::DictionaryValue> LoadJsonDict(
const std::string& json_string,
chromeos::ErrorPtr* error) {
std::unique_ptr<base::DictionaryValue> result;
std::string error_message;
base::Value* value = base::JSONReader::ReadAndReturnError(
json_string, base::JSON_PARSE_RFC, nullptr, &error_message);
if (!value) {
chromeos::Error::AddToPrintf(error, FROM_HERE,
chromeos::errors::json::kDomain,
chromeos::errors::json::kParseError,
"Error parsing JSON string '%s': %s",
LimitString(json_string, kMaxStrLen).c_str(),
error_message.c_str());
return result;
}
base::DictionaryValue* dict_value = nullptr;
if (!value->GetAsDictionary(&dict_value)) {
delete value;
chromeos::Error::AddToPrintf(error, FROM_HERE,
chromeos::errors::json::kDomain,
chromeos::errors::json::kObjectExpected,
"JSON string '%s' is not a JSON object",
LimitString(json_string, kMaxStrLen).c_str());
return result;
}
result.reset(dict_value);
return result;
}
int ConnectSocket(const std::string& host, uint16_t port) {
std::string service = std::to_string(port);
addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
addrinfo* result = nullptr;
if (getaddrinfo(host.c_str(), service.c_str(), &hints, &result))
return -1;
int socket_fd = -1;
for (const addrinfo* info = result; info != nullptr; info = info->ai_next) {
socket_fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
if (socket_fd < 0)
continue;
if (connect(socket_fd, info->ai_addr, info->ai_addrlen) == 0)
break; // Success.
close(socket_fd);
socket_fd = -1;
}
freeaddrinfo(result);
return socket_fd;
}
} // namespace buffet