blob: 707b19d20e44459f75cc3991baa37ac7c3f1d562 [file] [log] [blame]
Alex Vakulenkob04936f2014-09-19 14:53:58 -07001// Copyright 2014 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "buffet/utils.h"
6
7#include <map>
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -07008#include <netdb.h>
Alex Vakulenkob04936f2014-09-19 14:53:58 -07009#include <string>
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -070010#include <sys/socket.h>
11#include <sys/types.h>
12#include <unistd.h>
Alex Vakulenkob04936f2014-09-19 14:53:58 -070013
14#include <base/files/file_util.h>
15#include <base/json/json_reader.h>
16#include <chromeos/errors/error_codes.h>
17
18namespace buffet {
19
Alex Vakulenko36c85aa2015-04-09 09:06:39 -070020namespace {
21
22// Truncates a string if it is too long. Used for error reporting with really
23// long JSON strings.
24std::string LimitString(const std::string& text, size_t max_len) {
25 if (text.size() <= max_len)
26 return text;
27 return text.substr(0, max_len - 3) + "...";
28}
29
30const size_t kMaxStrLen = 1700; // Log messages are limited to 2000 chars.
31
32} // anonymous namespace
33
Alex Vakulenkob04936f2014-09-19 14:53:58 -070034const char kErrorDomainBuffet[] = "buffet";
35const char kFileReadError[] = "file_read_error";
Alex Vakulenko07216fe2014-09-19 15:31:09 -070036const char kInvalidCategoryError[] = "invalid_category";
37const char kInvalidPackageError[] = "invalid_package";
Alex Vakulenkob04936f2014-09-19 14:53:58 -070038
Vitaly Buka207c1cb2015-05-14 17:06:18 -070039std::unique_ptr<base::DictionaryValue> LoadJsonDict(
40 const base::FilePath& json_file_path,
41 chromeos::ErrorPtr* error) {
Alex Vakulenkob04936f2014-09-19 14:53:58 -070042 std::string json_string;
43 if (!base::ReadFileToString(json_file_path, &json_string)) {
Alex Vakulenkoac8037d2014-11-11 11:42:05 -080044 chromeos::errors::system::AddSystemError(error, FROM_HERE, errno);
45 chromeos::Error::AddToPrintf(error, FROM_HERE, kErrorDomainBuffet,
Alex Vakulenkob04936f2014-09-19 14:53:58 -070046 kFileReadError,
47 "Failed to read file '%s'",
48 json_file_path.value().c_str());
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -070049 return {};
Alex Vakulenkob04936f2014-09-19 14:53:58 -070050 }
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -070051 return LoadJsonDict(json_string, error);
52}
53
Vitaly Buka207c1cb2015-05-14 17:06:18 -070054std::unique_ptr<base::DictionaryValue> LoadJsonDict(
55 const std::string& json_string,
56 chromeos::ErrorPtr* error) {
57 std::unique_ptr<base::DictionaryValue> result;
Alex Vakulenkob04936f2014-09-19 14:53:58 -070058 std::string error_message;
59 base::Value* value = base::JSONReader::ReadAndReturnError(
60 json_string, base::JSON_PARSE_RFC, nullptr, &error_message);
61 if (!value) {
Alex Vakulenkoac8037d2014-11-11 11:42:05 -080062 chromeos::Error::AddToPrintf(error, FROM_HERE,
63 chromeos::errors::json::kDomain,
Alex Vakulenkob04936f2014-09-19 14:53:58 -070064 chromeos::errors::json::kParseError,
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -070065 "Error parsing JSON string '%s': %s",
Alex Vakulenko36c85aa2015-04-09 09:06:39 -070066 LimitString(json_string, kMaxStrLen).c_str(),
Alex Vakulenkob04936f2014-09-19 14:53:58 -070067 error_message.c_str());
68 return result;
69 }
Vitaly Buka207c1cb2015-05-14 17:06:18 -070070 base::DictionaryValue* dict_value = nullptr;
Alex Vakulenkob04936f2014-09-19 14:53:58 -070071 if (!value->GetAsDictionary(&dict_value)) {
72 delete value;
Alex Vakulenkoac8037d2014-11-11 11:42:05 -080073 chromeos::Error::AddToPrintf(error, FROM_HERE,
74 chromeos::errors::json::kDomain,
Alex Vakulenkob04936f2014-09-19 14:53:58 -070075 chromeos::errors::json::kObjectExpected,
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -070076 "JSON string '%s' is not a JSON object",
Alex Vakulenko36c85aa2015-04-09 09:06:39 -070077 LimitString(json_string, kMaxStrLen).c_str());
Alex Vakulenkob04936f2014-09-19 14:53:58 -070078 return result;
79 }
80 result.reset(dict_value);
81 return result;
82}
83
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -070084int ConnectSocket(const std::string& host, uint16_t port) {
85 std::string service = std::to_string(port);
86 addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
87 addrinfo* result = nullptr;
88 if (getaddrinfo(host.c_str(), service.c_str(), &hints, &result))
89 return -1;
90
91 int socket_fd = -1;
92 for (const addrinfo* info = result; info != nullptr; info = info->ai_next) {
93 socket_fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
94 if (socket_fd < 0)
95 continue;
96
97 if (connect(socket_fd, info->ai_addr, info->ai_addrlen) == 0)
98 break; // Success.
99
100 close(socket_fd);
101 socket_fd = -1;
102 }
103
104 freeaddrinfo(result);
105 return socket_fd;
106}
107
Alex Vakulenkob04936f2014-09-19 14:53:58 -0700108} // namespace buffet