blob: 33fc2925c36a91d7fde1d939051ee63aa2ef9f32 [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
Alex Vakulenkoae1ffbc2015-06-15 12:53:22 -070014#include <base/bind_helpers.h>
Alex Vakulenkob04936f2014-09-19 14:53:58 -070015#include <base/files/file_util.h>
16#include <base/json/json_reader.h>
17#include <chromeos/errors/error_codes.h>
18
19namespace buffet {
20
Alex Vakulenko36c85aa2015-04-09 09:06:39 -070021namespace {
22
23// Truncates a string if it is too long. Used for error reporting with really
24// long JSON strings.
25std::string LimitString(const std::string& text, size_t max_len) {
26 if (text.size() <= max_len)
27 return text;
28 return text.substr(0, max_len - 3) + "...";
29}
30
31const size_t kMaxStrLen = 1700; // Log messages are limited to 2000 chars.
32
33} // anonymous namespace
34
Alex Vakulenkob04936f2014-09-19 14:53:58 -070035const char kErrorDomainBuffet[] = "buffet";
36const char kFileReadError[] = "file_read_error";
Alex Vakulenko07216fe2014-09-19 15:31:09 -070037const char kInvalidCategoryError[] = "invalid_category";
38const char kInvalidPackageError[] = "invalid_package";
Alex Vakulenkob04936f2014-09-19 14:53:58 -070039
Vitaly Buka207c1cb2015-05-14 17:06:18 -070040std::unique_ptr<base::DictionaryValue> LoadJsonDict(
41 const base::FilePath& json_file_path,
42 chromeos::ErrorPtr* error) {
Alex Vakulenkob04936f2014-09-19 14:53:58 -070043 std::string json_string;
44 if (!base::ReadFileToString(json_file_path, &json_string)) {
Alex Vakulenkoac8037d2014-11-11 11:42:05 -080045 chromeos::errors::system::AddSystemError(error, FROM_HERE, errno);
46 chromeos::Error::AddToPrintf(error, FROM_HERE, kErrorDomainBuffet,
Alex Vakulenkob04936f2014-09-19 14:53:58 -070047 kFileReadError,
48 "Failed to read file '%s'",
49 json_file_path.value().c_str());
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -070050 return {};
Alex Vakulenkob04936f2014-09-19 14:53:58 -070051 }
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -070052 return LoadJsonDict(json_string, error);
53}
54
Vitaly Buka207c1cb2015-05-14 17:06:18 -070055std::unique_ptr<base::DictionaryValue> LoadJsonDict(
56 const std::string& json_string,
57 chromeos::ErrorPtr* error) {
58 std::unique_ptr<base::DictionaryValue> result;
Alex Vakulenkob04936f2014-09-19 14:53:58 -070059 std::string error_message;
Alex Vakulenkoae1ffbc2015-06-15 12:53:22 -070060 auto value = base::JSONReader::ReadAndReturnError(
Alex Vakulenkob04936f2014-09-19 14:53:58 -070061 json_string, base::JSON_PARSE_RFC, nullptr, &error_message);
62 if (!value) {
Alex Vakulenkoac8037d2014-11-11 11:42:05 -080063 chromeos::Error::AddToPrintf(error, FROM_HERE,
64 chromeos::errors::json::kDomain,
Alex Vakulenkob04936f2014-09-19 14:53:58 -070065 chromeos::errors::json::kParseError,
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -070066 "Error parsing JSON string '%s': %s",
Alex Vakulenko36c85aa2015-04-09 09:06:39 -070067 LimitString(json_string, kMaxStrLen).c_str(),
Alex Vakulenkob04936f2014-09-19 14:53:58 -070068 error_message.c_str());
69 return result;
70 }
Vitaly Buka207c1cb2015-05-14 17:06:18 -070071 base::DictionaryValue* dict_value = nullptr;
Alex Vakulenkob04936f2014-09-19 14:53:58 -070072 if (!value->GetAsDictionary(&dict_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;
Alex Vakulenkoae1ffbc2015-06-15 12:53:22 -070079 } else {
80 // |value| is now owned by |dict_value|.
81 base::IgnoreResult(value.release());
Alex Vakulenkob04936f2014-09-19 14:53:58 -070082 }
83 result.reset(dict_value);
84 return result;
85}
86
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -070087int ConnectSocket(const std::string& host, uint16_t port) {
88 std::string service = std::to_string(port);
89 addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
90 addrinfo* result = nullptr;
91 if (getaddrinfo(host.c_str(), service.c_str(), &hints, &result))
92 return -1;
93
94 int socket_fd = -1;
95 for (const addrinfo* info = result; info != nullptr; info = info->ai_next) {
96 socket_fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
97 if (socket_fd < 0)
98 continue;
99
100 if (connect(socket_fd, info->ai_addr, info->ai_addrlen) == 0)
101 break; // Success.
102
103 close(socket_fd);
104 socket_fd = -1;
105 }
106
107 freeaddrinfo(result);
108 return socket_fd;
109}
110
Alex Vakulenkob04936f2014-09-19 14:53:58 -0700111} // namespace buffet