OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "blimp/client/session/assignment_source.h" | 5 #include "blimp/client/session/assignment_source.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback.h" | |
8 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/files/file_util.h" | |
9 #include "base/location.h" | 11 #include "base/location.h" |
10 #include "base/numerics/safe_conversions.h" | 12 #include "base/numerics/safe_conversions.h" |
11 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
12 #include "blimp/client/app/blimp_client_switches.h" | 14 #include "blimp/client/app/blimp_client_switches.h" |
15 #include "net/base/hash_value.h" | |
13 #include "net/base/ip_address.h" | 16 #include "net/base/ip_address.h" |
14 #include "net/base/ip_endpoint.h" | 17 #include "net/base/ip_endpoint.h" |
18 #include "net/cert/pem_tokenizer.h" | |
15 | 19 |
16 namespace blimp { | 20 namespace blimp { |
17 namespace { | 21 namespace { |
18 | 22 |
19 // TODO(kmarshall): Take values from configuration data. | 23 // TODO(kmarshall): Take values from configuration data. |
20 const char kDummyClientToken[] = "MyVoiceIsMyPassport"; | 24 const char kDummyClientToken[] = "MyVoiceIsMyPassport"; |
21 const std::string kDefaultBlimpletIPAddress = "127.0.0.1"; | 25 const std::string kDefaultBlimpletIPAddress = "127.0.0.1"; |
22 const uint16_t kDefaultBlimpletTCPPort = 25467; | 26 const uint16_t kNoPort = 0; |
Wez
2016/02/12 02:31:13
nit: kPortNotSet or kInvalidPort?
Kevin M
2016/02/13 00:44:17
Done.
| |
23 | 27 |
24 net::IPAddress GetBlimpletIPAddress() { | 28 net::IPAddress GetBlimpletIPAddress() { |
25 std::string host; | 29 std::string host; |
26 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 30 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
27 switches::kBlimpletHost)) { | 31 switches::kBlimpletHost)) { |
28 host = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 32 host = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
29 switches::kBlimpletHost); | 33 switches::kBlimpletHost); |
30 } else { | 34 } else { |
31 host = kDefaultBlimpletIPAddress; | 35 host = kDefaultBlimpletIPAddress; |
32 } | 36 } |
33 net::IPAddress ip_address; | 37 net::IPAddress ip_address; |
34 if (!ip_address.AssignFromIPLiteral(host)) | 38 if (!ip_address.AssignFromIPLiteral(host)) |
35 CHECK(false) << "Invalid BlimpletAssignment host " << host; | 39 CHECK(false) << "Invalid BlimpletAssignment host " << host; |
36 return ip_address; | 40 return ip_address; |
37 } | 41 } |
38 | 42 |
39 uint16_t GetBlimpletTCPPort() { | 43 uint16_t GetBlimpletTCPPort() { |
40 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | 44 if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
41 switches::kBlimpletTCPPort)) { | 45 switches::kBlimpletTCPPort)) { |
42 std::string port_str = | 46 std::string port_str = |
43 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | 47 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
44 switches::kBlimpletTCPPort); | 48 switches::kBlimpletTCPPort); |
45 uint port_64t; | 49 uint port_64t; |
Wez
2016/02/12 02:31:13
nit: This needs to be explicitly initialized.
Kevin M
2016/02/13 00:44:17
Done.
| |
46 if (!base::StringToUint(port_str, &port_64t) || | 50 if (!base::StringToUint(port_str, &port_64t) || |
47 !base::IsValueInRangeForNumericType<uint16_t>(port_64t)) { | 51 !base::IsValueInRangeForNumericType<uint16_t>(port_64t)) { |
48 CHECK(false) << "Invalid BlimpletAssignment port " << port_str; | 52 CHECK(false) << "Invalid BlimpletAssignment port " << port_str; |
49 } | 53 } |
50 return base::checked_cast<uint16_t>(port_64t); | 54 return base::checked_cast<uint16_t>(port_64t); |
51 } else { | 55 } else { |
52 return kDefaultBlimpletTCPPort; | 56 return kNoPort; |
53 } | 57 } |
54 } | 58 } |
55 | 59 |
60 uint16_t GetBlimpletSSLPort() { | |
Wez
2016/02/12 02:31:13
This is basically identical to the TCP port one ab
Kevin M
2016/02/13 00:44:17
Done.
| |
61 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
62 switches::kBlimpletSSLPort)) { | |
Wez
2016/02/12 02:31:13
GetSwitchValueASCII returns an empty string if the
Kevin M
2016/02/13 00:44:18
Done.
| |
63 std::string port_str = | |
64 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
65 switches::kBlimpletSSLPort); | |
66 uint port_64t; | |
Wez
2016/02/12 02:31:13
nit: This needs to be explicitly initialized.
Kevin M
2016/02/13 00:44:17
Done.
| |
67 if (!base::StringToUint(port_str, &port_64t) || | |
68 !base::IsValueInRangeForNumericType<uint16_t>(port_64t)) { | |
69 CHECK(false) << "Invalid SSL port " << port_str; | |
Wez
2016/02/12 02:31:13
nit: Save the result of StringToUint || IsValue..
Kevin M
2016/02/13 00:44:17
Done.
| |
70 } | |
71 return base::checked_cast<uint16_t>(port_64t); | |
72 } else { | |
73 return kNoPort; | |
74 } | |
75 } | |
76 | |
77 base::FilePath GetBlimpletCertPath() { | |
Wez
2016/02/12 02:31:13
This function is redundant; GetSwitchValuePath() a
Kevin M
2016/02/13 00:44:18
Done.
| |
78 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
79 switches::kBlimpletCertPath)) { | |
80 return base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( | |
81 switches::kBlimpletCertPath); | |
82 } | |
83 return base::FilePath(); | |
84 } | |
85 | |
56 } // namespace | 86 } // namespace |
57 | 87 |
58 namespace client { | 88 namespace client { |
59 | 89 |
90 Assignment::Assignment() {} | |
Wez
2016/02/12 02:31:13
See above re inline init; you need to make sure to
Kevin M
2016/02/13 00:44:17
Done.
| |
91 | |
92 Assignment::~Assignment() {} | |
93 | |
60 AssignmentSource::AssignmentSource( | 94 AssignmentSource::AssignmentSource( |
61 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) | 95 const scoped_refptr<base::SingleThreadTaskRunner>& main_task_runner) |
62 : main_task_runner_(main_task_runner) {} | 96 : main_task_runner_(main_task_runner), io_thread_("CertFileThread") { |
97 base::Thread::Options options; | |
98 options.message_loop_type = base::MessageLoop::TYPE_IO; | |
99 io_thread_.StartWithOptions(options); | |
Wez
2016/02/12 02:31:13
Cleaner to avoid creating this thread until you ac
Kevin M
2016/02/13 00:44:17
Done.
| |
100 } | |
63 | 101 |
64 AssignmentSource::~AssignmentSource() {} | 102 AssignmentSource::~AssignmentSource() {} |
65 | 103 |
104 void AssignmentSource::ReadFromDisk( | |
Wez
2016/02/12 02:31:13
As noted elsewhere, this function can be a static
Kevin M
2016/02/13 00:44:17
Done.
| |
105 base::FilePath path, | |
106 const base::Callback<void(const std::string&)>& callback) { | |
107 if (!io_thread_.task_runner()->RunsTasksOnCurrentThread()) { | |
108 // Execute file reads on the I/O thread. | |
109 io_thread_.task_runner()->PostTask( | |
110 FROM_HERE, base::Bind(&AssignmentSource::ReadFromDisk, | |
111 base::Unretained(this), path, callback)); | |
112 return; | |
Wez
2016/02/12 02:31:13
ICK! This sort of trampolining is safe while the
Kevin M
2016/02/13 00:44:18
Done.
| |
113 } | |
114 | |
115 std::string output; | |
116 if (!base::ReadFileToString(path, &output)) { | |
117 LOG(ERROR) << "Couldn't read cert from file: " << path.LossyDisplayName(); | |
Wez
2016/02/12 02:31:13
Why LOG(ERROR) when we CHECK for everything else?
Kevin M
2016/02/13 00:44:18
Done.
| |
118 } | |
119 | |
120 main_task_runner_->PostTask(FROM_HERE, base::Bind(callback, output)); | |
Wez
2016/02/12 02:31:13
This doesn't match the API comment.
Kevin M
2016/02/13 00:44:17
Acknowledged.
| |
121 } | |
122 | |
123 void AssignmentSource::ParseCertForAssignment( | |
124 Assignment assignment, | |
125 const AssignmentCallback& callback, | |
126 const std::string& cert_str) { | |
127 if (!cert_str.empty()) { | |
Wez
2016/02/12 02:31:13
Surely you can't reach here if it's empty, so this
Kevin M
2016/02/13 00:44:17
Done.
| |
128 scoped_refptr<net::X509Certificate> cert; | |
Wez
2016/02/12 02:31:13
Doesn't look like you use this?
Kevin M
2016/02/13 00:44:17
Done.
| |
129 net::PEMTokenizer pem_tokenizer(cert_str, {"CERTIFICATE"}); | |
130 int num_certs = 0; | |
Wez
2016/02/12 02:31:13
Rather than counting the certs, you can surely jus
Kevin M
2016/02/13 00:44:17
Done.
| |
131 for (; pem_tokenizer.GetNext(); ++num_certs) { | |
132 assignment.cert = net::X509Certificate::CreateFromBytes( | |
133 pem_tokenizer.data().data(), pem_tokenizer.data().length()); | |
134 if (!assignment.cert) { | |
135 LOG(ERROR) << "Couldn't parse cert!"; | |
136 } else { | |
137 DVLOG(1) << "Parsed X509 cert."; | |
138 } | |
139 } | |
140 if (num_certs != 1) { | |
141 LOG(ERROR) << "Expected exactly 1 CERTIFICATE block, but found " | |
142 << num_certs << " blocks instead."; | |
143 assignment.cert = nullptr; | |
144 } | |
145 } | |
146 | |
147 main_task_runner_->PostTask(FROM_HERE, base::Bind(callback, assignment)); | |
Wez
2016/02/12 02:31:13
You're already on the main task runner, with a cle
Kevin M
2016/02/13 00:44:18
This line is from Tommy's initial impl, I was thin
| |
148 } | |
149 | |
66 void AssignmentSource::GetAssignment(const AssignmentCallback& callback) { | 150 void AssignmentSource::GetAssignment(const AssignmentCallback& callback) { |
67 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 151 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
68 Assignment assignment; | 152 Assignment assignment; |
69 assignment.ip_endpoint = | 153 assignment.ip_addresses.push_back(GetBlimpletIPAddress()); |
70 net::IPEndPoint(GetBlimpletIPAddress(), GetBlimpletTCPPort()); | 154 if (GetBlimpletTCPPort() > 0) { |
Wez
2016/02/12 02:31:13
This if() is always true, since the Get*Port() met
Kevin M
2016/02/13 00:44:17
Done.
| |
155 assignment.tcp_port = GetBlimpletTCPPort(); | |
156 } | |
157 if (GetBlimpletSSLPort() > 0) { | |
158 assignment.ssl_port = GetBlimpletSSLPort(); | |
159 } | |
71 assignment.client_token = kDummyClientToken; | 160 assignment.client_token = kDummyClientToken; |
72 main_task_runner_->PostTask(FROM_HERE, base::Bind(callback, assignment)); | 161 |
162 base::FilePath cert_path = GetBlimpletCertPath(); | |
163 if (!cert_path.empty()) { | |
164 ReadFromDisk(cert_path, | |
165 base::Bind(&AssignmentSource::ParseCertForAssignment, | |
166 base::Unretained(this), assignment, callback)); | |
Wez
2016/02/12 02:31:13
See notes above re combining file-read and cert-pa
Kevin M
2016/02/13 00:44:18
Done.
| |
167 } else { | |
168 main_task_runner_->PostTask(FROM_HERE, base::Bind(callback, assignment)); | |
Wez
2016/02/12 02:31:13
Assert that the SSL port is kNoPort in this case?
Kevin M
2016/02/13 00:44:17
Done.
| |
169 } | |
73 } | 170 } |
74 | 171 |
75 } // namespace client | 172 } // namespace client |
76 } // namespace blimp | 173 } // namespace blimp |
OLD | NEW |