blob: 7e50d0f3c12381d4d896077aaf8cdb0a2b7df6ad [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
39std::unique_ptr<const base::DictionaryValue> LoadJsonDict(
40 const base::FilePath& json_file_path, chromeos::ErrorPtr* error) {
Alex Vakulenkob04936f2014-09-19 14:53:58 -070041 std::string json_string;
42 if (!base::ReadFileToString(json_file_path, &json_string)) {
Alex Vakulenkoac8037d2014-11-11 11:42:05 -080043 chromeos::errors::system::AddSystemError(error, FROM_HERE, errno);
44 chromeos::Error::AddToPrintf(error, FROM_HERE, kErrorDomainBuffet,
Alex Vakulenkob04936f2014-09-19 14:53:58 -070045 kFileReadError,
46 "Failed to read file '%s'",
47 json_file_path.value().c_str());
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -070048 return {};
Alex Vakulenkob04936f2014-09-19 14:53:58 -070049 }
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -070050 return LoadJsonDict(json_string, error);
51}
52
53std::unique_ptr<const base::DictionaryValue> LoadJsonDict(
54 const std::string& json_string, chromeos::ErrorPtr* error) {
55 std::unique_ptr<const base::DictionaryValue> result;
Alex Vakulenkob04936f2014-09-19 14:53:58 -070056 std::string error_message;
57 base::Value* value = base::JSONReader::ReadAndReturnError(
58 json_string, base::JSON_PARSE_RFC, nullptr, &error_message);
59 if (!value) {
Alex Vakulenkoac8037d2014-11-11 11:42:05 -080060 chromeos::Error::AddToPrintf(error, FROM_HERE,
61 chromeos::errors::json::kDomain,
Alex Vakulenkob04936f2014-09-19 14:53:58 -070062 chromeos::errors::json::kParseError,
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -070063 "Error parsing JSON string '%s': %s",
Alex Vakulenko36c85aa2015-04-09 09:06:39 -070064 LimitString(json_string, kMaxStrLen).c_str(),
Alex Vakulenkob04936f2014-09-19 14:53:58 -070065 error_message.c_str());
66 return result;
67 }
68 const base::DictionaryValue* dict_value = nullptr;
69 if (!value->GetAsDictionary(&dict_value)) {
70 delete value;
Alex Vakulenkoac8037d2014-11-11 11:42:05 -080071 chromeos::Error::AddToPrintf(error, FROM_HERE,
72 chromeos::errors::json::kDomain,
Alex Vakulenkob04936f2014-09-19 14:53:58 -070073 chromeos::errors::json::kObjectExpected,
Alex Vakulenko9e2f8cd2015-04-07 16:28:09 -070074 "JSON string '%s' is not a JSON object",
Alex Vakulenko36c85aa2015-04-09 09:06:39 -070075 LimitString(json_string, kMaxStrLen).c_str());
Alex Vakulenkob04936f2014-09-19 14:53:58 -070076 return result;
77 }
78 result.reset(dict_value);
79 return result;
80}
81
Alex Vakulenkoeedf3be2015-05-13 17:52:02 -070082int ConnectSocket(const std::string& host, uint16_t port) {
83 std::string service = std::to_string(port);
84 addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM};
85 addrinfo* result = nullptr;
86 if (getaddrinfo(host.c_str(), service.c_str(), &hints, &result))
87 return -1;
88
89 int socket_fd = -1;
90 for (const addrinfo* info = result; info != nullptr; info = info->ai_next) {
91 socket_fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
92 if (socket_fd < 0)
93 continue;
94
95 if (connect(socket_fd, info->ai_addr, info->ai_addrlen) == 0)
96 break; // Success.
97
98 close(socket_fd);
99 socket_fd = -1;
100 }
101
102 freeaddrinfo(result);
103 return socket_fd;
104}
105
Alex Vakulenkob04936f2014-09-19 14:53:58 -0700106} // namespace buffet